# HG changeset patch # User Xeli # Date 1315538145 -7200 # Node ID 2e5835130d9ad8c17e21f4f3423dc2dcf7d19a81 # Parent 5ab22736bdb6eb79e0a4c59b9d08d06bccbed9b5# Parent f906f6645e02530b0dba7ed3de8ed8bf6389ea1a merge diff -r 5ab22736bdb6 -r 2e5835130d9a CMakeLists.txt --- a/CMakeLists.txt Fri Sep 09 04:39:17 2011 +0200 +++ b/CMakeLists.txt Fri Sep 09 05:15:45 2011 +0200 @@ -197,6 +197,7 @@ if(NOT BUILD_ENGINE_LIBRARY) add_subdirectory(bin) + add_subdirectory(misc/quazip) add_subdirectory(QTfrontend) add_subdirectory(share) add_subdirectory(tools) diff -r 5ab22736bdb6 -r 2e5835130d9a ChangeLog.txt --- a/ChangeLog.txt Fri Sep 09 04:39:17 2011 +0200 +++ b/ChangeLog.txt Fri Sep 09 05:15:45 2011 +0200 @@ -7,6 +7,7 @@ + Sudden Death art + New Weapon/Utility: Land Spray Gun + New Game mode: Tag team + + Get away time modifier (in %) + Allow up to 8 teams in a game + Shoppa scheme by default resets ammo + Shots are on a tenth of a second delay instead of a 1 and a quarter second delay (fast deagle/portal fire) @@ -22,6 +23,7 @@ + Indicator for height of plane when using napalm + Land smoothing (looks less pixelated on generation and damage) + Improved lua script support (e.g. possibility to change hats) + + The names of the ShoppaKingTournament winners are now written on the Trophies in the ShoppaKing and TrophyRace maps! * Prevent portaling to impossible locations better * Snow accumulates more smoothly * Rope should be less sticky now diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/CMakeLists.txt --- a/QTfrontend/CMakeLists.txt Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/CMakeLists.txt Fri Sep 09 05:15:45 2011 +0200 @@ -4,7 +4,6 @@ set(QT_USE_QTCORE TRUE) set(QT_USE_QTGUI TRUE) set(QT_USE_QTNETWORK TRUE) -set(QT_USE_QTWEBKIT TRUE) set(QT_USE_QTSVG FALSE) set(QT_USE_QTXML FALSE) set(QT_USE_QTOPENGL FALSE) @@ -20,6 +19,7 @@ include_directories(.) include_directories(${SDL_INCLUDE_DIR}) include_directories(${SDLMIXER_INCLUDE_DIR}) +include_directories(${CMAKE_SOURCE_DIR}/misc/quazip) if(UNIX) # HACK: in freebsd cannot find iconv.h included via SDL.h include_directories("/usr/local/include") @@ -115,6 +115,7 @@ drawmapwidget.cpp drawmapscene.cpp themesmodel.cpp + databrowser.cpp ) #xfire integration @@ -196,6 +197,7 @@ drawmapwidget.h drawmapscene.h themesmodel.h + databrowser.h ) set(hwfr_hdrs @@ -236,6 +238,7 @@ set(HW_LINK_LIBS + quazip ${QT_LIBRARIES} ${SDL_LIBRARY} ${SDLMIXER_LIBRARY} @@ -247,7 +250,7 @@ set(HW_LINK_LIBS ${HW_LINK_LIBS} SDL) endif() - set( HW_LINK_LIBS + set(HW_LINK_LIBS ${HW_LINK_LIBS} ole32 oleaut32 @@ -257,7 +260,7 @@ endif() -target_link_libraries(hedgewars ${HW_LINK_LIBS}) +target_link_libraries(hedgewars ${HW_LINK_LIBS}) install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/hedgewars${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_dir}) diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/SDLs.cpp --- a/QTfrontend/SDLs.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/SDLs.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -104,11 +104,11 @@ // Entry for "Axis Up" sprintf(sdlkeys[i][0], "j%da%du", jid, aid); - sprintf(sdlkeys[i++][1], "%s", ((isxb && aid < 5) ? (prefix + HWApplication::translate("binds (keys)", xbox360axes[aid * 2])) : axis + HWApplication::translate("binds (keys)", "(Up)")).toStdString().c_str()); + sprintf(sdlkeys[i++][1], "%s", ((isxb && aid < 5) ? (prefix + HWApplication::translate("binds (keys)", xbox360axes[aid * 2])) : axis + HWApplication::translate("binds (keys)", "(Up)")).toUtf8().constData()); // Entry for "Axis Down" sprintf(sdlkeys[i][0], "j%da%dd", jid, aid); - sprintf(sdlkeys[i++][1], "%s", ((isxb && aid < 5) ? (prefix + HWApplication::translate("binds (keys)", xbox360axes[aid * 2 + 1])) : axis + HWApplication::translate("binds (keys)", "(Down)")).toStdString().c_str()); + sprintf(sdlkeys[i++][1], "%s", ((isxb && aid < 5) ? (prefix + HWApplication::translate("binds (keys)", xbox360axes[aid * 2 + 1])) : axis + HWApplication::translate("binds (keys)", "(Down)")).toUtf8().constData()); } // Register entries for all coolie hats of this joystick/gamepad @@ -119,19 +119,19 @@ // Entry for "Hat Up" sprintf(sdlkeys[i][0], "j%dh%du", jid, hid); - sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Up)")).toStdString().c_str()); + sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Up)")).toUtf8().constData()); // Entry for "Hat Down" sprintf(sdlkeys[i][0], "j%dh%dd", jid, hid); - sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Down)")).toStdString().c_str()); + sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Down)")).toUtf8().constData()); // Entry for "Hat Left" sprintf(sdlkeys[i][0], "j%dh%dl", jid, hid); - sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Left)")).toStdString().c_str()); + sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Left)")).toUtf8().constData()); // Entry for "Hat Right" sprintf(sdlkeys[i][0], "j%dh%dr", jid, hid); - sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Right)")).toStdString().c_str()); + sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Right)")).toUtf8().constData()); } // Register entries for all buttons of this joystick/gamepad @@ -139,7 +139,7 @@ { // Buttons sprintf(sdlkeys[i][0], "j%db%d", jid, bid); - sprintf(sdlkeys[i++][1], "%s", (prefix + ((isxb && bid < 10) ? (HWApplication::translate("binds (keys)", xb360buttons[bid]) + QString(" ")) : HWApplication::translate("binds (keys)", "Button") + QString(" %1").arg(bid + 1))).toStdString().c_str()); + sprintf(sdlkeys[i++][1], "%s", (prefix + ((isxb && bid < 10) ? (HWApplication::translate("binds (keys)", xb360buttons[bid]) + QString(" ")) : HWApplication::translate("binds (keys)", "Button") + QString(" %1").arg(bid + 1))).toUtf8().constData()); } // Close the game controller as we no longer need it SDL_JoystickClose(joy); diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/chatwidget.cpp --- a/QTfrontend/chatwidget.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/chatwidget.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -233,7 +233,7 @@ void HWChatWidget::loadList(QStringList & list, const QString & file) { list.clear(); - QFile txt((cfgdir->absolutePath() + "/" + file).toLocal8Bit().constData()); + QFile txt(cfgdir->absolutePath() + "/" + file); if(!txt.open(QIODevice::ReadOnly)) return; QTextStream stream(&txt); @@ -253,7 +253,7 @@ void HWChatWidget::saveList(QStringList & list, const QString & file) { - QFile txt((cfgdir->absolutePath() + "/" + file).toLocal8Bit().constData()); + QFile txt(cfgdir->absolutePath() + "/" + file); if(!txt.open(QIODevice::WriteOnly | QIODevice::Truncate)) return; QTextStream stream(&txt); @@ -400,9 +400,8 @@ void HWChatWidget::nickRemoved(const QString& nick) { - QList items = chatNicks->findItems(nick, Qt::MatchExactly); - QListIterator it(items); - while(it.hasNext()) chatNicks->takeItem(chatNicks->row(it.next())); + foreach(QListWidgetItem * item, chatNicks->findItems(nick, Qt::MatchExactly)) + chatNicks->takeItem(chatNicks->row(item)); emit nickCountUpdate(chatNicks->count()); } diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/databrowser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/databrowser.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include + +#include "databrowser.h" + +const QNetworkRequest::Attribute typeAttribute = (QNetworkRequest::Attribute)(QNetworkRequest::User + 1); +const QNetworkRequest::Attribute urlAttribute = (QNetworkRequest::Attribute)(QNetworkRequest::User + 2); + +DataBrowser::DataBrowser(QWidget *parent) : + QTextBrowser(parent) +{ + + manager = new QNetworkAccessManager(this); +} + +QVariant DataBrowser::loadResource(int type, const QUrl & name) +{ + if(type == QTextDocument::ImageResource || type == QTextDocument::StyleSheetResource) + { + if(resources.contains(name.toString())) + { + return resources.take(name.toString()); + } + else + if(!requestedResources.contains(name.toString())) + { + qDebug() << "Requesting resource" << name.toString(); + requestedResources.insert(name.toString()); + + QNetworkRequest newRequest(QUrl("http://www.hedgewars.org" + name.toString())); + newRequest.setAttribute(typeAttribute, type); + newRequest.setAttribute(urlAttribute, name); + + QNetworkReply *reply = manager->get(newRequest); + connect(reply, SIGNAL(finished()), this, SLOT(resourceDownloaded())); + } + } + + return QVariant(); +} + +void DataBrowser::resourceDownloaded() +{ + QNetworkReply * reply = qobject_cast(sender()); + + if(reply) + { + int type = reply->request().attribute(typeAttribute).toInt(); + QUrl url = reply->request().attribute(urlAttribute).toUrl(); + resources.insert(url.toString(), reply->readAll()); + document()->addResource(type, reply->request().url(), QVariant()); + update(); + } +} diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/databrowser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/databrowser.h Fri Sep 09 05:15:45 2011 +0200 @@ -0,0 +1,33 @@ +#ifndef DATABROWSER_H +#define DATABROWSER_H + +#include +#include + +class QNetworkAccessManager; + +class DataBrowser : public QTextBrowser +{ + Q_OBJECT +public: + explicit DataBrowser(QWidget *parent = 0); + +signals: + +public slots: + +private: + QNetworkAccessManager *manager; + + // hash and set of QString instead of QUrl to support Qt versions + // older than 4.7 (those have no support for qHash(const QUrl &)) + QHash resources; + QSet requestedResources; + + QVariant loadResource(int type, const QUrl & name); + +private slots: + void resourceDownloaded(); +}; + +#endif // DATABROWSER_H diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/game.cpp --- a/QTfrontend/game.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/game.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -53,7 +53,9 @@ void HWGame::onClientDisconnect() { switch (gameType) { - case gtDemo: break; + case gtDemo: + if (gameState == gsInterrupted || gameState == gsHalted) emit HaveRecord(false, demo); + break; case gtNet: emit HaveRecord(true, demo); break; @@ -84,8 +86,7 @@ if (m_pTeamSelWidget) { - QListIterator it(m_pTeamSelWidget->getPlayingTeams()); - while(it.hasNext()) + foreach(HWTeam team, m_pTeamSelWidget->getPlayingTeams()) { HWProto::addStringToBuffer(buf, QString("eammloadt %1").arg(ammostr.mid(0, cAmmoNumber))); HWProto::addStringToBuffer(buf, QString("eammprob %1").arg(ammostr.mid(cAmmoNumber, cAmmoNumber))); @@ -93,7 +94,7 @@ HWProto::addStringToBuffer(buf, QString("eammreinf %1").arg(ammostr.mid(3 * cAmmoNumber, cAmmoNumber))); if(!gamecfg->schemeData(21).toBool()) HWProto::addStringToBuffer(buf, QString("eammstore")); HWProto::addStringListToBuffer(buf, - it.next().TeamGameConfig(gamecfg->getInitHealth())); + team.TeamGameConfig(gamecfg->getInitHealth())); ; } } @@ -392,9 +393,8 @@ if (m_pTeamSelWidget) { QByteArray buf; - QListIterator it(m_pTeamSelWidget->getPlayingTeams()); - while(it.hasNext()) - HWProto::addStringToBuffer(buf, QString("eteamgone %1").arg(it.next().TeamName)); + foreach(HWTeam team, m_pTeamSelWidget->getPlayingTeams()) + HWProto::addStringToBuffer(buf, QString("eteamgone %1").arg(team.TeamName)); RawSendIPC(buf); } } diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/hwconsts.h --- a/QTfrontend/hwconsts.h Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/hwconsts.h Fri Sep 09 05:15:45 2011 +0200 @@ -74,9 +74,9 @@ #define AMMOLINE_PROMODE_CRATE "111111111111111111111111111111111111111110010111111101" #define AMMOLINE_SHOPPA_QT "000000990000000000000000000000000000000000000000000000" -#define AMMOLINE_SHOPPA_PROB "444441004424440221011212122242200000000200040001001101" +#define AMMOLINE_SHOPPA_PROB "444441004424440221011212122242200000000200040001001100" #define AMMOLINE_SHOPPA_DELAY "000000000000000000000000000000000000000000000000000000" -#define AMMOLINE_SHOPPA_CRATE "111111111111111111111111111111111111111110110111111101" +#define AMMOLINE_SHOPPA_CRATE "111111111111111111111111111111111111111110110111111100" #define AMMOLINE_CLEAN_QT "101000900001000001100000000000000000000000000000100000" #define AMMOLINE_CLEAN_PROB "040504054160065554655446477657666666615551010111541101" diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/hwform.cpp --- a/QTfrontend/hwform.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/hwform.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -38,6 +38,7 @@ #include #include #include +#include #include "hwform.h" #include "game.h" @@ -151,12 +152,17 @@ connect(ui.pageMain->BtnNet, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); pageSwitchMapper->setMapping(ui.pageMain->BtnNet, ID_PAGE_NETTYPE); + connect(ui.pageMain->BtnInfo, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); - pageSwitchMapper->setMapping(ui.pageMain->BtnInfo, ID_PAGE_DATADOWNLOAD); + pageSwitchMapper->setMapping(ui.pageMain->BtnInfo, ID_PAGE_INFO); + + connect(ui.pageMain->BtnDataDownload, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageMain->BtnDataDownload, ID_PAGE_DATADOWNLOAD); connect(ui.pageMain->BtnExit, SIGNAL(pressed()), this, SLOT(btnExitPressed())); connect(ui.pageMain->BtnExit, SIGNAL(clicked()), this, SLOT(btnExitClicked())); + connect(ui.pageInfo->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); connect(ui.pageDataDownload->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); connect(ui.pageEditTeam->BtnTeamSave, SIGNAL(clicked()), this, SLOT(TeamSave())); @@ -223,6 +229,7 @@ connect(ui.pageInfo->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); connect(ui.pageGameStats->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); + connect(ui.pageGameStats, SIGNAL(saveDemoRequested()), this, SLOT(saveDemoWithCustomName())); connect(ui.pageSinglePlayer->BtnSimpleGamePage, SIGNAL(clicked()), this, SLOT(SimpleGame())); connect(ui.pageSinglePlayer->BtnTrainPage, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); @@ -619,8 +626,9 @@ } QStringList tmnames; - QListIterator it(curTeamSelWidget->getDontPlayingTeams()); - while(it.hasNext()) tmnames += it.next().TeamName; + + foreach(HWTeam team, curTeamSelWidget->getNotPlayingTeams()) + tmnames += team.TeamName; //UpdateTeamsLists(&tmnames); // FIXME: still need more work if teamname is updated while configuring UpdateTeamsLists(); @@ -1033,6 +1041,7 @@ connect(game, SIGNAL(GameStats(char, const QString &)), ui.pageGameStats, SLOT(GameStats(char, const QString &))); connect(game, SIGNAL(ErrorMessage(const QString &)), this, SLOT(ShowErrorMessage(const QString &)), Qt::QueuedConnection); connect(game, SIGNAL(HaveRecord(bool, const QByteArray &)), this, SLOT(GetRecord(bool, const QByteArray &))); + m_lastDemo = QByteArray(); } void HWForm::ShowErrorMessage(const QString & msg) @@ -1061,6 +1070,7 @@ demo.replace(QByteArray("\x02TN"), QByteArray("\x02TD")); demo.replace(QByteArray("\x02TS"), QByteArray("\x02TD")); filename = cfgdir->absolutePath() + "/Demos/" + recordFileName + "." + *cProtoVer + ".hwd"; + m_lastDemo = demo; } else { demo.replace(QByteArray("\x02TL"), QByteArray("\x02TS")); @@ -1075,7 +1085,7 @@ ShowErrorMessage(tr("Cannot save record to file %1").arg(filename)); return ; } - demofile.write(demo.constData(), demo.size()); + demofile.write(demo); demofile.close(); } @@ -1293,3 +1303,30 @@ else QMessageBox::information(0, "", QMessageBox::tr("File association failed.")); } +void HWForm::saveDemoWithCustomName() +{ + if(!m_lastDemo.isEmpty()) + { + QString fileName; + bool ok = false; + do + { + fileName = QInputDialog::getText(this, tr("Demo name"), tr("Demo name:")); + + if(!fileName.isEmpty()) + { + QString filePath = cfgdir->absolutePath() + "/Demos/" + fileName + "." + *cProtoVer + ".hwd"; + QFile demofile(filePath); + ok = demofile.open(QIODevice::WriteOnly); + if (!ok) + ShowErrorMessage(tr("Cannot save record to file %1").arg(filePath)); + else + { + ok = -1 != demofile.write(m_lastDemo); + demofile.close(); + } + } + } while(!fileName.isEmpty() && !ok); + } +} + diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/hwform.h --- a/QTfrontend/hwform.h Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/hwform.h Fri Sep 09 05:15:45 2011 +0200 @@ -117,6 +117,8 @@ void AsyncNetServerStart(); void NetLeftRoom(); void selectFirstNetScheme(); + + void saveDemoWithCustomName(); private: void _NetConnect(const QString & hostName, quint16 port, const QString & nick); @@ -162,6 +164,7 @@ QTime eggTimer; BGWidget * wBackground; QSignalMapper * pageSwitchMapper; + QByteArray m_lastDemo; #ifdef __APPLE__ InstallController * panel; diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/main.cpp --- a/QTfrontend/main.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/main.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -470,8 +470,8 @@ app.installTranslator(&Translator); } +#ifdef _WIN32 // Win32 registry setup (used for xfire detection etc. - don't set it if we're running in "portable" mode with a custom config dir) -#ifdef _WIN32 if(!custom_config) { QSettings registry_hklm("HKEY_LOCAL_MACHINE", QSettings::NativeFormat); diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/mapContainer.cpp --- a/QTfrontend/mapContainer.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/mapContainer.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -64,8 +64,6 @@ imageButt->setFlat(true); imageButt->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);//QSizePolicy::Minimum, QSizePolicy::Minimum); mapLayout->addWidget(imageButt, 0, 0, 1, 2); - //connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomSeed())); - //connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomTheme())); connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomMap())); chooseMap = new QComboBox(mapWidget); @@ -293,7 +291,6 @@ maze_size_label->hide(); cbMazeSize->hide(); emit mapChanged("+rnd+"); - emit mapgenChanged(mapgen); emit themeChanged(chooseMap->itemData(index).toList()[1].toString()); break; case MAPGEN_MAZE: @@ -305,7 +302,6 @@ maze_size_label->show(); cbMazeSize->show(); emit mapChanged("+maze+"); - emit mapgenChanged(mapgen); emit themeChanged(chooseMap->itemData(index).toList()[1].toString()); break; case MAPGEN_DRAWN: @@ -317,10 +313,10 @@ maze_size_label->hide(); cbMazeSize->hide(); emit mapChanged("+drawn+"); - emit mapgenChanged(mapgen); emit themeChanged(chooseMap->itemData(index).toList()[1].toString()); break; default: + mapgen = MAPGEN_MAP; updatePreview(); gbThemes->hide(); lblFilter->hide(); @@ -329,6 +325,8 @@ cbMazeSize->hide(); emit mapChanged(chooseMap->itemData(index).toList()[0].toString()); } + + emit mapgenChanged(mapgen); } // Should this add text to identify map size? @@ -447,7 +445,7 @@ void HWMapContainer::setSeed(const QString & seed) { intSetSeed(seed); - if (chooseMap->currentIndex() < MAPGEN_MAP) + if (chooseMap->currentIndex() < MAPGEN_DRAWN) updatePreview(); } @@ -511,15 +509,14 @@ { int i = MAPGEN_MAP + 3 + numMissions + rand() % (chooseMap->count() - MAPGEN_MAP - 3 - numMissions); chooseMap->setCurrentIndex(i); - setRandomSeed(); + updatePreview(); } void HWMapContainer::setRandomMission() { int i = MAPGEN_MAP + 2 + rand() % numMissions; - qDebug() << i << MAPGEN_MAP << numMissions; chooseMap->setCurrentIndex(i); - setRandomSeed(); + updatePreview(); } void HWMapContainer::setRandomSeed() @@ -575,7 +572,10 @@ void HWMapContainer::intSetMapgen(MapGenerator m) { mapgen = m; - chooseMap->setCurrentIndex(m); + + if(m != MAPGEN_MAP) + chooseMap->setCurrentIndex(m); + emit mapgenChanged(m); } @@ -644,9 +644,8 @@ break; default: QPixmap mapImage; - qDebug() << "Map data" << curIndex << chooseMap->currentText() << chooseMap->itemData(curIndex); QFile tmpfile; - tmpfile.setFileName(cfgdir->absolutePath() + "/Data//Maps/" + chooseMap->itemData(curIndex).toList()[0].toString() + "/preview.png"); + tmpfile.setFileName(cfgdir->absolutePath() + "/Data/Maps/" + chooseMap->itemData(curIndex).toList()[0].toString() + "/preview.png"); if (!tmpfile.exists()) tmpfile.setFileName(datadir->absolutePath() + "/Maps/" + chooseMap->itemData(curIndex).toList()[0].toString() + "/preview.png"); if(!mapImage.load(QFileInfo(tmpfile).absoluteFilePath())) { imageButt->setIcon(QIcon()); diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/pagedata.cpp --- a/QTfrontend/pagedata.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/pagedata.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -20,10 +20,19 @@ #include #include #include +#include #include #include +#include +#include +#include #include "pagedata.h" +#include "databrowser.h" +#include "hwconsts.h" + +#include "quazip.h" +#include "quazipfile.h" PageDataDownload::PageDataDownload(QWidget* parent) : AbstractPage(parent) { @@ -32,25 +41,181 @@ pageLayout->setColumnStretch(1, 1); pageLayout->setColumnStretch(2, 1); - BtnBack = addButton(":/res/Exit.png", pageLayout, 1, 0, true); + BtnBack = addButton(":/res/Exit.png", pageLayout, 2, 0, true); + + web = new DataBrowser(this); + connect(web, SIGNAL(anchorClicked(QUrl)), this, SLOT(request(const QUrl&))); + web->setOpenLinks(false); + pageLayout->addWidget(web, 0, 0, 1, 3); + + progressBarsLayout = new QVBoxLayout(); + pageLayout->addLayout(progressBarsLayout, 1, 0, 1, 3); + + fetchList(); +} + +void PageDataDownload::request(const QUrl &url) +{ + QUrl finalUrl; + if(url.host().isEmpty()) + finalUrl = QUrl("http://www.hedgewars.org" + url.path()); + else + finalUrl = url; + + if(url.path().endsWith(".zip")) + { + qWarning() << "Download Request" << url.toString(); + QString fileName = QFileInfo(url.toString()).fileName(); + + QNetworkRequest newRequest(finalUrl); + newRequest.setAttribute(QNetworkRequest::User, fileName); + + QNetworkAccessManager *manager = new QNetworkAccessManager(this); + QNetworkReply *reply = manager->get(newRequest); + connect(reply, SIGNAL(finished()), this, SLOT(fileDownloaded())); + connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64))); + + QProgressBar *progressBar = new QProgressBar(this); + progressBarsLayout->addWidget(progressBar); + progressBars.insert(reply, progressBar); + } else + { + qWarning() << "Page Request" << url.toString(); + + QNetworkRequest newRequest(finalUrl); - web = new QWebView(this); - connect(web, SIGNAL(linkClicked(const QUrl&)), this, SLOT(install(const QUrl&))); - web->load(QUrl("http://m8y.org/hw/downloads/")); - web->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); - pageLayout->addWidget(web, 0, 0, 1, 3); + QNetworkAccessManager *manager = new QNetworkAccessManager(this); + QNetworkReply *reply = manager->get(newRequest); + connect(reply, SIGNAL(finished()), this, SLOT(pageDownloaded())); + } +} + + +void PageDataDownload::pageDownloaded() +{ + QNetworkReply * reply = qobject_cast(sender()); + + if(reply) + { + QString html = QString::fromUtf8(reply->readAll()); + int begin = html.indexOf(""); + int end = html.indexOf(""); + if(begin != -1 && begin < end) + { + html.truncate(end); + html.remove(0, begin); + } + web->setHtml(html); + } +} + +void PageDataDownload::fileDownloaded() +{ + QNetworkReply * reply = qobject_cast(sender()); + + if(reply) + { + QByteArray fileContents = reply->readAll(); + QProgressBar *progressBar = progressBars.value(reply, 0); + + if(progressBar) + { + progressBars.remove(reply); + progressBar->deleteLater(); + } + + extractDataPack(&fileContents); + } } -void PageDataDownload::install(const QUrl &url) +void PageDataDownload::downloadProgress(qint64 bytesRecieved, qint64 bytesTotal) +{ + QNetworkReply * reply = qobject_cast(sender()); + + if(reply) + { + QProgressBar *progressBar = progressBars.value(reply, 0); + + if(progressBar) + { + progressBar->setValue(bytesRecieved); + progressBar->setMaximum(bytesTotal); + } + } +} + +void PageDataDownload::fetchList() { -qWarning("Download Request"); -QString fileName = QFileInfo(url.toString()).fileName(); + request(QUrl("http://hedgewars.org/content.html")); +} + +bool PageDataDownload::extractDataPack(QByteArray * buf) +{ + QBuffer buffer; + buffer.setBuffer(buf); + + QuaZip zip; + zip.setIoDevice(&buffer); + if(!zip.open(QuaZip::mdUnzip)) + { + qWarning("testRead(): zip.open(): %d", zip.getZipError()); + return false; + } + + QuaZipFile file(&zip); + + QDir extractDir(*cfgdir); + extractDir.cd("Data"); -QNetworkRequest newRequest(url); -newRequest.setAttribute(QNetworkRequest::User, fileName); + for(bool more = zip.goToFirstFile(); more; more = zip.goToNextFile()) + { + if(!file.open(QIODevice::ReadOnly)) + { + qWarning("file.open(): %d", file.getZipError()); + return false; + } + + + QString fileName = file.getActualFileName(); + QString filePath = extractDir.filePath(fileName); + if (fileName.endsWith("/")) + { + QFileInfo fi(filePath); + QDir().mkpath(fi.filePath()); + } else + { + qDebug() << "Extracting" << filePath; + QFile out(filePath); + if(!out.open(QFile::WriteOnly)) + { + qWarning() << "out.open():" << out.errorString(); + return false; + } -QNetworkAccessManager *manager = new QNetworkAccessManager(this); -QNetworkReply *reply = manager->get(newRequest); -//connect( reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64)) ); -//connect( reply, SIGNAL(finished()), this, SLOT(downloadIssueFinished())); + out.write(file.readAll()); + + out.close(); + + if(file.getZipError() != UNZ_OK) { + qWarning("file.getFileName(): %d", file.getZipError()); + return false; + } + + if(!file.atEnd()) { + qWarning("read all but not EOF"); + return false; + } + } + + file.close(); + + if(file.getZipError()!=UNZ_OK) { + qWarning("file.close(): %d", file.getZipError()); + return false; + } + } + + zip.close(); + + return true; } diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/pagedata.h --- a/QTfrontend/pagedata.h Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/pagedata.h Fri Sep 09 05:15:45 2011 +0200 @@ -18,10 +18,15 @@ #ifndef PAGE_DATA_H #define PAGE_DATA_H -#include + #include #include "AbstractPage.h" +class DataBrowser; +class QProgressBar; +class QNetworkReply; +class QVBoxLayout; + class PageDataDownload : public AbstractPage { Q_OBJECT @@ -30,10 +35,23 @@ PageDataDownload(QWidget* parent = 0); QPushButton *BtnBack; - QWebView *web; + +public slots: + void fetchList(); + +private: + DataBrowser *web; + QHash progressBars; + QVBoxLayout *progressBarsLayout; + + bool extractDataPack(QByteArray * buf); private slots: - void install(const QUrl &url); + void request(const QUrl &url); + + void pageDownloaded(); + void fileDownloaded(); + void downloadProgress(qint64, qint64); }; #endif diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/pagegamestats.cpp --- a/QTfrontend/pagegamestats.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/pagegamestats.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -47,6 +47,11 @@ BtnBack = addButton(":/res/Exit.png", pageLayout, 3, 0, true); BtnBack->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + BtnSave = addButton(":/res/Save.png", pageLayout, 3, 2, true); + BtnSave->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + BtnSave->setStyleSheet("QPushButton{margin: 12px 0px 12px 0px;}"); + connect(BtnSave, SIGNAL(clicked()), this, SIGNAL(saveDemoRequested())); + QGroupBox * gb = new QGroupBox(this); QVBoxLayout * gbl = new QVBoxLayout; @@ -62,7 +67,7 @@ gbl->addWidget(l); gbl->addWidget(labelGameStats); gb->setLayout(gbl); - pageLayout->addWidget(gb, 1, 1); + pageLayout->addWidget(gb, 1, 1, 1, 2); // graph graphic = new FitGraphicsView(gb); diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/pagegamestats.h --- a/QTfrontend/pagegamestats.h Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/pagegamestats.h Fri Sep 09 05:15:45 2011 +0200 @@ -44,6 +44,7 @@ PageGameStats(QWidget* parent = 0); QPushButton *BtnBack; + QPushButton *BtnSave; QLabel *labelGameStats; QLabel *labelGameWin; QLabel *labelGameRank; @@ -53,6 +54,9 @@ void GameStats(char type, const QString & info); void clear(); void renderStats(); + +signals: + void saveDemoRequested(); private: void AddStatText(const QString & msg); diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/pagemain.cpp --- a/QTfrontend/pagemain.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/pagemain.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -41,6 +41,7 @@ pageLayout->setRowStretch(2, 0); pageLayout->setRowStretch(3, 1); pageLayout->setRowStretch(4, 1); + pageLayout->setRowStretch(5, 1); BtnSinglePlayer = addButton(":/res/LocalPlay.png", pageLayout, 2, 0, 1, 2, true); BtnSinglePlayer->setToolTip(tr("Local Game (Play a game on a single computer)")); @@ -50,6 +51,9 @@ BtnNet->setToolTip(tr("Network Game (Play a game across a network)")); pageLayout->setAlignment(BtnNet, Qt::AlignHCenter); + BtnDataDownload = addButton(tr("Downloadable Content"), pageLayout, 4, 0, 1, 4, false); + pageLayout->setAlignment(BtnDataDownload, Qt::AlignHCenter); + mainNote = new QLabel(this); mainNote->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); mainNote->setWordWrap(true); @@ -119,9 +123,9 @@ else mainNote->setText(QLabel::tr("This development build is 'work in progress' and may not be compatible with other versions of the game. Some features might be broken or incomplete. Use at your own risk!")); - pageLayout->addWidget(mainNote, 4, 1, 1, 2); + pageLayout->addWidget(mainNote, 5, 1, 1, 2); - BtnSetup = addButton(":/res/Settings.png", pageLayout, 4, 3, true); + BtnSetup = addButton(":/res/Settings.png", pageLayout, 5, 3, true); //BtnInfo = addButton(":/res/About.png", pageLayout, 3, 1, 1, 2, true); BtnInfo = addButton(":/res/HedgewarsTitle.png", pageLayout, 0, 0, 1, 4, true); @@ -129,7 +133,7 @@ pageLayout->setAlignment(BtnInfo, Qt::AlignHCenter); //pageLayout->setAlignment(BtnInfo, Qt::AlignHCenter); - BtnExit = addButton(":/res/Exit.png", pageLayout, 4, 0, 1, 1, true); + BtnExit = addButton(":/res/Exit.png", pageLayout, 5, 0, 1, 1, true); BtnExit->setFixedHeight(BtnSetup->height()); BtnExit->setStyleSheet("QPushButton{margin-top: 2px;}"); } diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/pagemain.h --- a/QTfrontend/pagemain.h Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/pagemain.h Fri Sep 09 05:15:45 2011 +0200 @@ -33,6 +33,7 @@ QPushButton *BtnSetup; QPushButton *BtnInfo; QPushButton *BtnExit; + QPushButton *BtnDataDownload; QLabel *mainNote; }; diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/pageoptions.cpp --- a/QTfrontend/pageoptions.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/pageoptions.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -429,7 +429,6 @@ else this->CBResolution->setCurrentIndex(previousResolutionIndex); previousResolutionIndex = tmp; - this->CBResolution->setEnabled(!this->CBFullscreen->isChecked()); } void PageOptions::trimNetNick() diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/teamselect.cpp --- a/QTfrontend/teamselect.cpp Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/teamselect.cpp Fri Sep 09 05:15:45 2011 +0200 @@ -44,7 +44,7 @@ this, SLOT(proxyTeamColorChanged(const HWTeam&))); } else { frameDontPlaying->addTeam(team, false); - curDontPlayingTeams.push_back(team); + m_curNotPlayingTeams.push_back(team); if(m_acceptOuter) { connect(frameDontPlaying->getTeamWidget(team), SIGNAL(teamStatusChanged(HWTeam)), this, SLOT(pre_changeTeamStatus(HWTeam))); @@ -144,14 +144,14 @@ void TeamSelWidget::changeTeamStatus(HWTeam team) { - QList::iterator itDontPlay=std::find(curDontPlayingTeams.begin(), curDontPlayingTeams.end(), team); + QList::iterator itDontPlay=std::find(m_curNotPlayingTeams.begin(), m_curNotPlayingTeams.end(), team); QList::iterator itPlay=std::find(curPlayingTeams.begin(), curPlayingTeams.end(), team); - bool willBePlaying=itDontPlay!=curDontPlayingTeams.end(); + bool willBePlaying=itDontPlay!=m_curNotPlayingTeams.end(); if(!willBePlaying) { // playing team => dont playing - curDontPlayingTeams.push_back(*itPlay); + m_curNotPlayingTeams.push_back(*itPlay); emit teamNotPlaying(*itPlay); curPlayingTeams.erase(itPlay); } else { @@ -162,7 +162,7 @@ itDontPlay->teamColor=framePlaying->getNextColor(); curPlayingTeams.push_back(*itDontPlay); if(!m_acceptOuter) emit teamWillPlay(*itDontPlay); - curDontPlayingTeams.erase(itDontPlay); + m_curNotPlayingTeams.erase(itDontPlay); } FrameTeams* pRemoveTeams; @@ -253,10 +253,10 @@ //frameDontPlaying->removeTeam(*it); //} frameDontPlaying->resetTeams(); - curDontPlayingTeams.clear(); + m_curNotPlayingTeams.clear(); - QListIterator it(teamslist); - while(it.hasNext()) addTeam(it.next()); + foreach(HWTeam team, teamslist) + addTeam(team); } bool TeamSelWidget::isPlaying(HWTeam team) const @@ -269,9 +269,9 @@ return curPlayingTeams; } -QList TeamSelWidget::getDontPlayingTeams() const +QList TeamSelWidget::getNotPlayingTeams() const { - return curDontPlayingTeams; + return m_curNotPlayingTeams; } void TeamSelWidget::pre_changeTeamStatus(HWTeam team) diff -r 5ab22736bdb6 -r 2e5835130d9a QTfrontend/teamselect.h --- a/QTfrontend/teamselect.h Fri Sep 09 04:39:17 2011 +0200 +++ b/QTfrontend/teamselect.h Fri Sep 09 05:15:45 2011 +0200 @@ -45,7 +45,7 @@ void resetPlayingTeams(const QList& teamslist); bool isPlaying(HWTeam team) const; QList getPlayingTeams() const; - QList getDontPlayingTeams() const; + QList getNotPlayingTeams() const; void setInteractivity(bool interactive); public slots: @@ -77,7 +77,7 @@ bool m_acceptOuter; QList curPlayingTeams; - QList curDontPlayingTeams; + QList m_curNotPlayingTeams; }; #endif // _TEAM_SELECT_INCLUDED diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/GSHandlers.inc Fri Sep 09 05:15:45 2011 +0200 @@ -103,6 +103,35 @@ end; end; +procedure HideHog(HH: PHedgehog); +begin +ScriptCall('onHogHide', HH^.Gear^.Uid); +DeleteCI(HH^.Gear); +if FollowGear = HH^.Gear then FollowGear:= nil; +if lastGearByUID = HH^.Gear then lastGearByUID := nil; +RemoveGearFromList(HH^.Gear); +with HH^.Gear^ do + begin + Z := cHHZ; + Active := false; + State:= State and not (gstHHDriven or gstAttacking or gstAttacked); + Message := Message and not gmAttack; + end; +HH^.GearHidden:= HH^.Gear; +HH^.Gear:= nil; +end; + +procedure RestoreHog(HH: PHedgehog); +begin +HH^.Gear:=HH^.GearHidden; +HH^.GearHidden:= nil; +InsertGearToList(HH^.Gear); +HH^.Gear^.State:= (HH^.Gear^.State and not (gstHHDriven or gstInvisible or gstAttacking)) or gstAttacked; +AddGearCI(HH^.Gear); +HH^.Gear^.Active:= true; +ScriptCall('onHogRestore', HH^.Gear^.Uid) +end; + //////////////////////////////////////////////////////////////////////////////// procedure doStepDrowningGear(Gear: PGear); forward; @@ -766,8 +795,9 @@ procedure doStepBeeWork(Gear: PGear); var t: hwFloat; - gX,gY: LongInt; + gX,gY,i: LongInt; nuw: boolean; + flower: PVisualGear; const uw: boolean = false; begin @@ -816,6 +846,21 @@ begin StopSound(Gear^.SoundChannel); doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound); + for i:= 0 to 31 do + begin + flower:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot); + if flower <> nil then + with flower^ do + begin + Scale:= 0.75; + dx:= 0.001 * (random(200)); + dy:= 0.001 * (random(200)); + if random(2) = 0 then dx := -dx; + if random(2) = 0 then dy := -dy; + FrameTicks:= random(250) + 250; + State:= ord(sprTargetBee); + end; + end; DeleteGear(Gear); end; end; @@ -1110,7 +1155,8 @@ AllInactive := false; HHGear := Gear^.Hedgehog^.Gear; dec(Gear^.Timer); - if (Gear^.Timer = 0)or((Gear^.Message and gmDestroy) <> 0)or((HHGear^.State and gstHHDriven) = + if ((GameFlags and gfInfAttack) <> 0) and (TurnTimeLeft > 0) then dec(TurnTimeLeft); + if (TurnTimeLeft = 0) or (Gear^.Timer = 0)or((Gear^.Message and gmDestroy) <> 0)or((HHGear^.State and gstHHDriven) = 0) then begin StopSound(Gear^.SoundChannel); @@ -1219,6 +1265,8 @@ begin AllInactive := false; dec(Gear^.Timer); + if ((GameFlags and gfInfAttack) <> 0) and (TurnTimeLeft > 0) then dec(TurnTimeLeft); + HHGear := Gear^.Hedgehog^.Gear; HedgehogChAngle(HHGear); @@ -1286,7 +1334,7 @@ Gear^.dX, Gear^.dY, cHHRadius * 5, cHHRadius * 2 + 7); - if (Gear^.Timer = 0) or ((HHGear^.Message and gmAttack) <> 0) then + if (TurnTimeLeft = 0) or (Gear^.Timer = 0) or ((HHGear^.Message and gmAttack) <> 0) then begin HHGear^.Message := 0; HHGear^.State := HHGear^.State and (not gstNotKickable); @@ -2884,7 +2932,7 @@ dec(Gear^.Health); Gear^.Timer := Gear^.Health*10; - Gear^.PortalCounter:= 0; + if Gear^.Health mod 100 = 0 then Gear^.PortalCounter:= 0; // This is not seconds, but at least it is *some* feedback if (Gear^.Health = 0) or ((Gear^.Message and gmAttack) <> 0) then begin @@ -3019,7 +3067,7 @@ if random(2) = 0 then dx := -dx; if random(2) = 0 then dy := -dy; FrameTicks:= random(750) + 1000; - heart^.State:= ord(sprSeduction) + State:= ord(sprSeduction) end; end; @@ -3925,8 +3973,7 @@ // inverse cake's normal movement direction, // as if it just walked through a hole - if iscake then - nspeed.isNegative:= not nspeed.isNegative; + //if iscake then nspeed.isNegative:= not nspeed.isNegative; //AddFileLog('poffs:'+cstr(poffs)+' noffs:'+cstr(noffs)+' pspeed:'+cstr(pspeed)+' nspeed:'+cstr(nspeed)); iterator^.dX := -pspeed * conPortal^.dX + nspeed * nx; @@ -3977,8 +4024,8 @@ iterator^.Radius := iterator^.Radius - 1; // check front - isCollision := TestCollisionYwithGear(iterator, sy) - or TestCollisionXwithGear(iterator, sx); + isCollision := TestCollisionY(iterator, sy) + or TestCollisionX(iterator, sx); if not isCollision then begin @@ -3986,8 +4033,8 @@ // the square check won't check more pixels than we want to) iterator^.Radius := 1 + resetr div 2; rh := resetr div 4; - isCollision := TestCollisionYwithXYShift(iterator, 0, -sy * rh, sy) - or TestCollisionXwithXYShift(iterator, ox * rh, 0, sx); + isCollision := TestCollisionYwithXYShift(iterator, 0, -sy * rh, sy, false) + or TestCollisionXwithXYShift(iterator, ox * rh, 0, sx, false); end; iterator^.Radius := resetr; @@ -4008,7 +4055,8 @@ // // Until loops are reliably broken - inc(iterator^.PortalCounter); + if iscake then iterator^.PortalCounter:= 33 + else inc(iterator^.PortalCounter); if not isbullet and (iterator^.Kind <> gtFlake) then FollowGear := iterator; @@ -4921,38 +4969,26 @@ HH:= Gear^.Hedgehog; if Gear^.Pos = 2 then begin + StopSound(Gear^.SoundChannel); if (Gear^.Timer = 0) then begin if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible = 0) then begin - AfterAttack; + AfterAttack; if Gear = CurAmmoGear then CurAmmoGear := nil; - DeleteCI(HH^.Gear); - RemoveGearFromList(HH^.Gear); - with HH^.Gear^ do - begin - Z := cHHZ; - Active := false; - State:= State and not (gstHHDriven or gstAttacking or gstAttacked); - Message := Message and not gmAttack; - end; - HH^.GearHidden:= HH^.Gear; - HH^.Gear:= nil + HideHog(HH) end - else if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible <> 0) then - begin - InsertGearToList(HH^.Gear); - HH^.Gear^.State:= HH^.Gear^.State and not (gstHHDriven or gstInvisible); - AddGearCI(HH^.Gear); - HH^.Gear^.Active:= true - end; + //else if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible <> 0) then + else if (HH^.GearHidden <> nil) then// and (HH^.Gear^.State and gstInvisible <> 0) then + RestoreHog(HH) end; inc(Gear^.Timer); if (Gear^.Timer > 2000) and ((GameTicks mod 2000) = 1000) then begin - Gear^.Pos:= 3; - end; + Gear^.SoundChannel := LoopSound(sndTardis); + Gear^.Pos:= 3 + end end; if (Gear^.Pos = 1) and (GameTicks and $1F = 0) and (Gear^.Power < 255) then inc(Gear^.Power); @@ -4960,6 +4996,7 @@ if (Gear^.Pos = 1) and (Gear^.Power = 255) and ((GameTicks mod 2000) = 1000) then Gear^.Pos:= 2; if (Gear^.Pos = 3) and (Gear^.Power = 0) then begin + StopSound(Gear^.SoundChannel); if HH^.GearHidden = nil then begin DeleteGear(Gear); @@ -4981,17 +5018,18 @@ HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.Damage) then inc(cnt); if (cnt = 0) or SuddenDeathDmg or (Gear^.Timer = 0) then begin + Gear^.SoundChannel := LoopSound(sndTardis); Gear^.Pos:= 1; Gear^.Power:= 0; Gear^.Timer:= 0; if HH^.GearHidden <> nil then FindPlace(HH^.GearHidden, false, 0, LAND_WIDTH,true); if HH^.GearHidden <> nil then begin - HH^.Gear:=HH^.GearHidden; - HH^.GearHidden:= nil; - HH^.Gear^.State:= HH^.Gear^.State or gstInvisible; - Gear^.X:= HH^.Gear^.X; - Gear^.Y:= HH^.Gear^.Y; + Gear^.X:= HH^.GearHidden^.X; + Gear^.Y:= HH^.GearHidden^.Y; + //HH^.Gear:=HH^.GearHidden; + //HH^.GearHidden:= nil; + //HH^.Gear^.State:= HH^.Gear^.State or gstInvisible; end end else dec(Gear^.Timer); @@ -5039,6 +5077,7 @@ DeleteGear(gear); exit end; + Gear^.SoundChannel := LoopSound(sndTardis); Gear^.doStep:= @doStepTardisWarp end; diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/HHHandlers.inc --- a/hedgewars/HHHandlers.inc Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/HHHandlers.inc Fri Sep 09 05:15:45 2011 +0200 @@ -1012,7 +1012,7 @@ //////////////////////////////////////////////////////////////////////////////// procedure doStepHedgehogFree(Gear: PGear); -var prevState: Longword; +var prevState,i: Longword; begin prevState:= Gear^.State; @@ -1050,6 +1050,19 @@ begin Gear^.State:= Gear^.State or gstHHGone; Gear^.doStep:= @doStepHedgehogGone; + + with Gear^.Hedgehog^.Team^ do + for i:= 0 to cMaxHHIndex do + if Hedgehogs[i].GearHidden <> nil then + begin + RestoreHog(@Hedgehogs[i]); + if Hedgehogs[i].Gear <> nil then + begin + Hedgehogs[i].Gear^.State:= Gear^.State or gstHHGone; + Hedgehogs[i].Gear^.doStep:= @doStepHedgehogGone + end + end; + // Gone message AddCaption(Format(GetEventString(eidGone), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage); end diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/SDLh.pas --- a/hedgewars/SDLh.pas Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/SDLh.pas Fri Sep 09 05:15:45 2011 +0200 @@ -35,7 +35,7 @@ {$ENDIF} {$IFDEF UNIX} - {$IFNDEF DARWIN} + {$IFNDEF DARWIN} {$linklib c} {$ENDIF} {$IFDEF HAIKU} @@ -291,6 +291,11 @@ IMG_INIT_PNG = $00000002; IMG_INIT_TIF = $00000004; + {* SDL_EventMask type definition *} +{$IFNDEF SDL13} + SDL_ALLEVENTS = $FFFFFFFF; +{$ENDIF} + ///////////////////////////////////////////////////////////////// /////////////////////// TYPE DEFINITIONS /////////////////////// ///////////////////////////////////////////////////////////////// @@ -359,7 +364,7 @@ alpha: Byte; {$ENDIF} end; - + SDL_eventaction = (SDL_ADDEVENT = 0, SDL_PEEPEVENT, SDL_GETEVENT); PSDL_Surface = ^TSDL_Surface; @@ -488,7 +493,7 @@ type_: LongInt; windowID: LongInt; padding1, padding2: byte; - x, y, z,xrel, yrel : LongInt; + x, y, z, xrel, yrel : LongInt; pressure, pressure_max, pressure_min, rotation, tilt, cursor: LongInt; {$ELSE} @@ -642,6 +647,10 @@ {$ENDIF} end; + + TSDL_EventFilter = function( event : PSDL_Event ): Integer; cdecl; + + PByteArray = ^TByteArray; TByteArray = array[0..65535] of Byte; PLongWordArray = ^TLongWordArray; @@ -822,12 +831,12 @@ function SDL_PixelFormatEnumToMasks(format: TSDL_ArrayByteOrder; bpp: PLongInt; Rmask, Gmask, Bmask, Amask: PLongInt): boolean; cdecl; external SDLLibName; -procedure SDL_WarpMouseInWindow(window: PSDL_Window; x, y: LongInt); cdecl; external SDLLibName ; - -function SDL_SetHint(name, value: PChar): boolean; cdecl; external SDLLibName; +procedure SDL_WarpMouseInWindow(window: PSDL_Window; x, y: LongInt); cdecl; external SDLLibName; +function SDL_SetHint(name, value: PChar): boolean; cdecl; external SDLLibName; function SDL_PeepEvents(event: PSDL_Event; numevents: LongInt; action: SDL_eventaction; minType, maxType: LongInt): LongInt; cdecl; external SDLLibName; - +{$ELSE} +function SDL_PeepEvents(event: PSDL_Event; numevents: LongInt; action: SDL_eventaction; mask: LongInt): LongInt; cdecl; external SDLLibName; {$ENDIF} function SDL_GetMouseState(x, y: PLongInt): Byte; cdecl; external SDLLibName; @@ -836,6 +845,7 @@ procedure SDL_PumpEvents; cdecl; external SDLLibName; function SDL_PollEvent(event: PSDL_Event): LongInt; cdecl; external SDLLibName; function SDL_WaitEvent(event: PSDL_Event): LongInt; cdecl; external SDLLibName; +procedure SDL_SetEventFilter( filter : TSDL_EventFilter ); cdecl; external SDLLibName; function SDL_ShowCursor(toggle: LongInt): LongInt; cdecl; external SDLLibName; @@ -890,6 +900,7 @@ function TTF_RenderUTF8_Solid(font: PTTF_Font; const text: PChar; fg: TSDL_Color): PSDL_Surface; cdecl; external SDL_TTFLibName; function TTF_RenderUTF8_Blended(font: PTTF_Font; const text: PChar; fg: TSDL_Color): PSDL_Surface; cdecl; external SDL_TTFLibName; function TTF_RenderUTF8_Shaded(font: PTTF_Font; const text: PChar; fg, bg: TSDL_Color): PSDL_Surface; cdecl; external SDL_TTFLibName; + function TTF_OpenFont(const filename: PChar; size: LongInt): PTTF_Font; cdecl; external SDL_TTFLibName; procedure TTF_SetFontStyle(font: PTTF_Font; style: LongInt); cdecl; external SDL_TTFLibName; @@ -1020,4 +1031,6 @@ (PByteArray(buf)^[1] shl 16) or (PByteArray(buf)^[0] shl 24) end; + end. + diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/VGSHandlers.inc --- a/hedgewars/VGSHandlers.inc Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/VGSHandlers.inc Fri Sep 09 05:15:45 2011 +0200 @@ -596,6 +596,7 @@ One possible solution is, instead of using WorldDx, to use straight gl/SDL calls to jitter the screen a bit. // a comment by unC0Rr: instead of changing WorldDx shake cursor coordinates, that should be safe +// ... seems to still desync, and I tried banning when targetting too if (Gear^.Timer and 5) = 0 then begin @@ -603,6 +604,7 @@ ShakeCamera(maxMovement); end; *) + if Gear^.Timer > 250 then DeleteVisualGear(Gear); end; @@ -611,6 +613,9 @@ gX,gY: LongInt; vg: PVisualGear; begin +ScreenFade:= sfFromWhite; +ScreenFadeValue:= 250; +ScreenFadeSpeed:= 5; gX:= round(Gear^.X); gY:= round(Gear^.Y); AddVisualGear(gX, gY, vgtSmokeRing); diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/hwengine.pas Fri Sep 09 05:15:45 2011 +0200 @@ -150,12 +150,12 @@ PrevTime:= SDL_GetTicks; while isTerminated = false do begin -{$IFDEF ANDROID} - SDL_PumpEvents(); + SDL_PumpEvents(); + {$IFDEF SDL13} while SDL_PeepEvents(@event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0 do -{$ELSE} - while SDL_PollEvent(@event) <> 0 do -{$ENDIF} + {$ELSE} + while SDL_PeepEvents(@event, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0 do + {$ENDIF} begin case event.type_ of SDL_KEYDOWN: if GameState = gsChat then @@ -184,14 +184,13 @@ onFocusStateChanged() end; SDL_VIDEORESIZE: begin - // using lower values causes widget overlap and video issues - if event.resize.w > cMinScreenWidth then cScreenWidth:= event.resize.w - else cScreenWidth:= cMinScreenWidth; - if event.resize.h > cMinScreenHeight then cScreenHeight:= event.resize.h - else cScreenHeight:= cMinScreenHeight; - ParseCommand('fullscr '+intToStr(LongInt(cFullScreen)), true); - WriteLnToConsole('window resize'); - InitCameraBorders(); + // using lower values than cMinScreenWidth or cMinScreenHeight causes widget overlap and off-screen widget parts + // Change by sheepluva: + // Let's only use even numbers for custom width/height since I ran into scaling issues with odd width values. + // Maybe just fixes the symptom not the actual cause(?), I'm too tired to find out :P + cNewScreenWidth:= max(2 * (event.resize.w div 2), cMinScreenWidth); + cNewScreenHeight:= max(2 * (event.resize.h div 2), cMinScreenHeight); + cScreenResizeDelay:= RealTicks+500; end; {$ENDIF} SDL_JOYAXISMOTION: ControllerAxisEvent(event.jaxis.which, event.jaxis.axis, event.jaxis.value); @@ -201,6 +200,16 @@ SDL_QUITEV: isTerminated:= true end; //end case event.type_ of end; //end while SDL_PollEvent(@event) <> 0 do + if (cScreenResizeDelay <> 0) and (cScreenResizeDelay < RealTicks) and ((cNewScreenWidth <> cScreenWidth) or (cNewScreenHeight <> cScreenHeight)) then + begin + cScreenResizeDelay:= 0; + cScreenWidth:= cNewScreenWidth; + cScreenHeight:= cNewScreenHeight; + + ParseCommand('fullscr '+intToStr(LongInt(cFullScreen)), true); + WriteLnToConsole('window resize: ' + IntToStr(cScreenWidth) + ' x ' + IntToStr(cScreenHeight)); + InitCameraBorders() + end; if isTerminated = false then begin @@ -253,12 +262,10 @@ recordFileName:= gameArgs[10]; cStereoMode:= smNone; {$ENDIF} - cMinScreenWidth:= cScreenWidth; - cMinScreenHeight:= cScreenHeight; + cMinScreenWidth:= min(cScreenWidth, cMinScreenWidth); + cMinScreenHeight:= min(cScreenHeight, cMinScreenHeight); cOrigScreenWidth:= cScreenWidth; cOrigScreenHeight:= cScreenHeight; - if 480 < cMinScreenWidth then cMinScreenWidth:= 480; - if 320 < cMinScreenHeight then cMinScreenHeight:= 320; initEverything(true); WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (network protocol: ' + inttostr(cNetProtoVersion) + ')'); diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/uAmmos.pas --- a/hedgewars/uAmmos.pas Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/uAmmos.pas Fri Sep 09 05:15:45 2011 +0200 @@ -215,7 +215,7 @@ FillAmmoStore(hhammo, ammos); CurWeapon:= GetAmmoEntry(Hedgehog); with Hedgehog, CurWeapon^ do - if Count = 0 then + if (Count = 0) or (AmmoType = amNothing) then begin PackAmmo(Ammo, Ammoz[AmmoType].Slot); CurAmmoType:= amNothing diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/uCollisions.pas --- a/hedgewars/uCollisions.pas Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/uCollisions.pas Fri Sep 09 05:15:45 2011 +0200 @@ -47,8 +47,8 @@ function TestCollisionX(Gear: PGear; Dir: LongInt): boolean; function TestCollisionY(Gear: PGear; Dir: LongInt): boolean; -function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean; -function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): boolean; +function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean = true): boolean; +function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean = true): boolean; function calcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): Boolean; @@ -291,11 +291,13 @@ end end; -function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean; +function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean = true): boolean; begin Gear^.X:= Gear^.X + ShiftX; Gear^.Y:= Gear^.Y + int2hwFloat(ShiftY); -TestCollisionXwithXYShift:= TestCollisionXwithGear(Gear, Dir); +if withGear then + TestCollisionXwithXYShift:= TestCollisionXwithGear(Gear, Dir) +else TestCollisionXwithXYShift:= TestCollisionX(Gear, Dir); Gear^.X:= Gear^.X - ShiftX; Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY) end; @@ -337,11 +339,12 @@ TestCollisionY:= false end; -function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): boolean; +function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean = true): boolean; begin Gear^.X:= Gear^.X + int2hwFloat(ShiftX); Gear^.Y:= Gear^.Y + int2hwFloat(ShiftY); -TestCollisionYwithXYShift:= TestCollisionYwithGear(Gear, Dir); +if withGear then TestCollisionYwithXYShift:= TestCollisionYwithGear(Gear, Dir) +else TestCollisionYwithXYShift:= TestCollisionY(Gear, Dir); Gear^.X:= Gear^.X - int2hwFloat(ShiftX); Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY) end; diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/uGame.pas --- a/hedgewars/uGame.pas Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/uGame.pas Fri Sep 09 05:15:45 2011 +0200 @@ -73,7 +73,7 @@ SetBinds(CurrentTeam^.Binds); //CurrentHedgehog^.Gear^.Message:= 0; <- produces bugs with further save restoring and demos isSoundEnabled:= isSEBackup; - if isSoundEnabled then playMusic; + PlayMusic; GameType:= gmtLocal; AddVisualGear(0, 0, vgtTeamHealthSorter); AddVisualGear(0, 0, vgtSmoothWindBar); diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/uGears.pas --- a/hedgewars/uGears.pas Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/uGears.pas Fri Sep 09 05:15:45 2011 +0200 @@ -43,6 +43,8 @@ function GetAmmo: TAmmoType; function GetUtility: TAmmoType; procedure ResurrectHedgehog(gear: PGear); +procedure HideHog(HH: PHedgehog); +procedure RestoreHog(HH: PHedgehog); procedure ProcessGears; procedure EndTurnCleanup; procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource); @@ -944,7 +946,7 @@ end; if delay2 = 0 then begin - if (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.State and gstAttacked = 0) then SweepDirty; + if (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.State and gstAttacked = 0) and (CurAmmoGear = nil) then SweepDirty; CheckNoDamage; AliveCount:= 0; // shorter version of check for win to allow typical step activity to proceed for i:= 0 to Pred(ClansCount) do @@ -991,7 +993,10 @@ if ((GameTicks and $FFFF) = $FFFF) then begin if (not CurrentTeam^.ExtDriven) then - SendIPCTimeInc; + begin + SendIPC('#'); + AddFileLog('hiTicks increment message sent') + end; if (not CurrentTeam^.ExtDriven) or CurrentTeam^.hasGone then inc(hiTicks) // we do not recieve a message for this @@ -1747,7 +1752,6 @@ if (t > 0) then begin t:= GetRandom(t); - AddFileLog(inttostr(t)+' --------------'); while t >= 0 do begin inc(i); diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/uGearsRender.pas --- a/hedgewars/uGearsRender.pas Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/uGearsRender.pas Fri Sep 09 05:15:45 2011 +0200 @@ -1073,23 +1073,34 @@ //DrawTexture(x, y, SpritesData[sprVampiric].Texture, 0.1); Tint($FF, $FF, $FF, $FF); end - else if not isInLag then + else //if not isInLag then begin + if isInLag and (Gear^.FlightTime < 256) then inc(Gear^.FlightTime, 8) + else if not isInLag and (Gear^.FlightTime > 0) then dec(Gear^.FlightTime, 8); + if Gear^.FlightTime > 0 then Tint($FF, $FF, $FF, $FF-min(255,Gear^.FlightTime)); if vobVelocity = 0 then DrawSprite(sprFlake, x, y, Gear^.Timer) else - DrawRotatedF(sprFlake, x, y, Gear^.Timer, 1, Gear^.DirAngle) + DrawRotatedF(sprFlake, x, y, Gear^.Timer, 1, Gear^.DirAngle); //DrawSprite(sprFlake, x-SpritesData[sprFlake].Width div 2, y-SpritesData[sprFlake].Height div 2, Gear^.Timer) //DrawRotatedF(sprFlake, x-SpritesData[sprFlake].Width div 2, y-SpritesData[sprFlake].Height div 2, Gear^.Timer, 1, Gear^.DirAngle); + if Gear^.FlightTime > 0 then Tint($FF, $FF, $FF, $FF); end; gtStructure: DrawSprite(sprTarget, x - 16, y - 16, 0); gtTardis: if Gear^.Pos <> 4 then begin - if (Gear^.Pos = 1) or (Gear^.Pos = 3) then - Tint($FF, $FF, $FF, max($00, round(Gear^.Power * (1-abs(0.5 - (GameTicks mod 2000) / 2000))))); + if Gear^.Pos = 2 then Tint(Gear^.Hedgehog^.Team^.Clan^.Color shl 8 or $FF) + else Tint(Gear^.Hedgehog^.Team^.Clan^.Color shl 8 or max($00, round(Gear^.Power * (1-abs(0.5 - (GameTicks mod 2000) / 2000))))); DrawSprite(sprTardis, x-24, y-63,0); - if (Gear^.Pos = 1) or (Gear^.Pos = 3) then - Tint($FF, $FF, $FF, $FF) + if Gear^.Pos = 2 then Tint($FF, $FF, $FF, $FF) + else Tint($FF,$FF,$FF,max($00, round(Gear^.Power * (1-abs(0.5 - (GameTicks mod 2000) / 2000))))); + DrawSprite(sprTardis, x-24, y-63,1); + if Gear^.Pos <> 2 then Tint($FF, $FF, $FF, $FF) +(* + Tint(Gear^.Hedgehog^.Team^.Clan^.Color shl 8 or max($00, round(Gear^.Power * abs(1 - (RealTicks mod 500) / 250)))); + DrawTexture(x-6, y-70, SpritesData[sprVampiric].Texture, 0.25); + Tint($FF, $FF, $FF, $FF) +*) end; diff -r 5ab22736bdb6 -r 2e5835130d9a hedgewars/uIO.pas --- a/hedgewars/uIO.pas Fri Sep 09 04:39:17 2011 +0200 +++ b/hedgewars/uIO.pas Fri Sep 09 05:15:45 2011 +0200 @@ -29,7 +29,6 @@ procedure SendIPCXY(cmd: char; X, Y: SmallInt); procedure SendIPCRaw(p: pointer; len: Longword); procedure SendIPCAndWaitReply(s: shortstring); -procedure SendIPCTimeInc; procedure SendKeepAliveMessage(Lag: Longword); procedure LoadRecordFromFile(fileName: shortstring); procedure SendStat(sit: TStatInfoType; s: shortstring); @@ -246,13 +245,6 @@ SendIPC(s) end; -procedure SendIPCTimeInc; -const timeinc: shortstring = '#'; -begin -AddFileLog('[IPC out]