# HG changeset patch # User nemo # Date 1316201162 14400 # Node ID d4680c51b220fec1d13ea8557dfcfbb328256e0a # Parent 2de4fa7102bf8329029615ed9653dc635a360ec7# Parent f5dcef0bb8b97e63b4c32da3edefd03887b348c1 merge diff -r f5dcef0bb8b9 -r d4680c51b220 .hgtags --- a/.hgtags Thu Sep 08 00:34:57 2011 +0200 +++ b/.hgtags Fri Sep 16 15:26:02 2011 -0400 @@ -42,3 +42,5 @@ 0000000000000000000000000000000000000000 0.9.9 fee68e3a303998fdfcc69f74775dc84a36f587fb 0.9.9.1 0000000000000000000000000000000000000000 0.9.9.1 +718f98a9df122d73f3ba9add4d1654865199de31 Hedgewars-iOS-1.3 +cba92708277b6d0aeabfff2b878845b7d848bdcd Hedgewars-iOS-1.3.1 diff -r f5dcef0bb8b9 -r d4680c51b220 CMakeLists.txt --- a/CMakeLists.txt Thu Sep 08 00:34:57 2011 +0200 +++ b/CMakeLists.txt Fri Sep 16 15:26:02 2011 -0400 @@ -194,6 +194,7 @@ if(NOT BUILD_ENGINE_LIBRARY) add_subdirectory(bin) + add_subdirectory(misc/quazip) add_subdirectory(QTfrontend) add_subdirectory(share) add_subdirectory(tools) diff -r f5dcef0bb8b9 -r d4680c51b220 ChangeLog.txt --- a/ChangeLog.txt Thu Sep 08 00:34:57 2011 +0200 +++ b/ChangeLog.txt Fri Sep 16 15:26:02 2011 -0400 @@ -2,19 +2,27 @@ * bugfixes 0.9.15 -> ???: - + New modes: The Specialists, Space Invasion + + Stereoscopic rendering + Installing content (anything under Data/ - maps, sounds, and any such stuff) to user profile allows custom adding/overriding of any Data/ content - + Sudden Death art + + Screen for downloadable content + + Allow up to 8 teams in a game + + New gameplay modes/styles: Racer, The Specialists, Tumbler, Space Invasion + New Weapon/Utility: Land Spray Gun + + New Utility: Time Box + New Game mode: Tag team + + New Game option for map bottom border + + New Theme: Golf + + Many new hats + + Sudden Death art + 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) + Defective mines explode if they take enough damage + Rope head can attach to hogs/crates/barrels again (rope still passes through them) + Control of grenade bounce + Drill Strike bombs don't explode when leaving ground, but after a (customizable!) timer + + Hammer impacts mines/barrels + + Seduction is an Area-of-Effect attack now + Ukranian localization of Default voice. support for localized voices + Theme cleanup, including the new theme config file change + Improvements in scoring and tracking damage @@ -22,13 +30,20 @@ + Mudball does not end turn + 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) + + Improved lua script support (e.g. set per-hog ammo, place girders, spawn fake crates, switch hogs, change hats) + + The names of the ShoppaKingTournament winners are now written on the Trophies in the ShoppaKing and TrophyRace maps! + + Allow window resizes during game + + Improved fullscreen capabilities + + Additional/new sounds (mine impact, sine gun, etc) + + Victory/flawless victory sounds + * Voices don't overlap (was needed more due to faster game actions due to shortened delays) * Prevent portaling to impossible locations better * Snow accumulates more smoothly * Rope should be less sticky now + * Rope shouldn't be able to get Hogs stuck on walls anymore * Fix for last portal shot always being yellow * More accurate napalm strike drop location - * AI fixes + * AI fixes (heh, yeah right) * Fixed locales, such as korean * Code refactoring * Various bug/leak fixes @@ -39,6 +54,7 @@ + Improved nick sorting in lobby and rooms. (not case-sensitive, letters first, friend @ top, ignored @ bottom) + Display player count in lobby + Lobby: Player names of online players can be clicked in chat directly so that you don't have to find them in the player list + + Room names can be changed by the room admin without recreating the room * Fix invisible icons in popup menus * Various fixes and adjustments diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/CMakeLists.txt --- a/QTfrontend/CMakeLists.txt Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/CMakeLists.txt Fri Sep 16 15:26:02 2011 -0400 @@ -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) @@ -13,6 +12,16 @@ find_package(Qt4 REQUIRED) include(${QT_USE_FILE}) +# Check if we need zlib +check_library_exists(${QT_QTCORE_LIBRARY} inflateInit2_ ${QT_LIBRARY_DIR} QT_PROVIDES_ZLIB_FUNCTIONS) + +if(NOT QT_PROVIDES_ZLIB_FUNCTIONS) + find_package(ZLIB REQUIRED) + + set(HW_LINK_LIBS ${ZLIB_LIBRARIES} ${HW_LINK_LIBS}) +endif() + + # Configure for SDL find_package(SDL REQUIRED) find_package(SDL_mixer REQUIRED) @@ -20,6 +29,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 +125,7 @@ drawmapwidget.cpp drawmapscene.cpp themesmodel.cpp + databrowser.cpp ) #xfire integration @@ -196,6 +207,7 @@ drawmapwidget.h drawmapscene.h themesmodel.h + databrowser.h ) set(hwfr_hdrs @@ -214,7 +226,7 @@ if(APPLE) set(hwfr_src ${hwfr_src} InstallController.cpp CocoaInitializer.mm M3Panel.mm M3InstallController.m NSWorkspace_RBAdditions.m) - set(HW_LINK_LIBS IOKit) + set(HW_LINK_LIBS IOKit ${HW_LINK_LIBS}) if(NOT NOAUTOUPDATE) find_package(Sparkle) @@ -236,6 +248,7 @@ set(HW_LINK_LIBS + quazip ${QT_LIBRARIES} ${SDL_LIBRARY} ${SDLMIXER_LIBRARY} @@ -247,7 +260,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 +270,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 f5dcef0bb8b9 -r d4680c51b220 QTfrontend/binds.cpp --- a/QTfrontend/binds.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/binds.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -62,9 +62,7 @@ {"confirm", "y", QT_TRANSLATE_NOOP("binds", "confirmation"), NULL, NULL}, {"+voldown", "9", QT_TRANSLATE_NOOP("binds", "volume down"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Modify the game's volume while playing:")}, {"+volup", "0", QT_TRANSLATE_NOOP("binds", "volume up"), NULL, NULL}, -#ifndef _WIN32 {"fullscr", "f12", QT_TRANSLATE_NOOP("binds", "change mode"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle fullscreen mode:")}, -#endif {"capture", "c", QT_TRANSLATE_NOOP("binds", "capture"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Take a screenshot:")}, {"rotmask", "delete", QT_TRANSLATE_NOOP("binds", "hedgehogs\ninfo"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle labels above hedgehogs:")} }; diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/binds.h --- a/QTfrontend/binds.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/binds.h Fri Sep 16 15:26:02 2011 -0400 @@ -21,11 +21,7 @@ #include -#ifdef _WIN32 -#define BINDS_NUMBER 43 -#else #define BINDS_NUMBER 44 -#endif struct BindAction { diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/chatwidget.cpp --- a/QTfrontend/chatwidget.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/chatwidget.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -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 f5dcef0bb8b9 -r d4680c51b220 QTfrontend/databrowser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/databrowser.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -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 f5dcef0bb8b9 -r d4680c51b220 QTfrontend/databrowser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/databrowser.h Fri Sep 16 15:26:02 2011 -0400 @@ -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 f5dcef0bb8b9 -r d4680c51b220 QTfrontend/drawmapscene.cpp --- a/QTfrontend/drawmapscene.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/drawmapscene.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -108,11 +108,32 @@ emit pathChanged(); } + else if(oldItems.size()) + { + while(oldItems.size()) + addItem(oldItems.takeFirst()); + paths = oldPaths; + + emit pathChanged(); + } } void DrawMapScene::clearMap() { - clear(); + // don't clear if already cleared + if(!items().size()) + return; + + oldItems.clear(); + + // do this since clear() would _destroy_ all items + while(items().size()) { + oldItems.push_front(items().first()); + removeItem(items().first()); + } + + oldPaths = paths; + paths.clear(); emit pathChanged(); @@ -146,6 +167,8 @@ void DrawMapScene::decode(QByteArray data) { + oldItems.clear(); + oldPaths.clear(); clear(); paths.clear(); diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/drawmapscene.h --- a/QTfrontend/drawmapscene.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/drawmapscene.h Fri Sep 16 15:26:02 2011 -0400 @@ -48,6 +48,8 @@ QBrush m_brush; QGraphicsPathItem * m_currPath; Paths paths; + Paths oldPaths; + QList oldItems; virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent); virtual void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent); diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/game.cpp --- a/QTfrontend/game.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/game.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -53,7 +53,14 @@ void HWGame::onClientDisconnect() { switch (gameType) { - case gtDemo: break; + case gtSave: + if (gameState == gsInterrupted || gameState == gsHalted) + emit HaveRecord(false, demo); + else if (gameState == gsFinished) + emit HaveRecord(true, demo); + break; + case gtDemo: + break; case gtNet: emit HaveRecord(true, demo); break; @@ -84,8 +91,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 +99,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())); ; } } @@ -187,6 +193,7 @@ SendQuickConfig(); break; } + case gtSave: case gtDemo: break; case gtNet: { SendNetConfig(); @@ -320,9 +327,9 @@ TeamCount++; } -void HWGame::PlayDemo(const QString & demofilename) +void HWGame::PlayDemo(const QString & demofilename, bool isSave) { - gameType = gtDemo; + gameType = isSave ? gtSave : gtDemo; QFile demofile(demofilename); if (!demofile.open(QIODevice::ReadOnly)) { @@ -392,9 +399,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 f5dcef0bb8b9 -r d4680c51b220 QTfrontend/game.h --- a/QTfrontend/game.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/game.h Fri Sep 16 15:26:02 2011 -0400 @@ -48,7 +48,7 @@ HWGame(GameUIConfig * config, GameCFGWidget * gamecfg, QString ammo, TeamSelWidget* pTeamSelWidget = 0); virtual ~HWGame(); void AddTeam(const QString & team); - void PlayDemo(const QString & demofilename); + void PlayDemo(const QString & demofilename, bool isSave); void StartLocal(); void StartQuick(); void StartNet(); @@ -84,6 +84,7 @@ gtNet = 4, gtTraining = 5, gtCampaign = 6, + gtSave = 7, }; char msgbuf[MAXMSGCHARS]; QString teams[5]; diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/gamecfgwidget.cpp --- a/QTfrontend/gamecfgwidget.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/gamecfgwidget.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -49,9 +49,7 @@ QGridLayout *GBoxOptionsLayout = new QGridLayout(GBoxOptions); - QLabel *titleLabel = new QLabel(QLabel::tr("Game Options"), GBoxOptions); - titleLabel->setMargin(7); // TODO: make the text larger/richer!!!! - GBoxOptionsLayout->addWidget(titleLabel, 0, 0, 1, 0, Qt::AlignHCenter); + GBoxOptions->setTitle(tr("Game Options")); GBoxOptionsLayout->addWidget(new QLabel(QLabel::tr("Style"), GBoxOptions), 1, 0); Scripts = new QComboBox(GBoxOptions); diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/hwconsts.h --- a/QTfrontend/hwconsts.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/hwconsts.h Fri Sep 16 15:26:02 2011 -0400 @@ -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 f5dcef0bb8b9 -r d4680c51b220 QTfrontend/hwform.cpp --- a/QTfrontend/hwform.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/hwform.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -93,7 +93,7 @@ bool frontendEffects = true; QString playerHash; -HWForm::HWForm(QWidget *parent) +HWForm::HWForm(QWidget *parent, QString styleSheet) : QMainWindow(parent), pnetserver(0), pRegisterServer(0), editedTeam(0), hwnet(0) { #ifdef USE_XFIRE @@ -104,6 +104,7 @@ frontendEffects = gameSettings->value("frontend/effects", true).toBool(); playerHash = QString(QCryptographicHash::hash(gameSettings->value("net/nick","").toString().toLatin1(), QCryptographicHash::Md5).toHex()); + this->setStyleSheet(styleSheet); ui.setupUi(this); setMinimumSize(760, 580); //setFocusPolicy(Qt::StrongFocus); @@ -152,18 +153,23 @@ 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())); connect(ui.pageEditTeam->BtnTeamDiscard, SIGNAL(clicked()), this, SLOT(TeamDiscard())); - connect(ui.pageEditTeam->signalMapper, SIGNAL(mapped(const int &)), this, SLOT(RandomName(const int &))); + connect(ui.pageEditTeam->signalMapper2, SIGNAL(mapped(const int &)), this, SLOT(RandomName(const int &))); connect(ui.pageEditTeam->randTeamButton, SIGNAL(clicked()), this, SLOT(RandomNames())); connect(ui.pageMultiplayer->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); @@ -621,8 +627,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(); @@ -632,7 +639,7 @@ void HWForm::NewTeam() { - editedTeam = new HWTeam("unnamed"); + editedTeam = new HWTeam(QLineEdit::tr("unnamed")); editedTeam->SetToPage(this); GoToPage(ID_PAGE_SETUP_TEAM); } @@ -724,7 +731,7 @@ return; } CreateGame(0, 0, 0); - game->PlayDemo(curritem->data(Qt::UserRole).toString()); + game->PlayDemo(curritem->data(Qt::UserRole).toString(), ui.pagePlayDemo->isSave()); } void HWForm::PlayDemoQuick(const QString & demofilename) @@ -733,7 +740,7 @@ GoBack(); //needed to cleanly disconnect from netgame GoToPage(ID_PAGE_MAIN); CreateGame(0, 0, 0); - game->PlayDemo(demofilename); + game->PlayDemo(demofilename, false); } void HWForm::NetConnectServer(const QString & host, quint16 port) diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/hwform.h --- a/QTfrontend/hwform.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/hwform.h Fri Sep 16 15:26:02 2011 -0400 @@ -52,7 +52,7 @@ Q_OBJECT public: - HWForm(QWidget *parent = 0); + HWForm(QWidget *parent = 0, QString styleSheet = ""); Ui_HWForm ui; SDLInteraction sdli; GameUIConfig * config; diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/main.cpp --- a/QTfrontend/main.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/main.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -96,8 +96,8 @@ Q_INIT_RESOURCE(hedgewars); - qApp->setStyleSheet - (QString( + QString styleSheetFromHell = + QString( "HWForm,QDialog{" "background-image: url(\":/res/Background.png\");" "background-position: bottom center;" @@ -251,6 +251,8 @@ "subcontrol-origin: margin;" "subcontrol-position: top left;" "text-align: left;" + "left: 15px;" + "top: -4px;" "}" "QCheckBox::indicator:checked{" @@ -315,8 +317,7 @@ "background-color: #ffcc00;" "width: 8px;" "}" - ) - ); + ); bindir->cd("bin"); // workaround over NSIS installer @@ -470,8 +471,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); @@ -484,7 +485,7 @@ CocoaInitializer initializer; #endif - app.form = new HWForm(); + app.form = new HWForm(NULL,styleSheetFromHell); app.form->show(); return app.exec(); diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/mapContainer.cpp --- a/QTfrontend/mapContainer.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/mapContainer.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -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 f5dcef0bb8b9 -r d4680c51b220 QTfrontend/newnetclient.cpp --- a/QTfrontend/newnetclient.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/newnetclient.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -496,17 +496,6 @@ emit AskForRunGame(); return; } - - if (lst[0] == "BYE") { - if (lst[1] == "Authentication failed") - { - // Set the password blank if case the user tries to join and enter his password again - config->setValue("net/passwordlength", 0); - config->setNetPasswordLength(0); - } - // return early so the user won't get an unknown error message dialog (the user already gets a server connection is lost one) - return; - } if (lst[0] == "ASKPASSWORD") { bool ok = false; @@ -625,6 +614,12 @@ qWarning("Net: Bad BYE message"); return; } + if (lst[1] == "Authentication failed") + { + // Set the password blank if case the user tries to join and enter his password again + config->setValue("net/passwordlength", 0); + config->setNetPasswordLength(0); + } emit showMessage(HWNewNet::tr("Quit reason: ") + lst[1]); return; } diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pagedata.cpp --- a/QTfrontend/pagedata.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pagedata.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -23,10 +23,16 @@ #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) { @@ -35,49 +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 QTextBrowser(this); - connect(web, SIGNAL(anchorClicked(QUrl)), this, SLOT(install(const QUrl&))); + web = new DataBrowser(this); + connect(web, SIGNAL(anchorClicked(QUrl)), this, SLOT(request(const QUrl&))); web->setOpenLinks(false); - //web->setSource(); - //web->load(QUrl("http://m8y.org/hw/downloads/")); - //web->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); pageLayout->addWidget(web, 0, 0, 1, 3); - - QNetworkRequest newRequest(QUrl("http://m8y.org/hw/downloads/index.xhtml")); - //newRequest.setAttribute(QNetworkRequest::User, fileName); + progressBarsLayout = new QVBoxLayout(); + pageLayout->addLayout(progressBarsLayout, 1, 0, 1, 3); - QNetworkAccessManager *manager = new QNetworkAccessManager(this); - QNetworkReply *reply = manager->get(newRequest); - connect(reply, SIGNAL(finished()), this, SLOT(downloadIssueFinished())); + fetchList(); } -void PageDataDownload::install(const QUrl &url) +void PageDataDownload::request(const QUrl &url) { -qWarning("Download Request"); -QString fileName = QFileInfo(url.toString()).fileName(); + 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); -QNetworkRequest newRequest(url); -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))); -QNetworkAccessManager *manager = new QNetworkAccessManager(this); -QNetworkReply *reply = manager->get(newRequest); -//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); + + QNetworkAccessManager *manager = new QNetworkAccessManager(this); + QNetworkReply *reply = manager->get(newRequest); + connect(reply, SIGNAL(finished()), this, SLOT(pageDownloaded())); + } } -void PageDataDownload::downloadIssueFinished() +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) { - web->setHtml(QString::fromUtf8(reply->readAll())); + QByteArray fileContents = reply->readAll(); + QProgressBar *progressBar = progressBars.value(reply, 0); + + if(progressBar) + { + progressBars.remove(reply); + progressBar->deleteLater(); + } + + extractDataPack(&fileContents); + } +} + +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() +{ + 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"); + + 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; + } + 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 f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pagedata.h --- a/QTfrontend/pagedata.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pagedata.h Fri Sep 16 15:26:02 2011 -0400 @@ -22,7 +22,10 @@ #include #include "AbstractPage.h" -class QTextBrowser; +class DataBrowser; +class QProgressBar; +class QNetworkReply; +class QVBoxLayout; class PageDataDownload : public AbstractPage { @@ -32,12 +35,23 @@ PageDataDownload(QWidget* parent = 0); QPushButton *BtnBack; - QTextBrowser *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 downloadIssueFinished(); + void pageDownloaded(); + void fileDownloaded(); + void downloadProgress(qint64, qint64); }; #endif diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pagedrawmap.cpp --- a/QTfrontend/pagedrawmap.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pagedrawmap.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -45,7 +45,7 @@ void PageDrawMap::load() { - QString fileName = QFileDialog::getOpenFileName(this, tr("Load drawn map"), ".", tr("Drawn Maps (*.hwmap);;All files (*.*)")); + QString fileName = QFileDialog::getOpenFileName(NULL, tr("Load drawn map"), ".", tr("Drawn Maps") + " (*.hwmap);;" + tr("All files") + " (*)"); if(!fileName.isEmpty()) drawMapWidget->load(fileName); @@ -53,7 +53,7 @@ void PageDrawMap::save() { - QString fileName = QFileDialog::getSaveFileName(this, tr("Save drawn map"), ".", tr("Drawn Maps (*.hwmap);;All files (*.*)")); + QString fileName = QFileDialog::getSaveFileName(NULL, tr("Save drawn map"), ".", tr("Drawn Maps") + " (*.hwmap);;" + tr("All files") + " (*)"); if(!fileName.isEmpty()) drawMapWidget->save(fileName); diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pageeditteam.cpp --- a/QTfrontend/pageeditteam.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pageeditteam.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -64,7 +64,10 @@ GBoxHedgehogs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); QGridLayout * GBHLayout = new QGridLayout(GBoxHedgehogs); - signalMapper = new QSignalMapper(this); + signalMapper1 = new QSignalMapper(this); + signalMapper2 = new QSignalMapper(this); + + connect(signalMapper1, SIGNAL(mapped(int)), this, SLOT(fixHHname(int))); HatsModel * hatsModel = new HatsModel(GBoxHedgehogs); for(int i = 0; i < 8; i++) @@ -82,11 +85,13 @@ HHNameEdit[i]->setMinimumWidth(120); GBHLayout->addWidget(HHNameEdit[i], i, 1); + connect(HHNameEdit[i], SIGNAL(editingFinished()), signalMapper1, SLOT(map())); + signalMapper1->setMapping(HHNameEdit[i], i); + randButton[i] = addButton(":/res/dice.png", GBHLayout, i, 3, true); - connect(randButton[i], SIGNAL(clicked()), signalMapper, SLOT(map())); - signalMapper->setMapping(randButton[i], i); - + connect(randButton[i], SIGNAL(clicked()), signalMapper2, SLOT(map())); + signalMapper2->setMapping(randButton[i], i); } randTeamButton = addButton(QPushButton::tr("Random Team"), GBHLayout, 9, false); @@ -342,6 +347,14 @@ } } +void PageEditTeam::fixHHname(int idx) +{ + HHNameEdit[idx]->setText(HHNameEdit[idx]->text().trimmed()); + + if (HHNameEdit[idx]->text().isEmpty()) + HHNameEdit[idx]->setText(QLineEdit::tr("hedgehog %1").arg(idx+1)); +} + void PageEditTeam::CBFort_activated(const QString & fortname) { QFile tmp; @@ -358,10 +371,8 @@ mySdli->SDLMusicInit(); tmpdir.cd(cfgdir->absolutePath()); - tmpdir.cd("Data/Sounds/voices"); - tmpdir.cd(CBVoicepack->currentText()); - - if (!tmpdir.exists()) { + if (!tmpdir.cd("Data/Sounds/voices/"+CBVoicepack->currentText())) + { tmpdir.cd(datadir->absolutePath()); tmpdir.cd("Sounds/voices"); tmpdir.cd(CBVoicepack->currentText()); diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pageeditteam.h --- a/QTfrontend/pageeditteam.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pageeditteam.h Fri Sep 16 15:26:02 2011 -0400 @@ -31,7 +31,8 @@ public: PageEditTeam(QWidget* parent, SDLInteraction * sdli); - QSignalMapper* signalMapper; + QSignalMapper* signalMapper1; + QSignalMapper* signalMapper2; QGroupBox *GBoxHedgehogs; QGroupBox *GBoxTeam; QGroupBox *GBoxFort; @@ -61,6 +62,7 @@ private slots: void testSound(); + void fixHHname(int idx); }; #endif diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pagegamestats.cpp --- a/QTfrontend/pagegamestats.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pagegamestats.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -43,14 +43,16 @@ pageLayout->setSpacing(20); pageLayout->setColumnStretch(0, 1); pageLayout->setColumnStretch(1, 1); + pageLayout->setContentsMargins(7, 7, 7, 0); + + BtnSave = addButton(":/res/Save.png", pageLayout, 3, 2, true); + BtnSave->setStyleSheet("QPushButton{margin: 12px 0px 12px 0px;}"); + connect(BtnSave, SIGNAL(clicked()), this, SIGNAL(saveDemoRequested())); 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())); + BtnBack->setFixedHeight(BtnSave->height()); + BtnBack->setFixedWidth(BtnBack->width()+2); + BtnBack->setStyleSheet("QPushButton{margin: 22px 0 9px 2px;}"); QGroupBox * gb = new QGroupBox(this); QVBoxLayout * gbl = new QVBoxLayout; diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pagemain.cpp --- a/QTfrontend/pagemain.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pagemain.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -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 f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pagemain.h --- a/QTfrontend/pagemain.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pagemain.h Fri Sep 16 15:26:02 2011 -0400 @@ -33,6 +33,7 @@ QPushButton *BtnSetup; QPushButton *BtnInfo; QPushButton *BtnExit; + QPushButton *BtnDataDownload; QLabel *mainNote; }; diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pageoptions.cpp --- a/QTfrontend/pageoptions.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pageoptions.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -295,11 +295,12 @@ CBResolution = new QComboBox(AGGroupBox); GBAreslayout->addWidget(CBResolution); GBAlayout->addLayout(GBAreslayout); + connect(CBResolution, SIGNAL(currentIndexChanged(int)), this, SLOT(setResolution(int))); CBFullscreen = new QCheckBox(AGGroupBox); CBFullscreen->setText(QCheckBox::tr("Fullscreen")); GBAlayout->addWidget(CBFullscreen); - connect(CBFullscreen, SIGNAL(stateChanged(int)), this, SLOT(setFullscreen(void))); + connect(CBFullscreen, SIGNAL(stateChanged(int)), this, SLOT(setFullscreen(int))); QLabel * quality = new QLabel(AGGroupBox); quality->setText(QLabel::tr("Quality")); @@ -313,6 +314,8 @@ SLQuality->setFixedWidth(150); GBAqualayout->addWidget(SLQuality); GBAlayout->addLayout(GBAqualayout); + connect(SLQuality, SIGNAL(valueChanged(int)), this, SLOT(setQuality(int))); + QLabel * stereo = new QLabel(AGGroupBox); stereo->setText(QLabel::tr("Stereo rendering")); GBAstereolayout->addWidget(stereo); @@ -402,33 +405,50 @@ BtnBack->setFixedHeight(BtnSaveOptions->height()); BtnBack->setFixedWidth(BtnBack->width()+2); BtnBack->setStyleSheet("QPushButton{margin: 22px 0 9px 2px;}"); + + previousQuality = this->SLQuality->value(); + previousResolutionIndex = this->CBResolution->currentIndex(); + previousFullscreenValue = this->CBFullscreen->isChecked(); } void PageOptions::forceFullscreen(int index) { + bool forced = (index == 7 || index == 8 || index == 9); + if (index != 0) { - previousFullscreenValue = this->CBFullscreen->isChecked(); - this->CBFullscreen->setChecked(true); - this->CBFullscreen->setEnabled(false); - previousQuality = this->SLQuality->value(); this->SLQuality->setValue(this->SLQuality->maximum()); this->SLQuality->setEnabled(false); + this->CBFullscreen->setEnabled(!forced); + this->CBFullscreen->setChecked(forced ? true : previousFullscreenValue); + this->CBResolution->setCurrentIndex(forced ? 0 : previousResolutionIndex); } else { - this->CBFullscreen->setChecked(previousFullscreenValue); + this->SLQuality->setEnabled(true); this->CBFullscreen->setEnabled(true); this->SLQuality->setValue(previousQuality); - this->SLQuality->setEnabled(true); + this->CBFullscreen->setChecked(previousFullscreenValue); + this->CBResolution->setCurrentIndex(previousResolutionIndex); } } -void PageOptions::setFullscreen(void) +void PageOptions::setQuality(int value) +{ + int index = this->CBStereoMode->currentIndex(); + if (index == 0) + previousQuality = this->SLQuality->value(); +} + +void PageOptions::setFullscreen(int state) { - int tmp = this->CBResolution->currentIndex(); - if (this->CBFullscreen->isChecked()) - this->CBResolution->setCurrentIndex(0); - else - this->CBResolution->setCurrentIndex(previousResolutionIndex); - previousResolutionIndex = tmp; + int index = this->CBStereoMode->currentIndex(); + if (index != 7 && index != 8 && index != 9) + previousFullscreenValue = this->CBFullscreen->isChecked(); +} + +void PageOptions::setResolution(int state) +{ + int index = this->CBStereoMode->currentIndex(); + if (index != 7 && index != 8 && index != 9) + previousResolutionIndex = this->CBResolution->currentIndex(); } void PageOptions::trimNetNick() diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pageoptions.h --- a/QTfrontend/pageoptions.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pageoptions.h Fri Sep 16 15:26:02 2011 -0400 @@ -84,7 +84,9 @@ private slots: void forceFullscreen(int index); - void setFullscreen(void); + void setFullscreen(int state); + void setResolution(int state); + void setQuality(int value); void trimNetNick(); }; diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pageplayrecord.cpp --- a/QTfrontend/pageplayrecord.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pageplayrecord.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -150,3 +150,8 @@ else FillFromDir(recType); } + +bool PagePlayDemo::isSave() +{ + return recType == RT_Save; +} diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/pageplayrecord.h --- a/QTfrontend/pageplayrecord.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/pageplayrecord.h Fri Sep 16 15:26:02 2011 -0400 @@ -39,6 +39,7 @@ PagePlayDemo(QWidget* parent = 0); void FillFromDir(RecordType rectype); + bool isSave(); QPushButton *BtnBack; QPushButton *BtnPlayDemo; diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/team.cpp --- a/QTfrontend/team.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/team.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -38,7 +38,7 @@ OldTeamName = TeamName; for (int i = 0; i < 8; i++) { - Hedgehogs[i].Name.sprintf("hedgehog %d", i); + Hedgehogs[i].Name = (QLineEdit::tr("hedgehog %1").arg(i+1)); Hedgehogs[i].Hat = "NoHat"; } Grave = "Statue"; @@ -125,7 +125,7 @@ for(int i = 0; i < 8; i++) { QString hh = QString("Hedgehog%1/").arg(i); - Hedgehogs[i].Name = teamfile.value(hh + "Name", QString("hedgehog %1").arg(i)).toString(); + Hedgehogs[i].Name = teamfile.value(hh + "Name", QString("hedgehog %1").arg(i+1)).toString(); Hedgehogs[i].Hat = teamfile.value(hh + "Hat", "NoHat").toString(); Hedgehogs[i].Rounds = teamfile.value(hh + "Rounds", 0).toInt(); Hedgehogs[i].Kills = teamfile.value(hh + "Kills", 0).toInt(); diff -r f5dcef0bb8b9 -r d4680c51b220 QTfrontend/teamselect.cpp --- a/QTfrontend/teamselect.cpp Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/teamselect.cpp Fri Sep 16 15:26:02 2011 -0400 @@ -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 f5dcef0bb8b9 -r d4680c51b220 QTfrontend/teamselect.h --- a/QTfrontend/teamselect.h Thu Sep 08 00:34:57 2011 +0200 +++ b/QTfrontend/teamselect.h Fri Sep 16 15:26:02 2011 -0400 @@ -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 f5dcef0bb8b9 -r d4680c51b220 gameServer/HWProtoInRoomState.hs --- a/gameServer/HWProtoInRoomState.hs Thu Sep 08 00:34:57 2011 +0200 +++ b/gameServer/HWProtoInRoomState.hs Fri Sep 16 15:26:02 2011 -0400 @@ -52,7 +52,7 @@ clChan <- thisClientChans othChans <- roomOthersChans return $ - if not . null . drop 5 $ teams rm then + if not . null . drop (maxTeams rm - 1) $ teams rm then [Warning "too many teams"] else if canAddNumber rm <= 0 then [Warning "too many hedgehogs"] @@ -78,6 +78,10 @@ hhsList [_] = error "Hedgehogs list with odd elements number" hhsList (n:h:hhs) = HedgehogInfo n h : hhsList hhs newTeamHHNum r = min 4 (canAddNumber r) + maxTeams r + | roomProto r < 38 = 6 + | otherwise = 8 + handleCmd_inRoom ["REMOVE_TEAM", tName] = do (ci, _) <- ask diff -r f5dcef0bb8b9 -r d4680c51b220 gameServer/HWProtoLobbyState.hs --- a/gameServer/HWProtoLobbyState.hs Thu Sep 08 00:34:57 2011 +0200 +++ b/gameServer/HWProtoLobbyState.hs Fri Sep 16 15:26:02 2011 -0400 @@ -75,11 +75,12 @@ let maybeRI = find (\ri -> roomName == name (irnc `room` ri)) ris let jRI = fromJust maybeRI let jRoom = irnc `room` jRI + let sameProto = clientProto cl == roomProto jRoom let jRoomClients = map (client irnc) $ roomClients irnc jRI let nicks = map nick jRoomClients let chans = map sendChan (cl : jRoomClients) return $ - if isNothing maybeRI then + if isNothing maybeRI || not sameProto then [Warning "No such rooms"] else if isRestrictedJoins jRoom then [Warning "Joining restricted"] @@ -135,7 +136,7 @@ cl <- thisClient let ri = clientRoom rnc $ fromJust ci let clRoom = room rnc ri - if isNothing ci || ri == lobbyId || clientProto cl /= roomProto clRoom then + if isNothing ci || ri == lobbyId then return [] else handleCmd_lobby ["JOIN_ROOM", name clRoom] diff -r f5dcef0bb8b9 -r d4680c51b220 gameServer/Utils.hs --- a/gameServer/Utils.hs Thu Sep 08 00:34:57 2011 +0200 +++ b/gameServer/Utils.hs Fri Sep 16 15:26:02 2011 -0400 @@ -103,6 +103,8 @@ , (35, "0.9.14.1") , (37, "0.9.15") , (38, "0.9.16-dev") + , (39, "0.9.16") + , (40, "0.9.17-dev") ] askFromConsole :: B.ByteString -> IO B.ByteString diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/CMakeLists.txt --- a/hedgewars/CMakeLists.txt Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/CMakeLists.txt Fri Sep 16 15:26:02 2011 -0400 @@ -183,6 +183,8 @@ add_custom_target(${engine_output_name} ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}${CMAKE_EXECUTABLE_SUFFIX}") +add_custom_target(ENGINECLEAN COMMAND ${CMAKE_BUILD_TOOL} "clean" "${PROJECT_BINARY_DIR}" "${hedgewars_SOURCE_DIR}/hedgewars") +add_dependencies(${engine_output_name} ENGINECLEAN) install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_dir}) diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/GSHandlers.inc Fri Sep 16 15:26:02 2011 -0400 @@ -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; @@ -483,18 +512,52 @@ i, gX, gY: LongInt; dX, dY: hwFloat; Fire: PGear; + smoke, glass: PVisualGear; begin AllInactive := false; doStepFallingGear(Gear); CalcRotationDirAngle(Gear); + // let's add some smoke depending on speed + i:= max(32,152 - hwRound(Distance(Gear^.dX,Gear^.dY)*120))+random(10); + if (GameTicks mod i) = 0 then + begin + // adjust angle to match the texture + if Gear^.dX.isNegative then i:= 130 else i:= 50; + smoke:= AddVisualGear(hwRound(Gear^.X)-round(cos((Gear^.DirAngle+i) * pi / 180)*20), hwRound(Gear^.Y)-round(sin((Gear^.DirAngle+i) * pi / 180)*20), vgtSmoke); + if smoke <> nil then smoke^.Scale:= 0.75; + end; + if (Gear^.State and gstCollision) <> 0 then begin PlaySound(sndMolotov); gX := hwRound(Gear^.X); gY := hwRound(Gear^.Y); - //doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 5, EXPLAutoSound); + for i:= 0 to 4 do + begin + (*glass:= AddVisualGear(gx+random(7)-3, gy+random(5)-2, vgtEgg); + if glass <> nil then + begin + glass^.Frame:= 2; + glass^.Tint:= $41B83ED0 - i * $10081000; + glass^.dX:= 1/(10*(random(11)-5)); + glass^.dY:= -1/(random(4)+5); + end;*) + glass:= AddVisualGear(gx+random(7)-3, gy+random(7)-3, vgtStraightShot); + if glass <> nil then + with glass^ do + begin + Frame:= 2; + Tint:= $41B83ED0 - i * $10081000; + Angle:= random * 360; + dx:= 0.0000001; + dy:= 0; + if random(2) = 0 then dx := -dx; + FrameTicks:= 750; + State:= ord(sprEgg) + end; + end; for i:= 0 to 24 do begin dX := AngleCos(i * 2) * ((_0_15*(i div 5))) * (GetRandom + _1); @@ -930,6 +993,44 @@ end; //////////////////////////////////////////////////////////////////////////////// +procedure spawnBulletTrail(Bullet: PGear); +var oX, oY: hwFloat; + VGear: PVisualGear; +begin + if Bullet^.PortalCounter = 0 then + begin + ox:= CurrentHedgehog^.Gear^.X + Int2hwFloat(GetLaunchX(CurrentHedgehog^.CurAmmoType, hwSign(CurrentHedgehog^.Gear^.dX), CurrentHedgehog^.Gear^.Angle)); + oy:= CurrentHedgehog^.Gear^.Y + Int2hwFloat(GetLaunchY(CurrentHedgehog^.CurAmmoType, CurrentHedgehog^.Gear^.Angle)); + end + else + begin + ox:= Bullet^.Elasticity; + oy:= Bullet^.Friction; + end; + + // Bullet trail + VGear := AddVisualGear(hwRound(ox), hwRound(oy), vgtLineTrail); + if VGear <> nil then + begin + VGear^.X:= hwFloat2Float(ox); + VGear^.Y:= hwFloat2Float(oy); + VGear^.dX:= hwFloat2Float(Bullet^.X); + VGear^.dY:= hwFloat2Float(Bullet^.Y); + + // reached edge of land. assume infinite beam. Extend it way out past camera + if (hwRound(Bullet^.X) and LAND_WIDTH_MASK <> 0) + or (hwRound(Bullet^.Y) and LAND_HEIGHT_MASK <> 0) then + // only extend if not under water + if hwRound(Bullet^.Y) < cWaterLine then + begin + VGear^.dX := VGear^.dX + LAND_WIDTH * (VGear^.dX - VGear^.X); + VGear^.dY := VGear^.dY + LAND_WIDTH * (VGear^.dY - VGear^.Y); + end; + + VGear^.Timer := 200; + end; +end; + procedure doStepBulletWork(Gear: PGear); var i, x, y: LongWord; @@ -948,6 +1049,19 @@ y := hwRound(Gear^.Y); if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then inc(Gear^.Damage); + // let's interrupt before a collision to give portals a chance to catch the bullet + if (Gear^.Damage = 1) and (Gear^.Tag = 0) and (Land[y, x] > 255) then + begin + Gear^.Tag := 1; + Gear^.Damage := 0; + Gear^.X := Gear^.X - Gear^.dX; + Gear^.Y := Gear^.Y - Gear^.dY; + CheckGearDrowning(Gear); + break; + end + else + Gear^.Tag := 0; + if Gear^.Damage > 5 then if Gear^.AmmoType = amDEagle then AmmoShove(Gear, 7, 20) @@ -993,31 +1107,7 @@ end; end; - if Gear^.PortalCounter = 0 then - begin - // Bullet trail - VGear := AddVisualGear( - hwround(CurrentHedgehog^.Gear^.X) + GetLaunchX(CurrentHedgehog^.CurAmmoType, hwSign(CurrentHedgehog^.Gear^.dX), CurrentHedgehog^.Gear^.Angle), - hwround(CurrentHedgehog^.Gear^.Y) + GetLaunchY(CurrentHedgehog^.CurAmmoType, CurrentHedgehog^.Gear^.Angle), - vgtLineTrail - ); - if VGear <> nil then - begin - // http://mantis.freepascal.org/view.php?id=17714 hits again - VGear^.dX := Gear^.X.QWordValue / SignAs(_1,_1).QWordValue; - VGear^.dY := Gear^.Y.QWordValue / SignAs(_1,_1).QWordValue; - - // reached edge of land. assume infinite beam. Extend it way out past camera - if (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0) - or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then - begin - VGear^.dX := VGear^.dX + (CurrentHedgehog^.Gear^.dX * LAND_WIDTH).QWordValue / SignAs(_1,_1).QWordValue; - VGear^.dY := VGear^.dY + (CurrentHedgehog^.Gear^.dY * LAND_WIDTH).QWordValue / SignAs(_1,_1).QWordValue; - end; - - VGear^.Timer := 200; - end - end; + spawnBulletTrail(Gear); Gear^.doStep := @doStepShotIdle end; end; @@ -1025,9 +1115,9 @@ procedure doStepDEagleShot(Gear: PGear); begin PlaySound(sndGun); - // add 2 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths - Gear^.X := Gear^.X + Gear^.dX * 2; - Gear^.Y := Gear^.Y + Gear^.dY * 2; + // add 3 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just plain old weird angles + Gear^.X := Gear^.X + Gear^.dX * 3; + Gear^.Y := Gear^.Y + Gear^.dY * 3; Gear^.doStep := @doStepBulletWork end; @@ -1061,9 +1151,9 @@ Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5; Gear^.dY := -AngleCos(HHGear^.Angle) * _0_5; PlaySound(sndGun); - // add an initial step to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths - Gear^.X := Gear^.X + Gear^.dX; - Gear^.Y := Gear^.Y + Gear^.dY; + // add 3 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just weird angles + Gear^.X := Gear^.X + Gear^.dX * 3; + Gear^.Y := Gear^.Y + Gear^.dY * 3; Gear^.doStep := @doStepBulletWork; end else @@ -1126,7 +1216,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); @@ -1235,6 +1326,8 @@ begin AllInactive := false; dec(Gear^.Timer); + if ((GameFlags and gfInfAttack) <> 0) and (TurnTimeLeft > 0) then dec(TurnTimeLeft); + HHGear := Gear^.Hedgehog^.Gear; HedgehogChAngle(HHGear); @@ -1302,7 +1395,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); @@ -1373,7 +1466,7 @@ var HHGear: PGear; len, tx, ty, nx, ny, ropeDx, ropeDy, mdX, mdY: hwFloat; - lx, ly: LongInt; + lx, ly, cd: LongInt; haveCollision, haveDivided: boolean; @@ -1414,16 +1507,30 @@ else if (Gear^.Message and gmRight <> 0) then HHGear^.dX := HHGear^.dX + _0_0002; - if not TestCollisionYwithGear(HHGear, 1) then - begin - HHGear^.dY := HHGear^.dY + cGravity; - if (GameFlags and gfMoreWind) <> 0 then HHGear^.dX := HHGear^.dX + cWindSpeed / HHGear^.Density; - end; - // vector between hedgehog and rope attaching point ropeDx := HHGear^.X - Gear^.X; ropeDy := HHGear^.Y - Gear^.Y; + if not TestCollisionYwithGear(HHGear, 1) then + begin + + // depending on the rope vector we know which X-side to check for collision + // in order to find out if the hog can still be moved by gravity + if ropeDx.isNegative = RopeDy.IsNegative then + cd:= -1 + else + cd:= 1; + + // apply gravity if there is no obstacle + if not TestCollisionXwithGear(HHGear, cd) then + HHGear^.dY := HHGear^.dY + cGravity; + + if (GameFlags and gfMoreWind) <> 0 then + // apply wind if there's no obstacle + if not TestCollisionXwithGear(HHGear, hwSign(cWindSpeed)) then + HHGear^.dX := HHGear^.dX + cWindSpeed / HHGear^.Density; + end; + mdX := ropeDx + HHGear^.dX; mdY := ropeDy + HHGear^.dY; len := _1 / Distance(mdX, mdY); @@ -2619,7 +2726,7 @@ repeat CurrentTeam^.CurrHedgehog := Succ(CurrentTeam^.CurrHedgehog) mod (CurrentTeam^. HedgehogsNumber); - until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil); + until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear^.Damage = 0); CurrentHedgehog := @CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog]; @@ -2690,8 +2797,12 @@ var i: LongWord; HHGear: PGear; + sparkles: PVisualGear; + hasWishes: boolean; begin AllInactive := false; + hasWishes:= ((Gear^.Message and (gmPrecise or gmSwitch)) = (gmPrecise or gmSwitch)); + if hasWishes then Gear^.AdvBounce:= 1; HHGear := Gear^.Hedgehog^.Gear; HHGear^.State := HHGear^.State or gstNoDamage; @@ -2699,9 +2810,19 @@ Gear^.X := HHGear^.X; Gear^.Y := HHGear^.Y; + if (GameTicks mod 2 = 0) and hasWishes then + begin + sparkles:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtDust, 1); + if sparkles <> nil then + begin + sparkles^.Tint:= ((random(210)+45) shl 24) or ((random(210)+45) shl 16) or ((random(210)+45) shl 8) or $FF; + sparkles^.Angle:= random * 360; + end + end; i := 2; repeat + Gear^.X := Gear^.X + HHGear^.dX; Gear^.Y := Gear^.Y + HHGear^.dY; HHGear^.X := Gear^.X; @@ -2718,7 +2839,13 @@ inc(upd); if upd > 3 then begin - if Gear^.Health < 1500 then Gear^.Pos := 2; + if Gear^.Health < 1500 then + begin + if Gear^.AdvBounce <> 0 then + Gear^.Pos := 3 + else + Gear^.Pos := 2; + end; AmmoShove(Gear, 30, 40); @@ -2735,6 +2862,21 @@ if Gear^.Health < Gear^.Damage then begin doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound); + for i:= 0 to 31 do + begin + sparkles:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot); + if sparkles <> nil then + with sparkles^ do + begin + Tint:= ((random(210)+45) shl 24) or ((random(210)+45) shl 16) or ((random(210)+45) shl 8) or $FF; + Angle:= random * 360; + 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(400) + 250 + end; + end; AfterAttack; DeleteGear(Gear); DeleteGear(HHGear); @@ -2751,11 +2893,11 @@ AllInactive := false; dec(Gear^.Timer); if Gear^.Timer = 0 then - begin + begin Gear^.Pos := 1; PlaySound(sndKamikaze, Gear^.Hedgehog^.Team^.voicepack); Gear^.doStep := @doStepKamikazeWork - end + end end; procedure doStepKamikaze(Gear: PGear); @@ -3880,12 +4022,20 @@ continue; end; + // draw bullet trail + if isbullet then + spawnBulletTrail(iterator); + // calc gear offset in portal vector direction ox := (iterator^.X - Gear^.X); oy := (iterator^.Y - Gear^.Y); poffs:= (Gear^.dX * ox + Gear^.dY * oy); - if poffs < _0 then + if not isBullet and poffs.isNegative then + continue; + + // only port bullets close to the portal + if isBullet and not (hwAbs(poffs) < _3) then continue; // @@ -3913,8 +4063,11 @@ // calc gear offset in portal normal vector direction noffs:= (nx * ox + ny * oy); + if isBullet and (hwRound(hwAbs(noffs)) >= Gear^.Radius) then + continue; + // avoid gravity related loops of not really moving gear - if not iscake and (Gear^.dY.isNegative) and (conPortal^.dY.isNegative) + if not (iscake or isbullet) and (Gear^.dY.isNegative) and (conPortal^.dY.isNegative) and ((iterator^.dX.QWordValue + iterator^.dY.QWordValue) < _0_08.QWordValue) and (iterator^.PortalCounter > 0) then continue; @@ -4029,6 +4182,13 @@ if not isbullet and (iterator^.Kind <> gtFlake) then FollowGear := iterator; + // store X/Y values of exit for net bullet trail + if isbullet then + begin + iterator^.Elasticity:= iterator^.X; + iterator^.Friction := iterator^.Y; + end; + // This jiggles gears, to ensure a portal connection just placed under a gear takes effect. iterator:= GearsList; while iterator <> nil do @@ -4090,7 +4250,7 @@ begin Gear^.State := Gear^.State or gstCollision; Gear^.State := Gear^.State and not gstMoving; - if not calcSlopeTangent(Gear, x, y, tx, ty, 255) + if not CalcSlopeTangent(Gear, x, y, tx, ty, 255) or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain begin loadNewPortalBall(Gear, true); @@ -4942,30 +5102,13 @@ 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 else if (HH^.GearHidden <> nil) then// and (HH^.Gear^.State and gstInvisible <> 0) then - 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 - end; + RestoreHog(HH) end; inc(Gear^.Timer); @@ -4976,7 +5119,20 @@ end end; -if (Gear^.Pos = 1) and (GameTicks and $1F = 0) and (Gear^.Power < 255) then inc(Gear^.Power); +if (Gear^.Pos = 1) and (GameTicks and $1F = 0) and (Gear^.Power < 255) then + begin + inc(Gear^.Power); + if (Gear^.Power = 172) and (Gear^.Hedgehog^.Gear <> nil) then + begin + with Gear^.Hedgehog^.Gear^ do + begin + State:= State or gstAnimation; + Tag:= 2; + Timer:= 0; + Pos:= 0 + end + end + end; if (Gear^.Pos = 3) and (GameTicks and $1F = 0) and (Gear^.Power > 0) then dec(Gear^.Power); 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 diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/HHHandlers.inc --- a/hedgewars/HHHandlers.inc Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/HHHandlers.inc Fri Sep 16 15:26:02 2011 -0400 @@ -53,7 +53,6 @@ HHGear^.Message:= HHGear^.Message and not gmSlot; ammoidx:= 0; if ((HHGear^.State and (gstAttacking or gstAttacked)) <> 0) or - (TargetPoint.X <> NoPointX) or ((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0)) or ((HHGear^.State and gstHHDriven) = 0) then exit; ChangeAmmo:= true; @@ -775,6 +774,11 @@ begin if (Gear^.dY.isNegative) and TestCollisionYKick(Gear, -1) then Gear^.dY:= _0; Gear^.State:= Gear^.State or gstMoving; + if (CurrentHedgehog^.Gear = Gear) + and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then + begin + FollowGear:= Gear; + end; if isUnderwater then Gear^.dY:= Gear^.dY + cGravity / _2 else begin @@ -1034,7 +1038,7 @@ PrvInactive:= false; AllInactive:= false; - if not Gear^.Hedgehog^.Team^.hasGone then + if (Gear^.State and gstHHGone) = 0 then begin Gear^.Hedgehog^.Effects[hePoisoned] := false; if Gear^.Hedgehog^.Effects[heResurrectable] then begin @@ -1048,8 +1052,8 @@ end else begin - Gear^.State:= Gear^.State or gstHHGone; Gear^.doStep:= @doStepHedgehogGone; + // Gone message AddCaption(Format(GetEventString(eidGone), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage); end @@ -1090,7 +1094,9 @@ else begin with Gear^.Hedgehog^ do - if Team^.hasGone then TeamGoneEffect(Team^); - doStepHedgehogDriven(Gear) + if Team^.hasGone then + TeamGoneEffect(Team^) + else + doStepHedgehogDriven(Gear) end; end; diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/VGSHandlers.inc --- a/hedgewars/VGSHandlers.inc Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/VGSHandlers.inc Fri Sep 16 15:26:02 2011 -0400 @@ -174,7 +174,10 @@ if Gear^.FrameTicks <= Steps then DeleteVisualGear(Gear) else - dec(Gear^.FrameTicks, Steps) + dec(Gear^.FrameTicks, Steps); + +if Gear^.FrameTicks < $FF then + Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or Gear^.FrameTicks end; //////////////////////////////////////////////////////////////////////////////// @@ -587,22 +590,16 @@ //////////////////////////////////////////////////////////////////////////////// procedure doStepBigExplosionWork(Gear: PVisualGear; Steps: Longword); -//var maxMovement: LongInt; +var maxMovement: LongInt; begin inc(Gear^.Timer, Steps); -(* -FIXME - This block desyncs due to the way WorldDx is important for various things network related. -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 - if (Gear^.Timer and 5) = 0 then begin maxMovement := max(1, 13 - ((Gear^.Timer * 15) div 250)); ShakeCamera(maxMovement); end; -*) + if Gear^.Timer > 250 then DeleteVisualGear(Gear); end; @@ -611,6 +608,9 @@ gX,gY: LongInt; vg: PVisualGear; begin +//ScreenFade:= sfFromWhite; +//ScreenFadeValue:= round(60 * zoom * zoom); +//ScreenFadeSpeed:= 5; gX:= round(Gear^.X); gY:= round(Gear^.Y); AddVisualGear(gX, gY, vgtSmokeRing); diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/hwengine.pas Fri Sep 16 15:26:02 2011 -0400 @@ -111,10 +111,18 @@ if flagMakeCapture then begin flagMakeCapture:= false; + {$IFNDEF IPHONEOS} s:= 'hw_' + FormatDateTime('YYYY-MM-DD_HH-mm-ss', Now()) + inttostr(GameTicks); - WriteLnToConsole('Saving ' + s + '...'); + playSound(sndShutter); - {$IFNDEF IPHONEOS}MakeScreenshot(s);{$ENDIF} + if not MakeScreenshot(s) then + begin + WriteLnToConsole('Screenshot failed.'); + AddChatString(#5 + 'screen capture failed (lack of memory or write permissions)'); + end + else + WriteLnToConsole('Screenshot saved: ' + s); + {$ENDIF} end; end; @@ -180,9 +188,12 @@ onFocusStateChanged() end; SDL_VIDEORESIZE: begin - // using lower values causes widget overlap and video issues - cNewScreenWidth:= max(event.resize.w, cMinScreenWidth); - cNewScreenHeight:= max(event.resize.h, cMinScreenHeight); + // 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} @@ -200,7 +211,8 @@ cScreenHeight:= cNewScreenHeight; ParseCommand('fullscr '+intToStr(LongInt(cFullScreen)), true); - WriteLnToConsole('window resize'); + WriteLnToConsole('window resize: ' + IntToStr(cScreenWidth) + ' x ' + IntToStr(cScreenHeight)); + ScriptOnScreenResize(); InitCameraBorders() end; @@ -250,8 +262,8 @@ recordFileName:= gameArgs[10]; cStereoMode:= smNone; {$ENDIF} - cMinScreenWidth:= min(cScreenWidth, 480); - cMinScreenHeight:= min(cScreenHeight, 320); + cMinScreenWidth:= min(cScreenWidth, cMinScreenWidth); + cMinScreenHeight:= min(cScreenHeight, cMinScreenHeight); cOrigScreenWidth:= cScreenWidth; cOrigScreenHeight:= cScreenHeight; diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/uAIAmmoTests.pas --- a/hedgewars/uAIAmmoTests.pas Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/uAIAmmoTests.pas Fri Sep 16 15:26:02 2011 -0400 @@ -105,7 +105,7 @@ (proc: @TestHammer; flags: 0), // amHammer (proc: nil; flags: 0), // amResurrector (proc: nil; flags: 0), // amDrillStrike - (proc: @TestSnowball; flags: 0), // amSnowball + (proc: nil; flags: 0), // amSnowball (proc: nil; flags: 0), // amTardis (proc: nil; flags: 0), // amStructure (proc: nil; flags: 0) // amLandGun diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/uAIMisc.pas --- a/hedgewars/uAIMisc.pas Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/uAIMisc.pas Fri Sep 16 15:26:02 2011 -0400 @@ -112,7 +112,7 @@ end; if e > f then friendlyfactor:= 300 + (e - f) * 30 -else friendlyfactor:= max(30, 300 - f * 80 div e) +else friendlyfactor:= max(30, 300 - f * 80 div max(1,e)) end; procedure FillBonuses(isAfterAttack: boolean; filter: TGearsType); diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/uAmmos.pas --- a/hedgewars/uAmmos.pas Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/uAmmos.pas Fri Sep 16 15:26:02 2011 -0400 @@ -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 f5dcef0bb8b9 -r d4680c51b220 hedgewars/uCollisions.pas --- a/hedgewars/uCollisions.pas Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/uCollisions.pas Fri Sep 16 15:26:02 2011 -0400 @@ -50,7 +50,8 @@ 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; +function TestRectancleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean; +function CalcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): Boolean; implementation uses uConsts, uLandGraphics, uVariables, uDebug, uGears; @@ -349,8 +350,42 @@ Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY) end; +function TestRectancleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean; +var x, y: LongInt; + TestWord: LongWord; +begin +if landOnly then + TestWord:= 255 +else + TestWord:= 0; -function calcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): boolean; +if x1 > x2 then +begin + x := x1; + x1 := x2; + x2 := x; +end; + +if y1 > y2 then +begin + y := y1; + y1 := y2; + y2 := y; +end; + +if (hasBorder and ((y1 < 0) or (x1 < 0) or (x2 > LAND_WIDTH))) then + exit(true); + +for y := y1 to y2 do + for x := x1 to x2 do + if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) + and (Land[y, x] > TestWord) then + exit(true); + +TestRectancleForObstacle:= false +end; + +function CalcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): boolean; var ldx, ldy, rdx, rdy: LongInt; i, j, mx, my, li, ri, jfr, jto, tmpo : ShortInt; tmpx, tmpy: LongWord; diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/uFloat.pas diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/uGame.pas --- a/hedgewars/uGame.pas Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/uGame.pas Fri Sep 16 15:26:02 2011 -0400 @@ -72,7 +72,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 f5dcef0bb8b9 -r d4680c51b220 hedgewars/uGears.pas --- a/hedgewars/uGears.pas Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/uGears.pas Fri Sep 16 15:26:02 2011 -0400 @@ -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); @@ -601,6 +603,7 @@ else if Gear^.Kind = gtHedgehog then if (CurAmmoGear <> nil) and (CurrentHedgehog^.Gear = Gear) then begin + AttackBar:= 0; Gear^.Message:= gmDestroy; CurAmmoGear^.Message:= gmDestroy; exit @@ -618,6 +621,7 @@ team:= Gear^.Hedgehog^.Team; if CurrentHedgehog^.Gear = Gear then begin + AttackBar:= 0; FreeActionsList; // to avoid ThinkThread on drawned gear if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (CurrentHedgehog^.MultiShootAttacks > 0) then OnUsedAmmo(CurrentHedgehog^); end; @@ -991,7 +995,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 @@ -1650,6 +1657,7 @@ procedure ResurrectHedgehog(gear: PGear); var tempTeam : PTeam; begin + AttackBar:= 0; gear^.dX := _0; gear^.dY := _0; gear^.Damage := 0; @@ -1747,7 +1755,6 @@ if (t > 0) then begin t:= GetRandom(t); - AddFileLog(inttostr(t)+' --------------'); while t >= 0 do begin inc(i); diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/uGearsRender.pas --- a/hedgewars/uGearsRender.pas Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/uGearsRender.pas Fri Sep 16 15:26:02 2011 -0400 @@ -328,7 +328,7 @@ hx:= ox + 8 * sign; hy:= oy - 2; aangle:= Gear^.Angle * 180 / cMaxAngle - 90; - if CurAmmoGear <> nil then + if (CurAmmoGear <> nil) and (CurAmmoGear^.Kind <> gtTardis) then begin case CurAmmoGear^.Kind of gtShotgunShot: begin @@ -886,7 +886,10 @@ gtGrenade: DrawRotated(sprBomb, x, y, 0, Gear^.DirAngle); gtSnowball: DrawRotated(sprSnowball, x, y, 0, Gear^.DirAngle); gtGasBomb: DrawRotated(sprCheese, x, y, 0, Gear^.DirAngle); - gtMolotov: DrawRotated(sprMolotov, x, y, 0, Gear^.DirAngle); + + gtMolotov: if (Gear^.State and gstDrowning) = 0 then + DrawRotatedF(sprMolotov, x, y, (RealTicks div 125) mod 8, hwSign(Gear^.dX), Gear^.DirAngle * hwSign(Gear^.dX)) + else DrawSprite(sprMolotov, x, y, 8); gtRCPlane: begin if (Gear^.Tag = -1) then @@ -1071,14 +1074,18 @@ //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 diff -r f5dcef0bb8b9 -r d4680c51b220 hedgewars/uIO.pas --- a/hedgewars/uIO.pas Thu Sep 08 00:34:57 2011 +0200 +++ b/hedgewars/uIO.pas Fri Sep 16 15:26:02 2011 -0400 @@ -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]