summaryrefslogtreecommitdiffstats
path: root/twin4
diff options
context:
space:
mode:
Diffstat (limited to 'twin4')
-rw-r--r--twin4/AUTHORS1
-rw-r--r--twin4/COPYING341
-rw-r--r--twin4/INSTALL167
-rw-r--r--twin4/Makefile.am7
-rw-r--r--twin4/README26
-rw-r--r--twin4/grafix/Makefile.am22
-rw-r--r--twin4/grafix/default/aboute.pngbin0 -> 1056 bytes
-rw-r--r--twin4/grafix/default/arrow0.pngbin0 -> 1279 bytes
-rw-r--r--twin4/grafix/default/arrow1.pngbin0 -> 1131 bytes
-rw-r--r--twin4/grafix/default/arrow2.pngbin0 -> 1035 bytes
-rw-r--r--twin4/grafix/default/background.pngbin0 -> 184 bytes
-rw-r--r--twin4/grafix/default/board.pngbin0 -> 649 bytes
-rw-r--r--twin4/grafix/default/crnt.pngbin0 -> 1052 bytes
-rw-r--r--twin4/grafix/default/empty.pngbin0 -> 954 bytes
-rw-r--r--twin4/grafix/default/empty2.pngbin0 -> 495 bytes
-rw-r--r--twin4/grafix/default/game_over.pngbin0 -> 15301 bytes
-rw-r--r--twin4/grafix/default/grafix.rc148
-rw-r--r--twin4/grafix/default/introabout.pngbin0 -> 2047 bytes
-rw-r--r--twin4/grafix/default/piece0.pngbin0 -> 1171 bytes
-rw-r--r--twin4/grafix/default/piece1.pngbin0 -> 950 bytes
-rw-r--r--twin4/grafix/default/star0.pngbin0 -> 452 bytes
-rw-r--r--twin4/grafix/default/star1.pngbin0 -> 414 bytes
-rw-r--r--twin4/grafix/default/star2.pngbin0 -> 392 bytes
-rw-r--r--twin4/grafix/default/star3.pngbin0 -> 375 bytes
-rw-r--r--twin4/grafix/default/star4.pngbin0 -> 369 bytes
-rw-r--r--twin4/hi128-app-twin4.pngbin0 -> 10209 bytes
-rw-r--r--twin4/hi16-app-twin4.pngbin0 -> 871 bytes
-rw-r--r--twin4/hi22-app-twin4.pngbin0 -> 1281 bytes
-rw-r--r--twin4/hi32-app-twin4.pngbin0 -> 2037 bytes
-rw-r--r--twin4/hi48-app-twin4.pngbin0 -> 3574 bytes
-rw-r--r--twin4/hi64-app-twin4.pngbin0 -> 4236 bytes
-rw-r--r--twin4/index.html213
-rwxr-xr-xtwin4/install-sh238
-rw-r--r--twin4/twin4.desktop94
-rw-r--r--twin4/twin4.kdelnk24
-rw-r--r--twin4/twin4.lsm14
-rw-r--r--twin4/twin4/AboutDlg.kdevdlg138
-rw-r--r--twin4/twin4/Makefile.am28
-rw-r--r--twin4/twin4/kspritecache.cpp812
-rw-r--r--twin4/twin4/kspritecache.h508
-rw-r--r--twin4/twin4/main.cpp75
-rw-r--r--twin4/twin4/prefs.kcfgc7
-rw-r--r--twin4/twin4/scorewidget.cpp193
-rw-r--r--twin4/twin4/scorewidget.h46
-rw-r--r--twin4/twin4/settings.ui248
-rw-r--r--twin4/twin4/statistics.ui249
-rw-r--r--twin4/twin4/statuswidget.ui263
-rw-r--r--twin4/twin4/twin4.cpp626
-rw-r--r--twin4/twin4/twin4.h128
-rw-r--r--twin4/twin4/twin4.kcfg46
-rw-r--r--twin4/twin4/twin4doc.cpp1322
-rw-r--r--twin4/twin4/twin4doc.h195
-rw-r--r--twin4/twin4/twin4player.cpp160
-rw-r--r--twin4/twin4/twin4player.h73
-rw-r--r--twin4/twin4/twin4proc.cpp432
-rw-r--r--twin4/twin4/twin4proc.h84
-rw-r--r--twin4/twin4/twin4ui.rc28
-rw-r--r--twin4/twin4/twin4view.cpp729
-rw-r--r--twin4/twin4/twin4view.h83
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
new file mode 100644
index 00000000..78c8f4c1
--- /dev/null
+++ b/twin4/grafix/default/aboute.png
Binary files differ
diff --git a/twin4/grafix/default/arrow0.png b/twin4/grafix/default/arrow0.png
new file mode 100644
index 00000000..c93e7e63
--- /dev/null
+++ b/twin4/grafix/default/arrow0.png
Binary files differ
diff --git a/twin4/grafix/default/arrow1.png b/twin4/grafix/default/arrow1.png
new file mode 100644
index 00000000..81a2b5e7
--- /dev/null
+++ b/twin4/grafix/default/arrow1.png
Binary files differ
diff --git a/twin4/grafix/default/arrow2.png b/twin4/grafix/default/arrow2.png
new file mode 100644
index 00000000..89c9b815
--- /dev/null
+++ b/twin4/grafix/default/arrow2.png
Binary files differ
diff --git a/twin4/grafix/default/background.png b/twin4/grafix/default/background.png
new file mode 100644
index 00000000..7edcd84e
--- /dev/null
+++ b/twin4/grafix/default/background.png
Binary files differ
diff --git a/twin4/grafix/default/board.png b/twin4/grafix/default/board.png
new file mode 100644
index 00000000..d27ff61f
--- /dev/null
+++ b/twin4/grafix/default/board.png
Binary files differ
diff --git a/twin4/grafix/default/crnt.png b/twin4/grafix/default/crnt.png
new file mode 100644
index 00000000..5a3c0c69
--- /dev/null
+++ b/twin4/grafix/default/crnt.png
Binary files differ
diff --git a/twin4/grafix/default/empty.png b/twin4/grafix/default/empty.png
new file mode 100644
index 00000000..acb05be3
--- /dev/null
+++ b/twin4/grafix/default/empty.png
Binary files differ
diff --git a/twin4/grafix/default/empty2.png b/twin4/grafix/default/empty2.png
new file mode 100644
index 00000000..94ec038d
--- /dev/null
+++ b/twin4/grafix/default/empty2.png
Binary files differ
diff --git a/twin4/grafix/default/game_over.png b/twin4/grafix/default/game_over.png
new file mode 100644
index 00000000..45f030f7
--- /dev/null
+++ b/twin4/grafix/default/game_over.png
Binary files differ
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
new file mode 100644
index 00000000..23e4eeeb
--- /dev/null
+++ b/twin4/grafix/default/introabout.png
Binary files differ
diff --git a/twin4/grafix/default/piece0.png b/twin4/grafix/default/piece0.png
new file mode 100644
index 00000000..a2570b54
--- /dev/null
+++ b/twin4/grafix/default/piece0.png
Binary files differ
diff --git a/twin4/grafix/default/piece1.png b/twin4/grafix/default/piece1.png
new file mode 100644
index 00000000..80dbba36
--- /dev/null
+++ b/twin4/grafix/default/piece1.png
Binary files differ
diff --git a/twin4/grafix/default/star0.png b/twin4/grafix/default/star0.png
new file mode 100644
index 00000000..e125cc53
--- /dev/null
+++ b/twin4/grafix/default/star0.png
Binary files differ
diff --git a/twin4/grafix/default/star1.png b/twin4/grafix/default/star1.png
new file mode 100644
index 00000000..bce75e13
--- /dev/null
+++ b/twin4/grafix/default/star1.png
Binary files differ
diff --git a/twin4/grafix/default/star2.png b/twin4/grafix/default/star2.png
new file mode 100644
index 00000000..11175dd4
--- /dev/null
+++ b/twin4/grafix/default/star2.png
Binary files differ
diff --git a/twin4/grafix/default/star3.png b/twin4/grafix/default/star3.png
new file mode 100644
index 00000000..862f457e
--- /dev/null
+++ b/twin4/grafix/default/star3.png
Binary files differ
diff --git a/twin4/grafix/default/star4.png b/twin4/grafix/default/star4.png
new file mode 100644
index 00000000..40bf4bad
--- /dev/null
+++ b/twin4/grafix/default/star4.png
Binary files differ
diff --git a/twin4/hi128-app-twin4.png b/twin4/hi128-app-twin4.png
new file mode 100644
index 00000000..10ba8a47
--- /dev/null
+++ b/twin4/hi128-app-twin4.png
Binary files differ
diff --git a/twin4/hi16-app-twin4.png b/twin4/hi16-app-twin4.png
new file mode 100644
index 00000000..e908a50c
--- /dev/null
+++ b/twin4/hi16-app-twin4.png
Binary files differ
diff --git a/twin4/hi22-app-twin4.png b/twin4/hi22-app-twin4.png
new file mode 100644
index 00000000..31956ad2
--- /dev/null
+++ b/twin4/hi22-app-twin4.png
Binary files differ
diff --git a/twin4/hi32-app-twin4.png b/twin4/hi32-app-twin4.png
new file mode 100644
index 00000000..e7ae6152
--- /dev/null
+++ b/twin4/hi32-app-twin4.png
Binary files differ
diff --git a/twin4/hi48-app-twin4.png b/twin4/hi48-app-twin4.png
new file mode 100644
index 00000000..54a4e4a0
--- /dev/null
+++ b/twin4/hi48-app-twin4.png
Binary files differ
diff --git a/twin4/hi64-app-twin4.png b/twin4/hi64-app-twin4.png
new file mode 100644
index 00000000..69911333
--- /dev/null
+++ b/twin4/hi64-app-twin4.png
Binary files differ
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>&nbsp;</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>&nbsp;<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>&nbsp;<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>&nbsp;<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>&nbsp;<p>
+<B>The View menu</b>
+<P>
+
+<UL>
+<LI>Show statusbar<BR>
+Displays the status bar
+<br>
+</LI>
+</UL>
+
+
+<p>&nbsp;<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>&nbsp;<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>&nbsp;<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>
+&nbsp;
+<p>
+<hr>
+<B>Author: </B>
+<P>&copy; 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>&amp;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>&amp;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
+