From a11f93df4d9f59c1b34adac259c023e8a8c2b9ea Mon Sep 17 00:00:00 2001 From: Max-Wilhelm Bruker Date: Fri, 13 Mar 2009 22:50:41 +0100 Subject: [PATCH] initial commit --- cockatrice/Doxyfile | 311 +++++++++++++ cockatrice/clienttest.pro | 15 + cockatrice/copying | 340 ++++++++++++++ cockatrice/src/carddatabase.cpp | 203 ++++++++ cockatrice/src/carddatabase.h | 51 ++ cockatrice/src/carddragitem.cpp | 97 ++++ cockatrice/src/carddragitem.h | 28 ++ cockatrice/src/cardinfowidget.cpp | 61 +++ cockatrice/src/cardinfowidget.h | 29 ++ cockatrice/src/carditem.cpp | 202 ++++++++ cockatrice/src/carditem.h | 81 ++++ cockatrice/src/cardlist.cpp | 31 ++ cockatrice/src/cardlist.h | 16 + cockatrice/src/client.cpp | 322 +++++++++++++ cockatrice/src/client.h | 86 ++++ cockatrice/src/counter.cpp | 30 ++ cockatrice/src/counter.h | 24 + cockatrice/src/counterlist.cpp | 11 + cockatrice/src/counterlist.h | 12 + cockatrice/src/decklistmodel.cpp | 92 ++++ cockatrice/src/decklistmodel.h | 36 ++ cockatrice/src/dlg_connect.cpp | 61 +++ cockatrice/src/dlg_connect.h | 23 + cockatrice/src/dlg_creategame.cpp | 85 ++++ cockatrice/src/dlg_creategame.h | 28 ++ cockatrice/src/dlg_games.cpp | 87 ++++ cockatrice/src/dlg_games.h | 32 ++ cockatrice/src/dlg_startgame.cpp | 63 +++ cockatrice/src/dlg_startgame.h | 26 ++ cockatrice/src/game.cpp | 371 +++++++++++++++ cockatrice/src/game.h | 80 ++++ cockatrice/src/gamesmodel.cpp | 74 +++ cockatrice/src/gamesmodel.h | 26 ++ cockatrice/src/gameview.cpp | 33 ++ cockatrice/src/gameview.h | 14 + cockatrice/src/gravezone.cpp | 53 +++ cockatrice/src/gravezone.h | 17 + cockatrice/src/handzone.cpp | 73 +++ cockatrice/src/handzone.h | 17 + cockatrice/src/libraryzone.cpp | 88 ++++ cockatrice/src/libraryzone.h | 21 + cockatrice/src/main.cpp | 51 ++ cockatrice/src/messagelogwidget.cpp | 147 ++++++ cockatrice/src/messagelogwidget.h | 39 ++ cockatrice/src/pendingcommand.h | 19 + cockatrice/src/player.cpp | 296 ++++++++++++ cockatrice/src/player.h | 71 +++ cockatrice/src/playerlist.cpp | 11 + cockatrice/src/playerlist.h | 12 + cockatrice/src/playerzone.cpp | 98 ++++ cockatrice/src/playerzone.h | 47 ++ cockatrice/src/rfgzone.cpp | 53 +++ cockatrice/src/rfgzone.h | 17 + cockatrice/src/servereventdata.cpp | 49 ++ cockatrice/src/servereventdata.h | 54 +++ cockatrice/src/servergame.h | 21 + cockatrice/src/serverplayer.h | 17 + cockatrice/src/serverresponse.h | 22 + cockatrice/src/serverzone.h | 21 + cockatrice/src/serverzonecard.h | 28 ++ cockatrice/src/sideboardzone.cpp | 54 +++ cockatrice/src/sideboardzone.h | 17 + cockatrice/src/tablezone.cpp | 56 +++ cockatrice/src/tablezone.h | 22 + cockatrice/src/window.cpp | 258 ++++++++++ cockatrice/src/window.h | 85 ++++ cockatrice/src/zoneclosebutton.cpp | 18 + cockatrice/src/zoneclosebutton.h | 17 + cockatrice/src/zonelist.cpp | 11 + cockatrice/src/zonelist.h | 12 + cockatrice/src/zoneviewlayout.cpp | 36 ++ cockatrice/src/zoneviewlayout.h | 25 + cockatrice/src/zoneviewwidget.cpp | 45 ++ cockatrice/src/zoneviewwidget.h | 31 ++ cockatrice/src/zoneviewzone.cpp | 104 +++++ cockatrice/src/zoneviewzone.h | 27 ++ servatrice/Doxyfile | 311 +++++++++++++ servatrice/copying | 340 ++++++++++++++ servatrice/servertest.pro | 32 ++ servatrice/src/counter.cpp | 21 + servatrice/src/counter.h | 37 ++ servatrice/src/main.cpp | 33 ++ servatrice/src/playerzone.cpp | 86 ++++ servatrice/src/playerzone.h | 55 +++ servatrice/src/returnmessage.cpp | 33 ++ servatrice/src/returnmessage.h | 21 + servatrice/src/testcard.cpp | 62 +++ servatrice/src/testcard.h | 63 +++ servatrice/src/testrandom.cpp | 18 + servatrice/src/testrandom.h | 18 + servatrice/src/testserver.cpp | 107 +++++ servatrice/src/testserver.h | 49 ++ servatrice/src/testservergame.cpp | 155 ++++++ servatrice/src/testservergame.h | 64 +++ servatrice/src/testservergamethread.cpp | 20 + servatrice/src/testservergamethread.h | 30 ++ servatrice/src/testserversocket.cpp | 595 ++++++++++++++++++++++++ servatrice/src/testserversocket.h | 81 ++++ servatrice/src/version.h | 21 + 99 files changed, 7493 insertions(+) create mode 100644 cockatrice/Doxyfile create mode 100644 cockatrice/clienttest.pro create mode 100644 cockatrice/copying create mode 100644 cockatrice/src/carddatabase.cpp create mode 100644 cockatrice/src/carddatabase.h create mode 100644 cockatrice/src/carddragitem.cpp create mode 100644 cockatrice/src/carddragitem.h create mode 100644 cockatrice/src/cardinfowidget.cpp create mode 100644 cockatrice/src/cardinfowidget.h create mode 100644 cockatrice/src/carditem.cpp create mode 100644 cockatrice/src/carditem.h create mode 100644 cockatrice/src/cardlist.cpp create mode 100644 cockatrice/src/cardlist.h create mode 100644 cockatrice/src/client.cpp create mode 100644 cockatrice/src/client.h create mode 100644 cockatrice/src/counter.cpp create mode 100644 cockatrice/src/counter.h create mode 100644 cockatrice/src/counterlist.cpp create mode 100644 cockatrice/src/counterlist.h create mode 100644 cockatrice/src/decklistmodel.cpp create mode 100644 cockatrice/src/decklistmodel.h create mode 100644 cockatrice/src/dlg_connect.cpp create mode 100644 cockatrice/src/dlg_connect.h create mode 100644 cockatrice/src/dlg_creategame.cpp create mode 100644 cockatrice/src/dlg_creategame.h create mode 100644 cockatrice/src/dlg_games.cpp create mode 100644 cockatrice/src/dlg_games.h create mode 100644 cockatrice/src/dlg_startgame.cpp create mode 100644 cockatrice/src/dlg_startgame.h create mode 100644 cockatrice/src/game.cpp create mode 100644 cockatrice/src/game.h create mode 100644 cockatrice/src/gamesmodel.cpp create mode 100644 cockatrice/src/gamesmodel.h create mode 100644 cockatrice/src/gameview.cpp create mode 100644 cockatrice/src/gameview.h create mode 100644 cockatrice/src/gravezone.cpp create mode 100644 cockatrice/src/gravezone.h create mode 100644 cockatrice/src/handzone.cpp create mode 100644 cockatrice/src/handzone.h create mode 100644 cockatrice/src/libraryzone.cpp create mode 100644 cockatrice/src/libraryzone.h create mode 100644 cockatrice/src/main.cpp create mode 100644 cockatrice/src/messagelogwidget.cpp create mode 100644 cockatrice/src/messagelogwidget.h create mode 100644 cockatrice/src/pendingcommand.h create mode 100644 cockatrice/src/player.cpp create mode 100644 cockatrice/src/player.h create mode 100644 cockatrice/src/playerlist.cpp create mode 100644 cockatrice/src/playerlist.h create mode 100644 cockatrice/src/playerzone.cpp create mode 100644 cockatrice/src/playerzone.h create mode 100644 cockatrice/src/rfgzone.cpp create mode 100644 cockatrice/src/rfgzone.h create mode 100644 cockatrice/src/servereventdata.cpp create mode 100644 cockatrice/src/servereventdata.h create mode 100644 cockatrice/src/servergame.h create mode 100644 cockatrice/src/serverplayer.h create mode 100644 cockatrice/src/serverresponse.h create mode 100644 cockatrice/src/serverzone.h create mode 100644 cockatrice/src/serverzonecard.h create mode 100644 cockatrice/src/sideboardzone.cpp create mode 100644 cockatrice/src/sideboardzone.h create mode 100644 cockatrice/src/tablezone.cpp create mode 100644 cockatrice/src/tablezone.h create mode 100644 cockatrice/src/window.cpp create mode 100644 cockatrice/src/window.h create mode 100644 cockatrice/src/zoneclosebutton.cpp create mode 100644 cockatrice/src/zoneclosebutton.h create mode 100644 cockatrice/src/zonelist.cpp create mode 100644 cockatrice/src/zonelist.h create mode 100644 cockatrice/src/zoneviewlayout.cpp create mode 100644 cockatrice/src/zoneviewlayout.h create mode 100644 cockatrice/src/zoneviewwidget.cpp create mode 100644 cockatrice/src/zoneviewwidget.h create mode 100644 cockatrice/src/zoneviewzone.cpp create mode 100644 cockatrice/src/zoneviewzone.h create mode 100755 servatrice/Doxyfile create mode 100755 servatrice/copying create mode 100755 servatrice/servertest.pro create mode 100644 servatrice/src/counter.cpp create mode 100644 servatrice/src/counter.h create mode 100644 servatrice/src/main.cpp create mode 100644 servatrice/src/playerzone.cpp create mode 100644 servatrice/src/playerzone.h create mode 100644 servatrice/src/returnmessage.cpp create mode 100644 servatrice/src/returnmessage.h create mode 100644 servatrice/src/testcard.cpp create mode 100644 servatrice/src/testcard.h create mode 100644 servatrice/src/testrandom.cpp create mode 100644 servatrice/src/testrandom.h create mode 100644 servatrice/src/testserver.cpp create mode 100644 servatrice/src/testserver.h create mode 100644 servatrice/src/testservergame.cpp create mode 100644 servatrice/src/testservergame.h create mode 100644 servatrice/src/testservergamethread.cpp create mode 100644 servatrice/src/testservergamethread.h create mode 100644 servatrice/src/testserversocket.cpp create mode 100644 servatrice/src/testserversocket.h create mode 100644 servatrice/src/version.h diff --git a/cockatrice/Doxyfile b/cockatrice/Doxyfile new file mode 100644 index 00000000..0ae4b93f --- /dev/null +++ b/cockatrice/Doxyfile @@ -0,0 +1,311 @@ +# Doxyfile 1.5.5-KDevelop + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = clienttest +PROJECT_NUMBER = 0.1 +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = /home/brukie/ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = /home/brukie/clienttest +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY \ + *.F90 \ + *.F \ + *.VHD \ + *.VHDL \ + *.C \ + *.H \ + *.tlh \ + *.diff \ + *.patch \ + *.moc \ + *.xpm \ + *.dox +RECURSIVE = yes +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NONE +TREEVIEW_WIDTH = 250 +FORMULA_FONTSIZE = 10 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = yes +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = clienttest.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_FONTNAME = FreeSans +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/cockatrice/clienttest.pro b/cockatrice/clienttest.pro new file mode 100644 index 00000000..99790bcd --- /dev/null +++ b/cockatrice/clienttest.pro @@ -0,0 +1,15 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Sa Sep 6 14:27:18 2008 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . src +INCLUDEPATH += . src + +QT += network opengl +#QTPLUGIN += qjpeg + +# Input +HEADERS += src/counter.h src/dlg_games.h src/dlg_creategame.h src/dlg_connect.h src/gamesmodel.h src/client.h src/window.h src/servergame.h src/servereventdata.h src/serverresponse.h src/pendingcommand.h src/zonelist.h src/counterlist.h src/playerzone.h src/player.h src/cardlist.h src/carditem.h src/tablezone.h src/handzone.h src/playerlist.h src/game.h src/carddatabase.h src/gameview.h src/decklistmodel.h src/dlg_startgame.h src/cardinfowidget.h src/messagelogwidget.h src/serverzonecard.h src/zoneviewzone.h src/zoneviewwidget.h src/libraryzone.h src/gravezone.h src/rfgzone.h src/sideboardzone.h src/carddragitem.h src/zoneclosebutton.h src/zoneviewlayout.h +SOURCES += src/counter.cpp src/dlg_games.cpp src/dlg_creategame.cpp src/dlg_connect.cpp src/client.cpp src/main.cpp src/window.cpp src/servereventdata.cpp src/gamesmodel.cpp src/player.cpp src/playerzone.cpp src/zonelist.cpp src/counterlist.cpp src/cardlist.cpp src/carditem.cpp src/tablezone.cpp src/handzone.cpp src/playerlist.cpp src/game.cpp src/carddatabase.cpp src/gameview.cpp src/decklistmodel.cpp src/dlg_startgame.cpp src/cardinfowidget.cpp src/messagelogwidget.cpp src/zoneviewzone.cpp src/zoneviewwidget.cpp src/libraryzone.cpp src/gravezone.cpp src/rfgzone.cpp src/sideboardzone.cpp src/carddragitem.cpp src/zoneclosebutton.cpp src/zoneviewlayout.cpp diff --git a/cockatrice/copying b/cockatrice/copying new file mode 100644 index 00000000..5b6e7c66 --- /dev/null +++ b/cockatrice/copying @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp new file mode 100644 index 00000000..8eb325c6 --- /dev/null +++ b/cockatrice/src/carddatabase.cpp @@ -0,0 +1,203 @@ +#include "carddatabase.h" +#include +#include +#include +#include + +CardInfo::CardInfo(const QString &_name, const QString &_manacost, const QString &_cardtype, const QString &_powtough, const QStringList &_text) + : name(_name), manacost(_manacost), cardtype(_cardtype), powtough(_powtough), text(_text), pixmap(NULL) +{ + +} + +CardInfo::CardInfo(QDataStream &stream) + : pixmap(NULL) +{ + stream >> name + >> editions + >> manacost + >> cardtype + >> powtough + >> text; +} + +CardInfo::~CardInfo() +{ + if (pixmap) + qDebug(QString("Deleting pixmap for %1").arg(name).toLatin1()); + delete pixmap; +} + +void CardInfo::addEdition(const QString &edition) +{ + if (!editions.contains(edition)) + editions << edition; +} + +QPixmap *CardInfo::getPixmap() +{ + if (pixmap) + return pixmap; + pixmap = new QPixmap(); + if (getName().isEmpty()) { + pixmap->load("../pics/back.jpg"); + return pixmap; + } + qDebug(QString("CardDatabase: loading pixmap for %1").arg(getName()).toLatin1()); + for (int i = 0; i < editions.size(); i++) { + /* Fire // Ice */ + if (pixmap->load(QString("../pics/%1/%2.full.jpg").arg(editions.at(i)).arg(getName().replace(" // ", "")))) + return pixmap; + if (pixmap->load(QString("../pics/%1/%2%3.full.jpg").arg(editions.at(i)).arg(getName().replace(" // ", "")).arg(1))) + return pixmap; + } + pixmap->load("../pics/none.jpg"); + return pixmap; +} + +void CardInfo::saveToStream(QDataStream &stream) +{ + stream << name + << editions + << manacost + << cardtype + << powtough + << text; +} + +CardDatabase::CardDatabase() +{ +} + +CardDatabase::~CardDatabase() +{ + clear(); +} + +void CardDatabase::clear() +{ + QHashIterator i(hash); + while (i.hasNext()) { + i.next(); + delete i.value(); + } + hash.clear(); +} + +CardInfo *CardDatabase::getCard(const QString &cardName) +{ + if (hash.contains(cardName)) + return hash.value(cardName); + else { + qDebug(QString("CardDatabase: card not found: %1").arg(cardName).toLatin1()); + CardInfo *newCard = new CardInfo(cardName); + newCard->addEdition("TK"); + hash.insert(cardName, newCard); + return newCard; + } +} + +void CardDatabase::importOracle() +{ + clear(); + QDir dir("../db"); + + // XXX User soll selber auswählen können, welche Karten ihm am besten gefallen. + // XXX Muss momentan schmutzig über Zahlen vor den Dateinamen gemacht werden. + + dir.setSorting(QDir::Name | QDir::IgnoreCase); + QFileInfoList files = dir.entryInfoList(QStringList() << "*.txt"); + for (int k = 0; k < files.size(); k++) { + QFileInfo i = files[k]; + QString edition = i.fileName().mid(i.fileName().indexOf('_') + 1); + edition = edition.left(edition.indexOf('.')); + QFile file(i.filePath()); + file.open(QIODevice::ReadOnly | QIODevice::Text); + QTextStream in(&file); + while (!in.atEnd()) { + QString cardname = in.readLine(); + QString manacost = in.readLine(); + QString cardtype, powtough; + QStringList text; + if (manacost.contains("Land", Qt::CaseInsensitive)) { + cardtype = manacost; + manacost.clear(); + } else { + cardtype = in.readLine(); + powtough = in.readLine(); + // Dirty hack. + // Cards to test: Any creature, any basic land, Ancestral Vision, Fire // Ice. + if (!powtough.contains("/") || powtough.size() > 5) { + text << powtough; + powtough = QString(); + } + } + QString line = in.readLine(); + while (!line.isEmpty()) { + text << line; + line = in.readLine(); + } + CardInfo *card; + if (hash.contains(cardname)) + card = hash.value(cardname); + else { + card = new CardInfo(cardname, manacost, cardtype, powtough, text); + hash.insert(cardname, card); + } + card->addEdition(edition); + } + } + + qDebug(QString("CardDatabase: %1 cards imported").arg(hash.size()).toLatin1()); + + CardInfo *empty = new CardInfo(); + empty->getPixmap(); // cache pixmap for card back + hash.insert("", empty); +} + +int CardDatabase::loadFromFile(const QString &fileName) +{ + QFile file(fileName); + file.open(QIODevice::ReadOnly); + QDataStream in(&file); + in.setVersion(QDataStream::Qt_4_4); + + quint32 _magicNumber, _fileVersion, cardCount; + in >> _magicNumber + >> _fileVersion + >> cardCount; + + if (_magicNumber != magicNumber) + return -1; + if (_fileVersion != fileVersion) + return -2; + + clear(); + hash.reserve(cardCount); + for (unsigned int i = 0; i < cardCount; i++) { + CardInfo *newCard = new CardInfo(in); + hash.insert(newCard->getName(), newCard); + } + + return cardCount; +} + +bool CardDatabase::saveToFile(const QString &fileName) +{ + QFile file(fileName); + file.open(QIODevice::WriteOnly); + QDataStream out(&file); + out.setVersion(QDataStream::Qt_4_4); + + out << (quint32) magicNumber + << (quint32) fileVersion + << (quint32) hash.size(); + + QHashIterator i(hash); + while (i.hasNext()) { + i.next(); + i.value()->saveToStream(out); + } + + return true; +} diff --git a/cockatrice/src/carddatabase.h b/cockatrice/src/carddatabase.h new file mode 100644 index 00000000..8ca624be --- /dev/null +++ b/cockatrice/src/carddatabase.h @@ -0,0 +1,51 @@ +#ifndef CARDDATABASE_H +#define CARDDATABASE_H + +#include +#include +#include + +class CardInfo { +private: + QString name; + QStringList editions; + QString manacost; + QString cardtype; + QString powtough; + QStringList text; + QPixmap *pixmap; +public: + CardInfo(const QString &_name = QString(), + const QString &_manacost = QString(), + const QString &_cardtype = QString(), + const QString &_powtough = QString(), + const QStringList &_text = QStringList()); + CardInfo(QDataStream &stream); + ~CardInfo(); + QString getName() const { return name; } + QStringList getEditions() const { return editions; } + QString getManacost() const { return manacost; } + QString getCardType() const { return cardtype; } + QString getPowTough() const { return powtough; } + QStringList getText() const { return text; } + void addEdition(const QString &edition); + QPixmap *getPixmap(); + void saveToStream(QDataStream &stream); +}; + +class CardDatabase { +private: + QHash hash; + static const unsigned int magicNumber = 0x12345678; + static const unsigned int fileVersion = 1; +public: + CardDatabase(); + ~CardDatabase(); + void clear(); + CardInfo *getCard(const QString &cardName = QString()); + void importOracle(); + int loadFromFile(const QString &fileName); + bool saveToFile(const QString &fileName); +}; + +#endif diff --git a/cockatrice/src/carddragitem.cpp b/cockatrice/src/carddragitem.cpp new file mode 100644 index 00000000..5638a421 --- /dev/null +++ b/cockatrice/src/carddragitem.cpp @@ -0,0 +1,97 @@ +#include "carddragitem.h" +#include "playerzone.h" +#include + +CardDragItem::CardDragItem(QGraphicsScene *scene, PlayerZone *_startZone, QPixmap *_image, int _id, const QPointF &_hotSpot, QGraphicsItem *parent) + : QGraphicsItem(parent), image(_image), id(_id), hotSpot(_hotSpot), startZone(_startZone) +{ + if ((hotSpot.x() < 0) || (hotSpot.y() < 0)) { + qDebug(QString("CardDragItem: coordinate overflow: x = %1, y = %2").arg(hotSpot.x()).arg(hotSpot.y()).toLatin1()); + hotSpot = QPointF(); + } else if ((hotSpot.x() > CARD_WIDTH) || (hotSpot.y() > CARD_HEIGHT)) { + qDebug(QString("CardDragItem: coordinate overflow: x = %1, y = %2").arg(hotSpot.x()).arg(hotSpot.y()).toLatin1()); + hotSpot = QPointF(CARD_WIDTH, CARD_HEIGHT); + } + + setZValue(2000000000); + setCacheMode(DeviceCoordinateCache); + + scene->addItem(this); +} + +CardDragItem::~CardDragItem() +{ + qDebug("CardDragItem destructor"); +} + +QRectF CardDragItem::boundingRect() const +{ + return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT); +} + +void CardDragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ +// Q_UNUSED(option); + Q_UNUSED(widget); + + QRectF foo = option->matrix.mapRect(boundingRect()); + QPixmap bar = image->scaled(foo.width(), foo.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + painter->drawPixmap(boundingRect(), bar, bar.rect()); + +// painter->drawPixmap(boundingRect(), *image, QRectF(0, 0, image->width(), image->height())); +} + +void CardDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + QPointF sp = event->scenePos(); + QList colliding = scene()->items(sp); + + PlayerZone *cursorZone = 0; + for (int i = colliding.size() - 1; i >= 0; i--) { + if ((cursorZone = qgraphicsitem_cast(colliding.at(i)))) { + if (cursorZone->getName() == "table") { + QPointF cp = cursorZone->scenePos(); + QPointF localpos = sp - hotSpot - cp; + setPos(QPointF(round(localpos.x() / RASTER_WIDTH) * RASTER_WIDTH, round(localpos.y() / RASTER_HEIGHT) * RASTER_HEIGHT) + cp); + } else + setPos(sp - hotSpot); + break; + } + } + event->accept(); +} + +void CardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + setCursor(Qt::OpenHandCursor); + QGraphicsScene *sc = scene(); + QPointF sp = scenePos(); + sc->removeItem(this); + QList colliding = sc->items(event->scenePos()); + + qDebug(QString("drop: %1 collisions").arg(colliding.size()).toLatin1()); + PlayerZone *dropZone = 0; + for (int i = colliding.size() - 1; i >= 0; i--) { + QRectF bbox = colliding.at(i)->boundingRect(); + qDebug(QString("bbox x %1 y %2 w %3 h %4").arg(bbox.x()).arg(bbox.y()).arg(bbox.width()).arg(bbox.height()).toLatin1()); + + if ((dropZone = qgraphicsitem_cast(colliding.at(i)))) { + qDebug("zone found"); + break; + } + } + + if (dropZone) { + dropZone->handleDropEvent(id, startZone, (sp - dropZone->pos()).toPoint()); + QList childList = childItems(); + for (int i = 0; i < childList.size(); i++) { + CardDragItem *c = qgraphicsitem_cast(childList.at(i)); + if (!c) + QMessageBox::critical(0, "fehler", "null"); + dropZone->handleDropEvent(c->id, startZone, (sp - dropZone->pos() + c->pos()).toPoint()); + } + } else + QMessageBox::critical(0, "fehler", "fehler"); + + event->accept(); +} diff --git a/cockatrice/src/carddragitem.h b/cockatrice/src/carddragitem.h new file mode 100644 index 00000000..b6442c35 --- /dev/null +++ b/cockatrice/src/carddragitem.h @@ -0,0 +1,28 @@ +#ifndef CARDDRAGITEM_H +#define CARDDRAGITEM_H + +#include "carditem.h" + +class QGraphicsScene; +class PlayerZone; + +class CardDragItem : public QGraphicsItem { +private: + QPixmap *image; + int id; + QPointF hotSpot; + PlayerZone *startZone; +public: + enum { Type = typeCardDrag }; + int type() const { return Type; } + CardDragItem(QGraphicsScene *scene, PlayerZone *_startZone, QPixmap *_image, int _id, const QPointF &_hotSpot, QGraphicsItem *parent = 0); + ~CardDragItem(); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + QPointF getHotSpot() const { return hotSpot; } +protected: + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); +}; + +#endif diff --git a/cockatrice/src/cardinfowidget.cpp b/cockatrice/src/cardinfowidget.cpp new file mode 100644 index 00000000..77fe708c --- /dev/null +++ b/cockatrice/src/cardinfowidget.cpp @@ -0,0 +1,61 @@ +#include "cardinfowidget.h" +#include +#include +#include + +CardInfoWidget::CardInfoWidget(CardDatabase *_db, QWidget *parent) + : QFrame(parent), db(_db), aspectratio(0) +{ + cardPicture = new QLabel(); + cardPicture->setAlignment(Qt::AlignCenter); + + nameLabel1 = new QLabel(tr("Name:")); + nameLabel2 = new QLabel(); + manacostLabel1 = new QLabel(tr("Mana cost:")); + manacostLabel2 = new QLabel(); + cardtypeLabel1 = new QLabel(tr("Card type:")); + cardtypeLabel2 = new QLabel(); + powtoughLabel1 = new QLabel(tr("P / T:")); + powtoughLabel2 = new QLabel(); + + textLabel = new QTextEdit(); + textLabel->setReadOnly(true); + + QGridLayout *grid = new QGridLayout(this); + grid->addWidget(cardPicture, 0, 0, 1, 2); + grid->addWidget(nameLabel1, 1, 0); + grid->addWidget(nameLabel2, 1, 1); + grid->addWidget(manacostLabel1, 2, 0); + grid->addWidget(manacostLabel2, 2, 1); + grid->addWidget(cardtypeLabel1, 3, 0); + grid->addWidget(cardtypeLabel2, 3, 1); + grid->addWidget(powtoughLabel1, 4, 0); + grid->addWidget(powtoughLabel2, 4, 1); + grid->addWidget(textLabel, 5, 0, -1, 2); + grid->setRowStretch(5, 1); + + setFrameStyle(QFrame::Panel | QFrame::Raised); +} + +void CardInfoWidget::setCard(CardInfo *card) +{ + if (!card) + return; + + QPixmap *pixmap = card->getPixmap(); + if (aspectratio == 0) + aspectratio = (double) pixmap->height() / pixmap->width(); + double w = width() * 2.0 / 3.0; + cardPicture->setPixmap(pixmap->scaled((int) w, (int) (w * aspectratio), Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + nameLabel2->setText(card->getName()); + manacostLabel2->setText(card->getManacost()); + cardtypeLabel2->setText(card->getCardType()); + powtoughLabel2->setText(card->getPowTough()); + textLabel->setText(card->getText().join("\n")); +} + +void CardInfoWidget::setCard(const QString &cardName) +{ + setCard(db->getCard(cardName)); +} diff --git a/cockatrice/src/cardinfowidget.h b/cockatrice/src/cardinfowidget.h new file mode 100644 index 00000000..7f8d43dc --- /dev/null +++ b/cockatrice/src/cardinfowidget.h @@ -0,0 +1,29 @@ +#ifndef CARDINFOWIDGET_H +#define CARDINFOWIDGET_H + +#include "carddatabase.h" +#include + +class QLabel; +class QTextEdit; + +class CardInfoWidget : public QFrame { + Q_OBJECT +private: + CardDatabase *db; + double aspectratio; + + QLabel *cardPicture; + QLabel *nameLabel1, *nameLabel2; + QLabel *manacostLabel1, *manacostLabel2; + QLabel *cardtypeLabel1, *cardtypeLabel2; + QLabel *powtoughLabel1, *powtoughLabel2; + QTextEdit *textLabel; +public: + CardInfoWidget(CardDatabase *_db, QWidget *parent = 0); +public slots: + void setCard(CardInfo *card); + void setCard(const QString &cardName); +}; + +#endif diff --git a/cockatrice/src/carditem.cpp b/cockatrice/src/carditem.cpp new file mode 100644 index 00000000..c1d3d380 --- /dev/null +++ b/cockatrice/src/carditem.cpp @@ -0,0 +1,202 @@ +#include +#include +#include "carditem.h" +#include "carddragitem.h" +#include "carddatabase.h" +#include "playerzone.h" +#include "tablezone.h" +#include "player.h" + +CardItem::CardItem(CardDatabase *_db, const QString &_name, int _cardid, QGraphicsItem *parent) + : QGraphicsItem(parent), db(_db), name(_name), id(_cardid), tapped(false), attacking(false), facedown(false), counters(0), dragItem(NULL) +{ + width = CARD_WIDTH; + height = CARD_HEIGHT; + image = db->getCard(name)->getPixmap(); + setCursor(Qt::OpenHandCursor); + setFlag(ItemIsSelectable); + setAcceptsHoverEvents(true); + setCacheMode(DeviceCoordinateCache); +} + +CardItem::~CardItem() +{ + qDebug(QString("CardItem destructor: %1").arg(name).toLatin1()); +} + +QRectF CardItem::boundingRect() const +{ + return QRectF(0, 0, width, height); +} + +void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + painter->save(); + QRectF foo = option->matrix.mapRect(boundingRect()); + qDebug(QString("%1: w=%2,h=%3").arg(name).arg(foo.width()).arg(foo.height()).toLatin1()); + QPixmap bar = image->scaled((int) foo.width(), (int) foo.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); +// painter->drawPixmap(boundingRect(), *image, QRectF(0, 0, image->width(), image->height())); + painter->drawPixmap(boundingRect(), bar, bar.rect()); + if (isSelected()) { + painter->setPen(QPen(QColor("red"))); + painter->drawRect(QRectF(1, 1, width - 2, height - 2)); + } + if (counters) { + painter->setFont(QFont("Times", 32, QFont::Bold)); + painter->setPen(QPen(QColor("black"))); + painter->setBackground(QBrush(QColor(255, 255, 255, 100))); + painter->setBackgroundMode(Qt::OpaqueMode); + painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(counters)); + } + painter->restore(); +} + +void CardItem::setName(const QString &_name) +{ + name = _name; + image = db->getCard(name)->getPixmap(); + update(boundingRect()); +} + +void CardItem::setTapped(bool _tapped) +{ + tapped = _tapped; + if (tapped) + setTransform(QTransform().translate((float) width / 2, (float) height / 2).rotate(90).translate((float) -width / 2, (float) -height / 2)); + else + setTransform(QTransform()); + update(boundingRect()); +} + +void CardItem::setAttacking(bool _attacking) +{ + attacking = _attacking; + update(boundingRect()); +} + +void CardItem::setFacedown(bool _facedown) +{ + facedown = _facedown; + update(boundingRect()); +} + +void CardItem::setCounters(int _counters) +{ + counters = _counters; + update(boundingRect()); +} + +void CardItem::setAnnotation(const QString &_annotation) +{ + annotation = _annotation; + update(boundingRect()); +} + +void CardItem::resetState() +{ + attacking = false; + facedown = false; + counters = 0; + annotation = QString(); + setTapped(false); + update(boundingRect()); +} + +CardDragItem *CardItem::createDragItem(PlayerZone *startZone, int _id, const QPointF &_pos, const QPointF &_scenePos) +{ + dragItem = new CardDragItem(scene(), startZone, image, _id, _pos); + dragItem->setPos(_scenePos - dragItem->getHotSpot()); + + return dragItem; +} + +void CardItem::deleteDragItem() +{ + delete dragItem; + dragItem = NULL; +} + +void CardItem::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if (!isSelected()) { + scene()->clearSelection(); + setSelected(true); + } + if (event->button() == Qt::LeftButton) { + setCursor(Qt::ClosedHandCursor); + } else if (event->button() == Qt::RightButton) { + qgraphicsitem_cast(parentItem())->getPlayer()->showCardMenu(event->screenPos()); + } + event->accept(); +} + +void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() < QApplication::startDragDistance()) + return; + + createDragItem((PlayerZone *) parentItem(), id, event->pos(), event->scenePos()); + dragItem->grabMouse(); + + QList sel = scene()->selectedItems(); + for (int i = 0; i < sel.size(); i++) { + CardItem *c = (CardItem *) sel.at(i); + if (c == this) + continue; + CardDragItem *drag = new CardDragItem(scene(), (PlayerZone *) parentItem(), c->getImage(), c->getId(), QPointF(), dragItem); + drag->setPos(c->pos() - pos()); + } + + setCursor(Qt::OpenHandCursor); +} + +void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event); + setCursor(Qt::OpenHandCursor); +} + +void CardItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event); + if (!isSelected()) { + // Unselect all items, then select this one + scene()->setSelectionArea(QPainterPath()); + setSelected(true); + } + event->accept(); + + PlayerZone *zone = (PlayerZone *) parentItem(); + // Do nothing if the card belongs to another player + if (!zone->getPlayer()->getLocal()) + return; + + if (zone->getHasCardAttr()) + ((TableZone *) zone)->toggleTapped(); +} + +void CardItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + ((PlayerZone *) parentItem())->hoverCardEvent(this); + QGraphicsItem::hoverEnterEvent(event); +} + +void CardItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + QGraphicsItem::hoverLeaveEvent(event); +} + +QVariant CardItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemSelectedChange) { + // XXX + return value; + } else if (change == ItemSelectedHasChanged) { + update(); + return value; + } else + return QGraphicsItem::itemChange(change, value); +} diff --git a/cockatrice/src/carditem.h b/cockatrice/src/carditem.h new file mode 100644 index 00000000..4726610e --- /dev/null +++ b/cockatrice/src/carditem.h @@ -0,0 +1,81 @@ +#ifndef CARDITEM_H +#define CARDITEM_H + +#include + +class CardDatabase; +class CardDragItem; +class PlayerZone; + + +const int CARD_WIDTH = 72; +const int CARD_HEIGHT = 102; +const int RASTER_WIDTH = 36; +const int RASTER_HEIGHT = 34; + +/* +const int CARD_WIDTH = 72; +const int CARD_HEIGHT = 108; +const int RASTER_WIDTH = 36; +const int RASTER_HEIGHT = 36; +*/ + +const int MAX_COUNTERS_ON_CARD = 999; + +enum CardItemType { + typeCard = QGraphicsItem::UserType + 1, + typeCardDrag = QGraphicsItem::UserType + 2, + typeZone = QGraphicsItem::UserType + 3, + typeOther = QGraphicsItem::UserType + 4 +}; + +class CardItem : public QGraphicsItem { +private: + CardDatabase *db; + QString name; + int id; + int width, height; + QPixmap *image; + bool tapped; + bool attacking; + bool facedown; + int counters; + QString annotation; + CardDragItem *dragItem; +public: + enum { Type = typeCard }; + int type() const { return Type; } + CardItem(CardDatabase *_db, const QString &_name, int _cardid, QGraphicsItem *parent = 0); + ~CardItem(); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + int getId() const { return id; } + void setId(int _id) { id = _id; } + QString getName() const { return name; } + void setName(const QString &_name = QString()); + QPixmap *getImage() const { return image; } + bool getTapped() const { return tapped; } + void setTapped(bool _tapped); + bool getAttacking() const { return attacking; } + void setAttacking(bool _attacking); + bool getFacedown() const { return facedown; } + void setFacedown(bool _facedown); + int getCounters() const { return counters; } + void setCounters(int _counters); + QString getAnnotation() const { return annotation; } + void setAnnotation(const QString &_annotation); + void resetState(); + + CardDragItem *createDragItem(PlayerZone *startZone, int _id, const QPointF &_pos, const QPointF &_scenePos); + void deleteDragItem(); +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value); +}; + +#endif diff --git a/cockatrice/src/cardlist.cpp b/cockatrice/src/cardlist.cpp new file mode 100644 index 00000000..99e9544b --- /dev/null +++ b/cockatrice/src/cardlist.cpp @@ -0,0 +1,31 @@ +#include "cardlist.h" + +CardList::CardList(bool _contentsKnown) + : QList(), contentsKnown(_contentsKnown) +{ +} + +CardItem *CardList::findCard(const int id, const bool remove, int *position) +{ + if (!contentsKnown) { + if (empty()) + return 0; + CardItem *temp = at(0); + if (remove) + removeAt(0); + if (position) + *position = id; + return temp; + } else + for (int i = 0; i < size(); i++) { + CardItem *temp = at(i); + if (temp->getId() == id) { + if (remove) + removeAt(i); + if (position) + *position = i; + return temp; + } + } + return 0; +} diff --git a/cockatrice/src/cardlist.h b/cockatrice/src/cardlist.h new file mode 100644 index 00000000..06a30b60 --- /dev/null +++ b/cockatrice/src/cardlist.h @@ -0,0 +1,16 @@ +#ifndef CARDLIST_H +#define CARDLIST_H + +#include "carditem.h" +#include + +class CardList : public QList { +protected: + bool contentsKnown; +public: + CardList(bool _contentsKnown); + CardItem *findCard(const int id, const bool remove, int *position = NULL); + bool getContentsKnown() const { return contentsKnown; } +}; + +#endif diff --git a/cockatrice/src/client.cpp b/cockatrice/src/client.cpp new file mode 100644 index 00000000..c5bc1bc7 --- /dev/null +++ b/cockatrice/src/client.cpp @@ -0,0 +1,322 @@ +#include +#include "client.h" + +Client::Client(QObject *parent) + : QObject(parent) +{ + timer = new QTimer(this); + timer->setInterval(1000); + connect(timer, SIGNAL(timeout()), this, SLOT(checkTimeout())); + + MsgId = 0; + status = StatusDisconnected; + socket = new QTcpSocket(this); + socket->setTextModeEnabled(true); + connect(socket, SIGNAL(connected()), this, SLOT(slotConnected())); + connect(socket, SIGNAL(readyRead()), this, SLOT(readLine())); + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotSocketError(QAbstractSocket::SocketError))); +} + +Client::~Client() +{ + delete socket; +} + +void Client::checkTimeout() +{ + QListIterator i(PendingCommands); + while (i.hasNext()) { + PendingCommand *c = i.next(); + c->incTime(); + if (c->timeout()) { + disconnectFromServer(); + emit serverTimeout(); + return; + } + } +} + +void Client::slotSocketError(QAbstractSocket::SocketError error) +{ + emit logSocketError(socket->errorString()); + disconnectFromServer(); +} + +void Client::slotConnected() +{ + timer->start(); + setStatus(StatusAwaitingWelcome); +} + +void Client::readLine() +{ + QString line; + for (;;) { + if (!socket->canReadLine()) + break; + line = QString(socket->readLine()).trimmed(); + + if (line.isNull()) + break; + qDebug(QString("readLine: %1").arg(line).toLatin1()); + QStringList values = line.split("|"); + QString prefix = values.takeFirst(); + // prefix is one of {welcome, private, public, resp, list_games, list_players, list_counters, list_zones, dump_zone} + if (!(prefix.compare("private") && prefix.compare("public"))) { + ServerEventData *event = new ServerEventData(line); + if (event->getEventType() == eventPlayerId) { + QStringList data = event->getEventData(); + if (data.size() != 2) { + // XXX + } + bool ok; + int id = data[0].toInt(&ok); + if (!ok) { + // XXX + } + delete event; + emit playerIdReceived(id, data[1]); + } else + emit gameEvent(event); + } else if (!prefix.compare("resp")) { + bool ok; + int msgid = values.takeFirst().toInt(&ok); + if (!ok) { + // XXX + } + + if (values.empty()) { + // XXX + } + + ok = !values.takeFirst().compare("ok"); + + // XXX + ServerErrorMessage message = msgNone; + + // Update list of pending commands + QListIterator i(PendingCommands); + bool found = false; + PendingCommand *c; + while (i.hasNext()) { + c = i.next(); + if (c->getMsgId() == msgid) { + found = true; + + QString cmd = c->getCmd(); + if (cmd.startsWith("submit_deck")) + readyStart(); + + break; + } + } + if (found) { + PendingCommands.removeAt(PendingCommands.indexOf(c)); + delete c; + } + + emit responseReceived(new ServerResponse(msgid, ok, message)); + } else if (!(prefix.compare("list_games") + && prefix.compare("list_players") + && prefix.compare("list_counters") + && prefix.compare("list_zones") + && prefix.compare("dump_zone") + && prefix.compare("welcome"))) { + int cmdid = values.takeFirst().toInt(); + if (!values[0].compare(".")) { + QListIterator i(msgbuf); + QList gamelist; + QList playerlist; + QList zonelist; + QList zonedump; + QStringList welcomemsg; + while (i.hasNext()) { + QStringList val = i.next(); + + // XXX Parametergültigkeit überprüfen + if (!prefix.compare("list_games")) + gamelist << new ServerGame(val[0], val[1], val[2].toInt(), val[3].toInt(), val[4].toInt()); + else if (!prefix.compare("list_players")) + playerlist << new ServerPlayer(val[0].toInt(), val[1]); + else if (!prefix.compare("list_counters")) + { } + else if (!prefix.compare("list_zones")) + zonelist << new ServerZone(val[0], val[1] == "1", val[2] == "1", val[3].toInt()); + else if (!prefix.compare("dump_zone")) + zonedump << new ServerZoneCard(val[0].toInt(), val[1], val[2].toInt(), val[3].toInt(), val[4].toInt(), val[5] == "1", val[6]); + else if (!prefix.compare("welcome")) + welcomemsg << val[0]; + } + if (!prefix.compare("list_games")) + emit gameListReceived(gamelist); + else if (!prefix.compare("list_players")) + emit playerListReceived(playerlist); + else if (!prefix.compare("list_counters")) + { } + else if (!prefix.compare("list_zones")) + emit zoneListReceived(cmdid, zonelist); + else if (!prefix.compare("dump_zone")) + emit zoneDumpReceived(cmdid, zonedump); + else if (!prefix.compare("welcome")) { + emit welcomeMsgReceived(welcomemsg); + setStatus(StatusConnected); + setName(PlayerName); + } + msgbuf.clear(); + } else + msgbuf << values; + } else { + // XXX + } + } +} + +void Client::setStatus(const ProtocolStatus _status) +{ + status = _status; + emit statusChanged(_status); +} + +void Client::msg(const QString &s) +{ + qDebug(QString("msg gibt aus: %1").arg(s).toLatin1()); + QTextStream stream(socket); + stream.setCodec("UTF-8"); + stream << s << endl; + stream.flush(); + socket->flush(); +} + +int Client::cmd(const QString &s) +{ + msg(QString("%1|%2").arg(++MsgId).arg(s)); + PendingCommands << new PendingCommand(s, MsgId); + return MsgId; +} + +void Client::connectToServer(const QString &hostname, unsigned int port, const QString &playername) +{ + PlayerName = playername; + socket->connectToHost(hostname, port); + setStatus(StatusConnecting); +} + +void Client::disconnectFromServer() +{ + timer->stop(); + PendingCommands.clear(); + setStatus(StatusDisconnected); + socket->close(); +} + +int Client::listGames() +{ + return cmd("list_games"); +} + +int Client::listPlayers() +{ + return cmd("list_players"); +} + +int Client::createGame(const QString &name, const QString &description, const QString &password, unsigned int maxPlayers) +{ + return cmd(QString("create_game|%1|%2|%3|%4").arg(name).arg(description).arg(password).arg(maxPlayers)); +} + +int Client::joinGame(const QString &name, const QString &password) +{ + return cmd(QString("join_game|%1|%2").arg(name).arg(password)); +} + +int Client::leaveGame() +{ + return cmd("leave_game"); +} + +int Client::setName(const QString &name) +{ + return cmd(QString("set_name|%1").arg(name)); +} + +int Client::say(const QString &s) +{ + return cmd(QString("say|%1").arg(s)); +} + +int Client::shuffle() +{ + return cmd("shuffle"); +} + +int Client::rollDice(unsigned int sides) +{ + return cmd(QString("roll_dice|%1").arg(sides)); +} + +int Client::drawCards(unsigned int number) +{ + return cmd(QString("draw_cards|%1").arg(number)); +} + +int Client::moveCard(int cardid, const QString &startzone, const QString &targetzone, int x, int y) +{ + // if startzone is public: cardid is the card's id + // else: cardid is the position of the card in the zone (e.g. deck) + return cmd(QString("move_card|%1|%2|%3|%4|%5").arg(cardid).arg(startzone).arg(targetzone).arg(x).arg(y)); +} + +int Client::createToken(const QString &zone, const QString &name, const QString &powtough, int x, int y) +{ + return cmd(QString("create_token|%1|%2|%3|%4|%5").arg(zone).arg(name).arg(powtough).arg(x).arg(y)); +} + +int Client::setCardAttr(const QString &zone, int cardid, const QString &aname, const QString &avalue) +{ + return cmd(QString("set_card_attr|%1|%2|%3|%4").arg(zone).arg(cardid).arg(aname).arg(avalue)); +} + +int Client::submitDeck(const QStringList &deck) +{ + int retval = cmd("submit_deck"); + QStringListIterator i(deck); + while (i.hasNext()) + msg(i.next()); + msg("."); + return retval; +} + +int Client::readyStart() +{ + return cmd("ready_start"); +} + +int Client::incCounter(const QString &counter, int delta) +{ + return cmd(QString("inc_counter|%1|%2").arg(counter).arg(delta)); +} + +int Client::setCounter(const QString &counter, int value) +{ + return cmd(QString("set_counter|%1|%2").arg(counter).arg(value)); +} + +int Client::delCounter(const QString &counter) +{ + return cmd(QString("del_counter|%1").arg(counter)); +} + +int Client::setActivePlayer(int player) +{ + return cmd(QString("set_active_player|%1").arg(player)); +} + +int Client::setActivePhase(int phase) +{ + return cmd(QString("set_active_phase|%1").arg(phase)); +} + +int Client::dumpZone(int player, const QString &zone, int numberCards) +{ + return cmd(QString("dump_zone|%1|%2|%3").arg(player).arg(zone).arg(numberCards)); +} diff --git a/cockatrice/src/client.h b/cockatrice/src/client.h new file mode 100644 index 00000000..18558dd5 --- /dev/null +++ b/cockatrice/src/client.h @@ -0,0 +1,86 @@ +#ifndef CLIENT_H +#define CLIENT_H + +#include "servereventdata.h" +#include "serverresponse.h" +#include "servergame.h" +#include "serverplayer.h" +#include "serverzone.h" +#include "serverzonecard.h" +#include "pendingcommand.h" +#include + +class QTimer; + +// Connection state. +// The protocol handler itself is stateless once the connection +// has been established. +enum ProtocolStatus { StatusDisconnected, + StatusConnecting, + StatusAwaitingWelcome, + StatusConnected }; + +class Client : public QObject { + Q_OBJECT +signals: + void statusChanged(ProtocolStatus _status); + void welcomeMsgReceived(QStringList welcomeMsg); + void gameListReceived(QList games); + void playerListReceived(QList players); + void zoneListReceived(int commandId, QList zones); + void zoneDumpReceived(int commandId, QList cards); + void responseReceived(ServerResponse *response); + void playerIdReceived(int id, QString name); + void gameEvent(ServerEventData *msg); + void serverTimeout(); + void logSocketError(const QString &errorString); + +private slots: + void slotConnected(); + void readLine(); + void checkTimeout(); + void slotSocketError(QAbstractSocket::SocketError error); + +private: + QTimer *timer; + QList PendingCommands; + QTcpSocket *socket; + ProtocolStatus status; + QList msgbuf; + QString PlayerName; + unsigned int MsgId; + void msg(const QString &s); + int cmd(const QString &s); + void setStatus(const ProtocolStatus _status); +public: + Client(QObject *parent = 0); + ~Client(); + ProtocolStatus getStatus() { return status; } + QString peerName() const { return socket->peerName(); } + + void connectToServer(const QString &hostname, unsigned int port, const QString &playername); + void disconnectFromServer(); + int listGames(); + int listPlayers(); + int createGame(const QString &name, const QString &description, const QString &password, unsigned int maxPlayers); + int joinGame(const QString &name, const QString &password); + int leaveGame(); + int setName(const QString &name); + int say(const QString &s); + int shuffle(); + int rollDice(unsigned int sides); + int drawCards(unsigned int number); + int moveCard(int cardid, const QString &startzone, const QString &targetzone, int x, int y = 0); + int createToken(const QString &zone, const QString &name, const QString &powtough, int x, int y); + int setCardAttr(const QString &zone, int cardid, const QString &aname, const QString &avalue); + int submitDeck(const QStringList &deck); + int readyStart(); + int incCounter(const QString &counter, int delta); + int setCounter(const QString &counter, int value); + int delCounter(const QString &counter); + int setActivePlayer(int player); + int setActivePhase(int phase); + int dumpZone(int player, const QString &zone, int numberCards); +}; + +#endif diff --git a/cockatrice/src/counter.cpp b/cockatrice/src/counter.cpp new file mode 100644 index 00000000..a323cd53 --- /dev/null +++ b/cockatrice/src/counter.cpp @@ -0,0 +1,30 @@ +#include "counter.h" +#include "player.h" +#include + +Counter::Counter(Player *_player, const QString &_name, QGraphicsItem *parent) + : QGraphicsItem(parent), name(_name), value(0), player(_player) +{ + player->addCounter(this); +} + +QRectF Counter::boundingRect() const +{ + return QRectF(0, 0, 50, 30); +} + +void Counter::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + painter->save(); + painter->fillRect(boundingRect(), QBrush(QColor("gray"))); + painter->drawText(boundingRect(), Qt::AlignCenter, QString("%1").arg(value)); + painter->restore(); +} + +void Counter::setValue(int _value) +{ + value = _value; + update(boundingRect()); +} diff --git a/cockatrice/src/counter.h b/cockatrice/src/counter.h new file mode 100644 index 00000000..9c4af853 --- /dev/null +++ b/cockatrice/src/counter.h @@ -0,0 +1,24 @@ +#ifndef COUNTER_H +#define COUNTER_H + +#include + +class Player; + +class Counter : public QGraphicsItem { +private: + QString name; + int value; +protected: + Player *player; +public: + Counter(Player *_player, const QString &_name, QGraphicsItem *parent = 0); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + + QString getName() const { return name; } + int getValue() const { return value; } + void setValue(int _value); +}; + +#endif diff --git a/cockatrice/src/counterlist.cpp b/cockatrice/src/counterlist.cpp new file mode 100644 index 00000000..79b19b73 --- /dev/null +++ b/cockatrice/src/counterlist.cpp @@ -0,0 +1,11 @@ +#include "counterlist.h" + +Counter *CounterList::findCounter(const QString &name) const +{ + for (int i = 0; i < size(); i++) { + Counter *temp = at(i); + if (!temp->getName().compare(name)) + return temp; + } + return 0; +} diff --git a/cockatrice/src/counterlist.h b/cockatrice/src/counterlist.h new file mode 100644 index 00000000..5f3b44ea --- /dev/null +++ b/cockatrice/src/counterlist.h @@ -0,0 +1,12 @@ +#ifndef COUNTERLIST_H +#define COUNTERLIST_H + +#include "counter.h" +#include + +class CounterList : public QList { +public: + Counter *findCounter(const QString &name) const; +}; + +#endif diff --git a/cockatrice/src/decklistmodel.cpp b/cockatrice/src/decklistmodel.cpp new file mode 100644 index 00000000..e88d5273 --- /dev/null +++ b/cockatrice/src/decklistmodel.cpp @@ -0,0 +1,92 @@ +#include "decklistmodel.h" +#include +#include + +DeckListModel::~DeckListModel() +{ + qDebug("DeckListModel destructor"); + cleanList(); +} + +int DeckListModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return deckList.size(); +} + +int DeckListModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 2; +} + +QVariant DeckListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + if ((index.row() >= deckList.size()) || (index.column() >= 2)) + return QVariant(); + + if (role != Qt::DisplayRole) + return QVariant(); + + DecklistRow *r = deckList.at(index.row()); + switch (index.column()) { + case 0: return r->getNumber(); + case 1: return r->getCard(); + default: return QVariant(); + } +} + +QVariant DeckListModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + if (orientation != Qt::Horizontal) + return QVariant(); + switch (section) { + case 0: return QString(tr("Number")); + case 1: return QString(tr("Card")); + default: return QVariant(); + } +} + +void DeckListModel::cleanList() +{ + QListIterator i(deckList); + while (i.hasNext()) + delete i.next(); + deckList.clear(); +} + +void DeckListModel::loadFromFile(const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + QTextStream in(&file); + cleanList(); + while (!in.atEnd()) { + QString line = in.readLine().simplified(); + bool isSideboard = false; + if (line.startsWith("SB:")) { + line = line.mid(3).trimmed(); + isSideboard = true; + } + int i = line.indexOf(' '); + bool ok; + int number = line.left(i).toInt(&ok); + if (!ok) + continue; + DecklistRow *row = new DecklistRow(number, line.mid(i + 1), isSideboard); + deckList << row; + } + reset(); +} + +DecklistRow *DeckListModel::getRow(int row) const +{ + if (row >= deckList.size()) + return 0; + return deckList.at(row); +} diff --git a/cockatrice/src/decklistmodel.h b/cockatrice/src/decklistmodel.h new file mode 100644 index 00000000..384fe6f6 --- /dev/null +++ b/cockatrice/src/decklistmodel.h @@ -0,0 +1,36 @@ +#ifndef DECKLISTMODEL_H +#define DECKLISTMODEL_H + +#include +#include + +class DecklistRow { +private: + int number; + QString card; + bool sideboard; +public: + DecklistRow(int _number, const QString &_card, bool _sideboard) : number(_number), card(_card), sideboard(_sideboard) { } + int getNumber() const { return number; } + QString getCard() const { return card; } + bool isSideboard() const { return sideboard; } +}; + +class DeckListModel : public QAbstractListModel { + Q_OBJECT +public: + DeckListModel(QObject *parent = 0) + : QAbstractListModel(parent) { } + ~DeckListModel(); + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + void loadFromFile(const QString &fileName); + DecklistRow *getRow(int row) const; +private: + QList deckList; + void cleanList(); +}; + +#endif diff --git a/cockatrice/src/dlg_connect.cpp b/cockatrice/src/dlg_connect.cpp new file mode 100644 index 00000000..90430275 --- /dev/null +++ b/cockatrice/src/dlg_connect.cpp @@ -0,0 +1,61 @@ +#include +#include "dlg_connect.h" + +DlgConnect::DlgConnect(QWidget *parent) + : QDialog(parent) +{ + hostLabel = new QLabel(tr("&Host:")); + hostEdit = new QLineEdit("localhost"); + hostLabel->setBuddy(hostEdit); + + portLabel = new QLabel(tr("&Port:")); + portEdit = new QLineEdit("4747"); + portLabel->setBuddy(portEdit); + + playernameLabel = new QLabel(tr("Player &name:")); + playernameEdit = new QLineEdit("Player"); + playernameLabel->setBuddy(playernameEdit); + + okButton = new QPushButton(tr("&OK")); + okButton->setDefault(true); + cancelButton = new QPushButton(tr("&Cancel")); + + QGridLayout *grid = new QGridLayout; + grid->addWidget(hostLabel, 0, 0); + grid->addWidget(hostEdit, 0, 1); + grid->addWidget(portLabel, 1, 0); + grid->addWidget(portEdit, 1, 1); + grid->addWidget(playernameLabel, 2, 0); + grid->addWidget(playernameEdit, 2, 1); + + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addStretch(); + buttonLayout->addWidget(okButton); + buttonLayout->addWidget(cancelButton); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout(grid); + mainLayout->addLayout(buttonLayout); + setLayout(mainLayout); + + setWindowTitle(tr("Connect to server")); + setFixedHeight(sizeHint().height()); + + connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); +} + +QString DlgConnect::getHost() +{ + return hostEdit->text(); +} + +int DlgConnect::getPort() +{ + return portEdit->text().toInt(); +} + +QString DlgConnect::getPlayerName() +{ + return playernameEdit->text(); +} diff --git a/cockatrice/src/dlg_connect.h b/cockatrice/src/dlg_connect.h new file mode 100644 index 00000000..5c5b4243 --- /dev/null +++ b/cockatrice/src/dlg_connect.h @@ -0,0 +1,23 @@ +#ifndef DLG_CONNECT_H +#define DLG_CONNECT_H + +#include + +class QLabel; +class QLineEdit; +class QPushButton; + +class DlgConnect : public QDialog { + Q_OBJECT +public: + DlgConnect(QWidget *parent = 0); + QString getHost(); + int getPort(); + QString getPlayerName(); +private: + QLabel *hostLabel, *portLabel, *playernameLabel; + QLineEdit *hostEdit, *portEdit, *playernameEdit; + QPushButton *okButton, *cancelButton; +}; + +#endif diff --git a/cockatrice/src/dlg_creategame.cpp b/cockatrice/src/dlg_creategame.cpp new file mode 100644 index 00000000..4843e69c --- /dev/null +++ b/cockatrice/src/dlg_creategame.cpp @@ -0,0 +1,85 @@ +#include +#include "dlg_creategame.h" + +DlgCreateGame::DlgCreateGame(Client *_client, QWidget *parent) + : QDialog(parent), client(_client) +{ + msgid = 0; + + nameLabel = new QLabel(tr("&Name:")); + nameEdit = new QLineEdit; + nameLabel->setBuddy(nameEdit); + + descriptionLabel = new QLabel(tr("&Description:")); + descriptionEdit = new QLineEdit; + descriptionLabel->setBuddy(descriptionEdit); + + passwordLabel = new QLabel(tr("&Password:")); + passwordEdit = new QLineEdit; + passwordLabel->setBuddy(passwordEdit); + + maxPlayersLabel = new QLabel(tr("&Max Players:")); + maxPlayersEdit = new QLineEdit("2"); + maxPlayersLabel->setBuddy(maxPlayersEdit); + + QGridLayout *grid = new QGridLayout; + grid->addWidget(nameLabel, 0, 0); + grid->addWidget(nameEdit, 0, 1); + grid->addWidget(descriptionLabel, 1, 0); + grid->addWidget(descriptionEdit, 1, 1); + grid->addWidget(passwordLabel, 2, 0); + grid->addWidget(passwordEdit, 2, 1); + grid->addWidget(maxPlayersLabel, 3, 0); + grid->addWidget(maxPlayersEdit, 3, 1); + + okButton = new QPushButton(tr("&OK")); + okButton->setDefault(true); + cancelButton = new QPushButton(tr("&Cancel")); + + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addStretch(); + buttonLayout->addWidget(okButton); + buttonLayout->addWidget(cancelButton); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout(grid); + mainLayout->addLayout(buttonLayout); + + setLayout(mainLayout); + + setWindowTitle(tr("Create game")); + setFixedHeight(sizeHint().height()); + + connect(okButton, SIGNAL(clicked()), this, SLOT(actOK())); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + connect(client, SIGNAL(responseReceived(ServerResponse *)), this, SLOT(checkResponse(ServerResponse *))); +} + +void DlgCreateGame::actOK() +{ + bool ok; + int maxPlayers = maxPlayersEdit->text().toInt(&ok); + if (msgid) + return; + if (!ok) { + QMessageBox::critical(this, tr("Error"), tr("Invalid number of players.")); + return; + } + msgid = client->createGame(nameEdit->text(), + descriptionEdit->text(), + passwordEdit->text(), + maxPlayers); +} + +void DlgCreateGame::checkResponse(ServerResponse *response) +{ + if (response->getMsgId() != msgid) + return; + if (response->getOk()) + accept(); + else { + QMessageBox::critical(this, tr("Error"), tr("XXX")); + msgid = 0; + return; + } +} diff --git a/cockatrice/src/dlg_creategame.h b/cockatrice/src/dlg_creategame.h new file mode 100644 index 00000000..714240b6 --- /dev/null +++ b/cockatrice/src/dlg_creategame.h @@ -0,0 +1,28 @@ +#ifndef DLG_CREATEGAME_H +#define DLG_CREATEGAME_H + +#include +#include "client.h" + +class QLabel; +class QLineEdit; +class QPushButton; + +class DlgCreateGame : public QDialog { + Q_OBJECT +public: + DlgCreateGame(Client *_client, QWidget *parent = 0); +private slots: + void actOK(); + void checkResponse(ServerResponse *response); +private: + Client *client; + int msgid; + + QLabel *nameLabel, *descriptionLabel, *passwordLabel, *maxPlayersLabel; + QLineEdit *nameEdit, *descriptionEdit, *passwordEdit, *maxPlayersEdit; + QPushButton *okButton, *cancelButton; +}; + +#endif + diff --git a/cockatrice/src/dlg_games.cpp b/cockatrice/src/dlg_games.cpp new file mode 100644 index 00000000..859654a7 --- /dev/null +++ b/cockatrice/src/dlg_games.cpp @@ -0,0 +1,87 @@ +#include +#include "dlg_games.h" +#include "dlg_creategame.h" + +DlgGames::DlgGames(Client *_client, QWidget *parent) + : QDialog(parent), client(_client) +{ + msgid = 0; + + tableView = new QTreeView; + tableModel = new GamesModel(this); + tableView->setModel(tableModel); + + createButton = new QPushButton(tr("&Create")); + refreshButton = new QPushButton(tr("&Refresh")); + joinButton = new QPushButton(tr("&Join")); + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addWidget(createButton); + buttonLayout->addStretch(); + buttonLayout->addWidget(refreshButton); + buttonLayout->addStretch(); + buttonLayout->addWidget(joinButton); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(tableView); + mainLayout->addLayout(buttonLayout); + + setLayout(mainLayout); + + setWindowTitle(tr("Games")); + setMinimumWidth(sizeHint().width()); + + connect(createButton, SIGNAL(clicked()), this, SLOT(actCreate())); + connect(refreshButton, SIGNAL(clicked()), this, SLOT(actRefresh())); + connect(joinButton, SIGNAL(clicked()), this, SLOT(actJoin())); + + connect(client, SIGNAL(gameListReceived(QList)), this, SLOT(gameListReceived(QList))); + client->listGames(); +} + +void DlgGames::actCreate() +{ + DlgCreateGame dlg(client, this); + if (dlg.exec()) + accept(); +} + +void DlgGames::actRefresh() +{ + client->listGames(); +} + +void DlgGames::checkResponse(ServerResponse *response) +{ + if (response->getMsgId() != msgid) + return; + if (response->getOk()) + accept(); + else { + QMessageBox::critical(this, tr("Error"), tr("XXX")); + msgid = 0; + return; + } +} + +void DlgGames::actJoin() +{ + if (msgid) + return; + + ServerGame *game = tableModel->getGame(tableView->currentIndex().row()); + QString password; + if (game->getHasPassword()) { + bool ok; + password = QInputDialog::getText(this, tr("Join game"), tr("Password:"), QLineEdit::Password, QString(), &ok); + if (!ok) + return; + } + + connect(client, SIGNAL(responseReceived(ServerResponse *)), this, SLOT(checkResponse(ServerResponse *))); + msgid = client->joinGame(game->getName(), password); +} + +void DlgGames::gameListReceived(QList _gameList) +{ + tableModel->setGameList(_gameList); +} diff --git a/cockatrice/src/dlg_games.h b/cockatrice/src/dlg_games.h new file mode 100644 index 00000000..045478b7 --- /dev/null +++ b/cockatrice/src/dlg_games.h @@ -0,0 +1,32 @@ +#ifndef DLG_GAMES_H +#define DLG_GAMES_H + +#include +#include "gamesmodel.h" +#include "servergame.h" +#include "client.h" + +class QPushButton; +class QTreeView; + +class DlgGames : public QDialog { + Q_OBJECT +public: + DlgGames(Client *_client, QWidget *parent = 0); +private slots: + void actCreate(); + void actRefresh(); + void actJoin(); + void gameListReceived(QList _gameList); + void checkResponse(ServerResponse *response); +private: + Client *client; + int msgid; + + QTreeView *tableView; + GamesModel *tableModel; + QPushButton *refreshButton, *createButton, *joinButton; +}; + +#endif + diff --git a/cockatrice/src/dlg_startgame.cpp b/cockatrice/src/dlg_startgame.cpp new file mode 100644 index 00000000..786af228 --- /dev/null +++ b/cockatrice/src/dlg_startgame.cpp @@ -0,0 +1,63 @@ +#include +#include +#include "dlg_startgame.h" +#include "decklistmodel.h" +#include "carddatabase.h" + +DlgStartGame::DlgStartGame(CardDatabase *_db, QWidget *parent) + : QDialog(parent), db(_db) +{ + tableView = new QTreeView; + tableModel = new DeckListModel(this); + tableView->setModel(tableModel); + + loadButton = new QPushButton(tr("&Load...")); + okButton = new QPushButton(tr("&OK")); + okButton->setDefault(true); + + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addWidget(loadButton); + buttonLayout->addStretch(); + buttonLayout->addWidget(okButton); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(tableView); + mainLayout->addLayout(buttonLayout); + + setLayout(mainLayout); + + setWindowTitle(tr("Start game")); + setMinimumWidth(sizeHint().width()); + + connect(loadButton, SIGNAL(clicked()), this, SLOT(actLoad())); + connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); +} + +void DlgStartGame::actLoad() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Load deck"), QString(), tr("Deck files (*.dec)")); + if (!fileName.isEmpty()) + tableModel->loadFromFile(fileName); + + // Precache card pictures + for (int i = 0; i < tableModel->rowCount(); i++) { + QString cardName = tableModel->getRow(i)->getCard(); + CardInfo *card = db->getCard(cardName); + if (!card) { + qDebug(QString("Invalid card: %1").arg(cardName).toLatin1()); + continue; + } + card->getPixmap(); + } +} + +QStringList DlgStartGame::getDeckList() const +{ + QStringList result; + for (int i = 0; i < tableModel->rowCount(); i++) { + DecklistRow *temp = tableModel->getRow(i); + for (int j = 0; j < temp->getNumber(); j++) + result << QString("%1%2").arg(temp->isSideboard() ? "SB:" : "").arg(temp->getCard()); + } + return result; +} diff --git a/cockatrice/src/dlg_startgame.h b/cockatrice/src/dlg_startgame.h new file mode 100644 index 00000000..89e6cdb0 --- /dev/null +++ b/cockatrice/src/dlg_startgame.h @@ -0,0 +1,26 @@ +#ifndef DLG_STARTGAME_H +#define DLG_STARTGAME_H + +#include +#include "decklistmodel.h" + +class QTreeView; +class QPushButton; +class CardDatabase; + +class DlgStartGame: public QDialog { + Q_OBJECT +public: + DlgStartGame(CardDatabase *_db, QWidget *parent = 0); + QStringList getDeckList() const; +private slots: + void actLoad(); +private: + CardDatabase *db; + QTreeView *tableView; + DeckListModel *tableModel; + + QPushButton *loadButton, *okButton; +}; + +#endif diff --git a/cockatrice/src/game.cpp b/cockatrice/src/game.cpp new file mode 100644 index 00000000..fcbda772 --- /dev/null +++ b/cockatrice/src/game.cpp @@ -0,0 +1,371 @@ +#include +#include +#include +#include "serverplayer.h" +#include "game.h" +#include "servereventdata.h" +#include "client.h" +#include "tablezone.h" +#include "handzone.h" +#include "carddatabase.h" +#include "dlg_startgame.h" + +Game::Game(CardDatabase *_db, Client *_client, QGraphicsScene *_scene, QMenu *_actionsMenu, QMenu *_cardMenu, int playerId, const QString &playerName) + : QObject(), actionsMenu(_actionsMenu), cardMenu(_cardMenu), db(_db), client(_client), scene(_scene), started(false) +{ + QRectF sr = scene->sceneRect(); + localPlayer = addPlayer(playerId, playerName, QPointF(0, sr.y() + sr.height() / 2), true); + + connect(client, SIGNAL(gameEvent(ServerEventData *)), this, SLOT(gameEvent(ServerEventData *))); + connect(client, SIGNAL(playerListReceived(QList)), this, SLOT(playerListReceived(QList))); + + aUntapAll = new QAction(tr("&Untap all permanents"), this); + aUntapAll->setShortcut(tr("Ctrl+U")); + connect(aUntapAll, SIGNAL(triggered()), this, SLOT(actUntapAll())); + + aDecLife = new QAction(tr("&Decrement life"), this); + aDecLife->setShortcut(tr("F11")); + connect(aDecLife, SIGNAL(triggered()), this, SLOT(actDecLife())); + aIncLife = new QAction(tr("&Increment life"), this); + aIncLife->setShortcut(tr("F12")); + connect(aIncLife, SIGNAL(triggered()), this, SLOT(actIncLife())); + aSetLife = new QAction(tr("&Set life"), this); + aSetLife->setShortcut(tr("Ctrl+L")); + connect(aSetLife, SIGNAL(triggered()), this, SLOT(actSetLife())); + + aShuffle = new QAction(tr("&Shuffle"), this); + aShuffle->setShortcut(tr("Ctrl+S")); + connect(aShuffle, SIGNAL(triggered()), this, SLOT(actShuffle())); + aDraw = new QAction(tr("&Draw a card"), this); + aDraw->setShortcut(tr("Ctrl+D")); + connect(aDraw, SIGNAL(triggered()), this, SLOT(actDrawCard())); + aDrawCards = new QAction(tr("D&raw cards..."), this); + connect(aDrawCards, SIGNAL(triggered()), this, SLOT(actDrawCards())); + aRollDice = new QAction(tr("R&oll dice..."), this); + aRollDice->setShortcut(tr("Ctrl+I")); + connect(aRollDice, SIGNAL(triggered()), this, SLOT(actRollDice())); + + aCreateToken = new QAction(tr("&Create token..."), this); + aCreateToken->setShortcut(tr("Ctrl+T")); + connect(aCreateToken, SIGNAL(triggered()), this, SLOT(actCreateToken())); + + actionsMenu->addAction(aUntapAll); + actionsMenu->addSeparator(); + actionsMenu->addAction(aDecLife); + actionsMenu->addAction(aIncLife); + actionsMenu->addAction(aSetLife); + actionsMenu->addSeparator(); + actionsMenu->addAction(aShuffle); + actionsMenu->addAction(aDraw); + actionsMenu->addAction(aDrawCards); + actionsMenu->addAction(aRollDice); + actionsMenu->addSeparator(); + actionsMenu->addAction(aCreateToken); + + aTap = new QAction(tr("&Tap"), this); + connect(aTap, SIGNAL(triggered()), this, SLOT(actTap())); + aUntap = new QAction(tr("&Untap"), this); + connect(aUntap, SIGNAL(triggered()), this, SLOT(actUntap())); + aAddCounter = new QAction(tr("&Add counter"), this); + connect(aAddCounter, SIGNAL(triggered()), this, SLOT(actAddCounter())); + aRemoveCounter = new QAction(tr("&Remove counter"), this); + connect(aRemoveCounter, SIGNAL(triggered()), this, SLOT(actRemoveCounter())); + aSetCounters = new QAction(tr("&Set counters..."), this); + connect(aSetCounters, SIGNAL(triggered()), this, SLOT(actSetCounters())); + aRearrange = new QAction(tr("&Rearrange"), this); + connect(aRearrange, SIGNAL(triggered()), this, SLOT(actRearrange())); + + cardMenu->addAction(aTap); + cardMenu->addAction(aUntap); + cardMenu->addAction(aAddCounter); + cardMenu->addAction(aRemoveCounter); + cardMenu->addAction(aSetCounters); + cardMenu->addSeparator(); + cardMenu->addAction(aRearrange); + + dlgStartGame = new DlgStartGame(db); +} + +Game::~Game() +{ + qDebug("Game destructor"); + for (int i = 0; i < players.size(); i++) { + emit playerRemoved(players.at(i)); + delete players.at(i); + } +} + +Player *Game::addPlayer(int playerId, const QString &playerName, QPointF base, bool local) +{ + Player *newPlayer = new Player(playerName, playerId, base, local, db, client); + + const ZoneList *const z = newPlayer->getZones(); + for (int i = 0; i < z->size(); i++) + scene->addItem(z->at(i)); + + const CounterList *const c = newPlayer->getCounters(); + for (int i = 0; i < c->size(); i++) + scene->addItem(c->at(i)); + + connect(newPlayer, SIGNAL(hoverCard(QString)), this, SIGNAL(hoverCard(QString))); + connect(newPlayer, SIGNAL(sigShowCardMenu(QPoint)), this, SLOT(showCardMenu(QPoint))); + connect(newPlayer, SIGNAL(logMoveCard(QString, QString, QString, QString)), this, SIGNAL(logMoveCard(QString, QString, QString, QString))); + connect(newPlayer, SIGNAL(logCreateToken(QString, QString)), this, SIGNAL(logCreateToken(QString, QString))); + connect(newPlayer, SIGNAL(logSetCardCounters(QString, QString, int, int)), this, SIGNAL(logSetCardCounters(QString, QString, int, int))); + connect(newPlayer, SIGNAL(logSetTapped(QString, QString, bool)), this, SIGNAL(logSetTapped(QString, QString, bool))); + connect(newPlayer, SIGNAL(logSetCounter(QString, QString, int, int)), this, SIGNAL(logSetCounter(QString, QString, int, int))); + + players << newPlayer; + emit playerAdded(newPlayer); + + return newPlayer; +} + +void Game::playerListReceived(QList playerList) +{ + QListIterator i(playerList); + QStringList nameList; + while (i.hasNext()) { + ServerPlayer *temp = i.next(); + nameList << temp->getName(); + int id = temp->getPlayerId(); + + if (id != localPlayer->getId()) + addPlayer(id, temp->getName(), QPointF(0, 0), false); + + delete temp; + } + emit logPlayerListReceived(nameList); + restartGameDialog(); +} + +void Game::restartGameDialog() +{ + dlgStartGame->exec(); + client->submitDeck(dlgStartGame->getDeckList()); +} + +void Game::gameEvent(ServerEventData *msg) +{ + if (!msg->getPublic()) + localPlayer->gameEvent(msg); + else { + Player *p = players.findPlayer(msg->getPlayerId()); + if (!p) { + // XXX + } + + switch(msg->getEventType()) { + case eventSay: + emit logSay(p->getName(), msg->getEventData()[0]); + break; + case eventJoin: { + emit logJoin(msg->getPlayerName()); + addPlayer(msg->getPlayerId(), msg->getPlayerName(), QPointF(0, 0), false); + break; + } + case eventLeave: + emit logLeave(msg->getPlayerName()); + // XXX Spieler natürlich noch rauswerfen + break; + case eventReadyStart: + if (started) { + started = false; + emit logReadyStart(p->getName()); + if (!p->getLocal()) + restartGameDialog(); + } + break; + case eventGameStart: + started = true; + emit logGameStart(); + break; + case eventShuffle: + emit logShuffle(p->getName()); + break; + case eventRollDice: { + QStringList data = msg->getEventData(); + int sides = data[0].toInt(); + int roll = data[1].toInt(); + emit logRollDice(p->getName(), sides, roll); + break; + } + case eventSetActivePlayer: + break; + case eventSetActivePhase: + break; + + case eventName: + case eventCreateToken: + case eventSetupZones: + case eventSetCardAttr: + case eventSetCounter: + case eventDelCounter: + case eventPlayerId: { + p->gameEvent(msg); + break; + } + case eventDumpZone: { + QStringList data = msg->getEventData(); + emit logDumpZone(p->getName(), data[1], players.findPlayer(data[0].toInt())->getName(), data[2].toInt()); + break; + } + case eventMoveCard: { + if (msg->getPlayerId() == localPlayer->getId()) + break; + p->gameEvent(msg); + break; + } + case eventDraw: { + emit logDraw(p->getName(), msg->getEventData()[0].toInt()); + if (msg->getPlayerId() == localPlayer->getId()) + break; + p->gameEvent(msg); + break; + } + case eventInvalid: + qDebug("Unhandled global event"); + } + } +} + +void Game::actUntapAll() +{ + CardList *const cards = localPlayer->getZones()->findZone("table")->getCards(); + for (int i = 0; i < cards->size(); i++) + client->setCardAttr("table", cards->at(i)->getId(), "tapped", "false"); +} + +void Game::actIncLife() +{ + client->incCounter("life", 1); +} + +void Game::actDecLife() +{ + client->incCounter("life", -1); +} + +void Game::actSetLife() +{ + bool ok; + int life = QInputDialog::getInteger(0, tr("Set life"), tr("New life total:"), localPlayer->getCounters()->findCounter("life")->getValue(), 0, 2000000000, 1, &ok); + client->setCounter("life", life); +} + +void Game::actShuffle() +{ + client->shuffle(); +} + +void Game::actRollDice() +{ + bool ok; + int sides = QInputDialog::getInteger(0, tr("Roll dice"), tr("Number of sides:"), 20, 2, 1000, 1, &ok); + if (ok) + client->rollDice(sides); +} + +void Game::actDrawCard() +{ + client->drawCards(1); +} + +void Game::actDrawCards() +{ + int number = QInputDialog::getInteger(0, tr("Draw cards"), tr("Number:")); + if (number) + client->drawCards(number); +} + +void Game::actCreateToken() +{ + QString cardname = QInputDialog::getText(0, tr("Create token"), tr("Name:")); + if (!db->getCard(cardname)) + QMessageBox::critical(0, "Error", "No such card"); + else + client->createToken("table", cardname, QString(), 0, 0); +} + +void Game::showCardMenu(QPoint p) +{ + cardMenu->exec(p); +} + +void Game::actTap() +{ + QListIterator i(scene->selectedItems()); + while (i.hasNext()) { + CardItem *temp = (CardItem *) i.next(); + client->setCardAttr(qgraphicsitem_cast(temp->parentItem())->getName(), temp->getId(), "tapped", "1"); + } +} + +void Game::actUntap() +{ + QListIterator i(scene->selectedItems()); + while (i.hasNext()) { + CardItem *temp = (CardItem *) i.next(); + client->setCardAttr(qgraphicsitem_cast(temp->parentItem())->getName(), temp->getId(), "tapped", "0"); + } +} + +void Game::actAddCounter() +{ + QListIterator i(scene->selectedItems()); + while (i.hasNext()) { + CardItem *temp = (CardItem *) i.next(); + if (temp->getCounters() < MAX_COUNTERS_ON_CARD) + client->setCardAttr(qgraphicsitem_cast(temp->parentItem())->getName(), temp->getId(), "counters", QString::number(temp->getCounters() + 1)); + } +} + +void Game::actRemoveCounter() +{ + QListIterator i(scene->selectedItems()); + while (i.hasNext()) { + CardItem *temp = (CardItem *) i.next(); + if (temp->getCounters()) + client->setCardAttr(qgraphicsitem_cast(temp->parentItem())->getName(), temp->getId(), "counters", QString::number(temp->getCounters() - 1)); + } +} + +void Game::actSetCounters() +{ + bool ok; + int number = QInputDialog::getInteger(0, tr("Set counters"), tr("Number:"), 0, 0, MAX_COUNTERS_ON_CARD, 1, &ok); + if (!ok) + return; + + QListIterator i(scene->selectedItems()); + while (i.hasNext()) { + CardItem *temp = (CardItem *) i.next(); + client->setCardAttr(qgraphicsitem_cast(temp->parentItem())->getName(), temp->getId(), "counters", QString::number(number)); + } +} + +void Game::actRearrange() +{ + // nur sinnvoll bei Karten auf dem Tisch -> Einschränkung einbauen + int x, y, x_initial = 0, y_initial = 0; + QList list = scene->selectedItems(); + + // Find coordinates of leftmost card + for (int i = 0; i < list.size(); i++) { + CardItem *temp = (CardItem *) list.at(i); + if ((temp->pos().x() < x_initial) || (x_initial == 0)) { + x_initial = (int) temp->pos().x(); + y_initial = (int) temp->pos().y(); + } + } + x = x_initial; + y = y_initial; + + for (int i = 0; i < list.size(); i++) { + CardItem *temp = (CardItem *) list.at(i); + QString zoneName = qgraphicsitem_cast(temp->parentItem())->getName(); + x = x_initial + i * RASTER_WIDTH; + y = y_initial + (i % 3) * RASTER_HEIGHT; + client->moveCard(temp->getId(), zoneName, zoneName, x, y); + } +} diff --git a/cockatrice/src/game.h b/cockatrice/src/game.h new file mode 100644 index 00000000..72e39d55 --- /dev/null +++ b/cockatrice/src/game.h @@ -0,0 +1,80 @@ +#ifndef GAME_H +#define GAME_H + +#include "playerlist.h" + +class ServerPlayer; +class QGraphicsScene; +class Player; +class Client; +class ServerEventData; +class CardDatabase; +class DlgStartGame; + +class Game : public QObject { + Q_OBJECT +private: + QMenu *actionsMenu, *cardMenu; + QAction *aTap, *aUntap, *aAddCounter, *aRemoveCounter, *aSetCounters, *aRearrange, + *aUntapAll, *aDecLife, *aIncLife, *aSetLife, *aShuffle, *aDraw, *aDrawCards, *aRollDice, *aCreateToken; + DlgStartGame *dlgStartGame; + + CardDatabase *db; + Client *client; + QGraphicsScene *scene; + PlayerList players; + Player *localPlayer; + bool started; + Player *addPlayer(int playerId, const QString &playerName, QPointF base, bool local); +private slots: + void actUntapAll(); + void actIncLife(); + void actDecLife(); + void actSetLife(); + void actShuffle(); + void actDrawCard(); + void actDrawCards(); + void actRollDice(); + void actCreateToken(); + + void showCardMenu(QPoint p); + void actTap(); + void actUntap(); + void actAddCounter(); + void actRemoveCounter(); + void actSetCounters(); + void actRearrange(); + + void gameEvent(ServerEventData *msg); + void playerListReceived(QList playerList); +signals: + void submitDecklist(); + void hoverCard(QString name); + void playerAdded(Player *player); + void playerRemoved(Player *player); + + // Log events + void logPlayerListReceived(QStringList players); + void logJoin(QString playerName); + void logLeave(QString playerName); + void logReadyStart(QString playerName); + void logGameStart(); + void logSay(QString playerName, QString text); + void logShuffle(QString playerName); + void logRollDice(QString playerName, int sides, int roll); + void logDraw(QString playerName, int number); + void logMoveCard(QString playerName, QString cardName, QString startZone, QString targetZone); + void logCreateToken(QString playerName, QString cardName); + void logSetCardCounters(QString playerName, QString cardName, int value, int oldValue); + void logSetTapped(QString playerName, QString cardName, bool tapped); + void logSetCounter(QString playerName, QString counterName, int value, int oldValue); + void logDumpZone(QString playerName, QString zoneName, QString zoneOwner, int numberCards); +public slots: + void restartGameDialog(); +public: + Game(CardDatabase *_db, Client *_client, QGraphicsScene *_scene, QMenu *_actionsMenu, QMenu *_cardMenu, int playerId, const QString &playerName); + ~Game(); + Player *getLocalPlayer() const { return localPlayer; } +}; + +#endif diff --git a/cockatrice/src/gamesmodel.cpp b/cockatrice/src/gamesmodel.cpp new file mode 100644 index 00000000..55e23dcb --- /dev/null +++ b/cockatrice/src/gamesmodel.cpp @@ -0,0 +1,74 @@ +#include "gamesmodel.h" +#include "servergame.h" + +GamesModel::~GamesModel() +{ + cleanList(); +} + +int GamesModel::rowCount(const QModelIndex &parent) const +{ + return gameList.size(); +} + +int GamesModel::columnCount(const QModelIndex &parent) const +{ + return 4; +} + +QVariant GamesModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + if ((index.row() >= gameList.size()) || (index.column() >= 4)) + return QVariant(); + + if (role != Qt::DisplayRole) + return QVariant(); + + ServerGame *g = gameList.at(index.row()); + switch (index.column()) { + case 0: return g->getName(); + case 1: return g->getDescription(); + case 2: return QString(g->getHasPassword() ? "yes" : "no"); + case 3: return QString("%1/%2").arg(g->getPlayerCount()).arg(g->getMaxPlayers()); + default: return QVariant(); + } +} + +QVariant GamesModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + if (orientation != Qt::Horizontal) + return QVariant(); + switch (section) { + case 0: return QString("Name"); + case 1: return QString("Description"); + case 2: return QString("Password"); + case 3: return QString("Players"); + default: return QVariant(); + } +} + +ServerGame *GamesModel::getGame(int row) +{ + if (row >= gameList.size()) + return 0; + return gameList[row]; +} + +void GamesModel::setGameList(const QList &_gameList) +{ + cleanList(); + gameList = _gameList; + reset(); +} + +void GamesModel::cleanList() +{ + QListIterator i(gameList); + while (i.hasNext()) + delete i.next(); + gameList.clear(); +} diff --git a/cockatrice/src/gamesmodel.h b/cockatrice/src/gamesmodel.h new file mode 100644 index 00000000..43864fb2 --- /dev/null +++ b/cockatrice/src/gamesmodel.h @@ -0,0 +1,26 @@ +#ifndef GAMESMODEL_H +#define GAMESMODEL_H + +#include +#include +#include "servergame.h" + +class GamesModel : public QAbstractListModel { + Q_OBJECT +public: + GamesModel(QObject *parent = 0) + : QAbstractListModel(parent) { } + ~GamesModel(); + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + void setGameList(const QList &_gameList); + ServerGame *getGame(int row); +private: + QList gameList; + void cleanList(); +}; + +#endif diff --git a/cockatrice/src/gameview.cpp b/cockatrice/src/gameview.cpp new file mode 100644 index 00000000..152f57e7 --- /dev/null +++ b/cockatrice/src/gameview.cpp @@ -0,0 +1,33 @@ +#include "gameview.h" + +GameView::GameView(QGraphicsScene *scene, QWidget *parent) + : QGraphicsView(scene, parent) +{ + setBackgroundBrush(QBrush(QColor(0, 0, 0))); + setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + setOptimizationFlags(/*DontClipPainter | */DontSavePainterState); + setDragMode(RubberBandDrag); +} + +void GameView::scaleToScene() +{ + // This function ensures that the bounding rectangles of card pictures + // have integer sizes. This is achieved by using a scale factor of n / 6. + QRectF sr = scene()->sceneRect(); + QRectF vr = QRectF(viewport()->rect().adjusted(2, 2, -2, -2)); + qreal scale_h = vr.width() / sr.width(); + qreal scale_v = vr.height() / sr.height(); + qreal scale_total = qMin(scale_h, scale_v); + + qreal scale_corr = (qreal) ((int) (scale_total * 6)) / 6; + + qDebug(QString("scale_corr = %1 / 6").arg(scale_corr * 6).toLatin1()); + setTransform(QTransform().scale(scale_corr, scale_corr)); +} + +void GameView::resizeEvent(QResizeEvent *event) +{ + qDebug("GameView: resizeEvent"); + QGraphicsView::resizeEvent(event); + scaleToScene(); +} diff --git a/cockatrice/src/gameview.h b/cockatrice/src/gameview.h new file mode 100644 index 00000000..e3783caf --- /dev/null +++ b/cockatrice/src/gameview.h @@ -0,0 +1,14 @@ +#ifndef GAMEVIEW_H +#define GAMEVIEW_H + +#include + +class GameView : public QGraphicsView { +protected: + void resizeEvent(QResizeEvent *event); +public: + void scaleToScene(); + GameView(QGraphicsScene *scene, QWidget *parent = 0); +}; + +#endif diff --git a/cockatrice/src/gravezone.cpp b/cockatrice/src/gravezone.cpp new file mode 100644 index 00000000..ea32dd4a --- /dev/null +++ b/cockatrice/src/gravezone.cpp @@ -0,0 +1,53 @@ +#include +#include "gravezone.h" +#include "player.h" +#include "client.h" +#include "zoneviewzone.h" + +GraveZone::GraveZone(Player *_p) + : PlayerZone(_p, "grave") +{ + cards = new CardList(true); +} + +QRectF GraveZone::boundingRect() const +{ + return QRectF(0, 0, 50, 50); +} + +void GraveZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + painter->save(); + painter->fillRect(boundingRect(), QColor("yellow")); + painter->setFont(QFont("Times", 20, QFont::Bold)); + painter->setPen(QPen(QColor("black"))); + painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(cards->size())); + painter->restore(); +} + +void GraveZone::addCard(CardItem *card, bool reorganize, int x, int y) +{ + for (int i = 0; i < views.size(); i++) + views[i]->addCard(new CardItem(player->getDb(), card->getName(), card->getId()), reorganize, x, y); + + cards->insert(x, card); + card->setPos(0, 0); + card->setVisible(false); + card->resetState(); + card->setParentItem(this); + + if (reorganize) + reorganizeCards(); +} + +void GraveZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint) +{ + player->client->moveCard(cardId, startZone->getName(), getName(), 0, 0); +} + +void GraveZone::reorganizeCards() +{ + update(boundingRect()); +} diff --git a/cockatrice/src/gravezone.h b/cockatrice/src/gravezone.h new file mode 100644 index 00000000..bf2d243d --- /dev/null +++ b/cockatrice/src/gravezone.h @@ -0,0 +1,17 @@ +#ifndef GRAVEZONE_H +#define GRAVEZONE_H + +#include "playerzone.h" + +class GraveZone : public PlayerZone { +private: +public: + GraveZone(Player *_p); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void addCard(CardItem *card, bool reorganize = true, int x = 0, int y = -1); + void reorganizeCards(); + void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint); +}; + +#endif diff --git a/cockatrice/src/handzone.cpp b/cockatrice/src/handzone.cpp new file mode 100644 index 00000000..3a8603ba --- /dev/null +++ b/cockatrice/src/handzone.cpp @@ -0,0 +1,73 @@ +#include +#include "handzone.h" +#include "player.h" +#include "client.h" + +HandZone::HandZone(Player *_p) + : PlayerZone(_p, "hand") +{ + cards = new CardList(player->getLocal()); +} + +QRectF HandZone::boundingRect() const +{ + return QRectF(0, 0, 100, 500); +} + +void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + painter->fillRect(boundingRect(), QColor("green")); +} + +void HandZone::reorganizeCards() +{ + if (cards->isEmpty()) + return; + + int cardCount = cards->size(); + qreal totalWidth = boundingRect().width(); + qreal totalHeight = boundingRect().height(); + qreal cardWidth = cards->at(0)->boundingRect().width(); + qreal cardHeight = cards->at(0)->boundingRect().height(); + qreal x = (totalWidth - cardWidth) / 2; + + for (int i = 0; i < cardCount; i++) { + CardItem *c = cards->at(i); + // If the total height of the cards is smaller than the available height, + // the cards do not need to overlap and are displayed in the center of the area. + if (cardHeight * cardCount > totalHeight) + c->setPos(x, ((qreal) i) * (totalHeight - cardHeight) / (cardCount - 1)); + else + c->setPos(x, ((qreal) i) * cardHeight + (totalHeight - cardCount * cardHeight) / 2); + c->setZValue(i); + } +} + +void HandZone::addCard(CardItem *card, bool reorganize, int x, int y) +{ + Q_UNUSED(y); + + if (x == -1) + x = cards->size(); + cards->insert(x, card); + + if (!cards->getContentsKnown()) { + card->setId(-1); + card->setName(); + } + card->setParentItem(this); + card->resetState(); + card->setVisible(true); + card->update(card->boundingRect()); + + if (reorganize) + reorganizeCards(); +} + +void HandZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint) +{ + Q_UNUSED(dropPoint); + player->client->moveCard(cardId, startZone->getName(), getName(), cards->size(), 0); +} diff --git a/cockatrice/src/handzone.h b/cockatrice/src/handzone.h new file mode 100644 index 00000000..e5541cfd --- /dev/null +++ b/cockatrice/src/handzone.h @@ -0,0 +1,17 @@ +#ifndef HANDZONE_H +#define HANDZONE_H + +#include "playerzone.h" + +class HandZone : public PlayerZone { +private: +public: + HandZone(Player *_p); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void addCard(CardItem *card, bool reorganize = true, int x = -1, int y = -1); + void reorganizeCards(); + void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint); +}; + +#endif diff --git a/cockatrice/src/libraryzone.cpp b/cockatrice/src/libraryzone.cpp new file mode 100644 index 00000000..8fc76bad --- /dev/null +++ b/cockatrice/src/libraryzone.cpp @@ -0,0 +1,88 @@ +#include +#include "libraryzone.h" +#include "player.h" +#include "client.h" +#include "carddatabase.h" +#include "carddragitem.h" +#include "zoneviewzone.h" + +LibraryZone::LibraryZone(Player *_p) + : PlayerZone(_p, "deck") +{ + cards = new CardList(false); + setCursor(Qt::OpenHandCursor); +} + +QRectF LibraryZone::boundingRect() const +{ + return QRectF(0, 0, 50, 50); +} + +void LibraryZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + painter->save(); + painter->fillRect(boundingRect(), QColor("red")); + painter->setFont(QFont("Times", 20, QFont::Bold)); + painter->setPen(QPen(QColor("black"))); + painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(cards->size())); + painter->restore(); +} + +void LibraryZone::addCard(CardItem *card, bool reorganize, int x, int y) +{ + for (int i = 0; i < views.size(); i++) + views[i]->addCard(new CardItem(player->getDb(), card->getName(), card->getId()), reorganize, x, y); + + cards->insert(x, card); + card->setId(-1); + card->setName(QString()); + card->setPos(0, 0); + card->setVisible(false); + card->resetState(); + card->setParentItem(this); + + if (reorganize) + reorganizeCards(); +} + +void LibraryZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint) +{ + player->client->moveCard(cardId, startZone->getName(), getName(), 0, 0); +} + +void LibraryZone::reorganizeCards() +{ + update(boundingRect()); +} + +void LibraryZone::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + PlayerZone::mousePressEvent(event); + if (event->isAccepted()) + return; + + if (event->button() == Qt::LeftButton) { + setCursor(Qt::ClosedHandCursor); + event->accept(); + } else + event->ignore(); +} + +void LibraryZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() < QApplication::startDragDistance()) + return; + + CardItem *card = cards->at(0); + CardDragItem *drag = card->createDragItem(this, 0, event->pos(), event->scenePos()); + drag->grabMouse(); + setCursor(Qt::OpenHandCursor); +} + +void LibraryZone::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event); + setCursor(Qt::OpenHandCursor); +} diff --git a/cockatrice/src/libraryzone.h b/cockatrice/src/libraryzone.h new file mode 100644 index 00000000..f394f105 --- /dev/null +++ b/cockatrice/src/libraryzone.h @@ -0,0 +1,21 @@ +#ifndef LIBRARYZONE_H +#define LIBRARYZONE_H + +#include "playerzone.h" + +class LibraryZone : public PlayerZone { +private: +public: + LibraryZone(Player *_p); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void addCard(CardItem *card, bool reorganize = true, int x = 0, int y = -1); + void reorganizeCards(); + void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint); +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); +}; + +#endif diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp new file mode 100644 index 00000000..d6243c84 --- /dev/null +++ b/cockatrice/src/main.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@gmx.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#include +#include +#include +#include "window.h" +#include + +//Q_IMPORT_PLUGIN(qjpeg) + +void myMessageOutput(QtMsgType type, const char *msg) +{ + static FILE *f = NULL; + if (!f) + f = fopen("qdebug.txt", "w"); + fprintf(f, "%s\n", msg); + fflush(f); +} + +int main(int argc, char *argv[]) +{ + qInstallMsgHandler(myMessageOutput); + QApplication app(argc, argv); + app.addLibraryPath("plugins"); + QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); + + MainWindow *ui = new MainWindow; + ui->show(); + + return app.exec(); +} + diff --git a/cockatrice/src/messagelogwidget.cpp b/cockatrice/src/messagelogwidget.cpp new file mode 100644 index 00000000..4a36cff9 --- /dev/null +++ b/cockatrice/src/messagelogwidget.cpp @@ -0,0 +1,147 @@ +#include "messagelogwidget.h" +#include "game.h" +#include + +void MessageLogWidget::appendAndScroll(const QString &s) +{ + append(s); + verticalScrollBar()->setValue(verticalScrollBar()->maximum()); +} + +void MessageLogWidget::logConnecting(QString hostname) +{ + appendAndScroll(tr("Connecting to %1...").arg(hostname)); +} + +void MessageLogWidget::logConnected(const QStringList WelcomeMsg) +{ + appendAndScroll(tr("Connected.")); + + QStringListIterator i(WelcomeMsg); + while (i.hasNext()) + appendAndScroll(i.next()); +} + +void MessageLogWidget::logDisconnected() +{ + appendAndScroll(tr("Disconnected from server.")); +} + +void MessageLogWidget::logSocketError(const QString &errorString) +{ + appendAndScroll(errorString); +} + +void MessageLogWidget::logPlayerListReceived(QStringList players) +{ + append("---"); + append(tr("You have joined the game. Player list:")); + for (int i = 0; i < players.size(); i++) + append(players.at(i)); + appendAndScroll("---"); +} + +void MessageLogWidget::logJoin(QString playerName) +{ + appendAndScroll(tr("%1 has joined the game").arg(playerName)); +} + +void MessageLogWidget::logLeave(QString playerName) +{ + appendAndScroll(tr("%1 has left the game").arg(playerName)); +} + +void MessageLogWidget::logReadyStart(QString playerName) +{ + appendAndScroll(tr("%1 is ready to start a new game.").arg(playerName)); +} + +void MessageLogWidget::logGameStart() +{ + appendAndScroll(tr("Game has started.")); +} + +void MessageLogWidget::logSay(QString playerName, QString message) +{ + appendAndScroll(QString("%1: %2").arg(playerName).arg(message)); +} + +void MessageLogWidget::logShuffle(QString playerName) +{ + appendAndScroll(tr("%1 shuffles his/her library").arg(playerName)); +} + +void MessageLogWidget::logRollDice(QString playerName, int sides, int roll) +{ + appendAndScroll(tr("%1 rolled a %2 with a %3-sided dice").arg(playerName).arg(roll).arg(sides)); +} + +void MessageLogWidget::logDraw(QString playerName, int number) +{ + if (number == 1) + appendAndScroll(tr("%1 draws a card").arg(playerName)); + else + appendAndScroll(tr("%1 draws %2 cards").arg(playerName).arg(number)); +} + +void MessageLogWidget::logMoveCard(QString playerName, QString cardName, QString startZone, QString targetZone) +{ + appendAndScroll(tr("%1 moves %2 from %3 to %4").arg(playerName).arg(cardName).arg(startZone).arg(targetZone)); +} + +void MessageLogWidget::logCreateToken(QString playerName, QString cardName) +{ + appendAndScroll(tr("%1 creates token: %2").arg(playerName).arg(cardName)); +} + +void MessageLogWidget::logSetCardCounters(QString playerName, QString cardName, int value, int oldValue) +{ + if (value > oldValue) + appendAndScroll(tr("%1 places %2 counters on %3 (now %4)").arg(playerName).arg(value - oldValue).arg(cardName).arg(value)); + else + appendAndScroll(tr("%1 removes %2 counters from %3 (now %4)").arg(playerName).arg(oldValue - value).arg(cardName).arg(value)); +} + +void MessageLogWidget::logSetTapped(QString playerName, QString cardName, bool tapped) +{ + appendAndScroll(tr("%1 %2 %3").arg(playerName).arg(tapped ? "taps" : "untaps").arg(cardName)); +} + +void MessageLogWidget::logSetCounter(QString playerName, QString counterName, int value, int oldValue) +{ + appendAndScroll(tr("%1 sets counter \"%2\" to %3 (%4%5)").arg(playerName).arg(counterName).arg(value).arg(value > oldValue ? "+" : "").arg(value - oldValue)); +} + +void MessageLogWidget::logDumpZone(QString playerName, QString zoneName, QString zoneOwner, int numberCards) +{ + if (numberCards) + appendAndScroll(tr("%1 is looking at the top %2 cards of %3's %4").arg(playerName).arg(numberCards).arg(zoneOwner).arg(zoneName)); + else + appendAndScroll(tr("%1 is looking at %2's %3").arg(playerName).arg(zoneOwner).arg(zoneName)); +} + + +void MessageLogWidget::connectToGame(Game *game) +{ + connect(game, SIGNAL(logPlayerListReceived(QStringList)), this, SLOT(logPlayerListReceived(QStringList))); + connect(game, SIGNAL(logJoin(QString)), this, SLOT(logJoin(QString))); + connect(game, SIGNAL(logLeave(QString)), this, SLOT(logLeave(QString))); + connect(game, SIGNAL(logReadyStart(QString)), this, SLOT(logReadyStart(QString))); + connect(game, SIGNAL(logGameStart()), this, SLOT(logGameStart())); + connect(game, SIGNAL(logSay(QString, QString)), this, SLOT(logSay(QString, QString))); + connect(game, SIGNAL(logShuffle(QString)), this, SLOT(logShuffle(QString))); + connect(game, SIGNAL(logRollDice(QString, int, int)), this, SLOT(logRollDice(QString, int, int))); + connect(game, SIGNAL(logDraw(QString, int)), this, SLOT(logDraw(QString, int))); + connect(game, SIGNAL(logMoveCard(QString, QString, QString, QString)), this, SLOT(logMoveCard(QString, QString, QString, QString))); + connect(game, SIGNAL(logCreateToken(QString, QString)), this, SLOT(logCreateToken(QString, QString))); + connect(game, SIGNAL(logSetCardCounters(QString, QString, int, int)), this, SLOT(logSetCardCounters(QString, QString, int, int))); + connect(game, SIGNAL(logSetTapped(QString, QString, bool)), this, SLOT(logSetTapped(QString, QString, bool))); + connect(game, SIGNAL(logSetCounter(QString, QString, int, int)), this, SLOT(logSetCounter(QString, QString, int, int))); + connect(game, SIGNAL(logDumpZone(QString, QString, QString, int)), this, SLOT(logDumpZone(QString, QString, QString, int))); +} + +MessageLogWidget::MessageLogWidget(QWidget *parent) + : QTextEdit(parent) +{ + setReadOnly(true); +} diff --git a/cockatrice/src/messagelogwidget.h b/cockatrice/src/messagelogwidget.h new file mode 100644 index 00000000..29e5936d --- /dev/null +++ b/cockatrice/src/messagelogwidget.h @@ -0,0 +1,39 @@ +#ifndef MESSAGELOGWIDGET_H +#define MESSAGELOGWIDGET_H + +#include +#include + +class Game; + +class MessageLogWidget : public QTextEdit { + Q_OBJECT +public slots: + void logConnecting(QString hostname); + void logConnected(const QStringList WelcomeMsg); + void logDisconnected(); + void logSocketError(const QString &errorString); +private slots: + void logPlayerListReceived(QStringList players); + void logJoin(QString playerName); + void logLeave(QString playerName); + void logReadyStart(QString playerName); + void logGameStart(); + void logSay(QString playerName, QString message); + void logShuffle(QString playerName); + void logRollDice(QString playerName, int sides, int roll); + void logDraw(QString playerName, int number); + void logMoveCard(QString playerName, QString cardName, QString startZone, QString targetZone); + void logCreateToken(QString playerName, QString cardName); + void logSetCardCounters(QString playerName, QString cardName, int value, int oldValue); + void logSetTapped(QString playerName, QString cardName, bool tapped); + void logSetCounter(QString playerName, QString counterName, int value, int oldValue); + void logDumpZone(QString playerName, QString zoneName, QString zoneOwner, int numberCards); +private: + void appendAndScroll(const QString &s); +public: + void connectToGame(Game *game); + MessageLogWidget(QWidget *parent = 0); +}; + +#endif diff --git a/cockatrice/src/pendingcommand.h b/cockatrice/src/pendingcommand.h new file mode 100644 index 00000000..212cb1ea --- /dev/null +++ b/cockatrice/src/pendingcommand.h @@ -0,0 +1,19 @@ +#ifndef PENDINGCOMMAND_H +#define PENDINGCOMMAND_H + +#include + +class PendingCommand { +private: + QString cmd; + int msgid; + int time; +public: + int getMsgId() const { return msgid; } + QString getCmd() const { return cmd; } + bool timeout() const { return time > 5; } + void incTime() { ++time; } + PendingCommand(const QString &_cmd, int _msgid) : cmd(_cmd), msgid(_msgid), time(0) { } +}; + +#endif diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp new file mode 100644 index 00000000..491932ec --- /dev/null +++ b/cockatrice/src/player.cpp @@ -0,0 +1,296 @@ +#include "player.h" +#include "client.h" +#include "handzone.h" +#include "tablezone.h" +#include "libraryzone.h" +#include "gravezone.h" +#include "rfgzone.h" +#include "sideboardzone.h" +#include + +Player::Player(const QString &_name, int _id, QPointF _base, bool _local, CardDatabase *_db, Client *_client) + : QObject(), defaultNumberTopCards(3), name(_name), id(_id), base(_base), local(_local), db(_db), client(_client) +{ + LibraryZone *deck = new LibraryZone(this); + deck->setPos(_base); + + // XXX + qreal foo = deck->boundingRect().height(); + + GraveZone *grave = new GraveZone(this); + grave->setPos(_base + QPointF(0, foo)); + + RfgZone *rfg = new RfgZone(this); + rfg->setPos(_base + QPointF(0, 2 * foo)); + + SideboardZone *sb = new SideboardZone(this); + sb->setPos(_base + QPointF(0, 3 * foo)); + + Counter *life = new Counter(this, "life"); + life->setPos(_base + QPointF(-50, 5 * foo)); + + _base += QPointF(deck->boundingRect().width(), 0); + + PlayerZone *hand = new HandZone(this); + hand->setPos(_base); + _base += QPointF(hand->boundingRect().width(), 0); + + PlayerZone *table = new TableZone(this); + table->setPos(_base); + + aMoveHandToTopLibrary = new QAction(tr("Move to &top of library"), this); + connect(aMoveHandToTopLibrary, SIGNAL(triggered()), this, SLOT(actMoveHandToTopLibrary())); + aMoveHandToBottomLibrary = new QAction(tr("Move to &bottom of library"), this); + connect(aMoveHandToBottomLibrary, SIGNAL(triggered()), this, SLOT(actMoveHandToBottomLibrary())); + + aViewLibrary = new QAction(tr("&View library"), this); + if (local) + aViewLibrary->setShortcut(tr("F5")); + connect(aViewLibrary, SIGNAL(triggered()), this, SLOT(actViewLibrary())); + aViewTopCards = new QAction(tr("View &top cards of library..."), this); + connect(aViewTopCards, SIGNAL(triggered()), this, SLOT(actViewTopCards())); + + aViewGraveyard = new QAction(tr("&View graveyard"), this); + if (local) + aViewGraveyard->setShortcut(tr("F6")); + connect(aViewGraveyard, SIGNAL(triggered()), this, SLOT(actViewGraveyard())); + + aViewRfg = new QAction(tr("&View removed cards"), this); + connect(aViewRfg, SIGNAL(triggered()), this, SLOT(actViewRfg())); + + aViewSideboard = new QAction(tr("&View sideboard"), this); + connect(aViewSideboard, SIGNAL(triggered()), this, SLOT(actViewSideboard())); + + playerMenu = new QMenu(tr("Player \"%1\"").arg(name)); + + QMenu *handMenu = playerMenu->addMenu(tr("&Hand")); + handMenu->addAction(aMoveHandToTopLibrary); + handMenu->addAction(aMoveHandToBottomLibrary); + hand->setMenu(handMenu); + + QMenu *libraryMenu = playerMenu->addMenu(tr("&Library")); + libraryMenu->addAction(aViewLibrary); + libraryMenu->addAction(aViewTopCards); + deck->setMenu(libraryMenu); + + QMenu *graveMenu = playerMenu->addMenu(tr("&Graveyard")); + graveMenu->addAction(aViewGraveyard); + grave->setMenu(graveMenu); + + QMenu *rfgMenu = playerMenu->addMenu(tr("&Removed cards")); + rfgMenu->addAction(aViewRfg); + rfg->setMenu(rfgMenu); + + QMenu *sbMenu = playerMenu->addMenu(tr("&Sideboard")); + sbMenu->addAction(aViewSideboard); + sb->setMenu(sbMenu); +} + +Player::~Player() +{ + qDebug("Player destructor"); + + for (int i = 0; i < zones.size(); i++) + delete zones.at(i); + + for (int i = 0; i < counters.size(); i++) + delete counters.at(i); +} + +void Player::actMoveHandToTopLibrary() +{ + PlayerZone *library = zones.findZone("deck"); + zones.findZone("hand")->moveAllToZone(library->getName(), 0); +} + +void Player::actMoveHandToBottomLibrary() +{ + PlayerZone *library = zones.findZone("deck"); + zones.findZone("hand")->moveAllToZone(library->getName(), library->getCards()->size()); +} + +void Player::actViewLibrary() +{ + emit addZoneView(this, "deck", 0); +} + +void Player::actViewTopCards() +{ + bool ok; + int number = QInputDialog::getInteger(0, tr("View top cards of library"), tr("Number of cards:"), defaultNumberTopCards, 1, 2000000000, 1, &ok); + if (ok) { + defaultNumberTopCards = number; + emit addZoneView(this, "deck", number); + } +} + +void Player::actViewGraveyard() +{ + emit addZoneView(this, "grave", 0); +} + +void Player::actViewRfg() +{ + emit addZoneView(this, "rfg", 0); +} + +void Player::actViewSideboard() +{ + emit addZoneView(this, "sb", 0); +} + +void Player::addZone(PlayerZone *z) +{ + zones << z; +} + +void Player::addCounter(Counter *c) +{ + counters << c; +} + +void Player::gameEvent(ServerEventData *event) +{ + QStringList data = event->getEventData(); + switch (event->getEventType()) { + case eventSetupZones: { + // XXX Life counter + int life = data[0].toInt(); + int deck_cards = data[1].toInt(); + int sb_cards = data[2].toInt(); + // XXX Fehlerbehandlung + + // Clean up existing zones first + for (int i = 0; i < zones.size(); i++) + zones.at(i)->clearContents(); + + Counter *lifeCounter = counters.findCounter("life"); + lifeCounter->setValue(life); + + PlayerZone *deck = zones.findZone("deck"); + for (; deck_cards; deck_cards--) + deck->addCard(new CardItem(db, QString(), -1)); + deck->reorganizeCards(); + + PlayerZone *sb = zones.findZone("sb"); + for (; sb_cards; sb_cards--) + sb->addCard(new CardItem(db, QString(), -1)); + sb->reorganizeCards(); + + break; + } + case eventDraw: { + PlayerZone *deck = zones.findZone("deck"); + PlayerZone *hand = zones.findZone("hand"); + if (!event->getPublic()) { + hand->addCard(deck->takeCard(0, data[0].toInt(), data[1])); + } else { + int number = data[0].toInt(); + for (; number; number--) + hand->addCard(deck->takeCard(0, -1, QString())); + } + break; + } + case eventMoveCard: { + if (data.size() != 7) { + qDebug("error"); + // XXX + } + int cardId = data[0].toInt(); + QString cardName = data[1]; + PlayerZone *startZone = zones.findZone(data[2]); + if (!startZone) + qDebug(QString("start zone invalid: %1").arg(data[2]).toLatin1()); + int position = data[3].toInt(); + PlayerZone *targetZone = zones.findZone(data[4]); + if (!targetZone) + qDebug(QString("target zone invalid: %1").arg(data[4]).toLatin1()); + int x = data[5].toInt(); + int y = data[6].toInt(); + // XXX Mehr Fehlerbehandlung + + CardItem *card = startZone->takeCard(position, cardId, cardName); + if (!card) // XXX + qDebug("null"); + + card->deleteDragItem(); + + // The log event has to be sent before the card is added to the target zone + // because the addCard function can modify the card object. + emit logMoveCard(name, card->getName(), startZone->getName(), targetZone->getName()); + + targetZone->addCard(card, true, x, y); + + break; + } + case eventCreateToken: { + // zone, cardid, cardname, powtough, x, y + if (data.size() != 6) { + qDebug("error"); + } + PlayerZone *zone = zones.findZone(data[0]); + int cardid = data[1].toInt(); + QString cardname = data[2]; + QString powtough = data[3]; + int x = data[4].toInt(); + int y = data[5].toInt(); + + CardItem *card = new CardItem(db, cardname, cardid); + + emit logCreateToken(name, card->getName()); + zone->addCard(card, true, x, y); + + break; + } + case eventSetCardAttr: { + if (data.size() != 4) { + // XXX + } + PlayerZone *zone = zones.findZone(data[0]); + int cardId = data[1].toInt(); + CardItem *card = zone->getCard(cardId, ""); + QString aname = data[2]; + QString avalue = data[3]; + // XXX Fehlerbehandlung + + if (aname == "tapped") { + bool tapped = avalue == "1"; + emit logSetTapped(name, card->getName(), tapped); + card->setTapped(tapped); + } else if (aname == "attacking") + card->setAttacking(avalue == "1"); + else if (aname == "facedown") + card->setFacedown(avalue == "1"); + else if (aname == "counters") { + int value = avalue.toInt(); + emit logSetCardCounters(name, card->getName(), value, card->getCounters()); + card->setCounters(value); + } else if (aname == "annotation") + card->setAnnotation(avalue); + break; + } + case eventSetCounter: { + if (data.size() != 2) { + // XXX + } + int value = data[1].toInt(); + Counter *c = counters.findCounter(data[0]); + int oldValue = c->getValue(); + c->setValue(value); + emit logSetCounter(name, c->getName(), value, oldValue); + break; + } + default: + qDebug("unhandled player event"); + } +} + +void Player::hoverCardEvent(CardItem *card) +{ + emit hoverCard(card->getName()); +} + +void Player::showCardMenu(const QPoint &p) +{ + emit sigShowCardMenu(p); +} diff --git a/cockatrice/src/player.h b/cockatrice/src/player.h new file mode 100644 index 00000000..f2bd4677 --- /dev/null +++ b/cockatrice/src/player.h @@ -0,0 +1,71 @@ +#ifndef PLAYER_H +#define PLAYER_H + +#include +#include +#include "zonelist.h" +#include "counterlist.h" +#include "servereventdata.h" + +class Client; +class CardDatabase; +class QMenu; +class QAction; + +class Player : public QObject { + Q_OBJECT +signals: + void moveCard(int cardId, QString startZone, QString targetZone, int x, int y); + void hoverCard(QString name); + void addZoneView(Player *player, QString zoneName, int number); + void sigShowCardMenu(QPoint p); + // Log events + void logMoveCard(QString playerName, QString cardName, QString startZone, QString targetZone); + void logCreateToken(QString playerName, QString cardName); + void logSetCardCounters(QString playerName, QString cardName, int value, int oldValue); + void logSetTapped(QString playerName, QString cardName, bool tapped); + void logSetCounter(QString playerName, QString counterName, int value, int oldValue); +private slots: + void actMoveHandToTopLibrary(); + void actMoveHandToBottomLibrary(); + + void actViewLibrary(); + void actViewTopCards(); + + void actViewGraveyard(); + + void actViewRfg(); + + void actViewSideboard(); +private: + QMenu *playerMenu; + QAction *aMoveHandToTopLibrary, *aMoveHandToBottomLibrary, + *aViewLibrary, *aViewTopCards, *aViewGraveyard, *aViewRfg, *aViewSideboard; + + int defaultNumberTopCards; + QString name; + int id; + QPointF base; + bool local; + ZoneList zones; + CounterList counters; + CardDatabase *db; +public: + Client *client; + void addZone(PlayerZone *z); + void addCounter(Counter *c); + Player(const QString &_name, int _id, QPointF _base, bool _local, CardDatabase *_db, Client *_client); + ~Player(); + QMenu *getPlayerMenu() const { return playerMenu; } + int getId() const { return id; } + QString getName() const { return name; } + bool getLocal() const { return local; } + const ZoneList *const getZones() const { return &zones; } + const CounterList *const getCounters() const { return &counters; } + void gameEvent(ServerEventData *event); + void hoverCardEvent(CardItem *card); + CardDatabase *getDb() const { return db; } + void showCardMenu(const QPoint &p); +}; + +#endif diff --git a/cockatrice/src/playerlist.cpp b/cockatrice/src/playerlist.cpp new file mode 100644 index 00000000..091fae2c --- /dev/null +++ b/cockatrice/src/playerlist.cpp @@ -0,0 +1,11 @@ +#include "playerlist.h" + +Player *PlayerList::findPlayer(int id) const +{ + for (int i = 0; i < size(); i++) { + Player *temp = at(i); + if (temp->getId() == id) + return temp; + } + return 0; +} diff --git a/cockatrice/src/playerlist.h b/cockatrice/src/playerlist.h new file mode 100644 index 00000000..3658cf9f --- /dev/null +++ b/cockatrice/src/playerlist.h @@ -0,0 +1,12 @@ +#ifndef PLAYERLIST_H +#define PLAYERLIST_H + +#include "player.h" +#include + +class PlayerList : public QList { +public: + Player *findPlayer(int id) const; +}; + +#endif diff --git a/cockatrice/src/playerzone.cpp b/cockatrice/src/playerzone.cpp new file mode 100644 index 00000000..96fef484 --- /dev/null +++ b/cockatrice/src/playerzone.cpp @@ -0,0 +1,98 @@ +#include +#include "playerzone.h" +#include "carditem.h" +#include "player.h" +#include "client.h" +#include "zoneviewzone.h" + +PlayerZone::PlayerZone(Player *_p, const QString &_name, QGraphicsItem *parent, bool isView) + : QGraphicsItem(parent), player(_p), name(_name), cards(NULL), menu(NULL), hasCardAttr(false) +{ + if (!isView) + player->addZone(this); +} + +PlayerZone::~PlayerZone() +{ + qDebug(QString("PlayerZone destructor: %1").arg(name).toLatin1()); + while (!views.empty()) + delete views.at(0); + + clearContents(); + delete cards; +} + +void PlayerZone::clearContents() +{ + for (int i = 0; i < cards->size(); i++) + delete cards->at(i); + cards->clear(); +} + +void PlayerZone::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->button() == Qt::RightButton) { + if (menu) { + menu->exec(event->screenPos()); + event->accept(); + } else + event->ignore(); + } else + event->ignore(); +} + +CardItem *PlayerZone::getCard(int cardId, const QString &cardName) +{ + CardItem *c = cards->findCard(cardId, false); + // If the card's id is -1, this zone is invisible, + // so we need to give the card an id and a name as it comes out. + // It can be assumed that in an invisible zone, all cards are equal. + if ((c->getId() == -1) || (c->getName().isEmpty())) { + c->setId(cardId); + c->setName(cardName); + } + return c; +} + +CardItem *PlayerZone::takeCard(int position, int cardId, const QString &cardName) +{ + CardItem *c = cards->takeAt(position); + for (int i = 0; i < views.size(); i++) + views[i]->removeCard(position); + + if (c->getId() == -1) { + c->setId(cardId); + c->setName(cardName); + } + reorganizeCards(); + return c; +} + +void PlayerZone::setCardAttr(int cardId, const QString &aname, const QString &avalue) +{ + if (hasCardAttr) + player->client->setCardAttr(name, cardId, aname, avalue); +} + +void PlayerZone::hoverCardEvent(CardItem *card) +{ + player->hoverCardEvent(card); +} + +void PlayerZone::addView(ZoneViewZone *view) +{ + views.append(view); +} + +void PlayerZone::removeView(ZoneViewZone *view) +{ + views.removeAt(views.indexOf(view)); +} + +void PlayerZone::moveAllToZone(const QString &targetZone, int targetX) +{ + // Cards need to be moved in reverse order so that the other + // cards' list index doesn't change + for (int i = cards->size() - 1; i >= 0; i--) + player->client->moveCard(cards->at(i)->getId(), getName(), targetZone, targetX); +} diff --git a/cockatrice/src/playerzone.h b/cockatrice/src/playerzone.h new file mode 100644 index 00000000..804ae120 --- /dev/null +++ b/cockatrice/src/playerzone.h @@ -0,0 +1,47 @@ +#ifndef PLAYERZONE_H +#define PLAYERZONE_H + +#include +#include "cardlist.h" + +class Player; +class ZoneViewZone; +class QMenu; + +class PlayerZone : public QGraphicsItem { +protected: + Player *player; + QString name; + CardList *cards; + QList views; + QMenu *menu; + bool hasCardAttr; + void mousePressEvent(QGraphicsSceneMouseEvent *event); +public: + enum { Type = typeZone }; + int type() const { return Type; } + virtual void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint) = 0; + PlayerZone(Player *_player, const QString &_name, QGraphicsItem *parent = 0, bool isView = false); + ~PlayerZone(); + void clearContents(); + bool getHasCardAttr() const { return hasCardAttr; } + QMenu *getMenu() const { return menu; } + void setMenu(QMenu *_menu) { menu = _menu; } + QString getName() const { return name; } + Player *getPlayer() const { return player; } + bool contentsKnown() const { return cards->getContentsKnown(); } + CardList *const getCards() const { return cards; } + virtual void addCard(CardItem *card, bool reorganize = true, int x = -1, int y = -1) = 0; + // getCard() finds a card by id. + CardItem *getCard(int cardId, const QString &cardName); + // takeCard() finds a card by position and removes it from the zone and from all of its views. + CardItem *takeCard(int position, int cardId, const QString &cardName); + void setCardAttr(int cardId, const QString &aname, const QString &avalue); + void hoverCardEvent(CardItem *card); + void addView(ZoneViewZone *view); + void removeView(ZoneViewZone *view); + virtual void reorganizeCards() = 0; + void moveAllToZone(const QString &targetZone, int targetX); +}; + +#endif diff --git a/cockatrice/src/rfgzone.cpp b/cockatrice/src/rfgzone.cpp new file mode 100644 index 00000000..512b3020 --- /dev/null +++ b/cockatrice/src/rfgzone.cpp @@ -0,0 +1,53 @@ +#include +#include "rfgzone.h" +#include "player.h" +#include "client.h" +#include "zoneviewzone.h" + +RfgZone::RfgZone(Player *_p) + : PlayerZone(_p, "rfg") +{ + cards = new CardList(true); +} + +QRectF RfgZone::boundingRect() const +{ + return QRectF(0, 0, 50, 50); +} + +void RfgZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + painter->save(); + painter->fillRect(boundingRect(), QColor("white")); + painter->setFont(QFont("Times", 20, QFont::Bold)); + painter->setPen(QPen(QColor("black"))); + painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(cards->size())); + painter->restore(); +} + +void RfgZone::addCard(CardItem *card, bool reorganize, int x, int y) +{ + for (int i = 0; i < views.size(); i++) + views[i]->addCard(new CardItem(player->getDb(), card->getName(), card->getId()), reorganize, x, y); + + cards->insert(x, card); + card->setPos(0, 0); + card->setVisible(false); + card->resetState(); + card->setParentItem(this); + + if (reorganize) + reorganizeCards(); +} + +void RfgZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint) +{ + player->client->moveCard(cardId, startZone->getName(), getName(), 0, 0); +} + +void RfgZone::reorganizeCards() +{ + update(boundingRect()); +} diff --git a/cockatrice/src/rfgzone.h b/cockatrice/src/rfgzone.h new file mode 100644 index 00000000..4218c3fb --- /dev/null +++ b/cockatrice/src/rfgzone.h @@ -0,0 +1,17 @@ +#ifndef RFGZONE_H +#define RFGZONE_H + +#include "playerzone.h" + +class RfgZone : public PlayerZone { +private: +public: + RfgZone(Player *_p); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void addCard(CardItem *card, bool reorganize = true, int x = 0, int y = -1); + void reorganizeCards(); + void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint); +}; + +#endif diff --git a/cockatrice/src/servereventdata.cpp b/cockatrice/src/servereventdata.cpp new file mode 100644 index 00000000..8981ff02 --- /dev/null +++ b/cockatrice/src/servereventdata.cpp @@ -0,0 +1,49 @@ +#include "servereventdata.h" + +// Message structure for server events: +// {"private","public"}|PlayerId|PlayerName|EventType|EventData + +const int event_count = 19; +const event_string event_strings[event_count] = { + {eventPlayerId, "player_id"}, + {eventSay, "say"}, + {eventName, "name"}, + {eventJoin, "join"}, + {eventLeave, "leave"}, + {eventReadyStart, "ready_start"}, + {eventSetupZones, "setup_zones"}, + {eventGameStart, "game_start"}, + {eventShuffle, "shuffle"}, + {eventRollDice, "roll_dice"}, + {eventDraw, "draw"}, + {eventMoveCard, "move_card"}, + {eventCreateToken, "create_token"}, + {eventSetCardAttr, "set_card_attr"}, + {eventSetCounter, "set_counter"}, + {eventDelCounter, "del_counter"}, + {eventSetActivePlayer, "set_active_player"}, + {eventSetActivePhase, "set_active_phase"}, + {eventDumpZone, "dump_zone"} +}; + +ServerEventData::ServerEventData(const QString &line) +{ + QStringList values = line.split("|"); + + IsPublic = !values.takeFirst().compare("public"); + PlayerId = values.takeFirst().toInt(); + PlayerName = values.takeFirst(); + + QString type = values.takeFirst(); + bool found = false; + for (int i = 0; i < event_count; i++) + if (!type.compare(event_strings[i].str)) { + EventType = event_strings[i].type; + found = true; + break; + } + if (!found) + EventType = eventInvalid; + + EventData = values; +} diff --git a/cockatrice/src/servereventdata.h b/cockatrice/src/servereventdata.h new file mode 100644 index 00000000..662be5ba --- /dev/null +++ b/cockatrice/src/servereventdata.h @@ -0,0 +1,54 @@ +#ifndef SERVEREVENTDATA_H +#define SERVEREVENTDATA_H + +#include + + +enum ServerEventType { + eventInvalid, + eventPlayerId, + eventSay, + eventName, + eventJoin, + eventLeave, + eventReadyStart, + eventSetupZones, + eventGameStart, + eventShuffle, + eventRollDice, + eventDraw, + eventMoveCard, + eventCreateToken, + eventSetCardAttr, + eventSetCounter, + eventDelCounter, + eventSetActivePlayer, + eventSetActivePhase, + eventDumpZone +}; + +struct event_string { + ServerEventType type; + char *str; +}; + +extern const int event_count; +extern const event_string event_strings[]; + +class ServerEventData { +private: + bool IsPublic; + int PlayerId; + QString PlayerName; + ServerEventType EventType; + QStringList EventData; +public: + ServerEventData(const QString &line); + bool getPublic() { return IsPublic; } + int getPlayerId() { return PlayerId; } + QString getPlayerName() { return PlayerName; } + ServerEventType getEventType() { return EventType; } + QStringList getEventData() { return EventData; } +}; + +#endif diff --git a/cockatrice/src/servergame.h b/cockatrice/src/servergame.h new file mode 100644 index 00000000..30a9e39d --- /dev/null +++ b/cockatrice/src/servergame.h @@ -0,0 +1,21 @@ +#ifndef SERVERGAME_H +#define SERVERGAME_H + +class ServerGame { +private: + QString name; + QString description; + bool hasPassword; + unsigned char playerCount; + unsigned char maxPlayers; +public: + ServerGame(const QString &_name, const QString &_description, bool _hasPassword, unsigned char _playerCount, unsigned char _maxPlayers) + : name(_name), description(_description), hasPassword(_hasPassword), playerCount(_playerCount), maxPlayers(_maxPlayers) { } + QString getName() { return name; } + QString getDescription() { return description; } + bool getHasPassword() { return hasPassword; } + unsigned char getPlayerCount() { return playerCount; } + unsigned char getMaxPlayers() { return maxPlayers; } +}; + +#endif diff --git a/cockatrice/src/serverplayer.h b/cockatrice/src/serverplayer.h new file mode 100644 index 00000000..47d35ebe --- /dev/null +++ b/cockatrice/src/serverplayer.h @@ -0,0 +1,17 @@ +#ifndef SERVERPLAYER_H +#define SERVERPLAYER_H + +#include + +class ServerPlayer { +private: + int PlayerId; + QString name; +public: + ServerPlayer(int _PlayerId, const QString &_name) + : PlayerId(_PlayerId), name(_name) { } + int getPlayerId() { return PlayerId; } + QString getName() { return name; } +}; + +#endif diff --git a/cockatrice/src/serverresponse.h b/cockatrice/src/serverresponse.h new file mode 100644 index 00000000..e3b446a9 --- /dev/null +++ b/cockatrice/src/serverresponse.h @@ -0,0 +1,22 @@ +#ifndef SERVERRESPONSE_H +#define SERVERRESPONSE_H + +enum ServerErrorMessage { + msgNone, + msgSyntaxError +}; + +class ServerResponse { +private: + int msgId; + bool ok; + ServerErrorMessage message; +public: + ServerResponse(int _msgId, bool _ok, ServerErrorMessage _message) + : msgId(_msgId), ok(_ok), message(_message) { } + int getMsgId() { return msgId; } + bool getOk() { return ok; } + ServerErrorMessage getMessage() { return message; } +}; + +#endif diff --git a/cockatrice/src/serverzone.h b/cockatrice/src/serverzone.h new file mode 100644 index 00000000..6884d372 --- /dev/null +++ b/cockatrice/src/serverzone.h @@ -0,0 +1,21 @@ +#ifndef SERVERZONE_H +#define SERVERZONE_H + +#include + +class ServerZone { +private: + QString name; + bool isPublic; + bool hasCoords; + int cardCount; +public: + ServerZone(const QString &_name, bool _isPublic, bool _hasCoords, int _cardCount) + : name(_name), isPublic(_isPublic), hasCoords(_hasCoords), cardCount(_cardCount) { } + QString getName() const { return name; } + bool getPublic() const { return isPublic; } + bool getHasCoords() const { return hasCoords; } + int getCardCount() const { return cardCount; } +}; + +#endif diff --git a/cockatrice/src/serverzonecard.h b/cockatrice/src/serverzonecard.h new file mode 100644 index 00000000..acd1cf56 --- /dev/null +++ b/cockatrice/src/serverzonecard.h @@ -0,0 +1,28 @@ +#ifndef SERVERZONECARD_H +#define SERVERZONECARD_H + +#include + +class ServerZoneCard { +private: + int id; + QString name; + int x, y; + int counters; + bool tapped; + bool attacking; + QString annotation; +public: + ServerZoneCard(int _id, const QString &_name, int _x, int _y, int _counters, bool _attacking, const QString &_annotation) + : id(_id), name(_name), x(_x), y(_y), counters(_counters), attacking(_attacking), annotation(_annotation) { } + int getId() const { return id; } + QString getName() const { return name; } + int getX() const { return x; } + int getY() const { return y; } + int getCounters() const { return counters; } + bool getTapped() const { return tapped; } + bool getAttacking() const { return attacking; } + QString getAnnotation() const { return annotation; } +}; + +#endif diff --git a/cockatrice/src/sideboardzone.cpp b/cockatrice/src/sideboardzone.cpp new file mode 100644 index 00000000..c9083a27 --- /dev/null +++ b/cockatrice/src/sideboardzone.cpp @@ -0,0 +1,54 @@ +#include +#include "sideboardzone.h" +#include "player.h" +#include "client.h" +#include "zoneviewzone.h" + +SideboardZone::SideboardZone(Player *_p) + : PlayerZone(_p, "sb") +{ + cards = new CardList(false); +} + +QRectF SideboardZone::boundingRect() const +{ + return QRectF(0, 0, 50, 50); +} + +void SideboardZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + painter->save(); + painter->fillRect(boundingRect(), QColor("blue")); + painter->setFont(QFont("Times", 20, QFont::Bold)); + painter->setPen(QPen(QColor("black"))); + painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(cards->size())); + painter->restore(); +} + +void SideboardZone::addCard(CardItem *card, bool reorganize, int x, int y) +{ + for (int i = 0; i < views.size(); i++) + views[i]->addCard(new CardItem(player->getDb(), card->getName(), card->getId()), reorganize, x, y); + + cards->insert(x, card); + card->setPos(0, 0); + card->setVisible(false); + card->resetState(); + card->setParentItem(this); + + if (reorganize) + reorganizeCards(); +} + +void SideboardZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint) +{ + player->client->moveCard(cardId, startZone->getName(), getName(), 0, 0); +} + +void SideboardZone::reorganizeCards() +{ + update(boundingRect()); +} + diff --git a/cockatrice/src/sideboardzone.h b/cockatrice/src/sideboardzone.h new file mode 100644 index 00000000..c673ef06 --- /dev/null +++ b/cockatrice/src/sideboardzone.h @@ -0,0 +1,17 @@ +#ifndef SIDEBOARDZONE_H +#define SIDEBOARDZONE_H + +#include "playerzone.h" + +class SideboardZone : public PlayerZone { +private: +public: + SideboardZone(Player *_p); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void addCard(CardItem *card, bool reorganize = true, int x = 0, int y = -1); + void reorganizeCards(); + void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint); +}; + +#endif diff --git a/cockatrice/src/tablezone.cpp b/cockatrice/src/tablezone.cpp new file mode 100644 index 00000000..7c54dc29 --- /dev/null +++ b/cockatrice/src/tablezone.cpp @@ -0,0 +1,56 @@ +#include +#include "tablezone.h" +#include "player.h" +#include "client.h" + +TableZone::TableZone(Player *_p) + : PlayerZone(_p, "table"), width(700), height(500) +{ + cards = new CardList(true); + hasCardAttr = true; +} + +QRectF TableZone::boundingRect() const +{ + return QRectF(0, 0, width, height); +} + +void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + painter->fillRect(boundingRect(), QColor("blue")); +} + +void TableZone::addCard(CardItem *card, bool reorganize, int x, int y) +{ + Q_UNUSED(reorganize); + cards->append(card); + if ((x != -1) && (y != -1)) { + if (!player->getLocal()) + y = height - CARD_HEIGHT - y; + card->setPos(x, y); + } + card->setZValue((y + CARD_HEIGHT) * width + x + 1000); + card->setParentItem(this); + card->setVisible(true); + card->update(card->boundingRect()); +} + +void TableZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint) +{ + player->client->moveCard(cardId, startZone->getName(), getName(), dropPoint.x(), dropPoint.y()); +} + +void TableZone::reorganizeCards() +{ +} + +void TableZone::toggleTapped() +{ + QListIterator i(scene()->selectedItems()); + while (i.hasNext()) { + CardItem *temp = (CardItem *) i.next(); + setCardAttr(temp->getId(), "tapped", temp->getTapped() ? "0" : "1"); + } +} diff --git a/cockatrice/src/tablezone.h b/cockatrice/src/tablezone.h new file mode 100644 index 00000000..16af7eae --- /dev/null +++ b/cockatrice/src/tablezone.h @@ -0,0 +1,22 @@ +#ifndef TABLEZONE_H +#define TABLEZONE_H + +#include "playerzone.h" + +const int GRID_WIDTH = 30; +const int GRID_HEIGHT = 30; + +class TableZone : public PlayerZone { +private: + int width, height; +public: + TableZone(Player *_p); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void addCard(CardItem *card, bool reorganize = true, int x = -1, int y = -1); + void reorganizeCards(); + void toggleTapped(); + void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint); +}; + +#endif diff --git a/cockatrice/src/window.cpp b/cockatrice/src/window.cpp new file mode 100644 index 00000000..63b7020c --- /dev/null +++ b/cockatrice/src/window.cpp @@ -0,0 +1,258 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@gmx.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include +#include + +#include "window.h" +#include "dlg_connect.h" +#include "dlg_games.h" +#include "cardinfowidget.h" +#include "messagelogwidget.h" + +#include "gameview.h" +#include "player.h" +#include "game.h" +#include "carddatabase.h" +#include "zoneviewzone.h" +#include "zoneviewwidget.h" +#include "zoneviewlayout.h" + +void MainWindow::hoverCard(QString name) +{ + cardInfo->setCard(name); +} + +void MainWindow::playerAdded(Player *player) +{ + menuBar()->addMenu(player->getPlayerMenu()); + connect(player, SIGNAL(addZoneView(Player *, QString, int)), zoneLayout, SLOT(addItem(Player *, QString, int))); +} + +void MainWindow::playerRemoved(Player *player) +{ + menuBar()->removeAction(player->getPlayerMenu()->menuAction()); +} + +void MainWindow::statusChanged(ProtocolStatus _status) +{ + switch (_status) { + case StatusConnecting: + emit logConnecting(client->peerName()); + break; + case StatusDisconnected: + if (game) { + delete game; + game = 0; + } + aDisconnect->setEnabled(false); + aGames->setEnabled(false); + aRestartGame->setEnabled(false); + aLeaveGame->setEnabled(false); + emit logDisconnected(); + break; + case StatusConnected: + aDisconnect->setEnabled(true); + aGames->setEnabled(true); + default: + break; + } +} + +// Actions + +void MainWindow::actConnect() +{ + DlgConnect dlg(this); + if (dlg.exec()) + client->connectToServer(dlg.getHost(), dlg.getPort(), dlg.getPlayerName()); +} + +void MainWindow::actDisconnect() +{ + client->disconnectFromServer(); +} + +void MainWindow::actGames() +{ + DlgGames dlg(client, this); + dlg.exec(); +} + +void MainWindow::actLeaveGame() +{ + client->leaveGame(); + delete game; + game = 0; + aRestartGame->setEnabled(false); + aLeaveGame->setEnabled(false); + aGames->setEnabled(true); +} + +void MainWindow::actExit() +{ + close(); +} + +void MainWindow::updateSceneSize() +{ + QRectF sr = scene->sceneRect(); + QSizeF zoneSize = zoneLayout->size(); + qDebug(QString("updateSceneSize: width=%1").arg(850 + zoneSize.width()).toLatin1()); + scene->setSceneRect(sr.x(), sr.y(), 850 + zoneSize.width(), sr.height()); + view->scaleToScene(); +} + +// Knöpfe + +void MainWindow::buttonSay() +{ + client->say(sayEdit->text()); + sayEdit->clear(); +} + +void MainWindow::playerIdReceived(int id, QString name) +{ + game = new Game(db, client, scene, actionsMenu, cardMenu, id, name); + connect(game, SIGNAL(submitDecklist()), this, SLOT(decklistDialog())); + connect(game, SIGNAL(hoverCard(QString)), this, SLOT(hoverCard(QString))); + connect(game, SIGNAL(playerAdded(Player *)), this, SLOT(playerAdded(Player *))); + connect(game, SIGNAL(playerRemoved(Player *)), this, SLOT(playerRemoved(Player *))); + connect(aRestartGame, SIGNAL(triggered()), game, SLOT(restartGameDialog())); + playerAdded(game->getLocalPlayer()); + + messageLog->connectToGame(game); + aGames->setEnabled(false); + aRestartGame->setEnabled(true); + aLeaveGame->setEnabled(true); + + client->listPlayers(); +} + +void MainWindow::serverTimeout() +{ + QMessageBox::critical(this, tr("Error"), tr("Server timeout")); +} + +void MainWindow::createActions() +{ + aConnect = new QAction(tr("&Connect..."), this); + connect(aConnect, SIGNAL(triggered()), this, SLOT(actConnect())); + aDisconnect = new QAction(tr("&Disconnect"), this); + aDisconnect->setEnabled(false); + connect(aDisconnect, SIGNAL(triggered()), this, SLOT(actDisconnect())); + aGames = new QAction(tr("&Games..."), this); + aGames->setEnabled(false); + connect(aGames, SIGNAL(triggered()), this, SLOT(actGames())); + aRestartGame = new QAction(tr("&Restart game..."), this); + aRestartGame->setShortcut(tr("F2")); + aRestartGame->setEnabled(false); + aLeaveGame = new QAction(tr("&Leave game"), this); + aLeaveGame->setEnabled(false); + connect(aLeaveGame, SIGNAL(triggered()), this, SLOT(actLeaveGame())); + aExit = new QAction(tr("&Exit"), this); + connect(aExit, SIGNAL(triggered()), this, SLOT(actExit())); +} + +void MainWindow::createMenus() +{ + gameMenu = menuBar()->addMenu(tr("&Game")); + gameMenu->addAction(aConnect); + gameMenu->addAction(aDisconnect); + gameMenu->addSeparator(); + gameMenu->addAction(aGames); + gameMenu->addAction(aRestartGame); + gameMenu->addAction(aLeaveGame); + gameMenu->addSeparator(); + gameMenu->addAction(aExit); + + actionsMenu = menuBar()->addMenu(tr("&Actions")); + + cardMenu = menuBar()->addMenu(tr("&Card")); +} + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent), game(NULL) +{ +// setWindowState(windowState() | Qt::WindowFullScreen); + + QPixmapCache::setCacheLimit(200000); + createActions(); + createMenus(); + + db = new CardDatabase; + int cardCount = db->loadFromFile("../cards.dat"); + qDebug(QString("%1 cards loaded").arg(cardCount).toLatin1()); + + scene = new QGraphicsScene(0, 0, 850, 1000, this); + view = new GameView(scene); + +// view->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); +// view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); + + zoneLayout = new ZoneViewLayout(db); + zoneLayout->setPos(850, 0); + scene->addItem(zoneLayout); + connect(zoneLayout, SIGNAL(sizeChanged()), this, SLOT(updateSceneSize())); + + cardInfo = new CardInfoWidget(db); + messageLog = new MessageLogWidget; + sayEdit = new QLineEdit; + sayButton = new QPushButton(tr("&Say")); + + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->addWidget(sayEdit); + hLayout->addWidget(sayButton); + + QVBoxLayout *verticalLayout = new QVBoxLayout; + verticalLayout->addWidget(cardInfo); + verticalLayout->addWidget(messageLog); + verticalLayout->addLayout(hLayout); + + QHBoxLayout *mainLayout = new QHBoxLayout; + mainLayout->addWidget(view); + mainLayout->setStretchFactor(view, 10); + mainLayout->addLayout(verticalLayout); + + QWidget *centralWidget = new QWidget; + centralWidget->setLayout(mainLayout); + setCentralWidget(centralWidget); + + connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(buttonSay())); + connect(sayButton, SIGNAL(clicked()), this, SLOT(buttonSay())); + + client = new Client(this); + connect(client, SIGNAL(serverTimeout()), this, SLOT(serverTimeout())); + connect(client, SIGNAL(statusChanged(ProtocolStatus)), this, SLOT(statusChanged(ProtocolStatus))); + connect(client, SIGNAL(playerIdReceived(int, QString)), this, SLOT(playerIdReceived(int, QString))); + + connect(this, SIGNAL(logConnecting(QString)), messageLog, SLOT(logConnecting(QString))); + connect(client, SIGNAL(welcomeMsgReceived(const QStringList)), messageLog, SLOT(logConnected(const QStringList))); + connect(this, SIGNAL(logDisconnected()), messageLog, SLOT(logDisconnected())); + connect(client, SIGNAL(logSocketError(const QString &)), messageLog, SLOT(logSocketError(const QString &))); +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + delete game; + +// db->importOracle(); +// db->saveToFile("../cards.dat"); + delete db; +} diff --git a/cockatrice/src/window.h b/cockatrice/src/window.h new file mode 100644 index 00000000..9f622180 --- /dev/null +++ b/cockatrice/src/window.h @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@gmx.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef WINDOW_H +#define WINDOW_H + +#include +#include "client.h" + +class QGraphicsScene; +class GameView; +class Game; +class CardDatabase; +class Player; + +class CardInfoWidget; +class MessageLogWidget; +class QLineEdit; +class QPushButton; +class ServerZoneCard; +class ZoneViewLayout; +class ZoneViewWidget; + +class MainWindow : public QMainWindow { + Q_OBJECT +private slots: + void hoverCard(QString name); + void playerAdded(Player *player); + void playerRemoved(Player *player); + void statusChanged(ProtocolStatus _status); + void playerIdReceived(int id, QString name); + void serverTimeout(); + + void buttonSay(); + + void actConnect(); + void actDisconnect(); + void actGames(); + void actLeaveGame(); + void actExit(); + + void updateSceneSize(); +signals: + void logConnecting(QString hostname); + void logDisconnected(); +private: + void createActions(); + void createMenus(); + QMenu *gameMenu, *actionsMenu, *cardMenu; + QAction *aConnect, *aDisconnect, *aGames, *aRestartGame, *aLeaveGame, *aExit; + + CardInfoWidget *cardInfo; + MessageLogWidget *messageLog; + QLineEdit *sayEdit; + QPushButton *sayButton; + + Client *client; + QGraphicsScene *scene; + GameView *view; + Game *game; + CardDatabase *db; + ZoneViewLayout *zoneLayout; +public: + MainWindow(QWidget *parent = 0); +protected: + void closeEvent(QCloseEvent *event); +}; + +#endif diff --git a/cockatrice/src/zoneclosebutton.cpp b/cockatrice/src/zoneclosebutton.cpp new file mode 100644 index 00000000..831c6b79 --- /dev/null +++ b/cockatrice/src/zoneclosebutton.cpp @@ -0,0 +1,18 @@ +#include +#include "zoneclosebutton.h" + +void ZoneCloseButton::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + emit triggered(); +} + +void ZoneCloseButton::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + painter->fillRect(rect(), QColor("red")); +} + +ZoneCloseButton::ZoneCloseButton(QGraphicsItem *parent) + : QGraphicsWidget(parent) +{ + resize(20, 20); +} diff --git a/cockatrice/src/zoneclosebutton.h b/cockatrice/src/zoneclosebutton.h new file mode 100644 index 00000000..5f3b852e --- /dev/null +++ b/cockatrice/src/zoneclosebutton.h @@ -0,0 +1,17 @@ +#ifndef ZONECLOSEBUTTON_H +#define ZONECLOSEBUTTON_H + +#include + +class ZoneCloseButton : public QGraphicsWidget { + Q_OBJECT +signals: + void triggered(); +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event); +public: + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + ZoneCloseButton(QGraphicsItem *parent = 0); +}; + +#endif diff --git a/cockatrice/src/zonelist.cpp b/cockatrice/src/zonelist.cpp new file mode 100644 index 00000000..947784d2 --- /dev/null +++ b/cockatrice/src/zonelist.cpp @@ -0,0 +1,11 @@ +#include "zonelist.h" + +PlayerZone *ZoneList::findZone(const QString &name) const +{ + for (int i = 0; i < size(); i++) { + PlayerZone *temp = at(i); + if (!temp->getName().compare(name)) + return temp; + } + return 0; +} diff --git a/cockatrice/src/zonelist.h b/cockatrice/src/zonelist.h new file mode 100644 index 00000000..3042f104 --- /dev/null +++ b/cockatrice/src/zonelist.h @@ -0,0 +1,12 @@ +#ifndef ZONELIST_H +#define ZONELIST_H + +#include "playerzone.h" +#include + +class ZoneList : public QList { +public: + PlayerZone *findZone(const QString &name) const; +}; + +#endif diff --git a/cockatrice/src/zoneviewlayout.cpp b/cockatrice/src/zoneviewlayout.cpp new file mode 100644 index 00000000..04e1285a --- /dev/null +++ b/cockatrice/src/zoneviewlayout.cpp @@ -0,0 +1,36 @@ +#include "zoneviewlayout.h" +#include "zoneviewwidget.h" +#include "player.h" + +ZoneViewLayout::ZoneViewLayout(CardDatabase *_db, QGraphicsItem *parent) + : QGraphicsWidget(parent), db(_db) +{ + +} + +void ZoneViewLayout::reorganize() +{ + qDebug(QString("ZoneViewLayout: activate: count=%1").arg(views.size()).toLatin1()); + resize(views.size() * 150, 1000); + for (int i = 0; i < views.size(); i++) { + views.at(i)->setPos(i * 150, 0); + } + emit sizeChanged(); +} + +void ZoneViewLayout::addItem(Player *player, const QString &zoneName, int numberCards) +{ + ZoneViewWidget *item = new ZoneViewWidget(db, player, player->getZones()->findZone(zoneName), numberCards, this); + views.append(item); + connect(item, SIGNAL(closePressed(ZoneViewWidget *)), this, SLOT(removeItem(ZoneViewWidget *))); + reorganize(); +} + +void ZoneViewLayout::removeItem(ZoneViewWidget *item) +{ + qDebug("ZoneViewLayout::removeItem"); + views.removeAt(views.indexOf(item)); + scene()->removeItem(item); + delete item; + reorganize(); +} diff --git a/cockatrice/src/zoneviewlayout.h b/cockatrice/src/zoneviewlayout.h new file mode 100644 index 00000000..8e7da1d3 --- /dev/null +++ b/cockatrice/src/zoneviewlayout.h @@ -0,0 +1,25 @@ +#ifndef ZONEVIEWLAYOUT_H +#define ZONEVIEWLAYOUT_H + +#include + +class CardDatabase; +class ZoneViewWidget; +class Player; + +class ZoneViewLayout : public QGraphicsWidget { + Q_OBJECT +signals: + void sizeChanged(); +private: + QList views; + CardDatabase *db; +public: + ZoneViewLayout(CardDatabase *_db, QGraphicsItem *parent = 0); + void reorganize(); +public slots: + void addItem(Player *player, const QString &zoneName, int numberCards = 0); + void removeItem(ZoneViewWidget *item); +}; + +#endif diff --git a/cockatrice/src/zoneviewwidget.cpp b/cockatrice/src/zoneviewwidget.cpp new file mode 100644 index 00000000..d7398608 --- /dev/null +++ b/cockatrice/src/zoneviewwidget.cpp @@ -0,0 +1,45 @@ +#include + +#include "zoneviewwidget.h" +#include "carditem.h" +#include "zoneviewzone.h" +#include "player.h" +#include "client.h" +#include "zoneclosebutton.h" + +ZoneViewWidget::ZoneViewWidget(CardDatabase *_db, Player *_player, PlayerZone *_origZone, int numberCards, QGraphicsItem *parent) + : QGraphicsWidget(parent), db(_db), player(_player) +{ + ZoneCloseButton *closeButton = new ZoneCloseButton(this); + connect(closeButton, SIGNAL(triggered()), this, SLOT(slotClosePressed())); + + resize(150, 1000); + + zone = new ZoneViewZone(player, _origZone, numberCards, this); + zone->setPos(0, 30); + if (!zone->initializeCards()) { + connect(player->client, SIGNAL(zoneDumpReceived(int, QList)), this, SLOT(zoneDumpReceived(int, QList))); + cmdId = player->client->dumpZone(player->getId(), _origZone->getName(), numberCards); + } +} + +void ZoneViewWidget::zoneDumpReceived(int commandId, QList cards) +{ + if (commandId != cmdId) + return; + + for (int i = 0; i < cards.size(); i++) { + ServerZoneCard *temp = cards[i]; + + CardItem *card = new CardItem(db, temp->getName(), i, zone); + zone->addCard(card, false, i); + + delete temp; + } + zone->reorganizeCards(); +} + +void ZoneViewWidget::slotClosePressed() +{ + emit closePressed(this); +} diff --git a/cockatrice/src/zoneviewwidget.h b/cockatrice/src/zoneviewwidget.h new file mode 100644 index 00000000..005a6876 --- /dev/null +++ b/cockatrice/src/zoneviewwidget.h @@ -0,0 +1,31 @@ +#ifndef ZONEVIEWWIDGET_H +#define ZONEVIEWWIDGET_H + +#include +#include +#include +#include "serverzonecard.h" + +class PlayerZone; +class ZoneViewZone; +class Player; +class CardDatabase; + +class ZoneViewWidget : public QGraphicsWidget { + Q_OBJECT +private: + ZoneViewZone *zone; + int cmdId; + + CardDatabase *db; + Player *player; +signals: + void closePressed(ZoneViewWidget *zv); +private slots: + void zoneDumpReceived(int commandId, QList cards); + void slotClosePressed(); +public: + ZoneViewWidget(CardDatabase *_db, Player *_player, PlayerZone *_origZone, int numberCards = 0, QGraphicsItem *parent = 0); +}; + +#endif diff --git a/cockatrice/src/zoneviewzone.cpp b/cockatrice/src/zoneviewzone.cpp new file mode 100644 index 00000000..bf8d6501 --- /dev/null +++ b/cockatrice/src/zoneviewzone.cpp @@ -0,0 +1,104 @@ +#include +#include "zoneviewzone.h" +#include "player.h" +#include "client.h" + +ZoneViewZone::ZoneViewZone(Player *_p, PlayerZone *_origZone, int _numberCards, QGraphicsItem *parent) + : PlayerZone(_p, _origZone->getName(), parent, true), numberCards(_numberCards), origZone(_origZone) +{ + cards = new CardList(true); + origZone->addView(this); +} + +ZoneViewZone::~ZoneViewZone() +{ + qDebug("ZoneViewZone destructor"); + origZone->removeView(this); +} + +QRectF ZoneViewZone::boundingRect() const +{ + return QRectF(0, 0, CARD_WIDTH * 1.75, scene()->sceneRect().height()); +} + +void ZoneViewZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(painter); + Q_UNUSED(option); + Q_UNUSED(widget); +} + +bool ZoneViewZone::initializeCards() +{ + if (!origZone->contentsKnown()) + return false; + + CardList *const c = origZone->getCards(); + int number = numberCards == 0 ? c->size() : (numberCards < c->size() ? numberCards : c->size()); + for (int i = 0; i < number; i++) { + CardItem *card = c->at(i); + addCard(new CardItem(player->getDb(), card->getName(), card->getId(), this), false, i); + } + reorganizeCards(); + return true; +} + +// Because of boundingRect(), this function must not be called before the zone was added to a scene. +void ZoneViewZone::reorganizeCards() +{ + qDebug("reorganizeCards"); + + if (cards->isEmpty()) + return; + + int cardCount = cards->size(); + qreal totalWidth = boundingRect().width(); + qreal totalHeight = boundingRect().height(); + qreal cardWidth = cards->at(0)->boundingRect().width(); + qreal cardHeight = cards->at(0)->boundingRect().height(); + qreal x1 = 0; + qreal x2 = (totalWidth - cardWidth); + + for (int i = 0; i < cardCount; i++) { + CardItem *c = cards->at(i); + qreal x = i % 2 ? x2 : x1; + // If the total height of the cards is smaller than the available height, + // the cards do not need to overlap and are displayed in the center of the area. + if (cardHeight * cardCount > totalHeight) + c->setPos(x, ((qreal) i) * (totalHeight - cardHeight) / (cardCount - 1)); + else + c->setPos(x, ((qreal) i) * cardHeight + (totalHeight - cardCount * cardHeight) / 2); + if (!origZone->contentsKnown()) + c->setId(i); + c->setZValue(i); + } +} + +void ZoneViewZone::addCard(CardItem *card, bool reorganize, int x, int y) +{ + Q_UNUSED(y); + qDebug(QString("ZoneViewZone: inserting '%1' at x=%2").arg(card->getName()).arg(x).toLatin1()); + cards->insert(x, card); + card->setParentItem(this); + card->update(card->boundingRect()); + if (reorganize) + reorganizeCards(); +} + +void ZoneViewZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint) +{ + Q_UNUSED(dropPoint); + qDebug(QString("handleDropEvent id=%1").arg(cardId).toLatin1()); + player->client->moveCard(cardId, startZone->getName(), getName(), 0, 0); +} + +void ZoneViewZone::removeCard(int position) +{ + if (position >= cards->size()) + return; + + CardItem *card = cards->at(position); + cards->removeAt(position); + delete card; + reorganizeCards(); +} diff --git a/cockatrice/src/zoneviewzone.h b/cockatrice/src/zoneviewzone.h new file mode 100644 index 00000000..868f2d44 --- /dev/null +++ b/cockatrice/src/zoneviewzone.h @@ -0,0 +1,27 @@ +#ifndef ZONEVIEWERZONE_H +#define ZONEVIEWERZONE_H + +#include "playerzone.h" +#include "serverzonecard.h" + +class ZoneViewWidget; + +class ZoneViewZone : public PlayerZone { +private: + int numberCards; + void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint); + PlayerZone *origZone; +signals: + void removeZoneViewWidget(ZoneViewWidget *zv); +public: + ZoneViewZone(Player *_p, PlayerZone *_origZone, int _numberCards = 0, QGraphicsItem *parent = 0); + ~ZoneViewZone(); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void addCard(CardItem *card, bool reorganize = true, int x = 0, int y = -1); + void reorganizeCards(); + bool initializeCards(); + void removeCard(int position); +}; + +#endif diff --git a/servatrice/Doxyfile b/servatrice/Doxyfile new file mode 100755 index 00000000..6f10ab00 --- /dev/null +++ b/servatrice/Doxyfile @@ -0,0 +1,311 @@ +# Doxyfile 1.5.5-KDevelop + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = servertest +PROJECT_NUMBER = 0.1 +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = /home/brukie/ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = /home/brukie/servertest +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY \ + *.F90 \ + *.F \ + *.VHD \ + *.VHDL \ + *.C \ + *.H \ + *.tlh \ + *.diff \ + *.patch \ + *.moc \ + *.xpm \ + *.dox +RECURSIVE = yes +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NONE +TREEVIEW_WIDTH = 250 +FORMULA_FONTSIZE = 10 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = yes +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = servertest.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_FONTNAME = FreeSans +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/servatrice/copying b/servatrice/copying new file mode 100755 index 00000000..5b6e7c66 --- /dev/null +++ b/servatrice/copying @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/servatrice/servertest.pro b/servatrice/servertest.pro new file mode 100755 index 00000000..03aa811b --- /dev/null +++ b/servatrice/servertest.pro @@ -0,0 +1,32 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Fr Sep 5 18:02:29 2008 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . src +INCLUDEPATH += . src + +CONFIG += qt thread +QT += network +QT -= gui + +# Input +HEADERS += src/testserver.h src/testservergame.h src/testserversocket.h \ + src/playerzone.h \ + src/testcard.h \ + src/version.h \ + src/counter.h \ + src/testrandom.h \ + src/testservergamethread.h \ + src/returnmessage.h +SOURCES += src/main.cpp \ + src/testserver.cpp \ + src/testservergame.cpp \ + src/testserversocket.cpp \ + src/playerzone.cpp \ + src/testcard.cpp \ + src/counter.cpp \ + src/testrandom.cpp \ + src/testservergamethread.cpp \ + src/returnmessage.cpp diff --git a/servatrice/src/counter.cpp b/servatrice/src/counter.cpp new file mode 100644 index 00000000..ba1c1c43 --- /dev/null +++ b/servatrice/src/counter.cpp @@ -0,0 +1,21 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "counter.h" + diff --git a/servatrice/src/counter.h b/servatrice/src/counter.h new file mode 100644 index 00000000..a490f5dc --- /dev/null +++ b/servatrice/src/counter.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef COUNTER_H +#define COUNTER_H + +#include + +class Counter { +protected: + QString name; + int count; +public: + Counter(QString _name, int _count = 0) : name(_name), count(_count) { } + ~Counter() { } + int getCount() { return count; } + void setCount(int _count) { count = _count; } + QString getName() const { return name; } +}; + +#endif diff --git a/servatrice/src/main.cpp b/servatrice/src/main.cpp new file mode 100644 index 00000000..5a78ff90 --- /dev/null +++ b/servatrice/src/main.cpp @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#include +#include "testserver.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + TestServer server; + server.listen(QHostAddress::Any, 4747); + + return app.exec(); +} diff --git a/servatrice/src/playerzone.cpp b/servatrice/src/playerzone.cpp new file mode 100644 index 00000000..1d645a6c --- /dev/null +++ b/servatrice/src/playerzone.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "playerzone.h" + +PlayerZone::PlayerZone(QString _name, bool _has_coords, bool _is_public, bool _id_access) + : name(_name), has_coords(_has_coords), is_public(_is_public), id_access(_id_access) +{ +} + +PlayerZone::~PlayerZone() +{ + qDebug(QString("PlayerZone destructor: %1").arg(name).toLatin1()); + clear(); +} + +void PlayerZone::shuffle(TestRandom *rnd) +{ + QList temp; + for (int i = cards.size(); i; i--) + temp.append(cards.takeAt(rnd->getNumber(0, i - 1))); + cards = temp; +} + +TestCard *PlayerZone::getCard(int id, bool remove, int *position) +{ + if (hasIdAccess()) { + QListIterator CardIterator(cards); + int i = 0; + while (CardIterator.hasNext()) { + TestCard *tmp = CardIterator.next(); + if (tmp->getId() == id) { + if (remove) + cards.removeAt(i); + if (position) + *position = i; + return tmp; + } + i++; + } + return NULL; + } else { + if (id >= cards.size()) + return NULL; + TestCard *tmp = cards[id]; + if (remove) + cards.removeAt(id); + if (position) + *position = id; + return tmp; + } +} + +void PlayerZone::insertCard(TestCard *card, int x, int y) +{ + if (hasCoords()) { + card->setCoords(x, y); + cards.append(card); + } else { + card->setCoords(0, 0); + cards.insert(x, card); + } +} + +void PlayerZone::clear() +{ + for (int i = 0; i < cards.size(); i++) + delete cards.at(i); + cards.clear(); +} diff --git a/servatrice/src/playerzone.h b/servatrice/src/playerzone.h new file mode 100644 index 00000000..5d6bb45c --- /dev/null +++ b/servatrice/src/playerzone.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PLAYERZONE_H +#define PLAYERZONE_H + +#include +#include "testcard.h" +#include "testrandom.h" + +class PlayerZone { +private: + QString name; + bool has_coords; + bool is_public; // Contents of the zone are visible for anyone + bool id_access; // getCard() finds by id, not by list index + // Example: When moving a card from the library to the table, + // the card has to be found by list index because the client + // does not know the id. But when moving a card from the hand + // to the table, the card can be found by id because the client + // knows the id and the hand does not need to have a specific order. +public: + PlayerZone(QString _name, bool _has_coords, bool _is_public, bool _id_access); + ~PlayerZone(); + + TestCard *getCard(int id, bool remove, int *position = NULL); + + bool isPublic() { return is_public; } + bool hasCoords() { return has_coords; } + bool hasIdAccess() { return id_access; } + QString getName() { return name; } + + QList cards; + void insertCard(TestCard *card, int x, int y); + void shuffle(TestRandom *rnd); + void clear(); +}; + +#endif diff --git a/servatrice/src/returnmessage.cpp b/servatrice/src/returnmessage.cpp new file mode 100644 index 00000000..dee88e1f --- /dev/null +++ b/servatrice/src/returnmessage.cpp @@ -0,0 +1,33 @@ +#include "returnmessage.h" +#include "testserversocket.h" + +void ReturnMessage::setMsgId(unsigned int _msg_id) +{ + msg_id = _msg_id; +} + +bool ReturnMessage::send(const QString &args, bool success) +{ + TestServerSocket *s = qobject_cast(parent()); + if (!s) + return false; + s->msg(QString("resp|%1|%2|%3").arg(msg_id) + .arg(success ? "ok" : "err") + .arg(args)); + return success; +} + +bool ReturnMessage::sendList(const QStringList &args) +{ + TestServerSocket *s = qobject_cast(parent()); + if (!s) + return false; + + for (int i = 0; i < args.size(); i++) + s->msg(QString("%1|%2|%3").arg(cmd) + .arg(msg_id) + .arg(args[i])); + s->msg(QString("%1|%2|.").arg(cmd).arg(msg_id)); + + return true; +} diff --git a/servatrice/src/returnmessage.h b/servatrice/src/returnmessage.h new file mode 100644 index 00000000..95714d16 --- /dev/null +++ b/servatrice/src/returnmessage.h @@ -0,0 +1,21 @@ +#ifndef RETURNMESSAGE_H +#define RETURNMESSAGE_H + +#include +#include + +class ReturnMessage : public QObject { + Q_OBJECT +private: + unsigned int msg_id; + QString cmd; +public: + ReturnMessage(QObject *parent = 0) : QObject(parent), msg_id(0) { } + unsigned int getMsgId() const { return msg_id; } + void setMsgId(unsigned int _msg_id); + void setCmd(const QString &_cmd) { cmd = _cmd; } + bool send(const QString &args = QString(), bool success = true); + bool sendList(const QStringList &args); +}; + +#endif diff --git a/servatrice/src/testcard.cpp b/servatrice/src/testcard.cpp new file mode 100644 index 00000000..17424126 --- /dev/null +++ b/servatrice/src/testcard.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "testcard.h" + +TestCard::TestCard(QString _name, int _id, int _coord_x, int _coord_y) + : id(_id), coord_x(_coord_x), coord_y(_coord_y), name(_name), counters(0), tapped(false), attacking(false) +{ +} + + +TestCard::~TestCard() +{ +} + +void TestCard::resetState() +{ + setCoords(0, 0); + setCounters(0); + setTapped(false); + setAttacking(false); + setFaceDown(false); + setAnnotation(""); +} + +bool TestCard::setAttribute(const QString &aname, const QString &avalue) +{ + if (!aname.compare("counters")) { + bool ok; + int tmp_int = avalue.toInt(&ok); + if (!ok) + return false; + setCounters(tmp_int); + } else if (!aname.compare("tapped")) { + setTapped(!avalue.compare("1")); + } else if (!aname.compare("attacking")) { + setAttacking(!avalue.compare("1")); + } else if (!aname.compare("facedown")) { + setFaceDown(!avalue.compare("1")); + } else if (!aname.compare("annotation")) { + setAnnotation(avalue); + } else + return false; + + return true; +} diff --git a/servatrice/src/testcard.h b/servatrice/src/testcard.h new file mode 100644 index 00000000..23b45976 --- /dev/null +++ b/servatrice/src/testcard.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef TESTCARD_H +#define TESTCARD_H + +#include +/** + @author Max-Wilhelm Bruker +*/ +class TestCard { +private: + int id; + int coord_x, coord_y; + QString name; + int counters; + bool tapped; + bool attacking; + bool facedown; + QString annotation; +public: + TestCard(QString _name, int _id, int _coord_x, int _coord_y); + ~TestCard(); + + int getId() { return id; } + int getX() { return coord_x; } + int getY() { return coord_y; } + QString getName() { return name; } + int getCounters() { return counters; } + bool getTapped() { return tapped; } + bool getAttacking() { return attacking; } + bool getFaceDown() { return facedown; } + QString getAnnotation() { return annotation; } + + void setCoords(int x, int y) { coord_x = x; coord_y = y; } + void setName(const QString &_name) { name = _name; } + void setCounters(int _counters) { counters = _counters; } + void setTapped(bool _tapped) { tapped = _tapped; } + void setAttacking(bool _attacking) { attacking = _attacking; } + void setFaceDown(bool _facedown) { facedown = _facedown; } + void setAnnotation(const QString &_annotation) { annotation = _annotation; } + + void resetState(); + bool setAttribute(const QString &aname, const QString &avalue); +}; + +#endif diff --git a/servatrice/src/testrandom.cpp b/servatrice/src/testrandom.cpp new file mode 100644 index 00000000..8590154d --- /dev/null +++ b/servatrice/src/testrandom.cpp @@ -0,0 +1,18 @@ +#include "testrandom.h" +#include + +void TestRandom::init() +{ + if (initialized) + return; + int seed = QDateTime::currentDateTime().toTime_t(); + qDebug(QString("%1: qsrand(%2)").arg(thread()->metaObject()->className()).arg(seed).toLatin1()); + qsrand(seed); + initialized = true; +} + +unsigned int TestRandom::getNumber(unsigned int min, unsigned int max) +{ + int r = qrand(); + return min + (unsigned int) (((double) (max + 1 - min)) * r / (RAND_MAX + 1.0)); +} diff --git a/servatrice/src/testrandom.h b/servatrice/src/testrandom.h new file mode 100644 index 00000000..6ae998ba --- /dev/null +++ b/servatrice/src/testrandom.h @@ -0,0 +1,18 @@ +#ifndef TESTRANDOM_H +#define TESTRANDOM_H + +#include +#include +#include + +class TestRandom : public QObject { + Q_OBJECT +private: + bool initialized; +public: + TestRandom(QObject *parent) : QObject(parent), initialized(false) { } + void init(); + unsigned int getNumber(unsigned int min, unsigned int max); +}; + +#endif diff --git a/servatrice/src/testserver.cpp b/servatrice/src/testserver.cpp new file mode 100644 index 00000000..d590100a --- /dev/null +++ b/servatrice/src/testserver.cpp @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "testserver.h" + +TestServer::TestServer(QObject *parent) + : QTcpServer(parent) +{ +} + +TestServer::~TestServer() +{ +} + +void TestServer::gameCreated(TestServerGame *_game, TestServerSocket *_creator) +{ + games << _game; + _creator->moveToThread(_game->thread()); + _game->addPlayer(_creator); +} + +void TestServer::addGame(const QString name, const QString description, const QString password, const int maxPlayers, TestServerSocket *creator) +{ + TestServerGameThread *newThread = new TestServerGameThread(name, description, password, maxPlayers, creator); + connect(newThread, SIGNAL(gameCreated(TestServerGame *, TestServerSocket *)), this, SLOT(gameCreated(TestServerGame *, TestServerSocket *))); + connect(newThread, SIGNAL(finished()), this, SLOT(gameClosed())); + newThread->start(); +} + +void TestServer::incomingConnection(int socketId) +{ + TestServerSocket *socket = new TestServerSocket(this); + socket->setSocketDescriptor(socketId); + connect(socket, SIGNAL(createGame(const QString, const QString, const QString, const int, TestServerSocket *)), this, SLOT(addGame(const QString, const QString, const QString, const int, TestServerSocket *))); + connect(socket, SIGNAL(joinGame(const QString, TestServerSocket *)), this, SLOT(addClientToGame(const QString, TestServerSocket *))); + socket->initConnection(); +} + +TestServerGame *TestServer::getGame(const QString &name) +{ + QListIterator i(games); + while (i.hasNext()) { + TestServerGame *tmp = i.next(); + if ((!tmp->name.compare(name, Qt::CaseSensitive)) && !tmp->getGameStarted()) + return tmp; + } + return NULL; +} + +QList TestServer::listOpenGames() +{ + QList result; + QListIterator i(games); + while (i.hasNext()) { + TestServerGame *tmp = i.next(); + tmp->mutex->lock(); + if ((!tmp->getGameStarted()) + && (tmp->getPlayerCount() < tmp->maxPlayers)) + result.append(tmp); + tmp->mutex->unlock(); + } + return result; +} + +bool TestServer::checkGamePassword(const QString &name, const QString &password) +{ + TestServerGame *tmp; + if ((tmp = getGame(name))) { + QMutexLocker locker(tmp->mutex); + if ((!tmp->getGameStarted()) + && (!tmp->password.compare(password, Qt::CaseSensitive)) + && (tmp->getPlayerCount() < tmp->maxPlayers)) + return true; + } + return false; +} + +void TestServer::addClientToGame(const QString name, TestServerSocket *client) +{ + TestServerGame *tmp = getGame(name); + client->moveToThread(tmp->thread()); + tmp->addPlayer(client); +} + +void TestServer::gameClosed() +{ + qDebug("TestServer::gameClosed"); + TestServerGameThread *t = qobject_cast(sender()); + games.removeAt(games.indexOf(t->getGame())); + delete t; +} diff --git a/servatrice/src/testserver.h b/servatrice/src/testserver.h new file mode 100644 index 00000000..1fbe38fd --- /dev/null +++ b/servatrice/src/testserver.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef TESTSERVER_H +#define TESTSERVER_H + +#include +#include "testservergamethread.h" +#include "testservergame.h" + +class TestServerGame; +class TestServerSocket; + +class TestServer : public QTcpServer +{ + Q_OBJECT +private slots: + void addGame(const QString name, const QString description, const QString password, const int maxPlayers, TestServerSocket *creator); + void addClientToGame(const QString name, TestServerSocket *client); + void gameCreated(TestServerGame *_game, TestServerSocket *_creator); + void gameClosed(); +public: + TestServer(QObject *parent = 0); + ~TestServer(); + bool checkGamePassword(const QString &name, const QString &password); + QList listOpenGames(); + TestServerGame *getGame(const QString &name); +private: + void incomingConnection(int SocketId); + QList games; +}; + +#endif diff --git a/servatrice/src/testservergame.cpp b/servatrice/src/testservergame.cpp new file mode 100644 index 00000000..9d3e375e --- /dev/null +++ b/servatrice/src/testservergame.cpp @@ -0,0 +1,155 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "testservergame.h" + +TestServerGame::TestServerGame(QString _name, QString _description, QString _password, int _maxPlayers, QObject *parent) + : QObject(parent), name(_name), description(_description), password(_password), maxPlayers(_maxPlayers) +{ + gameStarted = false; + mutex = new QMutex(QMutex::Recursive); + rnd = NULL; +} + +TestServerGame::~TestServerGame() +{ + if (rnd) + delete rnd; + delete mutex; + qDebug("TestServerGame destructor"); +} + +bool TestServerGame::getGameStarted() +{ + return gameStarted; +} + +int TestServerGame::getPlayerCount() +{ + QMutexLocker locker(mutex); + return players.size(); +} + +QStringList TestServerGame::getPlayerNames() +{ + QMutexLocker locker(mutex); + + QStringList result; + QListIterator i(players); + while (i.hasNext()) { + TestServerSocket *tmp = i.next(); + result << QString("%1|%2").arg(tmp->getPlayerId()).arg(tmp->PlayerName); + } + return result; +} + +TestServerSocket *TestServerGame::getPlayer(int player_id) +{ + QListIterator i(players); + while (i.hasNext()) { + TestServerSocket *tmp = i.next(); + if (tmp->getPlayerId() == player_id) + return tmp; + } + return NULL; +} + +void TestServerGame::msg(const QString &s) +{ + QMutexLocker locker(mutex); + + QListIterator i(players); + while (i.hasNext()) + i.next()->msg(s); +} + +void TestServerGame::broadcastEvent(const QString &cmd, TestServerSocket *player) +{ + if (player) + msg(QString("public|%1|%2|%3").arg(player->getPlayerId()).arg(player->PlayerName).arg(cmd)); + else + msg(QString("public|||%1").arg(cmd)); +} + +void TestServerGame::startGameIfReady() +{ + QMutexLocker locker(mutex); + + if (players.size() < maxPlayers) + return; + for (int i = 0; i < players.size(); i++) + if (players.at(i)->getStatus() != StatusReadyStart) + return; + + rnd = new TestRandom(this); + rnd->init(); + + for (int i = 0; i < players.size(); i++) + players.at(i)->setupZones(); + + activePlayer = 0; + activePhase = 0; + gameStarted = true; + broadcastEvent("game_start", NULL); +} + +void TestServerGame::addPlayer(TestServerSocket *player) +{ + QMutexLocker locker(mutex); + + int max = -1; + QListIterator i(players); + while (i.hasNext()) { + int tmp = i.next()->getPlayerId(); + if (tmp > max) + max = tmp; + } + player->setPlayerId(max + 1); + + player->setGame(this); + player->msg(QString("private|||player_id|%1|%2").arg(max + 1).arg(player->PlayerName)); + broadcastEvent("join", player); + + players << player; + + connect(player, SIGNAL(broadcastEvent(const QString &, TestServerSocket *)), this, SLOT(broadcastEvent(const QString &, TestServerSocket *))); +} + +void TestServerGame::removePlayer(TestServerSocket *player) +{ + QMutexLocker locker(mutex); + + players.removeAt(players.indexOf(player)); + broadcastEvent("leave", player); + if (!players.size()) + thread()->quit(); +} + +void TestServerGame::setActivePlayer(int _activePlayer) +{ + activePlayer = _activePlayer; + broadcastEvent(QString("set_active_player|%1").arg(_activePlayer), NULL); + setActivePhase(0); +} + +void TestServerGame::setActivePhase(int _activePhase) +{ + activePhase = _activePhase; + broadcastEvent(QString("set_active_phase|%1").arg(_activePhase), NULL); +} diff --git a/servatrice/src/testservergame.h b/servatrice/src/testservergame.h new file mode 100644 index 00000000..42a7e26e --- /dev/null +++ b/servatrice/src/testservergame.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef TESTSERVERGAME_H +#define TESTSERVERGAME_H + +#include +#include +#include +#include "testserversocket.h" +#include "testrandom.h" + +class TestServerSocket; + +class TestServerGame : public QObject { + Q_OBJECT +private: + QList players; + bool gameStarted; + int activePlayer; + int activePhase; +public slots: + void broadcastEvent(const QString &event, TestServerSocket *player); +public: + QMutex *mutex; + TestRandom *rnd; + QString name; + QString description; + QString password; + int maxPlayers; + TestServerGame(QString _name, QString _description, QString _password, int _maxPlayers, QObject *parent = 0); + ~TestServerGame(); + bool getGameStarted(); + int getPlayerCount(); + QStringList getPlayerNames(); + TestServerSocket *getPlayer(int player_id); + void addPlayer(TestServerSocket *player); + void removePlayer(TestServerSocket *player); + void startGameIfReady(); + void msg(const QString &s); + int getActivePlayer() { return activePlayer; } + int getActivePhase() { return activePhase; } + void setActivePlayer(int _activePlayer); + void setActivePhase(int _activePhase); + +}; + +#endif diff --git a/servatrice/src/testservergamethread.cpp b/servatrice/src/testservergamethread.cpp new file mode 100644 index 00000000..b0c1b218 --- /dev/null +++ b/servatrice/src/testservergamethread.cpp @@ -0,0 +1,20 @@ +#include "testservergamethread.h" + +TestServerGameThread::TestServerGameThread(const QString _name, const QString _description, const QString _password, const int _maxPlayers, TestServerSocket *_creator, QObject *parent) + : QThread(parent), name(_name), description(_description), password(_password), maxPlayers(_maxPlayers), creator(_creator), game(0) +{ + +} + +TestServerGameThread::~TestServerGameThread() +{ + if (game) + delete game; +} + +void TestServerGameThread::run() +{ + game = new TestServerGame(name, description, password, maxPlayers); + emit gameCreated(game, creator); + exec(); +} diff --git a/servatrice/src/testservergamethread.h b/servatrice/src/testservergamethread.h new file mode 100644 index 00000000..f1dbfe84 --- /dev/null +++ b/servatrice/src/testservergamethread.h @@ -0,0 +1,30 @@ +#ifndef TESTSERVERGAMETHREAD_H +#define TESTSERVERGAMETHREAD_H + +#include +#include +#include "testservergame.h" +#include "testserversocket.h" + +class TestServerGame; +class TestServerSocket; + +class TestServerGameThread : public QThread { + Q_OBJECT +signals: + void gameCreated(TestServerGame *_game, TestServerSocket *creator); +private: + QString name; + QString description; + QString password; + int maxPlayers; + TestServerSocket *creator; + TestServerGame *game; +public: + TestServerGameThread(const QString _name, const QString _description, const QString _password, const int _maxPlayers, TestServerSocket *_creator, QObject *parent = 0); + ~TestServerGameThread(); + TestServerGame *getGame() { return game; } + void run(); +}; + +#endif diff --git a/servatrice/src/testserversocket.cpp b/servatrice/src/testserversocket.cpp new file mode 100644 index 00000000..b517c9ee --- /dev/null +++ b/servatrice/src/testserversocket.cpp @@ -0,0 +1,595 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include "testserver.h" +#include "testserversocket.h" +#include "version.h" + +TestServerSocket::TestServerSocket(TestServer *_server, QObject *parent) + : QTcpSocket(parent), server(_server) +{ + remsg = new ReturnMessage(this); + connect(this, SIGNAL(readyRead()), this, SLOT(readClient())); + connect(this, SIGNAL(disconnected()), this, SLOT(deleteLater())); + connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(catchSocketError(QAbstractSocket::SocketError))); + setTextModeEnabled(true); + PlayerStatus = StatusNormal; + game = 0; +} + +TestServerSocket::~TestServerSocket() +{ + qDebug("TestServerSocket destructor"); + if (game) + game->removePlayer(this); +} + +void TestServerSocket::setName(const QString &name) +{ + emit broadcastEvent(QString("name|%1|%2").arg(PlayerName).arg(name), this); + PlayerName = name; +} + +PlayerZone *TestServerSocket::getZone(const QString &name) +{ + QListIterator ZoneIterator(zones); + while (ZoneIterator.hasNext()) { + PlayerZone *temp = ZoneIterator.next(); + if (!temp->getName().compare(name)) + return temp; + } + return NULL; +} + +Counter *TestServerSocket::getCounter(const QString &name) +{ + QListIterator CounterIterator(counters); + while (CounterIterator.hasNext()) { + Counter *temp = CounterIterator.next(); + if (!temp->getName().compare(name)) + return temp; + } + return NULL; +} + +void TestServerSocket::setupZones() +{ + // Delete existing zones and counters + clearZones(); + + // This may need to be customized according to the game rules. + // ------------------------------------------------------------------ + + // Create zones + PlayerZone *deck = new PlayerZone("deck", false, false, false); + zones << deck; + PlayerZone *sb = new PlayerZone("sb", false, false, false); + zones << sb; + zones << new PlayerZone("table", true, true, true); + zones << new PlayerZone("hand", false, false, true); + zones << new PlayerZone("grave", false, true, true); + zones << new PlayerZone("rfg", false, true, true); + + // Create life counter + Counter *life = new Counter("life", 20); + counters << life; + + // ------------------------------------------------------------------ + + // Assign card ids and create deck from decklist + QListIterator DeckIterator(DeckList); + int i = 0; + while (DeckIterator.hasNext()) + deck->cards.append(new TestCard(DeckIterator.next(), i++, 0, 0)); + deck->shuffle(game->rnd); + + QListIterator SBIterator(SideboardList); + while (SBIterator.hasNext()) + sb->cards.append(new TestCard(SBIterator.next(), i++, 0, 0)); + + nextCardId = i; + + PlayerStatus = StatusPlaying; + broadcastEvent(QString("setup_zones|%1|%2|%3").arg(getCounter("life")->getCount()) + .arg(deck->cards.size()) + .arg(getZone("sb")->cards.size()), this); +} + +void TestServerSocket::clearZones() +{ + for (int i = 0; i < zones.size(); i++) + delete zones.at(i); + zones.clear(); + + for (int i = 0; i < counters.size(); i++) + delete counters.at(i); + counters.clear(); +} + +void TestServerSocket::leaveGame() +{ + if (!game) + return; + game->removePlayer(this); + game = 0; + PlayerStatus = StatusNormal; + clearZones(); + moveToThread(server->thread()); +} + +void TestServerSocket::readClient() +{ + QTextStream *stream = new QTextStream(this); + stream->setCodec("UTF-8"); + QStringList lines; + + // Before parsing, everything has to be buffered so that the stream + // can be deleted in order to avoid problems when moving the object + // to another thread while this function is still running. + for (;;) { + QString line = stream->readLine(); + if (line.isNull()) + break; + lines << line; + } + delete stream; + + QStringListIterator i(lines); + while (i.hasNext()) { + QString line = i.next(); + + qDebug(QString("<<< %1").arg(line).toLatin1()); + switch (PlayerStatus) { + case StatusNormal: + case StatusReadyStart: + case StatusPlaying: + parseCommand(line); + break; + case StatusSubmitDeck: + QString card = line; + if (!card.compare(".")) { + PlayerStatus = StatusNormal; + remsg->send(); + } else if (card.startsWith("SB:")) + SideboardList << card.mid(3); + else + DeckList << card; + } + } +} + +bool TestServerSocket::parseCommand(QString line) +{ + QStringList params = line.split("|"); + + // Extract message id + bool conv_ok; + int msgId = params.takeFirst().toInt(&conv_ok); + if (!conv_ok) { + remsg->setMsgId(0); + return remsg->send("syntax", false); + } + remsg->setMsgId(msgId); + + if (params.empty()) { + remsg->setMsgId(0); + return remsg->send("syntax", false); + } + + // Extract command + QString cmd = params.takeFirst(); + remsg->setCmd(cmd); + + // parse command + + if (!cmd.compare("list_games", Qt::CaseInsensitive)) { + remsg->send(); + QList gameList = server->listOpenGames(); + QListIterator gameListIterator(gameList); + QStringList result; + while (gameListIterator.hasNext()) { + TestServerGame *tmp = gameListIterator.next(); + tmp->mutex->lock(); + result << QString("%1|%2|%3|%4|%5").arg(tmp->name) + .arg(tmp->description) + .arg(tmp->password == "" ? 0 : 1) + .arg(tmp->getPlayerCount()) + .arg(tmp->maxPlayers); + tmp->mutex->unlock(); + } + remsg->sendList(result); + } else if (!cmd.compare("create_game", Qt::CaseInsensitive)) { + if (params.size() != 4) + return remsg->send("syntax", false); + QString name = params[0]; + QString description = params[1]; + QString password = params[2]; + int maxPlayers = params[3].toInt(); + if (server->getGame(name)) + return remsg->send("name_not_found", false); + remsg->send(); + leaveGame(); + + emit createGame(name, description, password, maxPlayers, this); + } else if (!cmd.compare("join_game", Qt::CaseInsensitive)) { + if (params.size() != 2) + return remsg->send("syntax", false); + QString name = params[0]; + QString password = params[1]; + if (!server->checkGamePassword(name, password)) + return remsg->send("wrong_password", false); + remsg->send(); + leaveGame(); + + emit joinGame(name, this); + } else if (!cmd.compare("leave_game", Qt::CaseInsensitive)) { + remsg->send(); + leaveGame(); + } else if (!cmd.compare("set_name", Qt::CaseInsensitive)) { + if (params.size() != 1) + return remsg->send("syntax", false); + remsg->send(); + setName(params[0]); + } else if (!cmd.compare("list_players", Qt::CaseInsensitive)) { + if (!game) + return remsg->send("game_state", false); + + remsg->send(); + remsg->sendList(game->getPlayerNames()); + } else if (!cmd.compare("say", Qt::CaseInsensitive)) { + if (params.size() != 1) + return remsg->send("syntax", false); + remsg->send(); + emit broadcastEvent(QString("say|%1").arg(params[0]), this); + } else if (!cmd.compare("submit_deck", Qt::CaseInsensitive)) { + PlayerStatus = StatusSubmitDeck; + DeckList.clear(); + SideboardList.clear(); + } else if (!cmd.compare("shuffle", Qt::CaseInsensitive)) { + if (!game) + return remsg->send("game_state", false); + if (!game->getGameStarted()) + return remsg->send("game_state", false); + getZone("deck")->shuffle(game->rnd); + remsg->send(); + emit broadcastEvent("shuffle", this); + } else if (!cmd.compare("ready_start", Qt::CaseInsensitive)) { + if (!game) + return remsg->send("game_state", false); + remsg->send(); + PlayerStatus = StatusReadyStart; + emit broadcastEvent(QString("ready_start"), this); + game->startGameIfReady(); + } else if (!cmd.compare("draw_cards", Qt::CaseInsensitive)) { + if (params.size() != 1) + return remsg->send("syntax", false); + bool ok; + int number = params[0].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + PlayerZone *deck = getZone("deck"); + PlayerZone *hand = getZone("hand"); + + if (deck->cards.size() < number) + return remsg->send("game_state", false); + remsg->send(); + + for (int i = 0; i < number; ++i) { + TestCard *card = deck->cards.first(); + deck->cards.removeFirst(); + hand->cards.append(card); + msg(QString("private|||draw|%1|%2").arg(card->getId()).arg(card->getName())); + } + + emit broadcastEvent(QString("draw|%1").arg(number), this); + } else if (!cmd.compare("move_card", Qt::CaseInsensitive)) { + // ID Karte, Startzone, Zielzone, Koordinaten X, Y + if (params.size() != 5) + return remsg->send("syntax", false); + bool ok; + int cardid = params[0].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + PlayerZone *startzone = getZone(params[1]); + PlayerZone *targetzone = getZone(params[2]); + if ((!startzone) || (!targetzone)) + return remsg->send("game_state", false); + + int position = -1; + TestCard *card = startzone->getCard(cardid, true, &position); + if (!card) + return remsg->send("game_state", false); + int x = params[3].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + int y = 0; + if (targetzone->hasCoords()) { + y = params[4].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + } + targetzone->insertCard(card, x, y); + remsg->send(); + msg(QString("private|||move_card|%1|%2|%3|%4|%5|%6|%7").arg(card->getId()) + .arg(card->getName()) + .arg(startzone->getName()) + .arg(position) + .arg(targetzone->getName()) + .arg(x) + .arg(y)); + // Was ist mit Facedown-Karten? + if ((startzone->isPublic()) || (targetzone->isPublic())) + emit broadcastEvent(QString("move_card|%1|%2|%3|%4|%5|%6|%7").arg(card->getId()) + .arg(card->getName()) + .arg(startzone->getName()) + .arg(position) + .arg(targetzone->getName()) + .arg(x) + .arg(y), this); + else + emit broadcastEvent(QString("move_card|||%1|%2|%3|%4|%5").arg(startzone->getName()) + .arg(position) + .arg(targetzone->getName()) + .arg(x) + .arg(y), this); + } else if (!cmd.compare("create_token", Qt::CaseInsensitive)) { + // zone, cardname, powtough, x, y + // powtough wird erst mal ignoriert + if (params.size() != 5) + return remsg->send("syntax", false); + PlayerZone *zone = getZone(params[0]); + if (!zone) + return remsg->send("game_state", false); + QString cardname = params[1]; + int x = params[3].toInt(); + int y = params[4].toInt(); + int cardid = nextCardId++; + QString powtough = params[2]; + + remsg->send(); + TestCard *card = new TestCard(cardname, cardid, x, y); + zone->insertCard(card, x, y); + emit broadcastEvent(QString("create_token|%1|%2|%3|%4|%5|%6").arg(zone->getName()) + .arg(cardid) + .arg(cardname) + .arg(powtough) + .arg(x) + .arg(y), this); + } else if (!cmd.compare("set_card_attr", Qt::CaseInsensitive)) { + if (params.size() != 4) + return remsg->send("syntax", false); + // zone, card id, attr name, attr value + // card id = -1 => affects all cards in the specified zone + PlayerZone *zone = getZone(params[0]); + if (!zone) + return remsg->send("game_state", false); + bool ok; + int cardid = params[1].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + + if (cardid == -1) { + QListIterator CardIterator(zone->cards); + while (CardIterator.hasNext()) + if (!CardIterator.next()->setAttribute(params[2], params[3])) + return remsg->send("syntax", false); + } else { + TestCard *card = zone->getCard(cardid, false); + if (!card) + return remsg->send("game_state", false); + if (!card->setAttribute(params[2], params[3])) + return remsg->send("syntax", false); + } + remsg->send(); + emit broadcastEvent(QString("set_card_attr|%1|%2|%3|%4").arg(zone->getName()).arg(cardid).arg(params[2]).arg(params[3]), this); + } else if (!cmd.compare("inc_counter", Qt::CaseInsensitive)) { + if (params.size() != 2) + return remsg->send("syntax", false); + Counter *c = getCounter(params[0]); + if (!c) + return remsg->send("game_state", false); + bool ok; + int delta = params[1].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + remsg->send(); + c->setCount(c->getCount() + delta); + emit broadcastEvent(QString("set_counter|%1|%2").arg(params[0]).arg(c->getCount()), this); + } else if (!cmd.compare("set_counter", Qt::CaseInsensitive)) { + if (params.size() != 2) + return remsg->send("syntax", false); + Counter *c = getCounter(params[0]); + bool ok; + int count = params[1].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + if (!c) { + c = new Counter(params[0], count); + counters << c; + } else + c->setCount(count); + remsg->send(); + emit broadcastEvent(QString("set_counter|%1|%2").arg(params[0]).arg(count), this); + } else if (!cmd.compare("del_counter", Qt::CaseInsensitive)) { + if (params.size() != 1) + return remsg->send("syntax", false); + Counter *c = getCounter(params[0]); + if (!c) + return remsg->send("game_state", false); + delete c; + counters.removeAt(counters.indexOf(c)); + remsg->send(); + emit broadcastEvent(QString("del_counter|%1").arg(params[0]), this); + } else if (!cmd.compare("list_counters", Qt::CaseInsensitive)) { + if (params.size() != 1) + return remsg->send("syntax", false); + bool ok; + int player_id = params[0].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + TestServerSocket *player = game->getPlayer(player_id); + if (!player) + return remsg->send("game_state", false); + remsg->send(); + remsg->sendList(player->listCounters()); + } else if (!cmd.compare("list_zones", Qt::CaseInsensitive)) { + if (params.size() != 1) + return remsg->send("syntax", false); + bool ok; + int player_id = params[0].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + TestServerSocket *player = game->getPlayer(player_id); + if (!player) + return remsg->send("game_state", false); + remsg->send(); + remsg->sendList(player->listZones()); + } else if (!cmd.compare("dump_zone", Qt::CaseInsensitive)) { + if (params.size() != 3) + return remsg->send("syntax", false); + bool ok; + int player_id = params[0].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + int number_cards = params[2].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + TestServerSocket *player = game->getPlayer(player_id); + if (!player) + return remsg->send("game_state", false); + PlayerZone *zone = player->getZone(params[1]); + if (!zone) + return remsg->send("game_state", false); + if (!(zone->isPublic() || (player_id == PlayerId))) + return remsg->send("game_state", false); + remsg->send(); + QListIterator card_iterator(zone->cards); + QStringList result; + for (int i = 0; card_iterator.hasNext() && (i < number_cards || number_cards == 0); i++) { + TestCard *tmp = card_iterator.next(); + // XXX Face down cards + if (zone->hasIdAccess()) + result << QString("%1|%2|%3|%4|%5|%6|%7|%8").arg(tmp->getId()) + .arg(tmp->getName()) + .arg(tmp->getX()) + .arg(tmp->getY()) + .arg(tmp->getCounters()) + .arg(tmp->getTapped()) + .arg(tmp->getAttacking()) + .arg(tmp->getAnnotation()); + else + result << QString("%1|%2||||||").arg(i).arg(tmp->getName()); + } + remsg->sendList(result); + emit broadcastEvent(QString("dump_zone|%1|%2|%3").arg(player_id).arg(zone->getName()).arg(number_cards), this); + } else if (!cmd.compare("roll_dice", Qt::CaseInsensitive)) { + if (params.size() != 1) + return remsg->send("syntax", false); + bool ok; + int sides = params[0].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + remsg->send(); + emit broadcastEvent(QString("roll_dice|%1|%2").arg(sides).arg(game->rnd->getNumber(1, sides)), this); + } else if (!cmd.compare("set_active_player", Qt::CaseInsensitive)) { + if (params.size() != 1) + return remsg->send("syntax", false); + bool ok; + int active_player = params[0].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + if (!game->getPlayer(active_player)) + return remsg->send("game_state", false); + remsg->send(); + game->setActivePlayer(active_player); + } else if (!cmd.compare("set_active_phase", Qt::CaseInsensitive)) { + if (params.size() != 1) + return remsg->send("syntax", false); + bool ok; + int active_phase = params[0].toInt(&ok); + if (!ok) + return remsg->send("syntax", false); + // XXX Überprüfung, ob die Phase existiert... + remsg->send(); + game->setActivePhase(active_phase); + } else + return remsg->send("syntax", false); + return true; +} + +PlayerStatusEnum TestServerSocket::getStatus() +{ + return PlayerStatus; +} + +void TestServerSocket::setStatus(PlayerStatusEnum status) +{ + PlayerStatus = status; +} + +void TestServerSocket::setGame(TestServerGame *g) +{ + game = g; +} + +QStringList TestServerSocket::listCounters() +{ + QStringList counter_list; + QListIterator i(counters); + while (i.hasNext()) { + Counter *tmp = i.next(); + counter_list << QString("%1|%2").arg(tmp->getName()).arg(tmp->getCount()); + } + return counter_list; +} + +QStringList TestServerSocket::listZones() +{ + QStringList zone_list; + QListIterator i(zones); + while (i.hasNext()) { + PlayerZone *tmp = i.next(); + zone_list << QString("%1|%2|%3|%4").arg(tmp->getName()).arg(tmp->isPublic()).arg(tmp->hasCoords()).arg(tmp->cards.size()); + } + return zone_list; +} + +void TestServerSocket::msg(const QString &s) +{ + qDebug(QString(">>> %1").arg(s).toLatin1()); + QTextStream stream(this); + stream.setCodec("UTF-8"); + stream << s << endl; + stream.flush(); + flush(); +} + +void TestServerSocket::initConnection() +{ + msg(QString("welcome||%1").arg(VERSION_STRING)); + msg("welcome||."); +} + +void TestServerSocket::catchSocketError(QAbstractSocket::SocketError socketError) +{ + qDebug(QString("socket error: %1").arg(socketError).toLatin1()); + deleteLater(); +} diff --git a/servatrice/src/testserversocket.h b/servatrice/src/testserversocket.h new file mode 100644 index 00000000..39e273dd --- /dev/null +++ b/servatrice/src/testserversocket.h @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef TESTSERVERSOCKET_H +#define TESTSERVERSOCKET_H + +#include +#include "testserver.h" +#include "testservergame.h" +#include "playerzone.h" +#include "returnmessage.h" +#include "counter.h" + +class TestServer; +class TestServerGame; +class PlayerZone; + +enum PlayerStatusEnum { StatusNormal, StatusSubmitDeck, StatusReadyStart, StatusPlaying }; + +class TestServerSocket : public QTcpSocket +{ + Q_OBJECT +private slots: + void readClient(); + void catchSocketError(QAbstractSocket::SocketError socketError); +signals: + void createGame(const QString name, const QString description, const QString password, const int maxPlayers, TestServerSocket *creator); + void joinGame(const QString name, TestServerSocket *player); + void commandReceived(QString cmd, TestServerSocket *player); + void broadcastEvent(const QString &event, TestServerSocket *player); + void startGameIfReady(); +private: + TestServer *server; + TestServerGame *game; + QList DeckList; + QList SideboardList; + QList zones; + QList counters; + int PlayerId; + int nextCardId; + PlayerZone *getZone(const QString &name); + Counter *getCounter(const QString &name); + void setName(const QString &name); + void clearZones(); + void leaveGame(); + bool parseCommand(QString line); + PlayerStatusEnum PlayerStatus; + ReturnMessage *remsg; +public: + QString PlayerName; + TestServerSocket(TestServer *_server, QObject *parent = 0); + ~TestServerSocket(); + void msg(const QString &s); + void setGame(TestServerGame *g); + PlayerStatusEnum getStatus(); + void setStatus(PlayerStatusEnum status); + void initConnection(); + int getPlayerId() { return PlayerId; } + void setPlayerId(int _id) { PlayerId = _id; } + QStringList listCounters(); + QStringList listZones(); + void setupZones(); +}; + +#endif diff --git a/servatrice/src/version.h b/servatrice/src/version.h new file mode 100644 index 00000000..c2be944e --- /dev/null +++ b/servatrice/src/version.h @@ -0,0 +1,21 @@ +/*************************************************************************** + * Copyright (C) 2008 by Max-Wilhelm Bruker * + * brukie@laptop * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +const char *VERSION_STRING = "Testserver 0.20090304";