# HG changeset patch # User koda # Date 1316032779 -7200 # Node ID ed9676dc8cb48ff4067c59dd418f3b19a8f4c43f # Parent 190d6bb075c57fcec94c05f38de7334a53028995# Parent 0a00bbe97e22d9843cf9428818061f30b8c4549d merge diff -r 190d6bb075c5 -r ed9676dc8cb4 CMakeLists.txt --- a/CMakeLists.txt Wed Sep 14 22:27:22 2011 +0200 +++ b/CMakeLists.txt Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 ChangeLog.txt --- a/ChangeLog.txt Wed Sep 14 22:27:22 2011 +0200 +++ b/ChangeLog.txt Wed Sep 14 22:39:39 2011 +0200 @@ -2,11 +2,16 @@ * bugfixes 0.9.15 -> ???: - + New modes: The Specialists, Space Invasion + + New gameplay modes/styles: Racer, The Specialists, Tumbler, Space Invasion + 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 + 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 + + 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,9 +27,12 @@ + 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! + + Allow window resizes during game. * 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 diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/CMakeLists.txt --- a/QTfrontend/CMakeLists.txt Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/CMakeLists.txt Wed Sep 14 22:39:39 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) @@ -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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/SDLs.cpp --- a/QTfrontend/SDLs.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/SDLs.cpp Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/ammoSchemeModel.cpp --- a/QTfrontend/ammoSchemeModel.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/ammoSchemeModel.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -48,21 +48,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(45) // turn time 26 - << QVariant(100) // init health 27 - << QVariant(15) // sudden death 28 - << QVariant(5) // case prob 29 - << QVariant(3) // mines time 30 - << QVariant(4) // mines number 31 - << QVariant(0) // mine dud pct 32 - << QVariant(2) // explosives 33 - << QVariant(35) // health case pct 34 - << QVariant(25) // health case amt 35 - << QVariant(47) // water rise amt 36 - << QVariant(5) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(45) // turn time 27 + << QVariant(100) // init health 28 + << QVariant(15) // sudden death 29 + << QVariant(5) // case prob 30 + << QVariant(3) // mines time 31 + << QVariant(4) // mines number 32 + << QVariant(0) // mine dud pct 33 + << QVariant(2) // explosives 34 + << QVariant(35) // health case pct 35 + << QVariant(25) // health case amt 36 + << QVariant(47) // water rise amt 37 + << QVariant(5) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; AmmoSchemeModel::AmmoSchemeModel(QObject* parent, const QString & fileName) : @@ -111,21 +112,22 @@ << "disablewind" // 22 << "morewind" // 23 << "tagteam" // 24 - << "damagefactor" // 25 - << "turntime" // 26 - << "health" // 27 - << "suddendeath" // 28 - << "caseprobability" // 29 - << "minestime" // 30 - << "minesnum" // 31 - << "minedudpct" // 32 - << "explosives" // 33 - << "healthprobability" // 34 - << "healthcaseamount" // 35 - << "waterrise" // 36 - << "healthdecrease" // 37 - << "ropepct" // 38 - << "getawaytime" // 39 + << "bottomborder" // 25 + << "damagefactor" // 26 + << "turntime" // 27 + << "health" // 28 + << "suddendeath" // 29 + << "caseprobability" // 30 + << "minestime" // 31 + << "minesnum" // 32 + << "minedudpct" // 33 + << "explosives" // 34 + << "healthprobability" // 35 + << "healthcaseamount" // 36 + << "waterrise" // 37 + << "healthdecrease" // 38 + << "ropepct" // 39 + << "getawaytime" // 40 ; QList proMode; @@ -155,21 +157,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(15) // turn time 26 - << QVariant(100) // init health 27 - << QVariant(15) // sudden death 28 - << QVariant(0) // case prob 29 - << QVariant(3) // mines time 30 - << QVariant(0) // mines number 31 - << QVariant(0) // mine dud pct 32 - << QVariant(2) // explosives 33 - << QVariant(35) // health case pct 34 - << QVariant(25) // health case amt 35 - << QVariant(47) // water rise amt 36 - << QVariant(5) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(15) // turn time 27 + << QVariant(100) // init health 28 + << QVariant(15) // sudden death 29 + << QVariant(0) // case prob 30 + << QVariant(3) // mines time 31 + << QVariant(0) // mines number 32 + << QVariant(0) // mine dud pct 33 + << QVariant(2) // explosives 34 + << QVariant(35) // health case pct 35 + << QVariant(25) // health case amt 36 + << QVariant(47) // water rise amt 37 + << QVariant(5) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; QList shoppa; @@ -199,21 +202,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(30) // turn time 26 - << QVariant(100) // init health 27 - << QVariant(50) // sudden death 28 - << QVariant(1) // case prob 29 - << QVariant(3) // mines time 30 - << QVariant(0) // mines number 31 - << QVariant(0) // mine dud pct 32 - << QVariant(0) // explosives 33 - << QVariant(0) // health case pct 34 - << QVariant(25) // health case amt 35 - << QVariant(47) // water rise amt 36 - << QVariant(5) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(30) // turn time 27 + << QVariant(100) // init health 28 + << QVariant(50) // sudden death 29 + << QVariant(1) // case prob 30 + << QVariant(3) // mines time 31 + << QVariant(0) // mines number 32 + << QVariant(0) // mine dud pct 33 + << QVariant(0) // explosives 34 + << QVariant(0) // health case pct 35 + << QVariant(25) // health case amt 36 + << QVariant(47) // water rise amt 37 + << QVariant(5) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; QList cleanslate; @@ -243,21 +247,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(45) // turn time 26 - << QVariant(100) // init health 27 - << QVariant(15) // sudden death 28 - << QVariant(5) // case prob 29 - << QVariant(3) // mines time 30 - << QVariant(4) // mines number 31 - << QVariant(0) // mine dud pct 32 - << QVariant(2) // explosives 33 - << QVariant(35) // health case pct 34 - << QVariant(25) // health case amt 35 - << QVariant(47) // water rise amt 36 - << QVariant(5) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(45) // turn time 27 + << QVariant(100) // init health 28 + << QVariant(15) // sudden death 29 + << QVariant(5) // case prob 30 + << QVariant(3) // mines time 31 + << QVariant(4) // mines number 32 + << QVariant(0) // mine dud pct 33 + << QVariant(2) // explosives 34 + << QVariant(35) // health case pct 35 + << QVariant(25) // health case amt 36 + << QVariant(47) // water rise amt 37 + << QVariant(5) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; QList minefield; @@ -287,21 +292,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(30) // turn time 26 - << QVariant(50) // init health 27 - << QVariant(15) // sudden death 28 - << QVariant(0) // case prob 29 - << QVariant(0) // mines time 30 - << QVariant(80) // mines number 31 - << QVariant(0) // mine dud pct 32 - << QVariant(0) // explosives 33 - << QVariant(35) // health case pct 34 - << QVariant(25) // health case amt 35 - << QVariant(47) // water rise amt 36 - << QVariant(5) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(30) // turn time 27 + << QVariant(50) // init health 28 + << QVariant(15) // sudden death 29 + << QVariant(0) // case prob 30 + << QVariant(0) // mines time 31 + << QVariant(80) // mines number 32 + << QVariant(0) // mine dud pct 33 + << QVariant(0) // explosives 34 + << QVariant(35) // health case pct 35 + << QVariant(25) // health case amt 36 + << QVariant(47) // water rise amt 37 + << QVariant(5) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; QList barrelmayhem; @@ -331,21 +337,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(30) // turn time 26 - << QVariant(100) // init health 27 - << QVariant(15) // sudden death 28 - << QVariant(0) // case prob 29 - << QVariant(0) // mines time 30 - << QVariant(0) // mines number 31 - << QVariant(0) // mine dud pct 32 - << QVariant(80) // explosives 33 - << QVariant(35) // health case pct 34 - << QVariant(25) // health case amt 35 - << QVariant(47) // water rise amt 36 - << QVariant(5) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(30) // turn time 27 + << QVariant(100) // init health 28 + << QVariant(15) // sudden death 29 + << QVariant(0) // case prob 30 + << QVariant(0) // mines time 31 + << QVariant(0) // mines number 32 + << QVariant(0) // mine dud pct 33 + << QVariant(80) // explosives 34 + << QVariant(35) // health case pct 35 + << QVariant(25) // health case amt 36 + << QVariant(47) // water rise amt 37 + << QVariant(5) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; QList tunnelhogs; @@ -375,21 +382,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(30) // turn time 26 - << QVariant(100) // init health 27 - << QVariant(15) // sudden death 28 - << QVariant(5) // case prob 29 - << QVariant(3) // mines time 30 - << QVariant(10) // mines number 31 - << QVariant(10) // mine dud pct 32 - << QVariant(10) // explosives 33 - << QVariant(35) // health case pct 34 - << QVariant(25) // health case amt 35 - << QVariant(47) // water rise amt 36 - << QVariant(5) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(30) // turn time 27 + << QVariant(100) // init health 28 + << QVariant(15) // sudden death 29 + << QVariant(5) // case prob 30 + << QVariant(3) // mines time 31 + << QVariant(10) // mines number 32 + << QVariant(10) // mine dud pct 33 + << QVariant(10) // explosives 34 + << QVariant(35) // health case pct 35 + << QVariant(25) // health case amt 36 + << QVariant(47) // water rise amt 37 + << QVariant(5) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; QList forts; @@ -419,21 +427,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(45) // turn time 26 - << QVariant(100) // init health 27 - << QVariant(15) // sudden death 28 - << QVariant(5) // case prob 29 - << QVariant(3) // mines time 30 - << QVariant(0) // mines number 31 - << QVariant(0) // mine dud pct 32 - << QVariant(0) // explosives 33 - << QVariant(35) // health case pct 34 - << QVariant(25) // health case amt 35 - << QVariant(47) // water rise amt 36 - << QVariant(5) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(45) // turn time 27 + << QVariant(100) // init health 28 + << QVariant(15) // sudden death 29 + << QVariant(5) // case prob 30 + << QVariant(3) // mines time 31 + << QVariant(0) // mines number 32 + << QVariant(0) // mine dud pct 33 + << QVariant(0) // explosives 34 + << QVariant(35) // health case pct 35 + << QVariant(25) // health case amt 36 + << QVariant(47) // water rise amt 37 + << QVariant(5) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; QList timeless; @@ -463,21 +472,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(9999) // turn time 26 - << QVariant(100) // init health 27 - << QVariant(15) // sudden death 28 - << QVariant(5) // case prob 29 - << QVariant(3) // mines time 30 - << QVariant(5) // mines number 31 - << QVariant(10) // mine dud pct 32 - << QVariant(2) // explosives 33 - << QVariant(35) // health case pct 34 - << QVariant(30) // health case amt 35 - << QVariant(0) // water rise amt 36 - << QVariant(0) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(9999) // turn time 27 + << QVariant(100) // init health 28 + << QVariant(15) // sudden death 29 + << QVariant(5) // case prob 30 + << QVariant(3) // mines time 31 + << QVariant(5) // mines number 32 + << QVariant(10) // mine dud pct 33 + << QVariant(2) // explosives 34 + << QVariant(35) // health case pct 35 + << QVariant(30) // health case amt 36 + << QVariant(0) // water rise amt 37 + << QVariant(0) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; QList thinkingportals; @@ -507,21 +517,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(45) // turn time 26 - << QVariant(100) // init health 27 - << QVariant(15) // sudden death 28 - << QVariant(2) // case prob 29 - << QVariant(3) // mines time 30 - << QVariant(5) // mines number 31 - << QVariant(0) // mine dud pct 32 - << QVariant(5) // explosives 33 - << QVariant(25) // health case pct 34 - << QVariant(25) // health case amt 35 - << QVariant(47) // water rise amt 36 - << QVariant(5) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(45) // turn time 27 + << QVariant(100) // init health 28 + << QVariant(15) // sudden death 29 + << QVariant(2) // case prob 30 + << QVariant(3) // mines time 31 + << QVariant(5) // mines number 32 + << QVariant(0) // mine dud pct 33 + << QVariant(5) // explosives 34 + << QVariant(25) // health case pct 35 + << QVariant(25) // health case amt 36 + << QVariant(47) // water rise amt 37 + << QVariant(5) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; QList kingmode; @@ -551,21 +562,22 @@ << QVariant(false) // no wind 22 << QVariant(false) // more wind 23 << QVariant(false) // tag team 24 - << QVariant(100) // damage modfier 25 - << QVariant(45) // turn time 26 - << QVariant(100) // init health 27 - << QVariant(15) // sudden death 28 - << QVariant(5) // case prob 29 - << QVariant(3) // mines time 30 - << QVariant(4) // mines number 31 - << QVariant(0) // mine dud pct 32 - << QVariant(2) // explosives 33 - << QVariant(35) // health case pct 34 - << QVariant(25) // health case amt 35 - << QVariant(47) // water rise amt 36 - << QVariant(5) // health dec amt 37 - << QVariant(100) // rope modfier 38 - << QVariant(100) // get away time 39 + << QVariant(false) // bottom border 25 + << QVariant(100) // damage modfier 26 + << QVariant(45) // turn time 27 + << QVariant(100) // init health 28 + << QVariant(15) // sudden death 29 + << QVariant(5) // case prob 30 + << QVariant(3) // mines time 31 + << QVariant(4) // mines number 32 + << QVariant(0) // mine dud pct 33 + << QVariant(2) // explosives 34 + << QVariant(35) // health case pct 35 + << QVariant(25) // health case amt 36 + << QVariant(47) // water rise amt 37 + << QVariant(5) // health dec amt 38 + << QVariant(100) // rope modfier 39 + << QVariant(100) // get away time 40 ; @@ -771,4 +783,4 @@ netScheme[i] = QVariant(cfg[i]); reset(); -} +} diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/binds.cpp --- a/QTfrontend/binds.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/binds.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/binds.h --- a/QTfrontend/binds.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/binds.h Wed Sep 14 22:39:39 2011 +0200 @@ -21,11 +21,7 @@ #include -#ifdef _WIN32 -#define BINDS_NUMBER 43 -#else #define BINDS_NUMBER 44 -#endif struct BindAction { diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/chatwidget.cpp --- a/QTfrontend/chatwidget.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/chatwidget.cpp Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/databrowser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/databrowser.cpp Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/databrowser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/databrowser.h Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/drawmapscene.cpp --- a/QTfrontend/drawmapscene.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/drawmapscene.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/drawmapscene.h --- a/QTfrontend/drawmapscene.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/drawmapscene.h Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/game.cpp --- a/QTfrontend/game.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/game.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/game.h --- a/QTfrontend/game.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/game.h Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/gamecfgwidget.cpp --- a/QTfrontend/gamecfgwidget.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/gamecfgwidget.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -215,13 +215,15 @@ result |= 0x01000000; // more wind if (schemeData(24).toBool()) result |= 0x02000000; // tag team + if (schemeData(25).toBool()) + result |= 0x04000000; // bottom border return result; } quint32 GameCFGWidget::getInitHealth() const { - return schemeData(27).toInt(); + return schemeData(28).toInt(); } QByteArray GameCFGWidget::getFullConfig() const @@ -245,20 +247,20 @@ bcfg << QString("eseed " + pMapContainer->getCurrentSeed()).toUtf8(); bcfg << QString("e$gmflags %1").arg(getGameFlags()).toUtf8(); - bcfg << QString("e$damagepct %1").arg(schemeData(25).toInt()).toUtf8(); - bcfg << QString("e$turntime %1").arg(schemeData(26).toInt() * 1000).toUtf8(); - bcfg << QString("e$sd_turns %1").arg(schemeData(28).toInt()).toUtf8(); - bcfg << QString("e$casefreq %1").arg(schemeData(29).toInt()).toUtf8(); - bcfg << QString("e$minestime %1").arg(schemeData(30).toInt() * 1000).toUtf8(); - bcfg << QString("e$minesnum %1").arg(schemeData(31).toInt()).toUtf8(); - bcfg << QString("e$minedudpct %1").arg(schemeData(32).toInt()).toUtf8(); - bcfg << QString("e$explosives %1").arg(schemeData(33).toInt()).toUtf8(); - bcfg << QString("e$healthprob %1").arg(schemeData(34).toInt()).toUtf8(); - bcfg << QString("e$hcaseamount %1").arg(schemeData(35).toInt()).toUtf8(); - bcfg << QString("e$waterrise %1").arg(schemeData(36).toInt()).toUtf8(); - bcfg << QString("e$healthdec %1").arg(schemeData(37).toInt()).toUtf8(); - bcfg << QString("e$ropepct %1").arg(schemeData(38).toInt()).toUtf8(); - bcfg << QString("e$getawaytime %1").arg(schemeData(39).toInt()).toUtf8(); + bcfg << QString("e$damagepct %1").arg(schemeData(26).toInt()).toUtf8(); + bcfg << QString("e$turntime %1").arg(schemeData(27).toInt() * 1000).toUtf8(); + bcfg << QString("e$sd_turns %1").arg(schemeData(29).toInt()).toUtf8(); + bcfg << QString("e$casefreq %1").arg(schemeData(30).toInt()).toUtf8(); + bcfg << QString("e$minestime %1").arg(schemeData(31).toInt() * 1000).toUtf8(); + bcfg << QString("e$minesnum %1").arg(schemeData(32).toInt()).toUtf8(); + bcfg << QString("e$minedudpct %1").arg(schemeData(33).toInt()).toUtf8(); + bcfg << QString("e$explosives %1").arg(schemeData(34).toInt()).toUtf8(); + bcfg << QString("e$healthprob %1").arg(schemeData(35).toInt()).toUtf8(); + bcfg << QString("e$hcaseamount %1").arg(schemeData(36).toInt()).toUtf8(); + bcfg << QString("e$waterrise %1").arg(schemeData(37).toInt()).toUtf8(); + bcfg << QString("e$healthdec %1").arg(schemeData(38).toInt()).toUtf8(); + bcfg << QString("e$ropepct %1").arg(schemeData(39).toInt()).toUtf8(); + bcfg << QString("e$getawaytime %1").arg(schemeData(40).toInt()).toUtf8(); bcfg << QString("e$template_filter %1").arg(pMapContainer->getTemplateFilter()).toUtf8(); bcfg << QString("e$mapgen %1").arg(mapgen).toUtf8(); diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/hedgewars.qrc --- a/QTfrontend/hedgewars.qrc Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/hedgewars.qrc Wed Sep 14 22:39:39 2011 +0200 @@ -81,6 +81,7 @@ res/btnNoWind.png res/btnMoreWind.png res/btnTagTeam.png + res/btnBottomBorder.png res/iconBox.png res/iconHealth.png res/iconSuddenDeath.png diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/hwconsts.h --- a/QTfrontend/hwconsts.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/hwconsts.h Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/hwform.cpp --- a/QTfrontend/hwform.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/hwform.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -38,6 +38,7 @@ #include #include #include +#include #include "hwform.h" #include "game.h" @@ -92,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 @@ -103,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); @@ -151,12 +153,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 +230,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 +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(); @@ -722,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) @@ -731,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) @@ -1033,6 +1042,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 +1071,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 +1086,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 +1304,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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/hwform.h --- a/QTfrontend/hwform.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/hwform.h Wed Sep 14 22:39:39 2011 +0200 @@ -52,7 +52,7 @@ Q_OBJECT public: - HWForm(QWidget *parent = 0); + HWForm(QWidget *parent = 0, QString styleSheet = ""); Ui_HWForm ui; SDLInteraction sdli; GameUIConfig * config; @@ -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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/main.cpp --- a/QTfrontend/main.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/main.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -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;" @@ -315,8 +315,7 @@ "background-color: #ffcc00;" "width: 8px;" "}" - ) - ); + ); bindir->cd("bin"); // workaround over NSIS installer @@ -470,8 +469,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 +483,7 @@ CocoaInitializer initializer; #endif - app.form = new HWForm(); + app.form = new HWForm(NULL,styleSheetFromHell); app.form->show(); return app.exec(); diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/mapContainer.cpp --- a/QTfrontend/mapContainer.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/mapContainer.cpp Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/newnetclient.cpp --- a/QTfrontend/newnetclient.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/newnetclient.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pagedata.cpp --- a/QTfrontend/pagedata.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pagedata.cpp Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pagedata.h --- a/QTfrontend/pagedata.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pagedata.h Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pagedrawmap.cpp --- a/QTfrontend/pagedrawmap.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pagedrawmap.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -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);;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);;All files (*)")); if(!fileName.isEmpty()) drawMapWidget->save(fileName); diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pageeditteam.cpp --- a/QTfrontend/pageeditteam.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pageeditteam.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -358,10 +358,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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pagegamestats.cpp --- a/QTfrontend/pagegamestats.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pagegamestats.cpp Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pagegamestats.h --- a/QTfrontend/pagegamestats.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pagegamestats.h Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pagemain.cpp --- a/QTfrontend/pagemain.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pagemain.cpp Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pagemain.h --- a/QTfrontend/pagemain.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pagemain.h Wed Sep 14 22:39:39 2011 +0200 @@ -33,6 +33,7 @@ QPushButton *BtnSetup; QPushButton *BtnInfo; QPushButton *BtnExit; + QPushButton *BtnDataDownload; QLabel *mainNote; }; diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pageoptions.cpp --- a/QTfrontend/pageoptions.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pageoptions.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -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,34 +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; - this->CBResolution->setEnabled(!this->CBFullscreen->isChecked()); + 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pageoptions.h --- a/QTfrontend/pageoptions.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pageoptions.h Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pageplayrecord.cpp --- a/QTfrontend/pageplayrecord.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pageplayrecord.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -150,3 +150,8 @@ else FillFromDir(recType); } + +bool PagePlayDemo::isSave() +{ + return recType == RT_Save; +} diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pageplayrecord.h --- a/QTfrontend/pageplayrecord.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pageplayrecord.h Wed Sep 14 22:39:39 2011 +0200 @@ -39,6 +39,7 @@ PagePlayDemo(QWidget* parent = 0); void FillFromDir(RecordType rectype); + bool isSave(); QPushButton *BtnBack; QPushButton *BtnPlayDemo; diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pagescheme.cpp --- a/QTfrontend/pagescheme.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pagescheme.cpp Wed Sep 14 22:39:39 2011 +0200 @@ -78,7 +78,7 @@ glGMLayout->addWidget(TBW_solid,0,2,1,1); TBW_border = new ToggleButtonWidget(gbGameModes, ":/res/btnBorder.png"); - TBW_border->setToolTip("" + ToggleButtonWidget::tr("Add Border") + ":
" + tr("Add an indestructable border around the terrain")); + TBW_border->setToolTip("" + ToggleButtonWidget::tr("Add Border") + ":
" + tr("Add an indestructible border around the terrain")); glGMLayout->addWidget(TBW_border,0,3,1,1); TBW_lowGravity = new ToggleButtonWidget(gbGameModes, ":/res/btnLowGravity.png"); @@ -161,6 +161,11 @@ TBW_tagteam->setToolTip("" + ToggleButtonWidget::tr("Tag Team") + ":
" + tr("Teams in each clan take successive turns sharing their turn time.")); glGMLayout->addWidget(TBW_tagteam,4,3,1,1); + TBW_bottomborder = new ToggleButtonWidget(gbGameModes, ":/res/btnBottomBorder.png"); + TBW_bottomborder->setToolTip("" + ToggleButtonWidget::tr("Add Bottom Border") + ":
" + tr("Add an indestructible border along the bottom")); + glGMLayout->addWidget(TBW_bottomborder,4,4,1,1); + + // Right QLabel * l; @@ -430,21 +435,22 @@ mapper->addMapping(TBW_nowind, 22); mapper->addMapping(TBW_morewind, 23); mapper->addMapping(TBW_tagteam, 24); - mapper->addMapping(SB_DamageModifier, 25); - mapper->addMapping(SB_TurnTime, 26); - mapper->addMapping(SB_InitHealth, 27); - mapper->addMapping(SB_SuddenDeath, 28); - mapper->addMapping(SB_CaseProb, 29); - mapper->addMapping(SB_MinesTime, 30); - mapper->addMapping(SB_Mines, 31); - mapper->addMapping(SB_MineDuds, 32); - mapper->addMapping(SB_Explosives, 33); - mapper->addMapping(SB_HealthCrates, 34); - mapper->addMapping(SB_CrateHealth, 35); - mapper->addMapping(SB_WaterRise, 36); - mapper->addMapping(SB_HealthDecrease, 37); - mapper->addMapping(SB_RopeModifier, 38); - mapper->addMapping(SB_GetAwayTime, 39); + mapper->addMapping(TBW_bottomborder, 25); + mapper->addMapping(SB_DamageModifier, 26); + mapper->addMapping(SB_TurnTime, 27); + mapper->addMapping(SB_InitHealth, 28); + mapper->addMapping(SB_SuddenDeath, 29); + mapper->addMapping(SB_CaseProb, 30); + mapper->addMapping(SB_MinesTime, 31); + mapper->addMapping(SB_Mines, 32); + mapper->addMapping(SB_MineDuds, 33); + mapper->addMapping(SB_Explosives, 34); + mapper->addMapping(SB_HealthCrates, 35); + mapper->addMapping(SB_CrateHealth, 36); + mapper->addMapping(SB_WaterRise, 37); + mapper->addMapping(SB_HealthDecrease, 38); + mapper->addMapping(SB_RopeModifier, 39); + mapper->addMapping(SB_GetAwayTime, 40); mapper->toFirst(); } diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/pagescheme.h --- a/QTfrontend/pagescheme.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/pagescheme.h Wed Sep 14 22:39:39 2011 +0200 @@ -71,6 +71,7 @@ ToggleButtonWidget * TBW_nowind; ToggleButtonWidget * TBW_morewind; ToggleButtonWidget * TBW_tagteam; + ToggleButtonWidget * TBW_bottomborder; QSpinBox * SB_DamageModifier; QSpinBox * SB_TurnTime; diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/res/btnBottomBorder.png Binary file QTfrontend/res/btnBottomBorder.png has changed diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/res/btnTagTeam.png Binary file QTfrontend/res/btnTagTeam.png has changed diff -r 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/teamselect.cpp --- a/QTfrontend/teamselect.cpp Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/teamselect.cpp Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 QTfrontend/teamselect.h --- a/QTfrontend/teamselect.h Wed Sep 14 22:27:22 2011 +0200 +++ b/QTfrontend/teamselect.h Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 gameServer/Utils.hs --- a/gameServer/Utils.hs Wed Sep 14 22:27:22 2011 +0200 +++ b/gameServer/Utils.hs Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 hedgewars/CMakeLists.txt --- a/hedgewars/CMakeLists.txt Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/CMakeLists.txt Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/GSHandlers.inc Wed Sep 14 22:39:39 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; @@ -483,18 +512,39 @@ 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 2 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; + end; for i:= 0 to 24 do begin dX := AngleCos(i * 2) * ((_0_15*(i div 5))) * (GetRandom + _1); @@ -766,8 +816,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 +867,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; @@ -914,6 +980,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; @@ -932,6 +1036,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) @@ -977,31 +1094,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; @@ -1110,7 +1203,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 +1313,8 @@ begin AllInactive := false; dec(Gear^.Timer); + if ((GameFlags and gfInfAttack) <> 0) and (TurnTimeLeft > 0) then dec(TurnTimeLeft); + HHGear := Gear^.Hedgehog^.Gear; HedgehogChAngle(HHGear); @@ -1226,21 +1322,21 @@ b := false; if abs(LongInt(HHGear^.Angle) - BTPrevAngle) > 7 then - begin - Gear^.dX := SignAs(AngleSin(HHGear^.Angle) * _0_5, HHGear^.dX); + begin + Gear^.dX := SignAs(AngleSin(HHGear^.Angle) * _0_5, Gear^.dX); Gear^.dY := AngleCos(HHGear^.Angle) * ( - _0_5); BTPrevAngle := HHGear^.Angle; b := true - end; + end; if ((HHGear^.State and gstMoving) <> 0) then - begin + begin doStepHedgehogMoving(HHGear); if (HHGear^.State and gstHHDriven) = 0 then Gear^.Timer := 0 - end; + end; if Gear^.Timer mod cHHStepTicks = 0 then - begin + begin b := true; if Gear^.dX.isNegative then HHGear^.Message := (HHGear^.Message and (gmAttack or gmUp or gmDown)) or gmLeft @@ -1248,7 +1344,7 @@ HHGear^.Message := (HHGear^.Message and (gmAttack or gmUp or gmDown)) or gmRight; if ((HHGear^.State and gstMoving) = 0) then - begin + begin HHGear^.State := HHGear^.State and not gstAttacking; prevX := hwRound(HHGear^.X); @@ -1261,24 +1357,24 @@ CheckLandValue(hwRound(HHGear^.X + SignAs(_6, HHGear^.dX)), hwRound(HHGear^.Y), lfIndestructible) then HHGear^.X := HHGear^.X + SignAs(_1, HHGear^.dX); HHGear^.State := HHGear^.State or gstAttacking - end; + end; inc(BTSteps); if BTSteps = 7 then - begin + begin BTSteps := 0; if CheckLandValue(hwRound(HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC) + SignAs(_6, Gear^.dX)), hwRound(HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC)), lfIndestructible) then - begin + begin Gear^.X := HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC); Gear^.Y := HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC); - end; + end; HHGear^.State := HHGear^.State or gstNoDamage; AmmoShove(Gear, 2, 15); HHGear^.State := HHGear^.State and not gstNoDamage + end; end; - end; if b then DrawTunnel(HHGear^.X - Gear^.dX * cHHRadius, HHGear^.Y - _4 - Gear^.dY * cHHRadius + hwAbs( @@ -1286,13 +1382,13 @@ Gear^.dX, Gear^.dY, cHHRadius * 5, cHHRadius * 2 + 7); - if (Gear^.Timer = 0) or ((HHGear^.Message and gmAttack) <> 0) then - begin + 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); DeleteGear(Gear); AfterAttack - end + end end; procedure doStepBlowTorch(Gear: PGear); @@ -1357,7 +1453,7 @@ var HHGear: PGear; len, tx, ty, nx, ny, ropeDx, ropeDy, mdX, mdY: hwFloat; - lx, ly: LongInt; + lx, ly, cd: LongInt; haveCollision, haveDivided: boolean; @@ -1398,16 +1494,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); @@ -2603,7 +2713,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]; @@ -2674,6 +2784,7 @@ var i: LongWord; HHGear: PGear; + sparkles: PVisualGear; begin AllInactive := false; @@ -2683,9 +2794,15 @@ Gear^.X := HHGear^.X; Gear^.Y := HHGear^.Y; + if (GameTicks mod 2 = 0) and ((Gear^.Message and (gmPrecise or gmSwitch)) = (gmPrecise or gmSwitch)) then + begin + sparkles:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtDust, 1); + if sparkles <> nil then sparkles^.Tint:= ((random(210)+45) shl 24) or ((random(210)+45) shl 16) or ((random(210)+45) shl 8) or $FF; + end; i := 2; repeat + Gear^.X := Gear^.X + HHGear^.dX; Gear^.Y := Gear^.Y + HHGear^.dY; HHGear^.X := Gear^.X; @@ -2884,7 +3001,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 @@ -2949,10 +3066,8 @@ //////////////////////////////////////////////////////////////////////////////// procedure doStepSeductionWork(Gear: PGear); -var - x, y, i: LongInt; +var i: LongInt; hogs: TPGearArray; - d: hwFloat; begin AllInactive := false; hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Radius); @@ -3021,7 +3136,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; @@ -3678,10 +3793,10 @@ AllInactive := false; FollowGear := HHGear; with HHGear^ do - begin + begin State := State and not gstAttacking; Message := Message and not (gmAttack or gmUp or gmPrecise or gmLeft or gmRight) - end + end end; //////////////////////////////////////////////////////////////////////////////// @@ -3866,12 +3981,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; // @@ -3899,8 +4022,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; @@ -3927,8 +4053,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; @@ -3979,8 +4104,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 @@ -3988,8 +4113,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; @@ -4010,11 +4135,19 @@ // // 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; + // 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 @@ -4076,7 +4209,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); @@ -4902,47 +5035,137 @@ end; //////////////////////////////////////////////////////////////////////////////// -procedure doStepTardis(Gear: PGear); -(*var - i, x, y: LongInt; - dX, dY: hwFloat; - Fire: PGear; - vg: PVisualGear;*) +(* + TARDIS needs + Warp in. Pos = 1 + Pause. Pos = 2 + Hide gear (TARDIS hedgehog was nil) + Warp out. Pos = 3 + ... idle active for some time period ... Pos = 4 + Warp in. Pos = 1 + Pause. Pos = 2 + Restore gear (TARDIS hedgehog was not nil) + Warp out. Pos = 3 +*) + +procedure doStepTardisWarp(Gear: PGear); +var HH: PHedgehog; + i,j,cnt: LongWord; begin - if (Gear^.State and gstTmpFlag) = 0 then dec(Gear^.Timer); - if (Gear^.Timer = 0) and (CurAmmoGear = Gear) then + +HH:= Gear^.Hedgehog; +if Gear^.Pos = 2 then + begin + StopSound(Gear^.SoundChannel); + if (Gear^.Timer = 0) then begin - if (CurrentHedgehog = nil) or (CurrentHedgehog^.Gear = nil) then + if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible = 0) then begin - DeleteGear(Gear); - exit - end; - if Gear = CurAmmoGear then CurAmmoGear := nil; - Gear^.Hedgehog:= CurrentHedgehog; - RemoveGearFromList(CurrentHedgehog^.Gear); - CurrentHedgehog^.Gear^.Z := cHHZ; - CurrentHedgehog^.Gear^.Active := false; - CurrentHedgehog^.Gear^.State:= CurrentHedgehog^.Gear^.State and not gstHHDriven; - CurrentHedgehog^.GearHidden:= CurrentHedgehog^.Gear; - CurrentHedgehog^.Gear:= nil; - Gear^.State:= Gear^.State or gstTmpFlag; - Gear^.Timer:= GameTicks + GetRandom(cHedgehogTurnTime*TeamsCount)+cHedgehogTurnTime; + AfterAttack; + if Gear = CurAmmoGear then CurAmmoGear := 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 + RestoreHog(HH) + end; + + inc(Gear^.Timer); + if (Gear^.Timer > 2000) and ((GameTicks mod 2000) = 1000) then + begin + Gear^.SoundChannel := LoopSound(sndTardis); + Gear^.Pos:= 3 end - else if (((Gear^.State and gstTmpFlag) <> 0) and (Gear^.Timer = GameTicks)) or SuddenDeath then + end; + +if (Gear^.Pos = 1) and (GameTicks and $1F = 0) and (Gear^.Power < 255) then inc(Gear^.Power); +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 + begin + StopSound(Gear^.SoundChannel); + if HH^.GearHidden = nil then begin - if Gear^.Hedgehog <> nil then + DeleteGear(Gear); + exit + end; + Gear^.Pos:= 4; + // This condition might need tweaking + Gear^.Timer:= GetRandom(cHedgehogTurnTime*TeamsCount)+cHedgehogTurnTime + end; + +if (Gear^.Pos = 4) then + begin + cnt:= 0; + for j:= 0 to Pred(HH^.Team^.Clan^.TeamsNumber) do + for i:= 0 to Pred(HH^.Team^.Clan^.Teams[j]^.HedgehogsNumber) do + if (HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear <> nil) and + ((HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.State and gstDrowning) = 0) and + (HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.Health > + 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 - Gear^.Hedgehog^.Gear:= Gear^.Hedgehog^.GearHidden; - Gear^.Hedgehog^.GearHidden:= nil; - FindPlace(Gear^.Hedgehog^.Gear, false, 0, LAND_WIDTH,true); - InsertGearToList(Gear^.Hedgehog^.Gear); - Gear^.Hedgehog^.Gear^.State:= (Gear^.Hedgehog^.Gear^.State or gstTmpFlag or gstAttacked) and not gstHHDriven; - Gear^.Hedgehog^.Gear^.Timer:= $FF; - Gear^.Hedgehog^.Gear^.doStep:= @doStepHedgehogReturn; - SetAllHHToActive; - end; - DeleteGear(Gear) + 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); + end; + +end; + +procedure doStepTardis(Gear: PGear); +var i,j,cnt: LongWord; + HH: PHedgehog; +begin +(* + Conditions for not activating. + 1. Hog is last of his clan + 2. Sudden Death is in play + 3. Hog is a king +*) + HH:= Gear^.Hedgehog; + if (HH^.Gear = nil) or (HH^.King) or (SuddenDeathDmg) then + begin + if HH^.Gear <> nil then + begin + HH^.Gear^.Message := HH^.Gear^.Message and not gmAttack; + HH^.Gear^.State:= HH^.Gear^.State and not gstAttacking; + end; + PlaySound(sndDenied); + DeleteGear(gear); + exit + end; + cnt:= 0; + for j:= 0 to Pred(HH^.Team^.Clan^.TeamsNumber) do + for i:= 0 to Pred(HH^.Team^.Clan^.Teams[j]^.HedgehogsNumber) do + if (HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear <> nil) and + ((HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.State and gstDrowning) = 0) and + (HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.Health > + HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.Damage) then inc(cnt); + if cnt < 2 then + begin + if HH^.Gear <> nil then + begin + HH^.Gear^.Message := HH^.Gear^.Message and not gmAttack; + HH^.Gear^.State:= HH^.Gear^.State and not gstAttacking; + end; + PlaySound(sndDenied); + DeleteGear(gear); + exit + end; + Gear^.SoundChannel := LoopSound(sndTardis); + Gear^.doStep:= @doStepTardisWarp end; //////////////////////////////////////////////////////////////////////////////// diff -r 190d6bb075c5 -r ed9676dc8cb4 hedgewars/HHHandlers.inc --- a/hedgewars/HHHandlers.inc Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/HHHandlers.inc Wed Sep 14 22:39:39 2011 +0200 @@ -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; @@ -423,7 +422,8 @@ end end else Message:= Message and not gmAttack; end; - TargetPoint.X := NoPointX + TargetPoint.X := NoPointX; + ScriptCall('onHogAttack'); end; procedure AfterAttack; @@ -774,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 @@ -1033,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 @@ -1047,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 @@ -1089,17 +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; - -procedure doStepHedgehogReturn(Gear: PGear); -begin -if (Gear^.Timer > 0) and ((GameTicks mod 20) = 0) then dec(Gear^.Timer) -else if (Gear^.Timer = 0) then - begin - Gear^.doStep:= @doStepHedgehog; - Gear^.State:= Gear^.State and not gstTmpFlag; - end -end; diff -r 190d6bb075c5 -r ed9676dc8cb4 hedgewars/SDLh.pas --- a/hedgewars/SDLh.pas Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/SDLh.pas Wed Sep 14 22:39:39 2011 +0200 @@ -278,6 +278,11 @@ IMG_INIT_PNG = $00000002; IMG_INIT_TIF = $00000004; + {* SDL_EventMask type definition *} +{$IFNDEF SDL13} + SDL_ALLEVENTS = $FFFFFFFF; +{$ENDIF} + ///////////////////////////////////////////////////////////////// /////////////////////// TYPE DEFINITIONS /////////////////////// ///////////////////////////////////////////////////////////////// @@ -347,6 +352,7 @@ {$ENDIF} end; + SDL_eventaction = (SDL_ADDEVENT = 0, SDL_PEEPEVENT, SDL_GETEVENT); PSDL_Surface = ^TSDL_Surface; TSDL_Surface = record @@ -612,6 +618,8 @@ {$ENDIF} end; + TSDL_EventFilter = function( event : PSDL_Event ): Integer; cdecl; + PByteArray = ^TByteArray; TByteArray = array[0..65535] of Byte; PLongWordArray = ^TLongWordArray; @@ -793,6 +801,10 @@ 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; @@ -801,6 +813,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; diff -r 190d6bb075c5 -r ed9676dc8cb4 hedgewars/VGSHandlers.inc --- a/hedgewars/VGSHandlers.inc Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/VGSHandlers.inc Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/hwengine.pas Wed Sep 14 22:39:39 2011 +0200 @@ -149,8 +149,12 @@ PrevTime:= SDL_GetTicks; while isTerminated = false do begin - - while SDL_PollEvent(@event) <> 0 do + SDL_PumpEvents(); + {$IFDEF SDL13} + while SDL_PeepEvents(@event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0 do + {$ELSE} + while SDL_PeepEvents(@event, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0 do + {$ENDIF} begin case event.type_ of SDL_KEYDOWN: if GameState = gsChat then @@ -176,14 +180,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); @@ -193,6 +196,17 @@ 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)); + ScriptOnScreenResize(); + InitCameraBorders() + end; if isTerminated = false then begin @@ -240,12 +254,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); diff -r 190d6bb075c5 -r ed9676dc8cb4 hedgewars/uAIMisc.pas --- a/hedgewars/uAIMisc.pas Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/uAIMisc.pas Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 hedgewars/uAmmos.pas --- a/hedgewars/uAmmos.pas Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/uAmmos.pas Wed Sep 14 22:39:39 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 190d6bb075c5 -r ed9676dc8cb4 hedgewars/uCollisions.pas --- a/hedgewars/uCollisions.pas Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/uCollisions.pas Wed Sep 14 22:39:39 2011 +0200 @@ -47,10 +47,11 @@ 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; +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; @@ -291,11 +292,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,17 +340,49 @@ 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; +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; + +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 190d6bb075c5 -r ed9676dc8cb4 hedgewars/uConsts.pas --- a/hedgewars/uConsts.pas Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/uConsts.pas Wed Sep 14 22:39:39 2011 +0200 @@ -196,6 +196,7 @@ gfDisableWind = $00800000; gfMoreWind = $01000000; gfTagTeam = $02000000; + gfBottomBorder = $04000000; // NOTE: When adding new game flags, ask yourself // if a "game start notice" would be useful. If so, // add one in uWorld.pas - look for "AddGoal". diff -r 190d6bb075c5 -r ed9676dc8cb4 hedgewars/uFloat.pas diff -r 190d6bb075c5 -r ed9676dc8cb4 hedgewars/uGame.pas --- a/hedgewars/uGame.pas Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/uGame.pas Wed Sep 14 22:39:39 2011 +0200 @@ -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 190d6bb075c5 -r ed9676dc8cb4 hedgewars/uGears.pas --- a/hedgewars/uGears.pas Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/uGears.pas Wed Sep 14 22:39:39 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); @@ -75,7 +77,6 @@ procedure AfterAttack; forward; procedure HedgehogStep(Gear: PGear); forward; procedure doStepHedgehogMoving(Gear: PGear); forward; -procedure doStepHedgehogReturn(Gear: PGear); forward; procedure HedgehogChAngle(HHGear: PGear); forward; procedure ShotgunShot(Gear: PGear); forward; procedure PickUp(HH, Gear: PGear); forward; @@ -218,7 +219,6 @@ gear^.doStep:= doStepHandlers[Kind]; gear^.CollisionIndex:= -1; gear^.Timer:= Timer; -gear^.Z:= cUsualZ; gear^.FlightTime:= 0; gear^.uid:= Counter; gear^.SoundChannel:= -1; @@ -226,6 +226,8 @@ gear^.nImpactSounds:= 0; // Define ammo association, if any. gear^.AmmoType:= GearKindAmmoTypeMap[Kind]; +if Ammoz[Gear^.AmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then gear^.Z:= cHHZ+1 +else gear^.Z:= cUsualZ; if CurrentHedgehog <> nil then begin @@ -372,7 +374,8 @@ gear^.Elasticity:= _0_4; gear^.Friction:= _0_995; gear^.Density:= _6; - gear^.Health:= cBarrelHealth + gear^.Health:= cBarrelHealth; + gear^.Z:= cHHZ-1 end; gtDEagleShot: begin gear^.Radius:= 1; @@ -428,6 +431,11 @@ gear^.Elasticity:= _0_3; gear^.Timer:= 0 end; + gtTardis: begin + gear^.Timer:= 0; + gear^.Pos:= 1; + gear^.Z:= cCurrHHZ+1; + end; gtMortar: begin gear^.Radius:= 4; gear^.Elasticity:= _0_2; @@ -595,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 @@ -612,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; @@ -938,7 +948,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 @@ -985,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 @@ -1450,7 +1463,11 @@ ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove) else Gear^.State:= Gear^.State or gstWinner; - if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch + if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then + begin + if (Ammo^.Hedgehog^.Gear <> nil) then Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and not gstNotKickable; + ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch + end; DeleteCI(Gear); if (Gear^.Kind = gtHedgehog) and Gear^.Hedgehog^.King then @@ -1640,6 +1657,7 @@ procedure ResurrectHedgehog(gear: PGear); var tempTeam : PTeam; begin + AttackBar:= 0; gear^.dX := _0; gear^.dY := _0; gear^.Damage := 0; @@ -1737,7 +1755,6 @@ if (t > 0) then begin t:= GetRandom(t); - AddFileLog(inttostr(t)+' --------------'); while t >= 0 do begin inc(i); diff -r 190d6bb075c5 -r ed9676dc8cb4 hedgewars/uGearsRender.pas --- a/hedgewars/uGearsRender.pas Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/uGearsRender.pas Wed Sep 14 22:39:39 2011 +0200 @@ -227,13 +227,6 @@ Tint($FF, $FF, $FF, $FF) end; - if (CurAmmoGear <> nil) and - (CurrentHedgehog^.Gear <> nil) and - (CurrentHedgehog^.Gear = Gear) and - (CurAmmoGear^.Kind = gtTardis) then Tint($FF, $FF, $FF, CurAmmoGear^.Timer div 20) - // probably will need a new flag for this - else if (Gear^.State and gstTmpFlag <> 0) then Tint($FF, $FF, $FF, $FF-Gear^.Timer); - if ((Gear^.State and gstWinner) <> 0) and ((CurAmmoGear = nil) or (CurAmmoGear^.Kind <> gtPickHammer)) then begin @@ -893,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 @@ -1078,16 +1074,36 @@ //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 = 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 = 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; + end; if Gear^.RenderTimer and (Gear^.Tex <> nil) then DrawCentered(x + 8, y + 8, Gear^.Tex); diff -r 190d6bb075c5 -r ed9676dc8cb4 hedgewars/uIO.pas --- a/hedgewars/uIO.pas Wed Sep 14 22:27:22 2011 +0200 +++ b/hedgewars/uIO.pas Wed Sep 14 22:39:39 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]