diff options
Diffstat (limited to 'twin4')
59 files changed, 7768 insertions, 0 deletions
diff --git a/twin4/AUTHORS b/twin4/AUTHORS new file mode 100644 index 00000000..944b9a7d --- /dev/null +++ b/twin4/AUTHORS @@ -0,0 +1 @@ +Martin Heni <martin@heni-online.de> diff --git a/twin4/COPYING b/twin4/COPYING new file mode 100644 index 00000000..54754ab4 --- /dev/null +++ b/twin4/COPYING @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. + + <one line to give the program's name and a brief 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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/twin4/INSTALL b/twin4/INSTALL new file mode 100644 index 00000000..02a4a074 --- /dev/null +++ b/twin4/INSTALL @@ -0,0 +1,167 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes a while. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Type `make install' to install the programs and any data files and + documentation. + + 4. You can remove the program binaries and object files from the + source code directory by typing `make clean'. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/twin4/Makefile.am b/twin4/Makefile.am new file mode 100644 index 00000000..bce84320 --- /dev/null +++ b/twin4/Makefile.am @@ -0,0 +1,7 @@ +SUBDIRS = twin4 grafix + +AUTOMAKE_OPTIONS = foreign + +KDE_ICON = twin4 + +xdg_apps_DATA = twin4.desktop diff --git a/twin4/README b/twin4/README new file mode 100644 index 00000000..9f2dc592 --- /dev/null +++ b/twin4/README @@ -0,0 +1,26 @@ +GENERAL NOTE: + + This is a small KDE 2.0 game, I wrote to practise + programming in KDE. + It should work quite stable. But if you find any bugs + please contact me. + It would be also nice to give me some general feedback + about the program, so that it can be approved or it + can be considered in other programs. + (Email: martin@heni-online.de) + +INSTALLATION: + +# unpack the archive +tar xzf twin4-0.9.tar.gz + +# build the package +cd twin4-0.9 +./configure +# or if KDE is in /opt/kde2 +./configure --prefix=/opt/kde2 +make + +# become superuser for installing +su -c 'make install' + diff --git a/twin4/grafix/Makefile.am b/twin4/grafix/Makefile.am new file mode 100644 index 00000000..70c3bfeb --- /dev/null +++ b/twin4/grafix/Makefile.am @@ -0,0 +1,22 @@ +GRAFIXDIRS = default + +grafixdir = $(kde_datadir)/twin4/grafix + +uninstall-local: + rm -rf $(DESTDIR)$(grafixdir) + +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(grafixdir) + for i in $(GRAFIXDIRS); do \ + if test -d $(DESTDIR)$(grafixdir)/$$i; then \ + echo "refreshing and removing $$i" ;\ + rm -rf $(DESTDIR)$(grafixdir)/$$i;\ + fi ;\ + echo "installing $$i" ;\ + if test ! -d $(DESTDIR)$(grafixdir)/$$i; then \ + cp -r $(srcdir)/$$i $(DESTDIR)$(grafixdir)/$$i ;\ + rm -rf $(DESTDIR)$(grafixdir)/$$i/CVS ;\ + rm -rf $(DESTDIR)$(grafixdir)/$$i/.svn ;\ + fi ;\ + done + diff --git a/twin4/grafix/default/aboute.png b/twin4/grafix/default/aboute.png Binary files differnew file mode 100644 index 00000000..78c8f4c1 --- /dev/null +++ b/twin4/grafix/default/aboute.png diff --git a/twin4/grafix/default/arrow0.png b/twin4/grafix/default/arrow0.png Binary files differnew file mode 100644 index 00000000..c93e7e63 --- /dev/null +++ b/twin4/grafix/default/arrow0.png diff --git a/twin4/grafix/default/arrow1.png b/twin4/grafix/default/arrow1.png Binary files differnew file mode 100644 index 00000000..81a2b5e7 --- /dev/null +++ b/twin4/grafix/default/arrow1.png diff --git a/twin4/grafix/default/arrow2.png b/twin4/grafix/default/arrow2.png Binary files differnew file mode 100644 index 00000000..89c9b815 --- /dev/null +++ b/twin4/grafix/default/arrow2.png diff --git a/twin4/grafix/default/background.png b/twin4/grafix/default/background.png Binary files differnew file mode 100644 index 00000000..7edcd84e --- /dev/null +++ b/twin4/grafix/default/background.png diff --git a/twin4/grafix/default/board.png b/twin4/grafix/default/board.png Binary files differnew file mode 100644 index 00000000..d27ff61f --- /dev/null +++ b/twin4/grafix/default/board.png diff --git a/twin4/grafix/default/crnt.png b/twin4/grafix/default/crnt.png Binary files differnew file mode 100644 index 00000000..5a3c0c69 --- /dev/null +++ b/twin4/grafix/default/crnt.png diff --git a/twin4/grafix/default/empty.png b/twin4/grafix/default/empty.png Binary files differnew file mode 100644 index 00000000..acb05be3 --- /dev/null +++ b/twin4/grafix/default/empty.png diff --git a/twin4/grafix/default/empty2.png b/twin4/grafix/default/empty2.png Binary files differnew file mode 100644 index 00000000..94ec038d --- /dev/null +++ b/twin4/grafix/default/empty2.png diff --git a/twin4/grafix/default/game_over.png b/twin4/grafix/default/game_over.png Binary files differnew file mode 100644 index 00000000..45f030f7 --- /dev/null +++ b/twin4/grafix/default/game_over.png diff --git a/twin4/grafix/default/grafix.rc b/twin4/grafix/default/grafix.rc new file mode 100644 index 00000000..afd8237c --- /dev/null +++ b/twin4/grafix/default/grafix.rc @@ -0,0 +1,148 @@ +[about] +file=aboute.png +rtti=32 +x=150.0 +y=50.0 +z=0.0 + +[arrow] +file=arrow%d.png +number=3 +offset=19,5 +rtti=32 +z=9.0 + +[board] +file=board.png +rtti=32 +x=15.0 +y=40.0 +z=0.0 + +# more then max(z piece) +[empty] +file=empty2.png +offset=19,12 +rtti=32 +z=60.0 + +# Less then z piece +[empty2] +file=empty.png +offset=19,12 +rtti=32 +z=5.0 + +[game] +scorewidget=390,25 +spread_x=8 +spread_y=8 +statuswidget=350,250 + +[gameover] +desty=140 +file=game_over.png +offset=0,0 +rtti=32 +speed=2.0 +x=25.0 +y=20.0 +z=150.0 + +[hint] +file=crnt.png +offset=19,20 +rtti=32 +z=100.0 + +[intro1] +color=255,255,0 +# Family, pointsize, pixelsize,stylehint,weight,italic, +# ... undeline,strikeout,fixedpitch,rawmode +# If you want pixelsize. Otherwise just OMIT the pixelsize +# argument +font=Sans Serif,-1,25,default,50,0,0,0,0,0 +rtti=3 +text=Dummy +x=230.0 +y=70.0 +z=150.0 + +[intro2] +color=255,255,0 +font=Sans Serif,-1,20,default,50,0,0,0,0,0 +rtti=3 +text=Dummy +x=275.0 +y=115.0 +z=150.0 + +[intro3] +color=255,255,0 +font=Sans Serif,-1,25,default,50,0,0,0,0,0 +rtti=3 +text=Dummy +x=245.0 +y=160.0 +z=150.0 + +# z = z..z+21 +[piece] +file=piece%d.png +number=2 +offset=19,20 +rtti=32 +speed=4.0 +z=10.0 + +[star] +anim0=0,4,2,8 +file=star%d.png +number=5 +offset=19,20 +rtti=32 +z=100.0 + +[text1] +color=255,255,255 +font=Sans Serif,-1,18,default,50,0,0,0,0,0 +rtti=3 +text=Dummy +x=30.0 +y=170.0 +z=150.0 + +[text2] +color=255,255,255 +font=Sans Serif,-1,18,default,50,0,0,0,0,0 +rtti=3 +text=Dummy +x=100.0 +y=170.0 +z=150.0 + +[text3] +color=255,255,255 +font=Sans Serif,-1,18,default,50,0,0,0,0,0 +rtti=3 +text=Dummy +x=35.0 +y=170.0 +z=150.0 + +[text4] +color=255,255,255 +font=Sans Serif,-1,18,default,50,0,0,0,0,0 +rtti=3 +text=Dummy +x=40.0 +y=170.0 +z=150.0 + +[win4about] +file=introabout.png +rtti=32 +x=170.0 +x2=340.0 +y=265.0 +z=1.0 diff --git a/twin4/grafix/default/introabout.png b/twin4/grafix/default/introabout.png Binary files differnew file mode 100644 index 00000000..23e4eeeb --- /dev/null +++ b/twin4/grafix/default/introabout.png diff --git a/twin4/grafix/default/piece0.png b/twin4/grafix/default/piece0.png Binary files differnew file mode 100644 index 00000000..a2570b54 --- /dev/null +++ b/twin4/grafix/default/piece0.png diff --git a/twin4/grafix/default/piece1.png b/twin4/grafix/default/piece1.png Binary files differnew file mode 100644 index 00000000..80dbba36 --- /dev/null +++ b/twin4/grafix/default/piece1.png diff --git a/twin4/grafix/default/star0.png b/twin4/grafix/default/star0.png Binary files differnew file mode 100644 index 00000000..e125cc53 --- /dev/null +++ b/twin4/grafix/default/star0.png diff --git a/twin4/grafix/default/star1.png b/twin4/grafix/default/star1.png Binary files differnew file mode 100644 index 00000000..bce75e13 --- /dev/null +++ b/twin4/grafix/default/star1.png diff --git a/twin4/grafix/default/star2.png b/twin4/grafix/default/star2.png Binary files differnew file mode 100644 index 00000000..11175dd4 --- /dev/null +++ b/twin4/grafix/default/star2.png diff --git a/twin4/grafix/default/star3.png b/twin4/grafix/default/star3.png Binary files differnew file mode 100644 index 00000000..862f457e --- /dev/null +++ b/twin4/grafix/default/star3.png diff --git a/twin4/grafix/default/star4.png b/twin4/grafix/default/star4.png Binary files differnew file mode 100644 index 00000000..40bf4bad --- /dev/null +++ b/twin4/grafix/default/star4.png diff --git a/twin4/hi128-app-twin4.png b/twin4/hi128-app-twin4.png Binary files differnew file mode 100644 index 00000000..10ba8a47 --- /dev/null +++ b/twin4/hi128-app-twin4.png diff --git a/twin4/hi16-app-twin4.png b/twin4/hi16-app-twin4.png Binary files differnew file mode 100644 index 00000000..e908a50c --- /dev/null +++ b/twin4/hi16-app-twin4.png diff --git a/twin4/hi22-app-twin4.png b/twin4/hi22-app-twin4.png Binary files differnew file mode 100644 index 00000000..31956ad2 --- /dev/null +++ b/twin4/hi22-app-twin4.png diff --git a/twin4/hi32-app-twin4.png b/twin4/hi32-app-twin4.png Binary files differnew file mode 100644 index 00000000..e7ae6152 --- /dev/null +++ b/twin4/hi32-app-twin4.png diff --git a/twin4/hi48-app-twin4.png b/twin4/hi48-app-twin4.png Binary files differnew file mode 100644 index 00000000..54a4e4a0 --- /dev/null +++ b/twin4/hi48-app-twin4.png diff --git a/twin4/hi64-app-twin4.png b/twin4/hi64-app-twin4.png Binary files differnew file mode 100644 index 00000000..69911333 --- /dev/null +++ b/twin4/hi64-app-twin4.png diff --git a/twin4/index.html b/twin4/index.html new file mode 100644 index 00000000..13d28255 --- /dev/null +++ b/twin4/index.html @@ -0,0 +1,213 @@ +<HTML> +<HEAD> +<META HTTP-ETQUIV="Content-Type" CONTENT="text/html";> + +<TITLE>Four wins manual</TITLE> +</HEAD> +<BODY LINK="#0000ff" VLINK="#800080" TEXT="#000000" BGCOLOR="#ffffff"> + + +<h1> Four wins</h1> +</B> </FONT><P> </P> +<B> How do you play "four wins" ? </B> + +<P> +Four wins is a game for two player. +Each player is represented by a colour (yellow and red). +The goal of the game is to get four connected pieces of your +colour into a row, column or any diagonal. +This is done by placing one of your pieces into any of the +seven columns. +A piece will begin to fill a column from the bottom, i.e. it +will fall down until it reaches the ground level or another stone. +After a move is done it is the turn of the other player. This is +repeated until the game is over, i.e. one of the players has +four pieces in a row, column or diagonal or no more moves are possbile +because the board is filled. +</P> + +<p> <p> +<B> The board </B> +<P>The board is separated into three regions.</P> + +<UL> +<LI>The game board:<BR> +It is constructed out of 7x6 fields which will be filled from bottom +to top. The fields are marked in the colour of the player who made the +current move.<BR> +On top of each column a coloured arrow shows were the last piece had been +put. +<br> +</LI> +<LI>The status display:<BR> +The status display shows which player colour starts and which colour is +played by whom (player,computer,remote connection). It further shows the +level of the computer opponent, the number of moves done as well as the +computer calculated chance of winning. This chance is calculated only if +the computer opponent makes a move. A positive number means that the player +has an advantage, a negative number means that the computer thinks +he is better. +<br> +</LI> +<LI>The table display:<BR> +Here the number of won, lost and drawn games is noted for both player. +Also the number of aborted games (Brk) and the sum of games is shown. +<br> +</LI> +</UL> + +<p> <p> +<B> The File menu</B> +<P> + +<UL> +<LI>New game<BR> +Start a new game. <br> +</LI> +<LI>End Game<BR> +Immediately end a game. This will raise the break counter in the statistics +by one.<br> +</LI> +<LI>Statistics<BR> +Show the all time statistic of all games. This will be saved, +but can be cleared in this menu as well.<br> +</LI> +<LI>Send remote message...:<BR> +Opens a dialog window which lets you send a message to a remote player. +<br> +</LI> +<LI>Hint<BR> +The computer will calculate the best possible move and mark it with a small +circle on the board. +How good the move is depends on the level of the computer.<br> +</LI> +<LI>Exit<BR> +Exit the program and save all statistical data +<br> +</LI> +</UL> + + + +<p> <p> +<B>The Edit menu</b> +<P> + +<UL> +<LI>Undo move<BR> +Undo the last move. If the previous player is played by the computer +two moves are taken back so that it is the player's turn again.<br> +</LI> +<LI>Redo move<BR> +Replay a move which had been undone. +<br> +</LI> +</UL> + +<p> <p> +<B>The View menu</b> +<P> + +<UL> +<LI>Show statusbar<BR> +Displays the status bar +<br> +</LI> +</UL> + + +<p> <p> +<B> The Options menu </b> +<p> +<UL> +<LI>Startcolour<BR> +Determines which colour has the first move.<br> +</LI> +<LI>Yellow played by<BR> +Choose here who shall play for the yellow side. This can either be +the local player, the computer or a remote player. Connecting to +a remote host will pop up a conenction dialog which is explained +later.<br> +During game only the player who is not moving can be changed. +<br> +</LI> +<LI>Red played by<BR> +This is analogous to the yellow side. It is possible that there are +two local players just as the computer can take both local players. +Only one remote player is possible though. If the client does +not choose one remote player he will be asked as soon as a connection +is built. It <b>does not matter</b> what colour the remote side +chooses. If both remote parties choose to play the same colour the +computer will handle this and transform the other players colour +appropriately! +<br> +</LI> +<LI>Level<BR> +The level determines who well the computr plays. A higher level makes +the computer play better but think longer. For levels larger than 5 or 6 +you need a fast computer! +<br> +</LI> +<LI>Change Names<BR> +Change the names of the two players. The names will be saved and reloaded +in the next game! +<br> +</LI> +<LI>Network server<BR> +If this menu item is selected your computer tries to behave as +game network server. This is of course only of any importance if +you are doing a network game. +Only the computer acting as server will be able to start a new game +or transfer a started game to the client's side. +<br> +If both computers want to be server or none of them it is randomly +selected. +<br> +</LI> +</UL> + +<p> <p> +<B> The Help menu </B> + <P>This menu displays the help text as well as information +about the program and the operation system.</P> + + +<p> <p> +<B> Remote connections </B> +<P> + +It is possible to play the game over a network connection +with another computer. To do so both player on both computers +have to select one colour played by a human player and the +other by the remote player. Who chooses which colour does not +matter. It even does not matter if both choose to play the same +colour as this will transparentely be interchanged by the game. +<p> +One of the computers will act as game server. Only this one can +start a nbew network game. Also all its game data will be transfered +to the client computer. This includes games already in play - this +means a remote player can join a game already begun. Who will be +server can be selected by the <i>network server</i> menu item in +the options menu. If both choose to be server or client the game +randomly selects one. +<p> + +When a network connection is build you are ask to enter a remote +host and a port. The port can usually just been left untouched. But +if you now what you do replace it by another number, which has to +be the same in both player games of course. The hostname should be +the name of the remote host to which you are connecting. Only one +of the two players has to supply a hostname, the other one need not +to, but can. +<p> + + + +<P> + +<p> +<hr> +<B>Author: </B> +<P>© 1995-2000 Martin Heni (martin@heni-online.de)</P> +<FONT SIZE=2></FONT></BODY> +</HTML> diff --git a/twin4/install-sh b/twin4/install-sh new file mode 100755 index 00000000..67c94290 --- /dev/null +++ b/twin4/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f "$src" -o -d "$src" ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd "$src" $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/twin4/twin4.desktop b/twin4/twin4.desktop new file mode 100644 index 00000000..c4a3edfa --- /dev/null +++ b/twin4/twin4.desktop @@ -0,0 +1,94 @@ +[Desktop Entry] +Name=KWin4 +Name[af]=Kwin4 +Name[be]=Перамога чатырох +Name[bn]=কে-উইন-ফোর +Name[de]=Vier gewinnt +Name[eo]=Kvar venkas +Name[es]=Kwin4 +Name[hi]=के-विन4 +Name[hu]=Négy a nyerő +Name[is]=Kwin4 +Name[nds]=Veer winnt +Name[ne]=केडीई विन ४ +Name[sv]=Kwin4 +Name[ta]=Kவிண்4 +Name[tg]=K4 Ғолиб мешавад +Name[th]=เรียงหมาก 4 - K +Name[tr]=4 Kazanır +Name[zu]=I-KWin4 +GenericName=Strategy Game +GenericName[af]=Strategie Speletjie +GenericName[ar]=لعبة استراتيجية +GenericName[be]=Стратэгічная гульня +GenericName[bg]=Морски шах +GenericName[bn]=কৌশলের খেলা +GenericName[br]=C'hoari a gadouriezh +GenericName[bs]=Strateška igra +GenericName[ca]=Joc d'estratègia +GenericName[cs]=Strategická hra +GenericName[cy]=Gêm Strategaeth +GenericName[da]=Strategispil +GenericName[de]=Strategiespiel +GenericName[el]=Παιχνίδι στρατηγικής +GenericName[eo]=Strategiludo +GenericName[es]=Juego de estrategia +GenericName[et]=Strateegiamäng +GenericName[eu]=Estrategia jokoa +GenericName[fa]=بازی Strategy +GenericName[fi]=Strategiapeli +GenericName[fo]=Strategispæl +GenericName[fr]=Jeu de stratégie +GenericName[ga]=Cluiche Straitéise +GenericName[gl]=Xogo de estratexia +GenericName[he]=משחק אסטרטגיה +GenericName[hi]=कौशल का खेल +GenericName[hr]=Igra strategije +GenericName[hu]=Stratégiai +GenericName[is]=Herkænskuleikur +GenericName[it]=Gioco di strategia +GenericName[ja]=戦略ゲーム +GenericName[km]=ល្បែងយុទ្ធសាស្ត្រ +GenericName[ko]=우주 전략 게임 +GenericName[lt]=Strateginis žaidimas +GenericName[lv]=Stratēģiskā Game +GenericName[mk]=Стратешка игра +GenericName[mt]=Logħba ta' strateġija +GenericName[nb]=Strategispill +GenericName[nds]=Strategiespeel +GenericName[ne]=रणनीति खेल +GenericName[nl]=Strategisch spel +GenericName[nn]=Strategispel +GenericName[pa]=ਨੀਤੀ ਖੇਡ +GenericName[pl]=Gra strategiczna +GenericName[pt]=Jogo de Estratégia +GenericName[pt_BR]=Jogo de Estratégia +GenericName[ro]=Joc de strategie +GenericName[ru]=Четыре побеждают +GenericName[rw]=Umukino w'Ingamba +GenericName[se]=Strategiijaspeallu +GenericName[sk]=Strategická hra +GenericName[sl]=Strateška igra +GenericName[sr]=Стратешка игра +GenericName[sr@Latn]=Strateška igra +GenericName[sv]=Strategispel +GenericName[ta]=தந்திர விளையாட்டு +GenericName[tg]=Бозии Стратегӣ +GenericName[th]=เกมกลยุทธ์ +GenericName[tr]=Strateji Oyunu +GenericName[uk]=Стратегічна гра "Чотири виграють" +GenericName[uz]=Strategiya oʻyini +GenericName[uz@cyrillic]=Стратегия ўйини +GenericName[ven]=Mutambo wa Maitele +GenericName[wa]=Djeu di stratedjeye +GenericName[xh]=Indlela yokudlala umdlalo +GenericName[zh_CN]=策略游戏 +GenericName[zh_TW]=策略遊戲 +GenericName[zu]=Umdlalo wamaqhinga +Exec=twin4 +Icon=twin4 +MimeType= +Terminal=false +Type=Application +DocPath=twin4/index.html +Categories=Qt;KDE;Game;BoardGame; diff --git a/twin4/twin4.kdelnk b/twin4/twin4.kdelnk new file mode 100644 index 00000000..5e56dc47 --- /dev/null +++ b/twin4/twin4.kdelnk @@ -0,0 +1,24 @@ +# KDE Config File +[KDE Desktop Entry] +Type=Application +Exec=twin4 -caption "%c" %i %m +Icon=twin4.xpm +MiniIcon=twin4.xpm +DocPath=twin4/index.html +Comment= +Terminal=0 +Name=Kwin4 +Name[be]=Перамога чатырох +Name[bn]=কে-উইন-ফোর +Name[de]=Vier gewinnt +Name[eo]=Kvar venkas +Name[hi]=के-विन4 +Name[hu]=Négy a nyerő +Name[it]=KWin4 +Name[nds]=Veer winnt +Name[nl]=Vier op een rij +Name[sl]=Štiri v vrsto +Name[ta]=Kவிண்4 +Name[tg]=K4 ғолиб мешавад +Name[th]=เรียงหมาก 4 - K +Name[zu]=I-Kwin4 diff --git a/twin4/twin4.lsm b/twin4/twin4.lsm new file mode 100644 index 00000000..0f4ace19 --- /dev/null +++ b/twin4/twin4.lsm @@ -0,0 +1,14 @@ +Begin3 +Title: Kwin4 +Version: 0.9 +Entered-date: +Description: A small game for the KDE 2 desktop +Keywords: four wins,game,computer,network,kde +Author: Martin Heni <martin@heni-online.de> +Maintained-by: Martin Heni <martin@heni-online.de> +Primary-site: +Home-page: http://www.heni-online.de/linux +Original-site: +Platforms: Linux and other Unices +Copying-policy: GNU Public License +End diff --git a/twin4/twin4/AboutDlg.kdevdlg b/twin4/twin4/AboutDlg.kdevdlg new file mode 100644 index 00000000..08ad214a --- /dev/null +++ b/twin4/twin4/AboutDlg.kdevdlg @@ -0,0 +1,138 @@ +// KDevelop Dialog Editor File (.kdevdlg) +// +// Created by KDlgEdit Version 0.1alpha (C) 1999 by Pascal Krahmer +// Get KDevelop including KDlgEdit at "www.beast.de/kdevelop" +// +data Information +{ + Filename="/home/martin/mgames/twin4/twin4/AboutDlg.kdevdlg" + KDevelopVersion="1.1" + DlgEditVersion="0.1alpha" + LastChanged="Mon Apr 17 09:29:55 2000" +} + +data SessionManagement +{ + OpenedRoot_1="Appearance" + OpenedRoot_2="C++ Code" + OpenedRoot_3="General" + OpenedRoot_4="Geometry" + OpenedRootCount="4" +} + +item QWidget +{ + Name="KWin4" + VarName="this" + X="0" + Y="0" + Width="320" + Height="290" + MinWidth="0" + MinHeight="0" + + item QGroupBox + { + Name="NoName" + VarName="QGroupBox_1" + X="20" + Y="10" + Width="280" + Height="230" + MinWidth="0" + MinHeight="0" + + item QLabel + { + Name="NoName" + VarName="QLabel_1" + X="10" + Y="90" + Width="260" + Height="40" + MinWidth="0" + MinHeight="0" + Text="Mail: martin@heni-online.de" + } + + item QLabel + { + Name="NoName" + VarName="QLabel_7" + X="160" + Y="10" + Width="90" + Height="30" + MinWidth="0" + MinHeight="0" + Text="Four wins" + } + + item QLabel + { + Name="NoName" + VarName="QLabel_2" + X="10" + Y="10" + Width="120" + Height="70" + MinWidth="0" + MinHeight="0" + BgPixmap=*mPixmap + } + + item QLabel + { + Name="NoName" + VarName="QLabel_8" + X="10" + Y="70" + Width="200" + Height="25" + MinWidth="0" + MinHeight="0" + Text="(c) 1995-2000 by Martin Heni" + } + + item QLabel + { + Name="NoName" + VarName="QLabel_5" + X="10" + Y="120" + Width="260" + Height="100" + MinWidth="0" + MinHeight="0" + Text="Gamefeatures:\n- Multiplayer network game\n- Computerplayer with ten levels\n\nThanks to Laura for betatesting!\n" + } + + item QLabel + { + Name="NoName" + VarName="QLabel_11" + X="160" + Y="40" + Width="100" + Height="30" + MinWidth="0" + MinHeight="0" + Text="Version 0.9" + } + + } + + item QPushButton + { + Name="NoName" + VarName="QPushButton_1" + HasFocus="true" + X="110" + Y="250" + Width="100" + Height="30" + MinWidth="0" + MinHeight="0" + Text="Ok" + } +} diff --git a/twin4/twin4/Makefile.am b/twin4/twin4/Makefile.am new file mode 100644 index 00000000..eda2b55f --- /dev/null +++ b/twin4/twin4/Makefile.am @@ -0,0 +1,28 @@ + +bin_PROGRAMS = twin4 twin4proc +twin4_SOURCES = main.cpp twin4.cpp twin4view.cpp twin4doc.cpp \ + twin4player.cpp kspritecache.cpp \ + scorewidget.cpp prefs.kcfgc settings.ui statistics.ui statuswidget.ui + +twin4_LDADD = $(LIB_KFILE) $(LIB_TDEGAMES) +twin4_DEPENDENCIES = $(LIB_TDEGAMES_DEP) + +twin4proc_SOURCES = twin4proc.cpp +twin4proc_LDADD = $(LIB_KFILE) $(LIB_TDEGAMES) +twin4proc_DEPENDENCIES = $(LIB_TDEGAMES_DEP) + +INCLUDES = -I$(top_srcdir)/libtdegames -I$(top_srcdir)/libtdegames/kgame $(all_includes) + +METASOURCES = AUTO + +rcdir = $(kde_datadir)/twin4 +rc_DATA = twin4ui.rc + +twin4_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -lktexteditor +twin4proc_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -lktexteditor + +kde_kcfg_DATA = twin4.kcfg + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/twin4.pot + diff --git a/twin4/twin4/kspritecache.cpp b/twin4/twin4/kspritecache.cpp new file mode 100644 index 00000000..bd55c418 --- /dev/null +++ b/twin4/twin4/kspritecache.cpp @@ -0,0 +1,812 @@ +/*************************************************************************** + Kwin4 - Four in a Row for KDE + ------------------- + begin : March 2000 + copyright : (C) 1995-2001 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "kspritecache.h" + +#include <kconfig.h> +#include <tqbitmap.h> +#include <tqimage.h> +#include <tqwmatrix.h> +#include <tqdir.h> +#include <kdebug.h> + +// KSprite +#include <math.h> + +KSpriteCache::KSpriteCache(TQString grafixdir, TQObject* parent,const char * name) + : TQObject(parent,name) +{ + kdDebug(11002) << "KSpriteCache:: grafixdir=" << grafixdir << endl; + mConfig=0; + mCanvas=0; + setRcFile(TQString("grafix.rc")); + setGrafixDir(grafixdir); + kdDebug(11002) << "Grafixdir=" << grafixDir() << " rcfile=" << rcFile() << endl; + reset(); +} + +KSpriteCache::~KSpriteCache() +{ + kdDebug(11002) << "KSpriteCache: ItemDict=" << mItemDict.count() << endl; + kdDebug(11002) << "KSpriteCache: CloneDict=" << mCloneDict.count() << endl; + reset(); + delete mConfig; +} + +void KSpriteCache::setRcFile(TQString name) +{ + mRcFile=name; +} +bool KSpriteCache::setGrafixDir(TQString name) +{ + delete mConfig; + + TQDir dir(name); + TQString d; + d=dir.absPath()+TQString("/"); + TQString file=d+rcFile(); + + // TODO check for filename + kdDebug(11002) << "Opening config " << file << endl; + mConfig=new KConfig(file,false,false); + mGrafixDir=d; + return true; +} + +void KSpriteCache::reset() +{ + mItemDict.setAutoDelete(false); + mCloneDict.setAutoDelete(false); + mItemDict.clear(); + mCloneDict.clear(); +} + + +void KSpriteCache::deleteAllItems() +{ + TQDictIterator<TQCanvasItem> it( mItemDict ); + //kdDebug(11002) << "KSpriteCache::deleteAllItems items in cache=" << mItemDict.size() << endl; + while ( it.current() ) + { + TQCanvasItem *item=it.current(); + mItemDict.remove(it.currentKey()); + delete item; + } +} +void KSpriteCache::deleteItem(TQString s,int no) +{ + TQCanvasItem *item; + TQString name=s+TQString("_%1").tqarg(no); + //kdDebug(11002) << "KSpriteCache::deleteItem name=" << name << endl; + item=mItemDict[name]; + if (item) + { + mItemDict.remove(name); +// kdDebug(11002) << "deleteitem "<<name<<" as sprite="<<item<<endl; + delete item; + } +} + +void KSpriteCache::deleteItem(TQCanvasItem *item) +{ + TQDictIterator<TQCanvasItem> it( mItemDict ); + while ( it.current() ) + { + if (item==it.current()) + { + // kdDebug(11002) << "KSpriteCache::deleteitem sprite="<<item<<" it="<<it.currentKey()<<endl; + mItemDict.remove(it.currentKey()); + delete item; + return ; + } + ++it; + } +} + + + +TQCanvasItem *KSpriteCache::getItem(TQString name,int no) +{ + + TQString dictname=name+TQString("_%1").tqarg(no); + TQCanvasItem *item=mItemDict[dictname]; + //kdDebug(11002) << " -> getItem("<<name<<","<<no<<") =>"<<dictname<<endl; + // Directly found item + if (item) + { + //kdDebug(11002) << "found item "<<dictname<<" as directly existing "<<item << endl; + return item; + } + + item=mCloneDict[name]; + // load item + if (!item) + { + // Now first time load the items + if (!mConfig->hasGroup(name)) + { + kdError() << "Item "<<name <<" not defined! " <<endl; + return 0; + } + mConfig->setGroup(name); + item=loadItem(mConfig,name); + // kdDebug(11002) << "Inserting sprite="<<item << " as " << name << " into CloneDict"<< endl; + mCloneDict.insert(name,item); + } + + // Clone new item + item=cloneItem(item); + mItemDict.insert(dictname,item); + // kdDebug(11002) << "Inserting sprite="<<item << " as " << dictname << " into ItemDict"<< endl; + + return item; +} +TQPixmap * KSpriteCache::loadPixmap(TQString file,TQString mask,TQString dir) +{ + TQPixmap *newP=new TQPixmap; + bool result1=false; + bool result2=false; + if (dir.isNull()) dir=grafixDir(); // default dir + if (!file.isNull()) + { + result1=newP->load(dir+file); + } + if (result1 && !mask.isNull()) + { + TQBitmap bitmask; + if (mask==TQString("auto")) // self mask..slow but quick to create + { + newP->setMask( newP->createHeuristicMask() ); + result2=true; + } + else + { + result2=bitmask.load(dir+mask); + if (result2) newP->setMask(bitmask); + } + } + //kdDebug(11002) << "KSpriteCache::loadPixmap: file="<<file<<" mask="<<mask<<" result1="<<result1<<" result2="<<result2<<endl; + return newP; +} + + + +TQCanvasPixmapArray *KSpriteCache::createPixmapArray(KConfig *config,TQString name) +{ + config->setGroup(name); + TQPoint defaultoffset=TQPoint(0,0); + // offset for the sprite + TQPoint offset=config->readPointEntry("offset",&defaultoffset); + + // operatins to perform. Can be ommited if you want only one operation + TQStringList operationList=config->readListEntry("pixmaps"); + // Append default entry (empty string) + if (operationList.count()==0) + { + operationList.append(TQString()); + } + + + // Prepare for the reading of the pixmaps + TQPixmap *pixmap=0; + TQPtrList<TQPixmap> pixlist; + pixlist.setAutoDelete(true); + TQPtrList<TQPoint> hotlist; + hotlist.setAutoDelete(true); + + // work through the operations list and create pixmaps + for ( TQStringList::Iterator it = operationList.begin(); it !=operationList.end(); ++it ) + { + TQString name=*it; + // Try to find out what we want to do, e.g. load, scale, ... + TQString type=config->readEntry(name+"method"); + if (type.isNull()) type=TQString("load"); // default load + //kdDebug(11002) << " Processing operation " << (name.isNull()?"default":name) << "type="<<type << endl; + + unsigned int number=config->readNumEntry(name+"number",1); + //kdDebug(11002) << " Reading " << number << " frames " << endl; + + TQString pixfile=config->readPathEntry(name+"file"); + TQString maskfile=config->readPathEntry(name+"mask"); + + // Load a given set of images or replace a %d by a sequence if there are + // less image names than number given + if (type==TQString("load")) + { + // Read images + for (unsigned int i=0;i<number;i++) + { + TQString tmpfile,tmpmask; + tmpfile.sprintf(pixfile.latin1(),i); + tmpmask.sprintf(maskfile.latin1(),i); + + pixmap=loadPixmap(tmpfile,tmpmask); + if (!pixmap) kdError() << "Could not create pixmap="<<tmpfile << " with mask " << tmpmask << endl; + else + { + applyFilter(pixmap,config,name); + + pixlist.append(pixmap); + TQPoint *copyoffset=new TQPoint(-offset); + hotlist.append(copyoffset); + } + } + } + // Scale some images in given axis + else if (type==TQString("scale")) + { + // scale images + int axis=config->readNumEntry(name+"axis",0); + double finalscale=config->readDoubleNumEntry(name+"final",0.0); + double step; + if (number>1) step=(100.0-finalscale)/100.0/(double)(number-1); + else step=1.0; + //kdDebug(11002) << " Scaling " << number << " pics axis="<<axis<<" final="<<finalscale<<" file="<<pixfile<< " mask="<<maskfile<<endl; + + pixmap=loadPixmap(pixfile,maskfile); + for (unsigned int j=0;j<(unsigned int)number;j++) + { + TQWMatrix matrix; + double sc=1.0-(double)(j)*step; + + // scale it + if (axis==1) matrix.scale(sc,1.0); + else if (axis==2) matrix.scale(1.0,sc); + else matrix.scale(sc,sc); + + TQPixmap *copypixmap=new TQPixmap(pixmap->xForm(matrix)); + + applyFilter(copypixmap,config,name); + + pixlist.append(copypixmap); + TQPoint *copyoffset=new TQPoint((-pixmap->width()+copypixmap->width())/2,(-pixmap->height()+copypixmap->height())/2); + hotlist.append(copyoffset); + } + delete pixmap; + + } + else + { + kdDebug(11002) << "WARNING: Unknown algorithm " << type << " for " << name << " not supported " << endl; + } + }// end create images + + //kdDebug(11002) <<"Pixarray count="<<pixlist.count()<<endl; + if (pixlist.count()<1) return 0; + + TQCanvasPixmapArray *pixmaparray=new TQCanvasPixmapArray(pixlist,hotlist); + return pixmaparray; +} + +void KSpriteCache::applyFilter(TQPixmap *pixmap,KConfig *config,TQString name) +{ + TQValueList<int> filterList; + filterList=config->readIntListEntry(name+"colorfilter"); + TQValueList<int> transformList; + transformList=config->readIntListEntry(name+"transformfilter"); + + // apply transformation filter + if (transformList.count()>0) + { + if (transformList[0]==1 && transformList.count()==2) // rotate + { + TQWMatrix rotate; + rotate.rotate(transformList[1]); + *pixmap=pixmap->xForm(rotate); + } + else if (transformList[0]==2 && transformList.count()==3) // scale + { + TQWMatrix scale; + scale.scale((double)transformList[1]/100.0,(double)transformList[2]/100.0); + *pixmap=pixmap->xForm(scale); + } + } + // apply colorfilter + if (filterList.count()>0) + { + // Only filter 1 HSV and 2: grey are implemented + if (filterList[0]==1 && filterList.count()==4) changeHSV(pixmap,filterList[1],filterList[2],filterList[3]); + else if (filterList[0]==2 && filterList.count()==2) changeGrey(pixmap,filterList[1]); + else if (filterList[0]==2 && filterList.count()==1) changeGrey(pixmap); + else kdWarning(11002) << "WARNING: Colorfilter parameter incorrect "<< endl; + } +} + +void KSpriteCache::changeHSV(TQPixmap *pixmap,int dh,int ds,int dv) +{ + if (!pixmap || (dh==0 && ds==0 && dv==0)) return ; + if (pixmap->isNull()) return ; + if (pixmap->width()==0 && pixmap->height()==0) return ; + + int h,s,v; + TQColor black=TQColor(0,0,0); + TQImage img=pixmap->convertToImage(); // slow + + for (int y=0;y<img.height();y++) + { + for (int x=0;x<img.width();x++) + { + TQRgb pix=img.pixel(x,y); + TQColor col(pix); + col.hsv(&h,&s,&v); + if (col==black) continue; // speed up? + h=((unsigned int)(h+dh))%360; + s=((unsigned int)(s+ds)%256); + v=((unsigned int)(v+dv)%256); + col.setHsv(h,s,v); + img.setPixel(x,y,tqRgba(col.red(),col.green(),col.blue(),tqAlpha(pix))); + } + } + pixmap->convertFromImage(img); // slow +} +void KSpriteCache::changeGrey(TQPixmap *pixmap,int lighter) +{ + if (!pixmap) return ; + if (pixmap->isNull()) return ; + if (pixmap->width()==0 && pixmap->height()==0) return ; + + TQImage img=pixmap->convertToImage(); // slow + + for (int y=0;y<img.height();y++) + { + for (int x=0;x<img.width();x++) + { + TQRgb pix=img.pixel(x,y); + int gray=tqGray(tqRed(pix),tqGreen(pix),tqBlue(pix)); + TQColor col(gray,gray,gray); + if (lighter>0) col=col.light(lighter); + if (lighter<0) col=col.dark(-lighter); + img.setPixel(x,y,tqRgba(col.red(),col.green(),col.blue(),tqAlpha(pix))); + } + } + pixmap->convertFromImage(img); // slow +} + +TQCanvasItem *KSpriteCache::loadItem(KConfig *config,TQString name) +{ + if (!config) return 0; + int rtti=config->readNumEntry("rtti",0); + TQCanvasItem *item=0; + switch(rtti) + { + case TQCanvasItem::Rtti_Text: + { + TQCanvasText *sprite=new TQCanvasText(canvas()); + //kdDebug(11002) << "new CanvasText =" << sprite << endl; + TQString text=config->readEntry("text"); + sprite->setText(text); + TQColor color=config->readColorEntry("color"); + sprite->setColor(color); + TQFont font=config->readFontEntry("font"); + sprite->setFont(font); + item=(TQCanvasItem *)sprite; + configureCanvasItem(config,item); + } + break; + case 32: + { + TQCanvasPixmapArray *pixmaps=createPixmapArray(config,name); + KSprite *sprite=new KSprite(pixmaps,canvas()); + //kdDebug(11002) << "new sprite =" << sprite << endl; + double speed=config->readDoubleNumEntry("speed",0.0); + sprite->setSpeed(speed); + //kdDebug(11002) << "speed=" << sprite->speed() << endl; + createAnimations(config,sprite); + + item=(TQCanvasItem *)sprite; + configureCanvasItem(config,item); + + } + break; + default: + { + kdError() << "KSpriteCache::loadItem: Should create unkwown rtti " << rtti << "...overwrite this function" << endl; + } + break; + } + return item; +} + +TQCanvasItem *KSpriteCache::cloneItem(TQCanvasItem *original) +{ + if (!original) return 0; + int rtti=original->rtti(); + TQCanvasItem *item=0; + switch(rtti) + { + case TQCanvasItem::Rtti_Text: + { + TQCanvasText *sprite=(TQCanvasText *)original; + TQCanvasText *copy=new TQCanvasText(canvas()); + configureCanvasItem(original,(TQCanvasItem *)copy); + copy->setText(sprite->text()); + copy->setColor(sprite->color()); + copy->setFont(sprite->font()); + item=(TQCanvasItem *)copy; + } + break; + case 32: + { + KSprite *sprite=(KSprite *)original; + KSprite *copy=new KSprite(sprite->images(),canvas()); + configureCanvasItem(original,(TQCanvasItem *)copy); + copy->setSpeed(sprite->speed()); + createAnimations(sprite,copy); + item=(TQCanvasItem *)copy; + } + break; + default: + { + kdError() << "KSpriteCache::cloneItem: Should create unkwown rtti " << rtti << "...overwrite this function" << endl; + } + break; + } + return item; +} + + +void KSpriteCache::configureCanvasItem(KConfig *config, TQCanvasItem *sprite) +{ + double x=config->readDoubleNumEntry("x",0.0); + double y=config->readDoubleNumEntry("y",0.0); + double z=config->readDoubleNumEntry("z",0.0); + sprite->setX(x); + sprite->setY(y); + sprite->setZ(z); + //kdDebug(11002) << "x=" << sprite->x() << endl; + //kdDebug(11002) << "y=" << sprite->y() << endl; + //kdDebug(11002) << "z=" << sprite->z() << endl; +} + +void KSpriteCache::configureCanvasItem(TQCanvasItem *original, TQCanvasItem *copy) +{ + copy->setX(original->x()); + copy->setY(original->y()); + copy->setZ(original->z()); +} + + +void KSpriteCache::createAnimations(KSprite *original,KSprite *sprite) +{ + unsigned int no=original->animationCount(); + for (unsigned int i=0;i<no;i++) + { + int start,end,mode,delay; + original->getAnimation(i,start,end,mode,delay); + sprite->createAnimation(i,start,end,mode,delay); + } +} + +void KSpriteCache::createAnimations(KConfig *config,KSprite *sprite) +{ + if (!sprite) return ; + for (int i=0;i<1000;i++) + { + TQString anim=TQString("anim%1").tqarg(i); + if (config->hasKey(anim)) + { + //kdDebug(11002) << "Found animation key " << anim << endl; + TQValueList<int> animList=config->readIntListEntry(anim); + if (animList.count()!=4) + { + kdWarning(11002) << "KSpriteCache::createAnimations:: warning animation parameter " << anim << " needs four arguments" << endl; + } + else + { + sprite->createAnimation(i,animList[0],animList[1],animList[2],animList[3]); + } + } + else + { + break; + } + } +} + + +// ----------------------- KSPRITE -------------------------------- +KSprite::KSprite(TQCanvasPixmapArray* array, TQCanvas* canvas) + :TQCanvasSprite(array,canvas) +{ + mImages=array; + mSpeed=0.0; + mNotify=0; + mAnimationNumber=-1; + mAnimSpeedCnt=0; + mMoveObj=0; + +} + +void KSprite::moveTo(double tx,double ty,double speed) +{ + if (speed>0.0) + { + mSpeed=speed; + } + + //kdDebug(11002) <<"KSprite::moveTo x=" << tx << " y="<<ty<< " speed=" << mSpeed<<endl; + mTargetX=tx; + mTargetY=ty; + if ((fabs(mTargetX-x())+fabs(mTargetY-y())) >0.0) + { + //kdDebug(11002) << " animation on" << endl; + setAnimated(true); + } + else + { + //kdDebug(11002) << " animation NOT on ihn moveTO" << endl; + } +} + +void KSprite::advance(int stage) +{ + if (stage!=1) return ; + if (!isVisible()) return ; + + int emitsignal=0; + bool isMoving=false; + bool isAnimated=true; + + // Animation + // mode 0: no animation + // 1: single shot a->b + // -1: single shot b->a + // 2: cycle a->b->a + // -2: cycle b->a->b + // 3: cycle a->b + // -3: cycle b->a + mAnimSpeedCnt++; + if (mAnimationNumber<0 || mAnimDelay[mAnimationNumber]==0) + { + // nothing to do? + isAnimated=false; + mAnimSpeedCnt=0; + } + if (mAnimationNumber>=0 && mAnimSpeedCnt>=mAnimDelay[mAnimationNumber]) + { + switch(mAnimDirection[mAnimationNumber]) + { + case 1: + if (frame()+1 <= mAnimTo[mAnimationNumber]) setFrame(frame()+1); + else emitsignal=2; + break; + case -1: + if (frame()-1 >= mAnimFrom[mAnimationNumber]) setFrame(frame()-1); + else emitsignal=2; + break; + case 2: + if (mAnimDirection[mAnimationNumber]==mCurrentAnimDir) + { + if (frame()+1 <= mAnimTo[mAnimationNumber]) setFrame(frame()+1); + else + { + mCurrentAnimDir=-mCurrentAnimDir; + if (frame()>0) setFrame(frame()-1); + } + } + else + { + if (frame()-1 >= mAnimFrom[mAnimationNumber]) setFrame(frame()-1); + else + { + mCurrentAnimDir=-mCurrentAnimDir; + if (frame()+1<frameCount()) setFrame(frame()+1); + } + } + break; + case -2: + if (mAnimDirection[mAnimationNumber]==mCurrentAnimDir) + { + if (frame()-1 >= mAnimFrom[mAnimationNumber]) setFrame(frame()-1); + else + { + mCurrentAnimDir=-mCurrentAnimDir; + if (frame()+1<frameCount()) setFrame(frame()+1); + } + } + else + { + if (frame()+1 <= mAnimTo[mAnimationNumber]) setFrame(frame()+1); + else + { + mCurrentAnimDir=-mCurrentAnimDir; + if (frame()>0) setFrame(frame()-1); + } + } + break; + case 3: + if (frame()+1 <= mAnimTo[mAnimationNumber]) setFrame(frame()+1); + else setFrame(mAnimFrom[mAnimationNumber]); + break; + case -3: + if (frame()-1 >= mAnimFrom[mAnimationNumber]) setFrame(frame()-1); + else setFrame(mAnimTo[mAnimationNumber]); + break; + default: //0 + isAnimated=false; + setFrame(0); + } + if (emitsignal) isAnimated=false; + + mAnimSpeedCnt=0; + } + + + + // Movement to target + if (!moveObject() && (fabs(mTargetX-x())+fabs(mTargetY-y())) >0.0 && mSpeed>0.0) + { + isMoving=spriteMove(mTargetX,mTargetY); + if (!isMoving) emitsignal=1; + } + else if (moveObject()) + { + isMoving=moveObject()->spriteMove(mTargetX,mTargetY,this); + if (!isMoving) emitsignal=1; + } + + + // Final checks + if (!isAnimated && !isMoving) + { + //kdDebug(11002) << "Animation over" << endl; + setAnimated(false); + } + + if (mNotify && emitsignal) + { + //kdDebug(11002) << " ADVANCE emits signal " << emitsignal << " for item "<< this << endl; + mNotify->emitSignal((TQCanvasItem *)this,emitsignal); + } +} + +// Generates linear movement to tx,ty +bool KSprite::spriteMove(double tx,double ty) +{ + bool isMoving=false; + double dx,dy; + double vx,vy; + dx=tx-x(); + dy=ty-y(); + vx=0.0; + vy=0.0; + + // first pure x,y movements + if (fabs(dy)<=0.0001) + { + if (dx>0.0) vx=mSpeed; + else if (dx<0.0) vx=-mSpeed; + else vx=0.0; + } + else if (fabs(dx)<=0.0001) + { + if (dy>0.0) vy=mSpeed; + else if (dy<0.0) vy=-mSpeed; + else vy=0.0; + } + else // diagonal + { + double alpha=atan2(dy,dx); + vx=cos(alpha)*mSpeed; + vy=sin(alpha)*mSpeed; + } + + if (fabs(dx)<=fabs(vx) && fabs(dy)<=fabs(vy)) + { + move(tx,ty); + isMoving=false; + } + else if (fabs(dx)<=fabs(vx)) + { + moveBy(dx,vy); + isMoving=true; + } + else if (fabs(dy)<=fabs(vy)) + { + moveBy(vx,dy); + isMoving=true; + } + else + { + moveBy(vx,vy); + isMoving=true; + } + return isMoving; +} + +void KSprite::emitNotify(int mode) +{ + if (!mNotify) return ; + //kdDebug(11002) << " ADVANCE emits DIRECT signal " << mode << " for item "<< this << endl; + mNotify->emitSignal((TQCanvasItem *)this,mode); +} +TQObject *KSprite::createNotify() +{ + if (!mNotify) mNotify=new KSpriteNotify; + mNotify->incRefCnt(); + return (TQObject *)mNotify; +} + +void KSprite::deleteNotify() +{ + if (!mNotify) return ; + mNotify->decRefCnt(); + if (mNotify->refCnt()<=0) + { + //kdDebug(11002) << "REALLY deleting notify" << endl; + delete mNotify; + mNotify=0; + } +} + +KSprite::~KSprite() +{ + delete mNotify; + mNotify=0; +} + +void KSprite::setAnimation(int no) +{ + if ((int)mAnimFrom.count()<=no) + { + kdError(11002) << "KSprite::setAnimation:: Animation " << no << " not defined " << endl; + return ; + } + mAnimationNumber=no; + if (no<0) return ; + mAnimSpeedCnt=0; + mCurrentAnimDir=mAnimDirection[no]; + + // Start frame + if (mCurrentAnimDir>0) setFrame(mAnimFrom[no]); + else if (mCurrentAnimDir<0) setFrame(mAnimTo[no]); + + // animated + if (mCurrentAnimDir!=0 && mAnimTo[no]>=mAnimFrom[no]) setAnimated(true); + else setAnimated(false); + + //kdDebug(11002) << this << " setAnimation("<<no<<") delay="<<mAnimDelay[no]<<" frames="<<mAnimFrom[no]<<"->"<<mAnimTo[no]<<" mode="<<mAnimDirection[no]<<" animated="<<animated()<<endl; +} + +void KSprite::getAnimation(int no,int &startframe,int &endframe,int &mode,int &delay) +{ + if ((int)mAnimFrom.count()<=no) return ; + startframe=mAnimFrom[no]; + endframe=mAnimTo[no]; + mode=mAnimDirection[no]; + delay=mAnimDelay[no]; +} + +void KSprite::createAnimation(int no,int startframe,int endframe,int mode,int delay) +{ + //kdDebug(11002) << this << " createAnimation " << no << endl; + // resize? + if ((int)mAnimFrom.count()<=no) + { + mAnimFrom.resize(no+1); + mAnimTo.resize(no+1); + mAnimDirection.resize(no+1); + mAnimDelay.resize(no+1); + } + mAnimFrom[no]=startframe; + mAnimTo[no]=endframe; + mAnimDirection[no]=mode; + mAnimDelay[no]=delay; + //kdDebug(11002) << "from=" << startframe << " to="<<endframe<<" mode="<<mode<<" delay="<<delay<<endl; +} + +#include "kspritecache.moc" diff --git a/twin4/twin4/kspritecache.h b/twin4/twin4/kspritecache.h new file mode 100644 index 00000000..5a17a8ba --- /dev/null +++ b/twin4/twin4/kspritecache.h @@ -0,0 +1,508 @@ +/*************************************************************************** + kspritecache.h + ------------------- + begin : September 2001 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _KSPRITECACHE_H +#define _KSPRITECACHE_H + +#include <tqcanvas.h> +#include <tqdict.h> + +class KConfig; + +class KSprite; + + /** + * this is an internal class to provide a @ref TQObject to emit + * a signal from a sprite if a notify object is created + * You do not need this directly. + * TODO: Can be part of the KSprite class + **/ + class KSpriteNotify : public TQObject + { + Q_OBJECT + TQ_OBJECT + + public: + KSpriteNotify() :TQObject(0,0) {mRefCnt=0;} + void emitSignal(TQCanvasItem *parent,int mode) {emit signalNotify(parent,mode);} + void incRefCnt() {mRefCnt++;} + void decRefCnt() {mRefCnt--;} + int refCnt() {return mRefCnt;} + signals: + void signalNotify(TQCanvasItem *,int); + private: + int mRefCnt; + }; + + class KSpriteMove + { + public: + KSpriteMove() {} + virtual ~KSpriteMove() {} + virtual bool spriteMove(double ,double ,KSprite *) {return false;} + private: + }; + +/** + * The KSprite class is an advance TQCanvasSprite class which + * is usable with the @ref KSpriteCache. It furthermore contains a + * few useful functions like advanced movement and animations which + * go beyond the TQCanvasSprite versions of them. Also it provides + * a signal which is emitted when movement or animation are finished. + * + * @short The main KDE game object + * @author Martin Heni <martin@heni-online.de> + * + */ +class KSprite : public TQCanvasSprite +{ + public: + /** + * Contructs a KSprite object. It is anlogous to the @ref TQCanvasSprite + * constructor + * + * @param array - the frames of the sprite + * @param canvas - the canvas the sprites lives on + **/ + KSprite(TQCanvasPixmapArray* array, TQCanvas* canvas); + + /** + * Destructs the sprite + **/ + virtual ~KSprite(); + + /** + * The sprites runtime idendification (32) + **/ + int rtti() const {return 32;} + + /** + * returns a pointer to the pixmap array which holds the + * frames of the sprite. + **/ + TQCanvasPixmapArray* images() const {return mImages;} + + /** + * Moves the sprite to the given position with the given speed. + * When it reaches its desitnation a signal is emmited if the + * emmiter @ref createNotify is enabled + * + * @param x - the x coordinate + * @param y - the y coordinate + * @param speed - the speed to move . If zero the last set speed is taken + **/ + void moveTo(double x,double y,double speed=0.0); + + /** + * Generates a linear move to the target tx,ty from the current + * position of the sprite with its set speed @ref setSpeed + * Upon arrival the function returns false to indicate an end of the + * movment. Otherwise true is returned. + * The sprite is moved in this function. + **/ + bool spriteMove(double tx,double ty); + + /** + * The sprites advance function. See the qt @ref QcanvasSprite advance + **/ + void advance(int stage); + + /** + * Sets the speed for the next move. Can be set with moveTo too. + * + * @param v - the speed in pixel per animation cycle + **/ + void setSpeed(double v) {mSpeed=v;} + + /** + * returns the speed + **/ + double speed() {return mSpeed;} + + /** + * returns the notification TQObject. You probably do not need this but + * @ref createNotify instead + **/ + TQObject *notify() {return (TQObject *)mNotify;} + + /** + * Directly emits the notification signal with the given parameter + * + * @param the notification parameter + **/ + void emitNotify(int mode); + + /** + * Creates a notification object. You can connect to it and it will emit + * the signal signalNotify(TQCanvasItem *parent, intmode) when a move or + * animation is finished. + * Example: + * <pre> + * connect(sprite->createNotify(),TQT_SIGNAL(signalNotify(TQCanvasItem *,int)), + * this,TQT_SLOT(moveDone(TQCanvasItem *,int))); + * </pre> + * In the move done function you best delete the notify again with + * @ref deleteNotify + **/ + TQObject *createNotify(); + + /** + * Deletes the sprite notify if it is no longer used. The notify keeps a + * reference count which deletes the TQObject when no reference to it is in + * use. + **/ + void deleteNotify(); + + /** + * Reads the animation parameters into the given variables for the given + * animation. Mostly used by @ref KSpriteCache + * + * @param no - the animation number + * @param startframe - the first frame of the animation + * @param endframe - the last frame of the animation + * @param mode - the mode of the animation see @ref creaetAnimation + * @param delay - the delay in TQCanvas animation cycles between two frames + **/ + void getAnimation(int no,int &startframe,int &endframe,int &mode,int &delay); + + /** + * Creates an animation of the sprite between two frames in one of the + * following modes + * 0: no animation + * 1: single shot a->b + *-1: single shot b->a + * 2: cycle a->b->a + *-2: cycle b->a->b + * 3: cycle a->b + *-3: cycle b->a + * + * The single shot animations will emit the above mentioned signal over the + * notify object if it is created. + * If you load the sprite over the KSpriteCache's config file you need not + * bother about calling this function. + **/ + void createAnimation(int no,int startframe,int endframe,int mode,int delay); + + /** + * Switches on the animation of the given number. Of course it needs to be + * defined beforehand either via loading the sprite with the + * @ref KSpriteCache or be calling @ref createAnimation + * + * @param no - the number of the animation + **/ + void setAnimation(int no); + + /** + * Returns how many different animations are stored + **/ + unsigned int animationCount() {return mAnimFrom.count();} + + void setMoveObject(KSpriteMove *m) {mMoveObj=m;} + KSpriteMove *moveObject() {return mMoveObj;} + + protected: + KSpriteMove *mMoveObj; + + private: + KSpriteNotify *mNotify; + TQCanvasPixmapArray* mImages; + TQByteArray mAnimFrom; + TQByteArray mAnimTo; + TQByteArray mAnimDirection; + TQByteArray mAnimDelay; + + double mTargetX,mTargetY; + double mSpeed; + int mAnimationNumber; + int mAnimSpeedCnt; + int mCurrentAnimDir; +}; + + +/** + * The KSpriteCache class is used to load and cache sprites. Loading + * is done via a @ref KConfig file which contains the definitions of the + * sprite in text form. Usng this approach allows you to tun the sprites + * without chaning the sourcecode of the program. This is especially useful if + * the graphics team is independent of the programmer or if you want to write + * external themes for your game. + * Furhtermore the class keeps sprites in memory so that they are fastly + * reloaded when you use more than one sprite of a given type. + * + * Example: + * <pre> + * # Sprite with three frames and a common mask for them + * # z position given but x,y set manually in the program + * [arrow] + * file=arrow%d.png + * mask=arrow_mask.png + * number=3 + * offset=19,5 + * rtti=32 + * z=9.0 + * + * # Simple sprite which is already positioned correcly. No mask just one file + * [board] + * file=board.png + * rtti=32 + * x=15.0 + * y=40.0 + * z=0.0 + * + * # Sprite with one cyclic (2) animation of 5 frames (0-4) and + * # a slow delay of 8 + * [star] + * anim0=0,4,2,8 + * file=star%d.png + * mask=star%d_mask.png + * number=5 + * offset=19,20 + * rtti=32 + * z=100.0 + * + * </pre> + * + * @todo Support single sprites (only one copy in memory) + * Support more sprite types (currently KSprite and TQCanvasText) + * + * @short The main KDE game object + * @author Martin Heni <martin@heni-online.de> + * + */ +class KSpriteCache : public TQObject +{ + Q_OBJECT + TQ_OBJECT + + public: + /** + * Create a sprite cache. Usuzally you will need one per program only. + * + * @param grafixdir - the directory where the configuration file and the graphics reside + **/ + KSpriteCache(TQString grafixdir, TQObject* parent=0,const char * name=0); + + /** + * Delete the sprite cache + **/ + ~KSpriteCache(); + + /** + * Change the grafichs directory. + * + * @todo this does not flush the cache or so... + **/ + bool setGrafixDir(TQString dir); // dir and load config + + /** + * Change the name of the config file. Its default is <em>grafix.rc</em> + **/ + void setRcFile(TQString file); + + /** + * return the graphics directory + **/ + TQString grafixDir() {return mGrafixDir;} + + /** + * return the rc/configuration file + **/ + TQString rcFile() {return mRcFile;} + + /** + * returns the canvas which belongs to the cache + **/ + TQCanvas *canvas() const {return mCanvas;} + + /** + * sets the canvas belonging to the cache + * + * @todo could be done in the constructor + **/ + void setCanvas(TQCanvas *c) {mCanvas=c;} + + /** + * returns the @ref KConfig configuration file where thegraphical data is + * read. Access to this is necessary if you want to store general game infos + * in theis file to or if you want to read additional sprite data which are + * not read be the default functions. + **/ + KConfig *config() {return mConfig;} + + /** + * Main function to create a sprite. You call this like + * <pre> + * KSprite *sprite=(KSprite *)(yourcahce->getItem("hello",1)); + * if (sprite) sprite->show(); + * </pre> + * Calling this function will load the given sprite from the + * configuration file. Its type is determined by the rtti= entry + * of the section [hello] in that file. Default is a KSprite. + * This file defines all data of the sprite so that you just have to show it. + * Each copy of the sprite gets its own number (1,2,...) + * Note: The sprite is hidden upon creation and you need to show it + * explicitly. + * TODO: What definitions are possible in the rc file + * + * @param name - the name of the sprite resp. the secion in the rc file + * @param no - the unique number of the sprite + * @return sprite - returns the sprite pointer as @ref TQCanvasItem + * + * @todo support call without number argument as single sprite's + * @todo support loading of frame sequence via one big pixmap + * + **/ + TQCanvasItem *getItem(TQString name, int no); + + /** + * This function loads a pixmap from the given file. Optional you can also + * provide a mask file. Also optinal you can provide the directory. Default + * is the directory which is set with this @ref KSpriteCache + **/ + TQPixmap * loadPixmap(TQString file,TQString mask=TQString(),TQString dir=TQString()); + + /** + * Deletes a item form the sprite cache given as a pointer to it + **/ + void deleteItem(TQCanvasItem *item); + + /** + * Same as above but delete the item with the name and number + **/ + void deleteItem(TQString s,int no); + + /** + * Deletes all items in the cache + **/ + void deleteAllItems(); + + protected: + /** + * Loads the default properties for all TQCanvasItems from the given config + * file. This is at the moment + * <pre> + * x=(double) + * y=(double) + * z=(double) + * </pre> + **/ + void configureCanvasItem(KConfig *config,TQCanvasItem *item); + + /** + * Copies the default properties for all TQCanvasItems from another sprite. + * Same as above. + **/ + void configureCanvasItem(TQCanvasItem *original,TQCanvasItem *item); + + /** + * Loads an item with the given name form the given config file. From the + * rtti entry it is determined what type it is and then it is loaded. + **/ + virtual TQCanvasItem *loadItem(KConfig *config,TQString name); + + /** + * Clone the sprite from another sprite, mostly from the copy stored in the + * cache. + **/ + virtual TQCanvasItem *cloneItem(TQCanvasItem *original); + + /** + * Creates a pixmap array for a @ref KSprite from the given config file + * for the sprite with the given name (is the name necessary?). + * Parameters are + * <pre> + * offset=(TQPoint) : The sprites offset (where 0,0 is) + * pixmaps=(TQStringList) : List of operations to create frames (TODO * rename) + * if ommited one operation without name is used + * </pre> + * All following calls have to be preceded by every given string of the + * pixmaps section. If this section is not supplied they can be used without + * prefix but only one frame sequence is created. + * <pre> + * method=(TQString) : load, scale (default=load) + * load: loads number frames from file + * scale: scales number frames from one loaded file + * number=(int) : how many frames to generate + * file=(Qstring) : the filename to load (can contain printf format args + * as %d which are replaced, e.g. file=hello_%d.png + * mask=(TQString) : Same for the mask of the pixmaps + * axis=(int) : (scale only): scale axis (1=x,2=y,3=x+y) + * final=(double) : final scale in percent (default 0.0, i.e. complete scaling) + * colorfilter=1,h,s,v: make a HSV transform of all sprite images + * colorfilter=2 : make it gray (lighter=100 is default) + * colorfilter=2,g : make it gray and lighter (positiv) or darker (negative) + * </pre> + **/ + virtual TQCanvasPixmapArray *createPixmapArray(KConfig *config,TQString name); + + /** + * Reads the animations from the config file and calls the corresponding + * KSprite function to create them. + * <pre> + * anim0=a,b,c,d + * anim1=e,f,g,h + * </pre> + * Where the animations have to to be in sequence starting with 0 (i.e. + * anim0). <em>a</em> is the first frame of the animation. <em>b</em> is + * the last frame of the animation. <em>c</em> is the mode of the animations, + * see @ref KSprite::createAnimation and <em>d</em> is the delay in cycles + * of the qcanvas animnation. + * + * @param config - the config file the sprite is read from + * @param sprite - the sprite whose animations are set + **/ + void createAnimations(KConfig *config,KSprite *sprite); + + /** + * Same as above but to copy the animations from an existing sprite + **/ + void createAnimations(KSprite *original,KSprite *sprite); + + /** + * Change a pixmap to grey values. If the second argument is bigger + * than 100 the pixmap is made lighter and if it less then 100 it is + * made darker too + **/ + virtual void changeGrey(TQPixmap *pixmap,int lighter=100); + + /** + * Change the HAS value of the pixmap by dH, dS and dV + **/ + virtual void changeHSV(TQPixmap *pixmap,int dh,int ds,int dv); + + /** + * Apply the filters as defined in the config file to the sprite name + * (TODO is this argument needed) to the pixmap. + */ + virtual void applyFilter(TQPixmap *pixmap,KConfig *config,TQString name); + + /** + * resets the cache (?) + */ + void reset(); + + protected: + TQDict<TQCanvasItem> mItemDict; // Spritename lookup + TQDict<TQCanvasItem> mCloneDict; // clone Items lookup + + TQString mGrafixDir; + TQString mRcFile; + KConfig *mConfig; + TQCanvas *mCanvas; + +}; + +#endif diff --git a/twin4/twin4/main.cpp b/twin4/twin4/main.cpp new file mode 100644 index 00000000..fbdebf3c --- /dev/null +++ b/twin4/twin4/main.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + Kwin4 - Four in a Row for KDE + ------------------- + begin : March 2000 + copyright : (C) 1995-2001 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kaboutdata.h> + +#include "twin4.h" + +#define KWIN4_VERSION "v1.10" + +static KCmdLineOptions options[] = +{ + { "d", 0, 0}, + { "debug <level>", I18N_NOOP("Enter debug level"), 0 }, + KCmdLineLastOption +}; + +int global_debug; + +int main(int argc, char *argv[]) +{ + global_debug=0; + KAboutData aboutData( "twin4", I18N_NOOP("KWin4"), + KWIN4_VERSION, + I18N_NOOP("KWin4: Two player network game"), + KAboutData::License_GPL, + "(c) 1995-2000, Martin Heni"); + aboutData.addAuthor("Martin Heni",0, "martin@heni-online.de"); + aboutData.addCredit("Laura", I18N_NOOP("Beta testing"), 0); + aboutData.addAuthor("Benjamin Meyer", I18N_NOOP("Code Improvements"), 0); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + + /* command line handling */ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (args->isSet("debug")) + { + global_debug=TQString(args->getOption("debug")).toInt(); + kdDebug(12010) << "Debug level set to " << global_debug << endl; + } + args->clear(); + KApplication app(argc, argv); + KGlobal::locale()->insertCatalogue("libtdegames"); + + if (app.isRestored()) + { + RESTORE(Kwin4App); + } + else + { + Kwin4App *twin4 = new Kwin4App(); + app.setMainWidget(twin4); + twin4->show(); + } + + return app.exec(); +} + diff --git a/twin4/twin4/prefs.kcfgc b/twin4/twin4/prefs.kcfgc new file mode 100644 index 00000000..ad918c2a --- /dev/null +++ b/twin4/twin4/prefs.kcfgc @@ -0,0 +1,7 @@ +# Code generation options for kconfig_compiler +File=twin4.kcfg +#IncludeFiles=defines.h +ClassName=Prefs +Singleton=true +#CustomAdditions=true +#Mutators=Zoom diff --git a/twin4/twin4/scorewidget.cpp b/twin4/twin4/scorewidget.cpp new file mode 100644 index 00000000..7a070322 --- /dev/null +++ b/twin4/twin4/scorewidget.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + twin4 program + ------------------- + begin : Sun Mar 26 12:50:12 CEST 2000 + copyright : (C) |1995-2000 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "scorewidget.h" + +#include "prefs.h" + +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpainter.h> +#include <tqsizepolicy.h> +#include <kdebug.h> +#include <klocale.h> + +#define COL_STATUSBORDER black +#define COL_STATUSFIELD TQColor(130,130,255) +#define COL_STATUSDARK TQColor(0,0,65) +#define COL_STATUSLIGHT TQColor(210,210,255) + +ScoreWidget::ScoreWidget( TQWidget* parent, const char* name, WFlags fl ) + : TQFrame( parent, name, fl ) +{ + setFrameStyle( TQFrame::Box | TQFrame::Raised ); + setLineWidth( 2 ); + setMidLineWidth( 4 ); + + setBackgroundColor( COL_STATUSFIELD ); + + resize( 255, 187 ); + int row=0; + + setCaption( i18n( "Form1" ) ); + //LayoutB = new TQGridLayout( this,4,3,15,5 ); + LayoutB = new TQGridLayout( this); + LayoutB->setSpacing( 3 ); + LayoutB->setMargin( 15 ); + + TextLabel7 = new TQLabel( this, "TextLabel7" ); + setPlayer("-----",0); + TextLabel7->setBackgroundColor( COL_STATUSFIELD ); + TextLabel7->tqsetAlignment(TQt::AlignHCenter); + LayoutB->addMultiCellWidget( TextLabel7, row, row,0,2 ); + row++; + + TextLabel8 = new TQLabel( this, "TextLabel8" ); + TextLabel8->setText( i18n( "vs" ) ); + TextLabel8->setBackgroundColor( COL_STATUSFIELD ); + TextLabel8->tqsetAlignment(TQt::AlignHCenter); + LayoutB->addMultiCellWidget( TextLabel8, row, row,0,2 ); + row++; + + TextLabel9 = new TQLabel( this, "TextLabel9" ); + setPlayer("-----",1); + // TextLabel9->setFrameShape(TQFrame::Box ); + // TextLabel9->setLineWidth(5); + TextLabel9->setBackgroundColor( COL_STATUSFIELD ); + TextLabel9->tqsetAlignment(TQt::AlignHCenter); + LayoutB->addMultiCellWidget( TextLabel9, row, row,0,2 ); + row++; + + TQSpacerItem *Spacer2=new TQSpacerItem(0,16,TQSizePolicy::Preferred,TQSizePolicy::Preferred); + LayoutB->addMultiCell( Spacer2, row, row,0,2 ); + row++; + + TQSpacerItem *Spacer1=new TQSpacerItem(25,0,TQSizePolicy::Preferred,TQSizePolicy::Preferred); + LayoutB->addMultiCell( Spacer1, row, row+2,1,1 ); + + TextLabel1 = new TQLabel( this, "Level" ); + TextLabel1->setText( i18n( "Level" ) ); + TextLabel1->setBackgroundColor( COL_STATUSFIELD ); + LayoutB->addWidget( TextLabel1, row, 0 ); + + TextLabel4 = new TQLabel( this, "L" ); + setLevel(Prefs::level()); + TextLabel4->tqsetAlignment(TQt::AlignRight); + TextLabel4->setBackgroundColor( COL_STATUSFIELD ); + LayoutB->addWidget( TextLabel4, row, 2 ); + + row++; + + + TextLabel2 = new TQLabel( this, "Move" ); + TextLabel2->setText( i18n("number of MOVE in game", "Move" ) ); + TextLabel2->setBackgroundColor( COL_STATUSFIELD ); + LayoutB->addWidget( TextLabel2, row, 0 ); + + TextLabel5 = new TQLabel( this, "M" ); + setMove(0); + TextLabel5->tqsetAlignment(TQt::AlignRight); + TextLabel5->setBackgroundColor( COL_STATUSFIELD ); + LayoutB->addWidget( TextLabel5, row, 2 ); + + row++; + + + TextLabel3 = new TQLabel( this, "Chance" ); + TextLabel3->setText( i18n( "Chance" ) ); + TextLabel3->setBackgroundColor( COL_STATUSFIELD ); + LayoutB->addWidget( TextLabel3, row, 0 ); + + TextLabel6 = new TQLabel( this, "C" ); + setChance(0); + TextLabel6->tqsetAlignment(TQt::AlignRight); + TextLabel6->setBackgroundColor( COL_STATUSFIELD ); + LayoutB->addWidget( TextLabel6, row, 2 ); + + row++; + + TQSpacerItem *Spacer3=new TQSpacerItem(0,8,TQSizePolicy::Preferred,TQSizePolicy::Preferred); + LayoutB->addMultiCell( Spacer3, row, row,0,2 ); + row++; + + + + adjustSize(); +} + +void ScoreWidget::paintEvent( TQPaintEvent * p) +{ + TQPainter paint( this ); + paint.setClipRect(p->rect()); + Paint( &paint, p->rect() ); +} + +void ScoreWidget::Paint(TQPainter *p,TQRect /*cliprect*/) +{ + TQPalette pal; + pal.setColor(TQColorGroup::Light, COL_STATUSLIGHT); + pal.setColor(TQColorGroup::Mid, COL_STATUSFIELD); + pal.setColor(TQColorGroup::Dark, COL_STATUSDARK); + setPalette(pal); + drawFrame(p); +} + +void ScoreWidget::setMove(int i) +{ + TextLabel5->setText( TQString("%1").tqarg(i)); +} + +void ScoreWidget::setLevel(int i) +{ + TextLabel4->setText( TQString("%1").tqarg(i)); +} + +void ScoreWidget::setChance(int i) +{ + if (i==0) + TextLabel6->setText(" ----"); + else if (i>=999) + TextLabel6->setText(i18n("Winner")); + else if (i<=-999) + TextLabel6->setText(i18n("Loser")); + else + TextLabel6->setText(TQString("%1").tqarg(i)); +} + +void ScoreWidget::setPlayer(TQString s,int no) +{ + if (no==0) TextLabel7->setText(s); + else TextLabel9->setText(s); +} + +void ScoreWidget::setTurn(int i) +{ + if (i==0) + { + TextLabel7->setPaletteForegroundColor ( yellow); + TextLabel9->setPaletteForegroundColor (black); + } + else + { + TextLabel9->setPaletteForegroundColor ( red); + TextLabel7->setPaletteForegroundColor (black); + } + TextLabel7->update(); + TextLabel9->update(); +} + +#include "scorewidget.moc" diff --git a/twin4/twin4/scorewidget.h b/twin4/twin4/scorewidget.h new file mode 100644 index 00000000..7d157812 --- /dev/null +++ b/twin4/twin4/scorewidget.h @@ -0,0 +1,46 @@ +#ifndef _SCOREWIDGET_H +#define _SCOREWIDGET_H + +#include <tqframe.h> +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class TQGroupBox; +class TQLabel; + +class ScoreWidget : public TQFrame +{ + Q_OBJECT + TQ_OBJECT + +public: + ScoreWidget( TQWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + void setMove(int i); + void setLevel(int i); + void setChance(int i); + void setPlayer(TQString s,int no); + void setTurn(int i); + +protected: + TQGroupBox* GroupBox1; + TQLabel* TextLabel4; + TQLabel* TextLabel5; + TQLabel* TextLabel6; + TQLabel* TextLabel1; + TQLabel* TextLabel2; + TQLabel* TextLabel3; + TQLabel* TextLabel7; + TQLabel* TextLabel8; + TQLabel* TextLabel9; + +protected: + void paintEvent( TQPaintEvent * ); + void Paint(TQPainter *p,TQRect rect); + void drawBorder(TQPainter *p,TQRect rect,int offset,int width,int mode); + +protected: + TQGridLayout* LayoutB; +}; + +#endif // _SCOREWIDGET_H + diff --git a/twin4/twin4/settings.ui b/twin4/twin4/settings.ui new file mode 100644 index 00000000..c64677c6 --- /dev/null +++ b/twin4/twin4/settings.ui @@ -0,0 +1,248 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>Settings</class> +<widget class="TQWidget"> + <property name="name"> + <cstring>Settings</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>411</width> + <height>319</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQGroupBox" row="0" column="1"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Player Names</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Player 1:</string> + </property> + </widget> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Player 2:</string> + </property> + </widget> + <widget class="TQLineEdit" row="0" column="1"> + <property name="name"> + <cstring>kcfg_Name1</cstring> + </property> + </widget> + <widget class="TQLineEdit" row="1" column="1"> + <property name="name"> + <cstring>kcfg_Name2</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="TQGroupBox" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Computer Difficulty</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Easy</string> + </property> + </widget> + <widget class="TQLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Hard</string> + </property> + <property name="tqalignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="TQSlider" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>kcfg_level</cstring> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="maxValue"> + <number>10</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="value"> + <number>3</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickmarks"> + <enum>Below</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>Change the strength of the computer player.</string> + </property> + </widget> + </grid> + </widget> + <widget class="TQButtonGroup" row="0" column="0"> + <property name="name"> + <cstring>kcfg_Colour1</cstring> + </property> + <property name="title"> + <string>Starting Player Color</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQRadioButton"> + <property name="name"> + <cstring>radioButton1</cstring> + </property> + <property name="text"> + <string>Red</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="TQRadioButton"> + <property name="name"> + <cstring>radioButton2</cstring> + </property> + <property name="text"> + <string>Yellow</string> + </property> + </widget> + </vbox> + </widget> + <widget class="TQButtonGroup" row="1" column="1"> + <property name="name"> + <cstring>kcfg_Input2</cstring> + </property> + <property name="title"> + <string>Red Plays With</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQRadioButton"> + <property name="name"> + <cstring>radioButton6</cstring> + </property> + <property name="text"> + <string>Mouse</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="TQRadioButton"> + <property name="name"> + <cstring>radioButton7</cstring> + </property> + <property name="text"> + <string>Computer</string> + </property> + </widget> + <widget class="TQRadioButton"> + <property name="name"> + <cstring>radioButton8</cstring> + </property> + <property name="text"> + <string>Keyboard</string> + </property> + </widget> + </vbox> + </widget> + <widget class="TQButtonGroup" row="1" column="0"> + <property name="name"> + <cstring>kcfg_Input1</cstring> + </property> + <property name="title"> + <string>Yellow Plays With</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQRadioButton"> + <property name="name"> + <cstring>radioButton3</cstring> + </property> + <property name="text"> + <string>Mouse</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="TQRadioButton"> + <property name="name"> + <cstring>radioButton4</cstring> + </property> + <property name="text"> + <string>Computer</string> + </property> + </widget> + <widget class="TQRadioButton"> + <property name="name"> + <cstring>radioButton5</cstring> + </property> + <property name="text"> + <string>Keyboard</string> + </property> + </widget> + </vbox> + </widget> + <spacer row="3" column="1"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="tqsizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/twin4/twin4/statistics.ui b/twin4/twin4/statistics.ui new file mode 100644 index 00000000..b02e8be6 --- /dev/null +++ b/twin4/twin4/statistics.ui @@ -0,0 +1,249 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>Statistics</class> +<widget class="TQDialog"> + <property name="name"> + <cstring>Statistics</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>439</width> + <height>164</height> + </rect> + </property> + <property name="caption"> + <string>Statistics</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="Line" row="1" column="0" rowspan="1" colspan="6"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <spacer row="5" column="2"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="tqsizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="TQLCDNumber" row="4" column="3"> + <property name="name"> + <cstring>p2_lost</cstring> + </property> + </widget> + <widget class="TQLabel" row="2" column="0" rowspan="2" colspan="1"> + <property name="name"> + <cstring>p1_name</cstring> + </property> + <property name="text"> + <string>Player 1</string> + </property> + </widget> + <widget class="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>Name</cstring> + </property> + <property name="text"> + <string>Name</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLabel" row="0" column="1"> + <property name="name"> + <cstring>won</cstring> + </property> + <property name="text"> + <string>Won</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLCDNumber" row="4" column="2"> + <property name="name"> + <cstring>p2_drawn</cstring> + </property> + </widget> + <widget class="TQLabel" row="0" column="3"> + <property name="name"> + <cstring>lost</cstring> + </property> + <property name="text"> + <string>Lost</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLCDNumber" row="4" column="4"> + <property name="name"> + <cstring>p2_aborted</cstring> + </property> + </widget> + <widget class="TQLCDNumber" row="4" column="5"> + <property name="name"> + <cstring>p2_sum</cstring> + </property> + </widget> + <widget class="TQLabel" row="0" column="5"> + <property name="name"> + <cstring>sum</cstring> + </property> + <property name="text"> + <string>Sum</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLabel" row="0" column="4"> + <property name="name"> + <cstring>aborted</cstring> + </property> + <property name="text"> + <string>Aborted</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLayoutWidget" row="6" column="0" rowspan="1" colspan="6"> + <property name="name"> + <cstring>tqlayout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQPushButton"> + <property name="name"> + <cstring>pushButton1</cstring> + </property> + <property name="text"> + <string>Clear All Statistics</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="tqsizeHint"> + <size> + <width>51</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="TQPushButton"> + <property name="name"> + <cstring>pushButton2</cstring> + </property> + <property name="text"> + <string>&Close</string> + </property> + </widget> + </hbox> + </widget> + <widget class="TQLCDNumber" row="3" column="1"> + <property name="name"> + <cstring>p1_won</cstring> + </property> + </widget> + <widget class="TQLabel" row="4" column="0"> + <property name="name"> + <cstring>p2_name</cstring> + </property> + <property name="text"> + <string>Player 2</string> + </property> + </widget> + <widget class="TQLCDNumber" row="4" column="1"> + <property name="name"> + <cstring>p2_won</cstring> + </property> + </widget> + <widget class="TQLabel" row="0" column="2"> + <property name="name"> + <cstring>drawn</cstring> + </property> + <property name="text"> + <string>Drawn</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLCDNumber" row="3" column="2"> + <property name="name"> + <cstring>p1_drawn</cstring> + </property> + </widget> + <widget class="TQLCDNumber" row="3" column="3"> + <property name="name"> + <cstring>p1_lost</cstring> + </property> + </widget> + <widget class="TQLCDNumber" row="3" column="4"> + <property name="name"> + <cstring>p1_aborted</cstring> + </property> + </widget> + <widget class="TQLCDNumber" row="3" column="5"> + <property name="name"> + <cstring>p1_sum</cstring> + </property> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>pushButton1</sender> + <signal>clicked()</signal> + <receiver>Statistics</receiver> + <slot>reject()</slot> + </connection> + <connection> + <sender>pushButton2</sender> + <signal>clicked()</signal> + <receiver>Statistics</receiver> + <slot>accept()</slot> + </connection> +</connections> +<tabstops> + <tabstop>pushButton2</tabstop> + <tabstop>pushButton1</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/twin4/twin4/statuswidget.ui b/twin4/twin4/statuswidget.ui new file mode 100644 index 00000000..41d6bef5 --- /dev/null +++ b/twin4/twin4/statuswidget.ui @@ -0,0 +1,263 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>StatusWidget</class> +<widget class="TQFrame"> + <property name="name"> + <cstring>StatusWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>304</width> + <height>120</height> + </rect> + </property> + <property name="frameShape"> + <enum>Box</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <property name="margin"> + <number>2</number> + </property> + <property name="midLineWidth"> + <number>4</number> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="4" column="5"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="tqsizeHint"> + <size> + <width>20</width> + <height>41</height> + </size> + </property> + </spacer> + <spacer row="0" column="0"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="tqsizeHint"> + <size> + <width>90</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="TQLabel" row="0" column="1"> + <property name="name"> + <cstring>wins</cstring> + </property> + <property name="text"> + <string>W</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLabel" row="0" column="2"> + <property name="name"> + <cstring>draws</cstring> + </property> + <property name="text"> + <string>D</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLabel" row="0" column="3"> + <property name="name"> + <cstring>loses</cstring> + </property> + <property name="text"> + <string>L</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLabel" row="0" column="4"> + <property name="name"> + <cstring>num</cstring> + </property> + <property name="text"> + <string>No</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLabel" row="0" column="5"> + <property name="name"> + <cstring>bk</cstring> + </property> + <property name="text"> + <string>Bk</string> + </property> + <property name="tqalignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQLabel" row="2" column="0"> + <property name="name"> + <cstring>p1_name</cstring> + </property> + <property name="text"> + <string>Player 1</string> + </property> + </widget> + <widget class="TQLCDNumber" row="2" column="1"> + <property name="name"> + <cstring>p1_w</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="numDigits"> + <number>2</number> + </property> + </widget> + <widget class="TQLCDNumber" row="2" column="2"> + <property name="name"> + <cstring>p1_d</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="numDigits"> + <number>2</number> + </property> + </widget> + <widget class="TQLCDNumber" row="2" column="3"> + <property name="name"> + <cstring>p1_l</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="numDigits"> + <number>2</number> + </property> + </widget> + <widget class="TQLCDNumber" row="2" column="4"> + <property name="name"> + <cstring>p1_n</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="numDigits"> + <number>2</number> + </property> + </widget> + <widget class="TQLCDNumber" row="2" column="5"> + <property name="name"> + <cstring>p1_b</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="numDigits"> + <number>2</number> + </property> + </widget> + <widget class="TQLCDNumber" row="3" column="2"> + <property name="name"> + <cstring>p2_d</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="numDigits"> + <number>2</number> + </property> + </widget> + <widget class="TQLCDNumber" row="3" column="5"> + <property name="name"> + <cstring>p2_b</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="numDigits"> + <number>2</number> + </property> + </widget> + <widget class="TQLCDNumber" row="3" column="3"> + <property name="name"> + <cstring>p2_l</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="numDigits"> + <number>2</number> + </property> + </widget> + <widget class="TQLCDNumber" row="3" column="4"> + <property name="name"> + <cstring>p2_n</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="numDigits"> + <number>2</number> + </property> + </widget> + <widget class="TQLCDNumber" row="3" column="1"> + <property name="name"> + <cstring>p2_w</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="numDigits"> + <number>2</number> + </property> + </widget> + <widget class="TQLabel" row="3" column="0"> + <property name="name"> + <cstring>p2_name</cstring> + </property> + <property name="text"> + <string>Player 2</string> + </property> + </widget> + <widget class="Line" row="1" column="0" rowspan="1" colspan="6"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/twin4/twin4/twin4.cpp b/twin4/twin4/twin4.cpp new file mode 100644 index 00000000..8500c2e6 --- /dev/null +++ b/twin4/twin4/twin4.cpp @@ -0,0 +1,626 @@ +/*************************************************************************** + twin4 - Boardgame for KDE + ------------------- + begin : Sun Mar 26 12:50:12 CEST 2000 + copyright : (C) |1995-2000 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// include files for QT +#include <tqstring.h> +#include <tqlayout.h> +#include <tqhgroupbox.h> +#include <tqvbox.h> +#include <tqradiobutton.h> +#include <tqvbuttongroup.h> +#include <tqlcdnumber.h> + +// include files for KDE +#include <kapplication.h> +#include <kstdgameaction.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <klocale.h> +#include <khelpmenu.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kstdaction.h> +#include <kaction.h> +#include <tqpushbutton.h> +#include <kstatusbar.h> +#include <kconfigdialog.h> + +#include <kchatdialog.h> +#include <kgamechat.h> +#include <dialogs/kgamedialog.h> +#include <dialogs/kgamedialogconfig.h> +#include <dialogs/kgameconnectdialog.h> +#include <dialogs/kgameerrordialog.h> +#include <dialogs/kgamedebugdialog.h> + +// application specific includes +#include "twin4.h" +#include "twin4view.h" +#include "twin4doc.h" +#include "prefs.h" +#include "settings.h" +#include "statistics.h" + +#define ACTION(x) (actionCollection()->action(x)) +#define ID_STATUS_MSG 1003 +#define ID_STATUS_MOVER 1002 + +/** + * Constructor for the chat widget. This widget + * is derived from the libtdegames chat widget + */ +ChatDlg::ChatDlg(KGame *game,TQWidget *parent) + : KDialogBase(Plain,i18n("Chat Dlg"),Ok,Ok,parent,0,false,true),mChat(0), mChatDlg(0) +{ + setMinimumSize(TQSize(200,200)); + + TQGridLayout* mGridLayout=new TQGridLayout(plainPage()); + TQHBoxLayout* h = new TQHBoxLayout(plainPage()); + TQHGroupBox* b = new TQHGroupBox(i18n("Chat"), plainPage()); + mChat = new KGameChat(game, 10000, b); + h->addWidget(b, 1); + h->addSpacing(10); + mGridLayout->addLayout(h,0,0); + + TQPushButton *mButton=new TQPushButton(i18n("Configure..."),plainPage()); + mGridLayout->addWidget(mButton,1,1); + + adjustSize(); + + mChatDlg=new KChatDialog(mChat,plainPage(),true); + connect(mButton,TQT_SIGNAL(clicked()),mChatDlg,TQT_SLOT(show())); +} + +/** + * Set the player in who does the chat. This should be + * the local player. + */ +void ChatDlg::setPlayer(Kwin4Player *p) +{ + if (!mChat) + { + kdError() << "ChatDlg::setPlayer::Chat not defined can't set player" << endl; + return ; + } + if (!p) + { + kdError() << "ChatDlg::setPlayer::Player not defined can't set player" << endl; + return ; + } + mChat->setFromPlayer(p); +} + +/** + * Construct the main application window + */ +Kwin4App::Kwin4App(TQWidget *parent, const char *name) : KMainWindow(parent,name), view(0), doc(0), mChat(0), mMyChatDlg(0) +{ + initGUI(); + initStatusBar(); + initDocument(); + + view = new Kwin4View(doc,this); + doc->setView(view); + setCentralWidget(view); + doc->initPlayers(); + + setMinimumSize(640,400); // TODO + setMaximumSize(800,600); + + setupGUI(); + + doc->ReadConfig(kapp->config()); + + checkMenus(); +} + +/** + * This method is called from various places + * and signals to check, uncheck and enable + * or disable all menu items. + * The menu parameter can limit this operation + * to one or more of the main menues (File,View,...) + */ +void Kwin4App::checkMenus(CheckFlags menu) +{ + bool localgame=(!doc->isNetwork()); + bool isRunning = (doc->gametqStatus()==KGame::Run); + if (!menu || (menu&CheckFileMenu)) + { + changeAction("hint", !(!isRunning && localgame)); + changeAction("new_game", !isRunning); + changeAction("save", isRunning); + changeAction("end_game", isRunning); + } + + if (!menu || (menu&CheckEditMenu)) + { + if (!isRunning || !localgame) + { + disableAction("edit_undo"); + } + else if (doc->QueryHistoryCnt()==0) + { + disableAction("edit_undo"); + } + else if (doc->QueryCurrentMove()<1 ) + { + disableAction("edit_undo"); + } + else + { + enableAction("edit_undo"); + } + + // Show redo + if (!isRunning || !localgame) + { + disableAction("edit_redo"); + } + else if (doc->QueryHistoryCnt()==doc->QueryMaxMove()) + { + disableAction("edit_redo"); + } + else + { + enableAction("edit_redo"); + } + } +} + +/** + * Function to create the actions for the menu. This + * works together with the xml guirc file + */ +void Kwin4App::initGUI() +{ + KStdGameAction::gameNew(TQT_TQOBJECT(this), TQT_SLOT(newGame()), actionCollection(), "new_game"); + ACTION("new_game")->setStatusText(i18n("Start a new game")); + + KStdGameAction::load(TQT_TQOBJECT(this), TQT_SLOT(slotOpenGame()), actionCollection(), "open"); + ACTION("open")->setStatusText(i18n("Open a saved game...")); + + KStdGameAction::save(TQT_TQOBJECT(this), TQT_SLOT(slotSaveGame()), actionCollection(), "save"); + ACTION("save")->setStatusText(i18n("Save a game...")); + + KStdGameAction::end(TQT_TQOBJECT(this), TQT_SLOT(endGame()), actionCollection(), "end_game"); + ACTION("end_game")->setStatusText(i18n("Ending the current game...")); + ACTION("end_game")->setWhatsThis(i18n("Aborts a currently played game. No winner will be declared.")); + + new KAction(i18n("&Network Configuration..."),0, TQT_TQOBJECT(this), TQT_SLOT(slotInitNetwork()), + actionCollection(), "network_conf"); + + new KAction(i18n("Network Chat..."),0, TQT_TQOBJECT(this), TQT_SLOT(slotChat()), + actionCollection(), "network_chat"); + + if (global_debug>0) + new KAction(i18n("Debug KGame"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotDebugKGame()), + actionCollection(), "file_debug"); + + new KAction(i18n("&Show Statistics"),"flag", 0, TQT_TQOBJECT(this), + TQT_SLOT(showStatistics()), actionCollection(), "statistics"); + ACTION("statistics")->setStatusText(i18n("Show statistics.")); + + KStdGameAction::hint(TQT_TQOBJECT(doc), TQT_SLOT(calcHint()), actionCollection(), "hint"); + ACTION("hint")->setStatusText(i18n("Shows a hint on how to move.")); + + KStdGameAction::quit(TQT_TQOBJECT(this), TQT_SLOT(close()), actionCollection(), "game_exit"); + ACTION("game_exit")->setStatusText(i18n("Quits the program.")); + + KStdGameAction::undo(TQT_TQOBJECT(this), TQT_SLOT(slotUndo()), actionCollection(), "edit_undo"); + ACTION("edit_undo")->setStatusText(i18n("Undo last move.")); + + KStdGameAction::redo(TQT_TQOBJECT(this), TQT_SLOT(slotRedo()), actionCollection(), "edit_redo"); + ACTION("edit_redo")->setStatusText(i18n("Redo last move.")); + + actionCollection()->setHighlightingEnabled(true); + connect(actionCollection(), TQT_SIGNAL(actionStatusText(const TQString &)), TQT_SLOT(slotStatusMsg(const TQString &))); + connect(actionCollection(), TQT_SIGNAL(clearStatusText()), TQT_SLOT(slotClearStatusText())); + + KStdAction::preferences(TQT_TQOBJECT(this), TQT_SLOT(showSettings()), actionCollection()); +} + +/** + * Set the status message to Ready + */ +void Kwin4App::slotClearStatusText() +{ + slotStatusMsg(i18n("Ready")); +} + +/** + * Create the status bar with the message part, the + * player part + */ +void Kwin4App::initStatusBar() +{ + statusBar()->insertItem(i18n("This leaves space for the mover"),ID_STATUS_MOVER,0,true); + statusBar()->insertItem(i18n("Ready"), ID_STATUS_MSG); + + slotStatusMover(i18n("(c) Martin Heni ")); + slotStatusMsg(i18n("Welcome to KWin4")); +} + +/** + * Set up the document, i.e. the KGame object + * and connect all signals emitted by it + */ +void Kwin4App::initDocument() +{ + doc = new Kwin4Doc(this); + // Game Over signal + connect(doc,TQT_SIGNAL(signalGameOver(int, KPlayer *,KGame *)), + this,TQT_SLOT(slotGameOver(int, KPlayer *,KGame *))); + connect(doc,TQT_SIGNAL(signalMoveDone(int, int)), + this,TQT_SLOT(slotMoveDone(int, int))); + connect(doc,TQT_SIGNAL(signalClientLeftGame(int, int,KGame *)), + this,TQT_SLOT(slotNetworkBroken(int, int, KGame *))); + connect(doc,TQT_SIGNAL(signalNextPlayer()), + this,TQT_SLOT(slotStatusNames())); + + connect(doc,TQT_SIGNAL(signalGameRun()), + this,TQT_SLOT(slotNewGame())); +} + +void Kwin4App::changeAction(const char *action, bool enable){ + if (!action) + return; + + KAction *act=actionCollection()->action(action); + if (act) + act->setEnabled(enable); +} + +/** + * Store the current game + */ +void Kwin4App::saveProperties(KConfig *cfg) +{ + TQString tempfile = kapp->tempSaveName(TQDir::currentDirPath()+"twin4"); + cfg->writePathEntry("filename", tempfile ); + doc->save(tempfile); +} + +/** + * Load game back + */ +void Kwin4App::readProperties(KConfig* cfg) +{ + TQString filename = cfg->readPathEntry("filename"); + if(!filename.isEmpty()) + doc->load(filename); +} + +/** + * Load a game + */ +void Kwin4App::slotOpenGame() +{ + TQString dir(":<twin4>"); + TQString filter("*"); + TQString file("/tmp/twin.save"); + if (global_debug < 10) + file=KFileDialog::getOpenFileName(dir,filter,this); + doc->load(file,true); + checkMenus(); +} + +/** + * Save game + */ +void Kwin4App::slotSaveGame() +{ + TQString dir(":<twin4>"); + TQString filter("*"); + TQString file("/tmp/twin.save"); + if (global_debug < 10) + file=KFileDialog::getSaveFileName(dir,filter,this); + doc->save(file); +} + +/** + * Start a new game + */ +void Kwin4App::newGame() +{ + // End the intro if it is running + doc->setGametqStatus(Kwin4Doc::End); + // Init the board and Clear the old game out + doc->setGametqStatus(Kwin4Doc::Init); + // Run it + doc->setGametqStatus(Kwin4Doc::Run); +} + +/** + * Slot: Noticed that a new game started...update menues + */ +void Kwin4App::slotNewGame() +{ + slotStatusNames(); + //checkMenus(CheckFileMenu|CheckEditMenu); + checkMenus(All); +} + +/** + * Abort a running game + */ +void Kwin4App::endGame() +{ + doc->setGametqStatus(Kwin4Doc::Abort); +} + +/** + * Show statistics dialog + */ +void Kwin4App::showStatistics() +{ + Statistics *dlg=new Statistics(this,"Game statistics"); + + dlg->p1_name->setText(doc->QueryName(Gelb)); + dlg->p1_won->display(doc->QueryStat(Gelb, TWin)); + dlg->p1_drawn->display(doc->QueryStat(Gelb, TRemis)); + dlg->p1_lost->display(doc->QueryStat(Gelb, TLost)); + dlg->p1_aborted->display(doc->QueryStat(Gelb, TBrk)); + dlg->p1_sum->display(doc->QueryStat(Gelb, TSum)); + + dlg->p2_name->setText(doc->QueryName(Rot)); + dlg->p2_won->display(doc->QueryStat(Rot, TWin)); + dlg->p2_drawn->display(doc->QueryStat(Rot, TRemis)); + dlg->p2_lost->display(doc->QueryStat(Rot, TLost)); + dlg->p2_aborted->display(doc->QueryStat(Rot, TBrk)); + dlg->p2_sum->display(doc->QueryStat(Rot, TSum)); + + if(dlg->exec() == TQDialog::Rejected) + doc->ResetStat(); +} + +/** + * Undo menu call + */ +void Kwin4App::slotUndo() +{ + doc->UndoMove(); + // Undo twice if computer is moving then + if (doc->playedBy(doc->QueryCurrentPlayer())==KGameIO::ProcessIO) + doc->UndoMove(); + + // Prepare menus + slotStatusNames(); + checkMenus(CheckEditMenu); +} + +/** + * Redo menu call + */ +void Kwin4App::slotRedo() +{ + doc->RedoMove(); + if (doc->playedBy(doc->QueryCurrentPlayer())==KGameIO::ProcessIO) + doc->RedoMove(); + slotStatusNames(); + checkMenus(CheckEditMenu); +} + +/** + * Set the given text into the statusbar + * change status message permanently + */ +void Kwin4App::slotStatusMsg(const TQString &text) +{ + statusBar()->clear(); + statusBar()->changeItem(text, ID_STATUS_MSG); +} + +/** + * Set the string in the statusbar window for + * the player currently moving + * change status mover permanently + */ +void Kwin4App::slotStatusMover(const TQString &text) +{ + statusBar()->clear(); + statusBar()->changeItem(text, ID_STATUS_MOVER); +} + +/** + * Ends the current game + * Called by the gameover signal + */ +void Kwin4App::EndGame(TABLE mode) +{ + doc->EndGame(mode); + doc->SwitchStartPlayer(); + slotStatusNames(); + checkMenus(); +} + +/** + * Set the names in the mover field + */ +void Kwin4App::slotStatusNames(){ + TQString msg; + if (!(doc->gametqStatus()==KGame::Run)) + msg=i18n("No game "); + else if (doc->QueryCurrentPlayer()==Gelb) + msg=TQString(" ")+doc->QueryName(Gelb)+ i18n(" - Yellow "); + else if (doc->QueryCurrentPlayer()) + msg=TQString(" ")+doc->QueryName(Rot)+ i18n(" - Red "); + else + msg=i18n("Nobody "); + slotStatusMover(msg); +} + +/** + * The network connection is lost + */ +void Kwin4App::slotNetworkBroken(int /*id*/, int oldstatus ,KGame * /*game */) +{ + kdDebug(12010) << "Kwin4App::slotNetworkBroken" << endl; + if (doc->playedBy(Gelb)==0) + doc->setPlayedBy(Gelb,KGameIO::MouseIO); + if (doc->playedBy(Rot)==0) + doc->setPlayedBy(Rot,KGameIO::MouseIO); + + kdDebug(12010) << "CurrrentPlayer=" << doc->QueryCurrentPlayer() << endl; + kdDebug(12010) << " " << doc->getPlayer(doc->QueryCurrentPlayer()) << endl; + doc->getPlayer(doc->QueryCurrentPlayer())->setTurn(true,true); + + KMessageBox::information(this,i18n("The network game ended!\n")); + doc->setGametqStatus(oldstatus); +} + +/** + * A move is done. update status + */ +void Kwin4App::slotMoveDone(int /* x */ ,int /* y */ ) +{ + checkMenus(CheckEditMenu); + slotStatusNames(); + slotStatusMsg(i18n("Game running...")); +} + +/** + * The game is over or aborted + */ +void Kwin4App::slotGameOver(int status, KPlayer * p, KGame * /*me*/) +{ + if (status==-1) // remis + { + EndGame(TRemis); + slotStatusMsg(i18n("The game is drawn. Please restart next round.")); + } + else if (status==1) + { + if (p->userId()==Gelb) + EndGame(TWin); + else + EndGame(TLost); + TQString msg=i18n("%1 won the game. Please restart next round.").tqarg(doc->QueryName(((FARBE)p->userId()))); + slotStatusMsg(msg); + } + else if (status==2) // Abort + { + EndGame(TBrk); + TQString m=i18n(" Game aborted. Please restart next round."); + slotStatusMsg(m); + } + else + { + kdError() << "Gameover with status " << status << ". This is unexpected and a serious problem" << endl; + } + checkMenus(CheckEditMenu); +} + +void Kwin4App::slotInitNetwork() +{ + if (doc->gametqStatus()==Kwin4Doc::Intro) doc->setGametqStatus(Kwin4Doc::Pause); + + TQString host = Prefs::host(); + int port=Prefs::port(); + + // just for testing - should be non-modal + KGameDialog dlg(doc, 0, i18n("Network Configuration"), this, + KGameDialog::NetworkConfig, 20000, true); + dlg.networkConfig()->setDefaultNetworkInfo(host, port); + dlg.networkConfig()->setDiscoveryInfo("_twin4._tcp",Prefs::gamename()); + + TQVBox *box=dlg.configPage(KGameDialog::NetworkConfig); + TQVBoxLayout *l=(TQVBoxLayout *)(box->tqlayout()); + + mColorGroup=new TQVButtonGroup(box); + connect(mColorGroup, TQT_SIGNAL(clicked(int)), TQT_TQOBJECT(this), TQT_SLOT(slotRemoteChanged(int))); + connect(dlg.networkConfig(), TQT_SIGNAL(signalServerTypeChanged(int)), TQT_TQOBJECT(this), TQT_SLOT(slotServerTypeChanged(int))); + + new TQRadioButton(i18n("Yellow should be played by remote"), mColorGroup); + new TQRadioButton(i18n("Red should be played by remote"), mColorGroup); + l->addWidget(mColorGroup); + mColorGroup->setButton(0); + slotRemoteChanged(0); + + dlg.exec();// note: we don't have to check for the result - maybe a bug +} + +/** + * Arg can't get rid of this function in KGame's current state. + * Can't pass a int signal to a bool slot, so this must be here + */ +void Kwin4App::slotServerTypeChanged(int t) +{ + mColorGroup->setDisabled(t); +} + +/** + * The remove player changed + */ +void Kwin4App::slotRemoteChanged(int button) +{ + if (button==0) + { + doc->getPlayer(Gelb)->setNetworkPriority(0); + doc->getPlayer(Rot)->setNetworkPriority(10); + } + else + { + doc->getPlayer(Gelb)->setNetworkPriority(10); + doc->getPlayer(Rot)->setNetworkPriority(0); + } +} + +void Kwin4App::slotChat() +{ + if (!mMyChatDlg) + { + mMyChatDlg=new ChatDlg(doc,this); + Kwin4Player *p=doc->getPlayer(Gelb); + if (!p->isVirtual()) + mMyChatDlg->setPlayer(doc->getPlayer(Gelb)); + else + mMyChatDlg->setPlayer(doc->getPlayer(Rot)); + connect(doc,TQT_SIGNAL(signalChatChanged(Kwin4Player *)), + mMyChatDlg,TQT_SLOT(setPlayer(Kwin4Player *))); + } + + if (mMyChatDlg->isHidden()) + mMyChatDlg->show(); + else + mMyChatDlg->hide(); +} + +/** + * Show the KGame debug window + */ +void Kwin4App::slotDebugKGame() +{ + KGameDebugDialog* debugWindow = new KGameDebugDialog(doc, this); + debugWindow->show(); +} + +/** + * Show Configure dialog. + */ +void Kwin4App::showSettings(){ + if(KConfigDialog::showDialog("settings")) + return; + + KConfigDialog *dialog = new KConfigDialog(this, "settings", Prefs::self(), KDialogBase::Swallow); + Settings *general = new Settings(0, "General"); + dialog->addPage(general, i18n("General"), "package_settings"); + connect(dialog, TQT_SIGNAL(settingsChanged()), doc, TQT_SLOT(loadSettings())); + dialog->show(); +} + +#include "twin4.moc" diff --git a/twin4/twin4/twin4.h b/twin4/twin4/twin4.h new file mode 100644 index 00000000..20141076 --- /dev/null +++ b/twin4/twin4/twin4.h @@ -0,0 +1,128 @@ +/*************************************************************************** + Kwin4 - Four in a Row for KDE + ------------------- + begin : March 2000 + copyright : (C) 1995-2001 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KWIN4_H +#define KWIN4_H + +#include <kmainwindow.h> +#include <kdialogbase.h> +#include "twin4doc.h" +#include <kdemacros.h> +class Kwin4Player; +class KGameChat; +class KChatDialog; +class Kwin4Doc; +class Kwin4View; +class TQVButtonGroup; +class KPlayer; + +/** + * Subclass of the chat dialog provided by the KGame lib. + * It supports a user defined chat and the setting of the + * owner player + **/ +class KDE_EXPORT ChatDlg : public KDialogBase +{ + Q_OBJECT + TQ_OBJECT +public: + ChatDlg(KGame *game,TQWidget* parent=0); + +public slots: + void setPlayer(Kwin4Player *p); + +private: + KGameChat *mChat; + KChatDialog *mChatDlg; +}; + +/** + * The base class for Kwin4 application window. + */ +class Kwin4App : public KMainWindow +{ + +Q_OBJECT + TQ_OBJECT + +public: + Kwin4App(TQWidget *parent=0, const char *name=0); + +protected: + void EndGame(TABLE mode); + + // Flags which menus should be checked and set by below functions + enum CheckFlags {All=0,CheckFileMenu=1,CheckEditMenu=2}; + + void changeAction(const char *,bool); + // Enabled/Disabled menu/toolbar items + void enableAction(const char *action) {changeAction(action, true); } + void disableAction(const char *action) {changeAction(action, false); } + // Checks all menus..usually done on init programm + void checkMenus(CheckFlags menu=All); + + void initGUI(); + void initStatusBar(); + void initDocument(); + + virtual void saveProperties(KConfig *cfg); + virtual void readProperties(KConfig *cfg); + +public slots: + void slotServerTypeChanged(int t); + + void slotRemoteChanged(int who); + void slotGameOver(int status, KPlayer * p, KGame * me); + void slotMoveDone(int x, int y); + + void slotNetworkBroken(int id, int oldstatus ,KGame *game); + /** Being noticed that a new game started */ + void slotNewGame(); + void slotStatusNames(); + + void slotInitNetwork(); + void slotChat(); + void slotDebugKGame(); + + void newGame(); + void slotOpenGame(); + void slotSaveGame(); + void endGame(); + void showStatistics(); + + void slotUndo(); + void slotRedo(); + + void slotStatusMover(const TQString &text); + void slotStatusMsg(const TQString &text); + +private: + Kwin4View *view; + Kwin4Doc *doc; + + TQVButtonGroup *mColorGroup; + KGameChat *mChat; + ChatDlg *mMyChatDlg; + +protected slots: + void slotClearStatusText(); + + void showSettings(); +}; + +#endif // KWIN4_H + diff --git a/twin4/twin4/twin4.kcfg b/twin4/twin4/twin4.kcfg new file mode 100644 index 00000000..c16e27c5 --- /dev/null +++ b/twin4/twin4/twin4.kcfg @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="twin4rc"/> + <group name="Parameter"> + <entry name="port" type="Int"> + <label>Network connection port</label> + <default>7442</default> + </entry> + <entry name="gamename" type="String"> + <label>Game name</label> + </entry> + <entry name="host" type="String"> + <label>Network connection host</label> + <default>localhost</default> + </entry> + <entry name="level" type="Int"> + <label>Change the strength of the computer player.</label> + <default>3</default> + <min>0</min> + <max>5</max> + </entry> + + <entry name="Name1" type="String"> + <label>Player 1 name</label> + <default>Player 1</default> + </entry> + <entry name="Name2" type="String"> + <label>Player 2 name</label> + <default>Player 2</default> + </entry> + <entry name="Input1" type="Int"> + <default>0</default> + </entry> + <entry name="Input2" type="Int"> + <default>0</default> + </entry> + + <entry name="Colour1" type="Int"> + <default>0</default> + </entry> + + </group> +</kcfg> diff --git a/twin4/twin4/twin4doc.cpp b/twin4/twin4/twin4doc.cpp new file mode 100644 index 00000000..303fd776 --- /dev/null +++ b/twin4/twin4/twin4doc.cpp @@ -0,0 +1,1322 @@ +/*************************************************************************** + twin4doc.cpp - Boardgame for KDE + ------------------- + begin : Sun Mar 26 12:50:12 CEST 2000 + copyright : (C) |1995-2000 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "twin4doc.h" + +// include files for TQt +#include <tqdir.h> +#include <tqtimer.h> + +// include files for KDE +#include <klocale.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <krandomsequence.h> +#include <kapplication.h> + +// application specific includes +#include "kspritecache.h" +#include "twin4view.h" +#include "scorewidget.h" +#include "prefs.h" +#include "statuswidget.h" + +Kwin4Doc::Kwin4Doc(TQWidget *parent, const char *) : KGame(1234,TQT_TQOBJECT(parent)), pView(0), mHintProcess(0) +{ + connect(this,TQT_SIGNAL(signalPropertyChanged(KGamePropertyBase *,KGame *)), + this,TQT_SLOT(slotPropertyChanged(KGamePropertyBase *,KGame *))); + + dataHandler()->Debug(); + //kdDebug(12010) << "Property 7 policy=" << dataHandler()->find(7)->policy() << endl; + setPolicy(KGame::PolicyDirty,true); + + //kdDebug(12010) << "Property 7 policy=" << dataHandler()->find(7)->policy() << endl; + + // Game design + setMaxPlayers(2); + setMinPlayers(2); + + // Game initialization + mField.resize(42); + + // **************************************** + // NOTE: Do not i18n the strings here. They + // are for debugging only + // **************************************** + + // The field array needs not be updated as any move will change it + // Careful only in new ResetGame! Maybe unlocal it there! + // mField.setPolicy(KGamePropertyBase::PolicyLocal); + mField.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mField")); + + mFieldFilled.resize(7); + mHistory.resize(43); + mHistory.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mHistory")); + + mAmzug.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mAmzug")); + mCurrentMove.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mCurrentMove")); + mMaxMove.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mMaxMove")); + mFieldFilled.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mFieldFilled")); + mHistoryCnt.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mHistoryCnt")); + mLastColumn.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mLastColumn")); + mLastHint.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mLastHint")); + mLastColour.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mLastColour")); + mScore.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mScore")); + + // game startup parameter + mStartPlayer=Gelb; + mStartPlayer.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,TQString("mStartPlayer")); + SetCurrentPlayer((FARBE)mStartPlayer.value()); + if (global_debug>1) kdDebug(12010) << "amZug policy=" << mAmzug.policy() << endl; + + mPlayedBy[Gelb]=KGameIO::MouseIO; + mPlayedBy[Rot]=KGameIO::MouseIO; + + // last in init + ResetGame(false); + + setGametqStatus(Intro); + + // Listen to network + connect(this,TQT_SIGNAL(signalMessageUpdate(int,TQ_UINT32,TQ_UINT32)), + this,TQT_SLOT(slotMessageUpdate(int, TQ_UINT32,TQ_UINT32))); + connect(this,TQT_SIGNAL(signalClientJoinedGame(TQ_UINT32,KGame *)), + this,TQT_SLOT(slotClientConnected(TQ_UINT32, KGame *))); + + // Debug only + connect(this,TQT_SIGNAL(signalGameOver(int, KPlayer *,KGame *)), + this,TQT_SLOT(slotGameOver(int, KPlayer *,KGame *))); + + // Change global KGame policy + //dataHandler()->setPolicy(KGamePropertyBase::PolicyDirty,false); + dataHandler()->Debug(); +} + +/** + * Player initialization + */ +void Kwin4Doc::initPlayers() +{ + // Create yellow + Kwin4Player *yellow = (Kwin4Player *)createPlayer(1, mPlayedBy[Gelb], false); + yellow->setUserId(Gelb); + yellow->setName(Prefs::name1()); + addPlayer(yellow); + setPlayedBy(Gelb,mPlayedBy[Gelb]); + + // Create Red + Kwin4Player *red = (Kwin4Player *)createPlayer(1, mPlayedBy[Rot], false); + red->setUserId(Rot); + red->setName(Prefs::name1()); + addPlayer(red); + setPlayedBy(Rot,mPlayedBy[Rot]); +} + +Kwin4Doc::~Kwin4Doc() +{ + WriteConfig(kapp->config()); + if (mHintProcess) + delete mHintProcess; +} + +void Kwin4Doc::setView(Kwin4View *view) +{ + pView=view; +} + +/** + * Returns colour + */ +FARBE Kwin4Doc::QueryColour(int x,int y){ + return (FARBE)mField.at(x+y*FIELD_SIZE_X); +} + +/** + * Set the colour + */ +void Kwin4Doc::SetColour(int x,int y,FARBE c){ + if (x<0 || x>=FIELD_SIZE_X || y<0 || y>=FIELD_SIZE_Y) + { + kdDebug(12010) << "ERROR: SetColour auf falsche Poition " << x << " " << y << endl; + return ; + } + //kdDebug(12010) << "SetColor::mField["<<x+y*FIELD_SIZE_X<<"="<<c<<endl; + mField.setAt(x+y*FIELD_SIZE_X,c); +} + +/** + * Reset the whole game + */ +void Kwin4Doc::ResetGame(bool initview){ + // Reset field + for (int x=0;x<FIELD_SIZE_X;x++) + { + for (int y=FIELD_SIZE_Y-1;y>=0;y--) + SetColour(x,y,Niemand); + } + mFieldFilled.fill(0); + + // Reset game vars + mHistoryCnt=0; + mCurrentMove=0; + mMaxMove=0; + mLastColumn=-1; + mLastColour=Niemand; + SetScore(0); + mLastHint=-1; + + // Reset the view + if (initview) + pView->initView(false); + + // Who starts this game + SetCurrentPlayer((FARBE)mStartPlayer.value()); +} + +/** + * Set current player to setTurn true + */ +void Kwin4Doc::preparePlayerTurn() +{ + if (global_debug>1) + kdDebug(12010) << "Setting the current player to turn"<<endl; + getPlayer(QueryCurrentPlayer())->setTurn(true,true); +} + +/** + * End a game + */ +void Kwin4Doc::EndGame(TABLE mode) +{ + setGametqStatus(End); + pView->clearError(); + pView->EndGame(); + Kwin4Player *yellow=getPlayer(Gelb); + Kwin4Player *red=getPlayer(Rot); + + switch(mode) + { + case TWin: yellow->incWin(); + red->incLost(); + break; + case TLost: yellow->incLost(); + red->incWin(); + break; + case TRemis: yellow->incRemis(); + red->incRemis(); + break; + default: + // Only break if moves have been made + if (mMaxMove>0) + { + yellow->incBrk(); + red->incBrk(); + } + break; + } + // switch start player +} + +void Kwin4Doc::moveDone(TQCanvasItem *item,int ) +{ + //kdDebug(12010) << "########################## SPRITE MOVE DONE ################# " << endl; + //Debug(); + //for (KPlayer* p=playerList()->first(); p!= 0; p=playerList()->next() ) + //{ + // p->Debug(); + //} + + if (playerCount()>1) + playerInputFinished(getPlayer(QueryCurrentPlayer())); + + pView->clearError(); + + KSprite *sprite=(KSprite *)item; + sprite->deleteNotify(); +} + +/** + * Calcualte the next players turn + */ +KPlayer * Kwin4Doc::nextPlayer(KPlayer *last,bool /*exclusive*/) +{ + if (global_debug>1) + kdDebug(12010) << k_funcinfo << "nextPlayer last="<<last->id() << " admin=" << isAdmin() <<endl; + + // Should be enough if the admin sets the turn + if (last->userId()==Gelb) + SetCurrentPlayer(Rot); + else + SetCurrentPlayer(Gelb); + if (global_debug>1) + kdDebug(12010) <<" Current set to "<<QueryCurrentPlayer()<<endl; + if (isAdmin()) + getPlayer(QueryCurrentPlayer())->setTurn(true,true); + emit signalMoveDone(0,0); + return getPlayer(QueryCurrentPlayer()); +} + +/** + * Make a game move + * mode=0 normal move, =1: redo move + */ +MOVESTATUS Kwin4Doc::MakeMove(int x,int mode){ + if (x<0 || x>=FIELD_SIZE_X) + { + kdDebug(12010) << "ERROR: MakeMove auf falsche Position " << x << endl; + return GNotAllowed; + } + + int y=mFieldFilled.at(x); + + if (y>=FIELD_SIZE_Y) + { + return GIllMove; // no space left in column + } + + if (mLastHint>=0) + { + int hy; + hy=mFieldFilled.at(mLastHint); + SetColour(mLastHint,hy,Niemand); + mLastHint=-1; + } + if (mode==Tip) + { + mLastHint=x; + SetColour(x,y,Tip); + return GTip ; // no real move + } + + mFieldFilled.setAt(x,mFieldFilled.at(x)+1); + SetColour(x,y,QueryCurrentPlayer()); + + mHistory.setAt(QueryHistoryCnt(),x); + mHistoryCnt=mHistoryCnt.value()+1; + + mLastColour=QueryCurrentPlayer(); + //if (QueryCurrentPlayer()==Gelb) SetCurrentPlayer(Rot); + //else SetCurrentPlayer(Gelb); + + mCurrentMove=mCurrentMove.value()+1; + + // only if a real move isdone the maxmove is raised + if (mode==0) mMaxMove=mCurrentMove.value(); + mLastColumn=x; + + pView->setArrow(x,mLastColour); + // animation onyl if no redo + pView->setPiece(x,y,mLastColour,mCurrentMove-1,mode==1?false:true); + pView->setHint(0,0,false); + + return GNormal; +} + + +/** + * Undo a move + */ +bool Kwin4Doc::UndoMove(){ + //kdDebug(12010) <<" undo: current player="<<QueryCurrentPlayer() << endl; + //kdDebug(12010) <<" undo: history="<<QueryHistoryCnt() << endl; + if (QueryHistoryCnt()<1) + return false; + + if (mLastHint>=0) + { + int hy; + hy=mFieldFilled.at(mLastHint); + SetColour(mLastHint,hy,Niemand); + mLastHint=-1; + } + // kdDebug(12010) << "Undo no="<<mHistoryCnt.value() << endl; + mHistoryCnt=mHistoryCnt.value()-1; + int x=mHistory.at(QueryHistoryCnt()); + mFieldFilled.setAt(x,mFieldFilled.at(x)-1); + int y=mFieldFilled.at(x); + // kdDebug(12010) << "Undo x="<<x << " y=" <<y << endl; + SetColour(x,y,Niemand); + // We have to remove the piece as well... + pView->setPiece(x,y,Niemand,mCurrentMove-1,false); + + mLastColour=QueryCurrentPlayer(); + if (QueryCurrentPlayer()==Gelb) SetCurrentPlayer(Rot); + else SetCurrentPlayer(Gelb); + mCurrentMove=mCurrentMove.value()-1; + + // sprite no, arrow pos, arrow color, enable + int oldx=-1; + if (QueryHistoryCnt()>0) oldx=mHistory.at(QueryHistoryCnt()-1); + pView->setSprite(mCurrentMove+1,oldx,QueryHistoryCnt()>0?mLastColour.value():0,false); + pView->setHint(0,0,false); + + if (QueryHistoryCnt()>0) + mLastColumn=mHistory.at(QueryHistoryCnt()-1); + else + mLastColumn=-1; + + SetScore(0); + + return true; +} + +/** + * Redo a move + */ +bool Kwin4Doc::RedoMove(){ + //kdDebug(12010) << "mMaxMove=" << mMaxMove.value() << " historycnt=" << QueryHistoryCnt() << endl; + if (QueryHistoryCnt()>=mMaxMove) + return false; + + int x=mHistory.at(QueryHistoryCnt()); + //kdDebug(12010) << "Redo x=" << x << endl; + MakeMove(x,1); + if (QueryCurrentPlayer()==Gelb) + SetCurrentPlayer(Rot); + else + SetCurrentPlayer(Gelb); + SetScore(0); + pView->setHint(0,0,false); + return true; +} + +/** + * Set the name of col + */ +void Kwin4Doc::SetName(FARBE i, const TQString &n){ + getPlayer(i)->setName(n); +} + +/** + * Query the name of i + */ +TQString Kwin4Doc::QueryName(FARBE i){ + return getPlayer(i)->name(); +} + +/** + * Returns the all time statistics for player i + */ +int Kwin4Doc::QueryStat(FARBE i,TABLE mode){ + Kwin4Player *player=getPlayer(i); + switch(mode) + { + case TWin: return player->win(); + break; + case TRemis: return player->remis(); + break; + case TLost: return player->lost(); + break; + case TBrk: return player->brk(); + break; + case TSum: return (player->win()+player->remis()+player->lost()); + default: + break; + } + return 0; +} + +/** + * Query the colour of player i + */ +FARBE Kwin4Doc::QueryPlayerColour(int player){ + if (player==0) + return (FARBE)mStartPlayer.value(); + + if (mStartPlayer.value()==Gelb) + return Rot; + else + return Gelb; +} + +/** */ +int Kwin4Doc::CheckGameOver(int x, FARBE col){ + int y,i; + FARBE c; + int star=1; + FARBE winc=Niemand; + + // Check vertical up + int flag=0; + for (i=0;i<4;i++) + { + y=mFieldFilled.at(x)-1-i; + if (y>=0) + { + c=QueryColour(x,y); + if (c==col) flag++; + } + } + if (flag>=4 /*&& doBlink*/) + { + // Store win fields + for (i=0;i<4;i++) + { + y=mFieldFilled.at(x)-1-i; + pView->drawStar(x,y,star++); + winc=QueryColour(x,y); + } + return 1; + } + else if (flag>=4) return 1; + + int xx; + // Check horizontal to the right + y=mFieldFilled.at(x)-1; + flag=0; + for (i=-3;i<=3 && flag<4;i++) + { + xx=x+i; + if (xx>=0 && xx<FIELD_SIZE_X) + { + c=QueryColour(xx,y); + if (c==col) flag++; + else flag=0; + } + } + if (flag>=4 /*&& doBlink*/) + { + // Store win fields + y=mFieldFilled.at(x)-1; + winc=QueryColour(x,y); + int cnt=0; + for (i=0;i<4;i++) + { + xx=x+i; + if (xx>=0 && xx<FIELD_SIZE_X) + { + if (QueryColour(xx,y)!=winc) break; + pView->drawStar(xx,y,star++); + cnt++; + } + else break; + } + for (i=-1;i>-4 && cnt<4;i--) + { + xx=x+i; + if (xx>=0 && xx<FIELD_SIZE_X) + { + if (QueryColour(xx,y)!=winc) break; + pView->drawStar(xx,y,star++); + cnt++; + } + else break; + } + return 1; + } + else if (flag>=4) return 1; + + + // Check dy+ + flag=0; + for (i=-3;i<=3 && flag<4;i++) + { + xx=x+i; + if (xx>=0 && xx<FIELD_SIZE_X) + { + y=mFieldFilled.at(x)-1-i; + if (y>=0 && y<FIELD_SIZE_Y) + { + c=QueryColour(xx,y); + if (c==col) flag++; + else flag=0; + } + } + } + if (flag>=4 /*&& doBlink*/) + { + // Store win fields + y=mFieldFilled.at(x)-1; + winc=QueryColour(x,y); + int cnt=0; + for (i=0;i<4;i++) + { + xx=x+i; + if (xx>=0 && xx<FIELD_SIZE_X) + { + y=mFieldFilled.at(x)-1-i; + if (y<0) break; + if (QueryColour(xx,y)!=winc) break; + pView->drawStar(xx,y,star++); + cnt++; + } + else break; + } + for (i=-1;i>-4 && cnt<4;i--) + { + xx=x+i; + if (xx>=0 && xx<FIELD_SIZE_X) + { + y=mFieldFilled.at(x)-1-i; + if (y>=FIELD_SIZE_Y) break; + if (QueryColour(xx,y)!=winc) break; + pView->drawStar(xx,y,star++); + cnt++; + } + else break; + } + return 1; + } + else if (flag>=4) return 1; + + + // Check dy- + flag=0; + for (i=-3;i<=3 && flag<4;i++) + { + xx=x+i; + if (xx>=0 && xx<FIELD_SIZE_X) + { + y=mFieldFilled.at(x)-1+i; + if (y>=0 && y<FIELD_SIZE_Y) + { + c=QueryColour(xx,y); + if (c==col) flag++; + else flag=0; + } + } + } + if (flag>=4 /*&& doBlink*/) + { + // Store win fields + y=mFieldFilled.at(x)-1; + winc=QueryColour(x,y); + int cnt=0; + for (i=0;i<4;i++) + { + xx=x+i; + if (xx>=0 && xx<FIELD_SIZE_X) + { + y=mFieldFilled.at(x)-1+i; + if (y>=FIELD_SIZE_Y) break; + if (QueryColour(xx,y)!=winc) break; + pView->drawStar(xx,y,star++); + cnt++; + } + else break; + } + //kdDebug(12010) << "Found + cnt=" << cnt <<endl; + for (i=-1;i>-4 && cnt<4;i--) + { + xx=x+i; + if (xx>=0 && xx<FIELD_SIZE_X) + { + y=mFieldFilled.at(x)-1+i; + if (y<0) break; + if (QueryColour(xx,y)!=winc) break; + pView->drawStar(xx,y,star++); + cnt++; + } + else break; + } + //kdDebug(12010) << "all cnt=" << cnt<<endl; + return 1; + } + else if (flag>=4) return 1; + + if (mCurrentMove>=42) return -1; + + return 0; +} + +/** + * Reset the stats + */ +void Kwin4Doc::ResetStat(){ + getPlayer(Gelb)->resetStats(); + getPlayer(Rot)->resetStats(); +} + +/** + * Set computer score + */ +void Kwin4Doc::SetScore(long i){ + mScore.setValue(i); +} + +/** + * Height of a column + */ +int Kwin4Doc::QueryHeight(int x){ + if (x<0 || x>=FIELD_SIZE_X) + { + kdError() << "ERROR: Query Height for wrong x " << x << endl; + return 0; + } + return mFieldFilled.at(x); +} + +int Kwin4Doc::QueryLastHint(){ + return mLastHint; +} + +void Kwin4Doc::loadSettings(){ + // TODO find out what to do with this... + // mLevel.setValue(Prefs::level()); + + SetName(Gelb, Prefs::name1()); + SetName(Rot, Prefs::name2()); + + KGameIO::IOMode mode = KGameIO::MouseIO; + + int m = Prefs::input1(); + if(m == 0) mode = KGameIO::MouseIO; + if(m == 1) mode = KGameIO::ProcessIO; + if(m == 2) mode = KGameIO::KeyIO; + setPlayedBy(Gelb, mode); + + m = Prefs::input2(); + if(m == 0) mode = KGameIO::MouseIO; + if(m == 1) mode = KGameIO::ProcessIO; + if(m == 2) mode = KGameIO::KeyIO; + setPlayedBy(Rot, mode); + + FARBE col = (FARBE)Prefs::colour1(); + if (QueryPlayerColour(0)!=col) + SwitchStartPlayer(); +} + +/** + * read config file + */ +void Kwin4Doc::ReadConfig(KConfig *config) +{ + loadSettings(); + + config->setGroup("YellowPlayer"); + getPlayer(Gelb)->readConfig(config); + + config->setGroup("RedPlayer"); + getPlayer(Rot)->readConfig(config); +} + +/** + * write config file + */ +void Kwin4Doc::WriteConfig(KConfig *config) +{ + config->setGroup("YellowPlayer"); + getPlayer(Gelb)->writeConfig(config); + + config->setGroup("RedPlayer"); + getPlayer(Rot)->writeConfig(config); + + config->sync(); +} + +/** + * Returns the current player, resp amzug + */ +FARBE Kwin4Doc::QueryCurrentPlayer(){ + return (FARBE)mAmzug.value(); +} + +void Kwin4Doc::SetCurrentPlayer(FARBE i) +{ + mAmzug.setValue(i); +} + +/** + * Swtich the starting player and return the new started + */ +FARBE Kwin4Doc::SwitchStartPlayer() +{ + if (mStartPlayer.value()==Gelb) + mStartPlayer.setValue(Rot); + else + mStartPlayer.setValue(Gelb); + + return (FARBE)mStartPlayer.value(); +} + +int Kwin4Doc::QueryLastcolumn() +{ + return mLastColumn; +} + +FARBE Kwin4Doc::QueryLastcolour() +{ + return (FARBE)(mLastColour.value()); +} + +int Kwin4Doc::QueryCurrentMove() +{ + return mCurrentMove; +} + +void Kwin4Doc::SetCurrentMove(int i) +{ + mCurrentMove=i; +} + +int Kwin4Doc::QueryMaxMove() +{ + return mMaxMove; +} + +int Kwin4Doc::QueryHistoryCnt() +{ + return mHistoryCnt; +} + +/** + * Return the name of the computer player process + */ +TQString Kwin4Doc::QueryProcessName() +{ + // First try a local dir override + TQDir dir; + TQString filename=dir.path()+TQString("/twin4/twin4proc"); + TQFile flocal(filename); + if (flocal.exists()) + { + if (global_debug>1) kdDebug(12010) << " Found local process " << filename << endl; + return filename; + } + TQString path=kapp->dirs()->findExe("twin4proc"); + if (!path.isNull()) + { + if (global_debug>1) kdDebug(12010) << " Found system process " << path << endl; + return path; + } + TQString empty; + kdError() << "Could not locate the computer player" << endl; + return empty; +} + +void Kwin4Doc::slotMessageUpdate(int /*id*/,TQ_UINT32 /*sender*/,TQ_UINT32 /*recv*/) +{ +// kdDebug(12010) << "MSG: id=" << id << " sender=" << sender << " receiver="<<recv<< endl; +} + +/** + * Create a KPlayer + */ +KPlayer *Kwin4Doc::createPlayer(int /*rtti*/,int io,bool isvirtual) +{ + KPlayer *player = new Kwin4Player; + if (!isvirtual) + createIO(player,(KGameIO::IOMode)io); + + connect(player,TQT_SIGNAL(signalPropertyChanged(KGamePropertyBase *, KPlayer *)), + this,TQT_SLOT(slotPlayerPropertyChanged(KGamePropertyBase *, KPlayer *))); + ((Kwin4Player *)player)->setWidget(pView->statusWidget()); + return player; +} + +/** + * Called when a player input is received from the KGame object + * this is e-.g. a mouse event + */ +bool Kwin4Doc::playerInput(TQDataStream &msg, KPlayer * /*player*/) +{ + int move, pl; + msg >> pl >> move; + if (!Move(move,pl)) + TQTimer::singleShot(0, this,TQT_SLOT(slotRepeatMove())); + + return false; +} + +/** + * Reactivate player in case of a move which could not pe performed + */ +void Kwin4Doc::slotRepeatMove() +{ + getPlayer(QueryCurrentPlayer())->setTurn(true); +} + +/** + * Performs a game move + */ +bool Kwin4Doc::Move(int x,int id) +{ + if (global_debug>1) + kdDebug(12010) <<" Kwin4Doc::Move("<<x<<","<<id<<")"<<endl; + + return (MakeMove(x,0) == GNormal); +} + +/** + * return -1: remis, 1:won, 0: continue + */ +int Kwin4Doc::checkGameOver(KPlayer *p) +{ + if (global_debug>1) + kdDebug(12010) <<"twin4doc::checkGameOver::"<<p->userId()<<endl; + return CheckGameOver(QueryLastcolumn(),QueryLastcolour()); +} + +KGameIO::IOMode Kwin4Doc::playedBy(int col) +{ + return mPlayedBy[col]; +} + +void Kwin4Doc::setPlayedBy(int col, KGameIO::IOMode io) +{ + if (global_debug>1) + kdDebug(12010) << " Kwin4Doc::setPlayedBy(int "<<col<<",KGameIO::IOMode "<<io<<")" << endl; + + Kwin4Player *player=getPlayer((FARBE)col); + + if (mPlayedBy[col]!=io && !player->isVirtual()) + { + mPlayedBy[col]=io; + player->removeGameIO(0); // remove all IO's + createIO(player,io); + } +} + +/* Get the io values right after a load game as the io the playedby + * is not set there + */ +void Kwin4Doc::recalcIO() +{ + mPlayedBy[Gelb]=(KGameIO::IOMode)getPlayer(Gelb)->calcIOValue(); + mPlayedBy[Rot]=(KGameIO::IOMode)getPlayer(Rot)->calcIOValue(); +} + +void Kwin4Doc::createIO(KPlayer *player,KGameIO::IOMode io) +{ + if (!player) + return; + + if (global_debug>1) + kdDebug(12010) << " Kwin4Doc::createIO(KPlayer *player("<<player->userId()<<"),KGameIO::IOMode "<<io<<") " << endl; + + if (io&KGameIO::MouseIO) + { + KGameMouseIO *input; + if (global_debug>1) kdDebug(12010) << "Creating MOUSE IO to "<<pView<< endl; + // We want the player to work over mouse + input=new KGameMouseIO(pView); + if (global_debug>1) kdDebug(12010) << "MOUSE IO added " << endl; + // Connect mouse input to a function to process the actual input + connect(input,TQT_SIGNAL(signalMouseEvent(KGameIO *,TQDataStream &,TQMouseEvent *,bool *)), + pView,TQT_SLOT(slotMouseInput(KGameIO *,TQDataStream &,TQMouseEvent *,bool *))); + player->addGameIO(input); + } + else if (io&KGameIO::ProcessIO) + { + TQString file=QueryProcessName(); + if (global_debug>1) kdDebug(12010) << "Creating PROCESS IO " << file << endl; + + KGameProcessIO *input; + // We want a computer player + input=new KGameProcessIO(file); + // Connect computer player to the setTurn + connect(input,TQT_SIGNAL(signalPrepareTurn(TQDataStream &,bool,KGameIO *,bool *)), + this,TQT_SLOT(slotPrepareTurn(TQDataStream &,bool,KGameIO *,bool *))); + + connect(input,TQT_SIGNAL(signalProcessQuery(TQDataStream &,KGameProcessIO *)), + this,TQT_SLOT(slotProcessQuery(TQDataStream &,KGameProcessIO *))); + player->addGameIO(input); + } + else if (io&KGameIO::KeyIO) + { + if (global_debug>1) kdDebug(12010) << "Creating KEYBOARD IO " << endl; + // We want the player to work over keyboard + KGameKeyIO *input; + input=new KGameKeyIO(pView->parentWidget()); + // Connect keys input to a function to process the actual input + connect((KGameKeyIO *)input,TQT_SIGNAL(signalKeyEvent(KGameIO *,TQDataStream &,TQKeyEvent *,bool *)), + pView,TQT_SLOT(slotKeyInput(KGameIO *,TQDataStream &,TQKeyEvent *,bool *))); + player->addGameIO(input); + } +} + +/** + * This slot is called when a computer move should be generated + */ +void Kwin4Doc::slotPrepareTurn(TQDataStream &stream,bool b,KGameIO *input,bool *sendit) +{ + if (global_debug>1) + kdDebug(12010) << " Kwin4Doc::slotPrepareTurn b="<<b << endl; + + *sendit=false; + // Our player + KPlayer *player=input->player(); + if (!player->myTurn()) return ; + if (!b) return ; // only on setTurn(true) + + TQ_INT32 pl; + if (global_debug>1) kdDebug(12010) << "slotPrepareComputerTurn for player id= " << player->id() << endl; + pl=player->userId(); + + prepareGameMessage(stream,pl); + + *sendit=true; +} + +/** + * Sends the current game status to the computer player + * Careful: The data needs to be the same than the computer + * player reading on the other side + **/ +void Kwin4Doc::prepareGameMessage(TQDataStream &stream, TQ_INT32 pl) +{ + if (global_debug>1) kdDebug(12010) << " sending col=" << pl << endl; + stream << pl ; + // This needs to be the same than the computer player reads! + stream << (TQ_INT32)QueryCurrentMove(); + stream << (TQ_INT32)QueryCurrentPlayer(); + stream << (TQ_INT32)QueryPlayerColour(0); + stream << (TQ_INT32)QueryPlayerColour(1); + stream << (TQ_INT32)Prefs::level(); + + int i,j; + for (i=0;i<FIELD_SIZE_Y;i++) + { + for (j=0;j<FIELD_SIZE_X;j++) + { + TQ_INT8 col; + col=QueryColour(j,i); + stream << col; + } + if (global_debug>1) kdDebug(12010) + << QueryColour(0,i) << " " + << QueryColour(1,i) << " " + << QueryColour(2,i) << " " + << QueryColour(3,i) << " " + << QueryColour(4,i) << " " + << QueryColour(5,i) << " " + << QueryColour(6,i) << endl; + } + stream << (TQ_INT32)421256; +} + +void Kwin4Doc::slotProcessQuery(TQDataStream &in,KGameProcessIO * /*me*/) +{ + TQ_INT8 cid; + in >> cid; + switch(cid) + { + case 1: // value + long value; + in >> value; + if (global_debug>1) kdDebug(12010) << "#### Computer thinks value is " << value << endl; + SetScore(value); + break; + default: + kdError() << "Kwin4Doc::slotProcessQuery: Unknown id " << cid << endl; + break; + } +} + +/** + * This slot is called by the signal of KGame to indicated + * that the network connection is done and a new client is + * connected + * cid is the id of the client connected. if this is equal + * gameId() WE are the client + */ +void Kwin4Doc::slotClientConnected(TQ_UINT32 cid,KGame *) +{ + if (global_debug>1) kdDebug(12010) << " void Kwin4Doc::slotClientConnected id="<<cid << " we=" << + gameId() << " we admin=" << isAdmin() << "master)" << isMaster() << endl; + + if (playerList()->count()!=2) + { + kdError() << "SERIOUS ERROR: We do not have two players...Trying to disconnect!"<<endl; + disconnect(); + return ; + } + + // Get the two players - more are not possible + Kwin4Player *p1=(Kwin4Player *)playerList()->at(0); + Kwin4Player *p2=(Kwin4Player *)playerList()->at(1); + if (!p1->isVirtual()) + { + emit signalChatChanged(p1); + if (global_debug>1) kdDebug(12010) << "CHAT to player 0 " << endl; + } + else + { + emit signalChatChanged(p2); + if (global_debug>1) kdDebug(12010) << "CHAT to player 1 " << endl; + } + + // Now check whose turn it is. The Admin will rule this + if (isAdmin()) + { + if (global_debug>1) kdDebug(12010) << "WE are ADMIN == COOL ! " << endl; + // p1 is local + if (!p1->isVirtual()) + { + if (global_debug>1) kdDebug(12010) << "p1 id=" << p1->userId() << " is local turn="<<p1->myTurn()<< endl; + // Exclusive setting of the turn + p1->setTurn(p1->myTurn(),true); + p2->setTurn(!p1->myTurn(),true); + } + else if (!p2->isVirtual()) + { + if (global_debug>1) kdDebug(12010) << "p2 id=" << p2->userId() << " is local turn="<<p2->myTurn()<< endl; + // Exclusive setting of the turn + p2->setTurn(p2->myTurn(),true); + p1->setTurn(!p2->myTurn(),true); + } + } +} + +/** + * Get the KPlayer from the color by searching all players + * users id's + **/ +Kwin4Player *Kwin4Doc::getPlayer(FARBE col) +{ + Kwin4Player *p; + for ( p=(Kwin4Player *)playerList()->first(); p!= 0; p=(Kwin4Player *)playerList()->next() ) + { + if (p->userId()==col) + return p; + } + kdError() << "SERIOUS ERROR: Cannot find player with colour " << col << ". CRASH imminent" << endl; + return 0; +} + +/** + * We create a process which calulcates a computer move + * which is shown as hint + **/ +void Kwin4Doc::calcHint() +{ + // We allocate the hint process only if it is needed + if (!mHintProcess) + { + TQString file=QueryProcessName(); + if (global_debug>1) kdDebug(12010) << "Creating HINT PROCESS IO " << endl; + + // We want a computer player + mHintProcess=new KGameProcessIO(file); + + connect(mHintProcess,TQT_SIGNAL(signalProcessQuery(TQDataStream &,KGameProcessIO *)), + this,TQT_SLOT(slotProcessHint(TQDataStream &,KGameProcessIO *))); + } + TQ_INT32 pl; + TQByteArray buffer; + TQDataStream stream(buffer,IO_WriteOnly); + pl=QueryCurrentPlayer(); + prepareGameMessage(stream,pl); + mHintProcess->sendMessage(stream,2,0,gameId()); +} + +/** + * The compute rprocess sent a hint which we show in the + * game board + **/ +void Kwin4Doc::slotProcessHint(TQDataStream &in,KGameProcessIO * /*me*/) +{ + TQ_INT8 cid; + in >> cid; + switch(cid) + { + case 2: // Hint + { + TQ_INT32 pl; + TQ_INT32 move; + long value; + in >> pl >> move >> value; + if (global_debug>1) kdDebug(12010) << "#### Computer thinks pl=" << pl << " move =" << move << endl; + if (global_debug>1) kdDebug(12010) << "#### Computer thinks hint is " << move << " and value is " << value << endl; + int x=move; + int y=mFieldFilled.at(x); + pView->setHint(x,y,true); + } + break; + default: + kdError() << "Kwin4Doc::slotProcessHint: Unknown id " << cid << endl; + break; + } +} + +/** + * Called when a player property has changed. We check whether the name + * changed and then update the score widget + * We should maybe do this for the other properties too to update + * the status widget...I am not sure here...we'll see + **/ +void Kwin4Doc::slotPlayerPropertyChanged(KGamePropertyBase *prop,KPlayer *player) +{ + if (!pView) return ; + if (prop->id()==KGamePropertyBase::IdName) + { + if (global_debug>1) kdDebug(12010) << "Player name id=" << player->userId() << " changed to " << player->name()<<endl; + pView->scoreWidget()->setPlayer(player->name(),player->userId()); + } +} + +void Kwin4Doc::slotPropertyChanged(KGamePropertyBase *prop,KGame *) +{ + if (!pView) + return ; + + if (prop->id()==mCurrentMove.id()) + { + pView->scoreWidget()->setMove(mCurrentMove); + } + else if (prop->id()==mScore.id()) + { + int sc=mScore/10000; + if (sc==0 && mScore.value()>0) sc=1; + else if (sc==0 && mScore.value()<0) sc=-1; + pView->scoreWidget()->setChance(sc); + } + else if (prop->id()==mAmzug.id()) + { + if (global_debug>1) kdDebug(12010) << "Amzug changed to " << mAmzug.value()<<endl; + pView->scoreWidget()->setTurn(mAmzug); + } + else if (prop->id()==KGamePropertyBase::IdGametqStatus) + { + if (gametqStatus()==Abort) + { + if (global_debug>1) kdDebug(12010) << "PropertyChanged::status signal game abort +++" << endl; + emit signalGameOver(2,getPlayer(QueryCurrentPlayer()),0); // 2 indicates Abort + } + else if (gametqStatus()==Run) + { + if (global_debug>1) kdDebug(12010) << "PropertyChanged::status signal game run +++" << endl; + preparePlayerTurn(); // Set the current player to play + emit signalGameRun(); + } + else if (gametqStatus()==Init) + { + if (global_debug>1) kdDebug(12010) << "PropertyChanged::status signal game INIT +++" << endl; + ResetGame(true); + } + else + { + if (global_debug>1) kdDebug(12010) << "PropertyChanged::other status signal +++" << endl; + } + + } +} + +/** + * Called by KGame if the game has ended. + * DEBUG only as we do not need any extension to + * the KGame behavior + */ +void Kwin4Doc::slotGameOver(int status, KPlayer * p, KGame * /*me*/) +{ + if (global_debug>1) kdDebug(12010) << "SlotGameOver: status="<<status<<" lastplayer uid="<<p->userId()<<endl; + +} + +/** + * This is an overwritten function of KGame which is called + * when a game is loaded. This can either be via a networ + * connect or via a real load from file + **/ +bool Kwin4Doc::loadgame(TQDataStream &stream,bool network,bool reset) +{ + if (global_debug>1) + kdDebug () << "loadgame() network=" << network << " reset="<< reset << endl; + if (!network) setGametqStatus(End); + + // Clear out the old game + if (global_debug>1) kdDebug(12010)<<"loadgame wants to reset the game"<<endl; + ResetGame(true); + + // load the new game + bool res=KGame::loadgame(stream,network,reset); + if (global_debug>1) kdDebug(12010) << "amzug loaded to ="<<mAmzug.value() << endl; + + // Replay the game be undoing and redoing + if (global_debug>1) kdDebug(12010) << "REDRAW GAME using undo/redo" << endl; + if (global_debug>1) kdDebug(12010) << "history cnt="<<mHistoryCnt.value() << endl; + if (global_debug>1) kdDebug(12010) << "amzug ="<<mAmzug.value() << endl; + int cnt=0; + while(UndoMove()) + { + cnt++; + if (global_debug>1) kdDebug(12010) << "Undoing move "<<cnt<<endl; + } + if (global_debug>1) kdDebug(12010) << "amzug ="<<mAmzug.value() << endl; + while(cnt>0) + { + RedoMove(); + cnt--; + if (global_debug>1) kdDebug(12010) << "Redoing move "<<cnt<<endl; + } + if (global_debug>1) kdDebug(12010) << "amzug ="<<mAmzug.value() << endl; + + // Set the input devices + recalcIO(); + // And set the right player to turn + preparePlayerTurn(); + + if (global_debug>1) + kdDebug(12010) << "loadgame done +++" << endl; + return res; +} + +/** + * This is also an overwritten function of KGame. It is + * Called in the game negotiation upon connect. Here + * the games have to determine what player is remote and + * what is local + * This function is only called in the Admin. + */ +void Kwin4Doc::newPlayersJoin(KGamePlayerList * /*oldList*/,KGamePlayerList *newList,TQValueList<int> &inactivate) +{ + if (global_debug>1) + kdDebug(12010) << "newPlayersJoin: START"<<endl; + + Kwin4Player *yellow=getPlayer(Gelb); + Kwin4Player *red=getPlayer(Rot); + KPlayer *player; + // Take the master player with the higher priority. Prioirty is set + // be the network dialog + if (yellow->networkPriority()>red->networkPriority()) + { + // Deactivate the lower one + inactivate.append(red->id()); + if (global_debug>1) kdDebug(12010) << "ADMIN keeps yellow and kicks red= " << red->id()<<" userId/col="<<red->userId()<<endl; + // loop all client players and deactivate the one which have the color + // yellow + for ( player=newList->first(); player != 0; player=newList->next() ) + { + if (player->userId()==yellow->userId()) + { + inactivate.append(player->id()); + if (global_debug>1) kdDebug(12010) << "Deactivate C1 " << player->id()<<" col="<<player->userId()<<endl; + } + } + } + else + { + // Deactivate the lower one + inactivate.append(yellow->id()); + if (global_debug>1) kdDebug(12010) << "ADMIN keeps red and kicks yellow= " << yellow->id()<<" userId/col="<<yellow->userId()<<endl; + // loop all client players and deactivate the one which have the color + // red + for ( player=newList->first(); player != 0; player=newList->next() ) + { + if (player->userId()==red->userId()) + { + inactivate.append(player->id()); + if (global_debug>1) kdDebug(12010) << "Deactivate C2 " << player->id()<<" col="<<player->userId()<<endl; + } + } + } + if (global_debug>1) + kdDebug(12010) << "newPlayersJoin: DONE"<<endl; +} + +#include "twin4doc.moc" diff --git a/twin4/twin4/twin4doc.h b/twin4/twin4/twin4doc.h new file mode 100644 index 00000000..25be0c2f --- /dev/null +++ b/twin4/twin4/twin4doc.h @@ -0,0 +1,195 @@ +/*************************************************************************** + Kwin4 - Four in a Row for KDE + ------------------- + begin : March 2000 + copyright : (C) 1995-2000 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KWIN4DOC_H +#define KWIN4DOC_H + +#include <kgame.h> +#include <kgameio.h> +#include <kgamepropertyarray.h> + +#include "twin4player.h" + +class Kwin4View; +class TQCanvasItem; + +extern int global_debug; + +// The user or color? +typedef enum e_Farbe {Niemand=-1,Gelb=0,Rot=1,Tip=3,Rand=4,GelbWin=8,RotWin=9} FARBE; +// The type of player +typedef enum {Men=0,Computer=1,Remote=2} PLAYER; +typedef enum {TSum,TWin,TRemis,TLost,TBrk} TABLE; +typedef enum {GIllMove=-2,GNotAllowed=-1,GNormal=0,GYellowWin=1,GRedWin=2,GRemis=3,GTip=4} MOVESTATUS; + +#define NOOFPLAYER 2 + +#define FIELD_SIZE_X 7 +#define FIELD_SIZE_Y 6 +#define FIELD_SPACING 40 + +/** + * The board "engine" + */ +class Kwin4Doc : public KGame +{ +Q_OBJECT + TQ_OBJECT + +public: + Kwin4Doc(TQWidget *parent, const char *name=0); + ~Kwin4Doc(); + + /** adds a view to the document which represents the document contents. Usually this is your main view. */ + void setView(Kwin4View *view); + /** initializes the players */ + void initPlayers(); + /** saves the document under filename and format.*/ + bool loadgame(TQDataStream &stream, bool network, bool reset); + + int QueryLastHint(); + int QueryHeight(int x); + void SetScore(long i); + void ResetStat(); + int CheckGameOver(int x, FARBE col); + FARBE QueryPlayerColour(int player); + int QueryStat(FARBE i, TABLE mode); + TQString QueryName(FARBE i); + void SetName(FARBE i, const TQString &n); + + /** + * Set and query the IO mode of player Gelb/Rot + */ + KGameIO::IOMode playedBy(int col); + void setPlayedBy(int col,KGameIO::IOMode mode); + + /** + * create and add an IO device to an given player. + * The old ones have to be removed manually before + */ + void createIO(KPlayer *player,KGameIO::IOMode io); + + Kwin4Player *getPlayer(FARBE col); + + bool RedoMove(); + bool UndoMove(); + + /** Make a game move */ + MOVESTATUS MakeMove(int x,int mode); + /** End a game */ + void EndGame(TABLE mode); + /** Reset the whole game */ + void ResetGame(bool initview); + /** Set the colour */ + void SetColour(int x,int y,FARBE c); + /** Returns colour */ + FARBE QueryColour(int x,int y); + + void ReadConfig(KConfig *config); + void WriteConfig(KConfig *config); + + FARBE QueryCurrentPlayer(); + void SetCurrentPlayer(FARBE i); + + FARBE SwitchStartPlayer(); + + int QueryLastcolumn(); // last x moved + FARBE QueryLastcolour(); // last colour moved + int QueryCurrentMove(); // 0..42 + void SetCurrentMove(int ); // 0..42 + int QueryMaxMove(); // 0..42 + int QueryHistoryCnt(); // 0..42 + TQString QueryProcessName(); + + KPlayer *createPlayer(int rtti, int io, bool isvirtual); + KPlayer * nextPlayer(KPlayer *last, bool exclusive=true); + + void newPlayersJoin(KGamePlayerList *,KGamePlayerList *,TQValueList<int> &); + +protected: + bool Move(int x,int id); + /** Check whether the field has a game over situation */ + int checkGameOver(KPlayer *); + /** Send to the computer player */ + void prepareGameMessage(TQDataStream &stream, TQ_INT32 pl); + /** Main function to do player input */ + bool playerInput(TQDataStream &msg,KPlayer *player); + /** Set the IO devices new */ + void recalcIO(); + /** Set the turn of the current player to true */ + void preparePlayerTurn(); + + +public slots: + void calcHint(); + + void slotPropertyChanged(KGamePropertyBase *,KGame *); + void slotPlayerPropertyChanged(KGamePropertyBase *,KPlayer *); + void moveDone(TQCanvasItem *,int); + void slotMessageUpdate(int,TQ_UINT32,TQ_UINT32); + void slotPrepareTurn(TQDataStream &stream,bool b,KGameIO *input,bool *eatevent); + void slotClientConnected(TQ_UINT32,KGame *); + void slotProcessQuery(TQDataStream &,KGameProcessIO *); + void slotProcessHint(TQDataStream &,KGameProcessIO *); + void slotGameOver(int status, KPlayer * p, KGame * me); + void slotRepeatMove(); + void loadSettings(); + +signals: + /** + * emmitted if the game status changes to run + */ + void signalGameRun(); + /** + * Emmitted if the chat origin changes + */ + void signalChatChanged(Kwin4Player *); + /** + * emmitted after a sprite move ends + **/ + void signalMoveDone(int,int); + void signalNextPlayer(); + /** + * emmitted if the game ends + **/ + void GameOver(int,KPlayer *,KGame *); + +private: + Kwin4View *pView; + + KGamePropertyInt mLastColumn; // last x moved + KGamePropertyInt mLastColour; // last colour moved + + KGamePropertyInt mHistoryCnt; + KGamePropertyArray<int> mField; // 42 pieces + Kwin4Player *yellowPlayer; + KGamePropertyInt mStartPlayer; // Player started game + KGamePropertyInt mAmzug; // Player's to move + KGamePropertyInt mMaxMove; // maximal move made in a game before undo + KGamePropertyInt mCurrentMove; // current move in the game + KGamePropertyArray<int> mFieldFilled; // to what height is the column filled + KGamePropertyInt mLastHint; + KGamePropertyInt mScore; // Computer score + KGamePropertyArray<int> mHistory; // to what height is the column filled + + KGameIO::IOMode mPlayedBy[NOOFPLAYER]; + KGameProcessIO *mHintProcess; + +}; + +#endif // KWIN4DOC_H + diff --git a/twin4/twin4/twin4player.cpp b/twin4/twin4/twin4player.cpp new file mode 100644 index 00000000..ca05ab5d --- /dev/null +++ b/twin4/twin4/twin4player.cpp @@ -0,0 +1,160 @@ +/*************************************************************************** + KWin4Player + ------------------- + begin : August 2001 + copyright : (C) |1995-2001 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + +// include files for KDE +#include <kdebug.h> +#include <kconfig.h> +#include <kgamepropertyhandler.h> + +#include "twin4player.h" +#include "statuswidget.h" + +Kwin4Player::Kwin4Player() : KPlayer(), sWidget(0) +{ + int id; + id=mWin.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,TQString("mWin")); + id=mRemis.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,TQString("mRemis")); + id=mLost.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,TQString("mLost")); + id=mBrk.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,TQString("mBrk")); + id=mAllWin.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,TQString("mAllWin")); + id=mAllRemis.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,TQString("mAllRemis")); + id=mAllLost.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,TQString("mAllLost")); + id=mAllBrk.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,TQString("mAllBrk")); + + dataHandler()->setPolicy(KGamePropertyBase::PolicyDirty,false); + + resetStats(); + connect(this,TQT_SIGNAL(signalPropertyChanged(KGamePropertyBase *,KPlayer *)), + this,TQT_SLOT(slotPlayerPropertyChanged(KGamePropertyBase *,KPlayer *))); +} + +#include <tqlabel.h> +#include <tqlcdnumber.h> + +void Kwin4Player::slotPlayerPropertyChanged(KGamePropertyBase *prop, KPlayer * /*player*/) +{ + if (!sWidget) return ; + if (!isActive()) return ; + if (prop->id()==KGamePropertyBase::IdName) + { + if(userId()) + sWidget->p1_name->setText(name()); + else + sWidget->p2_name->setText(name()); + } + else if (prop->id()==mWin.id()) + { + if(userId()){ + sWidget->p1_w->display(mWin); + sWidget->p1_n->display(mWin+mRemis+mLost); + } + else{ + sWidget->p2_w->display(mWin); + sWidget->p2_n->display(mWin+mRemis+mLost); + } + } + else if (prop->id()==mRemis.id()) + { + if(userId()){ + sWidget->p1_d->display(mRemis); + sWidget->p1_n->display(mWin+mRemis+mLost); + } + else{ + sWidget->p2_d->display(mRemis); + sWidget->p2_n->display(mWin+mRemis+mLost); + } + } + else if (prop->id()==mLost.id()) + { + if(userId()){ + sWidget->p1_l->display(mLost); + sWidget->p1_n->display(mWin+mRemis+mLost); + } + else{ + sWidget->p2_l->display(mLost); + sWidget->p2_n->display(mWin+mRemis+mLost); + } + } + else if (prop->id()==mBrk.id()) + { + if(userId()) + sWidget->p1_b->display(mBrk); + else + sWidget->p2_b->display(mBrk); + } +} + +void Kwin4Player::readConfig(KConfig *config) +{ + mAllWin.setValue(config->readNumEntry("win",0)); + mAllRemis.setValue(config->readNumEntry("remis",0)); + mAllLost.setValue(config->readNumEntry("lost",0)); + mAllBrk.setValue(config->readNumEntry("brk",0)); +} + +void Kwin4Player::writeConfig(KConfig *config) +{ + config->writeEntry("win",mAllWin.value()); + config->writeEntry("remis",mAllRemis.value()); + config->writeEntry("lost",mAllLost.value()); + config->writeEntry("brk",mAllBrk.value()); +} + +void Kwin4Player::incWin() +{ + mWin.setValue(mWin.value()+1); + mAllWin.setValue(mAllWin.value()+1); +} + +void Kwin4Player::incLost() +{ + mLost.setValue(mLost.value()+1); + mAllLost.setValue(mAllLost.value()+1); +} + +void Kwin4Player::incRemis() +{ + mRemis.setValue(mRemis.value()+1); + mAllRemis.setValue(mAllRemis.value()+1); +} + +void Kwin4Player::incBrk() +{ + mBrk.setValue(mBrk.value()+1); + mAllBrk.setValue(mAllBrk.value()+1); +} + +void Kwin4Player::resetStats(bool all) +{ + mWin=0; + mLost=0; + mBrk=0; + mRemis=0; + if (all) + { + mAllWin=0; + mAllLost=0; + mAllBrk=0; + mAllRemis=0; + } +} + +#include "twin4player.moc" + + + diff --git a/twin4/twin4/twin4player.h b/twin4/twin4/twin4player.h new file mode 100644 index 00000000..003c80a9 --- /dev/null +++ b/twin4/twin4/twin4player.h @@ -0,0 +1,73 @@ +/*************************************************************************** + Kwin4Player + ------------------- + begin : August 2001 + copyright : (C) 1995-2000 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KWIN4PLAYER_H +#define KWIN4PLAYER_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <kplayer.h> + +class StatusWidget; +class KConfig; + +class Kwin4Player : public KPlayer +{ + Q_OBJECT + TQ_OBJECT + + signals: + + public: + Kwin4Player(); + int rtti() const {return 1;} + void setWidget(StatusWidget *w) {sWidget=w;} + void readConfig(KConfig *config); + void writeConfig(KConfig *config); + void incWin(); + void incRemis(); + void incLost(); + void incBrk(); + int win() {return mAllWin.value();} + int lost() {return mAllLost.value();} + int brk() {return mAllBrk.value();} + int remis() {return mAllRemis.value();} + void resetStats(bool all=true); + + protected slots: + void slotPlayerPropertyChanged(KGamePropertyBase *prop,KPlayer *player); + + private: + // One session + KGamePropertyInt mWin; + KGamePropertyInt mRemis; + KGamePropertyInt mLost; + KGamePropertyInt mBrk; + + // all time + KGamePropertyInt mAllWin; + KGamePropertyInt mAllRemis; + KGamePropertyInt mAllLost; + KGamePropertyInt mAllBrk; + + StatusWidget *sWidget; +}; + +#endif // KWIN4PLAYER_H + diff --git a/twin4/twin4/twin4proc.cpp b/twin4/twin4/twin4proc.cpp new file mode 100644 index 00000000..4b798a62 --- /dev/null +++ b/twin4/twin4/twin4proc.cpp @@ -0,0 +1,432 @@ +/*************************************************************************** + kproc4.cpp - description + ------------------- + begin : Sun Apr 9 2000 + copyright : (C) 2000 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "twin4proc.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <kgamemessage.h> +#include <kdebug.h> + +#define MIN_TIME 1 // sec + +#define NOOFPLAYER 2/* Zwei Spieler */ +#define MAXANZAHL 6 /* Maximal 6 Steine pro Reihe */ +#define WIN4 4 /* 4er Reihe hat gewonnen */ +#define MAXZUG 42 /* Soviele Zuege moeglich */ +#define FELD_OFF 10 +#define LOWERT -999999999L +#define SIEG_WERT 9999999L + + +#define START_REK 1 // (0) 1:Nur Stellungsbewertung bei Level 1 + // 0:Level 1 schon eine Rekursion + +KComputer::KComputer() : TQObject(0,0) +{ + InitField(); + + const char *s1="7777776666666123456654321123456654321"; + const char *s2="0000000000000000000123456000000123456"; + + unsigned int i; + for (i=0;i<strlen(s1);i++) + lenofrow[i]=s1[i]-'0'; + for (i=0;i<strlen(s2);i++) + startofrow[i]=s2[i]-'0'; + + connect(&proc,TQT_SIGNAL(signalCommand(TQDataStream &,int ,int ,int )), + this,TQT_SLOT(slotCommand(TQDataStream & ,int ,int ,int ))); + connect(&proc,TQT_SIGNAL(signalInit(TQDataStream &,int)), + this,TQT_SLOT(slotInit(TQDataStream & ,int ))); + connect(&proc,TQT_SIGNAL(signalTurn(TQDataStream &,bool )), + this,TQT_SLOT(slotTurn(TQDataStream & ,bool ))); + fprintf(stderr, "----------------->\nKComputer::Computer\n"); +} + +void KComputer::slotInit(TQDataStream &in,int id) +{ + fprintf(stderr,"----------------->\nKComputer::slotInit\nid:%d\n",id); + /* + TQByteArray buffer; + TQDataStream out(buffer,IO_WriteOnly); + int msgid=KGameMessage::IdProcessQuery; + out << (int)1; + proc.sendSystemMessage(out,msgid,0); + */ +} + +void KComputer::slotTurn(TQDataStream &in,bool turn) +{ + TQByteArray buffer; + TQDataStream out(buffer,IO_WriteOnly); + fprintf(stderr,"----------------->\nKComputer::slotTurn\nturn:%d\n",turn); + if (turn) + { + // Create a move + long value=think(in,out,false); + int id=KGameMessage::IdPlayerInput; + proc.sendSystemMessage(out,id,0); + sendValue(value); + } +} + +void KComputer::sendValue(long value) +{ + TQ_INT8 cid=1; // notifies our KGameIO that this is a value message + int id=KGameMessage::IdProcessQuery; + TQByteArray buffer; + TQDataStream out(buffer,IO_WriteOnly); + out << cid << value; + proc.sendSystemMessage(out,id,0); +} + +long KComputer::think(TQDataStream &in,TQDataStream &out,bool hint) +{ + TQ_INT32 pl; + TQ_INT32 move; + TQ_INT32 tmp; + in >> pl ; + in >> tmp; + aktzug=tmp; + in >> tmp; + // We need all the +1 because the main programm has different defines + // for the colours. And chaning it here seems not to work.... + amZug=(Farbe)(tmp+1); + in >> tmp; + beginner=(Farbe)(tmp+1); + in >> tmp; + second=(Farbe)(tmp+1); + in >> tmp; + mymaxreklev=tmp; + fprintf(stderr,"think: pl=%d, aktzug=%d amzug=%d begin=%d second=%d level=%d\n", + pl,aktzug,amZug,beginner,second,mymaxreklev); + + InitField(); + + // Field as 42 TQ_INT8's + int i,j; + for (i=0;i<=SIZE_Y;i++) + { + for (j=0;j<=SIZE_X;j++) + { + TQ_INT8 col; + in >> col; + Farbe colour; + if (col<2) colour=(Farbe)(col+1); + else colour=(Farbe)col; + DoMove(j,colour,feldmatrix,anzahlmatrix); + } + } + + for (i=0;i<=SIZE_Y;i++) + { + char tstr[1024]; + tstr[0]=0; + for (j=0;j<=SIZE_X;j++) + { + sprintf(tstr+strlen(tstr),"%02d ", feldmatrix[i][j]); + } + fprintf(stderr,"%s\n",tstr); + } + + in >> tmp; + fprintf(stderr,"CHECKSUM=%ld should be 421256\n",(long)tmp); + + time_t timea,timee; + timea=time(0); + + int mymove; + mymove= GetCompMove(); + + fprintf(stderr,"Computermove to %d value=%ld\n",mymove,aktwert); + + timee=time(0); + // Sleep a minimum amount to slow down moves + if (timee-timea < MIN_TIME) sleep((MIN_TIME-(timee-timea))); + + + move=mymove; + if (hint) + { + out << pl << move; + } + else + { + out << pl << move; + } + return aktwert; +} + +void KComputer::slotCommand(TQDataStream &in,int msgid,int receiver,int sender) +{ + fprintf(stderr,"----------------->\nKComputer::slotCommand\nMsgid:%d\n",msgid); + TQByteArray buffer; + TQDataStream out(buffer,IO_WriteOnly); + switch(msgid) + { + case 2: // hint + { + TQ_INT8 cid=2; + TQ_INT32 pl=0; + TQ_INT32 move=3; + out << cid; + long value=think(in,out,true); + out << value; + int id=KGameMessage::IdProcessQuery; + proc.sendSystemMessage(out,id,0); + } + break; + default: + fprintf(stderr,"KComputer:: unknown command Msgid:%d\n",msgid); + } +} + +/** + * Computer Routinen + */ +int KComputer::GetCompMove() +{ + int cmove; + long cmax,wert; + int x; + FARBE lfeld[SIZE_Y_ALL+1][SIZE_X+1]; + char lanzahl[SIZE_Y_ALL+1]; + Farbe farbe; + + + farbe=amZug; + cmove=-1; /* Kein Zug */ + cmax=LOWERT; + for (x=0;x<=SIZE_X;x++) + { + if (anzahlmatrix[6+x]>=MAXANZAHL) continue; + memcpy(lanzahl,anzahlmatrix,sizeof(lanzahl)); + memcpy(lfeld,feldmatrix,sizeof(lfeld)); + + DoMove(x,farbe,lfeld,lanzahl); + wert=Wertung(farbe,lfeld,lanzahl,START_REK,aktzug+1); + + if (wert>=cmax) + { + cmax=wert; + cmove=x; + if (cmax>=SIEG_WERT) break; + } + }/*next x*/ + aktwert=cmax; + amZug=farbe; // Wertung changes amZug! +return cmove; +} + +long KComputer::Wertung(Farbe farbe,FARBE feld[][SIZE_X+1],char anzahl[],int reklev,int zug) +{ + static long gaus[]={10,50,300,500,300,50,10}; + FARBE lfeld[SIZE_Y_ALL+1][SIZE_X+1]; + char lanzahl[SIZE_Y_ALL+1]; + long max,wert; + int x; + Farbe winner; + + winner=GameOver(feld,anzahl); + if (winner!=Niemand) + { + if (winner==farbe) return(SIEG_WERT); + else return(-SIEG_WERT); + } + if (zug>=MAXZUG) return(0); /* Remis */ + if (reklev>=mymaxreklev) return Bewertung(farbe,feld); + + + farbe=SwitchPlayer(farbe); + max=LOWERT; + for (x=0;x<=SIZE_X;x++) + { + if (anzahl[6+x]>=MAXANZAHL) continue; + memcpy(lfeld,feld,sizeof(lfeld)); + memcpy(lanzahl,anzahl,sizeof(lanzahl)); + DoMove(x,farbe,lfeld,lanzahl); + wert=Wertung(farbe,lfeld,lanzahl,reklev+1,zug+1)+gaus[x]; + if (wert>=max) + { + max=wert; + if (max>=SIEG_WERT) break; + } + }/*next x*/ + return(-max); +}/*end wertung*/ + +long KComputer::Bewertung(Farbe farbe,FARBE feld[][SIZE_X+1]) +{ +/* Abstand: 0 1 2 3 4 5 */ +static long myWERT[]={2200,600, 300, 75, 20, 0}; +//static long myWERT[]={0,0,0,0,0,0}; +/* Wieviele von Farbe: 0 1 2 3 4 */ +static long steinWERT[4][5]= +{ + { 0, 500L, 40000L,200000L,SIEG_WERT}, // Leerfelder=0 + { 0, 500L, 8000L, 40000L,SIEG_WERT}, // =1 + { 0, 00L, 4000L, 25000L,SIEG_WERT}, // =2 + { 0, 00L, 2000L, 12500L,SIEG_WERT}, // =3 +}; + long gelb_wert,rot_wert,wert; + int cntcol,cnt; + Farbe color; + FARBE field; + int y,i,j; + gelb_wert=random(2500); + rot_wert=random(2500); + for (y=0;y<=SIZE_Y_ALL;y++) + { + if (lenofrow[y]<WIN4) continue; + for (i=0;i<=(lenofrow[y]-WIN4);i++) + { + color=Niemand; + wert=0; + cntcol=0; + cnt=0; + for (j=0;j<WIN4;j++) + { + field=feld[y][i+j+startofrow[y]]; + if ((Farbe)field==Rot) + { + if (color==Gelb) {color=Niemand;break;} + cntcol++; + color=Rot; + } + else if ((Farbe)field==Gelb) + { + if (color==Rot) {color=Niemand;break;} + cntcol++; + color=Gelb; + } + else + { + cnt+=field-FELD_OFF; + wert+=myWERT[field-FELD_OFF]; + } + }/*next j */ + if (cnt>3) cnt=3; + if (color==Rot) rot_wert+=(wert+steinWERT[cnt][cntcol]); + else if (color==Gelb) gelb_wert+=(wert+steinWERT[cnt][cntcol]); + }/*next i*/ + }/*next y*/ + if (farbe==Rot) wert=rot_wert-gelb_wert; + else wert=gelb_wert-rot_wert; +return(wert); +} + +Farbe KComputer::GameOver(FARBE feld[][SIZE_X+1],char anzahl[]) +{ + Farbe thiscolor,field; + int x,y,cnt; + for (y=0;y<=SIZE_Y_ALL;y++) + { + if (anzahl[y]<WIN4) continue; + if ( lenofrow[y]<WIN4 ) continue; + cnt=0; + thiscolor=Niemand; + for (x=0;x<lenofrow[y];x++) + { + field=(Farbe)feld[y][x+startofrow[y]]; + if (field==thiscolor) cnt++; + else {cnt=1;thiscolor=field;} + if ( (cnt>=WIN4)&&( (thiscolor==Gelb)||(thiscolor==Rot) ) ) return(thiscolor); + }/*next x */ + }/*next y*/ + return(Niemand); +} + +Farbe KComputer::SwitchPlayer(Farbe m_amZug) +{ + if (m_amZug==Niemand) + m_amZug=amZug; + if (m_amZug==Rot) + amZug=Gelb; + else if (m_amZug==Gelb) + amZug=Rot; + else amZug=beginner; + return amZug; +} + +void KComputer::DoMove(char move,Farbe farbe,FARBE feld[][SIZE_X+1],char anzahl[]) +{ + int x,i,y; + + if (farbe==Tip || farbe==Niemand) return ; // no real move + x=move; + y=anzahl[6+move]; + feld[y][x]=farbe; + + //if (farbe==Tip || farbe==Niemand) return ; // no real move + + feld[6+x][y]=farbe; + feld[13+x+y][x]=farbe; + feld[30+x-y][x]=farbe; + anzahl[y]++; + anzahl[6+x]++; + anzahl[13+x+y]++; + anzahl[30+x-y]++; + for (i=y+1;i<=SIZE_Y;i++) + { + feld[i][x]--; + feld[6+x][i]--; + feld[13+x+i][x]--; + feld[30+x-i][x]--; + } +} + +void KComputer::InitField() { + int x,y; + for (y=0;y<=SIZE_Y_ALL;y++) + anzahlmatrix[y]=0; + for (y=0;y<=SIZE_Y;y++) + { + for (x=0;x<=SIZE_X;x++) + { + feldmatrix[y][x]=(FARBE)(y+FELD_OFF); + feldmatrix[6+x][y]=(FARBE)(y+FELD_OFF); + feldmatrix[13+x+y][x]=(FARBE)(y+FELD_OFF); + feldmatrix[30+x-y][x]=(FARBE)(y+FELD_OFF); + } + }/* next y */ +} + +long KComputer::random(long max) +{ + long wert; + wert=proc.random()->getLong(max); + return wert; +} + +// Main startup +int main(int argc ,char * argv[]) +{ + // This is the computer player...it should do the calulation + // It doesn't do much here + fprintf(stderr,"Vor KComputer\n"); + fflush(stderr); + KComputer comp; + fprintf(stderr,"Vor exec\n"); + // And start the event loop + comp.proc.exec(argc,argv); + fprintf(stderr,"nach exec\n"); + return 1; +} +#include "twin4proc.moc" diff --git a/twin4/twin4/twin4proc.h b/twin4/twin4/twin4proc.h new file mode 100644 index 00000000..6d988c06 --- /dev/null +++ b/twin4/twin4/twin4proc.h @@ -0,0 +1,84 @@ +/*************************************************************************** + Kwin4 - Four in a Row for KDE + ------------------- + begin : March 2000 + copyright : (C) 1995-2001 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _KWIN4PROC_H_ +#define _KWIN4PROC_H_ + +#include <kgameprocess.h> + +// TODO match up with what is in twin4doc.h +typedef enum e_farbe {Niemand=0,Gelb=1,Rot=2,Tip=3,Rand=4} Farbe; +typedef char FARBE; + +#define SIZE_Y_ALL 36 +#define SIZE_X 6 +#define SIZE_Y 5 + +class KComputer : public TQObject +{ + +Q_OBJECT + TQ_OBJECT + +public: + KComputer(); + // The KGameProcess is the main program and event loop + KGameProcess proc; + +public slots: + void slotCommand(TQDataStream &, int msgid,int receiver,int sender); + void slotInit(TQDataStream &, int id); + void slotTurn(TQDataStream &, bool turn); + +protected: + void sendValue(long value); + long random(long max); + long think(TQDataStream &in,TQDataStream &out,bool hint); + + // Old computer stuff + Farbe SwitchPlayer(Farbe amZug=Niemand); + Farbe GameOver(FARBE feld[][SIZE_X+1],char anzahl[]); + void DoMove(char move,Farbe farbe,FARBE feld[][SIZE_X+1],char anzahl[]); + int GetCompMove(); + long Wertung(Farbe farbe,FARBE feld[][SIZE_X+1],char anzahl[],int reklev,int zug); + long Bewertung(Farbe farbe,FARBE feld[][SIZE_X+1]); + void InitField(); + +private: + /* rows: 0-5 =6 : horiz(i:0-6) */ + /* 6-12 =7 : vert(i:0-5) */ + /* 13-24 =12: diag-45(i:...) */ + /* 25-36 =12: diag45(i:...) */ + + char lenofrow[38]; + char startofrow[38]; + + Farbe beginner,second; // Welche Farbe faengt an und zieht nach + + Farbe amZug; // wer ist am Zug + Farbe winner; // who won thee game + FARBE feldmatrix[SIZE_Y_ALL+1][SIZE_X+1]; + char anzahlmatrix[SIZE_Y_ALL+1]; + + int aktzug; // welcher Zug ist getade gemacht 0..42 + int mymaxreklev; // maximale Rekursion + long aktwert; // Stellungsbewertung + +}; + +#endif // _KWIN4PROC_H_ + diff --git a/twin4/twin4/twin4ui.rc b/twin4/twin4/twin4ui.rc new file mode 100644 index 00000000..0024576f --- /dev/null +++ b/twin4/twin4/twin4ui.rc @@ -0,0 +1,28 @@ +<!DOCTYPE kpartgui> +<kpartgui name="twin4" version="1"> + +<MenuBar> + <Menu name="game"><text>&Game</text> + <Action name="new_game"/> + <Action name="open"/> + <Action name="save"/> + <Action name="end_game"/> + <Separator/> + <Action name="network_conf"/> + <Action name="network_chat"/> + <Action name="file_debug"/> + <Action name="flag"/> + <Separator/> + <Action name="hint"/> + <Separator/> + <Action name="game_exit"/> + </Menu> +</MenuBar> + +<ToolBar name="mainToolBar"><text>Main Toolbar</text> + <Action name="new_game"/> + <Action name="end_game"/> + <Action name="hint"/> +</ToolBar> + +</kpartgui> diff --git a/twin4/twin4/twin4view.cpp b/twin4/twin4/twin4view.cpp new file mode 100644 index 00000000..c425f90f --- /dev/null +++ b/twin4/twin4/twin4view.cpp @@ -0,0 +1,729 @@ +/*************************************************************************** + twin4view.cpp - View of the twin4 program + ------------------- + begin : Sun Mar 26 12:50:12 CEST 2000 + copyright : (C) |1995-2000 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "twin4view.h" + +#include <stdio.h> +#include <math.h> + +#include <kconfig.h> +#include <klocale.h> +#include <kapplication.h> +#include <kstandarddirs.h> + +#include "twin4doc.h" +#include "scorewidget.h" +#include "statuswidget.h" +#include "kspritecache.h" + +#include <tqlabel.h> +#include <tqlcdnumber.h> + +#define COL_STATUSLIGHT TQColor(210,210,255) +#define COL_STATUSFIELD TQColor(130,130,255) +#define COL_STATUSDARK TQColor(0,0,65) + +#define COL_STATUSBORDER black +#define COL_PLAYER TQColor(255,255,0) +#define COL_RED red +#define COL_YELLOW yellow + +class KIntroMove : public KSpriteMove +{ + public: + KIntroMove() : KSpriteMove() {mode=0;cnt=0;} + virtual bool spriteMove(double tx,double ty,KSprite *sp) + { + double sign=1.0; + if (!dir) sign=-1.0; + if (mode==0) + { + cnt++; + if (sp->x()<120.0) + { + sp->spriteMove(tx,ty); + return true; + } + else + { + cnt=0; + mode=1; + cx=sp->x(); + cy=sp->y()-sign*50; + } + } + if (mode==1) + { + if (cnt<360) + { + double x,y; + x=cx+50*cos((sign*90.0-sign*(double)cnt)/180.0*M_PI); + y=cy+50*sin((sign*90.0-sign*(double)cnt)/180.0*M_PI); + sp->move(x,y); + cnt+=5; + } + else + { + cnt=0; + mode=2; + } + } + if (mode==2) + { + return sp->spriteMove(tx,ty); + } + + return true; + } + + void setDir(bool d) {dir=d;} + +private: + + bool dir; + int mode; + int cnt; + double cx,cy; + +}; + +Kwin4View::Kwin4View(Kwin4Doc *theDoc, TQWidget *parent, const char *name) + : TQCanvasView(0,parent, name), doc(theDoc) +{ + mLastArrow=-1; + + + // localise data file + TQString file="twin4/grafix/default/grafix.rc"; + TQString mGrafix=kapp->dirs()->findResourceDir("data",file); + if (mGrafix.isNull()) + mGrafix="grafix/default/"; + else + mGrafix+="twin4/grafix/default/"; + if (global_debug>3) + kdDebug(12010) << "Localised grafix dir " << mGrafix << endl; + + // Allow overriding of the grafix directory + // This is a cheap and dirty way for theming + kapp->config()->setGroup("Themes"); + mGrafix = kapp->config()->readPathEntry("grafixdir", mGrafix); + + + setVScrollBarMode(AlwaysOff); + setHScrollBarMode(AlwaysOff); + + //setBackgroundMode(PaletteBase); + setBackgroundColor(TQColor(0,0,128)); + + mCanvas=new TQCanvas(TQT_TQOBJECT(parent)); + mCanvas->resize(parent->width(),parent->height()); + mCanvas->setDoubleBuffering(true); + mCanvas->setBackgroundColor(TQColor(0,0,128)); + setCanvas(mCanvas); + + mCache=new KSpriteCache(mGrafix,TQT_TQOBJECT(this)); + mCache->setCanvas(mCanvas); + KConfig *config=mCache->config(); + + TQPoint pnt; + config->setGroup("game"); + + pnt=config->readPointEntry("scorewidget"); + mScoreWidget=new ScoreWidget(viewport()); + addChild(mScoreWidget); + mScoreWidget->move(pnt); + + pnt=config->readPointEntry("statuswidget"); + mStatusWidget=new StatusWidget(this); + mStatusWidget->move(pnt); + TQPalette pal; + pal.setColor(TQColorGroup::Light, COL_STATUSLIGHT); + pal.setColor(TQColorGroup::Mid, COL_STATUSFIELD); + pal.setColor(TQColorGroup::Dark, COL_STATUSDARK); + mStatusWidget->setPalette(pal); + mStatusWidget->setBackgroundColor(COL_STATUSFIELD); + + mStatusWidget->wins->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->draws->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->loses->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->num->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->bk->setBackgroundColor(COL_STATUSFIELD); + + mStatusWidget->p1_name->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->p1_w->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->p1_d->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->p1_l->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->p1_n->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->p1_b->setBackgroundColor(COL_STATUSFIELD); + + mStatusWidget->p2_name->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->p2_w->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->p2_d->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->p2_l->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->p2_n->setBackgroundColor(COL_STATUSFIELD); + mStatusWidget->p2_b->setBackgroundColor(COL_STATUSFIELD); + + mScoreWidget->hide(); + mStatusWidget->hide(); + + move(0,0); + adjustSize(); + + initView(false); +} + +void Kwin4View::initView(bool deleteall) +{ + KSprite *sprite=0; + // mCanvas->setAdvancePeriod(period); + mCanvas->setAdvancePeriod(15); + + KConfig *config=mCache->config(); + config->setGroup("game"); + mSpreadX=config->readNumEntry("spread_x",0); + mSpreadY=config->readNumEntry("spread_y",0); + //kdDebug(12010) << "Spread : x=" << mSpreadX << " y=" << mSpreadY << endl; + + TQPixmap *pixmap=loadPixmap("background.png"); + if (pixmap) + mCanvas->tqsetBackgroundPixmap(*pixmap); + else + mCanvas->setBackgroundColor(TQColor(0,0,128)); + delete pixmap; + + if (doc->gametqStatus()==KGame::Intro) + { + mScoreWidget->hide(); + mStatusWidget->hide(); + drawIntro(deleteall); + } + else + { + // TODO in start functions to distinguish from intro + kdDebug(12010) << "Clearing board" <<endl; + drawBoard(deleteall); + mScoreWidget->show(); + mStatusWidget->show(); + // Hide pieces in any case + for (int i=0;i<42;i++) + { + sprite=(KSprite *)(mCache->getItem("piece",i)); + if (sprite) + { + introMoveDone(sprite,0 ); + sprite->hide(); + } + } + hideIntro(); + } + + // Hide stars in any case + for (int i=0;i<8;i++) + { + sprite=(KSprite *)(mCache->getItem("star",i)); + if (sprite) sprite->hide(); + } + // Hide GameOver in any case + sprite=(KSprite *)(mCache->getItem("gameover",1)); + if (sprite) sprite->hide(); + + + // Hide hint in any case + setHint(0,0,false); + + // Clear error text + clearError(); +} + +TQPixmap *Kwin4View::loadPixmap(TQString name) +{ + if (!mCache) + return 0; + return mCache->loadPixmap(name); +} + +/** + * Called by the doc/app to signal the end of the game + */ +void Kwin4View::EndGame() +{ + KSprite *sprite; + sprite=(KSprite *)(mCache->getItem("gameover",1)); + KConfig *config=mCache->config(); + int dest=config->readNumEntry("destY",150); + int src=config->readNumEntry("y",0); + //kdDebug(12010) << "MOVING gameover to " << dest << endl; + + if (sprite) + { + sprite->show(); + sprite->setY(src); + sprite->moveTo(sprite->x(),dest); + } +} + +/** + * Draw Sprites + */ +void Kwin4View::drawStar(int x,int y,int no) +{ + int dx,dy; + y=5-y; + KSprite *piece=(KSprite *)(mCache->getItem("piece",0)); + if (piece) + { + dx=piece->width(); + dy=piece->height(); + } + else + { + dx=0; + dy=0; + } + + KSprite *sprite=(KSprite *)(mCache->getItem("star",no)); + //kdDebug(12010) << " setStar("<<x<<","<<y<<","<<no<<") sprite=" << sprite<<endl; + if (sprite) + { + sprite->move(dx/2-sprite->width()/2+x*(dx+mSpreadX)+mBoardX, + dy/2-sprite->height()/2+y*(dy+mSpreadY)+mBoardY); + sprite->show(); + sprite->setAnimation(0); + } +} + +void Kwin4View::hideIntro() +{ + KSprite *sprite=0; + sprite=(KSprite *)(mCache->getItem("about",1)); + if (sprite) sprite->hide(); + sprite=(KSprite *)(mCache->getItem("win4about",1)); + if (sprite) sprite->hide(); + sprite=(KSprite *)(mCache->getItem("win4about",2)); + if (sprite) sprite->hide(); + + TQCanvasText *text; + text=(TQCanvasText *)(mCache->getItem("intro1",1)); + if (text) text->hide(); + text=(TQCanvasText *)(mCache->getItem("intro2",1)); + if (text) text->hide(); + text=(TQCanvasText *)(mCache->getItem("intro3",1)); + if (text) text->hide(); +} + +void Kwin4View::drawIntro(bool /*remove*/) +{ + KSprite *sprite=0; + // background + sprite=(KSprite *)(mCache->getItem("about",1)); + if (sprite) sprite->show(); + + sprite=(KSprite *)(mCache->getItem("win4about",1)); + if (sprite) sprite->show(); + sprite=(KSprite *)(mCache->getItem("win4about",2)); + if (sprite) + { + KConfig *config=mCache->config(); + double dest=config->readDoubleNumEntry("x2",250.0); + sprite->setX(dest); + sprite->show(); + } + + TQCanvasText *text; + text=(TQCanvasText *)(mCache->getItem("intro1",1)); + if (text) + { + text->setText(i18n("1. intro line, welcome to win4","Welcome")); + text->show(); + } + text=(TQCanvasText *)(mCache->getItem("intro2",1)); + if (text) + { + text->setText(i18n("2. intro line, welcome to win4","to")); + text->show(); + } + text=(TQCanvasText *)(mCache->getItem("intro3",1)); + if (text) + { + text->setText(i18n("3. intro line, welcome to win4","KWin4")); + text->show(); + } + // text + + // animation + for (int no=0;no<42;no++) + { + sprite=(KSprite *)(mCache->getItem("piece",no)); + if (sprite) + { + KIntroMove *move=new KIntroMove; + connect(sprite->createNotify(),TQT_SIGNAL(signalNotify(TQCanvasItem *,int)), + this,TQT_SLOT(introMoveDone(TQCanvasItem *,int))); + sprite->setMoveObject(move); + if (no%2==0) + { + sprite->move(0-20*no,0); + sprite->moveTo(150+2*no,105+4*no); + move->setDir(true); + sprite->setFrame((no/2)%2); + } + else + { + sprite->move(0-20*no,height()); + sprite->moveTo(340-2*(no-1),105+4*(no-1)); + move->setDir(false); + sprite->setFrame(((no-1)/2)%2); + } + // Increase the nz coord for consecutive peices + // to allow proper intro + // Carefule: The number must be more then the + // z coord of [empty] and less than [empty2] + sprite->setZ(sprite->z()+no/2); + // kdDebug(12010) << "Z("<<no<<")="<<sprite->z()<<endl; + sprite->show(); + } + } +} + +/** + * received after the movment of an intro sprite is finished + **/ +void Kwin4View::introMoveDone(TQCanvasItem *item,int ) +{ + KSprite *sprite=(KSprite *)item; + sprite->deleteNotify(); + KIntroMove *move=(KIntroMove *)sprite->moveObject(); + if (move) + { + delete move; + sprite->setMoveObject(0); + } +} + +void Kwin4View::drawBoard(bool remove) +{ + KSprite *sprite=0; + KSprite *board=0; + int x,y; + + // Board + // TODO: Without number as it is unique item + board=(KSprite *)(mCache->getItem("board",1)); + if (board) + { + if (remove) board->hide(); + else if (!board->isVisible()) board->show(); + mBoardX=(int)(board->x()); + mBoardY=(int)(board->y()); + } + else + { + mBoardX=0; + mBoardY=0; + } + //kdDebug(12010) << "Board X=" << mBoardX << " y="<<mBoardY<<endl; + + // Arrows + for (x=0;x<7;x++) + { + sprite=(KSprite *)(mCache->getItem("arrow",x)); + if (sprite) + { + sprite->setFrame(0); + sprite->setX(x*(sprite->width()+mSpreadX)+mBoardX); + if (remove) sprite->hide(); + else if (!sprite->isVisible()) sprite->show(); + } + }/* end arrows */ + + // Field + for (y=5;y>=0;y--) + { + for (x=0;x<7;x++) + { + // Lower layer + sprite=(KSprite *)(mCache->getItem("empty2",x+7*y)); + if (sprite) + { + sprite->move(x*(sprite->width()+mSpreadX)+mBoardX, + y*(sprite->height())+mBoardY); + if (remove) sprite->hide(); + else if (!sprite->isVisible()) sprite->show(); + } + // upper layer + sprite=(KSprite *)(mCache->getItem("empty",x+7*y)); + if (sprite) + { + sprite->move(x*(sprite->width()+mSpreadX)+mBoardX, + y*(sprite->height())+mBoardY); + if (remove) sprite->hide(); + else if (!sprite->isVisible()) sprite->show(); + } + } + }/* end field */ +} + +void Kwin4View::setSprite(int no, int x, int col, bool enable) +{ + KSprite *sprite; + sprite=(KSprite *)(mCache->getItem("piece",no)); + if (sprite) sprite->tqsetVisible(enable); + setArrow(x,col); +} + +void Kwin4View::setHint(int x,int y,bool enabled) +{ + KSprite *sprite; + sprite=(KSprite *)(mCache->getItem("hint",1)); + y=5-y; + if (sprite) + { + if (enabled) + { + sprite->move(x*(sprite->width()+mSpreadX)+mBoardX, + y*(sprite->height()+mSpreadY)+mBoardY); + } + sprite->tqsetVisible(enabled); + } +} + +void Kwin4View::setPiece(int x,int y,int color,int no,bool animation) +{ + KSprite *sprite=0; + + y=5-y; + + sprite=(KSprite *)(mCache->getItem("piece",no)); + + //kdDebug(12010) << " setPiece("<<x<<","<<y<<","<<color<<","<<no<<") sprite=" << sprite<<endl; + + // Check for removal of sprite + if (color==Niemand) + { + sprite->hide(); + return ; + } + + // Make sure the frames are ok + int c; + if (color==Gelb) c=0; + else c=1; + + if (sprite) + { + if (animation) + { + sprite->move(x*(sprite->width()+mSpreadX)+mBoardX, + mBoardY-sprite->height()-mSpreadY); + sprite->moveTo(sprite->x(), + sprite->y()+y*(sprite->height()+mSpreadY)+mBoardY); + connect(sprite->createNotify(),TQT_SIGNAL(signalNotify(TQCanvasItem *,int)), + doc,TQT_SLOT(moveDone(TQCanvasItem *,int))); + } + else + { + sprite->move(x*(sprite->width()+mSpreadX)+mBoardX, + mBoardY-sprite->height()-mSpreadY+ + y*(sprite->height()+mSpreadY)+mBoardY); + // Prevent moving (== speed =0) + sprite->moveTo(sprite->x(),sprite->y()); + connect(sprite->createNotify(),TQT_SIGNAL(signalNotify(TQCanvasItem *,int)), + doc,TQT_SLOT(moveDone(TQCanvasItem *,int))); + sprite->emitNotify(3); + } + + sprite->setFrame(c); + sprite->show(); + } +} + +void Kwin4View::setArrow(int x,int color) +{ + KSprite *sprite=0; + + if (mLastArrow>=0) + sprite=(KSprite *)(mCache->getItem("arrow",mLastArrow)); + else + sprite=0; + if (sprite) + sprite->setFrame(0); + + sprite=(KSprite *)(mCache->getItem("arrow",x)); + + //kdDebug(12010) << " setArrow("<<x<<","<<color<<") sprite=" << sprite<<endl; + + // Make sure the frames are ok + int c = 0; + if (color==Gelb) + c=1; + else if (color==Rot) + c=2; + + if (sprite) + sprite->setFrame(c); + mLastArrow=x; +} + + +/** + * Error message if the wrong player moved + */ +bool Kwin4View::wrongPlayer(KPlayer *player,KGameIO::IOMode io) +{ + // Hack to find out whether there is a IO Device whose turn it is + KGame::KGamePlayerList *playerList=doc->playerList(); + KPlayer *p; + + bool flag=false; + for ( p=playerList->first(); p!= 0; p=playerList->next() ) + { + if (p==player) continue; + if (p->hasRtti(io) && p->myTurn()) flag=true; + } + + if (flag) + return false; + + clearError(); + int rnd=(kapp->random()%4) +1; + TQString m; + m=TQString("text%1").tqarg(rnd); + TQString ms; + if (rnd==1) ms=i18n("Hold on... the other player has not been yet..."); + else if (rnd==2) ms=i18n("Hold your horses..."); + else if (rnd==3) ms=i18n("Ah ah ah... only one go at a time..."); + else ms=i18n("Please wait... it is not your turn."); + + // TODO MH can be unique + TQCanvasText *text=(TQCanvasText *)(mCache->getItem(m,1)); + if (text) + { + text->setText(ms); + text->show(); + } + return true; +} + +/** + * This slot is called when a key event is received. It then prduces a + * valid move for the game. + **/ +// This is analogous to the mouse event only it is called when a key is +// pressed +void Kwin4View::slotKeyInput(KGameIO *input,TQDataStream &stream,TQKeyEvent *e,bool *eatevent) +{ + // Ignore non running + if (!doc->isRunning()) + return; + // kdDebug(12010) << "KEY EVENT" << e->ascii() << endl; + + // Ignore non key press + if (e->type() != TQEvent::KeyPress) return ; + + // Our player + KPlayer *player=input->player(); + if (!player->myTurn()) + { + *eatevent=wrongPlayer(player,KGameIO::KeyIO); + return; + } + + int code=e->ascii(); + if (code<'1' || code>'7') + { + //kdDebug(12010) << "Key not supported\n"; + return ; + } + + // Create a move + TQ_INT32 move,pl; + move=code-'1'; + pl=player->userId(); + stream << pl << move; + *eatevent=true; +} + +/** + * This slot is called when a mouse key is pressed. As the mouse is used as + * input for all players + * this slot is called to generate a player move out of a mouse input, i.e. + * it converts a TQMouseEvent into a move for the game. We do here some + * simple nonsense and use the position of the mouse to generate + * moves containing the keycodes + */ +void Kwin4View::slotMouseInput(KGameIO *input,TQDataStream &stream,TQMouseEvent *mouse,bool *eatevent) +{ + // Only react to key pressed not released + if (mouse->type() != TQEvent::MouseButtonPress ) return ; + if (!doc->isRunning()) + return; + + // Our player + KPlayer *player=input->player(); + if (!player->myTurn()) + { + *eatevent=wrongPlayer(player,KGameIO::MouseIO); + return; + } + + if (mouse->button()!=Qt::LeftButton) return ; + //if (!doc->IsRunning()) return ; + + TQPoint point; + int x,y; + + point=mouse->pos() - TQPoint(15,40) - TQPoint(20,20); + if (point.x()<0) return ; + + x=point.x()/FIELD_SPACING; + y=point.y()/FIELD_SPACING; + + if (y>=FIELD_SIZE_Y) return ; + if (x<0 || x>=FIELD_SIZE_X) return; + + // Create a move + TQ_INT32 move,pl; + move=x; + pl=player->userId(); + stream << pl << move; + *eatevent=true; + // kdDebug(12010) << "Mouse input done..eatevent=true" << endl; +} + +/** + * Hide all the error sprites + */ +void Kwin4View::clearError() +{ + TQCanvasText *text; + + text=(TQCanvasText *)(mCache->getItem("text1",1)); + if (text) text->hide(); + text=(TQCanvasText *)(mCache->getItem("text2",1)); + if (text) text->hide(); + text=(TQCanvasText *)(mCache->getItem("text3",1)); + if (text) text->hide(); + text=(TQCanvasText *)(mCache->getItem("text4",1)); + if (text) text->hide(); +} + +void Kwin4View::resizeEvent(TQResizeEvent *e) +{ + if (mCanvas) mCanvas->resize(e->size().width(),e->size().height()); +} + +#include "twin4view.moc" diff --git a/twin4/twin4/twin4view.h b/twin4/twin4/twin4view.h new file mode 100644 index 00000000..f35ed154 --- /dev/null +++ b/twin4/twin4/twin4view.h @@ -0,0 +1,83 @@ +/*************************************************************************** + Kwin4 - Four in a Row for KDE + ------------------- + begin : March 2000 + copyright : (C) 1995-2001 by Martin Heni + email : martin@heni-online.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef KWIN4VIEW_H +#define KWIN4VIEW_H + +#include <tqcanvas.h> +#include <kgameio.h> + +class Kwin4Doc; +class ScoreWidget; +class StatusWidget; +class KSpriteCache; + +/** + * The Kwin4View class provides the view widget for the Kwin4App instance. + */ +class Kwin4View : public TQCanvasView +{ +Q_OBJECT + TQ_OBJECT + +public: + Kwin4View(Kwin4Doc *theDoc, TQWidget *parent = 0, const char *name=0); + + void initView(bool deleteall=true); + void drawBoard(bool remove=false); + void drawIntro(bool remove=false); + void hideIntro(); + void drawStar(int x,int y,int no); + void setArrow(int x,int color); + void setPiece(int x,int y,int color,int no,bool animation=true); + void setHint(int x,int y,bool enabled); + ScoreWidget *scoreWidget() {return mScoreWidget;} + StatusWidget *statusWidget() {return mStatusWidget;} + void setSprite(int no,int x, int col, bool enable); + void clearError(); + void EndGame(); + +public slots: + void slotMouseInput(KGameIO *input,TQDataStream &stream,TQMouseEvent *e,bool *eatevent); + void slotKeyInput(KGameIO *input,TQDataStream &stream,TQKeyEvent *e,bool *eatevent); + void introMoveDone(TQCanvasItem *item,int mode); + +protected: + TQPixmap *loadPixmap(TQString name); + void resizeEvent(TQResizeEvent *e); + bool wrongPlayer(KPlayer *player,KGameIO::IOMode io); + +private: + Kwin4Doc *doc; + TQCanvas *mCanvas; // our drawing canvas + KSpriteCache *mCache; // The sprite cache + TQString mGrafix; // grafix dir + + int mLastArrow; // last drawn arrow + int mLastX; // last piece + int mLastY; + int mSpreadX; // spread x,y board pieces + int mSpreadY; + int mBoardX; // board offset + int mBoardY; + + ScoreWidget *mScoreWidget; // score widget + StatusWidget *mStatusWidget; // score widget +}; + +#endif // KWIN4VIEW_H + |