diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c1063ba..c8756e90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,15 +50,21 @@ elseif(WIN32) endif() # Define proper compilation flags -IF (CMAKE_COMPILER_IS_GNUCC) +IF(MSVC) + # Visual Studio: + # Maximum optimization + set(CMAKE_CXX_FLAGS_RELEASE "/Ox") + # Generate complete debugging information + #set(CMAKE_CXX_FLAGS_DEBUG "/Zi") +ELSEIF (CMAKE_COMPILER_IS_GNUCXX) # linux/gcc, bsd/gcc, windows/mingw set(CMAKE_CXX_FLAGS_RELEASE "-s -O2") set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0") -else() +ELSE() # other: osx/llvm, bsd/llvm set(CMAKE_CXX_FLAGS_RELEASE "-O2") set(CMAKE_CXX_FLAGS_DEBUG "-g -O0") -ENDIF (CMAKE_COMPILER_IS_GNUCC) +ENDIF() # GNU systems need to define the Mersenne exponent for the RNG to compile w/o warning IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 1d915bdb..499836dd 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -154,8 +154,11 @@ INCLUDE_DIRECTORIES(${QT_MOBILITY_MULTIMEDIAKIT_INCLUDE_DIR}) # Build cockatrice binary and link it ADD_EXECUTABLE(cockatrice WIN32 MACOSX_BUNDLE ${cockatrice_SOURCES} ${cockatrice_QM} ${cockatrice_RESOURCES_RCC} ${cockatrice_MOC_SRCS}) -TARGET_LINK_LIBRARIES(cockatrice cockatrice_common ${QT_LIBRARIES} ${QT_MOBILITY_MULTIMEDIAKIT_LIBRARY}) +TARGET_LINK_LIBRARIES(cockatrice cockatrice_common ${QT_QTMAIN_LIBRARY} ${QT_LIBRARIES} ${QT_MOBILITY_MULTIMEDIAKIT_LIBRARY}) +if(MSVC) + set_target_properties(cockatrice PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS") +endif(MSVC) if(UNIX) if(APPLE) diff --git a/cockatrice/src/abstractcarditem.cpp b/cockatrice/src/abstractcarditem.cpp index 7b624572..018cc5e0 100644 --- a/cockatrice/src/abstractcarditem.cpp +++ b/cockatrice/src/abstractcarditem.cpp @@ -2,7 +2,10 @@ #include #include #include -#include +#include +#ifdef _WIN32 +#include "round.h" +#endif /* _WIN32 */ #include "carddatabase.h" #include "cardinfowidget.h" #include "abstractcarditem.h" @@ -143,7 +146,7 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS painter->restore(); } -void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { painter->save(); diff --git a/cockatrice/src/arrowitem.cpp b/cockatrice/src/arrowitem.cpp index a27b451a..969be2b4 100644 --- a/cockatrice/src/arrowitem.cpp +++ b/cockatrice/src/arrowitem.cpp @@ -1,9 +1,11 @@ +#define _USE_MATH_DEFINES +#include + #include "arrowitem.h" #include "playertarget.h" #include "carditem.h" #include "cardzone.h" #include "player.h" -#include "math.h" #include #include #include @@ -64,7 +66,7 @@ void ArrowItem::updatePath(const QPointF &endPoint) { const double arrowWidth = 15.0; const double headWidth = 40.0; - const double headLength = headWidth / sqrt(2); + const double headLength = headWidth / pow(2, 0.5); // aka headWidth / sqrt (2) but this produces a compile error with MSVC++ const double phi = 15; if (!startItem) diff --git a/cockatrice/src/cardzone.cpp b/cockatrice/src/cardzone.cpp index f09cac1f..dc26263b 100644 --- a/cockatrice/src/cardzone.cpp +++ b/cockatrice/src/cardzone.cpp @@ -148,7 +148,7 @@ QString CardZone::getTranslatedName(bool hisOwn, GrammaticalCase gc) const return QString(); } -void CardZone::mouseDoubleClickEvent(QGraphicsSceneMouseEvent */*event*/) +void CardZone::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * /*event*/) { if (doubleClickAction) doubleClickAction->trigger(); diff --git a/cockatrice/src/counter_general.cpp b/cockatrice/src/counter_general.cpp index edc44519..e282f1bd 100644 --- a/cockatrice/src/counter_general.cpp +++ b/cockatrice/src/counter_general.cpp @@ -13,7 +13,7 @@ QRectF GeneralCounter::boundingRect() const return QRectF(0, 0, radius * 2, radius * 2); } -void GeneralCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +void GeneralCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { QRectF mapRect = painter->combinedTransform().mapRect(boundingRect()); int translatedHeight = mapRect.size().height(); diff --git a/cockatrice/src/decklistmodel.h b/cockatrice/src/decklistmodel.h index e2a85c56..27376c7a 100644 --- a/cockatrice/src/decklistmodel.h +++ b/cockatrice/src/decklistmodel.h @@ -19,7 +19,7 @@ public: int getNumber() const { return dataNode->getNumber(); } void setNumber(int _number) { dataNode->setNumber(_number); } float getPrice() const { return dataNode->getPrice(); } - void setPrice(float _price) { dataNode->setPrice(_price); } + void setPrice(const float _price) { dataNode->setPrice(_price); } QString getName() const { return dataNode->getName(); } void setName(const QString &_name) { dataNode->setName(_name); } DecklistCardNode *getDataNode() const { return dataNode; } diff --git a/cockatrice/src/filtertree.cpp b/cockatrice/src/filtertree.cpp index 4c28028b..5fc516f3 100644 --- a/cockatrice/src/filtertree.cpp +++ b/cockatrice/src/filtertree.cpp @@ -266,7 +266,7 @@ FilterItemList *FilterTree::attrTypeList(CardFilter::Attr attr, int FilterTree::findTermIndex(CardFilter::Attr attr, CardFilter::Type type, const QString &term) { - attrTypeList(attr, type)->termIndex(term); + return attrTypeList(attr, type)->termIndex(term); } int FilterTree::findTermIndex(const CardFilter *f) diff --git a/cockatrice/src/gamesmodel.cpp b/cockatrice/src/gamesmodel.cpp index 0ee41f35..9dd7185d 100644 --- a/cockatrice/src/gamesmodel.cpp +++ b/cockatrice/src/gamesmodel.cpp @@ -180,9 +180,9 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &/*sourc if (!gameTypeFilter.isEmpty() && gameTypes.intersect(gameTypeFilter).isEmpty()) return false; - if ((maxPlayersFilterMin != -1) && (game.max_players() < maxPlayersFilterMin)) + if ((maxPlayersFilterMin != -1) && ((int)game.max_players() < maxPlayersFilterMin)) return false; - if ((maxPlayersFilterMax != -1) && (game.max_players() > maxPlayersFilterMax)) + if ((maxPlayersFilterMax != -1) && ((int)game.max_players() > maxPlayersFilterMax)) return false; return true; diff --git a/cockatrice/src/handzone.cpp b/cockatrice/src/handzone.cpp index 1799b65f..cd9ba959 100644 --- a/cockatrice/src/handzone.cpp +++ b/cockatrice/src/handzone.cpp @@ -75,7 +75,7 @@ QRectF HandZone::boundingRect() const return QRectF(0, 0, 100, zoneHeight); } -void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { if (bgPixmap.isNull()) painter->fillRect(boundingRect(), Qt::darkGreen); diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp index 595a6534..ef57655a 100644 --- a/cockatrice/src/main.cpp +++ b/cockatrice/src/main.cpp @@ -19,6 +19,8 @@ ***************************************************************************/ #include +#include +#include #include #include #include @@ -28,7 +30,6 @@ #include #include #include -#include #include "main.h" #include "window_main.h" @@ -56,11 +57,11 @@ QString translationPath = QString(); 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); + QFile file("qdebug.txt"); + file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text); + QTextStream out(&file); + out << msg << endl; + file.close(); } void installNewTranslator() diff --git a/cockatrice/src/phasestoolbar.cpp b/cockatrice/src/phasestoolbar.cpp index 98f27404..b34872f6 100644 --- a/cockatrice/src/phasestoolbar.cpp +++ b/cockatrice/src/phasestoolbar.cpp @@ -3,7 +3,10 @@ #include #include #include -#include +#include +#ifdef _WIN32 +#include "round.h" +#endif /* _WIN32 */ #include "phasestoolbar.h" #include "pixmapgenerator.h" @@ -85,7 +88,7 @@ void PhaseButton::mousePressEvent(QGraphicsSceneMouseEvent * /*event*/) emit clicked(); } -void PhaseButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent */*event*/) +void PhaseButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * /*event*/) { triggerDoubleClickAction(); } diff --git a/cockatrice/src/pilezone.cpp b/cockatrice/src/pilezone.cpp index d34d4c06..0dbdd566 100644 --- a/cockatrice/src/pilezone.cpp +++ b/cockatrice/src/pilezone.cpp @@ -105,7 +105,7 @@ void PileZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event) setCursor(Qt::OpenHandCursor); } -void PileZone::mouseReleaseEvent(QGraphicsSceneMouseEvent */*event*/) +void PileZone::mouseReleaseEvent(QGraphicsSceneMouseEvent * /*event*/) { setCursor(Qt::OpenHandCursor); } diff --git a/cockatrice/src/pixmapgenerator.cpp b/cockatrice/src/pixmapgenerator.cpp index 7ff7ca98..8bae4853 100644 --- a/cockatrice/src/pixmapgenerator.cpp +++ b/cockatrice/src/pixmapgenerator.cpp @@ -2,7 +2,10 @@ #include "pb/serverinfo_user.pb.h" #include #include -#include +#include +#ifdef _WIN32 +#include "round.h" +#endif /* _WIN32 */ #include QMap PhasePixmapGenerator::pmCache; diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index 35d5bea9..762b4387 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -85,7 +85,7 @@ void PlayerArea::updateBgPixmap() update(); } -void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { painter->fillRect(bRect, bgPixmapBrush); } @@ -1430,7 +1430,7 @@ QRectF Player::boundingRect() const return bRect; } -void Player::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +void Player::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { } diff --git a/cockatrice/src/playertarget.cpp b/cockatrice/src/playertarget.cpp index eb18a332..98b266df 100644 --- a/cockatrice/src/playertarget.cpp +++ b/cockatrice/src/playertarget.cpp @@ -5,7 +5,10 @@ #include #include #include -#include +#include +#ifdef _WIN32 +#include "round.h" +#endif /* _WIN32 */ PlayerCounter::PlayerCounter(Player *_player, int _id, const QString &_name, int _value, QGraphicsItem *parent) : AbstractCounter(_player, _id, _name, false, _value, parent) @@ -87,7 +90,8 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o cachedPixmap = QPixmap(translatedSize.width(), translatedSize.height()); QPainter tempPainter(&cachedPixmap); - QRadialGradient grad(translatedRect.center(), sqrt(translatedSize.width() * translatedSize.width() + translatedSize.height() * translatedSize.height()) / 2); + // pow(foo, 0.5) equals to sqrt(foo), but using sqrt(foo) in this context will produce a compile error with MSVC++ + QRadialGradient grad(translatedRect.center(), pow(translatedSize.width() * translatedSize.width() + translatedSize.height() * translatedSize.height(), 0.5) / 2); grad.setColorAt(1, Qt::black); grad.setColorAt(0, QColor(180, 180, 180)); tempPainter.fillRect(QRectF(0, 0, translatedSize.width(), translatedSize.height()), grad); diff --git a/cockatrice/src/replay_timeline_widget.cpp b/cockatrice/src/replay_timeline_widget.cpp index 7934fb0e..6127489f 100644 --- a/cockatrice/src/replay_timeline_widget.cpp +++ b/cockatrice/src/replay_timeline_widget.cpp @@ -2,7 +2,10 @@ #include #include #include -#include +#include +#ifdef _WIN32 +#include "round.h" +#endif /* _WIN32 */ ReplayTimelineWidget::ReplayTimelineWidget(QWidget *parent) : QWidget(parent), maxBinValue(1), maxTime(1), timeScaleFactor(1.0), currentTime(0), currentEvent(0) diff --git a/cockatrice/src/round.h b/cockatrice/src/round.h new file mode 100644 index 00000000..225da636 --- /dev/null +++ b/cockatrice/src/round.h @@ -0,0 +1,12 @@ +#ifndef MSVC_ROUND_FIX +#define MSVC_ROUND_FIX +/** + * This helper function exists only because MS VC++ 2010 does not support round() in + * . round() works with g++ and clang++ but is formally a C++11 extension. + * So this file exists for MS VC++ only. + */ +inline double round(double val) { + return floor(val + 0.5); +} + +#endif /* MSVC_ROUND_FIX */ diff --git a/cockatrice/src/stackzone.cpp b/cockatrice/src/stackzone.cpp index f3e4767c..a60c4037 100644 --- a/cockatrice/src/stackzone.cpp +++ b/cockatrice/src/stackzone.cpp @@ -46,7 +46,7 @@ QRectF StackZone::boundingRect() const return QRectF(0, 0, 100, zoneHeight); } -void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { if (bgPixmap.isNull()) painter->fillRect(boundingRect(), QColor(113, 43, 43)); diff --git a/cockatrice/src/tab_userlists.cpp b/cockatrice/src/tab_userlists.cpp index 3ad1d96a..61fe693c 100644 --- a/cockatrice/src/tab_userlists.cpp +++ b/cockatrice/src/tab_userlists.cpp @@ -4,6 +4,8 @@ #include "abstractclient.h" #include #include +#include +#include #include "pending_command.h" #include "pb/session_commands.pb.h" @@ -21,34 +23,90 @@ TabUserLists::TabUserLists(TabSupervisor *_tabSupervisor, AbstractClient *_clien ignoreList = new UserList(_tabSupervisor, client, UserList::IgnoreList); userInfoBox = new UserInfoBox(client, false); userInfoBox->updateInfo(userInfo); - + connect(allUsersList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool))); connect(buddyList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool))); connect(ignoreList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool))); - + connect(client, SIGNAL(userJoinedEventReceived(const Event_UserJoined &)), this, SLOT(processUserJoinedEvent(const Event_UserJoined &))); connect(client, SIGNAL(userLeftEventReceived(const Event_UserLeft &)), this, SLOT(processUserLeftEvent(const Event_UserLeft &))); connect(client, SIGNAL(buddyListReceived(const QList &)), this, SLOT(buddyListReceived(const QList &))); connect(client, SIGNAL(ignoreListReceived(const QList &)), this, SLOT(ignoreListReceived(const QList &))); connect(client, SIGNAL(addToListEventReceived(const Event_AddToList &)), this, SLOT(processAddToListEvent(const Event_AddToList &))); connect(client, SIGNAL(removeFromListEventReceived(const Event_RemoveFromList &)), this, SLOT(processRemoveFromListEvent(const Event_RemoveFromList &))); - + PendingCommand *pend = client->prepareSessionCommand(Command_ListUsers()); connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(processListUsersResponse(const Response &))); client->sendCommand(pend); - + QVBoxLayout *vbox = new QVBoxLayout; vbox->addWidget(userInfoBox); vbox->addWidget(allUsersList); - + + QHBoxLayout *addToBuddyList = new QHBoxLayout; + addBuddyEdit = new QLineEdit; + addBuddyEdit->setPlaceholderText(tr("Add to Buddy List")); + connect(addBuddyEdit, SIGNAL(returnPressed()), this, SLOT(addToBuddyList())); + QPushButton *addBuddyButton = new QPushButton("Add"); + connect(addBuddyButton, SIGNAL(clicked()), this, SLOT(addToBuddyList())); + addToBuddyList->addWidget(addBuddyEdit); + addToBuddyList->addWidget(addBuddyButton); + + QHBoxLayout *addToIgnoreList = new QHBoxLayout; + addIgnoreEdit = new QLineEdit; + addIgnoreEdit->setPlaceholderText(tr("Add to Ignore List")); + connect(addIgnoreEdit, SIGNAL(returnPressed()), this, SLOT(addToIgnoreList())); + QPushButton *addIgnoreButton = new QPushButton("Add"); + connect(addIgnoreButton, SIGNAL(clicked()), this, SLOT(addToIgnoreList())); + addToIgnoreList->addWidget(addIgnoreEdit); + addToIgnoreList->addWidget(addIgnoreButton); + + QVBoxLayout *buddyPanel = new QVBoxLayout; + buddyPanel->addWidget(buddyList); + buddyPanel->addLayout(addToBuddyList); + + QVBoxLayout *ignorePanel = new QVBoxLayout; + ignorePanel->addWidget(ignoreList); + ignorePanel->addLayout(addToIgnoreList); + QHBoxLayout *mainLayout = new QHBoxLayout; - mainLayout->addWidget(buddyList); - mainLayout->addWidget(ignoreList); + mainLayout->addLayout(buddyPanel); + mainLayout->addLayout(ignorePanel); mainLayout->addLayout(vbox); - + setLayout(mainLayout); } +void TabUserLists::addToBuddyList() +{ + QString userName = addBuddyEdit->text(); + if (userName.length() < 1) return; + + std::string listName = "buddy"; + addToList(listName, userName); + addBuddyEdit->clear(); +} + +void TabUserLists::addToIgnoreList() +{ + QString userName = addIgnoreEdit->text(); + if (userName.length() < 1) return; + + std::string listName = "ignore"; + addToList(listName, userName); + addIgnoreEdit->clear(); +} + +void TabUserLists::addToList(const std::string &listName, const QString &userName) +{ + Command_AddToList cmd; + cmd.set_list(listName); + cmd.set_user_name(userName.toStdString()); + + client->sendCommand(client->prepareSessionCommand(cmd)); +} + + void TabUserLists::retranslateUi() { allUsersList->retranslateUi(); diff --git a/cockatrice/src/tab_userlists.h b/cockatrice/src/tab_userlists.h index 90e25604..7511c9ea 100644 --- a/cockatrice/src/tab_userlists.h +++ b/cockatrice/src/tab_userlists.h @@ -3,6 +3,7 @@ #include "tab.h" #include "pb/serverinfo_user.pb.h" +#include class AbstractClient; class UserList; @@ -30,12 +31,17 @@ private slots: void ignoreListReceived(const QList &_ignoreList); void processAddToListEvent(const Event_AddToList &event); void processRemoveFromListEvent(const Event_RemoveFromList &event); + void addToIgnoreList(); + void addToBuddyList(); private: AbstractClient *client; UserList *allUsersList; UserList *buddyList; UserList *ignoreList; UserInfoBox *userInfoBox; + QLineEdit *addBuddyEdit; + QLineEdit *addIgnoreEdit; + void addToList(const std::string &listName, const QString &userName); public: TabUserLists(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User &userInfo, QWidget *parent = 0); void retranslateUi(); diff --git a/cockatrice/src/tablezone.cpp b/cockatrice/src/tablezone.cpp index 49965929..d7fa4218 100644 --- a/cockatrice/src/tablezone.cpp +++ b/cockatrice/src/tablezone.cpp @@ -1,7 +1,10 @@ #include #include #include -#include +#include +#ifdef _WIN32 +#include "round.h" +#endif /* _WIN32 */ #include "tablezone.h" #include "player.h" #include "settingscache.h" @@ -46,7 +49,7 @@ bool TableZone::isInverted() const return ((player->getMirrored() && !settingsCache->getInvertVerticalCoordinate()) || (!player->getMirrored() && settingsCache->getInvertVerticalCoordinate())); } -void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { if (bgPixmap.isNull()) painter->fillRect(boundingRect(), QColor(0, 0, 100)); diff --git a/cockatrice/src/zoneviewzone.cpp b/cockatrice/src/zoneviewzone.cpp index c42dfd0e..e3b34235 100644 --- a/cockatrice/src/zoneviewzone.cpp +++ b/cockatrice/src/zoneviewzone.cpp @@ -31,7 +31,7 @@ QRectF ZoneViewZone::boundingRect() const return bRect; } -void ZoneViewZone::paint(QPainter */*painter*/, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +void ZoneViewZone::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { } diff --git a/common/decklist.h b/common/decklist.h index c5535c2d..2e8f4a9b 100644 --- a/common/decklist.h +++ b/common/decklist.h @@ -83,7 +83,7 @@ public: virtual QString getName() const = 0; virtual void setName(const QString &_name) = 0; virtual float getPrice() const = 0; - virtual void setPrice(float _price) = 0; + virtual void setPrice(const float _price) = 0; float getTotalPrice() const { return getNumber() * getPrice(); } int height() const { return 0; } bool compare(AbstractDecklistNode *other) const; diff --git a/common/server_cardzone.cpp b/common/server_cardzone.cpp index 4a9345b3..c6456f5f 100644 --- a/common/server_cardzone.cpp +++ b/common/server_cardzone.cpp @@ -26,7 +26,7 @@ #include "pb/command_move_card.pb.h" Server_CardZone::Server_CardZone(Server_Player *_player, const QString &_name, bool _has_coords, ServerInfo_Zone::ZoneType _type) - : player(_player), + : player(_player), name(_name), has_coords(_has_coords), type(_type), @@ -37,255 +37,257 @@ Server_CardZone::Server_CardZone(Server_Player *_player, const QString &_name, b Server_CardZone::~Server_CardZone() { - qDebug() << "Server_CardZone destructor:" << name; - clear(); + qDebug() << "Server_CardZone destructor:" << name; + clear(); } void Server_CardZone::shuffle() { - QList temp; - for (int i = cards.size(); i; i--) - temp.append(cards.takeAt(rng->rand(0, i - 1))); - cards = temp; - - playersWithWritePermission.clear(); + // Size 0 or 1 decks are sorted + if (cards.size() < 2) return; + for (int i = cards.size() - 1; i > 0; i--){ + int j = rng->rand(0, i); + cards.swap(j,i); + } + playersWithWritePermission.clear(); } + void Server_CardZone::removeCardFromCoordMap(Server_Card *card, int oldX, int oldY) { - if (oldX < 0) - return; - - const int baseX = (oldX / 3) * 3; - QMap &coordMap = coordinateMap[oldY]; - - if (coordMap.contains(baseX) && coordMap.contains(baseX + 1) && coordMap.contains(baseX + 2)) - // If the removal of this card has opened up a previously full pile... - freePilesMap[oldY].insert(coordMap.value(baseX)->getName(), baseX); - - coordMap.remove(oldX); - - if (!(coordMap.contains(baseX) && coordMap.value(baseX)->getName() == card->getName()) && !(coordMap.contains(baseX + 1) && coordMap.value(baseX + 1)->getName() == card->getName()) && !(coordMap.contains(baseX + 2) && coordMap.value(baseX + 2)->getName() == card->getName())) - // If this card was the last one with this name... - freePilesMap[oldY].remove(card->getName(), baseX); - - if (!coordMap.contains(baseX) && !coordMap.contains(baseX + 1) && !coordMap.contains(baseX + 2)) { - // If the removal of this card has freed a whole pile, i.e. it was the last card in it... - if (baseX < freeSpaceMap[oldY]) - freeSpaceMap[oldY] = baseX; - } + if (oldX < 0) + return; + + const int baseX = (oldX / 3) * 3; + QMap &coordMap = coordinateMap[oldY]; + + if (coordMap.contains(baseX) && coordMap.contains(baseX + 1) && coordMap.contains(baseX + 2)) + // If the removal of this card has opened up a previously full pile... + freePilesMap[oldY].insert(coordMap.value(baseX)->getName(), baseX); + + coordMap.remove(oldX); + + if (!(coordMap.contains(baseX) && coordMap.value(baseX)->getName() == card->getName()) && !(coordMap.contains(baseX + 1) && coordMap.value(baseX + 1)->getName() == card->getName()) && !(coordMap.contains(baseX + 2) && coordMap.value(baseX + 2)->getName() == card->getName())) + // If this card was the last one with this name... + freePilesMap[oldY].remove(card->getName(), baseX); + + if (!coordMap.contains(baseX) && !coordMap.contains(baseX + 1) && !coordMap.contains(baseX + 2)) { + // If the removal of this card has freed a whole pile, i.e. it was the last card in it... + if (baseX < freeSpaceMap[oldY]) + freeSpaceMap[oldY] = baseX; + } } void Server_CardZone::insertCardIntoCoordMap(Server_Card *card, int x, int y) { - if (x < 0) - return; - - coordinateMap[y].insert(x, card); - if (!(x % 3)) { - if (!freePilesMap[y].contains(card->getName(), x) && card->getAttachedCards().isEmpty()) - freePilesMap[y].insert(card->getName(), x); - if (freeSpaceMap[y] == x) { - int nextFreeX = x; - do { - nextFreeX += 3; - } while (coordinateMap[y].contains(nextFreeX) || coordinateMap[y].contains(nextFreeX + 1) || coordinateMap[y].contains(nextFreeX + 2)); - freeSpaceMap[y] = nextFreeX; - } - } else if (!((x - 2) % 3)) { - const int baseX = (x / 3) * 3; - freePilesMap[y].remove(coordinateMap[y].value(baseX)->getName(), baseX); - } + if (x < 0) + return; + + coordinateMap[y].insert(x, card); + if (!(x % 3)) { + if (!freePilesMap[y].contains(card->getName(), x) && card->getAttachedCards().isEmpty()) + freePilesMap[y].insert(card->getName(), x); + if (freeSpaceMap[y] == x) { + int nextFreeX = x; + do { + nextFreeX += 3; + } while (coordinateMap[y].contains(nextFreeX) || coordinateMap[y].contains(nextFreeX + 1) || coordinateMap[y].contains(nextFreeX + 2)); + freeSpaceMap[y] = nextFreeX; + } + } else if (!((x - 2) % 3)) { + const int baseX = (x / 3) * 3; + freePilesMap[y].remove(coordinateMap[y].value(baseX)->getName(), baseX); + } } int Server_CardZone::removeCard(Server_Card *card) { - int index = cards.indexOf(card); - cards.removeAt(index); - if (has_coords) - removeCardFromCoordMap(card, card->getX(), card->getY()); - card->setZone(0); - - return index; + int index = cards.indexOf(card); + cards.removeAt(index); + if (has_coords) + removeCardFromCoordMap(card, card->getX(), card->getY()); + card->setZone(0); + + return index; } Server_Card *Server_CardZone::getCard(int id, int *position, bool remove) { - if (type != ServerInfo_Zone::HiddenZone) { - for (int i = 0; i < cards.size(); ++i) { - Server_Card *tmp = cards[i]; - if (tmp->getId() == id) { - if (position) - *position = i; - if (remove) { - cards.removeAt(i); - tmp->setZone(0); - } - return tmp; - } - } - return NULL; - } else { - if ((id >= cards.size()) || (id < 0)) - return NULL; - Server_Card *tmp = cards[id]; - if (position) - *position = id; - if (remove) { - cards.removeAt(id); - tmp->setZone(0); - } - return tmp; - } + if (type != ServerInfo_Zone::HiddenZone) { + for (int i = 0; i < cards.size(); ++i) { + Server_Card *tmp = cards[i]; + if (tmp->getId() == id) { + if (position) + *position = i; + if (remove) { + cards.removeAt(i); + tmp->setZone(0); + } + return tmp; + } + } + return NULL; + } else { + if ((id >= cards.size()) || (id < 0)) + return NULL; + Server_Card *tmp = cards[id]; + if (position) + *position = id; + if (remove) { + cards.removeAt(id); + tmp->setZone(0); + } + return tmp; + } } int Server_CardZone::getFreeGridColumn(int x, int y, const QString &cardName) const { - const QMap &coordMap = coordinateMap.value(y); - if (x == -1) { - if (freePilesMap[y].contains(cardName)) { - x = (freePilesMap[y].value(cardName) / 3) * 3; - if (!coordMap.contains(x)) - return x; - else if (!coordMap.contains(x + 1)) - return x + 1; - else - return x + 2; - } - } else if (x >= 0) { - int resultX = 0; - x = (x / 3) * 3; - if (!coordMap.contains(x)) - resultX = x; - else if (!coordMap.value(x)->getAttachedCards().isEmpty()) { - resultX = x; - x = -1; - } else if (!coordMap.contains(x + 1)) - resultX = x + 1; - else if (!coordMap.contains(x + 2)) - resultX = x + 2; - else { - resultX = x; - x = -1; - } - if (x < 0) - while (coordMap.contains(resultX)) - resultX += 3; + const QMap &coordMap = coordinateMap.value(y); + if (x == -1) { + if (freePilesMap[y].contains(cardName)) { + x = (freePilesMap[y].value(cardName) / 3) * 3; + if (!coordMap.contains(x)) + return x; + else if (!coordMap.contains(x + 1)) + return x + 1; + else + return x + 2; + } + } else if (x >= 0) { + int resultX = 0; + x = (x / 3) * 3; + if (!coordMap.contains(x)) + resultX = x; + else if (!coordMap.value(x)->getAttachedCards().isEmpty()) { + resultX = x; + x = -1; + } else if (!coordMap.contains(x + 1)) + resultX = x + 1; + else if (!coordMap.contains(x + 2)) + resultX = x + 2; + else { + resultX = x; + x = -1; + } + if (x < 0) + while (coordMap.contains(resultX)) + resultX += 3; - return resultX; - } - - return freeSpaceMap[y]; + return resultX; + } + + return freeSpaceMap[y]; } bool Server_CardZone::isColumnStacked(int x, int y) const { - if (!has_coords) - return false; - - return coordinateMap[y].contains((x / 3) * 3 + 1); + if (!has_coords) + return false; + + return coordinateMap[y].contains((x / 3) * 3 + 1); } bool Server_CardZone::isColumnEmpty(int x, int y) const { - if (!has_coords) - return true; - - return !coordinateMap[y].contains((x / 3) * 3); + if (!has_coords) + return true; + + return !coordinateMap[y].contains((x / 3) * 3); } void Server_CardZone::moveCardInRow(GameEventStorage &ges, Server_Card *card, int x, int y) { - CardToMove *cardToMove = new CardToMove; - cardToMove->set_card_id(card->getId()); - player->moveCard(ges, this, QList() << cardToMove, this, x, y, false, false); - delete cardToMove; + CardToMove *cardToMove = new CardToMove; + cardToMove->set_card_id(card->getId()); + player->moveCard(ges, this, QList() << cardToMove, this, x, y, false, false); + delete cardToMove; } void Server_CardZone::fixFreeSpaces(GameEventStorage &ges) { - if (!has_coords) - return; - - QSet > placesToLook; - for (int i = 0; i < cards.size(); ++i) - placesToLook.insert(QPair((cards[i]->getX() / 3) * 3, cards[i]->getY())); - - QSetIterator > placeIterator(placesToLook); - while (placeIterator.hasNext()) { - const QPair &foo = placeIterator.next(); - int baseX = foo.first; - int y = foo.second; - - if (!coordinateMap[y].contains(baseX)) { - if (coordinateMap[y].contains(baseX + 1)) - moveCardInRow(ges, coordinateMap[y].value(baseX + 1), baseX, y); - else if (coordinateMap[y].contains(baseX + 2)) { - moveCardInRow(ges, coordinateMap[y].value(baseX + 2), baseX, y); - continue; - } else - continue; - } - if (!coordinateMap[y].contains(baseX + 1) && coordinateMap[y].contains(baseX + 2)) - moveCardInRow(ges, coordinateMap[y].value(baseX + 2), baseX + 1, y); - } + if (!has_coords) + return; + + QSet > placesToLook; + for (int i = 0; i < cards.size(); ++i) + placesToLook.insert(QPair((cards[i]->getX() / 3) * 3, cards[i]->getY())); + + QSetIterator > placeIterator(placesToLook); + while (placeIterator.hasNext()) { + const QPair &foo = placeIterator.next(); + int baseX = foo.first; + int y = foo.second; + + if (!coordinateMap[y].contains(baseX)) { + if (coordinateMap[y].contains(baseX + 1)) + moveCardInRow(ges, coordinateMap[y].value(baseX + 1), baseX, y); + else if (coordinateMap[y].contains(baseX + 2)) { + moveCardInRow(ges, coordinateMap[y].value(baseX + 2), baseX, y); + continue; + } else + continue; + } + if (!coordinateMap[y].contains(baseX + 1) && coordinateMap[y].contains(baseX + 2)) + moveCardInRow(ges, coordinateMap[y].value(baseX + 2), baseX + 1, y); + } } void Server_CardZone::updateCardCoordinates(Server_Card *card, int oldX, int oldY) { - if (!has_coords) - return; - - if (oldX != -1) - removeCardFromCoordMap(card, oldX, oldY); - insertCardIntoCoordMap(card, card->getX(), card->getY()); + if (!has_coords) + return; + + if (oldX != -1) + removeCardFromCoordMap(card, oldX, oldY); + insertCardIntoCoordMap(card, card->getX(), card->getY()); } void Server_CardZone::insertCard(Server_Card *card, int x, int y) { - if (hasCoords()) { - card->setCoords(x, y); - cards.append(card); - insertCardIntoCoordMap(card, x, y); - } else { - card->setCoords(0, 0); - if (x == -1) - cards.append(card); - else - cards.insert(x, card); - } - card->setZone(this); + if (hasCoords()) { + card->setCoords(x, y); + cards.append(card); + insertCardIntoCoordMap(card, x, y); + } else { + card->setCoords(0, 0); + if (x == -1) + cards.append(card); + else + cards.insert(x, card); + } + card->setZone(this); } void Server_CardZone::clear() { - for (int i = 0; i < cards.size(); i++) - delete cards.at(i); - cards.clear(); - coordinateMap.clear(); - freePilesMap.clear(); - freeSpaceMap.clear(); - playersWithWritePermission.clear(); + for (int i = 0; i < cards.size(); i++) + delete cards.at(i); + cards.clear(); + coordinateMap.clear(); + freePilesMap.clear(); + freeSpaceMap.clear(); + playersWithWritePermission.clear(); } void Server_CardZone::addWritePermission(int playerId) { - playersWithWritePermission.insert(playerId); + playersWithWritePermission.insert(playerId); } void Server_CardZone::getInfo(ServerInfo_Zone *info, Server_Player *playerWhosAsking, bool omniscient) { - info->set_name(name.toStdString()); - info->set_type(type); - info->set_with_coords(has_coords); - info->set_card_count(cards.size()); - info->set_always_reveal_top_card(alwaysRevealTopCard); - if ( - (((playerWhosAsking == player) || omniscient) && (type != ServerInfo_Zone::HiddenZone)) - || ((playerWhosAsking != player) && (type == ServerInfo_Zone::PublicZone)) - ) { - QListIterator cardIterator(cards); - while (cardIterator.hasNext()) - cardIterator.next()->getInfo(info->add_card_list()); - } + info->set_name(name.toStdString()); + info->set_type(type); + info->set_with_coords(has_coords); + info->set_card_count(cards.size()); + info->set_always_reveal_top_card(alwaysRevealTopCard); + if ( + (((playerWhosAsking == player) || omniscient) && (type != ServerInfo_Zone::HiddenZone)) + || ((playerWhosAsking != player) && (type == ServerInfo_Zone::PublicZone)) + ) { + QListIterator cardIterator(cards); + while (cardIterator.hasNext()) + cardIterator.next()->getInfo(info->add_card_list()); + } } diff --git a/doc/usermanual/Usermanual.pdf b/doc/usermanual/Usermanual.pdf index 361bf157..2fdcdb3f 100644 Binary files a/doc/usermanual/Usermanual.pdf and b/doc/usermanual/Usermanual.pdf differ diff --git a/doc/usermanual/Usermanual.tex b/doc/usermanual/Usermanual.tex index f506f7c8..634c0040 100644 --- a/doc/usermanual/Usermanual.tex +++ b/doc/usermanual/Usermanual.tex @@ -83,87 +83,115 @@ If someone runs his own server where you can register a user profile, read his d \section{Downloading and Installing the Cockatrice Program} Due to a legal dispute there are currently no official builds left, so currently you have to build your own binaries. -\subsection{Client compilation} +\subsection{Building the Client} \subsubsection{Windows} -There should be two ways to compile Cockatrice: With Visual Studio 2010 and with MinGW. -As the Visual Studio method is more complicated and might not work, you should do it with MinGW. -The following howto has been tested with Windows 7 64Bit. +To build Cockatrice, we need the Cockatrice sourcecode, its dependencies and build tools of course. +Everything is freely available. + +There should be two ways to compile Cockatrice: +With Microsoft Visual Studio 2010 (Visual C++ 2010) and with MinGW, a minimalist GNU environment for Windows. + +We suggest to use Visual Studio because there is a severe problem with MinGW: +It doesn't offer a compatible version of its tools. +The Qt library needs a certain, old MinGW version\footnote{The officially needed version is MinGW 4.8.2, the last known working version was MinGW 20120426} which is unavailable on the internet because they use an online installer and don't offer old, stable releases. +Trying to build with the current version of MinGW will result in application crashes! +So MinGW and Qt force us to focus on Visual Studio and don't support MinGW. + +Gladly, Microsoft offers Visual Studio Express free of charge, which is a limited but sufficient version of Visual Studio. +It only requires a free of charge registration after 30 days. + +The following howto which uses Visual C++ 2010 Express has been tested with an up to date Windows 7 64Bit. +The resulting build is a 32bit binary, which runs on both 32bit and 64bit systems. \paragraph{Prerequisites} -We need the Cockatrice sourcecode, it's dependencies and build tools. Everything is freely available: +Here is an introduction of all dependencies and tools needed for Cockatrice, followed by a list of downloadlinks in the same order. \begin{enumerate} - \item MinGW is needed to compile everything, it ships the compiler and other tools for this task. + \item The Microsoft Windows SDK for Windows 7 and .NET Framework 4 provides tools and libraries to create Windows applications. + \item The Visual C++ 2010 SP 1 Compiler Update for Windows SDK 7.1 (KB2519277) is a necessary update for the SDK. + \item Microsoft Visual C++ 2010 Express is the actual development environment. + \item Microsoft Visual Studio 2010 Service Pack 1 (VS10sp1-KB983509) is an update for Visual Studio. + \item The Qt libraries 4.8.x for Windows (VS 2010) are the main dependency for Cockatrice. + \item protobuf 2.5.0 is another dependency for Cockatrice (it has no installer, you need to download the zip file with the sourcecode). + \item cmake version 2.8.12.x is needed to create Cockatrice's project files for Visual Studio. Version 3 has not been tested yet with Cockatrice. \item git is needed to download the latest Cockatrice source code. - \item cmake is needed to create Cockatrice's project files for MinGW. - \item Qt 4.8 is a dependency for Cockatrice (download the MinGW version!) - \item protobuf 2.5 is another dependency for Cockatrice (download the zip file with the sourcecode). - \item Nullsoft Scriptable Install System (NSIS) which can be used to create an installer for your own Cockatrice version. + \item Nullsoft Scriptable Install System (NSIS 3.0b0) is a program to create the Windows installer for Cockatrice. \end{enumerate} All downloadlinks together: \footnotesize{\begin{enumerate} - \item \url{http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/mingw-get-inst-20120426/} + \item \url{http://www.microsoft.com/en-us/download/details.aspx?id=8279} % Win SDK + \item \url{http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=4422} % SDK Update + \item \url{http://go.microsoft.com/?linkid=9709949} % MSVC + \item \url{http://www.microsoft.com/en-us/download/details.aspx?id=23691} % MSVC SP1 + \item \url{http://download.qt-project.org/official_releases/qt/4.8/4.8.6/qt-opensource-windows-x86-vs2010-4.8.6.exe} + \item \url{http://www.cmake.org/files/v2.8/cmake-2.8.12.2-win32-x86.exe} \item \url{http://git-scm.com/download/win} - \item \url{http://www.cmake.org/files/v2.8/cmake-2.8.10.2-win32-x86.exe} - \item \url{http://download.qt-project.org/official_releases/qt/4.8/4.8.4/qt-win-opensource-4.8.4-mingw.exe} \item \url{http://protobuf.googlecode.com/files/protobuf-2.5.0.zip} \item \url{http://nsis.sourceforge.net/Download} \end{enumerate}} \paragraph{Installation of the Prerequisites} +Problems will occur if you don't install the first four steps (all the Microsoft SDK and Visual Studio packages) in the exact same order as printed here! \begin{enumerate} - \item Download MinGW (mingw-get-inst), git, cmake, protobuf 2.5 sources zip and Qt 4.8.4 MinGW (see links above). - \item Make a standard installation for git, cmake and NSIS. - \item Install MinGW: - \begin{enumerate} - \item Select default values everywhere, except: Also check the C++ Compiler, check the MSYS Basis System and MinGW Developer Toolkit. - \item Append \shellcmd{C:\textbackslash MinGW\textbackslash bin} to your PATH variable (google how to do it for your Windows version, if you don't know it). - This is very important and overseen many times! You can keep the PATH configuration dialog open for the next step. - \end{enumerate} - \item Install Qt, select default values everywhere, ignore the message regarding win32.h and append \shellcmd{C:\textbackslash Qt\textbackslash 4.8.4\textbackslash bin} to your PATH variable like you did for MinGW. - \item Unpack protobuf-2.5.0.zip in \shellcmd{C:\textbackslash MinGW\textbackslash msys\textbackslash 1.0\textbackslash home\textbackslash YOURLOGIN} - \begin{enumerate} - \item Open MinGW Shell, type the following commands exactly: - \item \shellcmd{cd protobuf-2.5.0/protobuf-2.5.0} - \item \shellcmd{./configure --prefix=`cd /mingw; pwd -W`} (these apostrophs are backticks and do not forget the dot at the beginning!) - \item \shellcmd{make; make install} (this builds and installs protobuf, which needs some time) - \item Close MinGW Shell - \end{enumerate} + \item Install Microsoft Windows SDK for Windows 7 and .NET Framework 4. + \item Apply the Visual C++ 2010 SP 1 Compiler Update for Windows SDK 7.1 + \item Install Visual C++ 2010 Express (Start the web installer, you may disable Silverlight) + \item Apply Visual C++ 2010 Express Service Pack 1 + \item Install Qt4 VS 2010 edition. + \item Install NSIS. + \item Install cmake. Choose to add CMake to the System path. + \item Install git. Choose Run Git from Windows Command Prompt. \end{enumerate} -Your system is now able to compile Cockatrice. You do not have to repeat the process so far ever again. + +As protobuf does neither provide an installer nor the libraries needed for Cockatrice, you have to build those with Visual Studio from the protobuf sources. +The Cockatrice installer will search for the protobuf libraries within the Cockatrice sources, so before unpacking and building protobuf, you need to download the Cockatrice sources first: +\begin{enumerate} + \item Right click into a folder, select Git Gui, then Clone Existing Directory, + \item enter Source Location \url{https://github.com/Daenyth/Cockatrice} + \item enter target directory (from now on called Cockatrice), click clone and wait until the sources have been downloaded, + \item close Git Gui. +\end{enumerate} + +Now we prepare protobuf: +\begin{enumerate} + \item Create a \shellcmd{build} directory inside the Cockatrice directory. + \item Copy the protobuf-2.5.0.zip into the build directory. + \item Rightclick the zip, choose Extract all. This uses the Windows included zip unpacker to extract the archive. +\end{enumerate} +To be clear: you will (and must) have a Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0 directory hierarchy after that! + +Now the protobuf dependencies for Cockatrice will be built: +\begin{enumerate} + \item Start Visual C++ 2010 Express and from the File menu Open Project/Solution, move to the Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/vsprojects directory and choose protobuf.sln. + \item Let you guide through the Conversion Wizard, you don't need to create a backup. + \item After the conversion is finished, open the projects (uncheck ``Ask me for every project in this solution'' and click OK). + \item You don't need to look at the conversion report. + \item Select Release or Debug in the toolbar. Release optimizes the code for size and speed, while Debug creates larger, slower binaries, used for development. You need to use the same setting for Cockatrice later! We suggest to use Release. + \item Rightclick on libprotobuf, choose Build. Note that the output should say: Build started: Project libprotobuf, Configuration: Release Win32 + \item Then rightclick on protoc, choose Build. This will build libprotoc and the protoc executable, also as Release Win32. + \item After the build succeeded, close Visual C++. +\end{enumerate} +The Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/vsprojects/Release directory now contains libprotobuf.dll, libprotobuf.lib and protoc.exe which are needed for Cockatrice. \paragraph{Cockatrice Compilation} +Now everything is ready to compile Cockatrice. \begin{enumerate} - \item Checkout Cockatrice: - \begin{enumerate} - \item Start Git Bash and type the following command exactly: - \item \shellcmd{git clone https://github.com/Daenyth/Cockatrice} - \item Close Git Bash - \end{enumerate} - \item Start CMake (cmake-gui) and do the following: - \begin{enumerate} - \item Where is the source code: Point to the Cockatrice directory - \item Where to build the binaries: Point to the Cockatrice/build directory (it doesn't matter if it exists; if it doesn't, cmake will ask later if it shall create this directory) - \item Check Advanced - \item Click Configure, choose MinGW, leave the rest default - \item An error will occur, set the following: - \begin{itemize} - \item Set PROTOBUF\_INCLUDE\_DIR to C:/MinGW/include/google/protobuf - \item Set PROTOBUF\_LIBRARY to C:/MinGW/lib/libprotobuf.dll.a - \item Set PROTOBUF\_LITE\_LIBRARY to C:/MinGW/lib/libprotobuf-lite.dll.a - \item Set PROTOBUF\_PROTOC\_EXECUTABLE to C:/MinGW/bin/protoc.exe - \item Set PROTOBUF\_PROTOC\_LIBRARY to C:/MinGW/lib/libprotoc.dll.a - \end{itemize} - \item Click Configure again, then Generate - \item Close CMake - \end{enumerate} - \item Start cmd.exe (the Windows Command Prompt) and type the following commands: - \begin{enumerate} - \item \shellcmd{cd Cockatrice/build} (this changes to the build directory) - \item \shellcmd{make} (this builds everything and might need some time) - \end{enumerate} + \item Start CMake GUI, locate the Cockatrice directory and locate the Cockatrice/build directory. + Then click Configure and choose Visual Studio 10. + An error will occur during the Configure process because CMake does not know the location of the protobuf library. + \item To satisfy CMake, check Advanced, enter ``protobuf'' in the Search field, + \begin{enumerate} + \item Set PROTOBUF\_INCLUDE\_DIR to Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/src/ + \item Set PROTOBUF\_LIBRARY to Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/vsprojects/Release/libprotobuf.lib + \item Set PROTOBUF\_PROTOC\_EXECUTABLE to Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/vsprojects/Release/protoc.exe + \item Set PROTOBUF\_PROTOC\_LIBRARY to Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/vsprojects/Release/libprotoc.lib % TODO: Is this needed? I don't think so; but it doesn't hurt either. + \item Click Configure again. + \end{enumerate} + \item Click Generate, then close CMake GUI. The project files have been generated. + \item Start Visual C++ 2010 Express and from the File menu select Open Project/Solution, point to the Cockatrice/build directory and choose Cockatrice.sln. + \item Select Release or Debug in the toolbar exactly as you did for protobuf. We suggest Release. + \item Rightclick on ALL\_BUILD, choose Build. \end{enumerate} -Cockatrice has now been downloaded and built for the first time. You do not have to repeat the process so far ever again. \paragraph{Updating your Cockatrice build} If you just compiled Cockatrice for the first time, you skip this step obviously. @@ -174,17 +202,19 @@ But if you want to update Cockatrice after the source code changed on github, do \item \shellcmd{git pull origin master} \item \shellcmd{Close Git Bash} \end{enumerate} - \item Start cmd.exe, change to Cockatrice/build, type make like you did previously. + \item Start Visual C++ 2010 Express and build the Cockatrice sources again. \end{enumerate} Cockatrice has now been updated and built. You may repeat this process every time when the source code changed. \paragraph{Cockatrice installation} To install Cockatrice, you have to create an installer with NSIS now. -Change to the directory \shellcmd{nsis} in the Cockatrice root directory, right click the cockatrice.nsi file and select \shellcmd{Compile NSIS Script}. +Change to the directory \shellcmd{nsis} in the Cockatrice directory, right click the cockatrice.nsi file and select \shellcmd{Compile NSIS Script}. The NSIS program then creates a file called cockatrice\_win32\_YYYYmmdd\_git-xxxxxxx.exe. This is the complete, redistributable installer for your Cockatrice build. Now install Cockatrice by executing the installer. -Note: if you installed MinGW or Qt in other than the default paths, you have to fix the paths in the cockatrice.nsi file (also if some libraries change); you can edit this file with a text editor. +Note: if you installed Qt in other than the default path, you have to fix the paths in the cockatrice.nsi file; you can edit this file with a text editor. + +We will remove this static NSIS file in the future and let CMake create the NSIS file on the fly. \paragraph{Create a card database} Start the oracle.exe (the installer does this automatically) and let it generate a current cards.xml file: @@ -204,7 +234,7 @@ Before you install new software, you should update your system. The following in \begin{enumerate} \item You need to install the build tools and dependencies. This varies between the Linux distributions. \begin{description} - \item[Debian, Ubuntu and spin-offs] \shellcmd{sudo apt-get install build-essential git libqt4-dev qtmobility-dev libprotobuf-dev protobuf-compiler cmake} (see note below regarding pthread) + \item[Debian, Ubuntu and spin-offs] \shellcmd{sudo apt-get install build-essential git libqt4-dev qtmobility-dev libprotobuf-dev protobuf-compiler cmake} \item[Fedora] \shellcmd{sudo yum groupinstall "Development Tools"\\ yum install qt-devel qt-mobility-devel protobuf-devel protobuf-compiler cmake} \item[FreeBSD 9] \shellcmd{pkg\_add -r qt4 qt4-linguist qt4-moc qt4-qmake qt4-rcc qt4-uic git cmake protobuf} @@ -217,9 +247,6 @@ mkdir build \\ cd build \\ cmake ..\\ make}\\ -\begin{framed} -If you have linking errors with pthread\_* add 'pthread' to the ``target\_link\_libraries'' entry in the \shellcmd{CMakeFiles.txt} in \shellcmd{Cockatrice/common}, e.g. for Xubuntu, then continue the make process. -\end{framed} \item You may install the program into the directory \shellcmd{/usr/local} by typing \shellcmd{sudo make install} but you should also be able to start cockatrice and the oracle from the build directory. \item Before you start Cockatrice for the first time, run \shellcmd{oracle -dlsets} and download available cards, then run \shellcmd{cockatrice}. @@ -229,7 +256,7 @@ The default paths for decks, pics, cards and tokens are located in \\ \shellcmd{ \subsubsection{MacOS X} TODO, please contribute this section! See Linux section, then use the \shellcmd{prepareMacRelease.sh} script from Cockatrice. -\subsection{Server compilation} +\subsection{Building the Server} You don't need your own server if you plan to play only. But as Cockatrice is open source you are free to run your own. The compilation works like already written above, but instead of invoking \shellcmd{cmake ..}, you have to do it like this: \begin{itemize} diff --git a/nsis/cockatrice.nsi b/nsis/cockatrice.nsi index 396b0fc9..33cc496b 100644 --- a/nsis/cockatrice.nsi +++ b/nsis/cockatrice.nsi @@ -9,6 +9,9 @@ OutFile "cockatrice_win32_${TIMESTAMP}_git-${VERSION}.exe" SetCompressor /SOLID lzma InstallDir "$PROGRAMFILES\Cockatrice" +; set the Qt install dir here (and make sure you use the latest 4.8 version for packaging) +!define QTDIR "C:\Qt\4.8.6" + !define MUI_ABORTWARNING !define MUI_WELCOMEFINISHPAGE_BITMAP "leftimage.bmp" !define MUI_UNWELCOMEFINISHPAGE_BITMAP "leftimage.bmp" @@ -34,35 +37,33 @@ InstallDir "$PROGRAMFILES\Cockatrice" !insertmacro MUI_LANGUAGE "English" Section "Application" SecApplication + SetShellVarContext all SetOutPath "$INSTDIR" - File ..\build\cockatrice\cockatrice.exe - File ..\build\oracle\oracle.exe + File ..\build\cockatrice\Release\cockatrice.exe + File ..\build\oracle\Release\oracle.exe File ..\doc\usermanual\Usermanual.pdf - File C:\MinGW\bin\libstdc++-6.dll - File C:\MinGW\bin\libgcc_s_dw2-1.dll - File C:\MinGW\bin\mingwm10.dll - File C:\MinGW\bin\libprotobuf-8.dll - File C:\Qt\4.8.4\bin\QtCore4.dll - File C:\Qt\4.8.4\bin\QtGui4.dll - File C:\Qt\4.8.4\bin\QtNetwork4.dll - File C:\Qt\4.8.4\bin\QtSvg4.dll - File C:\Qt\4.8.4\bin\QtXml4.dll - File C:\Qt\4.8.4\bin\QtMultimedia4.dll + File ..\build\protobuf-2.5.0\protobuf-2.5.0\vsprojects\Release\libprotobuf.lib + File "${QTDIR}\bin\QtCore4.dll" + File "${QTDIR}\bin\QtGui4.dll" + File "${QTDIR}\bin\QtNetwork4.dll" + File "${QTDIR}\bin\QtSvg4.dll" + File "${QTDIR}\bin\QtXml4.dll" + File "${QTDIR}\bin\QtMultimedia4.dll" SetOutPath "$INSTDIR\zonebg" File /r ..\zonebg\*.* SetOutPath "$INSTDIR\plugins" SetOutPath "$INSTDIR\plugins\codecs" - File C:\Qt\4.8.4\plugins\codecs\qcncodecs4.dll - File C:\Qt\4.8.4\plugins\codecs\qjpcodecs4.dll - File C:\Qt\4.8.4\plugins\codecs\qkrcodecs4.dll - File C:\Qt\4.8.4\plugins\codecs\qtwcodecs4.dll + File "${QTDIR}\plugins\codecs\qcncodecs4.dll" + File "${QTDIR}\plugins\codecs\qjpcodecs4.dll" + File "${QTDIR}\plugins\codecs\qkrcodecs4.dll" + File "${QTDIR}\plugins\codecs\qtwcodecs4.dll" SetOutPath "$INSTDIR\plugins\iconengines" - File C:\Qt\4.8.4\plugins\iconengines\qsvgicon4.dll + File "${QTDIR}\plugins\iconengines\qsvgicon4.dll" SetOutPath "$INSTDIR\plugins\imageformats" - File C:\Qt\4.8.4\plugins\imageformats\qjpeg4.dll - File C:\Qt\4.8.4\plugins\imageformats\qsvg4.dll + File "${QTDIR}\plugins\imageformats\qjpeg4.dll" + File "${QTDIR}\plugins\imageformats\qsvg4.dll" SetOutPath "$INSTDIR\sounds" File /r ..\sounds\*.* @@ -70,9 +71,9 @@ Section "Application" SecApplication SetOutPath "$INSTDIR\translations" File /r ..\build\cockatrice\*.qm - WriteUninstaller "$INSTDIR\uninstall.exe" - ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 - IntFmt $0 "0x%08X" $0 + WriteUninstaller "$INSTDIR\uninstall.exe" + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "DisplayName" "Cockatrice" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" @@ -96,38 +97,36 @@ Section "Start menu item" SecStartMenu SectionEnd Section Uninstall - RMDir /r "$INSTDIR\zonebg" - RMDir /r "$INSTDIR\plugins" - RMDir /r "$INSTDIR\sounds" +SetShellVarContext all + RMDir /r "$INSTDIR\zonebg" + RMDir /r "$INSTDIR\plugins" + RMDir /r "$INSTDIR\sounds" RMDir /r "$INSTDIR\translations" - Delete "$INSTDIR\uninstall.exe" - Delete "$INSTDIR\cockatrice.exe" - Delete "$INSTDIR\oracle.exe" - Delete "$INSTDIR\Usermanual.pdf" - Delete "$INSTDIR\libstdc++-6.dll" - Delete "$INSTDIR\libprotobuf-8.dll" - Delete "$INSTDIR\libgcc_s_dw2-1.dll" - Delete "$INSTDIR\mingwm10.dll" - Delete "$INSTDIR\QtCore4.dll" - Delete "$INSTDIR\QtGui4.dll" - Delete "$INSTDIR\QtNetwork4.dll" - Delete "$INSTDIR\QtSvg4.dll" - Delete "$INSTDIR\QtXml4.dll" + Delete "$INSTDIR\uninstall.exe" + Delete "$INSTDIR\cockatrice.exe" + Delete "$INSTDIR\oracle.exe" + Delete "$INSTDIR\Usermanual.pdf" + Delete "$INSTDIR\libprotobuf.lib" + Delete "$INSTDIR\QtCore4.dll" + Delete "$INSTDIR\QtGui4.dll" + Delete "$INSTDIR\QtNetwork4.dll" + Delete "$INSTDIR\QtSvg4.dll" + Delete "$INSTDIR\QtXml4.dll" Delete "$INSTDIR\QtMultimedia4.dll" - RMDir "$INSTDIR" + RMDir "$INSTDIR" RMDir /r "$SMPROGRAMS\Cockatrice" - - DeleteRegKey HKCU "Software\Cockatrice" - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" + + DeleteRegKey HKCU "Software\Cockatrice" + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" SectionEnd LangString DESC_SecApplication ${LANG_ENGLISH} "Cockatrice program files" LangString DESC_SecUpdateConfig ${LANG_ENGLISH} "Update the paths in the application settings according to the installation paths." LangString DESC_SecStartMenu ${LANG_ENGLISH} "Create start menu items for Cockatrice and Oracle." !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${SecApplication} $(DESC_SecApplication) - !insertmacro MUI_DESCRIPTION_TEXT ${SecUpdateConfig} $(DESC_SecUpdateConfig) - !insertmacro MUI_DESCRIPTION_TEXT ${SecStartMenu} $(DESC_SecStartMenu) + !insertmacro MUI_DESCRIPTION_TEXT ${SecApplication} $(DESC_SecApplication) + !insertmacro MUI_DESCRIPTION_TEXT ${SecUpdateConfig} $(DESC_SecUpdateConfig) + !insertmacro MUI_DESCRIPTION_TEXT ${SecStartMenu} $(DESC_SecStartMenu) !insertmacro MUI_FUNCTION_DESCRIPTION_END diff --git a/oracle/CMakeLists.txt b/oracle/CMakeLists.txt index 031f38e4..2eada38c 100644 --- a/oracle/CMakeLists.txt +++ b/oracle/CMakeLists.txt @@ -26,7 +26,11 @@ INCLUDE_DIRECTORIES(../cockatrice/src) # Build oracle binary and link it ADD_EXECUTABLE(oracle WIN32 MACOSX_BUNDLE ${oracle_SOURCES} ${oracle_MOC_SRCS}) -TARGET_LINK_LIBRARIES(oracle ${QT_LIBRARIES}) +TARGET_LINK_LIBRARIES(oracle ${QT_QTMAIN_LIBRARY} ${QT_LIBRARIES}) + +if(MSVC) + set_target_properties(oracle PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS") +endif(MSVC) if(UNIX) if(APPLE)