# HG changeset patch
# User koda
# Date 1361505932 -3600
# Node ID 1dedcc37bfe85412ef9565c066b184d943fb9411
# Parent d5d5e16985547088be4fcb568b8b5c76e00def5d# Parent 24d2bdc6deff7e23007719ddc37b990eb08d989b
reopen and update branch
diff -r d5d5e1698554 -r 1dedcc37bfe8 .hgignore
--- a/.hgignore Sun Nov 18 01:06:01 2012 +0400
+++ b/.hgignore Fri Feb 22 05:05:32 2013 +0100
@@ -14,6 +14,7 @@
glob:config.inc
glob:cmake_install.cmake
glob:QTfrontend/hwconsts.cpp
+glob:QTfrontend/servermessages.h
glob:CPackConfig.cmake
glob:CPackSourceConfig.cmake
glob:tools/cmake_uninstall.cmake
@@ -30,6 +31,7 @@
glob:misc/liblua/Xcode/build/
glob:misc/libfreetype/Xcode/build/
glob:misc/libfreetype/Xcode-iOS/build/
+glob:misc/physfs/Xcode/build/
glob:moc_*.cxx_parameters
relre:^release\/
glob:*.log
@@ -55,4 +57,5 @@
glob:hedgewars-build-desktop-Qt_4_7_4_for_Desktop_-_MinGW_4_4__Qt_SDK__Release
glob:*.depends
glob:tools/build_windows_koda.bat
+glob:share/hedgewars/Data/misc/hwengine.desktop
diff -r d5d5e1698554 -r 1dedcc37bfe8 CMakeLists.txt
--- a/CMakeLists.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/CMakeLists.txt Fri Feb 22 05:05:32 2013 +0100
@@ -1,43 +1,63 @@
project(hedgewars)
-
#initialise cmake environment
-cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR)
-FOREACH(policy CMP0003 CMP0012)
- IF(POLICY ${policy})
- CMAKE_POLICY(SET ${policy} NEW)
- ENDIF()
-ENDFOREACH()
-set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules)
+cmake_minimum_required(VERSION 2.6.0)
+foreach(hwpolicy CMP0003 CMP0012 CMP0017)
+ if(POLICY ${hwpolicy})
+ cmake_policy(SET ${hwpolicy} NEW)
+ endif()
+endforeach()
+#use available modules, fallback to ours if not present (CMP0017 helps)
+set(CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules" "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
+
+
+#usually this is set at release time
+option(NOREVISION "Build Hedgewars without revision information [default: off]" OFF)
+#set other default values
+option(NOSERVER "Disable gameServer build [default: auto]" OFF)
+option(NOPNG "Disable screenshoot compression [default: auto]" OFF)
+option(NOVIDEOREC "Disable video recording [default: auto]" OFF)
+
+option(BUILD_ENGINE_LIBRARY "Enable hwengine library [default: off]" OFF)
+option(ANDROID "Enable Android build [default: off]" OFF)
+option(NOAUTOUPDATE "Disable OS X Sparkle update checking" OFF)
+option(MINIMAL_FLAGS "Respect system flags as much as possible [default: off]" OFF)
+set(FPFLAGS "" CACHE STRING "Additional Freepascal flags")
+set(GHFLAGS "" CACHE STRING "Additional Haskell flags")
+if(UNIX AND NOT APPLE)
+ set(DATA_INSTALL_DIR "share/hedgewars" CACHE STRING "Resource folder path")
+endif()
#detect Mercurial revision (if present)
-set(version_suffix "-dev") #UNSET THIS VARIABLE AT RELEASE TIME
-set(HGCHANGED "")
-IF(version_suffix MATCHES "-dev")
- set(HW_DEV true)
+if(NOT NOREVISION)
set(default_build_type "DEBUG")
- IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.hg)
- FIND_PROGRAM(HGCOMMAND hg)
- IF(HGCOMMAND)
- exec_program(${HGCOMMAND}
- ARGS identify -in ${CMAKE_CURRENT_SOURCE_DIR}
- OUTPUT_VARIABLE version_suffix
- )
- STRING(REGEX REPLACE "[^+]" "" HGCHANGED ${version_suffix})
- STRING(REGEX REPLACE "([0-9a-zA-Z]+)(.*) ([0-9]+)(.*)" "\\3-\\1" version_suffix ${version_suffix})
- IF (HGCHANGED)
- MESSAGE(STATUS "Building revision ${version_suffix} (SOURCE CODE MODIFIED)")
- ELSE()
- MESSAGE(STATUS "Building revision ${version_suffix}")
- ENDIF()
- set(version_suffix "-${version_suffix}")
- ENDIF()
- ENDIF()
-ELSE()
- set(HW_DEV false)
+ set(version_suffix "-development_version")
+ set(HW_DEV true)
+ find_program(HGCOMMAND hg)
+ if(HGCOMMAND AND (EXISTS ${CMAKE_SOURCE_DIR}/.hg))
+ execute_process(COMMAND ${HGCOMMAND} identify -in
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE internal_version
+ ERROR_QUIET
+ )
+ #check local repo status
+ string(REGEX REPLACE "[^+]" "" HGCHANGED ${internal_version})
+
+ string(REGEX REPLACE "[0-9a-zA-Z]+(.*) ([0-9]+)(.*)" "\\2" revision_number ${internal_version})
+ string(REGEX REPLACE "([0-9a-zA-Z]+)(.*) [0-9]+(.*)" "\\1" revision_hash ${internal_version})
+
+ message(STATUS "Building revision ${revision_number} from hash ${revision_hash} ${HGCHANGED}")
+ if(HGCHANGED)
+ MESSAGE(WARNING "Notice: you have uncommitted changes in your repository")
+ endif()
+ set(version_suffix "-${revision_number}${HGCHANGED}")
+ endif()
+else(NOT NOREVISION)
set(default_build_type "RELEASE")
-ENDIF()
+ set(HWDEV false)
+ message(STATUS "Building distributable version")
+endif(NOT NOREVISION)
#versioning
@@ -48,30 +68,31 @@
set(HEDGEWARS_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
-#set some default values
-option(NOSERVER "Disable gameServer build [default: auto]" OFF)
-option(NOPNG "Disable screenshoot compression [default: auto]" OFF)
-option(NOVIDEOREC "Disable video recording [default: auto]" OFF)
+set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
-option(BUILD_ENGINE_LIBRARY "Enable hwengine library [default: off]" OFF)
-option(ANDROID "Enable Android build [default: off]" OFF)
-option(NOAUTOUPDATE "Disable OS X Sparkle update checking" OFF)
-option(CROSSAPPLE "Enable OSX when not on OSX [default: off]" OFF)
-option(MINIMAL_FLAGS "Respect system flags as much as possible [default: off]" OFF)
+if(UNIX AND NOT APPLE)
+ set(target_binary_install_dir "bin")
+ set(target_library_install_dir "lib")
+ set(SHAREPATH "${DATA_INSTALL_DIR}/")
+else()
+ set(target_binary_install_dir "./")
-#bundle .app setup
-if(APPLE OR CROSSAPPLE)
- #paths for creating the bundle
- set(bundle_name Hedgewars.app)
- set(frameworks_dir ${bundle_name}/Contents/Frameworks/)
- set(CMAKE_INSTALL_PREFIX ${bundle_name}/Contents/MacOS/)
- set(DATA_INSTALL_DIR "../Resources/")
- set(target_dir ".")
- set(minimum_macosx_version "10.6")
-else()
- set(target_dir "bin")
+ if(APPLE)
+ set(CMAKE_INSTALL_PREFIX "Hedgewars.app/Contents/MacOS/")
+ set(SHAREPATH "../Resources/")
+ set(target_library_install_dir "../Frameworks/")
+ else()
+ if(WIN32)
+ set(target_library_install_dir "./")
+ set(SHAREPATH "./")
+ set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/misc/winutils/")
+ link_directories("${EXECUTABLE_OUTPUT_PATH}" "${CMAKE_SOURCE_DIR}/misc/winutils/bin")
+ endif(WIN32)
+ endif()
endif()
+
if(APPLE)
set(CMAKE_FIND_FRAMEWORK "FIRST")
@@ -81,12 +102,15 @@
#detect on which system we are: if sw_vers cannot be found for any reason (re)use minimum_macosx_version
find_program(sw_vers sw_vers)
if(sw_vers)
- exec_program(${sw_vers} ARGS "-productVersion" OUTPUT_VARIABLE current_macosx_version)
+ execute_process(COMMAND ${sw_vers} "-productVersion"
+ OUTPUT_VARIABLE current_macosx_version
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REGEX REPLACE "([0-9]+.[0-9]+).[0-9]+" "\\1" current_macosx_version ${current_macosx_version})
- else()
+ else()
if(NOT minimum_macosx_version)
message(FATAL_ERROR "sw_vers not found! Need explicit MACOSX_DEPLOYMENT_TARGET variable set")
else()
+ message(WARNING "sw_vers not found! Fallback to MACOSX_DEPLOYMENT_TARGET variable")
set(current_macosx_version ${minimum_macosx_version})
endif()
endif()
@@ -96,23 +120,23 @@
set(minimum_macosx_version ${current_macosx_version})
endif()
- #lower systems don't have enough processing power anyways
- if (minimum_macosx_version LESS "10.4")
+ #lower systems don't have enough processing power anyway
+ if (minimum_macosx_version VERSION_LESS "10.4")
message(FATAL_ERROR "Hedgewars is not supported on Mac OS X pre-10.4")
endif()
#workaround for http://playcontrol.net/ewing/jibberjabber/big_behind-the-scenes_chang.html#SDL_mixer (Update 2)
- if(current_macosx_version MATCHES "10.4")
+ if(current_macosx_version VERSION_EQUAL "10.4")
find_package(SDL_mixer REQUIRED)
set(DYLIB_SMPEG "-dylib_file @loader_path/Frameworks/smpeg.framework/Versions/A/smpeg:${SDLMIXER_LIBRARY}/Versions/A/Frameworks/smpeg.framework/Versions/A/smpeg")
set(DYLIB_MIKMOD "-dylib_file @loader_path/Frameworks/mikmod.framework/Versions/A/mikmod:${SDLMIXER_LIBRARY}/Versions/A/Frameworks/mikmod.framework/Versions/A/mikmod")
- set(pascal_flags "-k${DYLIB_SMPEG}" "-k${DYLIB_MIKMOD}" ${pascal_flags})
- set(CMAKE_C_FLAGS "${DYLIB_SMPEG}" "${DYLIB_MIKMOD}" ${CMAKE_C_FLAGS})
+ set(CMAKE_C_FLAGS "${DYLIB_SMPEG} ${DYLIB_MIKMOD}")
+ list(APPEND pascal_flags "-k${DYLIB_SMPEG}" "-k${DYLIB_MIKMOD}")
endif()
#CMAKE_OSX_ARCHITECTURES and CMAKE_OSX_SYSROOT need to be set for universal binary and correct linking
if(NOT CMAKE_OSX_ARCHITECTURES)
- if(current_macosx_version LESS "10.6")
+ if(current_macosx_version VERSION_LESS "10.6")
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "powerpc*")
set(CMAKE_OSX_ARCHITECTURES "ppc7400")
else()
@@ -125,8 +149,8 @@
#CMAKE_OSX_SYSROOT is set at the system version we are supposed to build on
#we need to provide the correct one when host and target differ
- if(NOT ${minimum_macosx_version} MATCHES ${current_macosx_version})
- if(minimum_macosx_version MATCHES "10.4")
+ if(NOT ${minimum_macosx_version} VERSION_EQUAL ${current_macosx_version})
+ if(minimum_macosx_version VERSION_EQUAL "10.4")
set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.4u.sdk/")
set(CMAKE_C_COMPILER "gcc-4.0")
set(CMAKE_CXX_COMPILER "g++-4.0")
@@ -137,12 +161,14 @@
endif()
#add user framework directory, other paths can be passed via FPFLAGS
- set(pascal_flags "-Ff~/Library/Frameworks" ${pascal_flags})
+ list(APPEND pascal_flags "-Ff~/Library/Frameworks")
#set deployment target
- set(pascal_flags "-k-macosx_version_min" "-k${minimum_macosx_version}" "-XR${CMAKE_OSX_SYSROOT}" ${pascal_flags})
+ list(APPEND pascal_flags "-k-macosx_version_min" "-k${minimum_macosx_version}" "-XR${CMAKE_OSX_SYSROOT}")
- message(STATUS "Build system: Mac OS X ${current_macosx_version} with GCC:${CMAKE_C_COMPILER}")
- message(STATUS "Target system: Mac OS X ${minimum_macosx_version} for architecture(s):${CMAKE_OSX_ARCHITECTURES}")
+ #silly libav that always brings in VideoDecoderAcceleration, avaible only from 10.6.3
+ if(NOT NOVIDEOREC AND ${minimum_macosx_version} VERSION_LESS "10.6")
+ set(WARNING "Video recording support before OS X 10.6 is experimental")
+ endif()
endif(APPLE)
@@ -150,7 +176,7 @@
if (CMAKE_BUILD_TYPE)
string (TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)
if ( NOT( (CMAKE_BUILD_TYPE MATCHES "RELEASE") OR (CMAKE_BUILD_TYPE MATCHES "DEBUG") ) )
- set (CMAKE_BUILD_TYPE ${default_build_type} CACHE STRING "Only 'Debug' or 'Release' options are allowed." FORCE)
+ set (CMAKE_BUILD_TYPE ${default_build_type} CACHE STRING "Choose the build type, options are: Debug Release." FORCE)
message (STATUS "Unknown build type, using default (${default_build_type})")
endif ()
else (CMAKE_BUILD_TYPE)
@@ -158,10 +184,10 @@
endif (CMAKE_BUILD_TYPE)
#set default flags values for all projects (unless MINIMAL_FLAGS is true)
-if(NOT MINIMAL_FLAGS)
- set(CMAKE_C_FLAGS "-pipe")
- set(CMAKE_C_FLAGS_RELEASE "-w -Os -fomit-frame-pointer")
- set(CMAKE_C_FLAGS_DEBUG "-Wall -O0 -g -DDEBUG")
+if(NOT ${MINIMAL_FLAGS})
+ set(CMAKE_C_FLAGS "-pipe ${CMAKE_C_FLAGS}")
+ set(CMAKE_C_FLAGS_RELEASE "-w -Os -fomit-frame-pointer ${CMAKE_C_FLAGS_RELEASE}")
+ set(CMAKE_C_FLAGS_DEBUG "-Wall -O0 -g -DDEBUG ${CMAKE_C_FLAGS_DEBUG}")
set(CMAKE_CXX_FLAGS ${CMAKE_C_FLAGS})
set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
@@ -175,41 +201,38 @@
#parse additional parameters
if(FPFLAGS OR GHFLAGS)
- math(EXPR cmake_version "${CMAKE_MAJOR_VERSION}*10000 + ${CMAKE_MINOR_VERSION}*100 + ${CMAKE_PATCH_VERSION}")
- if(cmake_version LESS "020800")
- message(STATUS "FPFLAGS and GHFLAGS are available only when using CMake >= 2.8")
+ set(cmake_version "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}")
+ if(cmake_version VERSION_LESS "2.8")
+ message(WARNING "FPFLAGS and GHFLAGS are available only when using CMake >= 2.8")
else()
separate_arguments(fpflags_parsed UNIX_COMMAND ${FPFLAGS})
separate_arguments(ghflags_parsed UNIX_COMMAND ${GHFLAGS})
endif()
endif()
-set(pascal_flags ${fpflags_parsed} "-vm4079,4080,4081" "-B" "-FE../bin" "-Cs2000000" "-vewnq" "-dDEBUGFILE" ${pascal_flags})
-set(haskell_flags "-O2" ${ghflags_parsed} ${haskell_flags})
+list(APPEND pascal_flags ${fpflags_parsed} # user flags
+ "-vm4079,4080,4081" # fpc output format
+ "-B" # compile all units
+ "-FE${PROJECT_BINARY_DIR}/bin" # fpc output directory
+ "-Fl${PROJECT_BINARY_DIR}/bin" # fpc linking directory
+ "-Cs2000000" # stack size
+ "-vewnq" # fpc output verbosity
+ "-dDEBUGFILE" # macro for engine output
+ )
+list(APPEND haskell_flags "-O2" ${ghflags_parsed})
#get BUILD_TYPE and enable/disable optimisation
+message(STATUS "Using ${CMAKE_BUILD_TYPE} configuration")
if(CMAKE_BUILD_TYPE MATCHES "DEBUG")
- message(STATUS "Building Debug flavour")
- set(pascal_flags "-O-" "-g" "-gl" "-gv" ${pascal_flags})
- set(haskell_flags "-Wall" "-debug" "-dcore-lint" "-fno-warn-unused-do-bind" ${haskell_flags})
+ list(APPEND pascal_flags "-O-" "-g" "-gl" "-gv")
+ list(APPEND haskell_flags "-Wall" "-debug" "-dcore-lint" "-fno-warn-unused-do-bind")
else()
- message(STATUS "Building Release flavour")
# set(pascal_flags "-O3" "-OpPENTIUM4" "-CfSSE3" "-Xs" "-Si" ${pascal_flags})
- set(pascal_flags "-Os" "-Ooregvar" "-Xs" "-Si" ${pascal_flags})
- set(haskell_flags "-w" "-fno-warn-unused-do-bind" ${haskell_flags})
+ list(APPEND pascal_flags "-Os" "-Xs" "-Si")
+ list(APPEND haskell_flags "-w" "-fno-warn-unused-do-bind")
endif()
-#finish setting paths
-if(DEFINED DATA_INSTALL_DIR)
- set(SHAREPATH ${DATA_INSTALL_DIR}/hedgewars/)
-else()
- set(SHAREPATH share/hedgewars/)
-endif()
-set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
-set(LIBRARY_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH})
-
-
#server discovery
if(NOT NOSERVER)
if(GHC)
@@ -223,7 +246,7 @@
add_subdirectory(gameServer)
message(STATUS "Found GHC: ${ghc_executable}")
else()
- message(STATUS "Could NOT find GHC, server will not be built")
+ message(WARNING "Could NOT find GHC, server will not be built")
set(HAVE_NETSERVER false)
endif()
else()
@@ -239,18 +262,21 @@
else()
message(STATUS "LUA will be provided by the bundled sources")
add_subdirectory(misc/liblua)
- #linking with liblua.a requires system readline -- this works everywhere, right?
- set(pascal_flags "-k${EXECUTABLE_OUTPUT_PATH}/lib${LUA_LIBRARY}.a" "-k-lreadline" ${pascal_flags})
+ #linking with liblua.a requires system readline
+ list(APPEND pascal_flags "-k${EXECUTABLE_OUTPUT_PATH}/lib${LUA_LIBRARY}.a" "-k-lreadline")
+endif()
+
+
+#physfs library (static on unix, dll on win32)
+add_subdirectory(misc/physfs)
+if(NOT WIN32)
+ list(APPEND pascal_flags "-k${LIBRARY_OUTPUT_PATH}/libphysfs.a")
endif()
#main engine
add_subdirectory(hedgewars)
-# physfs library
-add_subdirectory(misc/physfs)
-add_subdirectory(misc/physfs/extras)
-
#Android related build scripts
if(ANDROID)
#run cmake -DANDROID=1 to enable this
@@ -258,7 +284,7 @@
endif()
#TODO: when ANDROID, BUILD_ENGINE_LIBRARY should be set
-if(NOT (BUILD_ENGINE_LIBRARY OR ANDROID))
+if(NOT ANDROID)
add_subdirectory(bin)
add_subdirectory(QTfrontend)
add_subdirectory(share)
@@ -282,6 +308,7 @@
set(CPACK_NSIS_URL_INFO_ABOUT "http://www.hedgewars.org/")
set(CPACK_NSIS_CONTACT "unC0Rr@gmail.com")
set(CPACK_NSIS_MODIFY_PATH OFF)
+ set(CPACK_NSIS_EXECUTABLES_DIRECTORY "${target_binary_install_dir}")
set(CPACK_GENERATOR "ZIP;NSIS")
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "hedgewars")
else(WIN32 AND NOT UNIX)
diff -r d5d5e1698554 -r 1dedcc37bfe8 ChangeLog.txt
--- a/ChangeLog.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/ChangeLog.txt Fri Feb 22 05:05:32 2013 +0100
@@ -28,7 +28,7 @@
* Fix all knowns bugs which caused network game hang when players close engine or quit
* Fix drill strike bug when drill's timer gets ridiculously high value instead of explosion
* Fix some crashes, freezes and memory leaks in frontend and engine
-
+
0.9.16 -> 0.9.17:
+ New theme, Cave
+ New voicepack, Hillbilly
@@ -401,7 +401,7 @@
+ AI updates
+ Teams now work in fort mode, i.e. 2v2
+ Ability to attack whilst jumping/rope swinging
- + Some weapons can only be used after a certain number of turns
+ + Some weapons can only be used after a certain number of turns
+ Lots of new graphics
* Many network/gameplay bug fixes
diff -r d5d5e1698554 -r 1dedcc37bfe8 INSTALL
--- a/INSTALL Sun Nov 18 01:06:01 2012 +0400
+++ b/INSTALL Fri Feb 22 05:05:32 2013 +0100
@@ -1,13 +1,14 @@
To compile and install you need:
- - Qt >= 4.5
- - FreePascal >= 2.2.4
+ - CMake >= 2.6.0
+ - FreePascal >= 2.2.0
+ - Qt >= 4.5.0
- SDL >= 1.2.5
- SDL_net >= 1.2.5
- SDL_mixer >= 1.2
- SDL_image >= 1.2
- SDL_ttf >= 2.0
- - CMake >= 2.6.0
- Lua >= 5.1.0
+ - Physfs >= 2.1
For server:
- Glasgow Haskell Compiler >= 6.10
- bytestring-show package
@@ -16,6 +17,11 @@
For videorecording:
- FFmpeg or LibAV
- GLUT (when SDL < 2)
+For compressed screenshots:
+ - libpng
+
+Lua will be automatically built if not found.
+
1. Configure:
$ cmake .
@@ -23,8 +29,12 @@
$ cmake -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="install_prefix" \
-DDATA_INSTALL_DIR="data_dir" -DNOSERVER=1 .
-add -DNOSERVER=0 to compile net server; if you have Qt installed but it is
-not found you can set it up with -DQT_QMAKE_EXECUTABLE="path_to_qmake"
+Add -DNOSERVER=0 to compile net server (remember to check out the additional
+dependencies with the hedgewars-server.cabal configuration file. If you have
+Qt installed but it is not found, you can set it up with
+-DQT_QMAKE_EXECUTABLE="path_to_qmake".
+To get a glimpse of the main configuration options, you may use this command
+`cat CMakeLists.txt | grep option`
2. Compile:
$ make
@@ -34,3 +44,4 @@
That's all! Enjoy!
+
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/AutoUpdater.cpp
--- a/QTfrontend/AutoUpdater.cpp Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-/*
- * Copyright (C) 2008 Remko Troncon
- */
-
-#include "AutoUpdater.h"
-
-AutoUpdater::~AutoUpdater()
-{
-}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/AutoUpdater.h
--- a/QTfrontend/AutoUpdater.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-/*
- * Copyright (C) 2008 Remko Troncon
- */
-
-#ifndef AUTOUPDATER_H
-#define AUTOUPDATER_H
-
-class AutoUpdater
-{
- public:
- virtual ~AutoUpdater();
-
- virtual void checkForUpdates() = 0;
-};
-
-#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/CMakeLists.txt
--- a/QTfrontend/CMakeLists.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/CMakeLists.txt Fri Feb 22 05:05:32 2013 +0100
@@ -11,18 +11,41 @@
set(QT_USE_QTMAIN TRUE)
find_package(Qt4 REQUIRED)
-if (NOT CROSSAPPLE)
- include(${QT_USE_FILE})
+include(${QT_USE_FILE})
+
+find_package(SDL REQUIRED) #video in SDLInteraction
+find_package(SDL_mixer REQUIRED) #audio in SDLInteraction
+find_package(SDL_net REQUIRED) #network frontlib
+if(NOT NOVIDEOREC)
+ find_package(FFMPEG)
+ if(${FFMPEG_FOUND})
+ add_definitions(-DVIDEOREC -D__STDC_CONSTANT_MACROS)
+ endif()
endif()
-# Configure for SDL
-find_package(SDL REQUIRED)
-find_package(SDL_mixer REQUIRED)
-if(NOT NOVIDEOREC)
- find_package(FFMPEG)
-endif()
+# server messages localization
+file(GLOB ServerSources ${CMAKE_SOURCE_DIR}/gameServer/*.hs)
+foreach(hsfile ${ServerSources})
+ file(READ ${hsfile} hs)
+ string(REGEX MATCHALL "loc *\"[^\n\"]+\"" locs ${hs})
+ foreach(str ${locs})
+ string(REGEX REPLACE "loc *\"([^\n\"]+)\"" "QT_TRANSLATE_NOOP(\"server\", \"\\1\")" s ${str})
+ list(APPEND serverlocs ${s})
+ endforeach(str)
+endforeach(hsfile)
-include_directories(.)
+list(REMOVE_DUPLICATES serverlocs)
+list(GET serverlocs 0 firstline)
+list(REMOVE_AT serverlocs 0)
+set(locsout "const char * serverMessages[] = {\n")
+foreach(l ${serverlocs})
+ list(APPEND locsout ${l} ",\n")
+endforeach(l)
+list(APPEND locsout ${firstline} "\n}\\;\n")
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/servermessages.h ${locsout})
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/model)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/net)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ui)
@@ -30,6 +53,7 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ui/page)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ui/widget)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/util)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/util/platform)
include_directories(${SDL_INCLUDE_DIR})
include_directories(${SDLMIXER_INCLUDE_DIR})
include_directories(${FFMPEG_INCLUDE_DIR})
@@ -40,24 +64,19 @@
include_directories("/usr/local/include")
endif(UNIX)
-
-if(WIN32 AND NOT UNIX)
- set(HEDGEWARS_BINDIR ".")
- set(HEDGEWARS_DATADIR "../share/")
- add_definitions(-DUSE_XFIRE)
+#directory for resources, relative to bindir (on linux an absolute path is always used)
+string(SUBSTRING "${SHAREPATH}" 0 1 sharepath_start)
+if(APPLE OR WIN32 OR ${sharepath_start} MATCHES "/")
+ set(HEDGEWARS_DATADIR ${SHAREPATH})
else()
- set(HEDGEWARS_BINDIR ${CMAKE_INSTALL_PREFIX})
- if(DEFINED DATA_INSTALL_DIR)
- set(HEDGEWARS_DATADIR ${DATA_INSTALL_DIR})
- else()
- set(HEDGEWARS_DATADIR ${CMAKE_INSTALL_PREFIX}/share/)
- endif()
- #only the cocoa version of qt supports building 64 bit apps
- if(APPLE AND (CMAKE_OSX_ARCHITECTURES MATCHES "x86_64*") AND (NOT QT_MAC_USE_COCOA))
- message(FATAL_ERROR "Building the 64 bit version of Hedgewars *requires* the Cocoa variant of QT on Mac OS X")
- endif()
+ set(HEDGEWARS_DATADIR ${CMAKE_INSTALL_PREFIX}/${SHAREPATH})
endif()
+#only the cocoa version of qt supports building 64 bit apps
+if(APPLE AND (CMAKE_OSX_ARCHITECTURES MATCHES "x86_64*") AND (NOT QT_MAC_USE_COCOA))
+ message(FATAL_ERROR "Building the 64 bit version of Hedgewars *requires* the Cocoa variant of QT on Mac OS X")
+endif()
+#endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hwconsts.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp)
@@ -66,11 +85,7 @@
file(GLOB_RECURSE UIcpp ui/*.cpp)
file(GLOB UtilCpp util/*.cpp)
-if(${FFMPEG_FOUND})
- add_definitions(-DVIDEOREC -D__STDC_CONSTANT_MACROS)
-endif()
-
-set(hwfr_src
+list(APPEND hwfr_src
${ModelCpp}
${NetCpp}
${UIcpp}
@@ -91,18 +106,18 @@
#xfire integration
if(WIN32)
- set(hwfr_src ${hwfr_src} xfire.cpp ../misc/xfire/xfiregameclient.cpp)
+ list(APPEND hwfr_src util/platform/xfire.cpp util/platform/xfiregameclient.cpp)
endif(WIN32)
if(MINGW)
# resource compilation for mingw
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o
- COMMAND windres -I ${CMAKE_CURRENT_SOURCE_DIR}
- -i ${CMAKE_CURRENT_SOURCE_DIR}/hedgewars.rc
- -o ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
- set(hwfr_src ${hwfr_src} ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
+ COMMAND windres -I ${CMAKE_CURRENT_SOURCE_DIR}
+ -i ${CMAKE_CURRENT_SOURCE_DIR}/hedgewars.rc
+ -o ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
+ list(APPEND hwfr_src ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
else(MINGW)
- set(hwfr_src ${hwfr_src} hedgewars.rc)
+ list(APPEND hwfr_src hedgewars.rc)
endif(MINGW)
file(GLOB ModelHdr model/*.h)
@@ -134,55 +149,73 @@
hwconsts.h
sdlkeys.h
campaign.h
+ ${CMAKE_CURRENT_BINARY_DIR}/servermessages.h
)
set(hwfr_rez hedgewars.qrc)
+if(${BUILD_ENGINE_LIBRARY})
+ add_definitions(-DHWLIBRARY=1)
+ set(hwlibname "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}hwengine${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ list(APPEND HW_LINK_LIBS ${hwlibname})
+endif()
+
qt4_add_resources(hwfr_rez_src ${hwfr_rez})
qt4_wrap_cpp(hwfr_moc_srcs ${hwfr_moc_hdrs})
-if(APPLE OR CROSSAPPLE)
- set(hwfr_src ${hwfr_src} InstallController.cpp CocoaInitializer.mm M3Panel.mm M3InstallController.m NSWorkspace_RBAdditions.m)
- set(HW_LINK_LIBS IOKit ${HW_LINK_LIBS})
-
+if(APPLE)
+ find_library(iokit_framework NAMES IOKit)
+ list(APPEND HW_LINK_LIBS ${iokit_framework})
+ list(APPEND hwfr_src util/platform/CocoaInitializer.mm
+ util/platform/InstallController.cpp
+ util/platform/M3Panel.mm
+ util/platform/M3InstallController.m
+ util/platform/NSWorkspace_RBAdditions.m
+ )
if(NOT NOAUTOUPDATE)
find_package(Sparkle)
if(SPARKLE_FOUND)
add_definitions(-DSPARKLE_ENABLED)
- set(hwfr_src ${hwfr_src} AutoUpdater.cpp SparkleAutoUpdater.mm)
- set(HW_LINK_LIBS ${SPARKLE_LIBRARY} ${HW_LINK_LIBS})
+ list(APPEND hwfr_src util/platform/AutoUpdater.cpp
+ util/platform/SparkleAutoUpdater.mm)
+ list(APPEND HW_LINK_LIBS ${SPARKLE_LIBRARY})
endif()
endif()
endif()
+#when debugging, always prompt a console to see fronted messages
+#TODO: check it doesn't interfere on UNIX
+if(CMAKE_BUILD_TYPE MATCHES "RELEASE")
+ set(console_access "WIN32")
+endif(CMAKE_BUILD_TYPE MATCHES "RELEASE")
-add_executable(hedgewars WIN32
+add_executable(hedgewars ${console_access}
${hwfr_src}
${hwfr_moc_srcs}
${hwfr_hdrs}
${hwfr_rez_src}
)
+if((UNIX AND NOT APPLE) AND ${BUILD_ENGINE_LIBRARY})
+ set_target_properties(hedgewars PROPERTIES LINK_FLAGS "-Wl,-rpath,${CMAKE_INSTALL_PREFIX}/${target_library_install_dir}")
+endif()
-set(HW_LINK_LIBS
+list(APPEND HW_LINK_LIBS
physfs
- physfsrwops
${QT_LIBRARIES}
${SDL_LIBRARY}
${SDLMIXER_LIBRARY}
${FFMPEG_LIBRARIES}
- ${HW_LINK_LIBS}
)
if(WIN32 AND NOT UNIX)
if(NOT SDL_LIBRARY)
- set(HW_LINK_LIBS ${HW_LINK_LIBS} SDL)
+ list(APPEND HW_LINK_LIBS SDL)
endif()
- set(HW_LINK_LIBS
- ${HW_LINK_LIBS}
+ list(APPEND HW_LINK_LIBS
ole32
oleaut32
winspool
@@ -190,13 +223,8 @@
)
endif()
-
-if (CROSSAPPLE)
-
-else()
- target_link_libraries(hedgewars ${HW_LINK_LIBS})
-endif()
+target_link_libraries(hedgewars ${HW_LINK_LIBS})
-install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/hedgewars${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_dir})
+install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/hedgewars${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_binary_install_dir})
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/CocoaInitializer.h
--- a/QTfrontend/CocoaInitializer.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-// see original example here http://el-tramo.be/blog/mixing-cocoa-and-qt
-
-#ifndef COCOAINITIALIZER_H
-#define COCOAINITIALIZER_H
-
-class CocoaInitializer
-{
- public:
- CocoaInitializer();
- ~CocoaInitializer();
-
- private:
- class Private;
- Private* c;
-};
-
-#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/CocoaInitializer.mm
--- a/QTfrontend/CocoaInitializer.mm Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-// see original example here http://el-tramo.be/blog/mixing-cocoa-and-qt
-
-#include "CocoaInitializer.h"
-
-#include
-#include
-#include
-
-class CocoaInitializer::Private
-{
- public:
- NSAutoreleasePool* pool;
-};
-
-CocoaInitializer::CocoaInitializer()
-{
- c = new CocoaInitializer::Private();
- NSApplicationLoad();
- c->pool = [[NSAutoreleasePool alloc] init];
-}
-
-CocoaInitializer::~CocoaInitializer()
-{
- [c->pool release];
- delete c;
-}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/InstallController.cpp
--- a/QTfrontend/InstallController.cpp Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include "InstallController.h"
-
-InstallController::~InstallController()
-{
-}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/InstallController.h
--- a/QTfrontend/InstallController.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef INSTALLCONTROLLER_H
-#define INSTALLCONTROLLER_H
-
-class InstallController
-{
- public:
- virtual ~InstallController();
-
- virtual void showInstallController() = 0;
-};
-
-#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/M3InstallController.h
--- a/QTfrontend/M3InstallController.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*****************************************************************
- M3InstallController.m
-
- Created by Martin Pilkington on 02/06/2007.
-
- Copyright (c) 2006-2009 M Cubed Software
-
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use,
- copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following
- conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
-
- *****************************************************************/
-
-#import
-#import
-
-//#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
-#if __LP64__ || NS_BUILD_32_LIKE_64
-typedef long NSInteger;
-typedef unsigned long NSUInteger;
-#else
-typedef int NSInteger;
-typedef unsigned int NSUInteger;
-#endif
-//#endif
-
-
-@interface M3InstallController :
-NSObject
-{
- NSAlert *alert;
-}
-
-- (void)displayInstaller;
-- (void)installApp;
-@end
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/M3InstallController.m
--- a/QTfrontend/M3InstallController.m Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*****************************************************************
- M3InstallController.m
-
- Created by Martin Pilkington on 02/06/2007.
-
- Copyright (c) 2006-2009 M Cubed Software
-
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use,
- copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following
- conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
-
- *****************************************************************/
-
-#import "M3InstallController.h"
-#import "NSWorkspace_RBAdditions.h"
-
-#import
-
-@implementation M3InstallController
-
-- (id) init {
- if ((self = [super init])) {
- NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
- NSString *title = [NSString stringWithFormat:NSLocalizedString(@"%@ is currently running from a disk image", @"AppName is currently running from a disk image"), appName];
- NSString *body = [NSString stringWithFormat:NSLocalizedString(@"Would you like to install %@ in your applications folder before quitting?", @"Would you like to install App Name in your applications folder before quitting?"), appName];
- alert = [[NSAlert alertWithMessageText:title
- defaultButton:NSLocalizedString(@"Install", @"Install")
- alternateButton:NSLocalizedString(@"Don't Install", @"Don't Install")
- otherButton:nil
- informativeTextWithFormat:body] retain];
- //[alert setShowsSuppressionButton:YES];
- }
- return self;
-}
-
-- (void)displayInstaller {
- NSString *imageFilePath = [[[NSWorkspace sharedWorkspace] propertiesForPath:[[NSBundle mainBundle] bundlePath]] objectForKey:NSWorkspace_RBimagefilepath];
- if (imageFilePath && ![imageFilePath isEqualToString:[NSString stringWithFormat:@"/Users/.%@/%@.sparseimage", NSUserName(), NSUserName()]] && ![[NSUserDefaults standardUserDefaults] boolForKey:@"M3DontAskInstallAgain"]) {
- NSInteger returnValue = [alert runModal];
- if (returnValue == NSAlertDefaultReturn) {
- [self installApp];
- }
- if ([[alert suppressionButton] state] == NSOnState) {
- [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"M3DontAskInstallAgain"];
- }
- }
-}
-
-- (void)installApp {
- NSString *appsPath = [[NSString stringWithString:@"/Applications"] stringByAppendingPathComponent:[[[NSBundle mainBundle] bundlePath] lastPathComponent]];
- NSString *userAppsPath = [[[NSString stringWithString:@"~/Applications"] stringByAppendingPathComponent:[[[NSBundle mainBundle] bundlePath] lastPathComponent]] stringByExpandingTildeInPath];
- NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
-
- //Delete the app that is installed
- if ([[NSFileManager defaultManager] fileExistsAtPath:appsPath]) {
- [[NSFileManager defaultManager] removeFileAtPath:appsPath handler:nil];
- }
- //Delete the app that is installed
- if ([[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath] toPath:appsPath
- handler:nil]) {
- NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"App Name installed successfully"), appName],
- [NSString stringWithFormat:NSLocalizedString(@"%@ was installed in /Applications", @"App Name was installed in /Applications"), appName],
- NSLocalizedString(@"Quit", @"Quit"), nil, nil);
- } else {
- if ([[NSFileManager defaultManager] fileExistsAtPath:userAppsPath]) {
- [[NSFileManager defaultManager] removeFileAtPath:userAppsPath handler:nil];
- }
- if ([[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath] toPath:userAppsPath
- handler:nil]) {
- NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"AppName installed successfully"), appName],
- [NSString stringWithFormat:NSLocalizedString(@"%@ was installed in %@", @"App Name was installed in %@"), appName, [[NSString stringWithString:@"~/Applications"] stringByExpandingTildeInPath]],
- NSLocalizedString(@"Quit", @"Quit"), nil, nil);
- } else {
- NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"Could not install %@", @"Could not install App Name"), appName],
- NSLocalizedString(@"An error occurred when installing", @"An error occurred when installing"), NSLocalizedString(@"Quit", @"Quit"), nil, nil);
- }
- }
-}
-
-@end
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/M3Panel.h
--- a/QTfrontend/M3Panel.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef M3PANEL_H
-#define M3PANEL_H
-
-#include "InstallController.h"
-
-class M3Panel : public InstallController
-{
- public:
- M3Panel(void);
- ~M3Panel();
-
- void showInstallController();
-
- private:
- class Private;
- Private* c;
-};
-
-#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/M3Panel.mm
--- a/QTfrontend/M3Panel.mm Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include "M3Panel.h"
-#include "M3InstallController.h"
-
-#include
-
-class M3Panel::Private
-{
- public:
- M3InstallController *install;
-};
-
-M3Panel::M3Panel(void)
-{
- c = new Private;
-
- c->install = [[M3InstallController alloc] init];
- [c->install retain];
-}
-
-M3Panel::~M3Panel()
-{
- [c->install release];
- delete c;
-}
-
-void M3Panel::showInstallController()
-{
- [c->install displayInstaller];
-}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/NSWorkspace_RBAdditions.h
--- a/QTfrontend/NSWorkspace_RBAdditions.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-//
-// NSWorkspace_RBAdditions.h
-// PathProps
-//
-// Created by Rainer Brockerhoff on 10/04/2007.
-// Copyright 2007 Rainer Brockerhoff. All rights reserved.
-//
-
-#import
-
-extern NSString* NSWorkspace_RBfstypename;
-extern NSString* NSWorkspace_RBmntonname;
-extern NSString* NSWorkspace_RBmntfromname;
-extern NSString* NSWorkspace_RBdeviceinfo;
-extern NSString* NSWorkspace_RBimagefilepath;
-extern NSString* NSWorkspace_RBconnectiontype;
-extern NSString* NSWorkspace_RBpartitionscheme;
-extern NSString* NSWorkspace_RBserverURL;
-
-@interface NSWorkspace (NSWorkspace_RBAdditions)
-
-// This method will return nil if the input path is invalid. Otherwise, the returned NSDictionary may contain
-// the following keys:
-//- NSWorkspace_RBfstypename: will always be present.Shows the filesystem type (usually "hfs"), from statfs.
-//- NSWorkspace_RBmntonname: will always be present. Shows the volume mount point.
-//- NSWorkspace_RBmntfromname: will always be present. Shows the BSD device path for local volumes; info for
-// remote volumes depends on the filesystem type.
-//- NSWorkspace_RBconnectiontype: should always be present for local volumes. Shows the connection type ("SATA", "USB", etc.).
-//- NSWorkspace_RBpartitionscheme: should always be present for local volumes. Shows the partition scheme.
-//- NSWorkspace_RBdeviceinfo: should always be present for local volumes. Shows some information about the
-// physical device; varies widely.
-//- NSWorkspace_RBimagefilepath: should be present for disk images only. Shows the path of the disk image file.
-//- NSWorkspace_RBserverURL: should be present for remote volumes only. Shows the server URL.
-
-- (NSDictionary*)propertiesForPath:
-(NSString*)path;
-
-@end
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/NSWorkspace_RBAdditions.m
--- a/QTfrontend/NSWorkspace_RBAdditions.m Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +0,0 @@
-//
-// NSWorkspace_RBAdditions.m
-// PathProps
-//
-// Created by Rainer Brockerhoff on 10/04/2007.
-// Copyright 2007 Rainer Brockerhoff. All rights reserved.
-//
-
-#import "NSWorkspace_RBAdditions.h"
-#include
-#include
-#include
-
-NSString* NSWorkspace_RBfstypename = @"NSWorkspace_RBfstypename";
-NSString* NSWorkspace_RBmntonname = @"NSWorkspace_RBmntonname";
-NSString* NSWorkspace_RBmntfromname = @"NSWorkspace_RBmntfromname";
-NSString* NSWorkspace_RBdeviceinfo = @"NSWorkspace_RBdeviceinfo";
-NSString* NSWorkspace_RBimagefilepath = @"NSWorkspace_RBimagefilepath";
-NSString* NSWorkspace_RBconnectiontype = @"NSWorkspace_RBconnectiontype";
-NSString* NSWorkspace_RBpartitionscheme = @"NSWorkspace_RBpartitionscheme";
-NSString* NSWorkspace_RBserverURL = @"NSWorkspace_RBserverURL";
-
-// This static funtion concatenates two strings, but first checks several possibilities...
-// like one or the other nil, or one containing the other already.
-
-static NSString* AddPart(NSString* first,NSString* second) {
- if (!second) {
- return first;
- }
- second = [second stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
- if (first) {
- if ([first rangeOfString:second options:NSCaseInsensitiveSearch].location==NSNotFound) {
- if ([second rangeOfString:first options:NSCaseInsensitiveSearch].location==NSNotFound) {
- return [NSString stringWithFormat:@"%@; %@",first,second];
- }
- return second;
- }
- return first;
- }
- return second;
-}
-
-// This static functions recurses "upwards" over the IO registry. Returns strings that are concatenated
-// and ultimately end up under the NSWorkspace_RBdeviceinfo key.
-// This isn't too robust in that it assumes that objects returned by the objectForKey methods are
-// either strings or dictionaries. A "standard" implementations would use either only CoreFoundation and
-// IOKit calls for this, or do more robust type checking on the returned objects.
-//
-// Also notice that this works as determined experimentally in 10.4.9, there's no official docs I could find.
-// YMMV, and it may stop working in any new version of Mac OS X.
-
-static NSString* CheckParents(io_object_t thing,NSString* part,NSMutableDictionary* dict) {
- NSString* result = part;
- io_iterator_t parentsIterator = 0;
- kern_return_t kernResult = IORegistryEntryGetParentIterator(thing,kIOServicePlane,&parentsIterator);
- if ((kernResult==KERN_SUCCESS)&&parentsIterator) {
- io_object_t nextParent = 0;
- while ((nextParent = IOIteratorNext(parentsIterator))) {
- NSDictionary* props = nil;
- NSString* image = nil;
- NSString* partition = nil;
- NSString* connection = nil;
- kernResult = IORegistryEntryCreateCFProperties(nextParent,(CFMutableDictionaryRef*)&props,kCFAllocatorDefault,0);
- if (IOObjectConformsTo(nextParent,"IOApplePartitionScheme")) {
- partition = [props objectForKey:@"Content Mask"];
- } else if (IOObjectConformsTo(nextParent,"IOMedia")) {
- partition = [props objectForKey:@"Content"];
- } else if (IOObjectConformsTo(nextParent,"IODiskImageBlockStorageDeviceOutKernel")) {
- NSData* data = nil;
- if ((data = [[props objectForKey:@"Protocol Characteristics"] objectForKey:@"Virtual Interface Location Path"])) {
- image = [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding] autorelease];
- }
- } else if (IOObjectConformsTo(nextParent,"IOHDIXHDDriveInKernel")) {
- image = [props objectForKey:@"KDIURLPath"];
- }
- NSDictionary* subdict;
- if ((subdict = [props objectForKey:@"Protocol Characteristics"])) {
- connection = [subdict objectForKey:@"Physical Interconnect"];
- } else {
- connection = [props objectForKey:@"Physical Interconnect"];
- }
- if (connection) {
- [dict setObject:AddPart([dict objectForKey:NSWorkspace_RBconnectiontype],connection) forKey:NSWorkspace_RBconnectiontype];
- }
- if (partition) {
- [dict setObject:partition forKey:NSWorkspace_RBpartitionscheme];
- }
- if (image) {
- [dict setObject:image forKey:NSWorkspace_RBimagefilepath];
- }
- NSString* value;
- if ((subdict = [props objectForKey:@"Device Characteristics"])) {
- if ((value = [subdict objectForKey:@"Product Name"])) {
- result = AddPart(result,value);
- }
- if ((value = [subdict objectForKey:@"Product Revision Level"])) {
- result = AddPart(result,value);
- }
- if ((value = [subdict objectForKey:@"Vendor Name"])) {
- result = AddPart(result,value);
- }
- }
- if ((value = [props objectForKey:@"USB Serial Number"])) {
- result = AddPart(result,value);
- }
- if ((value = [props objectForKey:@"USB Vendor Name"])) {
- result = AddPart(result,value);
- }
- NSString* cls = [(NSString*)IOObjectCopyClass(nextParent) autorelease];
- if (![cls isEqualToString:@"IOPCIDevice"]) {
-
-// Uncomment the following line to have the device tree dumped to the console.
-// NSLog(@"=================================> %@:%@\n",cls,props);
-
- result = CheckParents(nextParent,result,dict);
- }
- IOObjectRelease(nextParent);
- }
- }
- if (parentsIterator) {
- IOObjectRelease(parentsIterator);
- }
- return result;
-}
-
-// This formats the (partially undocumented) AFPXMountInfo info into a string.
-
-/*
-static NSString* FormatAFPURL(AFPXVolMountInfoPtr mountInfo,NSString** devdesc) {
- UInt8* work = ((UInt8*)mountInfo)+mountInfo->serverNameOffset;
- if (devdesc) {
- *devdesc = [[[NSString alloc] initWithBytes:&work[1] length:work[0] encoding:NSUTF8StringEncoding] autorelease];
- }
- work = ((UInt8*)mountInfo)+mountInfo->volNameOffset;
- NSString* volname = [[[NSString alloc] initWithBytes:&work[1] length:work[0] encoding:NSUTF8StringEncoding] autorelease];
- work = ((UInt8*)mountInfo)+mountInfo->alternateAddressOffset;
- AFPAlternateAddress* afpa = (AFPAlternateAddress*)work;
- AFPTagData* afpta = (AFPTagData*)(&afpa->fAddressList);
- NSString* ip = nil;
- NSString* dns = nil;
- int i = afpa->fAddressCount;
- while ((i-->0)) {
- switch (afpta->fType) {
- case kAFPTagTypeIP:
- if (!ip) {
- ip = [[[NSString alloc] initWithBytes:&afpta->fData[0] length:afpta->fLength-2 encoding:NSUTF8StringEncoding] autorelease];
- }
- break;
- case kAFPTagTypeIPPort:
- ip = [NSString stringWithFormat:@"%u.%u.%u.%u:%u",afpta->fData[0],afpta->fData[1],afpta->fData[2],afpta->fData[3],OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[4])];
- break;
- case kAFPTagTypeDNS:
- dns = [[[NSString alloc] initWithBytes:&afpta->fData[0] length:afpta->fLength-2 encoding:NSUTF8StringEncoding] autorelease];
- break;
- case 0x07:
- ip = [NSString stringWithFormat:@"[%x:%x:%x:%x:%x:%x:%x:%x]",OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[0]),
- OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[2]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[4]),
- OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[6]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[8]),
- OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[10]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[12]),
- OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[14])];
- break;
- }
- afpta = (AFPTagData*)((char*)afpta+afpta->fLength);
- }
- return [NSString stringWithFormat:@"afp://%@/%@",dns?:(ip?:@""),volname];
-}
-*/
-
-@implementation NSWorkspace (NSWorkspace_RBAdditions)
-
-// Returns a NSDictionary with properties for the path. See details in the .h file.
-// This assumes that the length of path is less than PATH_MAX (currently 1024 characters).
-
-- (NSDictionary*)propertiesForPath:(NSString*)path {
- const char* ccpath = (const char*)[path fileSystemRepresentation];
- NSMutableDictionary* result = nil;
- struct statfs fs;
- if (!statfs(ccpath,&fs)) {
- NSString* from = [NSString stringWithUTF8String:fs.f_mntfromname];
- result = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- [NSString stringWithUTF8String:fs.f_fstypename],NSWorkspace_RBfstypename,
- [NSString stringWithUTF8String:fs.f_mntonname],NSWorkspace_RBmntonname,
- nil];
- if (strncmp(fs.f_mntfromname,"/dev/",5)==0) {
-// For a local volume,get the IO registry tree and search it for further info.
- mach_port_t masterPort = 0;
- io_iterator_t mediaIterator = 0;
- kern_return_t kernResult = IOMasterPort(bootstrap_port,&masterPort);
- if (kernResult==KERN_SUCCESS) {
- CFMutableDictionaryRef classesToMatch = IOBSDNameMatching(masterPort,0,&fs.f_mntfromname[5]);
- if (classesToMatch) {
- kernResult = IOServiceGetMatchingServices(masterPort,classesToMatch,&mediaIterator);
- if ((kernResult==KERN_SUCCESS)&&mediaIterator) {
- io_object_t firstMedia = 0;
- while ((firstMedia = IOIteratorNext(mediaIterator))) {
- NSString* stuff = CheckParents(firstMedia,nil,result);
- if (stuff) {
- [result setObject:stuff forKey:NSWorkspace_RBdeviceinfo];
- }
- IOObjectRelease(firstMedia);
- }
- }
- }
- }
- if (mediaIterator) {
- IOObjectRelease(mediaIterator);
- }
- if (masterPort) {
- mach_port_deallocate(mach_task_self(),masterPort);
- }
- }
- //Don't need this for disk images, gets around warnings for some deprecated functions
-
- /* else {
-// For a network volume, get the volume reference number and use to get the server URL.
- FSRef ref;
- if (FSPathMakeRef((const UInt8*)ccpath,&ref,NULL)==noErr) {
- FSCatalogInfo info;
- if (FSGetCatalogInfo(&ref,kFSCatInfoVolume,&info,NULL,NULL,NULL)==noErr) {
- ParamBlockRec pb;
- UInt16 vmisize = 0;
- VolumeMountInfoHeaderPtr mountInfo = NULL;
- pb.ioParam.ioCompletion = NULL;
- pb.ioParam.ioNamePtr = NULL;
- pb.ioParam.ioVRefNum = info.volume;
- pb.ioParam.ioBuffer = (Ptr)&vmisize;
- pb.ioParam.ioReqCount = sizeof(vmisize);
- if ((PBGetVolMountInfoSize(&pb)==noErr)&&vmisize) {
- mountInfo = (VolumeMountInfoHeaderPtr)malloc(vmisize);
- if (mountInfo) {
- pb.ioParam.ioBuffer = (Ptr)mountInfo;
- pb.ioParam.ioReqCount = vmisize;
- if (PBGetVolMountInfo(&pb)==noErr) {
- NSString* url = nil;
- switch (mountInfo->media) {
- case AppleShareMediaType:
- url = FormatAFPURL((AFPXVolMountInfoPtr)mountInfo,&from);
- break;
- case 'http':
- url = from;
- break;
- case 'crbm':
- case 'nfs_':
- case 'cifs':
- url = [NSString stringWithUTF8String:(char*)mountInfo+sizeof(VolumeMountInfoHeader)+sizeof(OSType)];
- break;
- }
- if (url) {
- [result setObject:url forKey:NSWorkspace_RBserverURL];
- }
- }
- }
- free(mountInfo);
- }
- }
- }
- }*/
- [result setObject:from forKey:NSWorkspace_RBmntfromname];
- }
- return result;
-}
-
-@end
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/SparkleAutoUpdater.h
--- a/QTfrontend/SparkleAutoUpdater.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2008 Remko Troncon
- */
-
-#ifndef SPARKLEAUTOUPDATER_H
-#define SPARKLEAUTOUPDATER_H
-
-#include
-
-#include "AutoUpdater.h"
-
-class SparkleAutoUpdater : public AutoUpdater
-{
- public:
- SparkleAutoUpdater();
- ~SparkleAutoUpdater();
-
- void checkForUpdates();
- void checkForUpdatesNow();
-
- private:
- class Private;
- Private* d;
-};
-
-#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/SparkleAutoUpdater.mm
--- a/QTfrontend/SparkleAutoUpdater.mm Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-// see original example here http://el-tramo.be/blog/mixing-cocoa-and-qt
-
-#include "SparkleAutoUpdater.h"
-
-#include
-#include
-
-class SparkleAutoUpdater::Private
-{
- public:
- SUUpdater* updater;
-};
-
-SparkleAutoUpdater::SparkleAutoUpdater()
-{
- d = new Private;
-
- d->updater = [SUUpdater sharedUpdater];
- [d->updater retain];
-}
-
-SparkleAutoUpdater::~SparkleAutoUpdater()
-{
- [d->updater release];
- delete d;
-}
-
-void SparkleAutoUpdater::checkForUpdates()
-{
- [d->updater checkForUpdatesInBackground];
-}
-
-void SparkleAutoUpdater::checkForUpdatesNow()
-{
- [d->updater checkForUpdates:NULL];
-}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/binds.cpp
--- a/QTfrontend/binds.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/binds.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -20,17 +20,15 @@
const BindAction cbinds[BINDS_NUMBER] =
{
- {"+up", "up", QT_TRANSLATE_NOOP("binds", "up"), QT_TRANSLATE_NOOP("binds (categories)", "Basic controls"), QT_TRANSLATE_NOOP("binds (descriptions)", "Move your hogs and aim:")},
+ {"+up", "up", QT_TRANSLATE_NOOP("binds", "up"), QT_TRANSLATE_NOOP("binds (categories)", "Movement"), QT_TRANSLATE_NOOP("binds (descriptions)", "Hedgehog movement")},
{"+left", "left", QT_TRANSLATE_NOOP("binds", "left"), NULL, NULL},
{"+right", "right", QT_TRANSLATE_NOOP("binds", "right"), NULL, NULL},
{"+down", "down", QT_TRANSLATE_NOOP("binds", "down"), NULL, NULL},
{"+precise", "left_shift", QT_TRANSLATE_NOOP("binds", "precise aim"), NULL, NULL},
{"ljump", "return", QT_TRANSLATE_NOOP("binds", "long jump"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Traverse gaps and obstacles by jumping:")},
{"hjump", "backspace", QT_TRANSLATE_NOOP("binds", "high jump"), NULL, NULL},
- {"+attack", "space", QT_TRANSLATE_NOOP("binds", "attack"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Fire your selected weapon or trigger an utility item:")},
- {"put", "mousel", QT_TRANSLATE_NOOP("binds", "put"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Pick a weapon or a target location under the cursor:")},
{"switch", "tab", QT_TRANSLATE_NOOP("binds", "switch"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Switch your currently active hog (if possible):")},
- {"ammomenu", "mouser", QT_TRANSLATE_NOOP("binds", "ammo menu"), QT_TRANSLATE_NOOP("binds (categories)", "Weapon controls"), QT_TRANSLATE_NOOP("binds (descriptions)", "Pick a weapon or utility item:")},
+ {"ammomenu", "mouser", QT_TRANSLATE_NOOP("binds", "ammo menu"), QT_TRANSLATE_NOOP("binds (categories)", "Weapons"), QT_TRANSLATE_NOOP("binds (descriptions)", "Pick a weapon or utility item:")},
{"slot 1", "f1", QT_TRANSLATE_NOOP("binds", "slot 1"), NULL, NULL},
{"slot 2", "f2", QT_TRANSLATE_NOOP("binds", "slot 2"), NULL, NULL},
{"slot 3", "f3", QT_TRANSLATE_NOOP("binds", "slot 3"), NULL, NULL},
@@ -46,7 +44,9 @@
{"timer 3", "3", QT_TRANSLATE_NOOP("binds", "timer 3 sec"), NULL, NULL},
{"timer 4", "4", QT_TRANSLATE_NOOP("binds", "timer 4 sec"), NULL, NULL},
{"timer 5", "5", QT_TRANSLATE_NOOP("binds", "timer 5 sec"), NULL, NULL},
- {"findhh", "h", QT_TRANSLATE_NOOP("binds", "find hedgehog"), QT_TRANSLATE_NOOP("binds (categories)", "Camera and cursor controls"), QT_TRANSLATE_NOOP("binds (descriptions)", "Move the camera to the active hog:")},
+ {"+attack", "space", QT_TRANSLATE_NOOP("binds", "attack"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Fire your selected weapon or trigger an utility item:")},
+ {"put", "mousel", QT_TRANSLATE_NOOP("binds", "put"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Pick a weapon or a target location under the cursor:")},
+ {"findhh", "h", QT_TRANSLATE_NOOP("binds", "find hedgehog"), QT_TRANSLATE_NOOP("binds (categories)", "Camera"), QT_TRANSLATE_NOOP("binds (descriptions)", "Move the camera to the active hog:")},
{"+cur_u", "[8]", QT_TRANSLATE_NOOP("binds", "up"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Move the cursor or camera without using the mouse:")},
{"+cur_l", "[4]", QT_TRANSLATE_NOOP("binds", "left"), NULL, NULL},
{"+cur_r", "[6]", QT_TRANSLATE_NOOP("binds", "right"), NULL, NULL},
@@ -55,7 +55,7 @@
{"zoomin", "wheelup", QT_TRANSLATE_NOOP("binds", "zoom in"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Modify the camera's zoom level:")},
{"zoomout", "wheeldown", QT_TRANSLATE_NOOP("binds", "zoom out"), NULL, NULL},
{"zoomreset", "mousem", QT_TRANSLATE_NOOP("binds", "reset zoom"), NULL, NULL},
- {"chat", "t", QT_TRANSLATE_NOOP("binds", "chat"), QT_TRANSLATE_NOOP("binds (categories)", "Other"), QT_TRANSLATE_NOOP("binds (descriptions)", "Talk to your team or all participants:")},
+ {"chat", "t", QT_TRANSLATE_NOOP("binds", "chat"), QT_TRANSLATE_NOOP("binds (categories)", "Miscellaneous"), QT_TRANSLATE_NOOP("binds (descriptions)", "Talk to your team or all participants:")},
{"history", "`", QT_TRANSLATE_NOOP("binds", "chat history"), NULL, NULL},
{"pause", "p", QT_TRANSLATE_NOOP("binds", "pause"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Pause, continue or leave your game:")},
{"quit", "escape", QT_TRANSLATE_NOOP("binds", "quit"), NULL, NULL},
@@ -65,6 +65,8 @@
{"mute", "8", QT_TRANSLATE_NOOP("binds", "mute audio"), NULL, NULL},
{"fullscr", "f12", QT_TRANSLATE_NOOP("binds", "change mode"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle fullscreen mode:")},
{"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:")},
+ {"rotmask", "delete", QT_TRANSLATE_NOOP("binds", "hedgehog info"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle labels above hedgehogs:")},
+#ifdef VIDEOREC
{"record", "r", QT_TRANSLATE_NOOP("binds", "record"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Record video:")}
+#endif
};
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/binds.h
--- a/QTfrontend/binds.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/binds.h Fri Feb 22 05:05:32 2013 +0100
@@ -21,7 +21,11 @@
#include
+#ifdef VIDEOREC
#define BINDS_NUMBER 46
+#else
+#define BINDS_NUMBER 45
+#endif
struct BindAction
{
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/campaign.cpp
--- a/QTfrontend/campaign.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/campaign.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -59,7 +59,7 @@
QSettings campfile("physfs://Missions/Campaign/" + campaign + "/campaign.ini", QSettings::IniFormat, 0);
campfile.setIniCodec("UTF-8");
unsigned int mNum = campfile.value("MissionNum", 0).toInt();
-
+
QStringList missionList;
for (unsigned int i = 0; i < mNum; i++)
{
@@ -67,7 +67,7 @@
}
return missionList;
}
-
+
unsigned int getCampProgress(QString & teamName, QString & campName)
{
QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + teamName + ".hwt", QSettings::IniFormat, 0);
@@ -81,10 +81,3 @@
campfile.setIniCodec("UTF-8");
return campfile.value(QString("Mission %1/Script").arg(mNum)).toString();
}
-
-
-
-
-
-
-
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/game.cpp
--- a/QTfrontend/game.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/game.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -22,13 +22,17 @@
#include
#include
#include
+#include
+#include "hwform.h"
+#include "ui/page/pageoptions.h"
#include "game.h"
#include "hwconsts.h"
#include "gameuiconfig.h"
#include "gamecfgwidget.h"
#include "teamselect.h"
#include "proto.h"
+#include "binds.h"
#include "campaign.h"
#include
@@ -37,7 +41,7 @@
QString training, campaign, campaignScript, campaignTeam; // TODO: Cleaner solution?
HWGame::HWGame(GameUIConfig * config, GameCFGWidget * gamecfg, QString ammo, TeamSelWidget* pTeamSelWidget) :
- TCPBase(true),
+ TCPBase(true, 0),
ammostr(ammo),
m_pTeamSelWidget(pTeamSelWidget)
{
@@ -56,7 +60,7 @@
switch (gameType)
{
case gtDemo:
- // for video recording we need demo anyway
+ // for video recording we need demo anyway
emit HaveRecord(rtNeither, demo);
break;
case gtNet:
@@ -73,6 +77,18 @@
SetGameState(gsStopped);
}
+void HWGame::addKeyBindings(QByteArray * buf)
+{
+ for(int i = 0; i < BINDS_NUMBER; i++)
+ {
+ QString value = config->value(QString("Binds/%1").arg(cbinds[i].action), cbinds[i].strbind).toString();
+ if (value.isEmpty() || value == "default") continue;
+
+ QString bind = QString("edbind " + value + " " + cbinds[i].action);
+ HWProto::addStringToBuffer(*buf, bind);
+ }
+}
+
void HWGame::commonConfig()
{
QByteArray buf;
@@ -90,6 +106,8 @@
}
HWProto::addStringToBuffer(buf, gt);
+ addKeyBindings(&buf);
+
buf += gamecfg->getFullConfig();
if (m_pTeamSelWidget)
@@ -102,10 +120,11 @@
HWProto::addStringToBuffer(buf, QString("eammreinf %1").arg(ammostr.mid(3 * cAmmoNumber, cAmmoNumber)));
if(gamecfg->schemeData(15).toBool() || !gamecfg->schemeData(21).toBool()) HWProto::addStringToBuffer(buf, QString("eammstore"));
HWProto::addStringListToBuffer(buf,
- team.teamGameConfig(gamecfg->getInitHealth()));
+ team.teamGameConfig(gamecfg->getInitHealth(), config));
;
}
}
+
RawSendIPC(buf);
}
@@ -119,6 +138,8 @@
QByteArray teamscfg;
ThemeModel * themeModel = DataManager::instance().themeModel();
+ addKeyBindings(&teamscfg);
+
HWProto::addStringToBuffer(teamscfg, "TL");
HWProto::addStringToBuffer(teamscfg, QString("etheme %1")
.arg((themeModel->rowCount() > 0) ? themeModel->index(rand() % themeModel->rowCount()).data().toString() : "steel"));
@@ -132,7 +153,7 @@
team1.setNumHedgehogs(4);
HWNamegen::teamRandomNames(team1,true);
HWProto::addStringListToBuffer(teamscfg,
- team1.teamGameConfig(100));
+ team1.teamGameConfig(100, config));
HWTeam team2;
team2.setDifficulty(4);
@@ -142,7 +163,7 @@
HWNamegen::teamRandomNames(team2,true);
while(!team2.name().compare(team1.name()) || !team2.hedgehog(0).Hat.compare(team1.hedgehog(0).Hat));
HWProto::addStringListToBuffer(teamscfg,
- team2.teamGameConfig(100));
+ team2.teamGameConfig(100, config));
HWProto::addStringToBuffer(teamscfg, QString("eammloadt %1").arg(cDefaultAmmoStore->mid(0, cAmmoNumber)));
HWProto::addStringToBuffer(teamscfg, QString("eammprob %1").arg(cDefaultAmmoStore->mid(cAmmoNumber, cAmmoNumber)));
@@ -150,6 +171,7 @@
HWProto::addStringToBuffer(teamscfg, QString("eammreinf %1").arg(cDefaultAmmoStore->mid(3 * cAmmoNumber, cAmmoNumber)));
HWProto::addStringToBuffer(teamscfg, QString("eammstore"));
HWProto::addStringToBuffer(teamscfg, QString("eammstore"));
+
RawSendIPC(teamscfg);
}
@@ -160,6 +182,8 @@
HWProto::addStringToBuffer(traincfg, "eseed " + QUuid::createUuid().toString());
HWProto::addStringToBuffer(traincfg, "escript " + training);
+ addKeyBindings(&traincfg);
+
RawSendIPC(traincfg);
}
@@ -171,6 +195,8 @@
HWProto::addStringToBuffer(campaigncfg, "escript " + campaignScript);
+ addKeyBindings(&campaigncfg);
+
RawSendIPC(campaigncfg);
}
@@ -274,12 +300,21 @@
writeCampaignVar(msg.right(msg.size() - 3));
break;
}
+ case 'W':
+ {
+ // fetch new window resolution via IPC and save it in the settings
+ int size = msg.size();
+ QString newResolution = QString().append(msg.mid(2)).left(size - 4);
+ QStringList wh = newResolution.split('x');
+ config->Form->ui.pageOptions->windowWidthEdit->setText(wh[0]);
+ config->Form->ui.pageOptions->windowHeightEdit->setText(wh[1]);
+ break;
+ }
default:
{
if (gameType == gtNet && !netSuspend)
- {
- emit SendNet(msg);
- }
+ m_netSendBuffer.append(msg);
+
demo.append(msg);
}
}
@@ -308,29 +343,64 @@
readbuffer.remove(0, msglen + 1);
ParseMessage(msg);
}
+
+ flushNetBuffer();
+}
+
+void HWGame::flushNetBuffer()
+{
+ if(m_netSendBuffer.size())
+ {
+ emit SendNet(m_netSendBuffer);
+
m_netSendBuffer.clear();
+ }
}
QStringList HWGame::getArguments()
{
QStringList arguments;
- QRect resolution = config->vid_Resolution();
- arguments << cfgdir->absolutePath();
- arguments << QString::number(resolution.width());
- arguments << QString::number(resolution.height());
- arguments << QString::number(config->bitDepth()); // bpp
+ std::pair resolutions = config->vid_ResolutionPair();
+ QString nick = config->netNick().toUtf8().toBase64();
+
+ arguments << "--internal"; //Must be passed as first argument
+ arguments << "--port";
arguments << QString("%1").arg(ipc_port);
- arguments << (config->vid_Fullscreen() ? "1" : "0");
- arguments << (config->isSoundEnabled() ? "1" : "0");
- arguments << (config->isMusicEnabled() ? "1" : "0");
- arguments << QString::number(config->volume()); // sound volume
- arguments << QString::number(config->timerInterval());
+ arguments << "--prefix";
arguments << datadir->absolutePath();
- arguments << (config->isShowFPSEnabled() ? "1" : "0");
- arguments << (config->isAltDamageEnabled() ? "1" : "0");
- arguments << config->netNick().toUtf8().toBase64();
+ arguments << "--user-prefix";
+ arguments << cfgdir->absolutePath();
+ arguments << "--locale";
+ arguments << tr("en.txt");
+ arguments << "--frame-interval";
+ arguments << QString::number(config->timerInterval());
+ arguments << "--volume";
+ arguments << QString::number(config->volume());
+ arguments << "--fullscreen-width";
+ arguments << QString::number(resolutions.first.width());
+ arguments << "--fullscreen-height";
+ arguments << QString::number(resolutions.first.height());
+ arguments << "--width";
+ arguments << QString::number(resolutions.second.width());
+ arguments << "--height";
+ arguments << QString::number(resolutions.second.height());
+ arguments << "--raw-quality";
arguments << QString::number(config->translateQuality());
+ arguments << "--stereo";
arguments << QString::number(config->stereoMode());
- arguments << tr("en.txt");
+ if (config->vid_Fullscreen())
+ arguments << "--fullscreen";
+ if (config->isShowFPSEnabled())
+ arguments << "--showfps";
+ if (config->isAltDamageEnabled())
+ arguments << "--altdmg";
+ if (!config->isSoundEnabled())
+ arguments << "--nosound";
+ if (!config->isMusicEnabled())
+ arguments << "--nomusic";
+ if (!nick.isEmpty()) {
+ arguments << "--nick";
+ arguments << nick;
+ }
return arguments;
}
@@ -350,7 +420,7 @@
// run engine
demo.clear();
- Start();
+ Start(false);
SetGameState(gsStarted);
}
@@ -358,7 +428,7 @@
{
gameType = gtNet;
demo.clear();
- Start();
+ Start(false);
SetGameState(gsStarted);
}
@@ -366,7 +436,7 @@
{
gameType = gtLocal;
demo.clear();
- Start();
+ Start(false);
SetGameState(gsStarted);
}
@@ -374,7 +444,7 @@
{
gameType = gtQLocal;
demo.clear();
- Start();
+ Start(false);
SetGameState(gsStarted);
}
@@ -383,7 +453,7 @@
gameType = gtTraining;
training = "Missions/Training/" + file + ".lua";
demo.clear();
- Start();
+ Start(false);
SetGameState(gsStarted);
}
@@ -394,7 +464,7 @@
campaignScript = "Missions/Campaign/" + camp + "/" + campScript;
campaignTeam = campTeam;
demo.clear();
- Start();
+ Start(false);
SetGameState(gsStarted);
}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/game.h
--- a/QTfrontend/game.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/game.h Fri Feb 22 05:05:32 2013 +0100
@@ -102,7 +102,9 @@
GameCFGWidget * gamecfg;
TeamSelWidget* m_pTeamSelWidget;
GameType gameType;
+ QByteArray m_netSendBuffer;
+ void addKeyBindings(QByteArray * buf);
void commonConfig();
void SendConfig();
void SendQuickConfig();
@@ -113,6 +115,7 @@
void SetGameState(GameState state);
void sendCampaignVar(const QByteArray & varToSend);
void writeCampaignVar(const QByteArray &varVal);
+ void flushNetBuffer();
};
#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/gameuiconfig.cpp
--- a/QTfrontend/gameuiconfig.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/gameuiconfig.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include "gameuiconfig.h"
#include "hwform.h"
@@ -34,6 +35,7 @@
#include "fpsedit.h"
#include "HWApplication.h"
#include "DataManager.h"
+#include "SDL.h"
const QNetworkProxy::ProxyType proxyTypesMap[] = {
@@ -44,24 +46,35 @@
GameUIConfig::GameUIConfig(HWForm * FormWidgets, const QString & fileName)
- : QSettings(fileName, QSettings::IniFormat)
+ : QSettings(fileName, QSettings::IniFormat, FormWidgets)
{
Form = FormWidgets;
- connect(Form->ui.pageOptions->CBEnableFrontendMusic, SIGNAL(toggled(bool)), Form, SLOT(Music(bool)));
+ setIniCodec("UTF-8");
+
+ connect(Form->ui.pageOptions->CBFrontendMusic, SIGNAL(toggled(bool)), Form, SLOT(Music(bool)));
+
+ for(int i = 0; i < BINDS_NUMBER; i++)
+ {
+ m_binds.append(BindAction());
+ m_binds[i].action = cbinds[i].action;
+ m_binds[i].strbind = cbinds[i].strbind;
+ }
//Form->resize(value("frontend/width", 640).toUInt(), value("frontend/height", 450).toUInt());
resizeToConfigValues();
reloadValues();
+#ifdef VIDEOREC
reloadVideosValues();
+#endif
}
void GameUIConfig::reloadValues(void)
{
Form->ui.pageOptions->WeaponTooltip->setChecked(value("misc/weaponTooltips", true).toBool());
- int t = Form->ui.pageOptions->CBResolution->findText(value("video/resolution").toString());
+ int t = Form->ui.pageOptions->CBResolution->findText(value("video/fullscreenResolution").toString());
if (t < 0)
{
if (Form->ui.pageOptions->CBResolution->count() > 1)
@@ -70,6 +83,20 @@
Form->ui.pageOptions->CBResolution->setCurrentIndex(0);
}
else Form->ui.pageOptions->CBResolution->setCurrentIndex(t);
+
+ // Default the windowed resolution to 5/6 of the screen size
+ int screenWidth = SDL_GetVideoInfo()->current_w * 5 / 6;
+ int screenHeight = SDL_GetVideoInfo()->current_h * 5 / 6;
+ QString widthStr; widthStr.setNum(screenWidth);
+ QString heightStr; heightStr.setNum(screenHeight);
+ QString wWidth = value("video/windowedWidth", widthStr).toString();
+ QString wHeight = value("video/windowedHeight", heightStr).toString();
+ // If left blank reset the resolution to the default
+ wWidth = (wWidth == "" ? widthStr : wWidth);
+ wHeight = (wHeight == "" ? heightStr : wHeight);
+ Form->ui.pageOptions->windowWidthEdit->setText(wWidth);
+ Form->ui.pageOptions->windowHeightEdit->setText(wHeight);
+
Form->ui.pageOptions->CBResolution->setCurrentIndex((t < 0) ? 1 : t);
Form->ui.pageOptions->CBFullscreen->setChecked(value("video/fullscreen", false).toBool());
bool ffscr=value("frontend/fullscreen", false).toBool();
@@ -77,12 +104,12 @@
Form->ui.pageOptions->SLQuality->setValue(value("video/quality", 5).toUInt());
Form->ui.pageOptions->CBStereoMode->setCurrentIndex(value("video/stereo", 0).toUInt());
- Form->ui.pageOptions->CBEnableFrontendSound->setChecked(value("frontend/effects", true).toBool());
- Form->ui.pageOptions->CBEnableSound->setChecked(value("audio/sound", true).toBool());
- Form->ui.pageOptions->CBEnableFrontendSound->setChecked(value("frontend/sound", true).toBool());
- Form->ui.pageOptions->CBEnableMusic->setChecked(value("audio/music", true).toBool());
- Form->ui.pageOptions->CBEnableFrontendMusic->setChecked(value("frontend/music", true).toBool());
- Form->ui.pageOptions->volumeBox->setValue(value("audio/volume", 100).toUInt());
+ Form->ui.pageOptions->CBFrontendEffects->setChecked(value("frontend/effects", true).toBool());
+ Form->ui.pageOptions->CBSound->setChecked(value("audio/sound", true).toBool());
+ Form->ui.pageOptions->CBFrontendSound->setChecked(value("frontend/sound", true).toBool());
+ Form->ui.pageOptions->CBMusic->setChecked(value("audio/music", true).toBool());
+ Form->ui.pageOptions->CBFrontendMusic->setChecked(value("frontend/music", true).toBool());
+ Form->ui.pageOptions->SLVolume->setValue(value("audio/volume", 100).toUInt());
QString netNick = value("net/nick", "").toString();
Form->ui.pageOptions->editNetNick->setText(netNick);
@@ -92,11 +119,13 @@
Form->ui.pageOptions->editNetPassword->installEventFilter(this);
int passLength = value("net/passwordlength", 0).toInt();
- setNetPasswordLength(passLength);
- if (savePwd == false) {
- Form->ui.pageOptions->editNetPassword->setEnabled(savePwd);
+ if (!savePwd) {
+ Form->ui.pageOptions->editNetPassword->setEnabled(false);
Form->ui.pageOptions->editNetPassword->setText("");
- setNetPasswordLength(0);
+ setNetPasswordLength(0);
+ } else
+ {
+ setNetPasswordLength(passLength);
}
delete netHost;
@@ -124,39 +153,51 @@
Form->ui.pageOptions->leProxyLogin->setText(value("proxy/login", "").toString());
Form->ui.pageOptions->leProxyPassword->setText(value("proxy/password", "").toString());
- depth = HWApplication::desktop()->depth();
- if (depth < 16) depth = 16;
- else if (depth > 16) depth = 32;
-
{ // load colors
QStandardItemModel * model = DataManager::instance().colorsModel();
for(int i = model->rowCount() - 1; i >= 0; --i)
- model->item(i)->setData(QColor(value(QString("colors/color%1").arg(i), model->item(i)->data().value()).value()));
+ model->item(i)->setData(value(QString("colors/color%1").arg(i), model->item(i)->data()));
+ }
+
+ { // load binds
+ for(int i = 0; i < BINDS_NUMBER; i++)
+ {
+ m_binds[i].strbind = value(QString("Binds/%1").arg(m_binds[i].action), cbinds[i].strbind).toString();
+ if (m_binds[i].strbind.isEmpty() || m_binds[i].strbind == "default") m_binds[i].strbind = cbinds[i].strbind;
+ }
}
}
void GameUIConfig::reloadVideosValues(void)
{
- Form->ui.pageVideos->framerateBox->setValue(value("videorec/fps",25).toUInt());
- Form->ui.pageVideos->bitrateBox->setValue(value("videorec/bitrate",400).toUInt());
- bool useGameRes = value("videorec/usegameres",true).toBool();
+ // one pass with default values
+ Form->ui.pageOptions->setDefaultOptions();
+
+ // then load user configuration
+ Form->ui.pageOptions->framerateBox->setCurrentIndex(
+ Form->ui.pageOptions->framerateBox->findData(
+ value("videorec/framerate", rec_Framerate()).toString() + " fps",
+ Qt::MatchExactly) );
+ Form->ui.pageOptions->bitrateBox->setValue(value("videorec/bitrate", rec_Bitrate()).toUInt());
+ bool useGameRes = value("videorec/usegameres",Form->ui.pageOptions->checkUseGameRes->isChecked()).toBool();
if (useGameRes)
{
QRect res = vid_Resolution();
- Form->ui.pageVideos->widthEdit->setText(QString::number(res.width()));
- Form->ui.pageVideos->heightEdit->setText(QString::number(res.height()));
+ Form->ui.pageOptions->widthEdit->setText(QString::number(res.width()));
+ Form->ui.pageOptions->heightEdit->setText(QString::number(res.height()));
}
else
{
- Form->ui.pageVideos->widthEdit->setText(value("videorec/width","800").toString());
- Form->ui.pageVideos->heightEdit->setText(value("videorec/height","600").toString());
+ Form->ui.pageOptions->widthEdit->setText(value("videorec/width","800").toString());
+ Form->ui.pageOptions->heightEdit->setText(value("videorec/height","600").toString());
}
- Form->ui.pageVideos->checkUseGameRes->setChecked(useGameRes);
- Form->ui.pageVideos->checkRecordAudio->setChecked(value("videorec/audio",true).toBool());
- if (!Form->ui.pageVideos->tryCodecs(value("videorec/format","no").toString(),
+ Form->ui.pageOptions->checkUseGameRes->setChecked(useGameRes);
+ Form->ui.pageOptions->checkRecordAudio->setChecked(
+ value("videorec/audio",Form->ui.pageOptions->checkRecordAudio->isChecked()).toBool() );
+ if (!Form->ui.pageOptions->tryCodecs(value("videorec/format","no").toString(),
value("videorec/videocodec","no").toString(),
value("videorec/audiocodec","no").toString()))
- Form->ui.pageVideos->setDefaultCodecs();
+ Form->ui.pageOptions->setDefaultCodecs();
}
QStringList GameUIConfig::GetTeamsList()
@@ -175,12 +216,23 @@
void GameUIConfig::resizeToConfigValues()
{
- Form->resize(value("frontend/width", 800).toUInt(), value("frontend/height", 600).toUInt());
+ // fill 2/3 of the screen desktop
+ const QRect deskSize = QApplication::desktop()->screenGeometry(-1);
+ Form->resize(value("frontend/width", qMin(qMax(deskSize.width()*2/3,800),deskSize.width())).toUInt(),
+ value("frontend/height", qMin(qMax(deskSize.height()*2/3,600),deskSize.height())).toUInt());
+
+ // move the window to the center of the screen
+ QPoint center = QApplication::desktop()->availableGeometry(-1).center();
+ center.setX(center.x() - (Form->width()/2));
+ center.setY(center.y() - (Form->height()/2));
+ Form->move(center);
}
void GameUIConfig::SaveOptions()
{
- setValue("video/resolution", Form->ui.pageOptions->CBResolution->currentText());
+ setValue("video/fullscreenResolution", Form->ui.pageOptions->CBResolution->currentText());
+ setValue("video/windowedWidth", Form->ui.pageOptions->windowWidthEdit->text());
+ setValue("video/windowedHeight", Form->ui.pageOptions->windowHeightEdit->text());
setValue("video/fullscreen", vid_Fullscreen());
setValue("video/quality", Form->ui.pageOptions->SLQuality->value());
@@ -207,14 +259,16 @@
setValue("frontend/sound", isFrontendSoundEnabled());
setValue("audio/music", isMusicEnabled());
setValue("frontend/music", isFrontendMusicEnabled());
- setValue("audio/volume", Form->ui.pageOptions->volumeBox->value());
+ setValue("audio/volume", Form->ui.pageOptions->SLVolume->value());
setValue("net/nick", netNick());
- if (netPasswordIsValid() && Form->ui.pageOptions->CBSavePassword->isChecked())
- {
- setValue("net/passwordhash", netPasswordHash());
- setValue("net/passwordlength", netPasswordLength());
+ if (netPasswordIsValid() && Form->ui.pageOptions->CBSavePassword->isChecked()) {
+ setPasswordHash(netPasswordHash());
}
+ else if(!Form->ui.pageOptions->CBSavePassword->isChecked()) {
+ clearPasswordHash();
+ }
+
setValue("net/savepassword", Form->ui.pageOptions->CBSavePassword->isChecked());
setValue("net/ip", *netHost);
setValue("net/port", netPort);
@@ -268,7 +322,7 @@
setValue(QString("colors/color%1").arg(i), model->item(i)->data());
}
- Form->gameSettings->sync();
+ sync();
}
void GameUIConfig::SaveVideosOptions()
@@ -277,14 +331,20 @@
setValue("videorec/format", AVFormat());
setValue("videorec/videocodec", videoCodec());
setValue("videorec/audiocodec", audioCodec());
- setValue("videorec/fps", rec_Framerate());
+ setValue("videorec/framerate", rec_Framerate());
setValue("videorec/bitrate", rec_Bitrate());
setValue("videorec/width", res.width());
setValue("videorec/height", res.height());
- setValue("videorec/usegameres", Form->ui.pageVideos->checkUseGameRes->isChecked());
+ setValue("videorec/usegameres", Form->ui.pageOptions->checkUseGameRes->isChecked());
setValue("videorec/audio", recordAudio());
- Form->gameSettings->sync();
+ sync();
+}
+
+void GameUIConfig::setValue(const QString &key, const QVariant &value)
+{
+ //qDebug() << "[settings]" << key << value;
+ QSettings::setValue(key, value);
}
QString GameUIConfig::language()
@@ -292,16 +352,28 @@
return Form->ui.pageOptions->CBLanguage->itemData(Form->ui.pageOptions->CBLanguage->currentIndex()).toString();
}
-QRect GameUIConfig::vid_Resolution()
-{
- QRect result(0, 0, 640, 480);
+std::pair GameUIConfig::vid_ResolutionPair() {
+ // returns a pair of both the fullscreen and the windowed resolution
+ QRect full(0, 0, 640, 480);
+ QRect windowed(0, 0, 640, 480);
QStringList wh = Form->ui.pageOptions->CBResolution->currentText().split('x');
if (wh.size() == 2)
{
- result.setWidth(wh[0].toInt());
- result.setHeight(wh[1].toInt());
+ full.setWidth(wh[0].toInt());
+ full.setHeight(wh[1].toInt());
}
- return result;
+ windowed.setWidth(Form->ui.pageOptions->windowWidthEdit->text().toInt());
+ windowed.setHeight(Form->ui.pageOptions->windowHeightEdit->text().toInt());
+ return std::make_pair(full, windowed);
+}
+
+QRect GameUIConfig::vid_Resolution()
+{
+ std::pair result = vid_ResolutionPair();
+ if(Form->ui.pageOptions->CBFullscreen->isChecked())
+ return result.first;
+ else
+ return result.second;
}
bool GameUIConfig::vid_Fullscreen()
@@ -370,20 +442,20 @@
bool GameUIConfig::isSoundEnabled()
{
- return Form->ui.pageOptions->CBEnableSound->isChecked();
+ return Form->ui.pageOptions->CBSound->isChecked();
}
bool GameUIConfig::isFrontendSoundEnabled()
{
- return Form->ui.pageOptions->CBEnableFrontendSound->isChecked();
+ return Form->ui.pageOptions->CBFrontendSound->isChecked();
}
bool GameUIConfig::isMusicEnabled()
{
- return Form->ui.pageOptions->CBEnableMusic->isChecked();
+ return Form->ui.pageOptions->CBMusic->isChecked();
}
bool GameUIConfig::isFrontendMusicEnabled()
{
- return Form->ui.pageOptions->CBEnableFrontendMusic->isChecked();
+ return Form->ui.pageOptions->CBFrontendMusic->isChecked();
}
bool GameUIConfig::isShowFPSEnabled()
@@ -418,11 +490,6 @@
return 35 - Form->ui.pageOptions->fpsedit->value();
}
-quint8 GameUIConfig::bitDepth()
-{
- return depth;
-}
-
QString GameUIConfig::netNick()
{
return Form->ui.pageOptions->editNetNick->text();
@@ -445,7 +512,41 @@
bool GameUIConfig::netPasswordIsValid()
{
- return (netPasswordLength() == 0 || Form->ui.pageOptions->editNetPassword->text() != QString(netPasswordLength(), '\0'));
+ return (netPasswordLength() == 0 || Form->ui.pageOptions->editNetPassword->text() != QString(netPasswordLength(), '*'));
+}
+
+void GameUIConfig::clearPasswordHash()
+{
+ setValue("net/passwordhash", QString());
+ setValue("net/passwordlength", 0);
+ setValue("net/savepassword", false); //changes the savepassword value to false in order to not let the user save an empty password in PAGE_SETUP
+ reloadValues(); //reloads the values of PAGE_SETUP
+}
+
+void GameUIConfig::setPasswordHash(const QString & passwordhash)
+{
+ setValue("net/passwordhash", passwordhash);
+ setValue("net/passwordlength", passwordhash.size()/4);
+ setNetPasswordLength(passwordhash.size()/4); //the hash.size() is divided by 4 let PAGE_SETUP use a reasonable number of stars to display the PW
+}
+
+QString GameUIConfig::passwordHash()
+{
+ return value("net/passwordhash").toString();
+}
+
+void GameUIConfig::clearTempHash()
+{
+ setTempHash(QString());
+}
+
+void GameUIConfig::setTempHash(const QString & temphash)
+{
+ this->temphash = temphash;
+}
+
+QString GameUIConfig::tempHash() {
+ return this->temphash;
}
// When hedgewars launches, the password field is set with null characters. If the user tries to edit the field and there are such characters, then clear the field
@@ -470,7 +571,7 @@
{
if (passwordLength > 0)
{
- Form->ui.pageOptions->editNetPassword->setText(QString(passwordLength, '\0'));
+ Form->ui.pageOptions->editNetPassword->setText(QString(passwordLength, '*'));
}
else
{
@@ -480,45 +581,61 @@
quint8 GameUIConfig::volume()
{
- return Form->ui.pageOptions->volumeBox->value() * 128 / 100;
+ return Form->ui.pageOptions->SLVolume->value() * 128 / 100;
}
QString GameUIConfig::AVFormat()
{
- return Form->ui.pageVideos->format();
+ return Form->ui.pageOptions->format();
}
QString GameUIConfig::videoCodec()
{
- return Form->ui.pageVideos->videoCodec();
+ return Form->ui.pageOptions->videoCodec();
}
QString GameUIConfig::audioCodec()
{
- return Form->ui.pageVideos->audioCodec();
+ return Form->ui.pageOptions->audioCodec();
}
QRect GameUIConfig::rec_Resolution()
{
- if (Form->ui.pageVideos->checkUseGameRes->isChecked())
+ if (Form->ui.pageOptions->checkUseGameRes->isChecked())
return vid_Resolution();
QRect res(0,0,0,0);
- res.setWidth(Form->ui.pageVideos->widthEdit->text().toUInt());
- res.setHeight(Form->ui.pageVideos->heightEdit->text().toUInt());
+ res.setWidth(Form->ui.pageOptions->widthEdit->text().toUInt());
+ res.setHeight(Form->ui.pageOptions->heightEdit->text().toUInt());
return res;
}
int GameUIConfig::rec_Framerate()
{
- return Form->ui.pageVideos->framerateBox->value();
+ // remove the "fps" label
+ QString fpsText = Form->ui.pageOptions->framerateBox->currentText();
+ QStringList fpsList = fpsText.split(" ");
+ return fpsList.first().toInt();
}
int GameUIConfig::rec_Bitrate()
{
- return Form->ui.pageVideos->bitrateBox->value();
+ return Form->ui.pageOptions->bitrateBox->value();
}
bool GameUIConfig::recordAudio()
{
- return Form->ui.pageVideos->checkRecordAudio->isChecked();
+ return Form->ui.pageOptions->checkRecordAudio->isChecked();
+}
+
+// Gets a bind for a bindID
+QString GameUIConfig::bind(int bindID)
+{
+ return m_binds[bindID].strbind;
}
+
+// Sets a bind for a bindID and saves it
+void GameUIConfig::setBind(int bindID, QString & strbind)
+{
+ m_binds[bindID].strbind = strbind;
+ setValue(QString("Binds/%1").arg(m_binds[bindID].action), strbind);
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/gameuiconfig.h
--- a/QTfrontend/gameuiconfig.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/gameuiconfig.h Fri Feb 22 05:05:32 2013 +0100
@@ -23,6 +23,9 @@
#include
#include
#include
+#include
+#include
+#include "binds.h"
class HWForm;
class QSettings;
@@ -36,6 +39,7 @@
GameUIConfig(HWForm * FormWidgets, const QString & fileName);
QStringList GetTeamsList();
QRect vid_Resolution();
+ std::pair vid_ResolutionPair();
bool vid_Fullscreen();
quint32 translateQuality();
bool isSoundEnabled();
@@ -48,16 +52,24 @@
bool appendDateTimeToRecordName();
quint8 volume();
quint8 timerInterval();
- quint8 bitDepth();
QString netNick();
QByteArray netPasswordHash();
int netPasswordLength();
+ void clearPasswordHash();
+ void setPasswordHash(const QString & passwordhash);
+ QString passwordHash();
+ void clearTempHash();
+ void setTempHash(const QString & temphash);
+ QString tempHash();
void setNetPasswordLength(int passwordLength);
bool isReducedQuality() const;
bool isFrontendEffects() const;
bool isFrontendFullscreen() const;
void resizeToConfigValues();
quint32 stereoMode() const;
+ void setValue(const QString & key, const QVariant & value);
+ QString bind(int bindID);
+ void setBind(int bindID, QString & strbind);
QString AVFormat();
QString videoCodec();
@@ -85,7 +97,8 @@
private:
bool netPasswordIsValid();
bool eventFilter(QObject *object, QEvent *event);
- quint8 depth;
+ QString temphash;
+ QList m_binds;
};
#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/hedgewars.qrc
--- a/QTfrontend/hedgewars.qrc Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/hedgewars.qrc Fri Feb 22 05:05:32 2013 +0100
@@ -44,6 +44,9 @@
res/HedgewarsTitle.png
res/LocalPlay.png
res/NetworkPlay.png
+ res/NetworkPlayDisabled.png
+ res/audio.png
+ res/camera.png
res/Settings.png
res/dropdown.png
res/new.png
@@ -102,6 +105,7 @@
res/iconRope.png
res/dice.png
res/Star.png
+ res/inverse-corner-bl.png
res/Flake.png
res/Egg.png
res/Confetti.png
@@ -129,6 +133,7 @@
res/StatsMostSelfDamage.png
res/StatsSelfKilled.png
res/StatsSkipped.png
+ res/Start.png
res/mapRandom.png
res/mapMaze.png
res/mapMissing.png
@@ -145,5 +150,8 @@
res/chat/serveradmin_gray.png
res/chat/lamp_off.png
res/chat/ingame.png
+ res/splash.png
+ res/html/about.html
+ res/xml/tips.xml
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/hwconsts.cpp.in
--- a/QTfrontend/hwconsts.cpp.in Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/hwconsts.cpp.in Fri Feb 22 05:05:32 2013 +0100
@@ -22,10 +22,9 @@
QString * cProtoVer = new QString("${HEDGEWARS_PROTO_VER}");
QString * cDataDir = new QString("${HEDGEWARS_DATADIR}");
-QString * cConfigDir = new QString("");
-QString * cVersionString = new QString("${HEDGEWARS_VERSION}${HGCHANGED}");
+QString * cVersionString = new QString("${HEDGEWARS_VERSION}");
-QDir * bindir = new QDir("${HEDGEWARS_BINDIR}");
+QDir * bindir = new QDir();
QDir * cfgdir = new QDir();
QDir * datadir = new QDir();
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/hwconsts.h
--- a/QTfrontend/hwconsts.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/hwconsts.h Fri Feb 22 05:05:32 2013 +0100
@@ -26,7 +26,6 @@
extern QString * cProtoVer;
extern QString * cVersionString;
extern QString * cDataDir;
-extern QString * cConfigDir;
extern QDir * bindir;
extern QDir * cfgdir;
@@ -63,40 +62,40 @@
#define HEDGEHOGS_PER_TEAM 8
-#define AMMOLINE_DEFAULT_QT "93919294221991210322351110012010000002111101010111110101"
-#define AMMOLINE_DEFAULT_PROB "04050405416006555465544647765766666661555101011154110101"
-#define AMMOLINE_DEFAULT_DELAY "00000000000002055000000400070040000000002200000006000000"
-#define AMMOLINE_DEFAULT_CRATE "13111103121111111231141111111111111112111111011111110101"
+#define AMMOLINE_DEFAULT_QT "9391929422199121032235111001201000000211110101011111101"
+#define AMMOLINE_DEFAULT_PROB "0405040541600655546554464776576666666155510101115411101"
+#define AMMOLINE_DEFAULT_DELAY "0000000000000205500000040007004000000000220000000600000"
+#define AMMOLINE_DEFAULT_CRATE "1311110312111111123114111111111111111211111101111111101"
-#define AMMOLINE_CRAZY_QT "99999999999999999929999999999999992999999999099999920909"
-#define AMMOLINE_CRAZY_PROB "11111101111111111111111111111111111111111111011111110101"
-#define AMMOLINE_CRAZY_DELAY "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CRAZY_CRATE "13111103121111111231141111111111111112111101011111110101"
+#define AMMOLINE_CRAZY_QT "9999999999999999992999999999999999299999999909999992909"
+#define AMMOLINE_CRAZY_PROB "1111110111111111111111111111111111111111111101111111101"
+#define AMMOLINE_CRAZY_DELAY "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_CRAZY_CRATE "1311110312111111123114111111111111111211110101111111101"
-#define AMMOLINE_PROMODE_QT "90900090000000000000090000000000000000000000000000000000"
-#define AMMOLINE_PROMODE_PROB "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_PROMODE_DELAY "00000000000002055000000400070040000000002000000000000002"
-#define AMMOLINE_PROMODE_CRATE "11111111111111111111111111111111111111111001011111110101"
+#define AMMOLINE_PROMODE_QT "9090009000000000000009000000000000000000000000000000000"
+#define AMMOLINE_PROMODE_PROB "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_PROMODE_DELAY "0000000000000205500000040007004000000000200000000000002"
+#define AMMOLINE_PROMODE_CRATE "1111111111111111111111111111111111111111100101111111101"
-#define AMMOLINE_SHOPPA_QT "00000099000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_PROB "44444100442444022101121212224220000000020004000100110001"
-#define AMMOLINE_SHOPPA_DELAY "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_CRATE "11111111111111111111111111111111111111111011011111110001"
+#define AMMOLINE_SHOPPA_QT "0000009900000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPA_PROB "4444410044244402210112121222422000000002000400010011001"
+#define AMMOLINE_SHOPPA_DELAY "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPA_CRATE "1111111111111111111111111111111111111111101101111111001"
-#define AMMOLINE_CLEAN_QT "10100090000100000110000000000000000000000000000010000000"
-#define AMMOLINE_CLEAN_PROB "04050405416006555465544647765766666661555101011154110101"
-#define AMMOLINE_CLEAN_DELAY "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CLEAN_CRATE "13111103121111111231141111111111111112111111011111110101"
+#define AMMOLINE_CLEAN_QT "1010009000010000011000000000000000000000000000001000000"
+#define AMMOLINE_CLEAN_PROB "0405040541600655546554464776576666666155510101115411101"
+#define AMMOLINE_CLEAN_DELAY "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_CLEAN_CRATE "1311110312111111123114111111111111111211111101111111101"
-#define AMMOLINE_MINES_QT "00000099000900000003000000000000000000000000000000000000"
-#define AMMOLINE_MINES_PROB "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_MINES_DELAY "00000000000002055000000400070040000000002000000006000000"
-#define AMMOLINE_MINES_CRATE "11111111111111111111111111111111111111111111011111110101"
+#define AMMOLINE_MINES_QT "0000009900090000000300000000000000000000000000000000000"
+#define AMMOLINE_MINES_PROB "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_MINES_DELAY "0000000000000205500000040007004000000000200000000600000"
+#define AMMOLINE_MINES_CRATE "1111111111111111111111111111111111111111111101111111101"
-#define AMMOLINE_PORTALS_QT "90000090020000000021000000000000001100000900000000000000"
-#define AMMOLINE_PORTALS_PROB "04050405416006555465544647765766666661555101011154110101"
-#define AMMOLINE_PORTALS_DELAY "00000000000002055000000400070040000000002000000006000000"
-#define AMMOLINE_PORTALS_CRATE "13111103121111111231141111111111111112111111011111110101"
+#define AMMOLINE_PORTALS_QT "9000009002000000002100000000000000110000090000000000000"
+#define AMMOLINE_PORTALS_PROB "0405040541600655546554464776576666666155510101115411101"
+#define AMMOLINE_PORTALS_DELAY "0000000000000205500000040007004000000000200000000600000"
+#define AMMOLINE_PORTALS_CRATE "1311110312111111123114111111111111111211111101111111101"
//Different seasons; assigned to season (int)
#define SEASON_NONE 0
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/hwform.cpp
--- a/QTfrontend/hwform.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/hwform.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -39,6 +40,8 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -70,10 +73,8 @@
#include "pagemultiplayer.h"
#include "pagenet.h"
#include "pagemain.h"
-#include "pagefeedback.h"
#include "pagenetserver.h"
#include "pagedrawmap.h"
-#include "pagenettype.h"
#include "pagegamestats.h"
#include "pageplayrecord.h"
#include "pagedata.h"
@@ -94,8 +95,23 @@
#include "roomslistmodel.h"
#include "recorder.h"
#include "playerslistmodel.h"
+#include "feedbackdialog.h"
+#include "MessageDialog.h"
#include "DataManager.h"
+#include "AutoUpdater.h"
+
+#ifdef Q_WS_WIN
+#define WINVER 0x0500
+#include
+#else
+#include
+#include
+#endif
+
+#ifdef Q_WS_MAC
+#include
+#endif
#ifdef __APPLE__
#include "M3Panel.h"
@@ -111,7 +127,6 @@
QString playerHash;
GameUIConfig* HWForm::config = NULL;
-QSettings* HWForm::gameSettings = NULL;
HWForm::HWForm(QWidget *parent, QString styleSheet)
: QMainWindow(parent)
@@ -127,10 +142,6 @@
#ifdef USE_XFIRE
xfire_init();
#endif
- gameSettings = new QSettings(cfgdir->absolutePath() + "/hedgewars.ini", QSettings::IniFormat);
- frontendEffects = gameSettings->value("frontend/effects", true).toBool();
- playerHash = QString(QCryptographicHash::hash(gameSettings->value("net/nick","").toString().toUtf8(), QCryptographicHash::Md5).toHex());
-
this->setStyleSheet(styleSheet);
ui.setupUi(this);
setMinimumSize(760, 580);
@@ -139,21 +150,39 @@
ui.pageOptions->CBResolution->addItems(SDLInteraction::instance().getResolutions());
- config = new GameUIConfig(this, cfgdir->absolutePath() + "/hedgewars.ini");
+ config = new GameUIConfig(this, "physfs://hedgewars.ini");
+ frontendEffects = config->value("frontend/effects", true).toBool();
+ playerHash = QString(QCryptographicHash::hash(config->value("net/nick","").toString().toUtf8(), QCryptographicHash::Md5).toHex());
+
+ ui.pageRoomsList->setSettings(config);
+ ui.pageNetGame->setSettings(config);
+ ui.pageNetGame->chatWidget->setSettings(config);
+ ui.pageRoomsList->chatWidget->setSettings(config);
+ ui.pageOptions->setConfig(config);
+#ifdef VIDEOREC
+ ui.pageVideos->init(config);
+#endif
- ui.pageVideos->init(config);
+#ifdef __APPLE__
+ AutoUpdater* updater = NULL;
+ if (config->isAutoUpdateEnabled())
+ {
+#ifdef __APPLE__
+#ifdef SPARKLE_ENABLED
+ updater = new SparkleAutoUpdater();
+#endif
+#endif
+ if (updater)
+ {
+ updater->checkForUpdates();
+ delete updater;
+ }
+ }
+#endif
#ifdef __APPLE__
panel = new M3Panel;
-#ifdef SPARKLE_ENABLED
- AutoUpdater* updater;
-
- updater = new SparkleAutoUpdater();
- if (updater && config->isAutoUpdateEnabled())
- updater->checkForUpdates();
-#endif
-
QShortcut *hideFrontend = new QShortcut(QKeySequence("Ctrl+M"), this);
connect (hideFrontend, SIGNAL(activated()), this, SLOT(showMinimized()));
#else
@@ -187,13 +216,7 @@
connect(ui.pageMain->BtnSetup, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
pageSwitchMapper->setMapping(ui.pageMain->BtnSetup, ID_PAGE_SETUP);
-#if 0
- connect(ui.pageMain->BtnFeedback, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
- pageSwitchMapper->setMapping(ui.pageMain->BtnFeedback, ID_PAGE_FEEDBACK);
-#endif
-
- connect(ui.pageMain->BtnNet, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
- pageSwitchMapper->setMapping(ui.pageMain->BtnNet, ID_PAGE_NETTYPE);
+ connect(ui.pageMain->BtnFeedback, SIGNAL(clicked()), this, SLOT(showFeedbackDialog()));
connect(ui.pageMain->BtnInfo, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
pageSwitchMapper->setMapping(ui.pageMain->BtnInfo, ID_PAGE_INFO);
@@ -210,8 +233,6 @@
//connect(ui.pageMain->BtnExit, SIGNAL(pressed()), this, SLOT(btnExitPressed()));
//connect(ui.pageMain->BtnExit, SIGNAL(clicked()), this, SLOT(btnExitClicked()));
- connect(ui.pageFeedback->BtnSend, SIGNAL(clicked()), this, SLOT(SendFeedback()));
-
connect(ui.pageEditTeam, SIGNAL(goBack()), this, SLOT(AfterTeamEdit()));
connect(ui.pageMultiplayer->BtnStartMPGame, SIGNAL(clicked()), this, SLOT(StartMPGame()));
@@ -293,8 +314,8 @@
// this, SLOT(GoBack())); // executed third
- connect(ui.pageNetType->BtnLAN, SIGNAL(clicked()), this, SLOT(GoToNet()));
- connect(ui.pageNetType->BtnOfficialServer, SIGNAL(clicked()), this, SLOT(NetConnectOfficialServer()));
+ connect(ui.pageMain->BtnNetLocal, SIGNAL(clicked()), this, SLOT(GoToNet()));
+ connect(ui.pageMain->BtnNetOfficial, SIGNAL(clicked()), this, SLOT(NetConnectOfficialServer()));
connect(ui.pageConnecting, SIGNAL(cancelConnection()), this, SLOT(GoBack()));
@@ -330,6 +351,7 @@
}
PagesStack.push(ID_PAGE_MAIN);
+ ((AbstractPage*)ui.Pages->widget(ID_PAGE_MAIN))->triggerPageEnter();
GoBack();
}
@@ -441,23 +463,27 @@
}
}
-void HWForm::UpdateTeamsLists(const QStringList* editable_teams)
+void HWForm::UpdateTeamsLists()
{
- QStringList teamslist;
- if(editable_teams)
- {
- teamslist =* editable_teams;
- }
- else
- {
- teamslist = config->GetTeamsList();
- }
+ QStringList teamslist = config->GetTeamsList();
if(teamslist.empty())
{
- HWTeam defaultTeam(tr("DefaultTeam"));
+ QString currentNickName = config->value("net/nick","").toString().toUtf8();
+ QString teamName;
+
+ if (currentNickName.isEmpty())
+ {
+ teamName = tr("DefaultTeam");
+ }
+ else
+ {
+ teamName = tr("%1's Team").arg(currentNickName);
+ }
+
+ HWTeam defaultTeam(teamName);
defaultTeam.saveToFile();
- teamslist.push_back(tr("DefaultTeam"));
+ teamslist.push_back(teamName);
}
ui.pageOptions->CBTeamName->clear();
@@ -528,11 +554,52 @@
GoToPage(ID_PAGE_VIDEOS);
}
+//TODO: maybe find a better place for this?
+QString HWForm::stringifyPageId(quint32 id)
+{
+ QString pageName;
+ switch (id)
+ {
+ case ID_PAGE_SETUP_TEAM : pageName = "PAGE_SETUP_TEAM"; break;
+ case ID_PAGE_SETUP : pageName = "PAGE_SETUP"; break;
+ case ID_PAGE_MULTIPLAYER : pageName = "PAGE_MULTIPLAYER"; break;
+ case ID_PAGE_DEMOS : pageName = "PAGE_DEMOS"; break;
+ case ID_PAGE_NET : pageName = "PAGE_NET"; break;
+ case ID_PAGE_NETGAME : pageName = "PAGE_NETGAME"; break;
+ case ID_PAGE_INFO : pageName = "PAGE_INFO"; break;
+ case ID_PAGE_MAIN : pageName = "PAGE_MAIN"; break;
+ case ID_PAGE_GAMESTATS : pageName = "PAGE_GAMESTATS"; break;
+ case ID_PAGE_SINGLEPLAYER : pageName = "PAGE_SINGLEPLAYER"; break;
+ case ID_PAGE_TRAINING : pageName = "PAGE_TRAINING"; break;
+ case ID_PAGE_SELECTWEAPON : pageName = "PAGE_SELECTWEAPON"; break;
+ case ID_PAGE_NETSERVER : pageName = "PAGE_NETSERVER"; break;
+ case ID_PAGE_INGAME : pageName = "PAGE_INGAME"; break;
+ case ID_PAGE_ROOMSLIST : pageName = "PAGE_ROOMSLIST"; break;
+ case ID_PAGE_CONNECTING : pageName = "PAGE_CONNECTING"; break;
+ case ID_PAGE_SCHEME : pageName = "PAGE_SCHEME"; break;
+ case ID_PAGE_ADMIN : pageName = "PAGE_ADMIN"; break;
+ case ID_PAGE_CAMPAIGN : pageName = "PAGE_CAMPAIGN"; break;
+ case ID_PAGE_DRAWMAP : pageName = "PAGE_DRAWMAP"; break;
+ case ID_PAGE_DATADOWNLOAD : pageName = "PAGE_DATADOWNLOAD"; break;
+ case ID_PAGE_VIDEOS : pageName = "PAGE_VIDEOS"; break;
+ case MAX_PAGE : pageName = "MAX_PAGE"; break;
+ default : pageName = "UNKNOWN_PAGE"; break;
+ }
+ return pageName;
+}
+
void HWForm::OnPageShown(quint8 id, quint8 lastid)
{
#ifdef USE_XFIRE
updateXfire();
#endif
+
+ qDebug("Leaving %s, entering %s", qPrintable(stringifyPageId(lastid)), qPrintable(stringifyPageId(id)));
+
+ // pageEnter and pageLeave events
+ ((AbstractPage*)ui.Pages->widget(lastid))->triggerPageLeave();
+ ((AbstractPage*)ui.Pages->widget(id))->triggerPageEnter();
+
if (id == ID_PAGE_DATADOWNLOAD)
{
ui.pageDataDownload->fetchList();
@@ -604,25 +671,11 @@
curTeamSelWidget->resetPlayingTeams(teamsList);
}
}
- else if (id == ID_PAGE_GAMESTATS)
- {
- ui.pageGameStats->renderStats();
- }
if (id == ID_PAGE_MAIN)
{
ui.pageOptions->setTeamOptionsEnabled(true);
}
-
- if (id == ID_PAGE_SETUP)
- {
- config->reloadValues();
- }
-
- if (id == ID_PAGE_VIDEOS )
- {
- config->reloadVideosValues();
- }
}
void HWForm::GoToPage(int id)
@@ -638,10 +691,11 @@
/* if (id == ID_PAGE_DRAWMAP || id == ID_PAGE_GAMESTATS)
stopAnim = true;
- This were disabled due to broken flake animations. I believe the more general problems w/ opacity that forced its disable makes blocking these
- unnecessary.
+ This were disabled due to broken flake animations. I believe the more general problems w/ opacity that forced its disable makes blocking these
+ unnecessary.
*/
+
#if (QT_VERSION >= 0x040600)
if (!stopAnim)
{
@@ -697,8 +751,8 @@
animationOldSlide->start(QAbstractAnimation::DeleteWhenStopped);
animationNewSlide->start(QAbstractAnimation::DeleteWhenStopped);
- /* this is for the situation when the animation below is interrupted by a new animation. For some reason, finished is not being fired */
- for(int i=0;iwidget(i)->hide();
+ /* this is for the situation when the animation below is interrupted by a new animation. For some reason, finished is not being fired */
+ for(int i=0;iwidget(i)->hide();
}
#endif
}
@@ -709,6 +763,7 @@
int curid = ui.Pages->currentIndex();
if (curid == ID_PAGE_MAIN)
{
+ ((AbstractPage*)ui.Pages->widget(ID_PAGE_MAIN))->triggerPageLeave();
if (!ui.pageVideos->tryQuit(this))
return;
stopAnim = true;
@@ -894,18 +949,8 @@
void HWForm::DeleteTeam(const QString & teamName)
{
- QMessageBox reallyDeleteMsg(this);
- reallyDeleteMsg.setIcon(QMessageBox::Question);
- reallyDeleteMsg.setWindowTitle(QMessageBox::tr("Teams - Are you sure?"));
- reallyDeleteMsg.setText(QMessageBox::tr("Do you really want to delete the team '%1'?").arg(teamName));
- reallyDeleteMsg.setWindowModality(Qt::WindowModal);
- reallyDeleteMsg.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
-
- if (reallyDeleteMsg.exec() == QMessageBox::Ok)
- {
- ui.pageEditTeam->deleteTeam(teamName);
- UpdateTeamsLists();
- }
+ ui.pageEditTeam->deleteTeam(teamName);
+ UpdateTeamsLists();
}
void HWForm::DeleteScheme()
@@ -913,7 +958,7 @@
ui.pageScheme->selectScheme->setCurrentIndex(ui.pageOptions->SchemesName->currentIndex());
if (ui.pageOptions->SchemesName->currentIndex() < ammoSchemeModel->numberOfDefaultSchemes)
{
- ShowErrorMessage(QMessageBox::tr("Cannot delete default scheme '%1'!").arg(ui.pageOptions->SchemesName->currentText()));
+ MessageDialog::ShowErrorMessage(QMessageBox::tr("Cannot delete default scheme '%1'!").arg(ui.pageOptions->SchemesName->currentText()), this);
}
else
{
@@ -939,7 +984,7 @@
QListWidgetItem * curritem = ui.pagePlayDemo->DemosList->currentItem();
if (!curritem)
{
- ShowErrorMessage(QMessageBox::tr("Please select a record from the list"));
+ MessageDialog::ShowErrorMessage(QMessageBox::tr("Please select a record from the list"), this);
return;
}
CreateGame(0, 0, 0);
@@ -967,37 +1012,81 @@
void HWForm::NetPassword(const QString & nick)
{
- int passLength = config->value("net/passwordlength", 0).toInt();
- QString hash = config->value("net/passwordhash", "").toString();
+ Q_UNUSED(nick);
+ //Get hashes
+ QString hash = config->passwordHash();
+ QString temphash = config->tempHash();
+
+ //Check them
- // If the password is blank, ask the user to enter one in
- if (passLength == 0)
- {
- HWPasswordDialog * hpd = new HWPasswordDialog(this, tr("Your nickname %1 is\nregistered on Hedgewars.org\nPlease provide your password below\nor pick another nickname in game config:").arg(nick));
- hpd->cbSave->setChecked(config->value("net/savepassword", true).toBool());
- if (hpd->exec() != QDialog::Accepted)
- {
- ForcedDisconnect(tr("No password supplied."));
- delete hpd;
- return;
- }
-
- QString password = hpd->lePassword->text();
- hash = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Md5).toHex();
-
- bool save = hpd->cbSave->isChecked();
- config->setValue("net/savepassword", save);
- if (save) // user wants to save password
- {
- config->setValue("net/passwordhash", hash);
- config->setValue("net/passwordlength", password.size());
- config->setNetPasswordLength(password.size());
- }
-
- delete hpd;
+ if (temphash.isEmpty() && hash.isEmpty()) { //If the user enters a registered nick with no password, sends a bogus hash
+ hwnet->SendPasswordHash("THISISNOHASH");
+ }
+ else if (temphash.isEmpty()) { //Send saved hash as default
+ hwnet->SendPasswordHash(hash);
+ }
+ else { //Send the hash
+ hwnet->SendPasswordHash(temphash);
}
- hwnet->SendPasswordHash(hash);
+ //Remove temporary hash from config
+ config->clearTempHash();
+}
+
+void HWForm::NetNickRegistered(const QString & nick)
+{
+ //Get hashes
+ QString hash = config->passwordHash();
+ QString temphash = config->tempHash();
+
+ if (hash.isEmpty()) {
+ if (temphash.isEmpty()) { //If the user enters a registered nick with no password
+ QString suppliedpass;
+ while (suppliedpass.isEmpty()) {
+ QInputDialog nickRegedDialog(this);
+ nickRegedDialog.setWindowModality(Qt::WindowModal);
+ nickRegedDialog.setInputMode(QInputDialog::TextInput);
+ nickRegedDialog.setWindowTitle(tr("Hedgewars - Nick registered"));
+ nickRegedDialog.setLabelText(tr("This nick is registered, and you haven't specified a password.\n\nIf this nick isn't yours, please register your own nick at www.hedgewars.org\n\nPassword:"));
+ nickRegedDialog.setTextEchoMode(QLineEdit::Password);
+ nickRegedDialog.exec();
+
+ suppliedpass = nickRegedDialog.textValue();
+
+ if (nickRegedDialog.result() == QDialog::Rejected) {
+ config->clearPasswordHash();
+ config->clearTempHash();
+ GoBack();
+ return;
+ }
+ temphash = QCryptographicHash::hash(suppliedpass.toUtf8(), QCryptographicHash::Md5).toHex();
+ config->setTempHash(temphash);
+ }
+ }
+ }
+ NetPassword(nick);
+}
+
+void HWForm::NetNickNotRegistered(const QString & nick)
+{
+ Q_UNUSED(nick);
+
+ QMessageBox noRegMsg(this);
+ noRegMsg.setIcon(QMessageBox::Information);
+ noRegMsg.setWindowTitle(QMessageBox::tr("Hedgewars - Nick not registered"));
+ noRegMsg.setWindowModality(Qt::WindowModal);
+ noRegMsg.setText(tr("Your nickname is not registered.\nTo prevent someone else from using it,\nplease register it at www.hedgewars.org"));
+
+ if (!config->passwordHash().isEmpty())
+ {
+ config->clearPasswordHash();
+ noRegMsg.setText(noRegMsg.text()+tr("\n\nYour password wasn't saved either."));
+ }
+ if (!config->tempHash().isEmpty())
+ {
+ config->clearTempHash();
+ }
+ noRegMsg.exec();
}
void HWForm::NetNickTaken(const QString & nick)
@@ -1007,7 +1096,12 @@
if (!ok || newNick.isEmpty())
{
- ForcedDisconnect(tr("No nickname supplied."));
+ //ForcedDisconnect(tr("No nickname supplied."));
+ bool retry = RetryDialog(tr("Hedgewars - Empty nickname"), tr("No nickname supplied."));
+ GoBack();
+ if (retry) {
+ NetConnectOfficialServer();
+ }
return;
}
@@ -1022,8 +1116,39 @@
void HWForm::NetAuthFailed()
{
// Set the password blank if case the user tries to join and enter his password again
- config->setValue("net/passwordlength", 0);
- config->setNetPasswordLength(0);
+ config->clearTempHash();
+
+ //Try to login again
+ bool retry = RetryDialog(tr("Hedgewars - Wrong password"), tr("You entered a wrong password."));
+ GoBack();
+
+ config->clearPasswordHash();
+ config->clearTempHash();
+ if (retry) {
+ NetConnectOfficialServer();
+ }
+}
+
+bool HWForm::RetryDialog(const QString & title, const QString & label)
+{
+ QMessageBox retryMsg(this);
+ retryMsg.setIcon(QMessageBox::Warning);
+ retryMsg.setWindowTitle(title);
+ retryMsg.setText(label);
+ retryMsg.setWindowModality(Qt::WindowModal);
+
+ retryMsg.addButton(QMessageBox::Cancel);
+
+ QPushButton *retryButton = retryMsg.addButton(QMessageBox::Ok);
+ retryButton->setText(tr("Try Again"));
+ retryButton->setFocus();
+
+ retryMsg.exec();
+
+ if (retryMsg.clickedButton() == retryButton) {
+ return true;
+ }
+ return false;
}
void HWForm::NetTeamAccepted(const QString & team)
@@ -1036,7 +1161,7 @@
switch (ui.Pages->currentIndex())
{
case ID_PAGE_INGAME:
- ShowErrorMessage(errmsg);
+ MessageDialog::ShowErrorMessage(errmsg, this);
// no break
case ID_PAGE_NETGAME:
ui.pageNetGame->displayError(errmsg);
@@ -1056,6 +1181,8 @@
void HWForm::_NetConnect(const QString & hostName, quint16 port, QString nick)
{
+ Q_UNUSED(nick);
+
if(hwnet)
{
hwnet->Disconnect();
@@ -1067,7 +1194,7 @@
GoToPage(ID_PAGE_CONNECTING);
- connect(hwnet, SIGNAL(AskForRunGame()), this, SLOT(CreateNetGame()));
+ connect(hwnet, SIGNAL(AskForRunGame()), this, SLOT(CreateNetGame()), Qt::QueuedConnection);
connect(hwnet, SIGNAL(connected()), this, SLOT(NetConnected()), Qt::QueuedConnection);
connect(hwnet, SIGNAL(Error(const QString&)), this, SLOT(NetError(const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(Warning(const QString&)), this, SLOT(NetWarning(const QString&)), Qt::QueuedConnection);
@@ -1076,13 +1203,14 @@
connect(hwnet, SIGNAL(AddNetTeam(const HWTeam&)), this, SLOT(AddNetTeam(const HWTeam&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(RemoveNetTeam(const HWTeam&)), this, SLOT(RemoveNetTeam(const HWTeam&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(TeamAccepted(const QString&)), this, SLOT(NetTeamAccepted(const QString&)), Qt::QueuedConnection);
- connect(hwnet, SIGNAL(AskForPassword(const QString&)), this, SLOT(NetPassword(const QString&)), Qt::QueuedConnection);
+ connect(hwnet, SIGNAL(NickRegistered(const QString&)), this, SLOT(NetNickRegistered(const QString&)), Qt::QueuedConnection);
+ connect(hwnet, SIGNAL(NickNotRegistered(const QString&)), this, SLOT(NetNickNotRegistered(const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(NickTaken(const QString&)), this, SLOT(NetNickTaken(const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(AuthFailed()), this, SLOT(NetAuthFailed()), Qt::QueuedConnection);
//connect(ui.pageNetGame->BtnBack, SIGNAL(clicked()), hwnet, SLOT(partRoom()));
ui.pageRoomsList->chatWidget->setUsersModel(hwnet->lobbyPlayersModel());
- ui.pageNetGame->pChatWidget->setUsersModel(hwnet->roomPlayersModel());
+ ui.pageNetGame->chatWidget->setUsersModel(hwnet->roomPlayersModel());
// rooms list page stuff
ui.pageRoomsList->setModel(hwnet->roomsListModel());
@@ -1106,32 +1234,37 @@
hwnet, SLOT(askRoomsList()));
// room status stuff
+// not queued because creates new signal/slot connection
connect(hwnet, SIGNAL(roomMaster(bool)),
- this, SLOT(NetGameChangeStatus(bool)), Qt::QueuedConnection);
+ this, SLOT(NetGameChangeStatus(bool)));
// net page stuff
+ connect(hwnet, SIGNAL(roomNameUpdated(const QString &)),
+ ui.pageNetGame, SLOT(setRoomName(const QString &)));
connect(hwnet, SIGNAL(chatStringFromNet(const QString&)),
- ui.pageNetGame->pChatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
+ ui.pageNetGame->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(chatStringFromMe(const QString&)),
- ui.pageNetGame->pChatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
+ ui.pageNetGame->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(roomMaster(bool)),
- ui.pageNetGame->pChatWidget, SLOT(adminAccess(bool)), Qt::QueuedConnection);
- connect(ui.pageNetGame->pChatWidget, SIGNAL(chatLine(const QString&)),
+ ui.pageNetGame->chatWidget, SLOT(adminAccess(bool)), Qt::QueuedConnection);
+ connect(ui.pageNetGame->chatWidget, SIGNAL(chatLine(const QString&)),
hwnet, SLOT(chatLineToNet(const QString&)));
connect(ui.pageNetGame->BtnGo, SIGNAL(clicked()), hwnet, SLOT(ToggleReady()));
connect(hwnet, SIGNAL(setMyReadyStatus(bool)),
ui.pageNetGame, SLOT(setReadyStatus(bool)), Qt::QueuedConnection);
// chat widget actions
- connect(ui.pageNetGame->pChatWidget, SIGNAL(kick(const QString&)),
+ connect(ui.pageNetGame->chatWidget, SIGNAL(kick(const QString&)),
hwnet, SLOT(kickPlayer(const QString&)));
- connect(ui.pageNetGame->pChatWidget, SIGNAL(ban(const QString&)),
+ connect(ui.pageNetGame->chatWidget, SIGNAL(ban(const QString&)),
hwnet, SLOT(banPlayer(const QString&)));
- connect(ui.pageNetGame->pChatWidget, SIGNAL(info(const QString&)),
+ connect(ui.pageNetGame->chatWidget, SIGNAL(info(const QString&)),
hwnet, SLOT(infoPlayer(const QString&)));
- connect(ui.pageNetGame->pChatWidget, SIGNAL(follow(const QString&)),
+ connect(ui.pageNetGame->chatWidget, SIGNAL(follow(const QString&)),
hwnet, SLOT(followPlayer(const QString&)));
+ connect(ui.pageNetGame->chatWidget, SIGNAL(consoleCommand(const QString&)),
+ hwnet, SLOT(consoleCommand(const QString&)));
connect(ui.pageRoomsList->chatWidget, SIGNAL(kick(const QString&)),
hwnet, SLOT(kickPlayer(const QString&)));
connect(ui.pageRoomsList->chatWidget, SIGNAL(ban(const QString&)),
@@ -1140,6 +1273,8 @@
hwnet, SLOT(infoPlayer(const QString&)));
connect(ui.pageRoomsList->chatWidget, SIGNAL(follow(const QString&)),
hwnet, SLOT(followPlayer(const QString&)));
+ connect(ui.pageRoomsList->chatWidget, SIGNAL(consoleCommand(const QString&)),
+ hwnet, SLOT(consoleCommand(const QString&)));
// chatting
connect(ui.pageRoomsList->chatWidget, SIGNAL(chatLine(const QString&)),
@@ -1147,15 +1282,15 @@
connect(hwnet, SIGNAL(chatStringLobby(const QString&)),
ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(chatStringLobby(const QString&, const QString&)),
- ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&, const QString&)));
+ ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&, const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(chatStringFromMeLobby(const QString&)),
ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
// nick list stuff
connect(hwnet, SIGNAL(nickAdded(const QString&, bool)),
- ui.pageNetGame->pChatWidget, SLOT(nickAdded(const QString&, bool)), Qt::QueuedConnection);
+ ui.pageNetGame->chatWidget, SLOT(nickAdded(const QString&, bool)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(nickRemoved(const QString&)),
- ui.pageNetGame->pChatWidget, SLOT(nickRemoved(const QString&)), Qt::QueuedConnection);
+ ui.pageNetGame->chatWidget, SLOT(nickRemoved(const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(nickAddedLobby(const QString&, bool)),
ui.pageRoomsList->chatWidget, SLOT(nickAdded(const QString&, bool)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(nickRemovedLobby(const QString&)),
@@ -1178,11 +1313,16 @@
connect(hwnet, SIGNAL(serverMessageNew(const QString&)), ui.pageAdmin, SLOT(serverMessageNew(const QString &)));
connect(hwnet, SIGNAL(serverMessageOld(const QString&)), ui.pageAdmin, SLOT(serverMessageOld(const QString &)));
connect(hwnet, SIGNAL(latestProtocolVar(int)), ui.pageAdmin, SLOT(protocol(int)));
+ connect(hwnet, SIGNAL(bansList(const QStringList &)), ui.pageAdmin, SLOT(setBansList(const QStringList &)));
connect(ui.pageAdmin, SIGNAL(setServerMessageNew(const QString&)), hwnet, SLOT(setServerMessageNew(const QString &)));
connect(ui.pageAdmin, SIGNAL(setServerMessageOld(const QString&)), hwnet, SLOT(setServerMessageOld(const QString &)));
connect(ui.pageAdmin, SIGNAL(setProtocol(int)), hwnet, SLOT(setLatestProtocolVar(int)));
connect(ui.pageAdmin, SIGNAL(askServerVars()), hwnet, SLOT(askServerVars()));
connect(ui.pageAdmin, SIGNAL(clearAccountsCache()), hwnet, SLOT(clearAccountsCache()));
+ connect(ui.pageAdmin, SIGNAL(bansListRequest()), hwnet, SLOT(getBanList()));
+ connect(ui.pageAdmin, SIGNAL(removeBan(QString)), hwnet, SLOT(removeBan(QString)));
+ connect(ui.pageAdmin, SIGNAL(banIP(QString,QString,int)), hwnet, SLOT(banIP(QString,QString,int)));
+ connect(ui.pageAdmin, SIGNAL(banNick(QString,QString,int)), hwnet, SLOT(banNick(QString,QString,int)));
// disconnect
connect(hwnet, SIGNAL(disconnected(const QString&)), this, SLOT(ForcedDisconnect(const QString&)), Qt::QueuedConnection);
@@ -1192,23 +1332,99 @@
connect(ui.pageNetGame->pGameCFG, SIGNAL(paramChanged(const QString &, const QStringList &)), hwnet, SLOT(onParamChanged(const QString &, const QStringList &)));
connect(hwnet, SIGNAL(configAsked()), ui.pageNetGame->pGameCFG, SLOT(fullNetConfig()));
- while (nick.isEmpty())
+//nick and pass stuff
+
+ //remove temppasswordhash just in case
+ config->clearTempHash();
+
+ //initialize
+ QString hash = config->passwordHash();
+ QString temphash = config->tempHash();
+ QString nickname = config->value("net/nick", "").toString();
+ QString password;
+
+ //if something from login is missing, start dialog loop
+ if (nickname.isEmpty() || hash.isEmpty())
{
- nick = QInputDialog::getText(this,
- QObject::tr("Nickname"),
- QObject::tr("Please enter your nickname"),
- QLineEdit::Normal,
- QDir::home().dirName());
- config->setValue("net/nick",nick);
- config->updNetNick();
+ while (nickname.isEmpty() || (hash.isEmpty() && temphash.isEmpty())) //while a nickname, or both hashes are missing
+ {
+ //open dialog
+ HWPasswordDialog * pwDialog = new HWPasswordDialog(this);
+ // make the "new account" button dialog open a browser with the registration page
+ connect(pwDialog->pbNewAccount, SIGNAL(clicked()), this, SLOT(openRegistrationPage()));
+ pwDialog->cbSave->setChecked(config->value("net/savepassword", true).toBool());
+
+ //if nickname is present, put it into the field
+ if (!nickname.isEmpty()) {
+ pwDialog->leNickname->setText(nickname);
+ pwDialog->lePassword->setFocus();
+ }
+
+ //if dialog close, create an error message
+ if (pwDialog->exec() != QDialog::Accepted) {
+ delete pwDialog;
+ GoBack();
+ return;
+ }
+
+ //set nick and pass from the dialog
+ nickname = pwDialog->leNickname->text();
+ password = pwDialog->lePassword->text();
+
+ //check the nickname variable
+ if (nickname.isEmpty()) {
+ int retry = RetryDialog(tr("Hedgewars - Empty nickname"), tr("No nickname supplied."));
+ GoBack();
+ delete pwDialog;
+ if (retry) {
+ NetConnectOfficialServer();
+ }
+ return;
+ }
+
+ if (!password.isEmpty()) {
+ //calculate temphash and set it into config
+ temphash = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Md5).toHex();
+ config->setTempHash(temphash);
+
+ //if user wants to save password
+ bool save = pwDialog->cbSave->isChecked();
+ config->setValue("net/savepassword", save);
+ if (save) // user wants to save password
+ {
+ ui.pageOptions->CBSavePassword->setChecked(true);
+ config->setPasswordHash(temphash);
+ }
+ }
+ else {
+ delete pwDialog;
+ config->setValue("net/nick", nickname);
+ config->updNetNick();
+ config->clearPasswordHash();
+ break;
+ }
+
+ delete pwDialog;
+
+ //update nickname
+ config->setValue("net/nick", nickname);
+ config->updNetNick();
+
+ //and all the variables
+ hash = config->passwordHash();
+ temphash = config->tempHash();
+ nickname = config->value("net/nick", "").toString();
+ }
}
- ui.pageRoomsList->setUser(nick);
- ui.pageNetGame->setUser(nick);
+ ui.pageRoomsList->setUser(nickname);
+ ui.pageNetGame->setUser(nickname);
- hwnet->Connect(hostName, port, nick);
+ hwnet->Connect(hostName, port, nickname);
}
+
+
void HWForm::NetConnect()
{
HWHostPortDialog * hpd = new HWHostPortDialog(this);
@@ -1233,7 +1449,7 @@
pnetserver = new HWNetServer;
if (!pnetserver->StartServer(ui.pageNetServer->sbPort->value()))
{
- ShowErrorMessage(QMessageBox::tr("Unable to start server"));
+ MessageDialog::ShowErrorMessage(QMessageBox::tr("Unable to start server"), this);
delete pnetserver;
pnetserver = 0;
@@ -1273,16 +1489,29 @@
void HWForm::ForcedDisconnect(const QString & reason)
{
+ if (reason == "Reconnected too fast") { //TODO: this is a hack, which should be remade
+ bool retry = RetryDialog(tr("Hedgewars - Connection error"), tr("You reconnected too fast.\nPlease wait a few seconds and try again."));
+ if (retry) {
+ NetConnectOfficialServer();
+ }
+ else {
+ while (ui.Pages->currentIndex() != ID_PAGE_NET
+ && ui.Pages->currentIndex() != ID_PAGE_MAIN)
+ {
+ GoBack();
+ }
+ }
+ return;
+ }
if (pnetserver)
return; // we have server - let it care of all things
if (hwnet)
{
QString errorStr = QMessageBox::tr("Connection to server is lost") + (reason.isEmpty()?"":("\n\n" + HWNewNet::tr("Quit reason: ") + '"' + reason +'"'));
- ShowErrorMessage(errorStr);
+ MessageDialog::ShowErrorMessage(errorStr, this);
}
while (ui.Pages->currentIndex() != ID_PAGE_NET
- && ui.Pages->currentIndex() != ID_PAGE_NETTYPE
&& ui.Pages->currentIndex() != ID_PAGE_MAIN)
{
GoBack();
@@ -1296,7 +1525,7 @@
void HWForm::NetGameEnter()
{
- ui.pageNetGame->pChatWidget->clear();
+ ui.pageNetGame->chatWidget->clear();
GoToPage(ID_PAGE_NETGAME);
}
@@ -1347,7 +1576,7 @@
//setVisible(true);
setFocusPolicy(Qt::StrongFocus);
if (id == ID_PAGE_INGAME) GoBack();
- Music(ui.pageOptions->CBEnableFrontendMusic->isChecked());
+ Music(ui.pageOptions->CBFrontendMusic->isChecked());
if (wBackground) wBackground->startAnimation();
GoToPage(ID_PAGE_GAMESTATS);
if (hwnet && (!game || !game->netSuspend)) hwnet->gameFinished(true);
@@ -1365,7 +1594,7 @@
(gameState == gsInterrupted || gameState == gsStopped || gameState == gsDestroyed || gameState == gsHalted)))
{
if (id == ID_PAGE_INGAME) GoBack();
- Music(ui.pageOptions->CBEnableFrontendMusic->isChecked());
+ Music(ui.pageOptions->CBFrontendMusic->isChecked());
if (wBackground) wBackground->startAnimation();
if (hwnet) hwnet->gameFinished(false);
}
@@ -1385,16 +1614,6 @@
m_lastDemo = QByteArray();
}
-void HWForm::ShowErrorMessage(const QString & msg)
-{
- QMessageBox msgMsg(this);
- msgMsg.setIcon(QMessageBox::Warning);
- msgMsg.setWindowTitle(QMessageBox::tr("Hedgewars - Error"));
- msgMsg.setText(msg);
- msgMsg.setWindowModality(Qt::WindowModal);
- msgMsg.exec();
-}
-
void HWForm::GetRecord(RecordType type, const QByteArray & record)
{
if (type != rtNeither)
@@ -1427,7 +1646,7 @@
QFile demofile(filename);
if (!demofile.open(QIODevice::WriteOnly))
- ShowErrorMessage(tr("Cannot save record to file %1").arg(filename));
+ MessageDialog::ShowErrorMessage(tr("Cannot save record to file %1").arg(filename), this);
else
{
demofile.write(demo);
@@ -1482,7 +1701,9 @@
xfire_free();
#endif
config->SaveOptions();
+#if VIDEOREC
config->SaveVideosOptions();
+#endif
event->accept();
}
@@ -1496,7 +1717,7 @@
void HWForm::NetGameChangeStatus(bool isMaster)
{
- ui.pageNetGame->pGameCFG->setEnabled(isMaster);
+ ui.pageNetGame->pGameCFG->setMaster(isMaster);
ui.pageNetGame->pNetTeamsWidget->setInteractivity(isMaster);
if (isMaster)
@@ -1511,21 +1732,22 @@
ui.pageNetGame->restrictJoins->setChecked(false);
ui.pageNetGame->restrictTeamAdds->setChecked(false);
ui.pageNetGame->pGameCFG->GameSchemes->setModel(ammoSchemeModel);
- ui.pageNetGame->pGameCFG->setEnabled(true);
+ ui.pageNetGame->pGameCFG->setMaster(true);
ui.pageNetGame->pNetTeamsWidget->setInteractivity(true);
if (hwnet)
{
// disconnect connections first to ensure their inexistance and not to connect twice
- ui.pageNetGame->BtnStart->disconnect(hwnet);
+ ui.pageNetGame->BtnStart->disconnect(this);
ui.pageNetGame->BtnUpdate->disconnect(hwnet);
+ ui.pageNetGame->leRoomName->disconnect(hwnet);
ui.pageNetGame->restrictJoins->disconnect(hwnet);
ui.pageNetGame->restrictTeamAdds->disconnect(hwnet);
ui.pageNetGame->disconnect(hwnet, SLOT(updateRoomName(const QString&)));
ui.pageNetGame->setRoomName(hwnet->getRoom());
- connect(ui.pageNetGame->BtnStart, SIGNAL(clicked()), hwnet, SLOT(startGame()));
+ connect(ui.pageNetGame->BtnStart, SIGNAL(clicked()), this, SLOT(startGame()));
connect(ui.pageNetGame, SIGNAL(askForUpdateRoomName(const QString &)), hwnet, SLOT(updateRoomName(const QString &)));
connect(ui.pageNetGame->restrictJoins, SIGNAL(triggered()), hwnet, SLOT(toggleRestrictJoins()));
connect(ui.pageNetGame->restrictTeamAdds, SIGNAL(triggered()), hwnet, SLOT(toggleRestrictTeamAdds()));
@@ -1539,7 +1761,7 @@
void HWForm::NetGameSlave()
{
- ui.pageNetGame->pGameCFG->setEnabled(false);
+ ui.pageNetGame->pGameCFG->setMaster(false);
ui.pageNetGame->pNetTeamsWidget->setInteractivity(false);
if (hwnet)
@@ -1548,6 +1770,8 @@
connect(hwnet, SIGNAL(netSchemeConfig(QStringList &)), netAmmo, SLOT(setNetSchemeConfig(QStringList &)));
ui.pageNetGame->pGameCFG->GameSchemes->setModel(netAmmo);
+ ui.pageNetGame->setRoomName(hwnet->getRoom());
+
ui.pageNetGame->pGameCFG->GameSchemes->view()->disconnect(hwnet);
connect(hwnet, SIGNAL(netSchemeConfig(QStringList &)),
this, SLOT(selectFirstNetScheme()));
@@ -1634,19 +1858,30 @@
// used for --set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]
QString HWForm::getDemoArguments()
{
- QRect resolution = config->vid_Resolution();
- return QString(QString::number(resolution.width()) + " "
- + QString::number(resolution.height()) + " "
- + QString::number(config->bitDepth()) + " " // bpp
- + QString::number(config->volume()) + " " // sound volume
- + (config->isMusicEnabled() ? "1" : "0") + " "
- + (config->isSoundEnabled() ? "1" : "0") + " "
- + config->language() + ".txt "
- + (config->vid_Fullscreen() ? "1" : "0") + " "
- + (config->isShowFPSEnabled() ? "1" : "0") + " "
- + (config->isAltDamageEnabled() ? "1" : "0") + " "
- + QString::number(config->timerInterval()) + " "
- + QString::number(config->translateQuality()));
+
+ QString prefix = datadir->absolutePath();
+ QString userPrefix = cfgdir->absolutePath();
+#ifdef Q_WS_WIN
+ prefix = prefix.replace("/","\\");
+ userPrefix = userPrefix.replace("/","\\");
+#endif
+
+ std::pair resolutions = config->vid_ResolutionPair();
+ return QString("--prefix " + prefix
+ + " --user-prefix " + userPrefix
+ + " --fullscreen-width " + QString::number(resolutions.first.width())
+ + " --fullscreen-height " + QString::number(resolutions.first.height())
+ + " --width " + QString::number(resolutions.second.width())
+ + " --height " + QString::number(resolutions.second.height())
+ + " --volume " + QString::number(config->volume())
+ + (config->isMusicEnabled() ? "" : " --nomusic")
+ + (config->isSoundEnabled() ? "" : " --nosound")
+ + " --locale " + config->language() + ".txt"
+ + (config->vid_Fullscreen() ? " --fullscreen" : "")
+ + (config->isShowFPSEnabled() ? " --showfps" : "")
+ + (config->isAltDamageEnabled() ? " --altdmg" : "")
+ + " --frame-interval " + QString::number(config->timerInterval())
+ + " --raw-quality " + QString::number(config->translateQuality()));
}
void HWForm::AssociateFiles()
@@ -1661,8 +1896,8 @@
registry_hkcr.setValue("Hedgewars.Save/Default", tr("Hedgewars Save File", "File Types"));
registry_hkcr.setValue("Hedgewars.Demo/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwdfile.ico\",0");
registry_hkcr.setValue("Hedgewars.Save/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwsfile.ico\",0");
- registry_hkcr.setValue("Hedgewars.Demo/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"" + cfgdir->absolutePath().replace("/","\\") + "\" \"" + datadir->absolutePath().replace("/", "\\") + "\" \"%1\" --set-everything "+arguments);
- registry_hkcr.setValue("Hedgewars.Save/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"" + cfgdir->absolutePath().replace("/","\\") + "\" \"" + datadir->absolutePath().replace("/", "\\") + "\" \"%1\" --set-everything "+arguments);
+ registry_hkcr.setValue("Hedgewars.Demo/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"%1\" "+arguments);
+ registry_hkcr.setValue("Hedgewars.Save/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"%1\" "+arguments);
#elif defined __APPLE__
// only useful when other apps have taken precedence over our file extensions and you want to reset it
system("defaults write com.apple.LaunchServices LSHandlers -array-add 'LSHandlerContentTaghwdLSHandlerContentTagClasspublic.filename-extensionLSHandlerRoleAllorg.hedgewars.desktop'");
@@ -1683,7 +1918,7 @@
if (success) success = system("xdg-mime default hwengine.desktop application/x-hedgewars-demo")==0;
if (success) success = system("xdg-mime default hwengine.desktop application/x-hedgewars-save")==0;
// hack to add user's settings to hwengine. might be better at this point to read in the file, append it, and write it out to its new home. This assumes no spaces in the data dir path
- if (success) success = system(("sed -i 's/^\\(Exec=.*\\) \\([^ ]* %f\\)/\\1 "+cfgdir->absolutePath().replace(" ","\\\\ ").replace("/","\\/")+" \\2 --set-everything "+arguments+"/' "+QDir::home().absolutePath()+"/.local/share/applications/hwengine.desktop").toLocal8Bit().constData())==0;
+ if (success) success = system(("sed -i 's/^\\(Exec=.*\\) \\([^ ]* %f\\)/\\1 \\2 "+arguments+"/' "+QDir::home().absolutePath()+"/.local/share/applications/hwengine.desktop").toLocal8Bit().constData())==0;
#endif
if (success)
{
@@ -1695,7 +1930,12 @@
infoMsg.exec();
}
else
- ShowErrorMessage(QMessageBox::tr("File association failed."));
+ MessageDialog::ShowErrorMessage(QMessageBox::tr("File association failed."), this);
+}
+
+void HWForm::openRegistrationPage()
+{
+ QDesktopServices::openUrl(QUrl("http://www.hedgewars.org/user/register"));
}
void HWForm::saveDemoWithCustomName()
@@ -1714,7 +1954,7 @@
QFile demofile(filePath);
ok = demofile.open(QIODevice::WriteOnly);
if (!ok)
- ShowErrorMessage(tr("Cannot save record to file %1").arg(filePath));
+ MessageDialog::ShowErrorMessage(tr("Cannot save record to file %1").arg(filePath), this);
else
{
ok = -1 != demofile.write(m_lastDemo);
@@ -1726,107 +1966,28 @@
}
}
-void HWForm::SendFeedback()
+
+void HWForm::ShowErrorMessage(const QString & msg)
{
- //Create Xml representation of google code issue first
- if (!CreateIssueXml())
- {
- ShowErrorMessage(QMessageBox::tr("Please fill out all fields"));
- return;
- }
-
- //Google login using fake account (feedback.hedgewars@gmail.com)
- nam = new QNetworkAccessManager(this);
- connect(nam, SIGNAL(finished(QNetworkReply*)),
- this, SLOT(finishedSlot(QNetworkReply*)));
-
- QUrl url(QString("https://www.google.com/accounts/ClientLogin?"
- "accountType=GOOGLE&Email=feedback.hedgewars@gmail.com&Passwd=hwfeedback&service=code&source=HedgewarsFoundation-Hedgewars-")
- + (cVersionString?(*cVersionString):QString("")));
- nam->get(QNetworkRequest(url));
-
+ MessageDialog::ShowErrorMessage(msg, this);
}
-bool HWForm::CreateIssueXml()
+void HWForm::showFeedbackDialog()
{
- QString summary = ui.pageFeedback->summary->text();
- QString description = ui.pageFeedback->description->toPlainText();
-
- //Check if all necessary information is entered
- if (summary.isEmpty() || description.isEmpty())
- return false;
-
- issueXml =
- ""
- ""
- "";
- issueXml.append(summary);
- issueXml.append("");
- issueXml.append(description);
- issueXml.append("feedback.hedgewars");
-
- return true;
+ FeedbackDialog dialog(this);
+ dialog.exec();
}
-void HWForm::finishedSlot(QNetworkReply* reply)
+void HWForm::startGame()
{
- if (reply && reply->error() == QNetworkReply::NoError)
- {
- QByteArray array = reply->readAll();
- QString str(array);
-
- if (authToken.length() != 0)
- {
-
- QMessageBox infoMsg(this);
- infoMsg.setIcon(QMessageBox::Information);
- infoMsg.setWindowTitle(QMessageBox::tr("Hedgewars - Success"));
- infoMsg.setText(QMessageBox::tr("Successfully posted the issue on hedgewars.googlecode.com"));
- infoMsg.setWindowModality(Qt::WindowModal);
- infoMsg.exec();
-
- ui.pageFeedback->summary->clear();
- ui.pageFeedback->description->clear();
- authToken = "";
- return;
- }
-
- if (!getAuthToken(str))
- {
- ShowErrorMessage(QMessageBox::tr("Error during authentication at google.com"));
- return;
- }
+ QMessageBox questionMsg(this);
+ questionMsg.setIcon(QMessageBox::Question);
+ questionMsg.setWindowTitle(QMessageBox::tr("Not all players are ready"));
+ questionMsg.setText(QMessageBox::tr("Are you sure you want to start this game?\nNot all players are ready."));
+ questionMsg.setWindowModality(Qt::WindowModal);
+ questionMsg.addButton(QMessageBox::Yes);
+ questionMsg.addButton(QMessageBox::Cancel);
- QByteArray body(issueXml.toUtf8());
- QNetworkRequest header(QUrl("https://code.google.com/feeds/issues/p/hedgewars/issues/full"));
- header.setRawHeader("Content-Length", QString::number(issueXml.length()).toAscii());
- header.setRawHeader("Content-Type", "application/atom+xml");
- header.setRawHeader("Authorization", QString("GoogleLogin auth=%1").arg(authToken).toUtf8());
- nam->post(header, body);
-
- }
- else if (authToken.length() == 0)
- ShowErrorMessage(QMessageBox::tr("Error during authentication at google.com"));
- else
- {
- ShowErrorMessage(QMessageBox::tr("Error reporting the issue, please try again later (or visit hedgewars.googlecode.com directly)"));
- authToken = "";
- }
-
+ if (hwnet->allPlayersReady() || questionMsg.exec() == QMessageBox::Yes)
+ hwnet->startGame();
}
-
-bool HWForm::getAuthToken(QString str)
-{
- QRegExp ex("Auth=(.+)");
-
- if (-1 == ex.indexIn(str))
- return false;
-
- authToken = ex.cap(1);
- authToken.remove(QChar('\n'));
-
- return true;
-}
-
-
-
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/hwform.h
--- a/QTfrontend/hwform.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/hwform.h Fri Feb 22 05:05:32 2013 +0100
@@ -61,7 +61,6 @@
HWForm(QWidget *parent = 0, QString styleSheet = "");
Ui_HWForm ui;
static GameUIConfig * config;
- static QSettings * gameSettings; // Same file GameUIConfig points to but without the baggage. Needs sync() calls if you want to get GameUIConfig changes though
void updateXfire();
void PlayDemoQuick(const QString & demofilename);
void exit();
@@ -106,8 +105,11 @@
void NetWarning(const QString & wrnmsg);
void NetGameEnter();
void NetPassword(const QString & nick);
+ void NetNickRegistered(const QString & nick);
+ void NetNickNotRegistered(const QString & nick);
void NetNickTaken(const QString & nick);
void NetAuthFailed();
+ bool RetryDialog(const QString & title, const QString & label);
void NetTeamAccepted(const QString& team);
void AddNetTeam(const HWTeam& team);
void RemoveNetTeam(const HWTeam& team);
@@ -124,15 +126,7 @@
void UpdateCampaignPage(int index);
void UpdateCampaignPageProgress(int index);
void InitCampaignPage();
- //Starts the transmission process for the feedback
- void SendFeedback();
- //Make a xml representation of the issue to be created
- bool CreateIssueXml();
- //Called the first time when receiving authorization token from google,
- //second time when receiving the response after posting the issue
- void finishedSlot(QNetworkReply* reply);
- //Filter the auth token from the reply from google
- bool getAuthToken(QString str);
+ void showFeedbackDialog();
void NetGameChangeStatus(bool isMaster);
void NetGameMaster();
@@ -143,14 +137,18 @@
void selectFirstNetScheme();
void saveDemoWithCustomName();
+ void openRegistrationPage();
+
+ void startGame();
private:
void _NetConnect(const QString & hostName, quint16 port, QString nick);
- void UpdateTeamsLists(const QStringList* editable_teams=0);
+ void UpdateTeamsLists();
void CreateGame(GameCFGWidget * gamecfg, TeamSelWidget* pTeamSelWidget, QString ammo);
void closeEvent(QCloseEvent *event);
void CustomizePalettes();
void resizeEvent(QResizeEvent * event);
+ QString stringifyPageId(quint32 id);
//void keyReleaseEvent(QKeyEvent *event);
enum PageIDs
@@ -173,13 +171,11 @@
ID_PAGE_CONNECTING ,
ID_PAGE_SCHEME ,
ID_PAGE_ADMIN ,
- ID_PAGE_NETTYPE ,
ID_PAGE_CAMPAIGN ,
ID_PAGE_DRAWMAP ,
ID_PAGE_DATADOWNLOAD ,
- ID_PAGE_FEEDBACK ,
- ID_PAGE_VIDEOS,
- MAX_PAGE
+ ID_PAGE_VIDEOS ,
+ MAX_PAGE
};
QPointer game;
QPointer pnetserver;
@@ -193,9 +189,6 @@
BGWidget * wBackground;
QSignalMapper * pageSwitchMapper;
QByteArray m_lastDemo;
- QNetworkAccessManager * nam;
- QString issueXml;
- QString authToken;
QPropertyAnimation *animationNewSlide;
QPropertyAnimation *animationOldSlide;
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/main.cpp
--- a/QTfrontend/main.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/main.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -27,6 +27,8 @@
#include
#include
#include
+#include
+#include
#include "hwform.h"
#include "hwconsts.h"
@@ -37,11 +39,18 @@
#ifdef _WIN32
#include
-#endif
-#ifdef __APPLE__
+#elif defined __APPLE__
#include "CocoaInitializer.h"
#endif
+#ifndef _WIN32
+#include
+#endif
+// Program resources
+#ifdef __APPLE__
+static CocoaInitializer * cocoaInit = NULL;
+#endif
+static FileEngineHandler * engine = NULL;
//Determines the day of easter in year
//from http://aa.usno.navy.mil/faq/docs/easter.php,adapted to C/C++
@@ -85,12 +94,20 @@
else
season = SEASON_NONE;
}
+#ifndef _WIN32
+void terminateFrontend(int signal)
+{
+ Q_UNUSED(signal);
+
+ QCoreApplication::exit(0);
+}
+#endif
bool checkForDir(const QString & dir)
{
- QDir tmpdir;
- if (!tmpdir.exists(dir))
- if (!tmpdir.mkdir(dir))
+ QDir tmpdir(dir);
+ if (!tmpdir.exists())
+ if (!tmpdir.mkpath(dir))
{
QMessageBox directoryMsg(QApplication::activeWindow());
directoryMsg.setIcon(QMessageBox::Warning);
@@ -103,11 +120,53 @@
return true;
}
+// Guaranteed to be the last thing ran in the application's life time.
+// Closes resources that need to exist as long as possible.
+void closeResources(void)
+{
+#ifdef __APPLE__
+ if (cocoaInit != NULL)
+ {
+ delete cocoaInit;
+ cocoaInit = NULL;
+ }
+#endif
+ if (engine != NULL)
+ {
+ delete engine;
+ engine = NULL;
+ }
+}
+
int main(int argc, char *argv[])
{
+ // Since we're calling this first, closeResources() will be the last thing called after main() returns.
+ atexit(closeResources);
+
+#ifdef __APPLE__
+ cocoaInit = new CocoaInitializer(); // Creates the autoreleasepool preventing cocoa object leaks on OS X.
+#endif
+
+#ifndef _WIN32
+ signal(SIGINT, &terminateFrontend);
+#endif
+
HWApplication app(argc, argv);
- FileEngineHandler engine(argv[0]);
+ QLabel *splash = NULL;
+#if defined Q_WS_WIN
+ QPixmap pixmap(":res/splash.png");
+ splash = new QLabel(0, Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
+ splash->setAttribute(Qt::WA_TranslucentBackground);
+ const QRect deskSize = QApplication::desktop()->screenGeometry(-1);
+ QPoint splashCenter = QPoint( (deskSize.width() - pixmap.width())/2,
+ (deskSize.height() - pixmap.height())/2 );
+ splash->move(splashCenter);
+ splash->setPixmap(pixmap);
+ splash->show();
+#endif
+
+ engine = new FileEngineHandler(argv[0]);
app.setAttribute(Qt::AA_DontShowIconsInMenus,false);
@@ -146,9 +205,14 @@
if(parsedArgs.contains("config-dir"))
{
QFileInfo f(parsedArgs["config-dir"]);
- *cConfigDir = f.absoluteFilePath();
+ cfgdir->setPath(f.absoluteFilePath());
custom_config = true;
}
+ else
+ {
+ cfgdir->setPath(QDir::homePath());
+ custom_config = false;
+ }
app.setStyle(new QPlastiqueStyle());
@@ -160,14 +224,9 @@
qRegisterMetaType("HWTeam");
- bindir->cd("bin"); // workaround over NSIS installer
+ bindir->cd(QCoreApplication::applicationDirPath());
- if(cConfigDir->length() == 0)
- cfgdir->setPath(cfgdir->homePath());
- else
- cfgdir->setPath(*cConfigDir);
-
- if(cConfigDir->length() == 0)
+ if(custom_config == false)
{
#ifdef __APPLE__
checkForDir(cfgdir->absolutePath() + "/Library/Application Support/Hedgewars");
@@ -208,29 +267,31 @@
datadir->cd(bindir->absolutePath());
datadir->cd(*cDataDir);
- if(!datadir->cd("hedgewars/Data"))
+ if(!datadir->cd("Data"))
{
QMessageBox missingMsg(QApplication::activeWindow());
missingMsg.setIcon(QMessageBox::Critical);
missingMsg.setWindowTitle(QMessageBox::tr("Main - Error"));
missingMsg.setText(QMessageBox::tr("Failed to open data directory:\n%1\n\n"
"Please check your installation!").
- arg(datadir->absolutePath()+"/hedgewars/Data"));
+ arg(datadir->absolutePath()+"/Data"));
missingMsg.setWindowModality(Qt::WindowModal);
missingMsg.exec();
return 1;
}
// setup PhysFS
- engine.mount(datadir->absolutePath());
- engine.mount(cfgdir->absolutePath() + "/Data");
- engine.mount(cfgdir->absolutePath(), "/config");
- engine.setWriteDir(cfgdir->absolutePath());
- engine.mountPacks();
+ engine->mount(datadir->absolutePath());
+ engine->mount(cfgdir->absolutePath() + "/Data");
+ engine->mount(cfgdir->absolutePath());
+ engine->setWriteDir(cfgdir->absolutePath());
+ engine->mountPacks();
+
+ DataManager::ensureFileExists("physfs://hedgewars.ini");
QTranslator Translator;
{
- QSettings settings("physfs://config/hedgewars.ini", QSettings::IniFormat);
+ QSettings settings("physfs://hedgewars.ini", QSettings::IniFormat);
QString cc = settings.value("misc/locale", QString()).toString();
if(cc.isEmpty())
cc = QLocale::system().name();
@@ -250,10 +311,6 @@
registry_hklm.setValue("Software/Hedgewars/Path", bindir->absolutePath().replace("/", "\\"));
}
#endif
-#ifdef __APPLE__
- // this creates the autoreleasepool that prevents leaking
- CocoaInitializer initializer;
-#endif
QString style = "";
QString fname;
@@ -276,6 +333,7 @@
break;
default :
fname = "qt.css";
+ break;
}
// load external stylesheet if there is any
@@ -290,5 +348,7 @@
app.form = new HWForm(NULL, style);
app.form->show();
+ if(splash)
+ splash->close();
return app.exec();
}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/model/GameStyleModel.cpp
--- a/QTfrontend/model/GameStyleModel.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/model/GameStyleModel.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -23,14 +23,15 @@
#include
+#include "physfs.h"
#include "GameStyleModel.h"
+#include "hwconsts.h"
void GameStyleModel::loadGameStyles()
{
beginResetModel();
-
// empty list, so that we can (re)fill it
QStandardItemModel::clear();
@@ -77,11 +78,16 @@
weapons.replace("_", " ");
}
- QStandardItem * item = new QStandardItem(name);
+ // detect if script is dlc
+ QString scriptPath = PHYSFS_getRealDir(QString("Scripts/Multiplayer/%1.lua").arg(script).toLocal8Bit().data());
+ bool isDLC = !scriptPath.startsWith(datadir->absolutePath());
+
+ QStandardItem * item = new QStandardItem((isDLC ? "*" : "") + name);
item->setData(script, ScriptRole);
item->setData(scheme, SchemeRole);
item->setData(weapons, WeaponsRole);
+ item->setData(isDLC, IsDlcRole);
items.append(item);
}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/model/GameStyleModel.h
--- a/QTfrontend/model/GameStyleModel.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/model/GameStyleModel.h Fri Feb 22 05:05:32 2013 +0100
@@ -38,7 +38,7 @@
Q_OBJECT
public:
- enum DataRoles { ScriptRole = Qt::UserRole+1, SchemeRole, WeaponsRole };
+ enum DataRoles { ScriptRole = Qt::UserRole+1, SchemeRole, WeaponsRole, IsDlcRole };
public slots:
/// reloads the themes from the DataManager
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/model/HatModel.cpp
--- a/QTfrontend/model/HatModel.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/model/HatModel.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -26,26 +26,28 @@
#include
#include
#include
+#include
#include "hwform.h" // player hash
#include "DataManager.h"
HatModel::HatModel(QObject* parent) :
- QAbstractListModel(parent)
-{
- hats = QVector >();
-}
+ QStandardItemModel(parent)
+{}
void HatModel::loadHats()
{
// this method resets the contents of this model (important to know for views).
- beginResetModel();
+ QStandardItemModel::beginResetModel();
+ QStandardItemModel::clear();
- // prepare hats Vector
- hats.clear();
+ // New hats to add to model
+ QList hats;
+ // we'll need the DataManager a few times, so let's get a reference to it
DataManager & dataMgr = DataManager::instance();
+ // Default hat icon
QPixmap hhpix = QPixmap("physfs://Graphics/Hedgehog/Idle.png").copy(0, 0, 32, 32);
// my reserved hats
@@ -54,7 +56,6 @@
QDir::Files,
QStringList(playerHash+"*.png")
);
-
int nReserved = hatsList.size();
// regular hats
@@ -64,19 +65,20 @@
QStringList("*.png")
)
);
-
-
int nHats = hatsList.size();
+ // Add each hat
for (int i = 0; i < nHats; i++)
{
bool isReserved = (i < nReserved);
+ if (isReserved) continue; // For some reason, reserved hats were added in 9.19-dev, so this will hide them. Uncomment to show them.
+
QString str = hatsList.at(i);
str = str.remove(QRegExp("\\.png$"));
- QPixmap pix(
+ QPixmap pix(
"physfs://Graphics/Hats/" + QString(isReserved?"Reserved/":"") + str +
- ".png"
+ ".png"
);
// rename properly
@@ -94,51 +96,11 @@
painter.end();
if (str == "NoHat")
- hats.prepend(qMakePair(str, QIcon(tmppix)));
+ hats.prepend(new QStandardItem(QIcon(tmppix), str));
else
- hats.append(qMakePair(str, QIcon(tmppix)));
+ hats.append(new QStandardItem(QIcon(tmppix), str));
}
-
- endResetModel();
-}
-
-QVariant HatModel::headerData(int section,
- Qt::Orientation orientation, int role) const
-{
- Q_UNUSED(section);
- Q_UNUSED(orientation);
- Q_UNUSED(role);
-
- return QVariant();
-}
-
-int HatModel::rowCount(const QModelIndex &parent) const
-{
- if (parent.isValid())
- return 0;
- else
- return hats.size();
+ QStandardItemModel::appendColumn(hats);
+ QStandardItemModel::endResetModel();
}
-
-/*int HatModel::columnCount(const QModelIndex & parent) const
-{
- if (parent.isValid())
- return 0;
- else
- return 2;
-}
-*/
-QVariant HatModel::data(const QModelIndex &index,
- int role) const
-{
- if (!index.isValid() || index.row() < 0
- || index.row() >= hats.size()
- || (role != Qt::DisplayRole && role != Qt::DecorationRole))
- return QVariant();
-
- if (role == Qt::DisplayRole)
- return hats.at(index.row()).first;
- else // role == Qt::DecorationRole
- return hats.at(index.row()).second;
-}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/model/HatModel.h
--- a/QTfrontend/model/HatModel.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/model/HatModel.h Fri Feb 22 05:05:32 2013 +0100
@@ -24,30 +24,22 @@
#ifndef HEDGEWARS_HATMODEL_H
#define HEDGEWARS_HATMODEL_H
-#include
+#include
#include
#include
#include
#include
-class HatModel : public QAbstractListModel
+class HatModel : public QStandardItemModel
{
Q_OBJECT
public:
HatModel(QObject *parent = 0);
- QVariant headerData(int section, Qt::Orientation orientation, int role) const;
- int rowCount(const QModelIndex & parent) const;
- //int columnCount(const QModelIndex & parent) const;
-
public slots:
/// Reloads hats using the DataManager.
void loadHats();
-
- QVariant data(const QModelIndex &index, int role) const;
- protected:
- QVector > hats;
};
#endif // HEDGEWARS_HATMODEL_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/model/MapModel.cpp
--- a/QTfrontend/model/MapModel.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/model/MapModel.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -21,10 +21,18 @@
* @brief MapModel class implementation
*/
-#include "MapModel.h"
+#include
+#include "physfs.h"
+#include "MapModel.h"
+#include "HWApplication.h"
+#include "hwconsts.h"
-void MapModel::loadMaps()
+MapModel::MapInfo MapModel::MapInfoRandom = {MapModel::GeneratedMap, "+rnd+", "", 0, "", "", ""};
+MapModel::MapInfo MapModel::MapInfoMaze = {MapModel::GeneratedMaze, "+maze+", "", 0, "", "", ""};
+MapModel::MapInfo MapModel::MapInfoDrawn = {MapModel::HandDrawnMap, "+drawn+", "", 0, "", "", ""};
+
+void MapModel::loadMaps(MapType maptype)
{
// this method resets the contents of this model (important to know for views).
beginResetModel();
@@ -39,32 +47,18 @@
// empty list, so that we can (re)fill it
QStandardItemModel::clear();
- QList genMaps;
- QList missionMaps;
- QList staticMaps;
-
- // add generated/handdrawn maps to list
- // TODO: icons for these
-
- genMaps.append(
- infoToItem(QIcon(), QComboBox::tr("generated map..."), GeneratedMap, "+rnd+"));
- genMaps.append(
- infoToItem(QIcon(), QComboBox::tr("generated maze..."), GeneratedMaze, "+maze+"));
- genMaps.append(
- infoToItem(QIcon(), QComboBox::tr("hand drawn map..."), HandDrawnMap, "+drawn+"));
-
- // only 2 map relate files are relevant:
- // - the cfg file that contains the settings/info of the map
- // - the lua file - if it exists it's a mission, otherwise it isn't
- QFile mapLuaFile;
- QFile mapCfgFile;
+ //QList staticMaps;
+ //QList missionMaps;
+ QList mapList;
// add mission/static maps to lists
foreach (QString map, maps)
{
- mapCfgFile.setFileName(QString("physfs://Maps/%1/map.cfg").arg(map));
- mapLuaFile.setFileName(QString("physfs://Maps/%1/map.lua").arg(map));
-
+ // only 2 map relate files are relevant:
+ // - the cfg file that contains the settings/info of the map
+ // - the lua file - if it exists it's a mission, otherwise it isn't
+ QFile mapLuaFile(QString("physfs://Maps/%1/map.lua").arg(map));
+ QFile mapCfgFile(QString("physfs://Maps/%1/map.cfg").arg(map));
if (mapCfgFile.open(QFile::ReadOnly))
{
@@ -73,25 +67,43 @@
quint32 limit = 0;
QString scheme;
QString weapons;
+ QString desc;
+ bool dlc;
+
// if there is a lua file for this map, then it's a mission
bool isMission = mapLuaFile.exists();
- MapType type = isMission?MissionMap:StaticMap;
+ MapType type = isMission ? MissionMap : StaticMap;
+
+ // if we're supposed to ignore this type, continue
+ if (type != maptype) continue;
// load map info from file
QTextStream input(&mapCfgFile);
- input >> theme;
- input >> limit;
+ theme = input.readLine();
+ limit = input.readLine().toInt();
if (isMission) { // scheme and weapons are only relevant for missions
- input >> scheme;
- input >> weapons;
+ scheme = input.readLine();
+ weapons = input.readLine();
}
mapCfgFile.close();
+ // load description (if applicable)
+ if (isMission)
+ {
+ QString locale = HWApplication::keyboardInputLocale().name();
+
+ QSettings descSettings(QString("physfs://Maps/%1/desc.txt").arg(map), QSettings::IniFormat);
+ desc = descSettings.value(locale, QString()).toString().replace("|", "\n").replace("\\,", ",");
+ }
+
+ // detect if map is dlc
+ QString mapDir = PHYSFS_getRealDir(QString("Maps/%1/map.cfg").arg(map).toLocal8Bit().data());
+ dlc = !mapDir.startsWith(datadir->absolutePath());
+
// let's use some semi-sane hedgehog limit, rather than none
if (limit == 0)
limit = 18;
-
// the default scheme/weaponset for missions.
// if empty we assume the map sets these internally -> locked
if (isMission)
@@ -107,97 +119,54 @@
weapons.replace("_", " ");
}
- // add a mission caption prefix to missions
- if (isMission)
- {
- // TODO: icon
- caption = QComboBox::tr("Mission") + ": " + map;
- }
- else
- caption = map;
+ // caption
+ caption = map;
// we know everything there is about the map, let's get am item for it
- QStandardItem * item = infoToItem(
- QIcon(), caption, type, map, theme, limit, scheme, weapons);
+ QStandardItem * item = MapModel::infoToItem(
+ QIcon(), caption, type, map, theme, limit, scheme, weapons, desc, dlc);
// append item to the list
- if (isMission)
- missionMaps.append(item);
- else
- staticMaps.append(item);
-
+ mapList.append(item);
}
}
-
- // define a separator item
- QStandardItem separator("---");
- separator.setData(QLatin1String("separator"), Qt::AccessibleDescriptionRole);
- separator.setFlags(separator.flags() & ~( Qt::ItemIsEnabled | Qt::ItemIsSelectable ) );
-
- // create list:
- // generated+handdrawn maps, 2 saperators, missions, 1 separator, static maps
- QList items;
- items.append(genMaps);
- items.append(separator.clone());
- items.append(separator.clone());
- items.append(missionMaps);
- items.append(separator.clone());
- items.append(staticMaps);
-
-
- // create row-index lookup table
+ // Create column-index lookup table
m_mapIndexes.clear();
- int count = items.size();
+ int count = mapList.size();
for (int i = 0; i < count; i++)
{
- QStandardItem * si = items.at(i);
+ QStandardItem * si = mapList.at(i);
QVariant v = si->data(Qt::UserRole + 1);
if (v.canConvert())
m_mapIndexes.insert(v.value().name, i);
}
-
- // store start-index and count of relevant types
-
- m_typeLoc.insert(GeneratedMap, QPair(0, 1));
- m_typeLoc.insert(GeneratedMaze, QPair(1, 1));
- m_typeLoc.insert(HandDrawnMap, QPair(2, 1));
- // mission maps
- int startIdx = genMaps.size() + 2; // start after genMaps and 2 separators
- count = missionMaps.size();
- m_typeLoc.insert(MissionMap, QPair(startIdx, count));
- // static maps
- startIdx += count + 1; // start after missions and 2 separators
- count = staticMaps.size();
- m_typeLoc.insert(StaticMap, QPair(startIdx, count));
-
- // store list contents in the item model
- QStandardItemModel::appendColumn(items);
-
+ QStandardItemModel::appendColumn(mapList);
endResetModel();
}
-
-int MapModel::randomMap(MapType type) const
+bool MapModel::mapExists(const QString & map) const
{
- // return a random index for this type or -1 if none available
- QPair loc = m_typeLoc.value(type, QPair(-1,0));
-
- int startIdx = loc.first;
- int count = loc.second;
-
- if (count < 1)
- return -1;
- else
- return startIdx + (rand() % count);
+ return findMap(map) >= 0;
}
+int MapModel::findMap(const QString & map) const
+{
+ return m_mapIndexes.value(map, -1);
+}
+
+QStandardItem * MapModel::getMap(const QString & map)
+{
+ int loc = findMap(map);
+ if (loc < 0) return NULL;
+ return item(loc);
+}
QStandardItem * MapModel::infoToItem(
const QIcon & icon,
@@ -207,10 +176,11 @@
QString theme,
quint32 limit,
QString scheme,
- QString weapons)
-const
+ QString weapons,
+ QString desc,
+ bool dlc)
{
- QStandardItem * item = new QStandardItem(icon, caption);
+ QStandardItem * item = new QStandardItem(icon, (dlc ? "*" : "") + caption);
MapInfo mapInfo;
QVariant qvar(QVariant::UserType);
@@ -220,17 +190,11 @@
mapInfo.limit = limit;
mapInfo.scheme = scheme;
mapInfo.weapons = weapons;
-
+ mapInfo.desc = desc.isEmpty() ? tr("No description available.") : desc;
+ mapInfo.dlc = dlc;
qvar.setValue(mapInfo);
item->setData(qvar, Qt::UserRole + 1);
return item;
}
-
-
-int MapModel::indexOf(const QString & map) const
-{
- return m_mapIndexes.value(map, -1);
-}
-
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/model/MapModel.h
--- a/QTfrontend/model/MapModel.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/model/MapModel.h Fri Feb 22 05:05:32 2013 +0100
@@ -63,32 +63,50 @@
quint32 limit; ///< The maximum allowed number of hedgehogs.
QString scheme; ///< Default scheme name or "locked", for mission-maps.
QString weapons; ///< Default weaponset name or "locked", for missions-maps.
+ QString desc; ///< The brief 1-2 sentence description of the mission, for mission-maps.
+ bool dlc; ///< True if this map was not packaged with the game
};
/**
- * @brief Returns the row-index of the given map.
- * @param map map of which to get the row-index of.
- * @return row-index of map or -1 if not available.
+ * @brief Searches maps in model to find out if one exists
+ * @param map map of which to check existence
+ * @return true if it exists
*/
- int indexOf(const QString & map) const;
+ bool mapExists(const QString & map) const;
+
+ /**
+ * @brief Finds a map index (column, row) for a map name
+ * @param map map of which to find index+column
+ * @return QPair with column, index, or (-1, -1) if map not found
+ */
+ //QPair findMap(const QString & map) const;
/**
- * @brief Returns the row-index of a random map with a specified type.
- * @param type desired type of map.
- * @return row-index of a map with the desired type, -1 if none found.
+ * @brief Finds a map index for a map name
+ * @param map map of which to find index
+ * @return int of index, or -1 if map not found
*/
- int randomMap(MapType type) const;
+ int findMap(const QString & map) const;
+
+ /**
+ * @brief Finds and returns a map item for a map name
+ * @param map map
+ * @return QStandardItem of map, or NULL if map not found
+ */
+ QStandardItem * getMap(const QString & map);
+
+ // Static MapInfos for drawn and generated maps
+ static MapInfo MapInfoRandom, MapInfoMaze, MapInfoDrawn;
public slots:
/// Reloads the maps using the DataManager.
- void loadMaps();
+ /// Accepts two map types: StaticMap or MissionMap.
+ void loadMaps(MapType maptype);
private:
- /// start-index and map count for each map-type.
- QMap > m_typeLoc;
-
- /// map index lookup table
+ /// map index lookup table. QPair contains:
+ //QHash > m_mapIndexes;
QHash m_mapIndexes;
/**
@@ -102,9 +120,10 @@
* @param limit the hedgehog limit of the map.
* @param scheme mission map: default scheme name or "locked".
* @param weapons mission map: default weaponset name or "locked".
+ * @param desc mission map: description of mission.
* @return pointer to item representing the map info: at Qt::UserRole + 1.
*/
- QStandardItem * infoToItem(
+ static QStandardItem * infoToItem(
const QIcon & icon,
const QString caption,
MapType type = Invalid,
@@ -112,7 +131,9 @@
QString theme = "",
quint32 limit = 0,
QString scheme = "",
- QString weapons = "") const;
+ QString weapons = "",
+ QString desc = "",
+ bool dlc = false);
};
Q_DECLARE_METATYPE(MapModel::MapInfo)
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/model/ThemeModel.cpp
--- a/QTfrontend/model/ThemeModel.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/model/ThemeModel.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -21,7 +21,9 @@
* @brief ThemeModel class implementation
*/
+#include "physfs.h"
#include "ThemeModel.h"
+#include "hwconsts.h"
ThemeModel::ThemeModel(QObject *parent) :
QAbstractListModel(parent)
@@ -51,7 +53,6 @@
{
beginResetModel();
-
DataManager & datamgr = DataManager::instance();
QStringList themes =
@@ -73,17 +74,23 @@
QMap dataset;
- // set name
- dataset.insert(Qt::DisplayRole, theme);
+ // detect if theme is dlc
+ QString themeDir = PHYSFS_getRealDir(QString("Themes/%1/icon.png").arg(theme).toLocal8Bit().data());
+ bool isDLC = !themeDir.startsWith(datadir->absolutePath());
+ dataset.insert(IsDlcRole, isDLC);
- // load and set icon
- QIcon icon(iconpath);
+ // set icon path
+ dataset.insert(IconPathRole, iconpath);
- dataset.insert(Qt::DecorationRole, icon);
+ // set name
+ dataset.insert(ActualNameRole, theme);
+
+ // set displayed name
+ dataset.insert(Qt::DisplayRole, (isDLC ? "*" : "") + theme);
// load and set preview icon
QIcon preview(QString("physfs://Themes/%1/icon@2x.png").arg(theme));
- dataset.insert(Qt::UserRole, preview);
+ dataset.insert(Qt::DecorationRole, preview);
m_data.append(dataset);
}
@@ -91,7 +98,3 @@
endResetModel();
}
-
-
-
-
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/model/ThemeModel.h
--- a/QTfrontend/model/ThemeModel.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/model/ThemeModel.h Fri Feb 22 05:05:32 2013 +0100
@@ -39,6 +39,7 @@
Q_OBJECT
public:
+ enum Roles { ActualNameRole = Qt::UserRole, IsDlcRole, IconPathRole };
explicit ThemeModel(QObject *parent = 0);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/model/roomslistmodel.cpp
--- a/QTfrontend/model/roomslistmodel.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/model/roomslistmodel.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -43,7 +43,8 @@
<< tr("Rules")
<< tr("Weapons");
- m_mapModel = DataManager::instance().mapModel();
+ m_staticMapModel = DataManager::instance().staticMapModel();
+ m_missionMapModel = DataManager::instance().missionMapModel();
}
@@ -134,7 +135,8 @@
}
// prefix ? if map not available
- if ((m_mapModel->indexOf(content) < 0))
+ if (!m_staticMapModel->mapExists(content) &&
+ !m_missionMapModel->mapExists(content))
return QString ("? %1").arg(content);
}
@@ -144,10 +146,14 @@
// dye map names red if map not available
if (role == Qt::ForegroundRole)
{
- if ((m_mapModel->indexOf(content) < 0))
+ if (content == "+rnd+" ||
+ content == "+maze+" ||
+ content == "+drawn+" ||
+ m_staticMapModel->mapExists(content) ||
+ m_missionMapModel->mapExists(content))
+ return QVariant();
+ else
return QBrush(QColor("darkred"));
- else
- return QVariant();
}
if (role == Qt::TextAlignmentRole)
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/model/roomslistmodel.h
--- a/QTfrontend/model/roomslistmodel.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/model/roomslistmodel.h Fri Feb 22 05:05:32 2013 +0100
@@ -64,7 +64,8 @@
const int c_nColumns;
QList m_data;
QStringList m_headerData;
- MapModel * m_mapModel;
+ MapModel * m_staticMapModel;
+ MapModel * m_missionMapModel;
QStringList roomInfo2RoomRecord(const QStringList & info);
};
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/net/hwmap.cpp
--- a/QTfrontend/net/hwmap.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/net/hwmap.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -20,8 +20,8 @@
#include "hwconsts.h"
#include "hwmap.h"
-HWMap::HWMap() :
- TCPBase(false)
+HWMap::HWMap(QObject * parent) :
+ TCPBase(false, parent)
{
}
@@ -29,6 +29,11 @@
{
}
+bool HWMap::couldBeRemoved()
+{
+ return !m_hasStarted;
+}
+
void HWMap::getImage(const QString & seed, int filter, MapGenerator mapgen, int maze_size, const QByteArray & drawMapData)
{
m_seed = seed;
@@ -36,15 +41,18 @@
m_mapgen = mapgen;
m_maze_size = maze_size;
if(mapgen == MAPGEN_DRAWN) m_drawMapData = drawMapData;
- Start();
+ Start(true);
}
QStringList HWMap::getArguments()
{
QStringList arguments;
- arguments << cfgdir->absolutePath();
+ arguments << "--internal";
+ arguments << "--port";
arguments << QString("%1").arg(ipc_port);
- arguments << "landpreview";
+ arguments << "--user-prefix";
+ arguments << cfgdir->absolutePath();
+ arguments << "--landpreview";
return arguments;
}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/net/hwmap.h
--- a/QTfrontend/net/hwmap.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/net/hwmap.h Fri Feb 22 05:05:32 2013 +0100
@@ -39,9 +39,10 @@
Q_OBJECT
public:
- HWMap();
+ HWMap(QObject *parent = 0);
virtual ~HWMap();
void getImage(const QString & seed, int templateFilter, MapGenerator mapgen, int maze_size, const QByteArray & drawMapData);
+ bool couldBeRemoved();
protected:
virtual QStringList getArguments();
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/net/newnetclient.cpp
--- a/QTfrontend/net/newnetclient.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/net/newnetclient.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -28,6 +28,8 @@
#include "game.h"
#include "roomslistmodel.h"
#include "playerslistmodel.h"
+#include "servermessages.h"
+#include "HWApplication.h"
char delimeter='\n';
@@ -241,6 +243,7 @@
{
mynick = lst[1];
m_playersModel->setNickname(mynick);
+ m_nick_registered = false;
return ;
}
@@ -250,7 +253,7 @@
if (lst[0] == "ERROR")
{
if (lst.size() == 2)
- emit Error(lst[1]);
+ emit Error(HWApplication::translate("server", lst[1].toAscii().constData()));
else
emit Error("Unknown error");
return;
@@ -259,7 +262,7 @@
if (lst[0] == "WARNING")
{
if (lst.size() == 2)
- emit Warning(lst[1]);
+ emit Warning(HWApplication::translate("server", lst[1].toAscii().constData()));
else
emit Warning("Unknown warning");
return;
@@ -304,6 +307,10 @@
QStringList tmp = lst;
tmp.removeFirst();
m_roomsListModel->setRoomsList(tmp);
+ if (m_nick_registered == false)
+ {
+ emit NickNotRegistered(mynick);
+ }
return;
}
@@ -364,6 +371,14 @@
return;
}
+ if (lst[0] == "BANLIST")
+ {
+ QStringList tmp = lst;
+ tmp.removeFirst();
+ emit bansList(tmp);
+ return;
+ }
+
if (lst[0] == "CLIENT_FLAGS")
{
if(lst.size() < 3 || lst[1].size() < 2)
@@ -380,11 +395,13 @@
{
flags.remove(0, 1);
char c = flags[0].toAscii();
+ bool inRoom = (netClientState == InRoom || netClientState == InGame);
switch(c)
{
// flag indicating if a player is ready to start a game
case 'r':
+ if(inRoom)
foreach (const QString & nick, nicks)
{
if (nick == mynick)
@@ -401,14 +418,16 @@
foreach(const QString & nick, nicks)
m_playersModel->setFlag(nick, PlayersListModel::Registered, setFlag);
break;
-
+ // flag indicating if a player has engine running
case 'g':
+ if(inRoom)
foreach(const QString & nick, nicks)
m_playersModel->setFlag(nick, PlayersListModel::InGame, setFlag);
break;
// flag indicating if a player is the host/master of the room
case 'h':
+ if(inRoom)
foreach (const QString & nick, nicks)
{
if (nick == mynick)
@@ -493,9 +512,12 @@
QString roomName = tmp.takeFirst();
m_roomsListModel->updateRoom(roomName, tmp);
- // keep track of room name so correct name is displayed when you become room admin
+ // keep track of room name so correct name is displayed
if(myroom == roomName)
+ {
myroom = tmp[1];
+ emit roomNameUpdated(myroom);
+ }
return;
}
@@ -526,7 +548,8 @@
if (lst[0] == "ASKPASSWORD")
{
- emit AskForPassword(mynick);
+ emit NickRegistered(mynick);
+ m_nick_registered = true;
return;
}
@@ -561,10 +584,14 @@
if (lst[1] == "Authentication failed")
{
emit AuthFailed();
+ m_game_connected = false;
+ Disconnect();
+ //omitted 'emit disconnected()', we don't want the error message
+ return;
}
m_game_connected = false;
Disconnect();
- emit disconnected(lst[1]);
+ emit disconnected(HWApplication::translate("server", lst[1].toAscii().constData()));
return;
}
@@ -574,6 +601,18 @@
return;
}
+ if(lst[0] == "JOINING")
+ {
+ if(lst.size() < 2)
+ {
+ qWarning("Net: Bad JOINING message");
+ return;
+ }
+
+ myroom = lst[1];
+ emit roomNameUpdated(myroom);
+ }
+
if(netClientState == InLobby && lst[0] == "JOINED")
{
if(lst.size() < 2 || lst[1] != mynick)
@@ -617,6 +656,12 @@
return;
}
+ if (lst[0] == "ROUND_FINISHED")
+ {
+ emit FromNet(QByteArray("\x01o"));
+ return;
+ }
+
if (lst[0] == "ADD_TEAM")
{
if(lst.size() != 24)
@@ -859,6 +904,26 @@
RawSendNet(QString("BAN%1%2").arg(delimeter).arg(nick));
}
+void HWNewNet::banIP(const QString & ip, const QString & reason, int seconds)
+{
+ RawSendNet(QString("BANIP%1%2%1%3%1%4").arg(delimeter).arg(ip).arg(reason).arg(seconds));
+}
+
+void HWNewNet::banNick(const QString & nick, const QString & reason, int seconds)
+{
+ RawSendNet(QString("BANNICK%1%2%1%3%1%4").arg(delimeter).arg(nick).arg(reason).arg(seconds));
+}
+
+void HWNewNet::getBanList()
+{
+ RawSendNet(QByteArray("BANLIST"));
+}
+
+void HWNewNet::removeBan(const QString & b)
+{
+ RawSendNet(QString("UNBAN%1%2").arg(delimeter).arg(b));
+}
+
void HWNewNet::kickPlayer(const QString & nick)
{
RawSendNet(QString("KICK%1%2").arg(delimeter).arg(nick));
@@ -878,6 +943,20 @@
}
}
+void HWNewNet::consoleCommand(const QString & cmd)
+{
+ RawSendNet(QString("CMD%1%2").arg(delimeter).arg(cmd));
+}
+
+bool HWNewNet::allPlayersReady()
+{
+ int ready = 0;
+ for (int i = 0; i < m_roomPlayersModel->rowCount(); i++)
+ if (m_roomPlayersModel->index(i, 0).data(PlayersListModel::Ready).toBool()) ready++;
+
+ return (ready == m_roomPlayersModel->rowCount());
+}
+
void HWNewNet::startGame()
{
RawSendNet(QString("START_GAME"));
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/net/newnetclient.h
--- a/QTfrontend/net/newnetclient.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/net/newnetclient.h Fri Feb 22 05:05:32 2013 +0100
@@ -60,6 +60,7 @@
RoomsListModel * roomsListModel();
QAbstractItemModel * lobbyPlayersModel();
QAbstractItemModel * roomPlayersModel();
+ bool allPlayersReady();
private:
bool isChief;
@@ -69,6 +70,7 @@
QTcpSocket NetSocket;
QString seed;
bool m_game_connected;
+ bool m_nick_registered;
RoomsListModel * m_roomsListModel;
PlayersListModel * m_playersModel;
QSortFilterProxyModel * m_lobbyPlayersModel;
@@ -90,7 +92,8 @@
void disconnected(const QString & reason);
void Error(const QString & errmsg);
void Warning(const QString & wrnmsg);
- void AskForPassword(const QString & nick);
+ void NickRegistered(const QString & nick);
+ void NickNotRegistered(const QString & nick);
void NickTaken(const QString & nick);
void AuthFailed();
void EnteredGame();
@@ -102,6 +105,7 @@
void FromNet(const QByteArray & buf);
void adminAccess(bool);
void roomMaster(bool);
+ void roomNameUpdated(const QString & name);
void netSchemeConfig(QStringList &);
void paramChanged(const QString & param, const QStringList & value);
@@ -123,6 +127,7 @@
void serverMessageNew(const QString &);
void serverMessageOld(const QString &);
void latestProtocolVar(int);
+ void bansList(const QStringList &);
void setMyReadyStatus(bool isReady);
@@ -152,11 +157,16 @@
void kickPlayer(const QString &);
void infoPlayer(const QString &);
void followPlayer(const QString &);
+ void consoleCommand(const QString &);
void startGame();
void toggleRestrictJoins();
void toggleRestrictTeamAdds();
void partRoom();
void clearAccountsCache();
+ void getBanList();
+ void removeBan(const QString &);
+ void banIP(const QString & ip, const QString & reason, int seconds);
+ void banNick(const QString & nick, const QString & reason, int seconds);
private slots:
void ClientRead();
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/net/recorder.cpp
--- a/QTfrontend/net/recorder.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/net/recorder.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -47,7 +47,7 @@
if (queue.empty())
numRecorders--;
else
- queue.takeFirst()->Start();
+ queue.takeFirst()->Start(false);
}
void HWRecorder::onClientDisconnect()
@@ -89,7 +89,7 @@
if (numRecorders < maxRecorders)
{
numRecorders++;
- Start(); // run engine
+ Start(false); // run engine
}
else
queue.push_back(this);
@@ -99,29 +99,44 @@
{
QStringList arguments;
QRect resolution = config->rec_Resolution();
- arguments << cfgdir->absolutePath();
- arguments << QString::number(resolution.width());
- arguments << QString::number(resolution.height());
- arguments << "32"; // bpp
+ QString nick = config->netNick().toUtf8().toBase64();
+
+ arguments << "--internal";
+ arguments << "--port";
arguments << QString("%1").arg(ipc_port);
- arguments << "0"; // fullscreen
- arguments << "0"; // sound
- arguments << "0"; // music
- arguments << "0"; // sound volume
+ arguments << "--prefix";
+ arguments << datadir->absolutePath();
+ arguments << "--user-prefix";
+ arguments << cfgdir->absolutePath();
+ arguments << "--locale";
+ arguments << HWGame::tr("en.txt");
+ arguments << "--frame-interval";
arguments << QString::number(config->timerInterval());
- arguments << datadir->absolutePath();
- arguments << "0"; // fps
- arguments << (config->isAltDamageEnabled() ? "1" : "0");
- arguments << config->netNick().toUtf8().toBase64();
+ arguments << "--width";
+ arguments << QString::number(resolution.width());
+ arguments << "--height";
+ arguments << QString::number(resolution.height());
+ arguments << "--nosound";
+ arguments << "--raw-quality";
arguments << QString::number(config->translateQuality());
+ arguments << "--stereo";
arguments << QString::number(config->stereoMode());
- arguments << HWGame::tr("en.txt");
- arguments << QString::number(config->rec_Framerate()); // framerate numerator
- arguments << "1"; // framerate denominator
+ arguments << "--nomusic";
+ arguments << "--volume";
+ arguments << "0";
+ if (config->isAltDamageEnabled())
+ arguments << "--altdmg";
+ if (!nick.isEmpty()) {
+ arguments << "--nick";
+ arguments << nick;
+ }
+ arguments << "--recorder";
+ arguments << QString::number(config->rec_Framerate()); //cVideoFramerateNum
+ arguments << "1"; //cVideoFramerateDen
arguments << prefix;
arguments << config->AVFormat();
arguments << config->videoCodec();
-// Could use a field to use quality instead. maybe quality could override bitrate - or just pass (and set) both.
+// Could use a field to use quality instead. maybe quality could override bitrate - or just pass (and set) both.
// The library does support using both at once after all.
arguments << QString::number(config->rec_Bitrate()*1024);
arguments << (config->recordAudio() ? config->audioCodec() : "no");
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/net/tcpBase.cpp
--- a/QTfrontend/net/tcpBase.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/net/tcpBase.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -23,19 +23,63 @@
#include
#include
#include
+#include
#include "hwconsts.h"
+#ifdef HWLIBRARY
+extern "C" void Game(char**arguments);
+extern "C" void GenLandPreview(int port);
+
+
+EngineInstance::EngineInstance(QObject *parent)
+ : QObject(parent)
+{
+ port = 0;
+}
+
+EngineInstance::~EngineInstance()
+{
+}
+
+void EngineInstance::start()
+{
+#if 0
+ char *args[11];
+ args[0] = "65000"; //ipcPort
+ args[1] = "1024"; //cScreenWidth
+ args[2] = "768"; //cScreenHeight
+ args[3] = "0"; //cReducedQuality
+ args[4] = "en.txt"; //cLocaleFName
+ args[5] = "koda"; //UserNick
+ args[6] = "1"; //SetSound
+ args[7] = "1"; //SetMusic
+ args[8] = "0"; //cAltDamage
+ args[9]= datadir->absolutePath().toAscii().data(); //cPathPrefix
+ args[10]= NULL; //recordFileName
+ Game(args);
+#endif
+ GenLandPreview(port);
+}
+
+#endif
+
QList srvsList;
QPointer TCPBase::IPCServer(0);
TCPBase::~TCPBase()
{
+ // make sure this object is not in the server list anymore
+ srvsList.removeOne(this);
+
if (IPCSocket)
IPCSocket->deleteLater();
+
}
-TCPBase::TCPBase(bool demoMode) :
+TCPBase::TCPBase(bool demoMode, QObject *parent) :
+ QObject(parent),
+ m_hasStarted(false),
m_isDemoMode(demoMode),
IPCSocket(0)
{
@@ -55,6 +99,7 @@
exit(0); // FIXME - should be graceful exit here (lower Critical -> Warning above when implemented)
}
}
+
ipc_port=IPCServer->serverPort();
}
@@ -71,9 +116,6 @@
connect(IPCSocket, SIGNAL(disconnected()), this, SLOT(ClientDisconnect()));
connect(IPCSocket, SIGNAL(readyRead()), this, SLOT(ClientRead()));
SendToClientFirst();
-
- if(srvsList.size()==1) srvsList.pop_front();
- emit isReadyNow();
}
void TCPBase::RealStart()
@@ -81,15 +123,31 @@
connect(IPCServer, SIGNAL(newConnection()), this, SLOT(NewConnection()));
IPCSocket = 0;
+#ifdef HWLIBRARY
+ QThread *thread = new QThread;
+ EngineInstance *instance = new EngineInstance;
+ instance->port = IPCServer->serverPort();
+
+ instance->moveToThread(thread);
+
+ connect(thread, SIGNAL(started()), instance, SLOT(start(void)));
+ connect(instance, SIGNAL(finished()), thread, SLOT(quit()));
+ connect(instance, SIGNAL(finished()), instance, SLOT(deleteLater()));
+ connect(instance, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+#else
QProcess * process;
- process = new QProcess;
+ process = new QProcess();
connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(StartProcessError(QProcess::ProcessError)));
QStringList arguments=getArguments();
// redirect everything written on stdout/stderr
if(isDevBuild)
process->setProcessChannelMode(QProcess::ForwardedChannels);
+
process->start(bindir->absolutePath() + "/hwengine", arguments);
+#endif
+ m_hasStarted = true;
}
void TCPBase::ClientDisconnect()
@@ -97,13 +155,9 @@
disconnect(IPCSocket, SIGNAL(readyRead()), this, SLOT(ClientRead()));
onClientDisconnect();
- /* if(srvsList.size()==1) srvsList.pop_front();
- emit isReadyNow();*/
+ emit isReadyNow();
IPCSocket->deleteLater();
- // make sure this object is not in the server list anymore
- srvsList.removeOne(this);
-
deleteLater();
}
@@ -130,25 +184,34 @@
void TCPBase::tcpServerReady()
{
- disconnect(srvsList.takeFirst(), SIGNAL(isReadyNow()), this, SLOT(tcpServerReady()));
+ disconnect(srvsList.first(), SIGNAL(isReadyNow()), this, SLOT(tcpServerReady()));
RealStart();
}
-void TCPBase::Start()
+void TCPBase::Start(bool couldCancelPreviousRequest)
{
if(srvsList.isEmpty())
{
srvsList.push_back(this);
+ RealStart();
}
else
{
- connect(srvsList.back(), SIGNAL(isReadyNow()), this, SLOT(tcpServerReady()));
- srvsList.push_back(this);
- return;
+ TCPBase * last = srvsList.last();
+ if(couldCancelPreviousRequest
+ && last->couldBeRemoved()
+ && (last->parent() == parent()))
+ {
+ srvsList.removeLast();
+ last->deleteLater();
+ Start(couldCancelPreviousRequest);
+ } else
+ {
+ connect(srvsList.last(), SIGNAL(isReadyNow()), this, SLOT(tcpServerReady()));
+ srvsList.push_back(this);
+ }
}
-
- RealStart();
}
void TCPBase::onClientRead()
@@ -191,3 +254,8 @@
}
}
}
+
+bool TCPBase::couldBeRemoved()
+{
+ return false;
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/net/tcpBase.h
--- a/QTfrontend/net/tcpBase.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/net/tcpBase.h Fri Feb 22 05:05:32 2013 +0100
@@ -38,16 +38,19 @@
Q_OBJECT
public:
- TCPBase(bool demoMode);
+ TCPBase(bool demoMode, QObject * parent = 0);
virtual ~TCPBase();
+ virtual bool couldBeRemoved();
+
signals:
void isReadyNow();
protected:
+ bool m_hasStarted;
quint16 ipc_port;
- void Start();
+ void Start(bool couldCancelPreviousRequest);
QByteArray readbuffer;
@@ -78,4 +81,21 @@
void tcpServerReady();
};
+#ifdef HWLIBRARY
+class EngineInstance : public QObject
+{
+ Q_OBJECT
+public:
+ EngineInstance(QObject *parent = 0);
+ ~EngineInstance();
+
+ int port;
+public slots:
+ void start(void);
+signals:
+ void finished(void);
+private:
+};
+#endif
+
#endif // _TCPBASE_INCLUDED
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/res/NetworkPlayDisabled.png
Binary file QTfrontend/res/NetworkPlayDisabled.png has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/res/Start.png
Binary file QTfrontend/res/Start.png has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/res/audio.png
Binary file QTfrontend/res/audio.png has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/res/camera.png
Binary file QTfrontend/res/camera.png has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/res/css/christmas.css
--- a/QTfrontend/res/css/christmas.css Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/res/css/christmas.css Fri Feb 22 05:05:32 2013 +0100
@@ -21,7 +21,7 @@
background-image: url(":/res/BackgroundChristmas.png");
background-position: bottom center;
background-repeat: repeat-x;
-background-color: #141250;
+background-color: #0c0f28;
}
* {
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/res/css/qt.css
--- a/QTfrontend/res/css/qt.css Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/res/css/qt.css Fri Feb 22 05:05:32 2013 +0100
@@ -33,7 +33,7 @@
a { color:#c8c8ff; }
QLineEdit, QListWidget, QListView, QTableView, QTextBrowser, QSpinBox, QComboBox,
-QComboBox QAbstractItemView, QPlainTextEdit, QMenu::item {
+QComboBox QAbstractItemView, QPlainTextEdit, QMenu::item, #labelLikeLineEdit {
background-color: rgba(13, 5, 68, 70%);
}
@@ -44,8 +44,8 @@
QPushButton, QListWidget, QListView, QTableView, QLineEdit, QHeaderView,
QTextBrowser, QSpinBox, QToolBox, QComboBox, QPlainTextEdit,
QComboBox QAbstractItemView, IconedGroupBox,
-.QGroupBox, GameCFGWidget, TeamSelWidget, SelWeaponWidget,
-QTabWidget::pane, QTabBar::tab {
+.QGroupBox, #gameStackContainer, TeamSelWidget, SelWeaponWidget,
+QTabWidget::pane, QTabBar::tab, #mapPreview, #labelLikeLineEdit {
border: solid;
border-width: 3px;
border-color: #ffcc00;
@@ -56,14 +56,30 @@
border-color: yellow;
}
+QToolButton {
+background-color: #11084A;
+}
+
+QToolButton:hover {
+background-color: #150A61;
+}
+
+QToolButton:pressed {
+background-color: #100744;
+}
+
QLineEdit, QListWidget, QListView, QTableView, QTextBrowser,
-QSpinBox, QToolBox, QPlainTextEdit {
+QSpinBox, QToolBox, QPlainTextEdit, QToolButton, #mapPreview, #labelLikeLineEdit {
border-radius: 10px;
}
+#mapPreview {
+background-color: #0d0544;
+}
+
QLineEdit, QLabel, QHeaderView, QListWidget, QListView, QTableView,
QSpinBox, QToolBox::tab, QComboBox, QComboBox QAbstractItemView,
-IconedGroupBox, .QGroupBox, GameCFGWidget, TeamSelWidget,
+IconedGroupBox, .QGroupBox, #gameStackContainer, TeamSelWidget,
SelWeaponWidget, QCheckBox, QRadioButton, QPushButton, QPlainTextEdit {
font: bold 13px;
}
@@ -72,7 +88,7 @@
background-repeat: repeat-x;
background-color: #000000;
}
-.QGroupBox,GameCFGWidget,TeamSelWidget,SelWeaponWidget {
+.QGroupBox, #gameStackContainer, TeamSelWidget, SelWeaponWidget {
background-position: bottom center;
background-repeat: repeat-x;
border-radius: 16px;
@@ -89,6 +105,18 @@
background-color: #130f2c;
}
+QTabWidget::pane {
+border-radius: 8px;
+border-top-left-radius: 0px;
+}
+
+QLineEdit:disabled, QSpinBox:disabled {
+border-color: gray;
+}
+
+GameCFGWidget {
+border: none;
+}
QPushButton {
border-radius: 8px;
@@ -97,7 +125,7 @@
background-color: rgba(18, 42, 5, 70%);
}
-QPushButton:pressed{
+QPushButton:pressed, QToolButton:pressed {
border-color: white;
}
@@ -105,7 +133,6 @@
outline: none;
}
-
QHeaderView {
border-radius: 0;
border-width: 0;
@@ -241,9 +268,62 @@
QSlider::handle::horizontal {
border: 0px;
-margin: -2px 0px;
+margin: -8px 0px;
+background-color: #ffcc00;
+width: 12px;
+height: 6px;
border-radius: 3px;
-background-color: #ffcc00;
-width: 8px;
+}
+
+HatButton, ThemeButton {
+text-align: left;
+}
+
+#hatList, #hatList:hover, #themeList, #themeList:hover {
+border-color: #F6CB1C;
+}
+
+#hatList QScrollBar, #themeList QScrollBar {
+background-color: #130F2A;
+border-top-right-radius: 10px;
+border-bottom-right-radius: 10px;
+}
+
+#hatList, #themeList {
+border-color: #F6CB1C;
+border-width: 3px;
+border-style: solid;
+border-radius: 10px;
+border-top-left-radius: 0px;
}
+#hatList::item, #themeList::item {
+background-color: #11084A;
+padding: 4px;
+border-radius: 10px;
+color: #ffcc00 !important;
+font: 8px;
+border-width: 2px;
+border-color: #11084A;
+}
+
+#hatList::item:hover, #themeList::item:hover {
+background-color: #150A61;
+}
+
+#hatList::item:selected, #themeList::item:selected {
+background-color: #150A61;
+}
+
+QDialogButtonBox QPushButton {
+padding: 3px 5px;
+}
+
+#gameCfgWidgetTabs {
+border-radius: 16px;
+border-top-left-radius: 0px;
+}
+
+TeamSelWidget, #gameStackContainer, #GBoxOptions {
+border-radius: 10px;
+}
\ No newline at end of file
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/res/html/about.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/res/html/about.html Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,98 @@
+
+
+
+Hedgewars - Authors
+
+
+
+
+ Developers:
+
+ Engine, frontend, net server: Andrey Korotaev <unC0Rr@gmail.com>
+ Many frontend improvements: Igor Ulyanov <disinbox@gmail.com>
+ Many engine and frontend improvements: Derek Pomery <nemo@m8y.org>
+ Drill rocket, Ballgun, RC Plane weapons: Martin Boze <afffect@gmail.com>
+ Mine number and time game settings: David A. Cuadrado <krawek@gmail.com>
+ Frontend improvements: Martin Minarik <ttsmj@pokec.sk>
+ Frontend improvements: Kristian Lehmann <email@thexception.net>
+ Mac OS X/iPhone port, OpenGL-ES conversion: Vittorio Giovara <vittorio.giovara@gmail.com>
+ Many engine and frontend improvements (and bugs): Richard Karolyi <sheepluva@ercatec.net>
+ Gamepad and Lua integration: Mario Liebisch <mario.liebisch@gmail.com>
+ Many engine improvements and graphics: Carlos Vives <mail@carlosvives.es>
+ Maze maps: Henning Kühn <prg@cooco.de>
+ Engine and frontend improvements: Henrik Rostedt <henrik.rostedt@gmail.com>
+ Lua game modes and missions: John Lambert <redgrinner@gmail.com>
+ Frontend improvements: Mayur Pawashe <zorgiepoo@gmail.com>
+ Android port: Richard Deurwaarder <xeli@xelification.com>
+ Android netplay, portability abstraction: Simeon Maxein <smaxein@googlemail.com>
+ WebGL port, some pas2c and GLES2 work: Meng Xiangyun <xymengxy@gmail.com>
+ Video recording: Stepan Podoskin <stepik-777@mail.ru>
+ Campaign support, first campaign: Szabolcs Orbàn <szabibibi@gmail.com>
+ Keybinds, feedback, maps and hats interfaces: Drew Gottlieb <gottlieb.drew@gmail.com>
+ Login dialogs, frontend improvements: Ondrej Skopek <skopekondrej@gmail.com>
+
+
+ Art:
+ John Dum <fizzy@gmail.com>
+
+ Joshua Frese <joshfrese@gmail.com>
+
+ Stanko Tadić <stanko@mfhinc.net>
+
+ Julien Koesten <julienkoesten@aol.com>
+
+ Joshua O'Sullivan <coheedftw@hotmail.co.uk>
+
+ Nils Lück <nils.luck.design@gmail.com>
+
+ Guillaume Englert <genglert@hybird.org>
+
+ Hats: Trey Perry <tx.perry.j@gmail.com>
+
+
+ Sounds:
+
+ Hedgehogs voice: Stephen Alexander <ArmagonNo1@gmail.com>
+
+ John Dum <fizzy@gmail.com>
+
+ Jonatan Nilsson <jonatanfan@gmail.com>
+
+ Daniel Martin <elhombresinremedio@gmail.com>
+
+
+ Translations:
+ Brazilian Portuguese: Romulo Fernandes Machado <abra185@gmail.com>
+ Bulgarian: Svetoslav Stefanov
+ Czech: Petr Řezáček <rezacek@gmail.com>
+ Chinese: Jie Luo <lililjlj@gmail.com>
+ English: Andrey Korotaev <unC0Rr@gmail.com>
+ Finnish: Nina Kuisma <ninnnu@gmail.com>
+ French: Antoine Turmel <geekshadow@gmail.com>, Clement Woitrain <sphrixclement@gmail.com>
+ German: Peter Hüwe <PeterHuewe@gmx.de>, Mario Liebisch <mario.liebisch@gmail.com>, Richard Karolyi <sheepluva@ercatec.net>
+ Greek: <talos_kriti@yahoo.gr>
+ Italian: Luca Bonora <bonora.luca@gmail.com>, Marco Bresciani
+ Japanese: ADAM Etienne <etienne.adam@gmail.com>
+ Korean: Anthony Bellew <anthonyreflected@gmail.com>
+ Lithuanian: Lukas Urbonas <lukasu08@gmail.com>
+ Polish: Maciej Mroziński <mynick2@o2.pl>, Wojciech Latkowski <magik17l@gmail.com>, Piotr Mitana, Maciej Górny
+ Portuguese: Fábio Canário <inufabie@gmail.com>
+ Russian: Andrey Korotaev <unC0Rr@gmail.com>
+ Slovak: Jose Riha
+ Spanish: Carlos Vives <mail@carlosvives.es>
+ Swedish: Niklas Grahn <raewolusjoon@yaoo.com>, Henrik Rostedt <henrik.rostedt@gmail.com>
+ Ukrainian: Eugene V. Lyubimkin <jackyf.devel@gmail.com>, Igor Paliychuk <mansonigor@gmail.com>, Eugene Sakara <eresid@gmail.com>
+
+
+ Special thanks:
+ Aleksey Andreev <blaknayabr@gmail.com>
+ Aleksander Rudalev <alexv@pomorsu.ru>
+ Natasha Korotaeva <layout@pisem.net>
+ Adam Higerd (aka ahigerd at FreeNode)
+
+
+
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/res/inverse-corner-bl.png
Binary file QTfrontend/res/inverse-corner-bl.png has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/res/splash.png
Binary file QTfrontend/res/splash.png has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/res/xml/tips.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/res/xml/tips.xml Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,61 @@
+# This is not xml actually, but it looks and behaves like it.
+# Including an xml library would need too much resources.
+# Tips between the platform specific tags are shown only on those platforms.
+# Do not escape characters or use the CDATA tag.
+
+ Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together.
+ Some weapons might do only low damage but they can be a lot more devastating in the right situation. Try to use the Desert Eagle to knock multiple hedgehogs into the water.
+ If you're unsure what to do and don't want to waste ammo, skip one round. But don't let too much time pass as there will be Sudden Death!
+ Want to save ropes? Release the rope in mid air and then shoot again. As long as you don't touch the ground or miss a shot you'll reuse your rope without wasting ammo!
+ If you'd like to keep others from using your preferred nickname on the official server, register an account at http://www.hedgewars.org/.
+ You're bored of default gameplay? Try one of the missions - they'll offer different gameplay depending on the one you picked.
+ By default the game will always record the last game played as a demo. Select 'Local Game' and pick the 'Demos' button on the lower right corner to play or manage them.
+ Hedgewars is free software (Open Source) we create in our spare time. If you've got problems, ask on our forums or visit our IRC room!
+ Hedgewars is free software (Open Source) we create in our spare time. If you like it, help us with a small donation or contribute your own work!
+ Hedgewars is free software (Open Source) we create in our spare time. Share it with your family and friends as you like!
+ Hedgewars is free software (Open Source) we create in our spare time, just for fun! Meet the devs in #hedgewars!
+ From time to time there will be official tournaments. Upcoming events will be announced at http://www.hedgewars.org/ some days in advance.
+ Hedgewars is available in many languages. If the translation in your language seems to be missing or outdated, feel free to contact us!
+ Hedgewars can be run on lots of different operating systems including Microsoft Windows, Mac OS X and GNU/Linux.
+ Always remember you're able to set up your own games in local and network/online play. You're not restricted to the 'Simple Game' option.
+ Connect one or more gamepads before starting the game to be able to assign their controls to your teams.
+ Create an account on http://www.hedgewars.org/ to keep others from using your most favourite nickname while playing on the official server.
+ While playing you should give yourself a short break at least once an hour.
+ If your graphics card isn't able to provide hardware accelerated OpenGL, try to enable the low quality mode to improve performance.
+ If your graphics card isn't able to provide hardware accelerated OpenGL, try to update the associated drivers.
+ We're open to suggestions and constructive feedback. If you don't like something or got a great idea, let us know!
+ Especially while playing online be polite and always remember there might be some minors playing with or against you as well!
+ Special game modes such as 'Vampirism' or 'Karma' allow you to develop completely new tactics. Try them in a custom game!
+ You should never install Hedgewars on computers you don't own (school, university, work, etc.). Please ask the responsible person instead!
+ Hedgewars can be perfect for short games during breaks. Just ensure you don't add too many hedgehogs or use an huge map. Reducing time and health might help as well.
+ No hedgehogs were harmed in making this game.
+ There are three different jumps available. Tap [high jump] twice to do a very high/backwards jump.
+ Afraid of falling off a cliff? Hold down [precise] to turn [left] or [right] without actually moving.
+ Some weapons require special strategies or just lots of training, so don't give up on a particular tool if you miss an enemy once.
+ Most weapons won't work once they touch the water. The Homing Bee as well as the Cake are exceptions to this.
+ The Old Limbuger only causes a small explosion. However the wind affected smelly cloud can poison lots of hogs at once.
+ The Piano Strike is the most damaging air strike. You'll lose the hedgehog performing it, so there's a huge downside as well.
+ The Homing Bee can be tricky to use. Its turn radius depends on its velocity, so try to not use full power.
+ Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water.
+ The Hammer is most effective when used on bridges or girders. Hit hogs will just break through the ground.
+ If you're stuck behind an enemy hedgehog, use the Hammer to free yourself without getting damaged by an explosion.
+ The Cake's maximum walking distance depends on the ground it has to pass. Use [attack] to detonate it early.
+ The Flame Thrower is a weapon but it can be used for tunnel digging as well.
+ Use the Molotov or Flame Thrower to temporary keep hedgehogs from passing terrain such as tunnels or platforms.
+ Want to know who's behind the game? Click on the Hedgewars logo in the main menu to see the credits.
+ Like Hedgewars? Become a fan on Facebook or follow us on Twitter
+ Feel free to draw your own graves, hats, flags or even maps and themes! But note that you'll have to share them somewhere to use them online.
+ Keep your video card drivers up to date to avoid issues playing the game.
+ You're able to associate Hedgewars related files (savegames and demo recordings) with the game to launch them right from your favorite file or internet browser.
+
+ The version of Hedgewars supports Xfire. Make sure to add Hedgewars to its game list so your friends can see you playing.
+ You can find your Hedgewars configuration files under "My Documents\Hedgewars". Create backups or take the files with you, but don't edit them by hand.
+
+
+ You can find your Hedgewars configuration files under "Library/Application Support/Hedgewars" in your home directory. Create backups or take the files with you, but don't edit them by hand.
+
+
+ lintip
+ You can find your Hedgewars configuration files under ".hedgewars" in your home directory. Create backups or take the files with you, but don't edit them by hand.
+
+
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/team.cpp
--- a/QTfrontend/team.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/team.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -23,10 +23,12 @@
#include
#include
#include
+#include
#include "team.h"
#include "hwform.h"
#include "DataManager.h"
+#include "gameuiconfig.h"
HWTeam::HWTeam(const QString & teamname) :
QObject(0)
@@ -50,7 +52,7 @@
{
m_binds.append(BindAction());
m_binds[i].action = cbinds[i].action;
- m_binds[i].strbind = cbinds[i].strbind;
+ m_binds[i].strbind = QString();
}
m_rounds = 0;
m_wins = 0;
@@ -110,7 +112,7 @@
{
m_binds.append(BindAction());
m_binds[i].action = cbinds[i].action;
- m_binds[i].strbind = cbinds[i].strbind;
+ m_binds[i].strbind = QString();
}
m_rounds = 0;
m_wins = 0;
@@ -169,7 +171,7 @@
bool HWTeam::loadFromFile()
{
- QSettings teamfile(QString("physfs://config/Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
+ QSettings teamfile(QString("physfs://Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
teamfile.setIniCodec("UTF-8");
m_name = teamfile.value("Team/Name", m_name).toString();
m_grave = teamfile.value("Team/Grave", "Statue").toString();
@@ -191,7 +193,7 @@
m_hedgehogs[i].Suicides = teamfile.value(hh + "Suicides", 0).toInt();
}
for(int i = 0; i < BINDS_NUMBER; i++)
- m_binds[i].strbind = teamfile.value(QString("Binds/%1").arg(m_binds[i].action), cbinds[i].strbind).toString();
+ m_binds[i].strbind = teamfile.value(QString("Binds/%1").arg(m_binds[i].action), QString()).toString();
for(int i = 0; i < MAX_ACHIEVEMENTS; i++)
if(achievements[i][0][0])
AchievementProgress[i] = teamfile.value(QString("Achievements/%1").arg(achievements[i][0]), 0).toUInt();
@@ -202,7 +204,7 @@
bool HWTeam::fileExists()
{
- QFile f(QString("physfs://config/Teams/%1.hwt").arg(m_name));
+ QFile f(QString("physfs://Teams/%1.hwt").arg(m_name));
return f.exists();
}
@@ -210,7 +212,7 @@
{
if(m_isNetTeam)
return false;
- QFile cfgfile(QString("physfs://config/Teams/%1.hwt").arg(m_name));
+ QFile cfgfile(QString("physfs://Teams/%1.hwt").arg(m_name));
cfgfile.remove();
return true;
}
@@ -219,11 +221,14 @@
{
if (OldTeamName != m_name)
{
- QFile cfgfile(QString("physfs://config/Teams/%1.hwt").arg(OldTeamName));
+ QFile cfgfile(QString("physfs://Teams/%1.hwt").arg(OldTeamName));
cfgfile.remove();
OldTeamName = m_name;
}
- QSettings teamfile(QString("physfs://config/Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
+
+ QString fileName = QString("physfs://Teams/%1.hwt").arg(m_name);
+ DataManager::ensureFileExists(fileName);
+ QSettings teamfile(fileName, QSettings::IniFormat, 0);
teamfile.setIniCodec("UTF-8");
teamfile.setValue("Team/Name", m_name);
teamfile.setValue("Team/Grave", m_grave);
@@ -234,6 +239,7 @@
teamfile.setValue("Team/Rounds", m_rounds);
teamfile.setValue("Team/Wins", m_wins);
teamfile.setValue("Team/CampaignProgress", m_campaignProgress);
+
for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
{
QString hh = QString("Hedgehog%1/").arg(i);
@@ -251,10 +257,11 @@
teamfile.setValue(QString("Achievements/%1").arg(achievements[i][0]), AchievementProgress[i]);
else
break;
+
return true;
}
-QStringList HWTeam::teamGameConfig(quint32 InitHealth) const
+QStringList HWTeam::teamGameConfig(quint32 InitHealth, GameUIConfig * config) const
{
QStringList sl;
if (m_isNetTeam)
@@ -270,9 +277,15 @@
sl.push_back(QString("eflag " + m_flag));
if (!m_isNetTeam)
+ {
for(int i = 0; i < BINDS_NUMBER; i++)
- if(!m_binds[i].strbind.isEmpty())
+ {
+ if(m_binds[i].strbind.isEmpty() || m_binds[i].strbind == "default")
+ sl.push_back(QString("ebind " + config->bind(i) + " " + m_binds[i].action));
+ else
sl.push_back(QString("ebind " + m_binds[i].strbind + " " + m_binds[i].action));
+ }
+ }
for (int t = 0; t < m_numHedgehogs; t++)
{
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/team.h
--- a/QTfrontend/team.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/team.h Fri Feb 22 05:05:32 2013 +0100
@@ -93,7 +93,7 @@
void incWins();
// convert team info into strings for further computation
- QStringList teamGameConfig(quint32 InitHealth) const;
+ QStringList teamGameConfig(quint32 InitHealth, GameUIConfig * config) const;
// comparison operators
bool operator == (const HWTeam& t1) const;
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/dialog/bandialog.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/dialog/bandialog.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,89 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "HWApplication.h"
+
+#include "bandialog.h"
+
+BanDialog::BanDialog(QWidget *parent) :
+ QDialog(parent)
+{
+ QFormLayout * formLayout = new QFormLayout(this);
+
+ rbIP = new QRadioButton(this);
+ rbIP->setChecked(true);
+ rbNick = new QRadioButton(this);
+ leId = new QLineEdit(this);
+ leReason = new QLineEdit(this);
+ cbTime = new QComboBox(this);
+
+ cbTime->addItem(HWApplication::tr("%1 minutes", 0, 10).arg("10"), 5 * 60);
+ cbTime->addItem(HWApplication::tr("%1 minutes", 0, 30).arg("30"), 10 * 60);
+ cbTime->addItem(HWApplication::tr("%1 hour", 0, 10).arg("10"), 60 * 60);
+ cbTime->addItem(HWApplication::tr("%1 hours", 0, 3).arg("3"), 3 * 60 * 60);
+ cbTime->addItem(HWApplication::tr("%1 hours", 0, 5).arg("5"), 5 * 60 * 60);
+ cbTime->addItem(HWApplication::tr("%1 hours", 0, 12).arg("12"), 12 * 60 * 60);
+ cbTime->addItem(HWApplication::tr("%1 day", 0, 1).arg("1"), 24 * 60 * 60);
+ cbTime->addItem(HWApplication::tr("%1 days", 0, 3).arg("3"), 72 * 60 * 60);
+ cbTime->addItem(HWApplication::tr("%1 days", 0, 7).arg("7"), 168 * 60 * 60);
+ cbTime->addItem(HWApplication::tr("%1 days", 0, 14).arg("14"), 336 * 60 * 60);
+ cbTime->addItem(tr("permanent"), 3650 * 24 * 60 * 60);
+ cbTime->setCurrentIndex(0);
+
+ formLayout->addRow(tr("IP"), rbIP);
+ formLayout->addRow(tr("Nick"), rbNick);
+ formLayout->addRow(tr("IP/Nick"), leId);
+ formLayout->addRow(tr("Reason"), leReason);
+ formLayout->addRow(tr("Duration"), cbTime);
+
+ formLayout->setLabelAlignment(Qt::AlignRight);
+
+ QHBoxLayout * hbox = new QHBoxLayout();
+ formLayout->addRow(hbox);
+ QPushButton * btnOk = new QPushButton(tr("Ok"), this);
+ QPushButton * btnCancel = new QPushButton(tr("Cancel"), this);
+ hbox->addStretch();
+ hbox->addWidget(btnOk);
+ hbox->addWidget(btnCancel);
+
+ connect(btnOk, SIGNAL(clicked()), this, SLOT(okClicked()));
+ connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+
+ this->setWindowModality(Qt::WindowModal);
+}
+
+bool BanDialog::byIP()
+{
+ return rbIP->isChecked();
+}
+
+int BanDialog::duration()
+{
+ return cbTime->itemData(cbTime->currentIndex()).toInt();
+}
+
+QString BanDialog::banId()
+{
+ return leId->text();
+}
+
+QString BanDialog::reason()
+{
+ return leReason->text().isEmpty() ? tr("you know why") : leReason->text();
+}
+
+void BanDialog::okClicked()
+{
+ if(leId->text().isEmpty())
+ {
+ QMessageBox::warning(this, tr("Warning"), tr("Please, specify %1").arg(byIP() ? tr("IP") : tr("nickname")));
+ return;
+ }
+
+ accept();
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/dialog/bandialog.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/dialog/bandialog.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,32 @@
+#ifndef BANDIALOG_H
+#define BANDIALOG_H
+
+#include
+
+class QComboBox;
+class QRadioButton;
+class QLineEdit;
+
+class BanDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit BanDialog(QWidget *parent = 0);
+
+ bool byIP();
+ int duration();
+ QString banId();
+ QString reason();
+
+private:
+ QRadioButton * rbIP;
+ QRadioButton * rbNick;
+ QLineEdit * leId;
+ QLineEdit * leReason;
+ QComboBox * cbTime;
+
+private slots:
+ void okClicked();
+};
+
+#endif // BANDIALOG_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/dialog/input_password.cpp
--- a/QTfrontend/ui/dialog/input_password.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/dialog/input_password.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -25,28 +25,45 @@
#include "input_password.h"
-HWPasswordDialog::HWPasswordDialog(QWidget* parent, const QString & label) : QDialog(parent)
+HWPasswordDialog::HWPasswordDialog(QWidget* parent) : QDialog(parent)
{
- setWindowTitle(tr("Password"));
+ setWindowTitle(tr("Login"));
+
+ QString titleLabelText = "To connect to the server, please log in.\n\nIf you don't have an account on www.hedgewars.org,\njust enter your nickname.";
+ QString nickLabelText = "Nickname:";
+ QString passLabelText = "Password:";
QGridLayout * layout = new QGridLayout(this);
- QLabel * lbLabel = new QLabel(this);
- lbLabel->setText(label);
- layout->addWidget(lbLabel, 0, 0);
+ QLabel * titleLabel = new QLabel(this);
+ titleLabel->setText(titleLabelText);
+ layout->addWidget(titleLabel, 0, 0);
+
+ QLabel * nickLabel = new QLabel(this);
+ nickLabel->setText(nickLabelText);
+ layout->addWidget(nickLabel, 1, 0);
+
+ leNickname = new QLineEdit(this);
+ leNickname->setEchoMode(QLineEdit::Normal);
+ layout->addWidget(leNickname, 2, 0);
+
+ QLabel * passLabel = new QLabel(this);
+ passLabel->setText(passLabelText);
+ layout->addWidget(passLabel, 3, 0);
lePassword = new QLineEdit(this);
lePassword->setEchoMode(QLineEdit::Password);
- layout->addWidget(lePassword, 1, 0);
+ layout->addWidget(lePassword, 4, 0);
cbSave = new QCheckBox(this);
cbSave->setText(QCheckBox::tr("Save password"));
- layout->addWidget(cbSave, 2, 0);
+ layout->addWidget(cbSave, 5, 0);
QDialogButtonBox* dbbButtons = new QDialogButtonBox(this);
+ pbNewAccount = dbbButtons->addButton(QString("New Account"), QDialogButtonBox::ActionRole);
QPushButton * pbOK = dbbButtons->addButton(QDialogButtonBox::Ok);
QPushButton * pbCancel = dbbButtons->addButton(QDialogButtonBox::Cancel);
- layout->addWidget(dbbButtons, 3, 0);
+ layout->addWidget(dbbButtons, 6, 0);
connect(pbOK, SIGNAL(clicked()), this, SLOT(accept()));
connect(pbCancel, SIGNAL(clicked()), this, SLOT(reject()));
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/dialog/input_password.h
--- a/QTfrontend/ui/dialog/input_password.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/dialog/input_password.h Fri Feb 22 05:05:32 2013 +0100
@@ -23,15 +23,18 @@
class QLineEdit;
class QCheckBox;
+class QPushButton;
class HWPasswordDialog : public QDialog
{
Q_OBJECT
public:
- HWPasswordDialog(QWidget* parent, const QString & label);
+ HWPasswordDialog(QWidget* parent);
QLineEdit* lePassword;
+ QLineEdit* leNickname;
QCheckBox* cbSave;
+ QPushButton * pbNewAccount;
};
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/mouseoverfilter.cpp
--- a/QTfrontend/ui/mouseoverfilter.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/mouseoverfilter.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -39,7 +39,7 @@
QComboBox * droplist = dynamic_cast(dist);
QSlider * slider = dynamic_cast(dist);
QTabWidget * tab = dynamic_cast(dist);
- if (HWForm::config->isFrontendSoundEnabled() && (button || textfield || checkbox || droplist || slider || tab))
+ if (button || textfield || checkbox || droplist || slider || tab)
{
SDLInteraction::instance().playSoundFile("/Sounds/steps.ogg");
}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/AbstractPage.cpp
--- a/QTfrontend/ui/page/AbstractPage.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/AbstractPage.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include "qpushbuttonwithsound.h"
@@ -39,27 +40,36 @@
void AbstractPage::initPage()
{
QGridLayout * pageLayout = new QGridLayout(this);
+ QHBoxLayout * bottomLeftLayout = new QHBoxLayout();
+ pageLayout->addLayout(bottomLeftLayout, 1, 0);
// stretch grid space for body and footer
- pageLayout->setColumnStretch(0,0);
- pageLayout->setColumnStretch(1,1);
+ pageLayout->setColumnStretch(0,1);
+ pageLayout->setColumnStretch(1,2);
+ pageLayout->setColumnStretch(2,1);
pageLayout->setRowStretch(0,1);
pageLayout->setRowStretch(1,0);
// add back/exit button
btnBack = formattedButton(":/res/Exit.png", true);
btnBack->setWhatsThis(tr("Go back"));
- pageLayout->addWidget(btnBack, 1, 0, 1, 1, Qt::AlignLeft | Qt::AlignBottom);
+ bottomLeftLayout->addWidget(btnBack, 0);
// add body layout as defined by the subclass
pageLayout->addLayout(bodyLayoutDefinition(), 0, 0, 1, 3);
+ // add left footer layout
+ QLayout * flld = footerLayoutLeftDefinition();
+ if (flld != NULL)
+ bottomLeftLayout->addLayout(flld, 0);
+
descLabel = new QLabel();
descLabel->setAlignment(Qt::AlignCenter);
descLabel->setWordWrap(true);
descLabel->setOpenExternalLinks(true);
descLabel->setFixedHeight(50);
descLabel->setStyleSheet("font-size: 16px");
+ bottomLeftLayout->addWidget(descLabel);
pageLayout->addWidget(descLabel, 1, 1);
// add footer layout
@@ -67,6 +77,8 @@
if (fld != NULL)
pageLayout->addLayout(fld, 1, 2);
+ bottomLeftLayout->addStretch(1);
+
// connect signals
connect(btnBack, SIGNAL(clicked()), this, SIGNAL(goBack()));
connectSignals();
@@ -156,3 +168,13 @@
{
return defautDesc;
}
+
+void AbstractPage::triggerPageEnter()
+{
+ emit pageEnter();
+}
+
+void AbstractPage::triggerPageLeave()
+{
+ emit pageLeave();
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/AbstractPage.h
--- a/QTfrontend/ui/page/AbstractPage.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/AbstractPage.h Fri Feb 22 05:05:32 2013 +0100
@@ -78,12 +78,35 @@
QString * getDefautDescription();
signals:
+
/**
* @brief This signal is emitted when going back to the previous is
* requested - e.g. when the back-button is clicked.
*/
void goBack();
+ /**
+ * @brief This signal is emitted when the page is displayed
+ */
+ void pageEnter();
+
+ /**
+ * @brief This signal is emitted when this page is left
+ */
+ void pageLeave();
+
+ public slots:
+
+ /**
+ * @brief This slot is called to trigger this page's pageEnter signal
+ */
+ void triggerPageEnter();
+
+ /**
+ * @brief This slot is called to trigger this page's pageLeave signal
+ */
+ void triggerPageLeave();
+
protected:
/**
* @brief Class constructor
@@ -121,6 +144,17 @@
* @brief Used during page construction.
* You can implement this method in your subclass.
*
+ * Use it to define layout (not behavior) of the page's footer to the left of the help text.
+ */
+ virtual QLayout * footerLayoutLeftDefinition()
+ {
+ return NULL;
+ };
+
+ /**
+ * @brief Used during page construction.
+ * You can implement this method in your subclass.
+ *
* This is a good place to connect signals within your page in order
* to get the desired page behavior.
* Keep in mind not to expose twidgets as public!
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pageadmin.cpp
--- a/QTfrontend/ui/page/pageadmin.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pageadmin.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -22,56 +22,98 @@
#include
#include
#include
+#include
+#include
#include "pageadmin.h"
#include "chatwidget.h"
+#include "bandialog.h"
QLayout * PageAdmin::bodyLayoutDefinition()
{
- QGridLayout * pageLayout = new QGridLayout();
-
- // 0
- pbAsk = addButton(tr("Fetch data"), pageLayout, 0, 0, 1, 3);
+ QVBoxLayout * pageLayout = new QVBoxLayout();
- // 1
- QLabel * lblSMN = new QLabel(this);
- lblSMN->setText(tr("Server message for latest version:"));
- pageLayout->addWidget(lblSMN, 1, 0);
+ QTabWidget * tabs = new QTabWidget(this);
+ pageLayout->addWidget(tabs);
+ QWidget * page1 = new QWidget(this);
+ QWidget * page2 = new QWidget(this);
+ tabs->addTab(page1, tr("General"));
+ tabs->addTab(page2, tr("Bans"));
+
+ // page 1
+ {
+ QGridLayout * tab1Layout = new QGridLayout(page1);
+
+ // 0
+ pbAsk = addButton(tr("Fetch data"), tab1Layout, 0, 0, 1, 3);
- leServerMessageNew = new QLineEdit(this);
- pageLayout->addWidget(leServerMessageNew, 1, 1);
+ // 1
+ QLabel * lblSMN = new QLabel(this);
+ lblSMN->setText(tr("Server message for latest version:"));
+ tab1Layout->addWidget(lblSMN, 1, 0);
+
+ leServerMessageNew = new QLineEdit(this);
+ tab1Layout->addWidget(leServerMessageNew, 1, 1);
- // 2
- QLabel * lblSMO = new QLabel(this);
- lblSMO->setText(tr("Server message for previous versions:"));
- pageLayout->addWidget(lblSMO, 2, 0);
+ // 2
+ QLabel * lblSMO = new QLabel(this);
+ lblSMO->setText(tr("Server message for previous versions:"));
+ tab1Layout->addWidget(lblSMO, 2, 0);
+
+ leServerMessageOld = new QLineEdit(this);
+ tab1Layout->addWidget(leServerMessageOld, 2, 1);
- leServerMessageOld = new QLineEdit(this);
- pageLayout->addWidget(leServerMessageOld, 2, 1);
+ // 3
+ QLabel * lblP = new QLabel(this);
+ lblP->setText(tr("Latest version protocol number:"));
+ tab1Layout->addWidget(lblP, 3, 0);
+
+ sbProtocol = new QSpinBox(this);
+ tab1Layout->addWidget(sbProtocol, 3, 1);
- // 3
- QLabel * lblP = new QLabel(this);
- lblP->setText(tr("Latest version protocol number:"));
- pageLayout->addWidget(lblP, 3, 0);
+ // 4
+ QLabel * lblPreview = new QLabel(this);
+ lblPreview->setText(tr("MOTD preview:"));
+ tab1Layout->addWidget(lblPreview, 4, 0);
- sbProtocol = new QSpinBox(this);
- pageLayout->addWidget(sbProtocol, 3, 1);
+ tb = new QTextBrowser(this);
+ tb->setOpenExternalLinks(true);
+ tb->document()->setDefaultStyleSheet(HWChatWidget::styleSheet());
+ tab1Layout->addWidget(tb, 4, 1, 1, 2);
+
+ // 5
+ pbClearAccountsCache = addButton(tr("Clear Accounts Cache"), tab1Layout, 5, 0);
+
+ // 6
+ pbSetSM = addButton(tr("Set data"), tab1Layout, 6, 0, 1, 3);
+ }
- // 4
- QLabel * lblPreview = new QLabel(this);
- lblPreview->setText(tr("MOTD preview:"));
- pageLayout->addWidget(lblPreview, 4, 0);
+ // page 2
+ {
+ QGridLayout * tab2Layout = new QGridLayout(page2);
+ twBans = new QTableWidget(this);
+ twBans->setColumnCount(3);
+ twBans->setHorizontalHeaderLabels(QStringList()
+ << tr("IP/Nick")
+ << tr("Expiration")
+ << tr("Reason")
+ );
+ twBans->horizontalHeader()->setResizeMode(2, QHeaderView::Stretch);
+ twBans->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ twBans->setSelectionBehavior(QAbstractItemView::SelectRows);
+ twBans->setSelectionMode(QAbstractItemView::SingleSelection);
+ twBans->setAlternatingRowColors(true);
+ tab2Layout->addWidget(twBans, 0, 1, 4, 1);
- tb = new QTextBrowser(this);
- tb->setOpenExternalLinks(true);
- tb->document()->setDefaultStyleSheet(HWChatWidget::styleSheet());
- pageLayout->addWidget(tb, 4, 1, 1, 2);
+ QPushButton * btnRefresh = addButton(tr("Refresh"), tab2Layout, 0, 0);
+ QPushButton * btnAdd = addButton(tr("Add"), tab2Layout, 1, 0);
+ QPushButton * btnRemove = addButton(tr("Remove"), tab2Layout, 2, 0);
- // 5
- pbClearAccountsCache = addButton(tr("Clear Accounts Cache"), pageLayout, 5, 0);
-
- // 6
- pbSetSM = addButton(tr("Set data"), pageLayout, 6, 0, 1, 3);
+ connect(btnRefresh, SIGNAL(clicked()), this, SIGNAL(bansListRequest()));
+ connect(btnRefresh, SIGNAL(clicked()), this, SLOT(onRefreshClicked()));
+ connect(btnAdd, SIGNAL(clicked()), this, SLOT(onAddClicked()));
+ connect(btnRemove, SIGNAL(clicked()), this, SLOT(onRemoveClicked()));
+ }
return pageLayout;
}
@@ -106,7 +148,64 @@
{
leServerMessageOld->setText(str);
}
+
void PageAdmin::protocol(int proto)
{
sbProtocol->setValue(proto);
}
+
+void PageAdmin::onAddClicked()
+{
+ BanDialog dialog(this);
+
+ if(dialog.exec())
+ {
+ if(dialog.byIP())
+ {
+ emit banIP(dialog.banId(), dialog.reason(), dialog.duration());
+ } else
+ {
+ emit banNick(dialog.banId(), dialog.reason(), dialog.duration());
+ }
+
+ emit bansListRequest();
+ }
+}
+
+void PageAdmin::onRemoveClicked()
+{
+ QList sel = twBans->selectedItems();
+
+ if(sel.size())
+ {
+ emit removeBan(twBans->item(sel[0]->row(), 0)->data(Qt::DisplayRole).toString());
+ emit bansListRequest();
+ }
+}
+
+void PageAdmin::setBansList(const QStringList & bans)
+{
+ if(bans.size() % 4)
+ return;
+
+ twBans->setRowCount(bans.size() / 4);
+
+ for(int i = 0; i < bans.size(); i += 4)
+ {
+ if(!twBans->item(i / 4, 0))
+ {
+ twBans->setItem(i / 4, 0, new QTableWidgetItem());
+ twBans->setItem(i / 4, 1, new QTableWidgetItem());
+ twBans->setItem(i / 4, 2, new QTableWidgetItem());
+ }
+
+ twBans->item(i / 4, 0)->setData(Qt::DisplayRole, bans[i + 1]);
+ twBans->item(i / 4, 1)->setData(Qt::DisplayRole, bans[i + 3]);
+ twBans->item(i / 4, 2)->setData(Qt::DisplayRole, bans[i + 2]);
+ }
+}
+
+void PageAdmin::onRefreshClicked()
+{
+ twBans->setRowCount(0);
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pageadmin.h
--- a/QTfrontend/ui/page/pageadmin.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pageadmin.h Fri Feb 22 05:05:32 2013 +0100
@@ -21,6 +21,8 @@
#include "AbstractPage.h"
+class QTableWidget;
+
class PageAdmin : public AbstractPage
{
Q_OBJECT
@@ -32,6 +34,7 @@
void serverMessageNew(const QString & str);
void serverMessageOld(const QString & str);
void protocol(int proto);
+ void setBansList(const QStringList & bans);
signals:
void setServerMessageNew(const QString & str);
@@ -39,6 +42,10 @@
void setProtocol(int proto);
void askServerVars();
void clearAccountsCache();
+ void bansListRequest();
+ void removeBan(const QString &);
+ void banIP(const QString & ip, const QString & reason, int seconds);
+ void banNick(const QString & nick, const QString & reason, int seconds);
protected:
QLayout * bodyLayoutDefinition();
@@ -52,9 +59,13 @@
QSpinBox * sbProtocol;
QTextBrowser * tb;
QPushButton * pbClearAccountsCache;
+ QTableWidget * twBans;
private slots:
void smChanged();
+ void onAddClicked();
+ void onRemoveClicked();
+ void onRefreshClicked();
};
#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagedata.cpp
--- a/QTfrontend/ui/page/pagedata.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagedata.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -72,7 +72,7 @@
else
finalUrl = url;
- if(url.path().endsWith(".hwp"))
+ if(url.path().endsWith(".hwp") || url.path().endsWith(".zip"))
{
qWarning() << "Download Request" << url.toString();
QString fileName = QFileInfo(url.toString()).fileName();
@@ -138,6 +138,8 @@
extractDir.cd("Data");
QString fileName = extractDir.filePath(QFileInfo(reply->url().path()).fileName());
+ if(fileName.endsWith(".zip"))
+ fileName = fileName.left(fileName.length() - 4) + ".hwp";
QFile out(fileName);
if(!out.open(QFile::WriteOnly))
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pageeditteam.cpp
--- a/QTfrontend/ui/page/pageeditteam.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pageeditteam.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -30,25 +30,26 @@
#include
#include "SquareLabel.h"
#include "HWApplication.h"
+#include "keybinder.h"
#include "DataManager.h"
-#include "HatModel.h"
+#include "hatbutton.h"
#include "pageeditteam.h"
QLayout * PageEditTeam::bodyLayoutDefinition()
{
QGridLayout * pageLayout = new QGridLayout();
- QTabWidget * tbw = new QTabWidget();
+ tbw = new QTabWidget();
QWidget * page1 = new QWidget(this);
- QWidget * page2 = new QWidget(this);
+ binder = new KeyBinder(this, tr("Select an action to choose a custom key bind for this team"), tr("Use my default"), tr("Reset all binds"));
+ connect(binder, SIGNAL(resetAllBinds()), this, SLOT(resetAllBinds()));
tbw->addTab(page1, tr("General"));
- tbw->addTab(page2, tr("Advanced"));
+ tbw->addTab(binder, tr("Custom Controls"));
pageLayout->addWidget(tbw, 0, 0, 1, 3);
QHBoxLayout * page1Layout = new QHBoxLayout(page1);
page1Layout->setAlignment(Qt::AlignTop);
- QGridLayout * page2Layout = new QGridLayout(page2);
// ====== Page 1 ======
QVBoxLayout * vbox1 = new QVBoxLayout();
@@ -61,27 +62,33 @@
GBoxHedgehogs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QGridLayout * GBHLayout = new QGridLayout(GBoxHedgehogs);
- HatModel * hatModel = DataManager::instance().hatModel();
+
+ GBHLayout->addWidget(new QLabel(tr("Hat")), 0, 0);
+ GBHLayout->addWidget(new QLabel(tr("Name")), 0, 1);
for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
{
- HHHats[i] = new QComboBox(GBoxHedgehogs);
- HHHats[i]->setModel(hatModel);
- HHHats[i]->setIconSize(QSize(32, 37));
- //HHHats[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
- //HHHats[i]->setModelColumn(1);
- //HHHats[i]->setMinimumWidth(132);
- GBHLayout->addWidget(HHHats[i], i, 0);
+ HHHats[i] = new HatButton(GBoxHedgehogs);
+ GBHLayout->addWidget(HHHats[i], i + 1, 0);
HHNameEdit[i] = new QLineEdit(GBoxHedgehogs);
HHNameEdit[i]->setMaxLength(64);
HHNameEdit[i]->setMinimumWidth(120);
- GBHLayout->addWidget(HHNameEdit[i], i, 1);
+ HHNameEdit[i]->setFixedHeight(36);
+ HHNameEdit[i]->setWhatsThis(tr("This hedgehog's name"));
+ HHNameEdit[i]->setStyleSheet("padding: 6px;");
+ GBHLayout->addWidget(HHNameEdit[i], i + 1, 1);
- btnRandomHogName[i] = addButton(":/res/dice.png", GBHLayout, i, 3, 1, 1, true);
+ btnRandomHogName[i] = addButton(":/res/dice.png", GBHLayout, i + 1, 3, 1, 1, true);
+ btnRandomHogName[i]->setFixedHeight(HHNameEdit[i]->height());
+ btnRandomHogName[i]->setWhatsThis(tr("Randomize this hedgehog's name"));
}
- btnRandomTeam = addButton(QPushButton::tr("Random Team"), GBHLayout, 9, 0);
+ btnRandomTeam = new QPushButton();
+ btnRandomTeam->setText(tr("Random Team"));
+ btnRandomTeam->setStyleSheet("padding: 6px 10px;");
+ GBHLayout->addWidget(btnRandomTeam, 9, 0, 1, 4, Qt::AlignCenter);
+ btnRandomTeam->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
vbox1->addWidget(GBoxHedgehogs);
@@ -157,52 +164,6 @@
vbox1->addStretch();
vbox2->addStretch();
-// ====== Page 2 ======
- GBoxBinds = new QGroupBox(this);
- GBoxBinds->setTitle(QGroupBox::tr("Key binds"));
- QGridLayout * GBBLayout = new QGridLayout(GBoxBinds);
- BindsBox = new QToolBox(GBoxBinds);
- BindsBox->setLineWidth(0);
- GBBLayout->addWidget(BindsBox);
- page2Layout->addWidget(GBoxBinds, 0, 0);
-
- quint16 i = 0;
- quint16 num = 0;
- QWidget * curW = NULL;
- QGridLayout * pagelayout = NULL;
- QLabel* l = NULL;
- while (i < BINDS_NUMBER)
- {
- if(cbinds[i].category != NULL)
- {
- if(curW != NULL)
- {
- l = new QLabel(curW);
- l->setText("");
- pagelayout->addWidget(l, num++, 0, 1, 2);
- }
- curW = new QWidget(this);
- BindsBox->addItem(curW, HWApplication::translate("binds (categories)", cbinds[i].category));
- pagelayout = new QGridLayout(curW);
- num = 0;
- }
- if(cbinds[i].description != NULL)
- {
- l = new QLabel(curW);
- l->setText((num > 0 ? QString("\n") : QString("")) + HWApplication::translate("binds (descriptions)", cbinds[i].description));
- pagelayout->addWidget(l, num++, 0, 1, 2);
- }
-
- l = new QLabel(curW);
- l->setText(HWApplication::translate("binds", cbinds[i].name));
- l->setAlignment(Qt::AlignRight);
- pagelayout->addWidget(l, num, 0);
-
- CBBind[i] = new QComboBox(curW);
- CBBind[i]->setModel(DataManager::instance().bindsModel());
- pagelayout->addWidget(CBBind[i++], num++, 1);
- }
-
return pageLayout;
}
@@ -213,7 +174,7 @@
void PageEditTeam::connectSignals()
{
- connect(this, SIGNAL(goBack()), this, SLOT(saveTeam()));
+ connect(this, SIGNAL(pageLeave()), this, SLOT(saveTeam()));
signalMapper1 = new QSignalMapper(this);
signalMapper2 = new QSignalMapper(this);
@@ -407,6 +368,9 @@
void PageEditTeam::loadTeam(const HWTeam & team)
{
+ tbw->setCurrentIndex(0);
+ binder->resetInterface();
+
TeamNameEdit->setText(team.name());
CBTeamLvl->setCurrentIndex(team.difficulty());
@@ -419,7 +383,7 @@
if (hh.Hat.startsWith("Reserved"))
hh.Hat = "Reserved "+hh.Hat.remove(0,40);
- HHHats[i]->setCurrentIndex(HHHats[i]->findData(hh.Hat, Qt::DisplayRole));
+ HHHats[i]->setCurrentHat(hh.Hat);
}
CBGrave->setCurrentIndex(CBGrave->findText(team.grave()));
@@ -431,10 +395,12 @@
QStandardItemModel * binds = DataManager::instance().bindsModel();
for(int i = 0; i < BINDS_NUMBER; i++)
{
+ if (team.keyBind(i).isEmpty()) continue;
+
QModelIndexList mdl = binds->match(binds->index(0, 0), Qt::UserRole + 1, team.keyBind(i), 1, Qt::MatchExactly);
if(mdl.size() == 1)
- CBBind[i]->setCurrentIndex(mdl[0].row());
+ binder->setBindIndex(i, mdl[0].row());
else
qDebug() << "Binds: cannot find" << team.keyBind(i);
}
@@ -449,7 +415,7 @@
{
HWHog hh;
hh.Name = HHNameEdit[i]->text();
- hh.Hat = HHHats[i]->currentText();
+ hh.Hat = HHHats[i]->currentHat();
if (hh.Hat.startsWith("Reserved"))
hh.Hat = "Reserved"+m_playerHash+hh.Hat.remove(0,9);
@@ -465,7 +431,7 @@
QStandardItemModel * binds = DataManager::instance().bindsModel();
for(int i = 0; i < BINDS_NUMBER; i++)
{
- team.bindKey(i, binds->index(CBBind[i]->currentIndex(), 0).data(Qt::UserRole + 1).toString());
+ team.bindKey(i, binds->index(binder->bindIndex(i), 0).data(Qt::UserRole + 1).toString());
}
return team;
@@ -475,3 +441,10 @@
{
data().saveToFile();
}
+
+// When the "Use default for all binds" is pressed...
+void PageEditTeam::resetAllBinds()
+{
+ for (int i = 0; i < BINDS_NUMBER; i++)
+ binder->setBindIndex(i, 0);
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pageeditteam.h
--- a/QTfrontend/ui/page/pageeditteam.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pageeditteam.h Fri Feb 22 05:05:32 2013 +0100
@@ -28,6 +28,8 @@
#include "team.h"
class SquareLabel;
+class KeyBinder;
+class HatButton;
class PageEditTeam : public AbstractPage
{
@@ -44,6 +46,7 @@
void CBFort_activated(const QString & gravename);
private:
+ QTabWidget * tbw;
QSignalMapper* signalMapper1;
QSignalMapper* signalMapper2;
QGroupBox *GBoxHedgehogs;
@@ -59,10 +62,10 @@
QToolBox *BindsBox;
QLineEdit * TeamNameEdit;
QLineEdit * HHNameEdit[HEDGEHOGS_PER_TEAM];
- QComboBox * HHHats[HEDGEHOGS_PER_TEAM];
- QComboBox * CBBind[BINDS_NUMBER];
+ HatButton * HHHats[HEDGEHOGS_PER_TEAM];
HWTeam data();
QString m_playerHash;
+ KeyBinder * binder;
QLayout * bodyLayoutDefinition();
QLayout * footerLayoutDefinition();
@@ -85,6 +88,7 @@
void testSound();
void fixHHname(int idx);
+ void resetAllBinds();
};
#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagefeedback.cpp
--- a/QTfrontend/ui/page/pagefeedback.cpp Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include
-#include
-#include
-#include
-
-#include "pagefeedback.h"
-#include "hwconsts.h"
-
-QLayout * PageFeedback::bodyLayoutDefinition()
-{
- QVBoxLayout * pageLayout = new QVBoxLayout();
- QHBoxLayout * summaryLayout = new QHBoxLayout();
-
- info = new QLabel();
- info->setText(
- ""
- "Please give us a feedback!
"
- "We are always happy about suggestions, ideas or bug reports."
- "The feedback will be posted as a new issue on our Google Code page."
- "
"
- );
- pageLayout->addWidget(info);
-
- label_summary = new QLabel();
- label_summary->setText(QLabel::tr("Summary "));
- summaryLayout->addWidget(label_summary);
- summary = new QLineEdit();
- summaryLayout->addWidget(summary);
- pageLayout->addLayout(summaryLayout);
-
- label_description = new QLabel();
- label_description->setText(QLabel::tr("Description"));
- pageLayout->addWidget(label_description, 0, Qt::AlignHCenter);
- description = new QTextBrowser();
- description->setReadOnly(false);
- pageLayout->addWidget(description);
-
- return pageLayout;
-}
-
-QLayout * PageFeedback::footerLayoutDefinition()
-{
- QHBoxLayout * bottomLayout = new QHBoxLayout();
-
- bottomLayout->setStretch(0,1);
- //TODO: create logo for send button
- BtnSend = addButton("Send", bottomLayout, 0, false);
- bottomLayout->insertStretch(0);
-
- return bottomLayout;
-}
-
-void PageFeedback::connectSignals()
-{
- //TODO
-}
-
-PageFeedback::PageFeedback(QWidget* parent) : AbstractPage(parent)
-{
- initPage();
-
-}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagefeedback.h
--- a/QTfrontend/ui/page/pagefeedback.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef PAGE_FEEDBACK_H
-#define PAGE_FEEDBACK_H
-
-#include "AbstractPage.h"
-
-class PageFeedback : public AbstractPage
-{
- Q_OBJECT
-
- public:
- PageFeedback(QWidget * parent = 0);
-
- QPushButton * BtnSend;
- QLineEdit * summary;
- QTextBrowser * description;
- QLabel * info;
- QLabel * label_summary;
- QLabel * label_description;
-
- private:
- QLayout * bodyLayoutDefinition();
- QLayout * footerLayoutDefinition();
- void connectSignals();
-};
-
-#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagegamestats.cpp
--- a/QTfrontend/ui/page/pagegamestats.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagegamestats.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -110,6 +110,7 @@
void PageGameStats::connectSignals()
{
+ connect(this, SIGNAL(pageEnter()), this, SLOT(renderStats()));
connect(btnSave, SIGNAL(clicked()), this, SIGNAL(saveDemoRequested()));
}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagemain.cpp
--- a/QTfrontend/ui/page/pagemain.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagemain.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -42,30 +42,48 @@
pageLayout->setRowStretch(4, 1);
BtnSinglePlayer = addButton(":/res/LocalPlay.png", pageLayout, 2, 0, 1, 2, true);
- BtnSinglePlayer->setToolTip(tr("Local Game"));
BtnSinglePlayer->setWhatsThis(tr("Play a game on a single computer"));
pageLayout->setAlignment(BtnSinglePlayer, Qt::AlignHCenter);
+ //BtnNet = addButton(":/res/NetworkPlay.png", (QBoxLayout*)netLayout, 1, true);
BtnNet = addButton(":/res/NetworkPlay.png", pageLayout, 2, 2, 1, 2, true);
- BtnNet->setToolTip(tr("Network Game"));
BtnNet->setWhatsThis(tr("Play a game across a network"));
pageLayout->setAlignment(BtnNet, Qt::AlignHCenter);
+ originalNetworkIcon = BtnNet->icon();
+ disabledNetworkIcon = QIcon(":/res/NetworkPlayDisabled.png");
+
+ //QWidget *netLayoutWidget = new QWidget();
+ QVBoxLayout *netLayout = new QVBoxLayout(BtnNet);
+ //pageLayout->addWidget(netLayoutWidget, 2, 2, 1, 2);
+ //netLayoutWidget->setStyleSheet("background: green;");
+ //netLayoutWidget->setFixedSize(314, 260);
+ netLayout->setSpacing(20);
+ netLayout->setAlignment(Qt::AlignHCenter);
+
+ BtnNetLocal = addButton("Play local network game", (QBoxLayout*)netLayout, 0, false);
+ BtnNetLocal->setWhatsThis(tr("Play a game across a local area network"));
+ BtnNetLocal->setFixedSize(BtnNet->width() - 50, 60);
+ BtnNetLocal->setVisible(false);
+
+ BtnNetOfficial = addButton("Play official network game", (QBoxLayout*)netLayout, 0, false);
+ BtnNetOfficial->setWhatsThis(tr("Play a game on an official server"));
+ BtnNetOfficial->setFixedSize(BtnNet->width() - 50, 60);
+ BtnNetOfficial->setVisible(false);
+
// button order matters for overlapping (what's on top and what isn't)
BtnInfo = addButton(":/res/HedgewarsTitle.png", pageLayout, 0, 0, 1, 4, true);
BtnInfo->setStyleSheet("border: transparent;background: transparent;");
- //BtnInfo->setToolTip(tr("Credits")); //tooltip looks horrible with transparent background buttons
BtnInfo->setWhatsThis(tr("Read about who is behind the Hedgewars Project"));
pageLayout->setAlignment(BtnInfo, Qt::AlignHCenter);
-#if 0
BtnFeedback = addButton("Feedback", pageLayout, 4, 0, 1, 4, false);
+ BtnFeedback->setFixedSize(86, 27);
BtnFeedback->setWhatsThis(tr("Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars"));
pageLayout->setAlignment(BtnFeedback, Qt::AlignHCenter);
-#endif
BtnDataDownload = addButton(tr("Downloadable Content"), pageLayout, 5, 0, 1, 4, false);
- //BtnDataDownload->setToolTip(tr(Downloadable Content"));
+ BtnDataDownload->setFixedSize(176, 27);
BtnDataDownload->setWhatsThis(tr("Access the user created content downloadable from our website"));
pageLayout->setAlignment(BtnDataDownload, Qt::AlignHCenter);
@@ -101,7 +119,8 @@
void PageMain::connectSignals()
{
- //TODO
+ connect(BtnNet, SIGNAL(clicked()), this, SLOT(toggleNetworkChoice()));
+ // TODO: add signal-forwarding required by (currently missing) encapsulation
}
PageMain::PageMain(QWidget* parent) : AbstractPage(parent)
@@ -117,70 +136,56 @@
}
else
{
- setDefautDescription(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!"));
+ setDefautDescription(QLabel::tr("This development build is 'work in progress' and may not be compatible with other versions of the game, while some features might be broken or incomplete!"));
}
}
QString PageMain::randomTip() const
{
+#ifdef _WIN32
+ int platform = 1;
+#elif defined __APPLE__
+ int platform = 2;
+#else
+ int platform = 3;
+#endif
QStringList Tips;
- Tips << tr("Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together.", "Tips");
- Tips << tr("Some weapons might do only low damage but they can be a lot more devastating in the right situation. Try to use the Desert Eagle to knock multiple hedgehogs into the water.", "Tips");
- Tips << tr("If you're unsure what to do and don't want to waste ammo, skip one round. But don't let too much time pass as there will be Sudden Death!", "Tips");
- Tips << tr("Want to save ropes? Release the rope in mid air and then shoot again. As long as you don't touch the ground you'll reuse your rope without wasting ammo!", "Tips");
- Tips << tr("If you'd like to keep others from using your preferred nickname on the official server, register an account at http://www.hedgewars.org/.", "Tips");
- Tips << tr("You're bored of default gameplay? Try one of the missions - they'll offer different gameplay depending on the one you picked.", "Tips");
- Tips << tr("By default the game will always record the last game played as a demo. Select 'Local Game' and pick the 'Demos' button on the lower right corner to play or manage them.", "Tips");
- Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. If you've got problems, ask on our forums but please don't expect 24/7 support!", "Tips");
- Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. If you like it, help us with a small donation or contribute your own work!", "Tips");
- Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. Share it with your family and friends as you like!", "Tips");
- Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. If someone sold you the game, you should try get a refund!", "Tips");
- Tips << tr("From time to time there will be official tournaments. Upcoming events will be announced at http://www.hedgewars.org/ some days in advance.", "Tips");
- Tips << tr("Hedgewars is available in many languages. If the translation in your language seems to be missing or outdated, feel free to contact us!", "Tips");
- Tips << tr("Hedgewars can be run on lots of different operating systems including Microsoft Windows, Mac OS X and Linux.", "Tips");
- Tips << tr("Always remember you're able to set up your own games in local and network/online play. You're not restricted to the 'Simple Game' option.", "Tips");
- Tips << tr("Connect one or more gamepads before starting the game to be able to assign their controls to your teams.", "Tips");
- Tips << tr("Create an account on %1 to keep others from using your most favourite nickname while playing on the official server.", "Tips").arg("http://www.hedgewars.org/");
- Tips << tr("While playing you should give yourself a short break at least once an hour.", "Tips");
- Tips << tr("If your graphics card isn't able to provide hardware accelerated OpenGL, try to enable the low quality mode to improve performance.", "Tips");
- Tips << tr("If your graphics card isn't able to provide hardware accelerated OpenGL, try to update the associated drivers.", "Tips");
- Tips << tr("We're open to suggestions and constructive feedback. If you don't like something or got a great idea, let us know!", "Tips");
- Tips << tr("Especially while playing online be polite and always remember there might be some minors playing with or against you as well!", "Tips");
- Tips << tr("Special game modes such as 'Vampirism' or 'Karma' allow you to develop completely new tactics. Try them in a custom game!", "Tips");
- Tips << tr("The Windows version of Hedgewars supports Xfire. Make sure to add Hedgewars to its game list so your friends can see you playing.", "Tips");
- Tips << tr("You should never install Hedgewars on computers you don't own (school, university, work, etc.). Please ask the responsible person instead!", "Tips");
- Tips << tr("Hedgewars can be perfect for short games during breaks. Just ensure you don't add too many hedgehogs or use an huge map. Reducing time and health might help as well.", "Tips");
- Tips << tr("No hedgehogs were harmed in making this game.", "Tips");
- Tips << tr("There are three different jumps available. Tap [high jump] twice to do a very high/backwards jump.", "Tips");
- Tips << tr("Afraid of falling off a cliff? Hold down [precise] to turn [left] or [right] without actually moving.", "Tips");
- Tips << tr("Some weapons require special strategies or just lots of training, so don't give up on a particular tool if you miss an enemy once.", "Tips");
- Tips << tr("Most weapons won't work once they touch the water. The Homing Bee as well as the Cake are exceptions to this.", "Tips");
- Tips << tr("The Old Limbuger only causes a small explosion. However the wind affected smelly cloud can poison lots of hogs at once.", "Tips");
- Tips << tr("The Piano Strike is the most damaging air strike. You'll lose the hedgehog performing it, so there's a huge downside as well.", "Tips");
- Tips << tr("The Homing Bee can be tricky to use. Its turn radius depends on its velocity, so try to not use full power.", "Tips");
- Tips << tr("Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water.", "Tips");
- Tips << tr("The Hammer is most effective when used on bridges or girders. Hit hogs will just break through the ground.", "Tips");
- Tips << tr("If you're stuck behind an enemy hedgehog, use the Hammer to free yourself without getting damaged by an explosion.", "Tips");
- Tips << tr("The Cake's maximum walking distance depends on the ground it has to pass. Use [attack] to detonate it early.", "Tips");
- Tips << tr("The Flame Thrower is a weapon but it can be used for tunnel digging as well.", "Tips");
- Tips << tr("Use the Molotov or Flame Thrower to temporary keep hedgehogs from passing terrain such as tunnels or platforms.", "Tips");
- Tips << tr("Want to know who's behind the game? Click on the Hedgewars logo in the main menu to see the credits.", "Tips");
- Tips << tr("Like Hedgewars? Become a fan on %1 or follow us on %2!", "Tips").arg("Facebook").arg("Twitter");
- Tips << tr("Feel free to draw your own graves, hats, flags or even maps and themes! But note that you'll have to share them somewhere to use them online.", "Tips");
- Tips << tr("Really want to wear a specific hat? Donate to us and receive an exclusive hat of your choice!", "Tips");
+ QFile file(":/res/xml/tips.xml");
+ file.open(QIODevice::ReadOnly);
+ QTextStream in(&file);
+ QString line = in.readLine();
+ int tip_platform = 0;
+ while (!line.isNull()) {
+ if(line.contains("", Qt::CaseSensitive))
+ tip_platform = 1;
+ if(line.contains("", Qt::CaseSensitive))
+ tip_platform = 2;
+ if(line.contains("", Qt::CaseSensitive))
+ tip_platform = 3;
+ if(line.contains("", Qt::CaseSensitive) ||
+ line.contains("", Qt::CaseSensitive) ||
+ line.contains("", Qt::CaseSensitive)) {
+ tip_platform = 0;
+ }
+ QStringList split_string = line.split(QRegExp("?tip>"));
+ if((tip_platform == platform || tip_platform == 0) && split_string.size() != 1)
+ Tips << tr(split_string[1].toLatin1().data(), "Tips");
+ line = in.readLine();
+ }
// The following tip will require links to app store entries first.
//Tips << tr("Want to play Hedgewars any time? Grab the Mobile version for %1 and %2.", "Tips").arg("").arg("");
// the ios version is located here: http://itunes.apple.com/us/app/hedgewars/id391234866
- Tips << tr("Keep your video card drivers up to date to avoid issues playing the game.", "Tips");
- Tips << tr("You're able to associate Hedgewars related files (savegames and demo recordings) with the game to launch them right from your favorite file or internet browser.", "Tips");
-#ifdef _WIN32
- Tips << tr("You can find your Hedgewars configuration files under \"My Documents\\Hedgewars\". Create backups or take the files with you, but don't edit them by hand.", "Tips");
-#elif defined __APPLE__
- Tips << tr("You can find your Hedgewars configuration files under \"Library/Application Support/Hedgewars\" in your home directory. Create backups or take the files with you, but don't edit them by hand.", "Tips");
-#else
- Tips << tr("You can find your Hedgewars configuration files under \".hedgewars\" in your home directory. Create backups or take the files with you, but don't edit them by hand.", "Tips");
-#endif
+ file.close();
return Tips[QTime(0, 0, 0).secsTo(QTime::currentTime()) % Tips.length()];
}
+
+void PageMain::toggleNetworkChoice()
+{
+ bool visible = BtnNetLocal->isVisible();
+ BtnNetLocal->setVisible(!visible);
+ BtnNetOfficial->setVisible(!visible);
+ if (visible) BtnNet->setIcon(originalNetworkIcon);
+ else BtnNet->setIcon(disabledNetworkIcon);
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagemain.h
--- a/QTfrontend/ui/page/pagemain.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagemain.h Fri Feb 22 05:05:32 2013 +0100
@@ -21,15 +21,19 @@
#include "AbstractPage.h"
+class QIcon;
+
class PageMain : public AbstractPage
{
- Q_OBJECT
+ Q_OBJECT
public:
PageMain(QWidget * parent = 0);
QPushButton * BtnSinglePlayer;
QPushButton * BtnNet;
+ QPushButton * BtnNetLocal;
+ QPushButton * BtnNetOfficial;
QPushButton * BtnSetup;
QPushButton * BtnFeedback;
QPushButton * BtnInfo;
@@ -41,8 +45,12 @@
QLayout * bodyLayoutDefinition();
QLayout * footerLayoutDefinition();
void connectSignals();
+ QIcon originalNetworkIcon, disabledNetworkIcon;
QString randomTip() const;
+
+ private slots:
+ void toggleNetworkChoice();
};
#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagemultiplayer.cpp
--- a/QTfrontend/ui/page/pagemultiplayer.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagemultiplayer.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -36,10 +36,6 @@
gameCFG = new GameCFGWidget(this);
pageLayout->addWidget(gameCFG, 0, 0, 1, 2);
- btnSetup = new QPushButton(this);
- btnSetup->setText(QPushButton::tr("Setup"));
- pageLayout->addWidget(btnSetup, 1, 0, 1, 2);
-
pageLayout->setRowStretch(2, 1);
teamsSelect = new TeamSelWidget(this);
@@ -48,12 +44,30 @@
return pageLayout;
}
+QLayout * PageMultiplayer::footerLayoutLeftDefinition()
+{
+ QHBoxLayout * bottomLeftLayout = new QHBoxLayout();
+
+ btnSetup = addButton(":/res/Settings.png", bottomLeftLayout, 0, true);
+ btnSetup->setWhatsThis(tr("Edit game preferences"));
+
+ return bottomLeftLayout;
+}
+
QLayout * PageMultiplayer::footerLayoutDefinition()
{
QHBoxLayout * footerLayout = new QHBoxLayout();
- BtnStartMPGame = formattedButton(tr("Start"));
- BtnStartMPGame->setMinimumWidth(180);
+ const QIcon& lp = QIcon(":/res/Start.png");
+ QSize sz = lp.actualSize(QSize(65535, 65535));
+ BtnStartMPGame = new QPushButton();
+ BtnStartMPGame->setText(tr("Start"));
+ BtnStartMPGame->setMinimumWidth(sz.width() + 60);
+ BtnStartMPGame->setIcon(lp);
+ BtnStartMPGame->setFixedHeight(50);
+ BtnStartMPGame->setIconSize(sz);
+ BtnStartMPGame->setFlat(true);
+ BtnStartMPGame->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
footerLayout->addStretch();
footerLayout->addWidget(BtnStartMPGame);
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagemultiplayer.h
--- a/QTfrontend/ui/page/pagemultiplayer.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagemultiplayer.h Fri Feb 22 05:05:32 2013 +0100
@@ -41,6 +41,7 @@
private:
QLayout * bodyLayoutDefinition();
QLayout * footerLayoutDefinition();
+ QLayout * footerLayoutLeftDefinition();
void connectSignals();
QPushButton * btnSetup;
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagenetgame.cpp
--- a/QTfrontend/ui/page/pagenetgame.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagenetgame.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -22,69 +22,130 @@
#include
#include
#include
+#include
#include "pagenetgame.h"
#include "gamecfgwidget.h"
#include "teamselect.h"
#include "chatwidget.h"
+const int cutoffHeight = 688; /* Don't make this number below 605, or else it'll
+ let the GameCFGWidget shrink too much before switching to tabbed mode. */
+
QLayout * PageNetGame::bodyLayoutDefinition()
{
QGridLayout * pageLayout = new QGridLayout();
pageLayout->setSizeConstraint(QLayout::SetMinimumSize);
- //pageLayout->setSpacing(1);
- pageLayout->setColumnStretch(0, 50);
- pageLayout->setColumnStretch(1, 50);
+ pageLayout->setColumnStretch(0, 1);
+ pageLayout->setColumnStretch(1, 1);
+ pageLayout->setRowStretch(0, 0);
+ pageLayout->setRowStretch(1, 0);
+ pageLayout->setRowStretch(2, 1);
+
+ // Room config
+
+ QHBoxLayout * roomConfigLayout = new QHBoxLayout();
+ pageLayout->addLayout(roomConfigLayout, 0, 0, 1, 2);
+ roomConfigLayout->setSpacing(0);
+
+ leRoomName = new HistoryLineEdit(this, 10);
+ leRoomName->setMaxLength(60);
+ leRoomName->setMinimumWidth(400);
+ leRoomName->setMaximumWidth(600);
+ leRoomName->setFixedHeight(30);
+ leRoomName->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ leRoomName->setStyleSheet("border-right: 0; padding-left: 4px; border-top-right-radius: 0px; border-bottom-right-radius: 0px;");
+ roomConfigLayout->addWidget(leRoomName, 100);
- // chatwidget
- pChatWidget = new HWChatWidget(this, m_gameSettings, true);
- pChatWidget->setShowFollow(false); // don't show follow in nicks' context menus
- pChatWidget->setIgnoreListKick(true); // kick ignored players automatically
- pageLayout->addWidget(pChatWidget, 2, 0, 1, 2);
- pageLayout->setRowStretch(1, 100);
- pageLayout->setRowStretch(2, 100);
+ BtnUpdate = new QPushButton();
+ BtnUpdate->setEnabled(false);
+ BtnUpdate->setText(tr("Update"));
+ BtnUpdate->setFixedHeight(leRoomName->height() - 0);
+ BtnUpdate->setStyleSheet("border-top-left-radius: 0px; border-bottom-left-radius: 0px; padding: auto 4px;");
+ roomConfigLayout->addWidget(BtnUpdate, 0);
+
+ lblRoomNameReadOnly = new QLabel();
+ lblRoomNameReadOnly->setMinimumWidth(400);
+ lblRoomNameReadOnly->setMaximumWidth(600);
+ lblRoomNameReadOnly->setFixedHeight(30);
+ lblRoomNameReadOnly->setObjectName("labelLikeLineEdit");
+ lblRoomNameReadOnly->setStyleSheet("font: 12px;");
+ lblRoomNameReadOnly->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ lblRoomNameReadOnly->setVisible(false);
+ roomConfigLayout->addWidget(lblRoomNameReadOnly, 100);
+
+ roomConfigLayout->addSpacing(10);
+
+ BtnMaster = new QPushButton();
+ BtnMaster->setText(tr("Room controls"));
+ BtnMaster->setFixedHeight(leRoomName->height() - 0);
+ BtnMaster->setStyleSheet("QPushButton { padding: auto 4px; } QPushButton:pressed { background-color: #ffcc00; border-color: #ffcc00; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; color: #11084A; }");
+ roomConfigLayout->addWidget(BtnMaster, 0);
+
+ roomConfigLayout->addStretch(1);
+
+ // Game config
pGameCFG = new GameCFGWidget(this);
- pageLayout->addWidget(pGameCFG, 0, 0);
+ pageLayout->addWidget(pGameCFG, 1, 0);
- btnSetup = new QPushButton(this);
- btnSetup->setText(QPushButton::tr("Setup"));
- pageLayout->addWidget(btnSetup, 1, 0);
+ // Teams
pNetTeamsWidget = new TeamSelWidget(this);
pNetTeamsWidget->setAcceptOuter(true);
- pageLayout->addWidget(pNetTeamsWidget, 0, 1, 2, 1);
+ pNetTeamsWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ pageLayout->addWidget(pNetTeamsWidget, 1, 1);
+
+ // Chat
+
+ chatWidget = new HWChatWidget(this, true);
+ chatWidget->setShowFollow(false); // don't show follow in nicks' context menus
+ chatWidget->setIgnoreListKick(true); // kick ignored players automatically
+ chatWidget->setMinimumHeight(50);
+ chatWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ pageLayout->addWidget(chatWidget, 2, 0, 1, 2);
return pageLayout;
}
+QLayout * PageNetGame::footerLayoutLeftDefinition()
+{
+ QHBoxLayout * bottomLeftLayout = new QHBoxLayout();
+
+ btnSetup = addButton(":/res/Settings.png", bottomLeftLayout, 0, true);
+ btnSetup->setWhatsThis(tr("Edit game preferences"));
+
+ return bottomLeftLayout;
+}
+
QLayout * PageNetGame::footerLayoutDefinition()
{
QHBoxLayout * bottomLayout = new QHBoxLayout;
- leRoomName = new HistoryLineEdit(this,10);
- leRoomName->setMaxLength(60);
- leRoomName->setMinimumWidth(200);
- leRoomName->setMaximumWidth(400);
+ // Ready button
- //Button to signify whether the player is ready to start playing
BtnGo = new QPushButton(this);
- BtnGo->setToolTip(QPushButton::tr("Ready"));
BtnGo->setIcon(QIcon(":/res/lightbulb_off.png"));
BtnGo->setIconSize(QSize(25, 34));
BtnGo->setMinimumWidth(50);
BtnGo->setMinimumHeight(50);
- bottomLayout->addWidget(leRoomName);
- BtnUpdate = addButton(QAction::tr("Update"), bottomLayout, 1);
-
bottomLayout->addStretch();
bottomLayout->addWidget(BtnGo);
- BtnMaster = addButton(tr("Control"), bottomLayout, 3);
- bottomLayout->insertStretch(3, 100);
+ // Start button
- BtnStart = addButton(QAction::tr("Start"), bottomLayout, 3);
+ const QIcon& lp = QIcon(":/res/Start.png");
+ QSize sz = lp.actualSize(QSize(65535, 65535));
+ BtnStart = new QPushButton();
+ BtnStart->setText(tr("Start"));
+ BtnStart->setMinimumWidth(sz.width() + 60);
+ BtnStart->setIcon(lp);
+ BtnStart->setFixedHeight(50);
+ BtnStart->setIconSize(sz);
+ BtnStart->setFlat(true);
+ BtnStart->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ bottomLayout->addWidget(BtnStart);
return bottomLayout;
}
@@ -94,12 +155,13 @@
connect(btnSetup, SIGNAL(clicked()), this, SIGNAL(SetupClicked()));
connect(BtnUpdate, SIGNAL(clicked()), this, SLOT(onUpdateClick()));
+ connect(leRoomName, SIGNAL(returnPressed()), this, SLOT(onUpdateClick()));
+
+ connect(leRoomName, SIGNAL(textChanged(const QString &)), this, SLOT(onRoomNameEdited()));
}
-PageNetGame::PageNetGame(QWidget* parent, QSettings * gameSettings) : AbstractPage(parent)
+PageNetGame::PageNetGame(QWidget* parent) : AbstractPage(parent)
{
- m_gameSettings = gameSettings;
-
initPage();
QMenu * menu = new QMenu(BtnMaster);
@@ -108,29 +170,44 @@
restrictJoins->setCheckable(true);
restrictTeamAdds = new QAction(QAction::tr("Restrict Team Additions"), menu);
restrictTeamAdds->setCheckable(true);
- //menu->addAction(startGame);
menu->addAction(restrictJoins);
menu->addAction(restrictTeamAdds);
BtnMaster->setMenu(menu);
+ if (height() < cutoffHeight)
+ pGameCFG->setTabbed(true);
}
+void PageNetGame::resizeEvent(QResizeEvent * event)
+{
+ int oldHeight = event->oldSize().height();
+ int newHeight = event->size().height();
+
+ if (newHeight < cutoffHeight && oldHeight >= cutoffHeight)
+ {
+ pGameCFG->setTabbed(true);
+ }
+ else if (newHeight >= cutoffHeight && oldHeight < cutoffHeight)
+ {
+ pGameCFG->setTabbed(false);
+ }
+}
void PageNetGame::displayError(const QString & message)
{
- pChatWidget->displayError(message);
+ chatWidget->displayError(message);
}
void PageNetGame::displayNotice(const QString & message)
{
- pChatWidget->displayNotice(message);
+ chatWidget->displayNotice(message);
}
void PageNetGame::displayWarning(const QString & message)
{
- pChatWidget->displayWarning(message);
+ chatWidget->displayWarning(message);
}
@@ -142,12 +219,19 @@
BtnGo->setIcon(QIcon(":/res/lightbulb_off.png"));
}
+void PageNetGame::onRoomNameEdited()
+{
+ BtnUpdate->setEnabled(true);
+}
+
void PageNetGame::onUpdateClick()
{
if (!leRoomName->text().trimmed().isEmpty())
{
+ m_gameSettings->setValue("frontend/lastroomname", leRoomName->text());
+ leRoomName->rememberCurrentText();
+ BtnUpdate->setEnabled(false);
emit askForUpdateRoomName(leRoomName->text());
- leRoomName->rememberCurrentText();
}
else
{
@@ -158,6 +242,7 @@
roomMsg.setText(QMessageBox::tr("Please enter room name"));
roomMsg.setWindowModality(Qt::WindowModal);
roomMsg.exec();
+ leRoomName->setFocus();
}
}
@@ -166,6 +251,8 @@
{
leRoomName->setText(roomName);
leRoomName->rememberCurrentText();
+ lblRoomNameReadOnly->setText(roomName);
+ BtnUpdate->setEnabled(false);
}
void PageNetGame::setMasterMode(bool isMaster)
@@ -174,9 +261,17 @@
BtnStart->setVisible(isMaster);
BtnUpdate->setVisible(isMaster);
leRoomName->setVisible(isMaster);
+ lblRoomNameReadOnly->setVisible(!isMaster);
+ pGameCFG->setMaster(isMaster);
+ repaint();
}
void PageNetGame::setUser(const QString & nickname)
{
- pChatWidget->setUser(nickname);
+ chatWidget->setUser(nickname);
}
+
+void PageNetGame::setSettings(QSettings *settings)
+{
+ m_gameSettings = settings;
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagenetgame.h
--- a/QTfrontend/ui/page/pagenetgame.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagenetgame.h Fri Feb 22 05:05:32 2013 +0100
@@ -26,19 +26,16 @@
class HWChatWidget;
class TeamSelWidget;
class GameCFGWidget;
+class QSettings;
class PageNetGame : public AbstractPage
{
Q_OBJECT
public:
- PageNetGame(QWidget* parent, QSettings * gameSettings);
+ PageNetGame(QWidget* parent);
- /**
- * Sets the room name to display.
- * @param roomName room name to be displayed.
- */
- void setRoomName(const QString & roomName);
+ void setSettings(QSettings * settings);
void displayError(const QString & message);
void displayNotice(const QString & message);
@@ -48,34 +45,42 @@
QPushButton *BtnMaster;
QPushButton *BtnStart;
QPushButton *BtnUpdate;
+ HistoryLineEdit *leRoomName;
QAction * restrictJoins;
QAction * restrictTeamAdds;
- HWChatWidget* pChatWidget;
+ HWChatWidget* chatWidget;
TeamSelWidget* pNetTeamsWidget;
GameCFGWidget* pGameCFG;
public slots:
+ void setRoomName(const QString & roomName);
void setReadyStatus(bool isReady);
void setUser(const QString & nickname);
void onUpdateClick();
void setMasterMode(bool isMaster);
+ private slots:
+ void onRoomNameEdited();
+
signals:
void SetupClicked();
void askForUpdateRoomName(const QString &);
+ protected:
+ void resizeEvent(QResizeEvent * event);
+
private:
QLayout * bodyLayoutDefinition();
QLayout * footerLayoutDefinition();
+ QLayout * footerLayoutLeftDefinition();
void connectSignals();
QSettings * m_gameSettings;
-
- HistoryLineEdit * leRoomName;
QPushButton * btnSetup;
+ QLabel * lblRoomNameReadOnly;
};
#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagenettype.cpp
--- a/QTfrontend/ui/page/pagenettype.cpp Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include
-#include
-
-#include "pagenettype.h"
-
-
-QLayout * PageNetType::bodyLayoutDefinition()
-{
- QGridLayout * pageLayout = new QGridLayout();
- pageLayout->setRowStretch(0, 10);
- pageLayout->setRowStretch(3, 10);
-
- pageLayout->setColumnStretch(1, 10);
- pageLayout->setColumnStretch(2, 20);
- pageLayout->setColumnStretch(3, 10);
-
- BtnLAN = addButton(tr("LAN game"), pageLayout, 1, 2);
- BtnLAN->setWhatsThis(tr("Join or host your own game server in a Local Area Network."));
- BtnOfficialServer = addButton(tr("Official server"), pageLayout, 2, 2);
- BtnOfficialServer->setWhatsThis(tr("Join hundreds of players online!"));
-
- // hack: temporary deactivated - requires server modifications that aren't backward compatible (yet)
- //BtnOfficialServer->setEnabled(false);
-
- return pageLayout;
-}
-
-PageNetType::PageNetType(QWidget* parent) : AbstractPage(parent)
-{
- initPage();
-}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagenettype.h
--- a/QTfrontend/ui/page/pagenettype.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef PAGE_NETTYPE_H
-#define PAGE_NETTYPE_H
-
-#include "AbstractPage.h"
-
-class PageNetType : public AbstractPage
-{
- Q_OBJECT
-
- public:
- PageNetType(QWidget* parent = 0);
-
- QPushButton * BtnLAN;
- QPushButton * BtnOfficialServer;
-
- protected:
- QLayout * bodyLayoutDefinition();
-};
-
-#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pageoptions.cpp
--- a/QTfrontend/ui/page/pageoptions.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pageoptions.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -23,20 +23,62 @@
#include
#include
#include
+#include
#include
#include
#include
-#include
+#include
+#include
#include
#include
#include
#include
+#include
#include "pageoptions.h"
+#include "gameuiconfig.h"
#include "hwconsts.h"
#include "fpsedit.h"
-#include "igbox.h"
#include "DataManager.h"
+#include "LibavInteraction.h"
+#include "AutoUpdater.h"
+#include "HWApplication.h"
+#include "keybinder.h"
+
+#ifdef __APPLE__
+#ifdef SPARKLE_ENABLED
+#include "SparkleAutoUpdater.h"
+#endif
+#endif
+
+const int OPTION_BOX_SPACING = 10;
+
+OptionGroupBox::OptionGroupBox(const QString & iconName,
+ const QString & title,
+ QWidget * parent) : IconedGroupBox(parent)
+{
+ setIcon(QIcon(iconName));
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ setTitle(title);
+ setMinimumWidth(300);
+ m_layout = new QGridLayout(this);
+ m_layout->setColumnStretch(0, 0);
+ m_layout->setColumnStretch(1, 1);
+}
+
+QGridLayout * OptionGroupBox::layout()
+{
+ return m_layout;
+}
+
+void OptionGroupBox::addDivider()
+{
+ QFrame * hr = new QFrame(this);
+ hr->setFrameStyle(QFrame::HLine);
+ hr->setLineWidth(3);
+ hr->setFixedHeight(10);
+ m_layout->addWidget(hr, m_layout->rowCount(), 0, 1, m_layout->columnCount());
+}
// TODO cleanup
QLayout * PageOptions::bodyLayoutDefinition()
@@ -45,270 +87,227 @@
QTabWidget * tabs = new QTabWidget(this);
pageLayout->addWidget(tabs);
- QWidget * page1 = new QWidget(this);
- QWidget * page2 = new QWidget(this);
- tabs->addTab(page1, tr("General"));
- tabs->addTab(page2, tr("Advanced"));
+
+ binder = new KeyBinder(this, tr("Select an action to change what key controls it"), tr("Reset to default"), tr("Reset all binds"));
+ connect(binder, SIGNAL(bindUpdate(int)), this, SLOT(bindUpdated(int)));
+ connect(binder, SIGNAL(resetAllBinds()), this, SLOT(resetAllBinds()));
+
+ QWidget * pageGame = new QWidget(this);
+ tabs->addTab(pageGame, tr("Game"));
+
+ QWidget * pageGraphics = new QWidget(this);
+ tabs->addTab(pageGraphics, tr("Graphics"));
- { // page 1
- QGridLayout * page1Layout = new QGridLayout(page1);
- //gbTBLayout->setMargin(0);
- page1Layout->setSpacing(0);
- page1Layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ QWidget * pageAudio = new QWidget(this);
+ tabs->addTab(pageAudio, tr("Audio"));
+
+ binderTab = tabs->addTab(binder, tr("Controls"));
- QPixmap pmNew(":/res/new.png");
- QPixmap pmEdit(":/res/edit.png");
- QPixmap pmDelete(":/res/delete.png");
+#ifdef VIDEOREC
+ QWidget * pageVideoRec = new QWidget(this);
+ tabs->addTab(pageVideoRec, tr("Video Recording"));
+#endif
+
+ QWidget * pageNetwork = new QWidget(this);
+ tabs->addTab(pageNetwork, tr("Network"));
- {
- teamsBox = new IconedGroupBox(this);
- //teamsBox->setContentTopPadding(0);
- //teamsBox->setAttribute(Qt::WA_PaintOnScreen, true);
- teamsBox->setIcon(QIcon(":/res/teamicon.png"));
- teamsBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
- teamsBox->setTitle(QGroupBox::tr("Teams"));
+ QWidget * pageAdvanced = new QWidget(this);
+ tabs->addTab(pageAdvanced, tr("Advanced"));
+
+ connect(tabs, SIGNAL(currentChanged(int)), this, SLOT(tabIndexChanged(int)));
+
+ QPixmap pmNew(":/res/new.png");
+ QPixmap pmEdit(":/res/edit.png");
+ QPixmap pmDelete(":/res/delete.png");
+
+ { // game page
+ QVBoxLayout * leftColumn, * rightColumn;
+ setupTabPage(pageGame, &leftColumn, &rightColumn);
- QGridLayout * GBTlayout = new QGridLayout(teamsBox);
+ { // group: Teams
+ OptionGroupBox * groupTeams = new OptionGroupBox(":/res/teamicon.png", tr("Teams"), this);
+ groupTeams->setMinimumWidth(400);
+ rightColumn->addWidget(groupTeams);
- CBTeamName = new QComboBox(teamsBox);
- GBTlayout->addWidget(CBTeamName, 0, 0);
+ groupTeams->layout()->setColumnStretch(0, 1);
- BtnNewTeam = new QPushButton(teamsBox);
- BtnNewTeam->setToolTip(tr("New team"));
+ CBTeamName = new QComboBox(groupTeams);
+ groupTeams->layout()->addWidget(CBTeamName, 0, 0);
+
+ BtnNewTeam = new QPushButton(groupTeams);
+ BtnNewTeam->setWhatsThis(tr("New team"));
BtnNewTeam->setIconSize(pmNew.size());
BtnNewTeam->setIcon(pmNew);
BtnNewTeam->setMaximumWidth(pmNew.width() + 6);
connect(BtnNewTeam, SIGNAL(clicked()), this, SIGNAL(newTeamRequested()));
- GBTlayout->addWidget(BtnNewTeam, 0, 1);
+ groupTeams->layout()->addWidget(BtnNewTeam, 0, 1);
- BtnEditTeam = new QPushButton(teamsBox);
- BtnEditTeam->setToolTip(tr("Edit team"));
+ BtnEditTeam = new QPushButton(groupTeams);
+ BtnEditTeam->setWhatsThis(tr("Edit team"));
BtnEditTeam->setIconSize(pmEdit.size());
BtnEditTeam->setIcon(pmEdit);
BtnEditTeam->setMaximumWidth(pmEdit.width() + 6);
connect(BtnEditTeam, SIGNAL(clicked()), this, SLOT(requestEditSelectedTeam()));
- GBTlayout->addWidget(BtnEditTeam, 0, 2);
+ groupTeams->layout()->addWidget(BtnEditTeam, 0, 2);
- BtnDeleteTeam = new QPushButton(teamsBox);
- BtnDeleteTeam->setToolTip(tr("Delete team"));
+ BtnDeleteTeam = new QPushButton(groupTeams);
+ BtnDeleteTeam->setWhatsThis(tr("Delete team"));
BtnDeleteTeam->setIconSize(pmDelete.size());
BtnDeleteTeam->setIcon(pmDelete);
BtnDeleteTeam->setMaximumWidth(pmDelete.width() + 6);
connect(BtnDeleteTeam, SIGNAL(clicked()), this, SLOT(requestDeleteSelectedTeam()));
- GBTlayout->addWidget(BtnDeleteTeam, 0, 3);
+ groupTeams->layout()->addWidget(BtnDeleteTeam, 0, 3);
- LblNoEditTeam = new QLabel(teamsBox);
+ LblNoEditTeam = new QLabel(groupTeams);
LblNoEditTeam->setText(tr("You can't edit teams from team selection. Go back to main menu to add, edit or delete teams."));
LblNoEditTeam->setWordWrap(true);
LblNoEditTeam->setVisible(false);
- GBTlayout->addWidget(LblNoEditTeam, 0, 0);
-
- page1Layout->addWidget(teamsBox, 0, 0);
+ groupTeams->layout()->addWidget(LblNoEditTeam, 1, 0, 1, 4);
}
- {
- IconedGroupBox* groupWeapons = new IconedGroupBox(this);
+ { // group: schemes
+ OptionGroupBox * groupSchemes = new OptionGroupBox(":/res/weaponsicon.png", tr("Schemes"), this);
+ leftColumn->addWidget(groupSchemes);
- //groupWeapons->setContentTopPadding(0);
- //groupWeapons->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- groupWeapons->setIcon(QIcon(":/res/weaponsicon.png"));
- groupWeapons->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
- groupWeapons->setTitle(QGroupBox::tr("Schemes and Weapons"));
- QGridLayout * WeaponsLayout = new QGridLayout(groupWeapons);
+ groupSchemes->layout()->setColumnStretch(0, 1);
- QLabel* SchemeLabel = new QLabel(groupWeapons);
- SchemeLabel->setText(QLabel::tr("Game scheme"));
- WeaponsLayout->addWidget(SchemeLabel, 1, 0);
+ SchemesName = new QComboBox(groupSchemes);
+ groupSchemes->layout()->addWidget(SchemesName, 0, 0);
- SchemesName = new QComboBox(groupWeapons);
- WeaponsLayout->addWidget(SchemesName, 1, 1);
-
- SchemeNew = new QPushButton(groupWeapons);
+ SchemeNew = new QPushButton(groupSchemes);
SchemeNew->setWhatsThis(tr("New scheme"));
SchemeNew->setIconSize(pmNew.size());
SchemeNew->setIcon(pmNew);
SchemeNew->setMaximumWidth(pmNew.width() + 6);
- WeaponsLayout->addWidget(SchemeNew, 1, 2);
+ groupSchemes->layout()->addWidget(SchemeNew, 0, 1);
- SchemeEdit = new QPushButton(groupWeapons);
+ SchemeEdit = new QPushButton(groupSchemes);
SchemeEdit->setWhatsThis(tr("Edit scheme"));
SchemeEdit->setIconSize(pmEdit.size());
SchemeEdit->setIcon(pmEdit);
SchemeEdit->setMaximumWidth(pmEdit.width() + 6);
- WeaponsLayout->addWidget(SchemeEdit, 1, 3);
+ groupSchemes->layout()->addWidget(SchemeEdit, 0, 2);
- SchemeDelete = new QPushButton(groupWeapons);
+ SchemeDelete = new QPushButton(groupSchemes);
SchemeDelete->setWhatsThis(tr("Delete scheme"));
SchemeDelete->setIconSize(pmDelete.size());
SchemeDelete->setIcon(pmDelete);
SchemeDelete->setMaximumWidth(pmDelete.width() + 6);
- WeaponsLayout->addWidget(SchemeDelete, 1, 4);
+ groupSchemes->layout()->addWidget(SchemeDelete, 0, 3);
+ }
- QLabel* WeaponLabel = new QLabel(groupWeapons);
- WeaponLabel->setText(QLabel::tr("Weapons"));
- WeaponsLayout->addWidget(WeaponLabel, 2, 0);
+ { // group: weapons
+ OptionGroupBox * groupWeapons = new OptionGroupBox(":/res/weaponsicon.png", tr("Weapons"), this);
+ leftColumn->addWidget(groupWeapons);
+
+ groupWeapons->layout()->setColumnStretch(0, 1);
WeaponsName = new QComboBox(groupWeapons);
- WeaponsLayout->addWidget(WeaponsName, 2, 1);
+ groupWeapons->layout()->addWidget(WeaponsName, 0, 0);
WeaponNew = new QPushButton(groupWeapons);
WeaponNew->setWhatsThis(tr("New weapon set"));
WeaponNew->setIconSize(pmNew.size());
WeaponNew->setIcon(pmNew);
WeaponNew->setMaximumWidth(pmNew.width() + 6);
- WeaponsLayout->addWidget(WeaponNew, 2, 2);
+ groupWeapons->layout()->addWidget(WeaponNew, 0, 1);
WeaponEdit = new QPushButton(groupWeapons);
WeaponEdit->setWhatsThis(tr("Edit weapon set"));
WeaponEdit->setIconSize(pmEdit.size());
WeaponEdit->setIcon(pmEdit);
WeaponEdit->setMaximumWidth(pmEdit.width() + 6);
- WeaponsLayout->addWidget(WeaponEdit, 2, 3);
+ groupWeapons->layout()->addWidget(WeaponEdit, 0, 2);
WeaponDelete = new QPushButton(groupWeapons);
WeaponDelete->setWhatsThis(tr("Delete weapon set"));
WeaponDelete->setIconSize(pmDelete.size());
WeaponDelete->setIcon(pmDelete);
WeaponDelete->setMaximumWidth(pmDelete.width() + 6);
- WeaponsLayout->addWidget(WeaponDelete, 2, 4);
-
- page1Layout->addWidget(groupWeapons, 1, 0);
+ groupWeapons->layout()->addWidget(WeaponDelete, 0, 3);
}
- {
- IconedGroupBox* groupMisc = new IconedGroupBox(this);
- //groupMisc->setContentTopPadding(0);
- //groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
- groupMisc->setIcon(QIcon(":/res/miscicon.png"));
- //groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
- groupMisc->setTitle(QGroupBox::tr("Misc"));
- QGridLayout * MiscLayout = new QGridLayout(groupMisc);
+ leftColumn->addStretch(1);
+ rightColumn->addStretch(1);
+ }
- // Label for "Language"
- QLabel *labelLanguage = new QLabel(groupMisc);
- labelLanguage->setText(QLabel::tr("Locale") + " *");
- MiscLayout->addWidget(labelLanguage, 0, 0);
+ { // graphics page
+ QVBoxLayout * leftColumn, * rightColumn;
+ setupTabPage(pageGraphics, &leftColumn, &rightColumn);
- // List of installed languages
- CBLanguage = new QComboBox(groupMisc);
- QDir tmpdir;
- tmpdir.cd(cfgdir->absolutePath());
- tmpdir.cd("Data/Locale");
- tmpdir.setFilter(QDir::Files);
- QStringList locs = tmpdir.entryList(QStringList("hedgewars_*.qm"));
- CBLanguage->addItem(QComboBox::tr("(System default)"), QString(""));
- for(int i = 0; i < locs.count(); i++)
- {
- QLocale loc(locs[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1"));
- CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name());
- }
+ { // group: game
+ OptionGroupBox * groupGame = new OptionGroupBox(":/res/graphicsicon.png", tr("Game"), this);
+ leftColumn->addWidget(groupGame);
+
+ groupGame->layout()->setColumnStretch(0, 0);
+ groupGame->layout()->setColumnStretch(1, 0);
+ groupGame->layout()->setColumnStretch(2, 1);
- tmpdir.cd(datadir->absolutePath());
- tmpdir.cd("Locale");
- tmpdir.setFilter(QDir::Files);
- QStringList tmplist = tmpdir.entryList(QStringList("hedgewars_*.qm"));
- for(int i = 0; i < tmplist.count(); i++)
- {
- if (locs.contains(tmplist[i])) continue;
- QLocale loc(tmplist[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1"));
- CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name());
- }
+ // Fullscreen
- MiscLayout->addWidget(CBLanguage, 0, 1);
+ CBFullscreen = new QCheckBox(groupGame);
+ groupGame->layout()->addWidget(CBFullscreen, 0, 0, 1, 2);
+ CBFullscreen->setText(QLabel::tr("Fullscreen"));
+
+ // Fullscreen resolution
- // Label and field for net nick
- labelNN = new QLabel(groupMisc);
- labelNN->setText(QLabel::tr("Nickname"));
- MiscLayout->addWidget(labelNN, 1, 0);
+ lblFullScreenRes = new QLabel(groupGame);
+ lblFullScreenRes->setText(QLabel::tr("Fullscreen Resolution"));
+ groupGame->layout()->addWidget(lblFullScreenRes, 1, 0);
- editNetNick = new QLineEdit(groupMisc);
- editNetNick->setMaxLength(20);
- editNetNick->setText(QLineEdit::tr("anonymous"));
- MiscLayout->addWidget(editNetNick, 1, 1);
+ CBResolution = new QComboBox(groupGame);
+ CBResolution->setFixedWidth(200);
+ groupGame->layout()->addWidget(CBResolution, 1, 1, Qt::AlignLeft);
- // checkbox and field for password
- CBSavePassword = new QCheckBox(groupMisc);
- CBSavePassword->setText(QCheckBox::tr("Save password"));
- MiscLayout->addWidget(CBSavePassword, 2, 0);
-
- editNetPassword = new QLineEdit(groupMisc);
- editNetPassword->setEchoMode(QLineEdit::Password);
- MiscLayout->addWidget(editNetPassword, 2, 1);
+ // Windowed resolution
- #ifdef __APPLE__
- #ifdef SPARKLE_ENABLED
- CBAutoUpdate = new QCheckBox(groupMisc);
- CBAutoUpdate->setText(QCheckBox::tr("Check for updates at startup"));
- MiscLayout->addWidget(CBAutoUpdate, 7, 0, 1, 3);
- #endif
- #endif
- page1Layout->addWidget(groupMisc, 2, 0);
- }
+ lblWinScreenRes = new QLabel(groupGame);
+ lblWinScreenRes->setText(QLabel::tr("Windowed Resolution"));
+ groupGame->layout()->addWidget(lblWinScreenRes, 2, 0);
- {
- AGGroupBox = new IconedGroupBox(this);
- //AGGroupBox->setContentTopPadding(0);
- AGGroupBox->setIcon(QIcon(":/res/graphicsicon.png"));
- //AGGroupBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
- AGGroupBox->setTitle(QGroupBox::tr("Audio/Graphic options"));
+ winResContainer = new QWidget();
+ QHBoxLayout * winResLayout = new QHBoxLayout(winResContainer);
+ winResLayout->setSpacing(0);
+ groupGame->layout()->addWidget(winResContainer, 2, 1);
- QVBoxLayout * GBAlayout = new QVBoxLayout(AGGroupBox);
- QHBoxLayout * GBAreslayout = new QHBoxLayout(0);
- QHBoxLayout * GBAstereolayout = new QHBoxLayout(0);
- QHBoxLayout * GBAqualayout = new QHBoxLayout(0);
-
- CBFrontendFullscreen = new QCheckBox(AGGroupBox);
- CBFrontendFullscreen->setText(QCheckBox::tr("Frontend fullscreen"));
- GBAlayout->addWidget(CBFrontendFullscreen);
-
- CBFrontendEffects = new QCheckBox(AGGroupBox);
- CBFrontendEffects->setText(QCheckBox::tr("Frontend effects"));
- GBAlayout->addWidget(CBFrontendEffects);
+ QLabel *winLabelX = new QLabel(groupGame);
+ winLabelX->setText("x"); // decorational x
+ winLabelX->setFixedWidth(40);
+ winLabelX->setAlignment(Qt::AlignCenter);
- CBEnableFrontendSound = new QCheckBox(AGGroupBox);
- CBEnableFrontendSound->setText(QCheckBox::tr("Enable frontend sounds"));
- GBAlayout->addWidget(CBEnableFrontendSound);
-
- CBEnableFrontendMusic = new QCheckBox(AGGroupBox);
- CBEnableFrontendMusic->setText(QCheckBox::tr("Enable frontend music"));
- GBAlayout->addWidget(CBEnableFrontendMusic);
-
- QFrame * hr = new QFrame(AGGroupBox);
- hr->setFrameStyle(QFrame::HLine);
- hr->setLineWidth(3);
- hr->setFixedHeight(10);
- GBAlayout->addWidget(hr);
+ windowWidthEdit = new QLineEdit(groupGame);
+ windowWidthEdit->setValidator(new QIntValidator(this));
+ windowWidthEdit->setFixedSize(55, CBResolution->height());
+ windowHeightEdit = new QLineEdit(groupGame);
+ windowHeightEdit->setValidator(new QIntValidator(this));
+ windowHeightEdit->setFixedSize(55, CBResolution->height());
- QLabel * resolution = new QLabel(AGGroupBox);
- resolution->setText(QLabel::tr("Resolution"));
- GBAreslayout->addWidget(resolution);
+ winResLayout->addWidget(windowWidthEdit, 0);
+ winResLayout->addWidget(winLabelX, 0);
+ winResLayout->addWidget(windowHeightEdit, 0);
+ winResLayout->addStretch(1);
- CBResolution = new QComboBox(AGGroupBox);
- GBAreslayout->addWidget(CBResolution);
- GBAlayout->addLayout(GBAreslayout);
+ // Quality
- CBFullscreen = new QCheckBox(AGGroupBox);
- CBFullscreen->setText(QCheckBox::tr("Fullscreen"));
- GBAreslayout->addWidget(CBFullscreen);
+ QLabel * lblQuality = new QLabel(groupGame);
+ lblQuality->setText(QLabel::tr("Quality"));
+ lblQuality->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ groupGame->layout()->addWidget(lblQuality, 3, 0);
- QLabel * quality = new QLabel(AGGroupBox);
- quality->setText(QLabel::tr("Quality"));
- quality->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
- GBAqualayout->addWidget(quality);
-
- SLQuality = new QSlider(Qt::Horizontal, AGGroupBox);
+ SLQuality = new QSlider(Qt::Horizontal, groupGame);
SLQuality->setTickPosition(QSlider::TicksBelow);
SLQuality->setMaximum(5);
SLQuality->setMinimum(0);
SLQuality->setFixedWidth(150);
- GBAqualayout->addWidget(SLQuality);
- GBAlayout->addLayout(GBAqualayout);
+ groupGame->layout()->addWidget(SLQuality, 3, 1, Qt::AlignLeft);
+
+ // Stereo spacing
- QLabel * stereo = new QLabel(AGGroupBox);
- stereo->setText(QLabel::tr("Stereo rendering"));
- GBAstereolayout->addWidget(stereo);
+ QLabel * lblStereo = new QLabel(groupGame);
+ lblStereo->setText(QLabel::tr("Stereo rendering"));
+ groupGame->layout()->addWidget(lblStereo, 4, 0);
- CBStereoMode = new QComboBox(AGGroupBox);
+ CBStereoMode = new QComboBox(groupGame);
CBStereoMode->addItem(QComboBox::tr("Disabled"));
CBStereoMode->addItem(QComboBox::tr("Red/Cyan"));
CBStereoMode->addItem(QComboBox::tr("Cyan/Red"));
@@ -316,74 +315,84 @@
CBStereoMode->addItem(QComboBox::tr("Blue/Red"));
CBStereoMode->addItem(QComboBox::tr("Red/Green"));
CBStereoMode->addItem(QComboBox::tr("Green/Red"));
- CBStereoMode->addItem(QComboBox::tr("Side-by-side"));
- CBStereoMode->addItem(QComboBox::tr("Top-Bottom"));
- CBStereoMode->addItem(QComboBox::tr("Wiggle"));
CBStereoMode->addItem(QComboBox::tr("Red/Cyan grayscale"));
CBStereoMode->addItem(QComboBox::tr("Cyan/Red grayscale"));
CBStereoMode->addItem(QComboBox::tr("Red/Blue grayscale"));
CBStereoMode->addItem(QComboBox::tr("Blue/Red grayscale"));
CBStereoMode->addItem(QComboBox::tr("Red/Green grayscale"));
CBStereoMode->addItem(QComboBox::tr("Green/Red grayscale"));
-
- GBAstereolayout->addWidget(CBStereoMode);
- GBAlayout->addLayout(GBAstereolayout);
+ CBStereoMode->addItem(QComboBox::tr("Side-by-side"));
+ CBStereoMode->addItem(QComboBox::tr("Top-Bottom"));
+ CBStereoMode->setFixedWidth(CBResolution->width());
+ groupGame->layout()->addWidget(CBStereoMode, 4, 1);
- hr = new QFrame(AGGroupBox);
- hr->setFrameStyle(QFrame::HLine);
- hr->setLineWidth(3);
- hr->setFixedHeight(10);
- GBAlayout->addWidget(hr);
+ // Divider
+
+ groupGame->addDivider(); // row 5
- QGridLayout * GBAvollayout = new QGridLayout();
- QLabel * vol = new QLabel(AGGroupBox);
- vol->setText(QLabel::tr("Initial sound volume"));
- GBAvollayout->addWidget(vol, 0, 0, 1, 2);
- GBAlayout->addLayout(GBAvollayout);
- volumeBox = new QSpinBox(AGGroupBox);
- volumeBox->setRange(0, 100);
- volumeBox->setSingleStep(5);
- GBAvollayout->addWidget(volumeBox, 0, 2);
+ // FPS limit
+
+ QHBoxLayout * fpsLayout = new QHBoxLayout();
+ groupGame->layout()->addLayout(fpsLayout, 6, 0, 1, 2);
+ QLabel * maxfps = new QLabel(groupGame);
+ maxfps->setText(QLabel::tr("FPS limit"));
+ fpsLayout->addWidget(maxfps);
+ fpsLayout->addSpacing(30);
+ fpsedit = new FPSEdit(groupGame);
+ fpsLayout->addWidget(fpsedit);
- CBEnableSound = new QCheckBox(AGGroupBox);
- CBEnableSound->setText(QCheckBox::tr("Enable sound"));
- GBAvollayout->addWidget(CBEnableSound, 1, 0, 1, 1);
+ // Show FPS
- CBEnableMusic = new QCheckBox(AGGroupBox);
- CBEnableMusic->setText(QCheckBox::tr("Enable music"));
- GBAvollayout->addWidget(CBEnableMusic, 1, 1, 1, 2);
+ CBShowFPS = new QCheckBox(groupGame);
+ CBShowFPS->setText(QCheckBox::tr("Show FPS"));
+ fpsLayout->addWidget(CBShowFPS);
+ fpsLayout->addStretch(1);
- GBAvollayout->setSizeConstraint(QLayout::SetMinimumSize);
+ // Divider
+
+ groupGame->addDivider(); // row 7
- hr = new QFrame(AGGroupBox);
- hr->setFrameStyle(QFrame::HLine);
- hr->setLineWidth(3);
- hr->setFixedHeight(10);
- GBAlayout->addWidget(hr);
+ // Alternative damage show
+
+ CBAltDamage = new QCheckBox(groupGame);
+ CBAltDamage->setText(QCheckBox::tr("Alternative damage show"));
+ groupGame->layout()->addWidget(CBAltDamage, 8, 0, 1, 2);
- CBAltDamage = new QCheckBox(AGGroupBox);
- CBAltDamage->setText(QCheckBox::tr("Alternative damage show"));
- GBAlayout->addWidget(CBAltDamage);
+ // Show ammo menu tooltips
- page1Layout->addWidget(AGGroupBox, 0, 1, 3, 1);
+ WeaponTooltip = new QCheckBox(groupGame);
+ WeaponTooltip->setText(QCheckBox::tr("Show ammo menu tooltips"));
+ groupGame->layout()->addWidget(WeaponTooltip, 9, 0, 1, 2);
}
- page1Layout->addWidget(new QWidget(this), 3, 0);
+ { // group: frontend
+ OptionGroupBox * groupFrontend = new OptionGroupBox(":/res/graphicsicon.png", tr("Frontend"), this);
+ rightColumn->addWidget(groupFrontend);
+
+ // Fullscreen
- }
+ CBFrontendFullscreen = new QCheckBox(groupFrontend);
+ CBFrontendFullscreen->setText(QCheckBox::tr("Fullscreen"));
+ groupFrontend->layout()->addWidget(CBFrontendFullscreen, 0, 0);
- { // page 2
- QGridLayout * page2Layout = new QGridLayout(page2);
+ // Visual effects
- {
- IconedGroupBox * gbColors = new IconedGroupBox(this);
- gbColors->setIcon(QIcon(":/res/lightbulb_on.png"));
- gbColors->setTitle(QGroupBox::tr("Custom colors"));
- page2Layout->addWidget(gbColors, 0, 0);
- QGridLayout * gbCLayout = new QGridLayout(gbColors);
+ CBFrontendEffects = new QCheckBox(groupFrontend);
+ CBFrontendEffects->setText(QCheckBox::tr("Visual effects"));
+ groupFrontend->layout()->addWidget(CBFrontendEffects, 1, 0);
+ }
+
+ { // group: colors
+ OptionGroupBox * groupColors = new OptionGroupBox(":/res/lightbulb_on.png", tr("Custom colors"), this);
+ rightColumn->addWidget(groupColors);
+
+ groupColors->layout()->setColumnStretch(0, 1);
+ groupColors->layout()->setColumnStretch(1, 1);
+ groupColors->layout()->setColumnStretch(2, 1);
+
+ // Color buttons
QSignalMapper * mapper = new QSignalMapper(this);
-
QStandardItemModel * model = DataManager::instance().colorsModel();
connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(onColorModelDataChanged(QModelIndex,QModelIndex)));
@@ -391,7 +400,7 @@
{
QPushButton * btn = new QPushButton(this);
btn->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
- gbCLayout->addWidget(btn, i / 3, i % 3);
+ groupColors->layout()->addWidget(btn, i / 3, i % 3);
btn->setStyleSheet(QString("background: %1").arg(model->item(i)->data().value().name()));
m_colorButtons.append(btn);
connect(btn, SIGNAL(clicked()), mapper, SLOT(map()));
@@ -400,103 +409,373 @@
connect(mapper, SIGNAL(mapped(int)), this, SLOT(colorButtonClicked(int)));
+ // Reset default colors
+
QPushButton * btn = new QPushButton(this);
- gbCLayout->addWidget(btn, (model->rowCount() - 1) / 3 + 1, 0, 1, 3);
+ groupColors->layout()->addWidget(btn, (model->rowCount() - 1) / 3 + 1, 0, 1, 3);
btn->setText(tr("Reset to default colors"));
connect(btn, SIGNAL(clicked()), &DataManager::instance(), SLOT(resetColors()));
}
- {
- IconedGroupBox * gbMisc = new IconedGroupBox(this);
- gbMisc->setIcon(QIcon(":/res/Settings.png"));
- gbMisc->setTitle(QGroupBox::tr("Miscellaneous"));
- page2Layout->addWidget(gbMisc, 0, 1);
- QVBoxLayout * gbCLayout = new QVBoxLayout(gbMisc);
+ leftColumn->addStretch(1);
+ rightColumn->addStretch(1);
+ }
+
+ { // audio page
+ QVBoxLayout * leftColumn, * rightColumn;
+ setupTabPage(pageAudio, &leftColumn, &rightColumn);
- QHBoxLayout * GBAfpslayout = new QHBoxLayout(0);
- QLabel * maxfps = new QLabel(AGGroupBox);
- maxfps->setText(QLabel::tr("FPS limit"));
- GBAfpslayout->addWidget(maxfps);
- fpsedit = new FPSEdit(AGGroupBox);
- GBAfpslayout->addWidget(fpsedit);
+ { // group: game
+ OptionGroupBox * groupGame = new OptionGroupBox(":/res/audio.png", tr("Game audio"), this);
+ leftColumn->addWidget(groupGame);
+ groupGame->layout()->setColumnStretch(1, 0);
+ groupGame->layout()->setColumnStretch(2, 1);
+
+ // Initial sound volume
+
+ QLabel * vol = new QLabel(groupGame);
+ vol->setText(QLabel::tr("Initial sound volume"));
+ groupGame->layout()->addWidget(vol, 0, 0);
- CBShowFPS = new QCheckBox(AGGroupBox);
- CBShowFPS->setText(QCheckBox::tr("Show FPS"));
- GBAfpslayout->addWidget(CBShowFPS);
+ SLVolume = new QSlider(Qt::Horizontal, groupGame);
+ SLVolume->setTickPosition(QSlider::TicksBelow);
+ SLVolume->setMaximum(100);
+ SLVolume->setMinimum(0);
+ SLVolume->setFixedWidth(150);
+ groupGame->layout()->addWidget(SLVolume, 0, 1, 1, 2);
- gbCLayout->addLayout(GBAfpslayout);
-
+ lblVolumeLevel = new QLabel(groupGame);
+ lblVolumeLevel->setFixedWidth(40);
+ groupGame->layout()->addWidget(lblVolumeLevel, 0, 3);
- WeaponTooltip = new QCheckBox(this);
- WeaponTooltip->setText(QCheckBox::tr("Show ammo menu tooltips"));
- gbCLayout->addWidget(WeaponTooltip);
+ // Sound
+ CBSound = new QCheckBox(groupGame);
+ CBSound->setText(QCheckBox::tr("Sound"));
+ CBSound->setWhatsThis(QCheckBox::tr("In-game sound effects"));
+ groupGame->layout()->addWidget(CBSound, 1, 1);
- CBNameWithDate = new QCheckBox(this);
- CBNameWithDate->setText(QCheckBox::tr("Append date and time to record file name"));
- gbCLayout->addWidget(CBNameWithDate);
+ // Music
- BtnAssociateFiles = new QPushButton(this);
- BtnAssociateFiles->setText(QPushButton::tr("Associate file extensions"));
- BtnAssociateFiles->setVisible(!custom_data && !custom_config);
- gbCLayout->addWidget(BtnAssociateFiles);
+ CBMusic = new QCheckBox(groupGame);
+ CBMusic->setText(QCheckBox::tr("Music"));
+ CBMusic->setWhatsThis(QCheckBox::tr("In-game music"));
+ groupGame->layout()->addWidget(CBMusic, 1, 2, 1, 2, Qt::AlignLeft);
}
- {
- IconedGroupBox * gbProxy = new IconedGroupBox(this);
- gbProxy->setIcon(QIcon(":/res/Settings.png"));
- gbProxy->setTitle(QGroupBox::tr("Proxy settings"));
- page2Layout->addWidget(gbProxy, 1, 0);
- QGridLayout * gbLayout = new QGridLayout(gbProxy);
+ { // group: frontend
+ OptionGroupBox * groupFrontend = new OptionGroupBox(":/res/audio.png", tr("Frontend audio"), this);
+ rightColumn->addWidget(groupFrontend);
+
+ CBFrontendSound = new QCheckBox(groupFrontend);
+ CBFrontendSound->setText(QCheckBox::tr("Sound"));
+ CBFrontendSound->setWhatsThis(QCheckBox::tr("Frontend sound effects"));
+ groupFrontend->layout()->addWidget(CBFrontendSound, 0, 0);
+
+ CBFrontendMusic = new QCheckBox(groupFrontend);
+ CBFrontendMusic->setText(QCheckBox::tr("Music"));
+ CBFrontendMusic->setWhatsThis(QCheckBox::tr("Frontend music"));
+ groupFrontend->layout()->addWidget(CBFrontendMusic, 0, 1);
+ }
+
+ leftColumn->addStretch(1);
+ rightColumn->addStretch(1);
+ }
+
+ { // network page
+ QVBoxLayout * leftColumn, * rightColumn;
+ setupTabPage(pageNetwork, &leftColumn, &rightColumn);
+
+ { // group: account
+ OptionGroupBox * groupAccount = new OptionGroupBox(":/res/teamicon.png", tr("Account"), this);
+ leftColumn->addWidget(groupAccount);
+
+ // Label and field for net nick
+
+ labelNN = new QLabel(groupAccount);
+ labelNN->setText(QLabel::tr("Nickname"));
+ groupAccount->layout()->addWidget(labelNN, 0, 0);
+
+ editNetNick = new QLineEdit(groupAccount);
+ editNetNick->setMaxLength(20);
+ editNetNick->setText(QLineEdit::tr("anonymous"));
+ groupAccount->layout()->addWidget(editNetNick, 0, 1);
+
+ // Checkbox and field for password
+
+ CBSavePassword = new QCheckBox(groupAccount);
+ CBSavePassword->setText(QCheckBox::tr("Save password"));
+ groupAccount->layout()->addWidget(CBSavePassword, 1, 0);
+
+ editNetPassword = new QLineEdit(groupAccount);
+ editNetPassword->setEchoMode(QLineEdit::Password);
+ groupAccount->layout()->addWidget(editNetPassword, 1, 1);
+ }
+
+ { // group: proxy
+ OptionGroupBox * groupProxy = new OptionGroupBox(":/res/net.png", tr("Proxy settings"), this);
+ rightColumn->addWidget(groupProxy);
+
+ // Labels
QStringList sl;
- sl
- << tr("Proxy host")
- << tr("Proxy port")
- << tr("Proxy login")
- << tr("Proxy password")
- ;
+ sl << tr("Proxy host")
+ << tr("Proxy port")
+ << tr("Proxy login")
+ << tr("Proxy password");
+
for(int i = 0; i < sl.size(); ++i)
{
- QLabel * l = new QLabel(gbProxy);
+ QLabel * l = new QLabel(groupProxy);
l->setText(sl[i]);
- gbLayout->addWidget(l, i + 1, 0);
+ groupProxy->layout()->addWidget(l, i + 1, 0);
}
- cbProxyType = new QComboBox(gbProxy);
+ // Proxy type
+
+ cbProxyType = new QComboBox(groupProxy);
cbProxyType->addItems(QStringList()
<< tr("No proxy")
<< tr("System proxy settings")
<< tr("Socks5 proxy")
<< tr("HTTP proxy"));
- gbLayout->addWidget(cbProxyType, 0, 1);
+ groupProxy->layout()->addWidget(cbProxyType, 0, 0, 1, 2);
+
+ // Proxy
- leProxy = new QLineEdit(gbProxy);
- gbLayout->addWidget(leProxy, 1, 1);
+ leProxy = new QLineEdit(groupProxy);
+ groupProxy->layout()->addWidget(leProxy, 1, 1);
- sbProxyPort = new QSpinBox(gbProxy);
+ // Proxy
+
+ sbProxyPort = new QSpinBox(groupProxy);
sbProxyPort->setMaximum(65535);
- gbLayout->addWidget(sbProxyPort, 2, 1);
+ groupProxy->layout()->addWidget(sbProxyPort, 2, 1);
- leProxyLogin = new QLineEdit(gbProxy);
- gbLayout->addWidget(leProxyLogin, 3, 1);
+ leProxyLogin = new QLineEdit(groupProxy);
+ groupProxy->layout()->addWidget(leProxyLogin, 3, 1);
- leProxyPassword = new QLineEdit(gbProxy);
+ leProxyPassword = new QLineEdit(groupProxy);
leProxyPassword->setEchoMode(QLineEdit::Password);
- gbLayout->addWidget(leProxyPassword, 4, 1);
+ groupProxy->layout()->addWidget(leProxyPassword, 4, 1);
connect(cbProxyType, SIGNAL(currentIndexChanged(int)), this, SLOT(onProxyTypeChanged()));
onProxyTypeChanged();
}
- page2Layout->addWidget(new QWidget(this), 2, 0);
+ leftColumn->addStretch(1);
+ rightColumn->addStretch(1);
+ }
+
+ { // advanced page
+ QVBoxLayout * leftColumn, * rightColumn;
+ setupTabPage(pageAdvanced, &leftColumn, &rightColumn);
+
+ { // group: miscellaneous
+ OptionGroupBox * groupMisc = new OptionGroupBox(":/res/Settings.png", tr("Miscellaneous"), this);
+ leftColumn->addWidget(groupMisc);
+
+ // Language
+
+ QLabel *labelLanguage = new QLabel(groupMisc);
+ labelLanguage->setText(QLabel::tr("Locale"));
+ groupMisc->layout()->addWidget(labelLanguage, 0, 0);
+
+ CBLanguage = new QComboBox(groupMisc);
+ groupMisc->layout()->addWidget(CBLanguage, 0, 1);
+ QStringList locs = DataManager::instance().entryList("Locale", QDir::Files, QStringList("hedgewars_*.qm"));
+ CBLanguage->addItem(QComboBox::tr("(System default)"), QString(""));
+ for(int i = 0; i < locs.count(); i++)
+ {
+ QLocale loc(locs[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1"));
+ CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name());
+ }
+
+ // Divider
+
+ groupMisc->addDivider(); // row 1
+
+ // Append date and time to record file name
+
+ CBNameWithDate = new QCheckBox(groupMisc);
+ CBNameWithDate->setText(QCheckBox::tr("Append date and time to record file name"));
+ groupMisc->layout()->addWidget(CBNameWithDate, 2, 0, 1, 2);
+
+ // Associate file extensions
+
+ BtnAssociateFiles = new QPushButton(groupMisc);
+ BtnAssociateFiles->setText(QPushButton::tr("Associate file extensions"));
+ BtnAssociateFiles->setVisible(!custom_data && !custom_config);
+ groupMisc->layout()->addWidget(BtnAssociateFiles, 3, 0, 1, 2);
+ }
+
+#ifdef __APPLE__
+#ifdef SPARKLE_ENABLED
+ { // group: updates
+ OptionGroupBox * groupUpdates = new OptionGroupBox(":/res/net.png", tr("Updates"), this);
+ rightColumn->addWidget(groupUpdates);
+
+ // Check for updates at startup
+
+ CBAutoUpdate = new QCheckBox(groupUpdates);
+ CBAutoUpdate->setText(QCheckBox::tr("Check for updates at startup"));
+ groupUpdates->layout()->addWidget(CBAutoUpdate, 0, 0);
+
+ // Check for updates now
+
+ btnUpdateNow = new QPushButton(groupUpdates);
+ connect(btnUpdateNow, SIGNAL(clicked()), this, SLOT(checkForUpdates()));
+ btnUpdateNow->setWhatsThis(tr("Check for updates"));
+ btnUpdateNow->setText("Check now");
+ btnUpdateNow->setFixedSize(130, 30);
+ groupUpdates->layout()->addWidget(btnUpdateNow, 0, 1);
+ }
+#endif
+#endif
+
+ leftColumn->addStretch(1);
+ rightColumn->addStretch(1);
}
+#ifdef VIDEOREC
+ { // video recording page
+ OptionGroupBox * groupVideoRec = new OptionGroupBox(":/res/camera.png", tr("Video recording options"), this);
+ groupVideoRec->setMinimumWidth(500);
+ groupVideoRec->setMaximumWidth(650);
+ QHBoxLayout * layoutVideoRec = new QHBoxLayout(pageVideoRec);
+ layoutVideoRec->addWidget(groupVideoRec, 1, Qt::AlignTop | Qt::AlignHCenter);
+
+ // label for format
+
+ QLabel *labelFormat = new QLabel(groupVideoRec);
+ labelFormat->setText(QLabel::tr("Format"));
+ groupVideoRec->layout()->addWidget(labelFormat, 0, 0);
+
+ // list of supported formats
+
+ comboAVFormats = new QComboBox(groupVideoRec);
+ groupVideoRec->layout()->addWidget(comboAVFormats, 0, 1, 1, 4);
+ LibavInteraction::instance().fillFormats(comboAVFormats);
+
+ // separator
+
+ QFrame * hr = new QFrame(groupVideoRec);
+ hr->setFrameStyle(QFrame::HLine);
+ hr->setLineWidth(3);
+ hr->setFixedHeight(10);
+ groupVideoRec->layout()->addWidget(hr, 1, 0, 1, 5);
+
+ // label for audio codec
+
+ QLabel *labelACodec = new QLabel(groupVideoRec);
+ labelACodec->setText(QLabel::tr("Audio codec"));
+ groupVideoRec->layout()->addWidget(labelACodec, 2, 0);
+
+ // list of supported audio codecs
+
+ comboAudioCodecs = new QComboBox(groupVideoRec);
+ groupVideoRec->layout()->addWidget(comboAudioCodecs, 2, 1, 1, 3);
+
+ // checkbox 'record audio'
+
+ checkRecordAudio = new QCheckBox(groupVideoRec);
+ checkRecordAudio->setText(QCheckBox::tr("Record audio"));
+ groupVideoRec->layout()->addWidget(checkRecordAudio, 2, 4);
+
+ // separator
+
+ hr = new QFrame(groupVideoRec);
+ hr->setFrameStyle(QFrame::HLine);
+ hr->setLineWidth(3);
+ hr->setFixedHeight(10);
+ groupVideoRec->layout()->addWidget(hr, 3, 0, 1, 5);
+
+ // label for video codec
+
+ QLabel *labelVCodec = new QLabel(groupVideoRec);
+ labelVCodec->setText(QLabel::tr("Video codec"));
+ groupVideoRec->layout()->addWidget(labelVCodec, 4, 0);
+
+ // list of supported video codecs
+
+ comboVideoCodecs = new QComboBox(groupVideoRec);
+ groupVideoRec->layout()->addWidget(comboVideoCodecs, 4, 1, 1, 4);
+
+ // label for resolution
+
+ QLabel *labelRes = new QLabel(groupVideoRec);
+ labelRes->setText(QLabel::tr("Resolution"));
+ groupVideoRec->layout()->addWidget(labelRes, 5, 0);
+
+ // width
+
+ widthEdit = new QLineEdit(groupVideoRec);
+ widthEdit->setValidator(new QIntValidator(this));
+ groupVideoRec->layout()->addWidget(widthEdit, 5, 1);
+
+ // x
+
+ QLabel *labelX = new QLabel(groupVideoRec);
+ labelX->setText("X");
+ groupVideoRec->layout()->addWidget(labelX, 5, 2);
+
+ // height
+
+ heightEdit = new QLineEdit(groupVideoRec);
+ heightEdit->setValidator(new QIntValidator(groupVideoRec));
+ groupVideoRec->layout()->addWidget(heightEdit, 5, 3);
+
+ // checkbox 'use game resolution'
+
+ checkUseGameRes = new QCheckBox(groupVideoRec);
+ checkUseGameRes->setText(QCheckBox::tr("Use game resolution"));
+ groupVideoRec->layout()->addWidget(checkUseGameRes, 5, 4);
+
+ // label for framerate
+
+ QLabel *labelFramerate = new QLabel(groupVideoRec);
+ labelFramerate->setText(QLabel::tr("Framerate"));
+ groupVideoRec->layout()->addWidget(labelFramerate, 6, 0);
+
+ framerateBox = new QComboBox(groupVideoRec);
+ framerateBox->addItem("24 fps", 24);
+ framerateBox->addItem("25 fps", 25);
+ framerateBox->addItem("30 fps", 30);
+ framerateBox->addItem("50 fps", 50);
+ framerateBox->addItem("60 fps", 60);
+ groupVideoRec->layout()->addWidget(framerateBox, 6, 1);
+
+ // label for Bitrate
+
+ QLabel *labelBitrate = new QLabel(groupVideoRec);
+ labelBitrate->setText(QLabel::tr("Bitrate (Kbps)"));
+ groupVideoRec->layout()->addWidget(labelBitrate, 6, 2);
+
+ // bitrate
+
+ bitrateBox = new QSpinBox(groupVideoRec);
+ bitrateBox->setRange(100, 5000);
+ bitrateBox->setSingleStep(100);
+ groupVideoRec->layout()->addWidget(bitrateBox, 6, 3);
+
+ // button 'set default options'
+
+ btnDefaults = new QPushButton(groupVideoRec);
+ btnDefaults->setText(QPushButton::tr("Set default options"));
+ btnDefaults->setWhatsThis(QPushButton::tr("Restore default coding parameters"));
+ groupVideoRec->layout()->addWidget(btnDefaults, 7, 0, 1, 5);
+ }
+#endif
+
previousQuality = this->SLQuality->value();
previousResolutionIndex = this->CBResolution->currentIndex();
previousFullscreenValue = this->CBFullscreen->isChecked();
+ setFullscreen(CBFullscreen->isChecked());
+ setVolume(SLVolume->value());
+
+ // mutually exclude window and fullscreen resolution
return pageLayout;
}
@@ -507,6 +786,14 @@
void PageOptions::connectSignals()
{
+#ifdef VIDEOREC
+ connect(checkUseGameRes, SIGNAL(stateChanged(int)), this, SLOT(changeUseGameRes(int)));
+ connect(checkRecordAudio, SIGNAL(stateChanged(int)), this, SLOT(changeRecordAudio(int)));
+ connect(comboAVFormats, SIGNAL(currentIndexChanged(int)), this, SLOT(changeAVFormat(int)));
+ connect(btnDefaults, SIGNAL(clicked()), this, SLOT(setDefaultOptions()));
+#endif
+ //connect(this, SIGNAL(pageEnter()), this, SLOT(setTeamOptionsEnabled()));
+ connect(SLVolume, SIGNAL(valueChanged(int)), this, SLOT(setVolume(int)));
connect(SLQuality, SIGNAL(valueChanged(int)), this, SLOT(setQuality(int)));
connect(CBResolution, SIGNAL(currentIndexChanged(int)), this, SLOT(setResolution(int)));
connect(CBFullscreen, SIGNAL(stateChanged(int)), this, SLOT(setFullscreen(int)));
@@ -515,7 +802,27 @@
connect(CBSavePassword, SIGNAL(stateChanged(int)), this, SLOT(savePwdChanged(int)));
}
-PageOptions::PageOptions(QWidget* parent) : AbstractPage(parent)
+void PageOptions::setVolume(int volume)
+{
+ lblVolumeLevel->setText(QString("%1\%").arg(volume));
+}
+
+void PageOptions::setupTabPage(QWidget * tabpage, QVBoxLayout ** leftColumn, QVBoxLayout ** rightColumn)
+{
+ QHBoxLayout * twoColumns = new QHBoxLayout(tabpage);
+ twoColumns->setSpacing(0);
+ *leftColumn = new QVBoxLayout();
+ *rightColumn = new QVBoxLayout();
+ (*leftColumn)->setSpacing(OPTION_BOX_SPACING);
+ (*rightColumn)->setSpacing(OPTION_BOX_SPACING);
+ twoColumns->addStretch(4);
+ twoColumns->addLayout(*leftColumn, 0);
+ twoColumns->addStretch(1);
+ twoColumns->addLayout(*rightColumn, 0);
+ twoColumns->addStretch(4);
+}
+
+PageOptions::PageOptions(QWidget* parent) : AbstractPage(parent), config(0)
{
initPage();
}
@@ -528,16 +835,16 @@
{
this->SLQuality->setValue(this->SLQuality->maximum());
this->SLQuality->setEnabled(false);
- this->CBFullscreen->setEnabled(!forced);
this->CBFullscreen->setChecked(forced ? true : previousFullscreenValue);
+ setFullscreen(forced ? true : previousFullscreenValue);
this->CBResolution->setCurrentIndex(forced ? 0 : previousResolutionIndex);
}
else
{
this->SLQuality->setEnabled(true);
- this->CBFullscreen->setEnabled(true);
this->SLQuality->setValue(previousQuality);
this->CBFullscreen->setChecked(previousFullscreenValue);
+ setFullscreen(previousFullscreenValue);
this->CBResolution->setCurrentIndex(previousResolutionIndex);
}
}
@@ -555,6 +862,11 @@
{
Q_UNUSED(state);
+ lblFullScreenRes->setVisible(state);
+ CBResolution->setVisible(state);
+ lblWinScreenRes->setVisible(!state);
+ winResContainer->setVisible(!state);
+
int index = this->CBStereoMode->currentIndex();
if (index != 7 && index != 8 && index != 9)
previousFullscreenValue = this->CBFullscreen->isChecked();
@@ -634,3 +946,199 @@
leProxyLogin->setEnabled(b);
leProxyPassword->setEnabled(b);
}
+
+// Video Recording
+
+void PageOptions::setConfig(GameUIConfig * config)
+{
+ this->config = config;
+}
+
+// user changed file format, we need to update list of codecs
+void PageOptions::changeAVFormat(int index)
+{
+ // remember selected codecs
+ QString prevVCodec = videoCodec();
+ QString prevACodec = audioCodec();
+
+ // clear lists of codecs
+ comboVideoCodecs->clear();
+ comboAudioCodecs->clear();
+
+ // get list of codecs for specified format
+ LibavInteraction::instance().fillCodecs(comboAVFormats->itemData(index).toString(), comboVideoCodecs, comboAudioCodecs);
+
+ // disable audio if there is no audio codec
+ if (comboAudioCodecs->count() == 0)
+ {
+ checkRecordAudio->setChecked(false);
+ checkRecordAudio->setEnabled(false);
+ }
+ else
+ checkRecordAudio->setEnabled(true);
+
+ // restore selected codecs if possible
+ int iVCodec = comboVideoCodecs->findData(prevVCodec);
+ if (iVCodec != -1)
+ comboVideoCodecs->setCurrentIndex(iVCodec);
+ int iACodec = comboAudioCodecs->findData(prevACodec);
+ if (iACodec != -1)
+ comboAudioCodecs->setCurrentIndex(iACodec);
+}
+
+// user switched checkbox 'use game resolution'
+void PageOptions::changeUseGameRes(int state)
+{
+ if (state && config)
+ {
+ // set resolution to game resolution
+ QRect resolution = config->vid_Resolution();
+ widthEdit->setText(QString::number(resolution.width()));
+ heightEdit->setText(QString::number(resolution.height()));
+ }
+ widthEdit->setEnabled(!state);
+ heightEdit->setEnabled(!state);
+}
+
+// user switched checkbox 'record audio'
+void PageOptions::changeRecordAudio(int state)
+{
+ comboAudioCodecs->setEnabled(!!state);
+}
+
+void PageOptions::setDefaultCodecs()
+{
+ // VLC should be able to handle any of these configurations
+ // Quicktime X only opens the first one
+ // Windows Media Player TODO
+ if (tryCodecs("mp4", "libx264", "aac"))
+ return;
+ if (tryCodecs("mp4", "libx264", "libfaac"))
+ return;
+ if (tryCodecs("mp4", "libx264", "libmp3lame"))
+ return;
+ if (tryCodecs("mp4", "libx264", "mp2"))
+ return;
+ if (tryCodecs("avi", "libxvid", "libmp3lame"))
+ return;
+ if (tryCodecs("avi", "libxvid", "ac3_fixed"))
+ return;
+ if (tryCodecs("avi", "libxvid", "mp2"))
+ return;
+ if (tryCodecs("avi", "mpeg4", "libmp3lame"))
+ return;
+ if (tryCodecs("avi", "mpeg4", "ac3_fixed"))
+ return;
+ if (tryCodecs("avi", "mpeg4", "mp2"))
+ return;
+
+ // this shouldn't happen, just in case
+ if (tryCodecs("ogg", "libtheora", "libvorbis"))
+ return;
+ tryCodecs("ogg", "libtheora", "flac");
+}
+
+void PageOptions::setDefaultOptions()
+{
+ framerateBox->setCurrentIndex(2);
+ bitrateBox->setValue(1000);
+ checkRecordAudio->setChecked(true);
+ checkUseGameRes->setChecked(true);
+ setDefaultCodecs();
+}
+
+void PageOptions::checkForUpdates()
+{
+ AutoUpdater *updater = NULL;
+
+#ifdef __APPLE__
+#ifdef SPARKLE_ENABLED
+ updater = new SparkleAutoUpdater();
+#endif
+#endif
+
+ if (updater)
+ {
+ updater->checkForUpdatesNow();
+ delete updater;
+ }
+}
+
+bool PageOptions::tryCodecs(const QString & format, const QString & vcodec, const QString & acodec)
+{
+ // first we should change format
+ int iFormat = comboAVFormats->findData(format);
+ if (iFormat == -1)
+ return false;
+ comboAVFormats->setCurrentIndex(iFormat);
+ // format was changed, so lists of codecs were automatically updated to codecs supported by this format
+
+ // try to find video codec
+ int iVCodec = comboVideoCodecs->findData(vcodec);
+ if (iVCodec == -1)
+ return false;
+ comboVideoCodecs->setCurrentIndex(iVCodec);
+
+ // try to find audio codec
+ int iACodec = comboAudioCodecs->findData(acodec);
+ if (iACodec == -1 && checkRecordAudio->isChecked())
+ return false;
+ if (iACodec != -1)
+ comboAudioCodecs->setCurrentIndex(iACodec);
+
+ return true;
+}
+
+// When the current tab is switched
+void PageOptions::tabIndexChanged(int index)
+{
+ if (index == binderTab) // Switched to bind tab
+ {
+ binder->resetInterface();
+
+ if (!config) return;
+
+ QStandardItemModel * binds = DataManager::instance().bindsModel();
+ for(int i = 0; i < BINDS_NUMBER; i++)
+ {
+ QString value = config->bind(i);
+ QModelIndexList mdl = binds->match(binds->index(0, 0), Qt::UserRole + 1, value, 1, Qt::MatchExactly);
+ if(mdl.size() == 1) binder->setBindIndex(i, mdl[0].row());
+ }
+ }
+
+ currentTab = index;
+}
+
+// When a key bind combobox is changed
+void PageOptions::bindUpdated(int bindID)
+{
+ int bindIndex = binder->bindIndex(bindID);
+
+ if (bindIndex == 0) bindIndex = resetBindToDefault(bindID);
+
+ // Save bind
+ QStandardItemModel * binds = DataManager::instance().bindsModel();
+ QString strbind = binds->index(binder->bindIndex(bindID), 0).data(Qt::UserRole + 1).toString();
+ config->setBind(bindID, strbind);
+}
+
+// Changes a key bind (bindID) to its default value. This updates the bind's combo-box in the UI.
+// Returns: The bind model index of the default.
+int PageOptions::resetBindToDefault(int bindID)
+{
+ QStandardItemModel * binds = DataManager::instance().bindsModel();
+ QModelIndexList mdl = binds->match(binds->index(0, 0), Qt::UserRole + 1, cbinds[bindID].strbind, 1, Qt::MatchExactly);
+ if(mdl.size() == 1) binder->setBindIndex(bindID, mdl[0].row());
+ return mdl[0].row();
+}
+
+// Called when "reset all binds" button is pressed
+void PageOptions::resetAllBinds()
+{
+ for (int i = 0; i < BINDS_NUMBER; i++)
+ {
+ resetBindToDefault(i);
+ bindUpdated(i);
+ }
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pageoptions.h
--- a/QTfrontend/ui/page/pageoptions.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pageoptions.h Fri Feb 22 05:05:32 2013 +0100
@@ -19,11 +19,32 @@
#ifndef PAGE_OPTIONS_H
#define PAGE_OPTIONS_H
+#include "igbox.h"
#include "AbstractPage.h"
+#include
+
+class GameUIConfig;
class FPSEdit;
-class IconedGroupBox;
class QSignalMapper;
+class KeyBinder;
+class QGridLayout;
+
+// Let's stay D-R-Y
+class OptionGroupBox : public IconedGroupBox
+{
+ Q_OBJECT
+
+ public:
+ OptionGroupBox(const QString & iconName,
+ const QString & title,
+ QWidget * parent = 0);
+ QGridLayout * layout();
+ void addDivider();
+
+ private:
+ QGridLayout * m_layout;
+};
class PageOptions : public AbstractPage
{
@@ -56,11 +77,13 @@
QComboBox *CBTeamName;
IconedGroupBox *AGGroupBox;
QComboBox *CBResolution;
+ QLineEdit *windowWidthEdit;
+ QLineEdit *windowHeightEdit;
QComboBox *CBStereoMode;
- QCheckBox *CBEnableSound;
- QCheckBox *CBEnableFrontendSound;
- QCheckBox *CBEnableMusic;
- QCheckBox *CBEnableFrontendMusic;
+ QCheckBox *CBFrontendSound;
+ QCheckBox *CBFrontendMusic;
+ QCheckBox *CBSound;
+ QCheckBox *CBMusic;
QCheckBox *CBFullscreen;
QCheckBox *CBFrontendFullscreen;
QCheckBox *CBShowFPS;
@@ -69,11 +92,13 @@
QCheckBox *CBNameWithDate;
#ifdef __APPLE__
QCheckBox *CBAutoUpdate;
+ QPushButton *BtnUpdateNow;
#endif
FPSEdit *fpsedit;
QLabel *labelNN;
- QSpinBox * volumeBox;
+ QSlider *SLVolume;
+ QLabel *lblVolumeLevel;
QLineEdit *editNetNick;
QLineEdit *editNetPassword;
QSlider *SLQuality;
@@ -84,6 +109,26 @@
QLineEdit * leProxyLogin;
QLineEdit * leProxyPassword;
+ QComboBox *framerateBox;
+ QSpinBox *bitrateBox;
+ QLineEdit *widthEdit;
+ QLineEdit *heightEdit;
+ QCheckBox *checkUseGameRes;
+ QCheckBox *checkRecordAudio;
+
+ QString format()
+ { return comboAVFormats->itemData(comboAVFormats->currentIndex()).toString(); }
+
+ QString videoCodec()
+ { return comboVideoCodecs->itemData(comboVideoCodecs->currentIndex()).toString(); }
+
+ QString audioCodec()
+ { return comboAudioCodecs->itemData(comboAudioCodecs->currentIndex()).toString(); }
+
+ void setDefaultCodecs();
+ bool tryCodecs(const QString & format, const QString & vcodec, const QString & acodec);
+ void setConfig(GameUIConfig * config);
+
void setTeamOptionsEnabled(bool enabled);
signals:
@@ -96,6 +141,8 @@
QLayout * bodyLayoutDefinition();
QLayout * footerLayoutDefinition();
void connectSignals();
+ int resetBindToDefault(int bindID);
+ void setupTabPage(QWidget * tabpage, QVBoxLayout ** leftColumn, QVBoxLayout ** rightColumn);
bool previousFullscreenValue;
int previousResolutionIndex;
@@ -106,6 +153,20 @@
QPushButton *BtnDeleteTeam;
QList m_colorButtons;
+ QComboBox *comboAVFormats;
+ QComboBox *comboVideoCodecs;
+ QComboBox *comboAudioCodecs;
+ QPushButton *btnDefaults;
+ QPushButton *btnUpdateNow;
+ GameUIConfig * config;
+ KeyBinder * binder;
+ int currentTab;
+ int binderTab;
+
+ QLabel * lblFullScreenRes;
+ QLabel * lblWinScreenRes;
+ QWidget * winResContainer;
+
private slots:
void forceFullscreen(int index);
void setFullscreen(int state);
@@ -118,6 +179,17 @@
void colorButtonClicked(int i);
void onColorModelDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight);
void onProxyTypeChanged();
+ void changeAVFormat(int index);
+ void changeUseGameRes(int state);
+ void changeRecordAudio(int state);
+ void checkForUpdates();
+ void tabIndexChanged(int);
+ void bindUpdated(int bindID);
+ void resetAllBinds();
+ void setVolume(int);
+
+ public slots:
+ void setDefaultOptions();
};
#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pageroomslist.cpp
--- a/QTfrontend/ui/page/pageroomslist.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pageroomslist.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -16,102 +16,177 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
+#include
+#include
#include
-#include
#include
#include
#include
#include
#include
#include
-#include
+#include
+#include
+#include
#include
#include "roomslistmodel.h"
#include "ammoSchemeModel.h"
-#include "pageroomslist.h"
#include "hwconsts.h"
#include "chatwidget.h"
+#include "roomnameprompt.h"
+#include "lineeditcursor.h"
+#include "pageroomslist.h"
QLayout * PageRoomsList::bodyLayoutDefinition()
{
- QGridLayout * pageLayout = new QGridLayout();
+ QVBoxLayout * pageLayout = new QVBoxLayout();
+ pageLayout->setSpacing(0);
+
+ QGridLayout * topLayout = new QGridLayout();
+ topLayout->setSpacing(0);
+ pageLayout->addLayout(topLayout, 0);
+
+ // Help/prompt message at top
+ QLabel * lblDesc = new QLabel(tr("Search for a room:"));
+ lblDesc->setObjectName("lblDesc");
+ lblDesc->setStyleSheet("#lblDesc { color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; padding: 4px 10px;}");
+ lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ lblDesc->setFixedHeight(24);
+ lblDesc->setMinimumWidth(0);
+
+ // Search text box
+ QWidget * searchContainer = new QWidget();
+ searchContainer->setFixedHeight(24);
+ searchContainer->setObjectName("searchContainer");
+ searchContainer->setStyleSheet("#searchContainer { background: #F6CB1C; border-top-right-radius: 10px; padding: 3px; }");
+ searchContainer->setFixedWidth(200);
+ searchText = new LineEditCursor(searchContainer);
+ searchText->setFixedWidth(200);
+ searchText->setMaxLength(60);
+ searchText->setFixedHeight(22);
+ searchText->setStyleSheet("LineEditCursor { border-width: 0px; border-radius: 6px; margin-top: 3px; margin-right: 3px; padding-left: 4px; padding-bottom: 2px; background-color: rgb(23, 11, 54); } LineEditCursor:hover, LineEditCursor:focus { background-color: rgb(13, 5, 68); }");
- QHBoxLayout * newRoomLayout = new QHBoxLayout();
- QLabel * roomNameLabel = new QLabel(this);
- roomNameLabel->setText(tr("Room Name:"));
- roomName = new QLineEdit(this);
- roomName->setMaxLength(60);
- newRoomLayout->addWidget(roomNameLabel);
- newRoomLayout->addWidget(roomName);
- pageLayout->addLayout(newRoomLayout, 0, 0, 1, 2);
+ // Corner widget
+ QLabel * corner = new QLabel();
+ corner->setPixmap(QPixmap(QString::fromUtf8(":/res/inverse-corner-bl.png")));
+ corner->setFixedSize(10, 10);
+
+ const QIcon& lp = QIcon(":/res/new.png");
+ QSize sz = lp.actualSize(QSize(65535, 65535));
+ BtnCreate = new QPushButton();
+ BtnCreate->setText(tr("Create room"));
+ BtnCreate->setIcon(lp);
+ BtnCreate->setStyleSheet("padding: 4px 8px; margin-bottom: 6px;");
+
+ BtnJoin = new QPushButton(tr("Join room"));
+ BtnJoin->setStyleSheet("padding: 4px 8px; margin-bottom: 6px; margin-left: 6px;");
+ BtnJoin->setEnabled(false);
- roomsList = new QTableView(this);
+ // Add widgets to top layout
+ topLayout->addWidget(lblDesc, 1, 0);
+ topLayout->addWidget(searchContainer, 1, 1);
+ topLayout->addWidget(corner, 1, 2, Qt::AlignBottom);
+ topLayout->addWidget(BtnCreate, 0, 4, 2, 1);
+ topLayout->addWidget(BtnJoin, 0, 5, 2, 1);
+
+ // Top layout stretch
+ topLayout->setRowStretch(0, 1);
+ topLayout->setRowStretch(1, 0);
+ topLayout->setColumnStretch(3, 1);
+
+ // Room list
+
+ roomsList = new RoomTableView(this);
roomsList->setSelectionBehavior(QAbstractItemView::SelectRows);
roomsList->verticalHeader()->setVisible(false);
roomsList->horizontalHeader()->setResizeMode(QHeaderView::Interactive);
roomsList->setAlternatingRowColors(true);
roomsList->setShowGrid(false);
roomsList->setSelectionMode(QAbstractItemView::SingleSelection);
- pageLayout->addWidget(roomsList, 1, 0, 3, 2);
- pageLayout->setRowStretch(2, 100);
+ roomsList->setStyleSheet("QTableView { border-top-left-radius: 0px; }");
+ roomsList->setFocusPolicy(Qt::NoFocus);
+ pageLayout->addWidget(roomsList, 200);
+
+ // Room filters container
+
+ QWidget * filtersContainer = new QWidget();
+ filtersContainer->setMaximumWidth(800);
+ filtersContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
- QHBoxLayout * filterLayout = new QHBoxLayout();
+ pageLayout->addSpacing(7);
+ pageLayout->addWidget(filtersContainer, 0, Qt::AlignHCenter);
+ pageLayout->addSpacing(7);
+
+ QHBoxLayout * filterLayout = new QHBoxLayout(filtersContainer);
+ filterLayout->setSpacing(0);
+ filterLayout->setMargin(0);
- QLabel * stateLabel = new QLabel(this);
- CBState = new QComboBox(this);
+ const int filterSpacing = 20;
+
+ // State button
- filterLayout->addWidget(stateLabel);
- filterLayout->addWidget(CBState);
- filterLayout->addStretch(1);
+ QPushButton * btnState = new QPushButton(tr("Room state"));
+ btnState->setStyleSheet("QPushButton { padding: 2px 4px; } QPushButton:pressed { background-color: #ffcc00; border-color: #ffcc00; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; color: #11084A; }");
+ btnState->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ filterLayout->addWidget(btnState);
+ filterLayout->addSpacing(filterSpacing);
+
+ // State menu
- QLabel * ruleLabel = new QLabel(this);
- ruleLabel->setText(tr("Rules:"));
+ QMenu * stateMenu = new QMenu(btnState);
+ showGamesInLobby = new QAction(QAction::tr("Show games in lobby"), stateMenu);
+ showGamesInLobby->setCheckable(true);
+ showGamesInLobby->setChecked(true);
+ showGamesInProgress = new QAction(QAction::tr("Show games in-progress"), stateMenu);
+ showGamesInProgress->setCheckable(true);
+ showGamesInProgress->setChecked(true);
+ stateMenu->addAction(showGamesInLobby);
+ stateMenu->addAction(showGamesInProgress);
+ btnState->setMenu(stateMenu);
+
+ // Rules dropdown
+
CBRules = new QComboBox(this);
+ CBRules->setStyleSheet("QComboBox { border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-left-width: 2px; }");
+
+ QLabel * ruleLabel = new QLabel(tr("Rules:"), this);
+ ruleLabel->setFixedHeight(CBRules->height());
+ ruleLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ ruleLabel->setStyleSheet("border: solid; border-width: 3px; border-right-width: 0px; border-color: #ffcc00; border-top-left-radius: 10px; border-bottom-left-radius: 10px; background-color: rgba(13, 5, 68, 70%);");
filterLayout->addWidget(ruleLabel);
filterLayout->addWidget(CBRules);
- filterLayout->addStretch(1);
+ filterLayout->addSpacing(filterSpacing);
+
+ // Weapons dropdown
- QLabel * weaponLabel = new QLabel(this);
- weaponLabel->setText(tr("Weapons:"));
CBWeapons = new QComboBox(this);
+ CBWeapons->setStyleSheet("QComboBox { border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-left-width: 2px; }");
+
+ QLabel * weaponLabel = new QLabel(tr("Weapons:"), this);
+ weaponLabel->setFixedHeight(CBWeapons->height());
+ weaponLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ weaponLabel->setStyleSheet("border: solid; border-width: 3px; border-right-width: 0px; border-color: #ffcc00; border-top-left-radius: 10px; border-bottom-left-radius: 10px; background-color: rgba(13, 5, 68, 70%);");
filterLayout->addWidget(weaponLabel);
filterLayout->addWidget(CBWeapons);
- filterLayout->addStretch(1);
+ filterLayout->addSpacing(filterSpacing);
- QLabel * searchLabel = new QLabel(this);
- searchLabel->setText(tr("Search:"));
- searchText = new QLineEdit(this);
- searchText->setMaxLength(60);
- searchText->setMinimumWidth(100);
- searchText->setMaximumWidth(360);
- filterLayout->addWidget(searchLabel);
- filterLayout->addWidget(searchText);
- filterLayout->setStretchFactor(searchText, 2);
+ // Clear filters button
- pageLayout->addLayout(filterLayout, 4, 0, 1, 2);
-
- chatWidget = new HWChatWidget(this, m_gameSettings, false);
- pageLayout->addWidget(chatWidget, 5, 0, 1, 3);
- pageLayout->setRowStretch(5, 350);
+ BtnClear = addButton(tr("Clear filters"), filterLayout, 0);
+ weaponLabel->setFixedHeight(CBWeapons->height());
+ BtnClear->setStyleSheet("padding: 4px;");
- BtnCreate = addButton(tr("Create"), pageLayout, 0, 2);
- BtnJoin = addButton(tr("Join"), pageLayout, 1, 2);
- BtnClear = addButton(tr("Clear"), pageLayout, 4, 2);
+ // Lobby chat
- // strech all but the buttons column
- pageLayout->setColumnStretch(0, 1);
- pageLayout->setColumnStretch(1, 1);
- pageLayout->setColumnStretch(2, 0);
+ chatWidget = new HWChatWidget(this, false);
+ pageLayout->addWidget(chatWidget, 350);
CBRules->addItem(QComboBox::tr("Any"));
- CBState->addItem(QComboBox::tr("Any"));
- CBState->addItem(QComboBox::tr("In lobby"));
- CBState->addItem(QComboBox::tr("In progress"));
return pageLayout;
}
@@ -120,18 +195,9 @@
{
QHBoxLayout * bottomLayout = new QHBoxLayout();
- lblCount = new QLabel(this);
- bottomLayout->addWidget(lblCount, 0, Qt::AlignHCenter);
- bottomLayout->setStretchFactor(lblCount, 1);
- lblCount->setText("?");
- lblCount->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
-
- BtnAdmin = addButton(tr("Admin features"), bottomLayout, 1);
- BtnAdmin->setMinimumWidth(160);
-
- // strech left part
- bottomLayout->setStretch(0, 1);
- bottomLayout->setStretch(1, 0);
+ BtnAdmin = addButton(tr("Admin features"), bottomLayout, 0);
+ BtnAdmin->setStyleSheet("padding: 4px auto;");
+ BtnAdmin->setWhatsThis(tr("Open server administration page"));
return bottomLayout;
}
@@ -143,24 +209,44 @@
connect(BtnCreate, SIGNAL(clicked()), this, SLOT(onCreateClick()));
connect(BtnJoin, SIGNAL(clicked()), this, SLOT(onJoinClick()));
connect(BtnClear, SIGNAL(clicked()), this, SLOT(onClearClick()));
+ connect(searchText, SIGNAL(moveUp()), this, SLOT(moveSelectionUp()));
+ connect(searchText, SIGNAL(moveDown()), this, SLOT(moveSelectionDown()));
+ connect(searchText, SIGNAL(returnPressed()), this, SLOT(onJoinClick()));
connect(roomsList, SIGNAL(doubleClicked (const QModelIndex &)), this, SLOT(onJoinClick()));
- connect(CBState, SIGNAL(currentIndexChanged (int)), this, SLOT(onFilterChanged()));
+ connect(roomsList, SIGNAL(clicked (const QModelIndex &)), searchText, SLOT(setFocus()));
+ connect(showGamesInLobby, SIGNAL(triggered()), this, SLOT(onFilterChanged()));
+ connect(showGamesInProgress, SIGNAL(triggered()), this, SLOT(onFilterChanged()));
connect(CBRules, SIGNAL(currentIndexChanged (int)), this, SLOT(onFilterChanged()));
connect(CBWeapons, SIGNAL(currentIndexChanged (int)), this, SLOT(onFilterChanged()));
connect(searchText, SIGNAL(textChanged (const QString &)), this, SLOT(onFilterChanged()));
connect(this, SIGNAL(askJoinConfirmation (const QString &)), this, SLOT(onJoinConfirmation(const QString &)), Qt::QueuedConnection);
+ // Set focus on search box
+ connect(this, SIGNAL(pageEnter()), searchText, SLOT(setFocus()));
+
// sorting
connect(roomsList->horizontalHeader(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)),
this, SLOT(onSortIndicatorChanged(int, Qt::SortOrder)));
}
+void PageRoomsList::moveSelectionUp()
+{
+ roomsList->setCurrentIndex(roomsList->moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier));
+}
-PageRoomsList::PageRoomsList(QWidget* parent, QSettings * gameSettings) :
+void PageRoomsList::moveSelectionDown()
+{
+ roomsList->setCurrentIndex(roomsList->moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier));
+}
+
+void PageRoomsList::roomSelectionChanged(const QModelIndex & current, const QModelIndex & previous)
+{
+ BtnJoin->setEnabled(current.isValid());
+}
+
+PageRoomsList::PageRoomsList(QWidget* parent) :
AbstractPage(parent)
{
- m_gameSettings = gameSettings;
-
roomsModel = NULL;
stateFilteredModel = NULL;
schemeFilteredModel = NULL;
@@ -421,16 +507,21 @@
void PageRoomsList::onCreateClick()
{
- if (roomName->text().size())
- emit askForCreateRoom(roomName->text());
+ RoomNamePrompt prompt(parentWidget()->parentWidget(), m_gameSettings->value("frontend/lastroomname", QString()).toString());
+ connect(&prompt, SIGNAL(roomNameChosen(const QString &)), this, SLOT(onRoomNameChosen(const QString &)));
+ prompt.exec();
+}
+
+void PageRoomsList::onRoomNameChosen(const QString & roomName)
+{
+ if (!roomName.trimmed().isEmpty())
+ {
+ m_gameSettings->setValue("frontend/lastroomname", roomName);
+ emit askForCreateRoom(roomName);
+ }
else
{
- QMessageBox roomNameMsg(this);
- roomNameMsg.setIcon(QMessageBox::Warning);
- roomNameMsg.setWindowTitle(QMessageBox::tr("Room Name - Error"));
- roomNameMsg.setText(QMessageBox::tr("Please enter room name"));
- roomNameMsg.setWindowModality(Qt::WindowModal);
- roomNameMsg.exec();
+ onCreateClick();
}
}
@@ -465,10 +556,12 @@
void PageRoomsList::onClearClick()
{
- CBState->setCurrentIndex(0);
+ showGamesInLobby->setChecked(true);
+ showGamesInProgress->setChecked(true);
CBRules->setCurrentIndex(0);
CBWeapons->setCurrentIndex(0);
searchText->clear();
+ searchText->setFocus();
}
void PageRoomsList::onJoinConfirmation(const QString & room)
@@ -489,7 +582,7 @@
void PageRoomsList::updateNickCounter(int cnt)
{
- lblCount->setText(tr("%1 players online", 0, cnt).arg(cnt));
+ setDefautDescription(tr("%1 players online", 0, cnt).arg(cnt));
}
void PageRoomsList::setUser(const QString & nickname)
@@ -533,6 +626,12 @@
// let the table view display the last model in the filter chain
roomsList->setModel(roomsModel);
+
+ // When the data changes
+ connect(roomsModel, SIGNAL(layoutChanged()), roomsList, SLOT(repaint()));
+
+ // When a selection changes
+ connect(roomsList->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(roomSelectionChanged(const QModelIndex &, const QModelIndex &)));
}
stateFilteredModel->setSourceModel(model);
@@ -561,6 +660,8 @@
this, SLOT(saveHeaderState()));
connect(roomsList->horizontalHeader(), SIGNAL(sectionResized(int, int, int)),
this, SLOT(saveHeaderState()));
+
+ roomsList->repaint();
}
@@ -591,13 +692,15 @@
roomsModel->setFilterWildcard(QString("*%1*").arg(searchText->text()));
- int stateIdx = CBState->currentIndex();
- // any = 0, in lobby/false = 1, in progress/true = 2
+ bool stateLobby = showGamesInLobby->isChecked();
+ bool stateProgress = showGamesInProgress->isChecked();
- if (stateIdx == 0)
+ if (stateLobby && stateProgress)
stateFilteredModel->setFilterWildcard("*"); // "any"
+ else if (stateLobby != stateProgress)
+ stateFilteredModel->setFilterFixedString(QString(stateProgress));
else
- stateFilteredModel->setFilterFixedString(QString(stateIdx == 2));
+ stateFilteredModel->setFilterFixedString(QString("none")); // Basically, none.
if (CBRules->currentIndex() == 0)
schemeFilteredModel->setFilterWildcard("*"); // "any"
@@ -612,13 +715,17 @@
QString("*%1*").arg(CBWeapons->currentText()));
}
+void PageRoomsList::setSettings(QSettings *settings)
+{
+ m_gameSettings = settings;
+}
bool PageRoomsList::restoreHeaderState()
{
if (!m_gameSettings->contains("frontend/roomslist_header"))
return false;
return roomsList->horizontalHeader()->restoreState(QByteArray::fromBase64(
- (m_gameSettings->value("frontend/roomslist_header").toString().toAscii())));
+ (m_gameSettings->value("frontend/roomslist_header").toByteArray())));
}
void PageRoomsList::saveHeaderState()
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pageroomslist.h
--- a/QTfrontend/ui/page/pageroomslist.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pageroomslist.h Fri Feb 22 05:05:32 2013 +0100
@@ -19,6 +19,7 @@
#ifndef PAGE_ROOMLIST_H
#define PAGE_ROOMLIST_H
+#include
#include "AbstractPage.h"
class HWChatWidget;
@@ -27,19 +28,27 @@
class RoomsListModel;
class QSortFilterProxyModel;
+class RoomTableView : public QTableView
+{
+ friend class PageRoomsList;
+
+ public:
+ RoomTableView(QWidget* parent = 0) : QTableView(parent){}
+};
+
class PageRoomsList : public AbstractPage
{
Q_OBJECT
public:
- PageRoomsList(QWidget* parent, QSettings * config);
+ PageRoomsList(QWidget* parent);
void displayError(const QString & message);
void displayNotice(const QString & message);
void displayWarning(const QString & message);
+ void setSettings(QSettings * settings);
- QLineEdit * roomName;
QLineEdit * searchText;
- QTableView * roomsList;
+ RoomTableView * roomsList;
QPushButton * BtnCreate;
QPushButton * BtnJoin;
QPushButton * BtnAdmin;
@@ -77,6 +86,10 @@
void onSortIndicatorChanged(int logicalIndex, Qt::SortOrder order);
void onFilterChanged();
void saveHeaderState();
+ void onRoomNameChosen(const QString &);
+ void roomSelectionChanged(const QModelIndex &, const QModelIndex &);
+ void moveSelectionUp();
+ void moveSelectionDown();
private:
QSettings * m_gameSettings;
@@ -84,6 +97,8 @@
QSortFilterProxyModel * stateFilteredModel;
QSortFilterProxyModel * schemeFilteredModel;
QSortFilterProxyModel * weaponsFilteredModel;
+ QAction * showGamesInLobby;
+ QAction * showGamesInProgress;
AmmoSchemeModel * ammoSchemeModel;
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagescheme.cpp
--- a/QTfrontend/ui/page/pagescheme.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagescheme.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -68,127 +68,102 @@
// Left
TBW_mode_Forts = new ToggleButtonWidget(gbGameModes, ":/res/btnForts@2x.png");
- TBW_mode_Forts->setToolTip("" + ToggleButtonWidget::tr("Fort Mode") + "");
TBW_mode_Forts->setWhatsThis(tr("Defend your fort and destroy the opponents, two team colours max!"));
glGMLayout->addWidget(TBW_mode_Forts,0,0,1,1);
TBW_teamsDivide = new ToggleButtonWidget(gbGameModes, ":/res/btnTeamsDivide@2x.png");
- TBW_teamsDivide->setToolTip("" + ToggleButtonWidget::tr("Divide Teams") + "");
TBW_teamsDivide->setWhatsThis(tr("Teams will start on opposite sides of the terrain, two team colours max!"));
glGMLayout->addWidget(TBW_teamsDivide,0,1,1,1);
TBW_solid = new ToggleButtonWidget(gbGameModes, ":/res/btnSolid@2x.png");
- TBW_solid->setToolTip("" + ToggleButtonWidget::tr("Solid Land") + "");
TBW_solid->setWhatsThis(tr("Land can not be destroyed!"));
glGMLayout->addWidget(TBW_solid,0,2,1,1);
TBW_border = new ToggleButtonWidget(gbGameModes, ":/res/btnBorder@2x.png");
- TBW_border->setToolTip("" + ToggleButtonWidget::tr("Add Border") + "");
TBW_border->setWhatsThis(tr("Add an indestructible border around the terrain"));
glGMLayout->addWidget(TBW_border,0,3,1,1);
TBW_lowGravity = new ToggleButtonWidget(gbGameModes, ":/res/btnLowGravity@2x.png");
- TBW_lowGravity->setToolTip("" + ToggleButtonWidget::tr("Low Gravity") + "");
TBW_lowGravity->setWhatsThis(tr("Lower gravity"));
glGMLayout->addWidget(TBW_lowGravity,0,4,1,1);
TBW_laserSight = new ToggleButtonWidget(gbGameModes, ":/res/btnLaserSight@2x.png");
- TBW_laserSight->setToolTip("" + ToggleButtonWidget::tr("Laser Sight") + "");
TBW_laserSight->setWhatsThis(tr("Assisted aiming with laser sight"));
glGMLayout->addWidget(TBW_laserSight,1,0,1,1);
TBW_invulnerable = new ToggleButtonWidget(gbGameModes, ":/res/btnInvulnerable@2x.png");
- TBW_invulnerable->setToolTip("" + ToggleButtonWidget::tr("Invulnerable") + "");
TBW_invulnerable->setWhatsThis(tr("All hogs have a personal forcefield"));
glGMLayout->addWidget(TBW_invulnerable,1,1,1,1);
TBW_resethealth = new ToggleButtonWidget(gbGameModes, ":/res/btnResetHealth@2x.png");
- TBW_resethealth->setToolTip("" + ToggleButtonWidget::tr("Reset Health") + "");
TBW_resethealth->setWhatsThis(tr("All (living) hedgehogs are fully restored at the end of turn"));
glGMLayout->addWidget(TBW_resethealth,1,2,1,1);
TBW_vampiric = new ToggleButtonWidget(gbGameModes, ":/res/btnVampiric@2x.png");
- TBW_vampiric->setToolTip("" + ToggleButtonWidget::tr("Vampirism") + "");
TBW_vampiric->setWhatsThis(tr("Gain 80% of the damage you do back in health"));
glGMLayout->addWidget(TBW_vampiric,1,3,1,1);
TBW_karma = new ToggleButtonWidget(gbGameModes, ":/res/btnKarma@2x.png");
- TBW_karma->setToolTip("" + ToggleButtonWidget::tr("Karma") + "");
TBW_karma->setWhatsThis(tr("Share your opponents pain, share their damage"));
glGMLayout->addWidget(TBW_karma,1,4,1,1);
TBW_artillery = new ToggleButtonWidget(gbGameModes, ":/res/btnArtillery@2x.png");
- TBW_artillery->setToolTip("" + ToggleButtonWidget::tr("Artillery") + "");
TBW_artillery->setWhatsThis(tr("Your hogs are unable to move, put your artillery skills to the test"));
glGMLayout->addWidget(TBW_artillery,2,0,1,1);
TBW_randomorder = new ToggleButtonWidget(gbGameModes, ":/res/btnRandomOrder@2x.png");
- TBW_randomorder->setToolTip("" + ToggleButtonWidget::tr("Random Order") + "");
TBW_randomorder->setWhatsThis(tr("Order of play is random instead of in room order."));
glGMLayout->addWidget(TBW_randomorder,2,1,1,1);
TBW_king = new ToggleButtonWidget(gbGameModes, ":/res/btnKing@2x.png");
- TBW_king->setToolTip("" + ToggleButtonWidget::tr("King") + "");
TBW_king->setWhatsThis(tr("Play with a King. If he dies, your side dies."));
glGMLayout->addWidget(TBW_king,2,2,1,1);
TBW_placehog = new ToggleButtonWidget(gbGameModes, ":/res/btnPlaceHog@2x.png");
- TBW_placehog->setToolTip("" + ToggleButtonWidget::tr("Place Hedgehogs") + "");
TBW_placehog->setWhatsThis(tr("Take turns placing your hedgehogs before the start of play."));
glGMLayout->addWidget(TBW_placehog,2,3,1,1);
TBW_sharedammo = new ToggleButtonWidget(gbGameModes, ":/res/btnSharedAmmo@2x.png");
- TBW_sharedammo->setToolTip("" + ToggleButtonWidget::tr("Clan Shares Ammo") + "");
TBW_sharedammo->setWhatsThis(tr("Ammo is shared between all teams that share a colour."));
glGMLayout->addWidget(TBW_sharedammo,2,4,1,1);
TBW_disablegirders = new ToggleButtonWidget(gbGameModes, ":/res/btnDisableGirders@2x.png");
- TBW_disablegirders->setToolTip("" + ToggleButtonWidget::tr("Disable Girders") + "");
TBW_disablegirders->setWhatsThis(tr("Disable girders when generating random maps."));
glGMLayout->addWidget(TBW_disablegirders,3,0,1,1);
TBW_disablelandobjects = new ToggleButtonWidget(gbGameModes, ":/res/btnDisableLandObjects@2x.png");
- TBW_disablelandobjects->setToolTip("" + ToggleButtonWidget::tr("Disable Land Objects") + "");
TBW_disablelandobjects->setWhatsThis(tr("Disable land objects when generating random maps."));
glGMLayout->addWidget(TBW_disablelandobjects,3,1,1,1);
TBW_aisurvival = new ToggleButtonWidget(gbGameModes, ":/res/btnAISurvival@2x.png");
- TBW_aisurvival->setToolTip("" + ToggleButtonWidget::tr("AI Survival Mode") + "");
TBW_aisurvival->setWhatsThis(tr("AI respawns on death."));
glGMLayout->addWidget(TBW_aisurvival,3,2,1,1);
TBW_infattack = new ToggleButtonWidget(gbGameModes, ":/res/btnInfAttack@2x.png");
- TBW_infattack->setToolTip("" + ToggleButtonWidget::tr("Unlimited Attacks") + "");
TBW_infattack->setWhatsThis(tr("Attacking does not end your turn."));
glGMLayout->addWidget(TBW_infattack,3,3,1,1);
TBW_resetweps = new ToggleButtonWidget(gbGameModes, ":/res/btnResetWeps@2x.png");
- TBW_resetweps->setToolTip("" + ToggleButtonWidget::tr("Reset Weapons") + "");
TBW_resetweps->setWhatsThis(tr("Weapons are reset to starting values each turn."));
glGMLayout->addWidget(TBW_resetweps,3,4,1,1);
TBW_perhogammo = new ToggleButtonWidget(gbGameModes, ":/res/btnPerHogAmmo@2x.png");
- TBW_perhogammo->setToolTip("" + ToggleButtonWidget::tr("Per Hedgehog Ammo") + "");
TBW_perhogammo->setWhatsThis(tr("Each hedgehog has its own ammo. It does not share with the team."));
glGMLayout->addWidget(TBW_perhogammo,4,0,1,1);
TBW_nowind = new ToggleButtonWidget(gbGameModes, ":/res/btnNoWind@2x.png");
- TBW_nowind->setToolTip("" + ToggleButtonWidget::tr("Disable Wind") + "");
TBW_nowind->setWhatsThis(tr("You will not have to worry about wind anymore."));
glGMLayout->addWidget(TBW_nowind,4,1,1,1);
TBW_morewind = new ToggleButtonWidget(gbGameModes, ":/res/btnMoreWind@2x.png");
- TBW_morewind->setToolTip("" + ToggleButtonWidget::tr("More Wind") + "");
TBW_morewind->setWhatsThis(tr("Wind will affect almost everything."));
glGMLayout->addWidget(TBW_morewind,4,2,1,1);
TBW_tagteam = new ToggleButtonWidget(gbGameModes, ":/res/btnTagTeam@2x.png");
- TBW_tagteam->setToolTip("" + ToggleButtonWidget::tr("Tag Team") + "");
TBW_tagteam->setWhatsThis(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@2x.png");
- TBW_bottomborder->setToolTip("" + ToggleButtonWidget::tr("Add Bottom Border") + "");
TBW_bottomborder->setWhatsThis(tr("Add an indestructible border along the bottom"));
glGMLayout->addWidget(TBW_bottomborder,4,4,1,1);
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagesingleplayer.cpp
--- a/QTfrontend/ui/page/pagesingleplayer.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagesingleplayer.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -36,22 +36,18 @@
topLine->addStretch();
BtnSimpleGamePage = addButton(":/res/SimpleGame.png", topLine, 0, true);
- BtnSimpleGamePage->setToolTip(tr("Simple Game"));
BtnSimpleGamePage->setWhatsThis(tr("Play a quick game against the computer with random settings"));
topLine->addSpacing(60);
BtnMultiplayer = addButton(":/res/Multiplayer.png", topLine, 1, true);
- BtnMultiplayer->setToolTip(tr("Multiplayer"));
BtnMultiplayer->setWhatsThis(tr("Play a hotseat game against your friends, or AI teams"));
topLine->addStretch();
BtnCampaignPage = addButton(":/res/Campaign.png", middleLine, 0, true);
- BtnCampaignPage->setToolTip(tr("Campaign Mode"));
BtnCampaignPage->setWhatsThis(tr("Campaign Mode"));
BtnCampaignPage->setVisible(true);
BtnTrainPage = addButton(":/res/Trainings.png", middleLine, 1, true);
- BtnTrainPage->setToolTip(tr("Training Mode"));
BtnTrainPage->setWhatsThis(tr("Practice your skills in a range of training missions"));
return vLayout;
@@ -63,11 +59,9 @@
bottomLine->addStretch();
BtnDemos = addButton(":/res/Record.png", bottomLine, 1, true);
- BtnDemos->setToolTip(tr("Demos"));
BtnDemos->setWhatsThis(tr("Watch recorded demos"));
BtnLoad = addButton(":/res/Load.png", bottomLine, 2, true);
BtnLoad->setStyleSheet("QPushButton{margin: 24px 0 0 0;}");
- BtnLoad->setToolTip(tr("Load"));
BtnLoad->setWhatsThis(tr("Load a previously saved game"));
bottomLine->setStretch(1,0);
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagetraining.cpp
--- a/QTfrontend/ui/page/pagetraining.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagetraining.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -118,7 +118,7 @@
DataManager & dataMgr = DataManager::instance();
// get locale
- QSettings settings(cfgdir->absolutePath() + "/hedgewars.ini",
+ QSettings settings("physfs://hedgewars.ini",
QSettings::IniFormat);
QString loc = settings.value("misc/locale", "").toString();
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagevideos.cpp
--- a/QTfrontend/ui/page/pagevideos.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagevideos.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -109,119 +109,6 @@
QGridLayout * pPageLayout = new QGridLayout();
pPageLayout->setColumnStretch(0, 1);
pPageLayout->setColumnStretch(1, 2);
- pPageLayout->setRowStretch(0, 1);
- pPageLayout->setRowStretch(1, 1);
-
- // options
- {
- IconedGroupBox* pOptionsGroup = new IconedGroupBox(this);
- pOptionsGroup->setIcon(QIcon(":/res/Settings.png")); // FIXME
- pOptionsGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- pOptionsGroup->setTitle(QGroupBox::tr("Video recording options"));
- QGridLayout * pOptLayout = new QGridLayout(pOptionsGroup);
-
- // label for format
- QLabel *labelFormat = new QLabel(pOptionsGroup);
- labelFormat->setText(QLabel::tr("Format"));
- pOptLayout->addWidget(labelFormat, 0, 0);
-
- // list of supported formats
- comboAVFormats = new QComboBox(pOptionsGroup);
- pOptLayout->addWidget(comboAVFormats, 0, 1, 1, 4);
- LibavInteraction::instance().fillFormats(comboAVFormats);
-
- // separator
- QFrame * hr = new QFrame(pOptionsGroup);
- hr->setFrameStyle(QFrame::HLine);
- hr->setLineWidth(3);
- hr->setFixedHeight(10);
- pOptLayout->addWidget(hr, 1, 0, 1, 5);
-
- // label for audio codec
- QLabel *labelACodec = new QLabel(pOptionsGroup);
- labelACodec->setText(QLabel::tr("Audio codec"));
- pOptLayout->addWidget(labelACodec, 2, 0);
-
- // list of supported audio codecs
- comboAudioCodecs = new QComboBox(pOptionsGroup);
- pOptLayout->addWidget(comboAudioCodecs, 2, 1, 1, 3);
-
- // checkbox 'record audio'
- checkRecordAudio = new QCheckBox(pOptionsGroup);
- checkRecordAudio->setText(QCheckBox::tr("Record audio"));
- pOptLayout->addWidget(checkRecordAudio, 2, 4);
-
- // separator
- hr = new QFrame(pOptionsGroup);
- hr->setFrameStyle(QFrame::HLine);
- hr->setLineWidth(3);
- hr->setFixedHeight(10);
- pOptLayout->addWidget(hr, 3, 0, 1, 5);
-
- // label for video codec
- QLabel *labelVCodec = new QLabel(pOptionsGroup);
- labelVCodec->setText(QLabel::tr("Video codec"));
- pOptLayout->addWidget(labelVCodec, 4, 0);
-
- // list of supported video codecs
- comboVideoCodecs = new QComboBox(pOptionsGroup);
- pOptLayout->addWidget(comboVideoCodecs, 4, 1, 1, 4);
-
- // label for resolution
- QLabel *labelRes = new QLabel(pOptionsGroup);
- labelRes->setText(QLabel::tr("Resolution"));
- pOptLayout->addWidget(labelRes, 5, 0);
-
- // width
- widthEdit = new QLineEdit(pOptionsGroup);
- widthEdit->setValidator(new QIntValidator(this));
- pOptLayout->addWidget(widthEdit, 5, 1);
-
- // x
- QLabel *labelX = new QLabel(pOptionsGroup);
- labelX->setText("X");
- pOptLayout->addWidget(labelX, 5, 2);
-
- // height
- heightEdit = new QLineEdit(pOptionsGroup);
- heightEdit->setValidator(new QIntValidator(pOptionsGroup));
- pOptLayout->addWidget(heightEdit, 5, 3);
-
- // checkbox 'use game resolution'
- checkUseGameRes = new QCheckBox(pOptionsGroup);
- checkUseGameRes->setText(QCheckBox::tr("Use game resolution"));
- pOptLayout->addWidget(checkUseGameRes, 5, 4);
-
- // label for framerate
- QLabel *labelFramerate = new QLabel(pOptionsGroup);
- labelFramerate->setText(QLabel::tr("Framerate"));
- pOptLayout->addWidget(labelFramerate, 6, 0);
-
- // framerate
- framerateBox = new QSpinBox(pOptionsGroup);
- framerateBox->setRange(1, 200);
- framerateBox->setSingleStep(1);
- pOptLayout->addWidget(framerateBox, 6, 1);
-
- // label for Bitrate
- QLabel *labelBitrate = new QLabel(pOptionsGroup);
- labelBitrate->setText(QLabel::tr("Bitrate (Kbps)"));
- pOptLayout->addWidget(labelBitrate, 6, 2);
-
- // bitrate
- bitrateBox = new QSpinBox(pOptionsGroup);
- bitrateBox->setRange(100, 5000);
- bitrateBox->setSingleStep(100);
- pOptLayout->addWidget(bitrateBox, 6, 3);
-
- // button 'set default options'
- btnDefaults = new QPushButton(pOptionsGroup);
- btnDefaults->setText(QPushButton::tr("Set default options"));
- btnDefaults->setWhatsThis(QPushButton::tr("Restore default coding parameters"));
- pOptLayout->addWidget(btnDefaults, 7, 0, 1, 5);
-
- pPageLayout->addWidget(pOptionsGroup, 1, 0);
- }
// list of videos
{
@@ -257,7 +144,7 @@
box->addWidget(filesTable);
box->addWidget(btnOpenDir);
- pPageLayout->addWidget(pTableGroup, 0, 1, 2, 1);
+ pPageLayout->addWidget(pTableGroup, 0, 1);
}
// description
@@ -267,7 +154,6 @@
pDescGroup->setTitle(QGroupBox::tr("Description"));
QVBoxLayout* pDescLayout = new QVBoxLayout(pDescGroup);
- QHBoxLayout* pTopDescLayout = new QHBoxLayout(0); // picture and text
QHBoxLayout* pBottomDescLayout = new QHBoxLayout(0); // buttons
// label with thumbnail picture
@@ -282,18 +168,19 @@
"border-radius: 4px;"
"}" );
clearThumbnail();
- pTopDescLayout->addWidget(labelThumbnail, 2);
// label with file description
labelDesc = new QLabel(pDescGroup);
labelDesc->setAlignment(Qt::AlignLeft | Qt::AlignTop);
labelDesc->setTextInteractionFlags(Qt::TextSelectableByMouse |
- Qt::TextSelectableByKeyboard |
+ Qt::TextSelectableByKeyboard |
Qt::LinksAccessibleByMouse |
Qt::LinksAccessibleByKeyboard);
labelDesc->setTextFormat(Qt::RichText);
+ labelDesc->setWordWrap(true);
labelDesc->setOpenExternalLinks(true);
- pTopDescLayout->addWidget(labelDesc, 1);
+ //labelDesc->setMinimumSize(ThumbnailSize);
+ //pTopDescLayout->addWidget(labelDesc, 1);
// buttons: play and delete
btnPlay = new QPushButton(QPushButton::tr("Play"), pDescGroup);
@@ -309,10 +196,10 @@
btnToYouTube->setWhatsThis(QPushButton::tr("Upload this video to your Youtube account"));
pBottomDescLayout->addWidget(btnToYouTube);
+ pDescLayout->addWidget(labelThumbnail, 0);
+ pDescLayout->addWidget(labelDesc, 0);
+ pDescLayout->addLayout(pBottomDescLayout, 0);
pDescLayout->addStretch(1);
- pDescLayout->addLayout(pTopDescLayout, 0);
- pDescLayout->addStretch(1);
- pDescLayout->addLayout(pBottomDescLayout, 0);
pPageLayout->addWidget(pDescGroup, 0, 0);
}
@@ -327,10 +214,6 @@
void PageVideos::connectSignals()
{
- connect(checkUseGameRes, SIGNAL(stateChanged(int)), this, SLOT(changeUseGameRes(int)));
- connect(checkRecordAudio, SIGNAL(stateChanged(int)), this, SLOT(changeRecordAudio(int)));
- connect(comboAVFormats, SIGNAL(currentIndexChanged(int)), this, SLOT(changeAVFormat(int)));
- connect(btnDefaults, SIGNAL(clicked()), this, SLOT(setDefaultOptions()));
connect(filesTable, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(cellDoubleClicked(int, int)));
connect(filesTable, SIGNAL(cellChanged(int,int)), this, SLOT(cellChanged(int, int)));
connect(filesTable, SIGNAL(currentCellChanged(int,int,int,int)), this, SLOT(currentCellChanged()));
@@ -362,124 +245,6 @@
startEncoding(); // this is for videos recorded from demos which were executed directly (without frontend)
}
-// user changed file format, we need to update list of codecs
-void PageVideos::changeAVFormat(int index)
-{
- // remember selected codecs
- QString prevVCodec = videoCodec();
- QString prevACodec = audioCodec();
-
- // clear lists of codecs
- comboVideoCodecs->clear();
- comboAudioCodecs->clear();
-
- // get list of codecs for specified format
- LibavInteraction::instance().fillCodecs(comboAVFormats->itemData(index).toString(), comboVideoCodecs, comboAudioCodecs);
-
- // disable audio if there is no audio codec
- if (comboAudioCodecs->count() == 0)
- {
- checkRecordAudio->setChecked(false);
- checkRecordAudio->setEnabled(false);
- }
- else
- checkRecordAudio->setEnabled(true);
-
- // restore selected codecs if possible
- int iVCodec = comboVideoCodecs->findData(prevVCodec);
- if (iVCodec != -1)
- comboVideoCodecs->setCurrentIndex(iVCodec);
- int iACodec = comboAudioCodecs->findData(prevACodec);
- if (iACodec != -1)
- comboAudioCodecs->setCurrentIndex(iACodec);
-}
-
-// user switched checkbox 'use game resolution'
-void PageVideos::changeUseGameRes(int state)
-{
- if (state && config)
- {
- // set resolution to game resolution
- QRect resolution = config->vid_Resolution();
- widthEdit->setText(QString::number(resolution.width()));
- heightEdit->setText(QString::number(resolution.height()));
- }
- widthEdit->setEnabled(!state);
- heightEdit->setEnabled(!state);
-}
-
-// user switched checkbox 'record audio'
-void PageVideos::changeRecordAudio(int state)
-{
- comboAudioCodecs->setEnabled(!!state);
-}
-
-void PageVideos::setDefaultCodecs()
-{
- // VLC should be able to handle any of these configurations
- // Quicktime X only opens the first one
- // Windows Media Player TODO
- if (tryCodecs("mp4", "libx264", "aac"))
- return;
- if (tryCodecs("mp4", "libx264", "libfaac"))
- return;
- if (tryCodecs("mp4", "libx264", "libmp3lame"))
- return;
- if (tryCodecs("mp4", "libx264", "mp2"))
- return;
- if (tryCodecs("avi", "libxvid", "libmp3lame"))
- return;
- if (tryCodecs("avi", "libxvid", "ac3_fixed"))
- return;
- if (tryCodecs("avi", "libxvid", "mp2"))
- return;
- if (tryCodecs("avi", "mpeg4", "libmp3lame"))
- return;
- if (tryCodecs("avi", "mpeg4", "ac3_fixed"))
- return;
- if (tryCodecs("avi", "mpeg4", "mp2"))
- return;
-
- // this shouldn't happen, just in case
- if (tryCodecs("ogg", "libtheora", "libvorbis"))
- return;
- tryCodecs("ogg", "libtheora", "flac");
-}
-
-void PageVideos::setDefaultOptions()
-{
- framerateBox->setValue(30);
- bitrateBox->setValue(1000);
- checkRecordAudio->setChecked(true);
- checkUseGameRes->setChecked(true);
- setDefaultCodecs();
-}
-
-bool PageVideos::tryCodecs(const QString & format, const QString & vcodec, const QString & acodec)
-{
- // first we should change format
- int iFormat = comboAVFormats->findData(format);
- if (iFormat == -1)
- return false;
- comboAVFormats->setCurrentIndex(iFormat);
- // format was changed, so lists of codecs were automatically updated to codecs supported by this format
-
- // try to find video codec
- int iVCodec = comboVideoCodecs->findData(vcodec);
- if (iVCodec == -1)
- return false;
- comboVideoCodecs->setCurrentIndex(iVCodec);
-
- // try to find audio codec
- int iACodec = comboAudioCodecs->findData(acodec);
- if (iACodec == -1 && checkRecordAudio->isChecked())
- return false;
- if (iACodec != -1)
- comboAudioCodecs->setCurrentIndex(iACodec);
-
- return true;
-}
-
// get file size as string
static QString FileSizeStr(const QString & path)
{
@@ -743,8 +508,8 @@
else
{
QString path = item->path();
- desc += tr("Date: ") + QFileInfo(path).created().toString(Qt::DefaultLocaleLongDate) + '\n';
- desc += tr("Size: ") + FileSizeStr(path) + '\n';
+ desc += tr("Date: %1\n").arg(QFileInfo(path).created().toString(Qt::DefaultLocaleLongDate));
+ desc += tr("Size: %1\n").arg(FileSizeStr(path));
if (item->desc.isEmpty())
{
// Extract description from file;
@@ -1096,7 +861,7 @@
int row = filesTable->currentRow();
VideoItem * item = nameItem(row);
- if (item->pUploading)
+ if (item->pUploading) //Act as 'cancel uploading' button
{
// ask user if (s)he is serious
QMessageBox reallyStopMsg(this);
@@ -1108,9 +873,10 @@
if (reallyStopMsg.exec() != QMessageBox::Ok)
return;
- item->pUploading->deleteLater();
+ item->pUploading->abort();
+ btnToYouTube->setText(QPushButton::tr("Upload to YouTube"));
filesTable->setCellWidget(row, vcProgress, NULL); // remove progress bar
- numUploads--;
+ //numUploads--;
return;
}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/page/pagevideos.h
--- a/QTfrontend/ui/page/pagevideos.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/page/pagevideos.h Fri Feb 22 05:05:32 2013 +0100
@@ -36,24 +36,6 @@
public:
PageVideos(QWidget* parent = 0);
- QSpinBox *framerateBox;
- QSpinBox *bitrateBox;
- QLineEdit *widthEdit;
- QLineEdit *heightEdit;
- QCheckBox *checkUseGameRes;
- QCheckBox *checkRecordAudio;
-
- QString format()
- { return comboAVFormats->itemData(comboAVFormats->currentIndex()).toString(); }
-
- QString videoCodec()
- { return comboVideoCodecs->itemData(comboVideoCodecs->currentIndex()).toString(); }
-
- QString audioCodec()
- { return comboAudioCodecs->itemData(comboAudioCodecs->currentIndex()).toString(); }
-
- void setDefaultCodecs();
- bool tryCodecs(const QString & format, const QString & vcodec, const QString & acodec);
void addRecorder(HWRecorder* pRecorder);
bool tryQuit(HWForm *form);
QString getVideosInProgress(); // get multi-line string with list of videos in progress
@@ -83,12 +65,6 @@
GameUIConfig * config;
QNetworkAccessManager* netManager;
- // options group
- QComboBox *comboAVFormats;
- QComboBox *comboVideoCodecs;
- QComboBox *comboAudioCodecs;
- QPushButton *btnDefaults;
-
// file list group
QTableWidget *filesTable;
QPushButton *btnOpenDir;
@@ -105,10 +81,6 @@
int numRecorders, numUploads;
private slots:
- void changeAVFormat(int index);
- void changeUseGameRes(int state);
- void changeRecordAudio(int state);
- void setDefaultOptions();
void encodingFinished(bool success);
void updateProgress(float value);
void cellDoubleClicked(int row, int column);
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/about.cpp
--- a/QTfrontend/ui/widget/about.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/about.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -21,8 +21,23 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
#include "hwconsts.h"
#include "SDLInteraction.h"
+#include "SDL.h"
+#include "SDL_version.h"
+#include "physfs.h"
+
+#ifdef VIDEOREC
+extern "C"
+{
+#include "libavutil/avutil.h"
+}
+#endif
#include "about.h"
@@ -31,6 +46,9 @@
{
QGridLayout *mainLayout = new QGridLayout(this);
+ QVBoxLayout * leftLayout = new QVBoxLayout();
+ mainLayout->addLayout(leftLayout, 0, 0, 2, 1);
+
QLabel *imageLabel = new QLabel;
QImage image(":/res/Hedgehog.png");
imageLabel->setPixmap(QPixmap::fromImage(image));
@@ -40,7 +58,7 @@
imageLabel->setMinimumHeight(30);
imageLabel->setMaximumHeight(300);
- mainLayout->addWidget(imageLabel, 0, 0, 2, 1);
+ leftLayout->addWidget(imageLabel, 0, Qt::AlignHCenter);
QLabel *lbl1 = new QLabel(this);
lbl1->setOpenExternalLinks(true);
@@ -51,7 +69,7 @@
""
""
);
@@ -59,98 +77,46 @@
mainLayout->addWidget(lbl1, 0, 1);
lbl2 = new QTextBrowser(this);
+ lbl2->setOpenExternalLinks(true);
+ QUrl localpage = QUrl::fromLocalFile(":/res/html/about.html");
+ lbl2->setSource(localpage); //sets the source of the label from the file above
+ mainLayout->addWidget(lbl2, 1, 1);
- lbl2->setOpenExternalLinks(true);
- lbl2->setText(
- "" +
- QString("") +
- QLabel::tr("Developers:") +
- "
"
- "Engine, frontend, net server: Andrey Korotaev <unC0Rr@gmail.com>
"
- "Many frontend improvements: Igor Ulyanov <disinbox@gmail.com>
"
- "Many engine and frontend improvements: Derek Pomery <nemo@m8y.org>
"
- "Drill rocket, Ballgun, RC Plane weapons: Martin Boze <afffect@gmail.com>
"
- "Mine number and time game settings: David A. Cuadrado <krawek@gmail.com>
"
- "Frontend improvements: Martin Minarik <ttsmj@pokec.sk>
"
- "Frontend improvements: Kristian Lehmann <email@thexception.net>
"
- "Mac OS X/iPhone port, OpenGL-ES conversion: Vittorio Giovara <vittorio.giovara@gmail.com>
"
- "Many engine and frontend improvements (and bugs): Richard Karolyi <sheepluva@" "ercatec.net>
"
- "Gamepad and Lua integration: Mario Liebisch <mario.liebisch@gmail.com>
"
- "Many engine improvements and graphics: Carlos Vives <mail@carlosvives.es>
"
- "Maze maps: Henning Kühn <prg@cooco.de>
"
- "Engine and frontend improvements: Henrik Rostedt <henrik.rostedt@gmail.com>
"
- "Lua game modes and missions: John Lambert <redgrinner@gmail.com>
"
- "Frontend improvements: Mayur Pawashe <zorgiepoo@gmail.com>
"
- "Android port: Richard Deurwaarder <xeli@xelification.com>
"
- "Android netplay, portability abstraction: Simeon Maxein <smaxein@googlemail.com>
"
- "WebGL port, some pas2c and GLES2 work: Meng Xiangyun <xymengxy@gmail.com>
"
- "Video recording: Stepan Podoskin <stepik-777@mail.ru>
"
- "Campaign support, first campaign: Szabolcs Orbàn <szabibibi@gmail.com>
"
- "
" +
+ /* Library information */
+
+ QString libinfo = "";
+
+#ifdef __GNUC__
+ libinfo.append(QString("GCC %1
").arg(__VERSION__));
+#else
+ libinfo.append(QString(tr("Unknown Compiler")).arg(__VERSION__) + QString("
"));
+#endif
+
+ libinfo.append(QString("SDL version: %1.%2.%3
")
+ .arg(SDL_MAJOR_VERSION)
+ .arg(SDL_MINOR_VERSION)
+ .arg(SDL_PATCHLEVEL));
- QLabel::tr("Art:") + "
"
- + QString::fromUtf8(
- "John Dum <fizzy@gmail.com>"
- "
"
- "Joshua Frese <joshfrese@gmail.com>"
- "
"
- "Stanko Tadić <stanko@mfhinc.net>"
- "
"
- "Julien Koesten <julienkoesten@aol.com>"
- "
"
- "Joshua O'Sullivan <coheedftw@hotmail.co.uk>"
- "
"
- "Nils Lück <nils.luck.design@gmail.com>"
- "
"
- "Guillaume Englert <genglert@hybird.org>"
- "
"
- "Hats: Trey Perry <tx.perry.j@gmail.com>"
- "
") +
- QLabel::tr("Sounds:") + "
"
- "Hedgehogs voice: Stephen Alexander <ArmagonNo1@gmail.com>"
- "
"
- "John Dum <fizzy@gmail.com>"
- "
"
- "Jonatan Nilsson <jonatanfan@gmail.com>"
- "
"
- "Daniel Martin <elhombresinremedio@gmail.com>"
- "" +
+ libinfo.append(QString("Qt version: %1
").arg(QT_VERSION_STR));
+
+#ifdef VIDEOREC
+ libinfo.append(QString("Libav version: %1.%2.%3
")
+ .arg(LIBAVUTIL_VERSION_MAJOR)
+ .arg(LIBAVUTIL_VERSION_MINOR)
+ .arg(LIBAVUTIL_VERSION_MICRO));
+#endif
- QLabel::tr("Translations:") + "
"
- + QString::fromUtf8(
- "Brazilian Portuguese: Romulo Fernandes Machado <abra185@gmail.com>
"
- "Bulgarian: Svetoslav Stefanov
"
- "Czech: Petr Řezáček <rezacek@gmail.com>
"
- "Chinese: Jie Luo <lililjlj@gmail.com>
"
- "English: Andrey Korotaev <unC0Rr@gmail.com>
"
- "Finnish: Nina Kuisma <ninnnu@gmail.com>
"
- "French: Antoine Turmel <geekshadow@gmail.com>, Clement Woitrain <sphrixclement@gmail.com>
"
- "German: Peter Hüwe <PeterHuewe@gmx.de>, Mario Liebisch <mario.liebisch@gmail.com>, Richard Karolyi <sheepluva@" "ercatec.net>
"
- "Greek: <talos_kriti@yahoo.gr>
"
- "Italian: Luca Bonora <bonora.luca@gmail.com>, Marco Bresciani
"
- "Japanese: ADAM Etienne <etienne.adam@gmail.com>
"
- "Korean: Anthony Bellew <anthonyreflected@gmail.com>
"
- "Lithuanian: Lukas Urbonas <lukasu08@gmail.com>
"
- "Polish: Maciej Mroziński <mynick2@o2.pl>, Wojciech Latkowski <magik17l@gmail.com>, Piotr Mitana, Maciej Górny
"
- "Portuguese: Fábio Canário <inufabie@gmail.com>
"
- "Russian: Andrey Korotaev <unC0Rr@gmail.com>
"
- "Slovak: Jose Riha
"
- "Spanish: Carlos Vives <mail@carlosvives.es>
"
- "Swedish: Niklas Grahn <raewolusjoon@yaoo.com>, Henrik Rostedt <henrik.rostedt@gmail.com>
"
- "Ukrainian: Eugene V. Lyubimkin <jackyf.devel@gmail.com>, Igor Paliychuk <mansonigor@gmail.com>, Eugene Sakara <eresid@gmail.com>"
- "
") +
+ libinfo.append(QString("PhysFS version: %1.%2.%3
")
+ .arg(PHYSFS_VER_MAJOR)
+ .arg(PHYSFS_VER_MINOR)
+ .arg(PHYSFS_VER_PATCH));
- QLabel::tr("Special thanks:") + "
"
- "Aleksey Andreev <blaknayabr@gmail.com>
"
- "Aleksander Rudalev <alexv@pomorsu.ru>
"
- "Natasha Korotaeva <layout@pisem.net>
"
- "Adam Higerd (aka ahigerd at FreeNode)"
- "
"
- );
- mainLayout->addWidget(lbl2, 1, 1);
+ QLabel * lblLibInfo = new QLabel();
+ lblLibInfo->setText(libinfo);
+ lblLibInfo->setWordWrap(true);
+ lblLibInfo->setMaximumWidth(280);
+ leftLayout->addWidget(lblLibInfo, 0, Qt::AlignHCenter);
+ leftLayout->addStretch(1);
setAcceptDrops(true);
}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/about.h
--- a/QTfrontend/ui/widget/about.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/about.h Fri Feb 22 05:05:32 2013 +0100
@@ -23,7 +23,6 @@
#include
#include
-
class About : public QWidget
{
Q_OBJECT
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/bgwidget.cpp
--- a/QTfrontend/ui/widget/bgwidget.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/bgwidget.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -176,6 +176,8 @@
int ydiff = newPos.y() - oldPos.y();
update(oldPos.x(), oldPos.y(), xdiff+sprite.width(), ydiff+sprite.height());
}
+
+ //repaint(); // Repaint every frame. Prevents ghosting of widgets if widgets resize in runtime.
}
void BGWidget::startAnimation()
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/chatwidget.cpp
--- a/QTfrontend/ui/widget/chatwidget.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/chatwidget.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
#include "DataManager.h"
#include "hwconsts.h"
@@ -156,28 +157,22 @@
void HWChatWidget::displayError(const QString & message)
{
addLine("msg_Error", " !!! " + message);
- // scroll to the end
- chatText->moveCursor(QTextCursor::End);
}
void HWChatWidget::displayNotice(const QString & message)
{
addLine("msg_Notice", " *** " + message);
- // scroll to the end
- chatText->moveCursor(QTextCursor::End);
}
void HWChatWidget::displayWarning(const QString & message)
{
addLine("msg_Warning", " *!* " + message);
- // scroll to the end
- chatText->moveCursor(QTextCursor::End);
}
-HWChatWidget::HWChatWidget(QWidget* parent, QSettings * gameSettings, bool notify) :
+HWChatWidget::HWChatWidget(QWidget* parent, bool notify) :
QWidget(parent),
mainLayout(this)
{
@@ -187,43 +182,54 @@
m_isAdmin = false;
m_autoKickEnabled = false;
- if(gameSettings->value("frontend/sound", true).toBool())
- {
- QStringList vpList =
- QStringList() << "Classic" << "Default" << "Mobster" << "Russian";
+ QStringList vpList =
+ QStringList() << "Classic" << "Default" << "Mobster" << "Russian";
- foreach (QString vp, vpList)
- {
- m_helloSounds.append(QString("physfs://Sounds/voices/%1/Hello.ogg").arg(vp));
- }
-
- m_hilightSound = "physfs://Sounds/beep.ogg";
-
+ foreach (const QString & vp, vpList)
+ {
+ m_helloSounds.append(QString("/Sounds/voices/%1/Hello.ogg").arg(vp));
}
- mainLayout.setSpacing(1);
- mainLayout.setMargin(1);
- mainLayout.setSizeConstraint(QLayout::SetMinimumSize);
- mainLayout.setColumnStretch(0, 76);
- mainLayout.setColumnStretch(1, 24);
+ m_hilightSound = "/Sounds/beep.ogg";
+
+ mainLayout.setMargin(0);
- chatEditLine = new SmartLineEdit(this);
- chatEditLine->setMaxLength(300);
- connect(chatEditLine, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
+ QWidget * leftSideContainer = new QWidget();
+ leftSideContainer->setObjectName("leftSideContainer");
+ leftSideContainer->setStyleSheet("#leftSideContainer { border-width: 0px; background-color: #ffcc00; border-radius: 10px;} QTextBrowser, SmartLineEdit { background-color: rgb(13, 5, 68); }");
+ QVBoxLayout * leftSide = new QVBoxLayout(leftSideContainer);
+ leftSide->setSpacing(3);
+ leftSide->setMargin(3);
+ mainLayout.addWidget(leftSideContainer, 76);
- mainLayout.addWidget(chatEditLine, 2, 0);
+ // Chat view
chatText = new QTextBrowser(this);
-
chatText->document()->setDefaultStyleSheet(styleSheet());
-
chatText->setMinimumHeight(20);
chatText->setMinimumWidth(10);
chatText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
chatText->setOpenLinks(false);
+ chatText->setStyleSheet("QTextBrowser { background-color: rgb(23, 11, 54); border-width: 0px; }");
connect(chatText, SIGNAL(anchorClicked(const QUrl&)),
this, SLOT(linkClicked(const QUrl&)));
- mainLayout.addWidget(chatText, 0, 0, 2, 1);
+ leftSide->addWidget(chatText, 1);
+
+ // Input box
+
+ // Normal: rgb(23, 11, 54)
+ // Hover: rgb(13, 5, 68)
+
+ chatEditLine = new SmartLineEdit();
+ chatEditLine->setMaxLength(300);
+ chatEditLine->setStyleSheet("SmartLineEdit { background-color: rgb(23, 11, 54); padding: 2px 8px; border-width: 0px; border-radius: 7px; } SmartLineEdit:hover, SmartLineEdit:focus { background-color: rgb(13, 5, 68); }");
+ chatEditLine->setFixedHeight(24);
+ chatEditLine->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ connect(chatEditLine, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
+
+ leftSide->addWidget(chatEditLine, 0);
+
+ // Nickname list
chatNicks = new QListView(this);
chatNicks->setIconSize(QSize(24, 16));
@@ -239,7 +245,8 @@
connect(chatNicks, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(nicksContextMenuRequested(QPoint)));
- mainLayout.addWidget(chatNicks, 0, 1, 3, 1);
+ mainLayout.addSpacing(0);
+ mainLayout.addWidget(chatNicks, 24);
// the userData is used to flag things that are even available when user
// is offline
@@ -281,6 +288,10 @@
clear();
}
+void HWChatWidget::setSettings(QSettings * settings)
+{
+ gameSettings = settings;
+}
void HWChatWidget::linkClicked(const QUrl & link)
{
@@ -435,6 +446,8 @@
if (s_displayNone->contains(cssClass))
return; // the css forbids us to display this line
+ beforeContentAdd();
+
if (chatStrings.size() > 250)
chatStrings.removeFirst();
@@ -457,11 +470,13 @@
chatText->setHtml(""+chatStrings.join("
")+"");
- chatText->moveCursor(QTextCursor::End);
+ afterContentAdd();
}
void HWChatWidget::onServerMessage(const QString& str)
{
+ beforeContentAdd();
+
if (chatStrings.size() > 250)
chatStrings.removeFirst();
@@ -469,7 +484,7 @@
chatText->setHtml(""+chatStrings.join("
")+"");
- chatText->moveCursor(QTextCursor::End);
+ afterContentAdd();
}
@@ -497,7 +512,7 @@
emit nickCountUpdate(chatNicks->model()->rowCount());
- if(notifyNick && notify && gameSettings->value("frontend/sound", true).toBool())
+ if (notifyNick && notify && (m_helloSounds.size() > 0))
{
SDLInteraction::instance().playSoundFile(
m_helloSounds.at(rand() % m_helloSounds.size()));
@@ -798,11 +813,7 @@
else if (tline == "/saveStyleSheet")
saveStyleSheet();
else
- {
- static QRegExp post("\\s.*$");
- tline.remove(post);
- displayWarning(tr("%1 is not a valid command!").arg(tline));
- }
+ emit consoleCommand(tline.mid(1));
return true;
}
@@ -889,3 +900,21 @@
m_nicksMenu->popup(chatNicks->mapToGlobal(pos));
}
+
+void HWChatWidget::beforeContentAdd()
+{
+ m_scrollBarPos = chatText->verticalScrollBar()->value();
+ m_scrollToBottom = m_scrollBarPos == chatText->verticalScrollBar()->maximum();
+}
+
+void HWChatWidget::afterContentAdd()
+{
+ if(m_scrollToBottom)
+ {
+ chatText->verticalScrollBar()->setValue(chatText->verticalScrollBar()->maximum());
+ chatText->moveCursor(QTextCursor::End);
+ } else
+ {
+ chatText->verticalScrollBar()->setValue(m_scrollBarPos);
+ }
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/chatwidget.h
--- a/QTfrontend/ui/widget/chatwidget.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/chatwidget.h Fri Feb 22 05:05:32 2013 +0100
@@ -54,7 +54,7 @@
Q_OBJECT
public:
- HWChatWidget(QWidget* parent, QSettings * gameSettings, bool notify);
+ HWChatWidget(QWidget* parent, bool notify);
void setIgnoreListKick(bool enabled); ///< automatically kick people on ignore list (if possible)
void setShowFollow(bool enabled);
static const QString & styleSheet();
@@ -63,6 +63,7 @@
void displayWarning(const QString & message);
void setUser(const QString & nickname);
void setUsersModel(QAbstractItemModel * model);
+ void setSettings(QSettings * settings);
protected:
virtual void dragEnterEvent(QDragEnterEvent * event);
@@ -82,6 +83,8 @@
void discardStyleSheet();
void saveStyleSheet();
QString linkedNick(const QString & nickname);
+ void beforeContentAdd();
+ void afterContentAdd();
public slots:
void onChatString(const QString& str);
@@ -99,10 +102,11 @@
void info(const QString & str);
void follow(const QString &);
void nickCountUpdate(int cnt);
+ void consoleCommand(const QString & command);
private:
bool m_isAdmin;
- QGridLayout mainLayout;
+ QHBoxLayout mainLayout;
QTextBrowser* chatText;
QStringList chatStrings;
QListView* chatNicks;
@@ -122,6 +126,8 @@
QList m_highlights; ///< regular expressions used for highlighting
bool notify;
bool m_autoKickEnabled;
+ bool m_scrollToBottom;
+ int m_scrollBarPos;
private slots:
void returnPressed();
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/colorwidget.h
--- a/QTfrontend/ui/widget/colorwidget.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/colorwidget.h Fri Feb 22 05:05:32 2013 +0100
@@ -13,7 +13,7 @@
class ColorWidget : public QFrame
{
Q_OBJECT
-
+
public:
explicit ColorWidget(QStandardItemModel *colorsModel, QWidget *parent = 0);
~ColorWidget();
@@ -24,7 +24,7 @@
signals:
void colorChanged(int color);
-
+
private:
int m_color;
QStandardItemModel * m_colorsModel;
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/feedbackdialog.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/feedbackdialog.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,484 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#ifdef Q_WS_WIN
+#define WINVER 0x0500
+#include
+#else
+#include
+#include
+#endif
+
+#ifdef Q_WS_MAC
+#include
+#endif
+
+#include
+
+#include "AbstractPage.h"
+#include "hwconsts.h"
+#include "feedbackdialog.h"
+
+FeedbackDialog::FeedbackDialog(QWidget * parent) : QDialog(parent)
+{
+ setModal(true);
+ setWindowFlags(Qt::Sheet);
+ setWindowModality(Qt::WindowModal);
+ setMinimumSize(700, 460);
+ resize(700, 460);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+ netManager = NULL;
+ GenerateSpecs();
+
+ /* Top layout */
+
+ QVBoxLayout * pageLayout = new QVBoxLayout();
+ QHBoxLayout * summaryLayout = new QHBoxLayout();
+ QHBoxLayout * emailLayout = new QHBoxLayout();
+ QHBoxLayout * descriptionLayout = new QHBoxLayout();
+ QHBoxLayout * combinedTopLayout = new QHBoxLayout();
+ QHBoxLayout * systemLayout = new QHBoxLayout();
+
+ info = new QLabel();
+ info->setText(
+ ""
+ "Please give us feedback!
"
+ "We are always happy about suggestions, ideas, or bug reports."
+ "Your email address is optional, but we may want to contact you."
+ "
"
+ );
+ pageLayout->addWidget(info);
+
+ QVBoxLayout * summaryEmailLayout = new QVBoxLayout();
+
+ const int labelWidth = 90;
+
+ label_email = new QLabel();
+ label_email->setText(QLabel::tr("Your Email"));
+ label_email->setFixedWidth(labelWidth);
+ emailLayout->addWidget(label_email);
+ email = new QLineEdit();
+ emailLayout->addWidget(email);
+ summaryEmailLayout->addLayout(emailLayout);
+
+ label_summary = new QLabel();
+ label_summary->setText(QLabel::tr("Summary"));
+ label_summary->setFixedWidth(labelWidth);
+ summaryLayout->addWidget(label_summary);
+ summary = new QLineEdit();
+ summaryLayout->addWidget(summary);
+ summaryEmailLayout->addLayout(summaryLayout);
+
+ combinedTopLayout->addLayout(summaryEmailLayout);
+
+ CheckSendSpecs = new QCheckBox();
+ CheckSendSpecs->setText(QLabel::tr("Send system information"));
+ CheckSendSpecs->setChecked(true);
+ systemLayout->addWidget(CheckSendSpecs);
+ BtnViewInfo = new QPushButton(tr("View"));
+ systemLayout->addWidget(BtnViewInfo, 1);
+ BtnViewInfo->setFixedSize(60, 30);
+ connect(BtnViewInfo, SIGNAL(clicked()), this, SLOT(ShowSpecs()));
+ combinedTopLayout->addLayout(systemLayout);
+
+ combinedTopLayout->setStretch(0, 1);
+ combinedTopLayout->insertSpacing(1, 20);
+
+ pageLayout->addLayout(combinedTopLayout);
+
+ label_description = new QLabel();
+ label_description->setText(QLabel::tr("Description"));
+ label_description->setFixedWidth(labelWidth);
+ descriptionLayout->addWidget(label_description, 0, Qt::AlignTop);
+ description = new QTextBrowser();
+ description->setReadOnly(false);
+ descriptionLayout->addWidget(description);
+ pageLayout->addLayout(descriptionLayout);
+
+ /* Bottom layout */
+
+ QHBoxLayout * bottomLayout = new QHBoxLayout();
+ QHBoxLayout * captchaLayout = new QHBoxLayout();
+ QVBoxLayout * captchaInputLayout = new QVBoxLayout();
+
+ QPushButton * BtnCancel = new QPushButton(tr("Cancel"));
+ bottomLayout->addWidget(BtnCancel, 0);
+ BtnCancel->setFixedSize(100, 40);
+ connect(BtnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+
+ bottomLayout->insertStretch(1);
+
+ label_captcha = new QLabel();
+ label_captcha->setStyleSheet("border: 3px solid #ffcc00; border-radius: 4px");
+ label_captcha->setText("loading
captcha");
+ label_captcha->setFixedSize(200, 50);
+ captchaLayout->addWidget(label_captcha);
+
+ label_captcha_input = new QLabel();
+ label_captcha_input->setText(QLabel::tr("Type the security code:"));
+ captchaInputLayout->addWidget(label_captcha_input);
+ captchaInputLayout->setAlignment(label_captcha, Qt::AlignBottom);
+ captcha_code = new QLineEdit();
+ captcha_code->setFixedSize(165, 30);
+ captchaInputLayout->addWidget(captcha_code);
+ captchaInputLayout->setAlignment(captcha_code, Qt::AlignTop);
+ captchaLayout->addLayout(captchaInputLayout);
+ captchaLayout->setAlignment(captchaInputLayout, Qt::AlignLeft);
+
+ bottomLayout->addLayout(captchaLayout);
+ bottomLayout->addSpacing(40);
+
+ // TODO: Set green arrow icon for send button (:/res/Start.png)
+ BtnSend = new QPushButton(tr("Send Feedback"));
+ bottomLayout->addWidget(BtnSend, 0);
+ BtnSend->setFixedSize(120, 40);
+ connect(BtnSend, SIGNAL(clicked()), this, SLOT(SendFeedback()));
+
+ bottomLayout->setStretchFactor(captchaLayout, 0);
+ bottomLayout->setStretchFactor(BtnSend, 1);
+
+ QVBoxLayout * dialogLayout = new QVBoxLayout(this);
+ dialogLayout->addLayout(pageLayout, 1);
+ dialogLayout->addLayout(bottomLayout);
+
+ LoadCaptchaImage();
+}
+
+void FeedbackDialog::GenerateSpecs()
+{
+ // Gather some information about the system and embed it into the report
+ QDesktopWidget* screen = QApplication::desktop();
+ QString os_version = "Operating system: ";
+ QString qt_version = QString("Qt version: ") + QT_VERSION_STR + QString("\n");
+ QString total_ram = "Total RAM: ";
+ QString number_of_cores = "Number of cores: ";
+ QString compiler_bits = "Compiler architecture: ";
+ QString compiler_version = "Compiler version: ";
+ QString kernel_line = "Kernel: ";
+ QString screen_size = "Size of the screen(s): " +
+ QString::number(screen->width()) + "x" + QString::number(screen->height()) + "\n";
+ QString number_of_screens = "Number of screens: " + QString::number(screen->screenCount()) + "\n";
+ std::string processor_name = "Processor: ";
+
+ // platform specific code
+#ifdef Q_WS_MACX
+ number_of_cores += QString::number(sysconf(_SC_NPROCESSORS_ONLN)) + "\n";
+
+ uint64_t memsize;
+ size_t len = sizeof(memsize);
+ static int mib_s[2] = { CTL_HW, HW_MEMSIZE };
+ if (sysctl (mib_s, 2, &memsize, &len, NULL, 0) == 0)
+ total_ram += QString::number(memsize/1024/1024) + " MB\n";
+ else
+ total_ram += "Error getting total RAM information\n";
+
+ int mib[] = {CTL_KERN, KERN_OSRELEASE};
+ sysctl(mib, sizeof mib / sizeof(int), NULL, &len, NULL, 0);
+
+ char *kernelVersion = (char *)malloc(sizeof(char)*len);
+ sysctl(mib, sizeof mib / sizeof(int), kernelVersion, &len, NULL, 0);
+
+ QString kernelVersionStr = QString(kernelVersion);
+ free(kernelVersion);
+ int major_version = kernelVersionStr.split(".").first().toUInt() - 4;
+ int minor_version = kernelVersionStr.split(".").at(1).toUInt();
+ os_version += QString("Mac OS X 10.%1.%2").arg(major_version).arg(minor_version) + " ";
+
+ switch(major_version)
+ {
+ case 4: os_version += "\"Tiger\"\n"; break;
+ case 5: os_version += "\"Leopard\"\n"; break;
+ case 6: os_version += "\"Snow Leopard\"\n"; break;
+ case 7: os_version += "\"Lion\"\n"; break;
+ case 8: os_version += "\"Mountain Lion\"\n"; break;
+ default: os_version += "\"Unknown version\"\n"; break;
+ }
+#endif
+#ifdef Q_WS_WIN
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ number_of_cores += QString::number(sysinfo.dwNumberOfProcessors) + "\n";
+ MEMORYSTATUSEX status;
+ status.dwLength = sizeof(status);
+ GlobalMemoryStatusEx(&status);
+ total_ram += QString::number(status.ullTotalPhys);
+
+ switch(QSysInfo::WinVersion())
+ {
+ case QSysInfo::WV_2000: os_version += "Windows 2000\n"; break;
+ case QSysInfo::WV_XP: os_version += "Windows XP\n"; break;
+ case QSysInfo::WV_VISTA: os_version += "Windows Vista\n"; break;
+ case QSysInfo::WV_WINDOWS7: os_version += "Windows 7\n"; break;
+ default: os_version += "Windows (Unknown version)\n"; break;
+ }
+ kernel_line += "Windows kernel\n";
+#endif
+#ifdef Q_WS_X11
+ number_of_cores += QString::number(sysconf(_SC_NPROCESSORS_ONLN)) + "\n";
+ long pages = sysconf(_SC_PHYS_PAGES),
+/*
+#ifndef Q_OS_FREEBSD
+ available_pages = sysconf(_SC_AVPHYS_PAGES),
+#else
+ available_pages = 0,
+#endif*/
+ page_size = sysconf(_SC_PAGE_SIZE);
+ total_ram += QString::number(pages * page_size) + "\n";
+ os_version += "GNU/Linux or BSD\n";
+#endif
+
+ // uname -a
+#if defined(Q_WS_X11) || defined(Q_WS_MACX)
+ QProcess *process = new QProcess();
+ QStringList arguments = QStringList("-a");
+ process->start("uname", arguments);
+ if (process->waitForFinished())
+ kernel_line += QString(process->readAll());
+ delete process;
+#endif
+
+ // cpu info
+ quint32 registers[4];
+ quint32 i;
+
+ i = 0x80000002;
+ asm volatile
+ ("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
+ : "a" (i), "c" (0));
+ processor_name += std::string((const char *)®isters[0], 4);
+ processor_name += std::string((const char *)®isters[1], 4);
+ processor_name += std::string((const char *)®isters[2], 4);
+ processor_name += std::string((const char *)®isters[3], 4);
+ i = 0x80000003;
+ asm volatile
+ ("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
+ : "a" (i), "c" (0));
+ processor_name += std::string((const char *)®isters[0], 4);
+ processor_name += std::string((const char *)®isters[1], 4);
+ processor_name += std::string((const char *)®isters[2], 4);
+ processor_name += std::string((const char *)®isters[3], 4);
+ i = 0x80000004;
+ asm volatile
+ ("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
+ : "a" (i), "c" (0));
+ processor_name += std::string((const char *)®isters[0], 4);
+ processor_name += std::string((const char *)®isters[1], 4);
+ processor_name += std::string((const char *)®isters[2], 4);
+ processor_name += std::string((const char *)®isters[3], 3);
+
+ // compiler
+#ifdef __GNUC__
+ compiler_version += "GCC " + QString(__VERSION__) + "\n";
+#else
+ compiler_version += "Unknown\n";
+#endif
+
+ if(sizeof(void*) == 4)
+ compiler_bits += "i386\n";
+ else if(sizeof(void*) == 8)
+ compiler_bits += "x86_64\n";
+
+ // concat system info
+ specs = qt_version
+ + os_version
+ + total_ram
+ + screen_size
+ + number_of_screens
+ + QString::fromStdString(processor_name + "\n")
+ + number_of_cores
+ + compiler_version
+ + compiler_bits
+ + kernel_line;
+}
+
+void FeedbackDialog::ShowErrorMessage(const QString & msg)
+{
+ QMessageBox msgMsg(this);
+ msgMsg.setIcon(QMessageBox::Warning);
+ msgMsg.setWindowTitle(QMessageBox::tr("Hedgewars - Error"));
+ msgMsg.setText(msg);
+ msgMsg.setWindowModality(Qt::WindowModal);
+ msgMsg.exec();
+}
+
+void FeedbackDialog::ShowSpecs()
+{
+ QMessageBox msgMsg(this);
+ msgMsg.setIcon(QMessageBox::Information);
+ msgMsg.setWindowTitle(QMessageBox::tr("System Information Preview"));
+ msgMsg.setText(specs);
+ msgMsg.setTextFormat(Qt::PlainText);
+ msgMsg.setWindowModality(Qt::WindowModal);
+ msgMsg.setStyleSheet("background: #0A0533;");
+ msgMsg.exec();
+}
+
+void FeedbackDialog::NetReply(QNetworkReply *reply)
+{
+ if (reply == genCaptchaRequest)
+ {
+ if (reply->error() != QNetworkReply::NoError)
+ {
+ qDebug() << "Error generating captcha image: " << reply->errorString();
+ ShowErrorMessage(QMessageBox::tr("Failed to generate captcha"));
+ return;
+ }
+
+ bool okay;
+ QByteArray body = reply->readAll();
+ captchaID = QString(body).toInt(&okay);
+
+ if (!okay)
+ {
+ qDebug() << "Failed to get captcha ID: " << body;
+ ShowErrorMessage(QMessageBox::tr("Failed to generate captcha"));
+ return;
+ }
+
+ QString url = "http://hedgewars.org/feedback/?captcha&id=";
+ url += QString::number(captchaID);
+
+ QNetworkAccessManager *netManager = GetNetManager();
+ QUrl captchaURL(url);
+ QNetworkRequest req(captchaURL);
+ captchaImageRequest = netManager->get(req);
+ }
+ else if (reply == captchaImageRequest)
+ {
+ if (reply->error() != QNetworkReply::NoError)
+ {
+ qDebug() << "Error loading captcha image: " << reply->errorString();
+ ShowErrorMessage(QMessageBox::tr("Failed to download captcha"));
+ return;
+ }
+
+ QByteArray imageData = reply->readAll();
+ QPixmap pixmap;
+ pixmap.loadFromData(imageData);
+ label_captcha->setPixmap(pixmap);
+ captcha_code->setText("");
+ }
+}
+
+QNetworkAccessManager * FeedbackDialog::GetNetManager()
+{
+ if (netManager) return netManager;
+ netManager = new QNetworkAccessManager(this);
+ connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(NetReply(QNetworkReply*)));
+ return netManager;
+}
+
+void FeedbackDialog::LoadCaptchaImage()
+{
+ QNetworkAccessManager *netManager = GetNetManager();
+ QUrl captchaURL("http://hedgewars.org/feedback/?gencaptcha");
+ QNetworkRequest req(captchaURL);
+ genCaptchaRequest = netManager->get(req);
+}
+
+void FeedbackDialog::finishedSlot(QNetworkReply* reply)
+{
+ if (reply && reply->error() == QNetworkReply::NoError)
+ {
+ QMessageBox infoMsg(this);
+ infoMsg.setIcon(QMessageBox::Information);
+ infoMsg.setWindowTitle(QMessageBox::tr("Hedgewars - Success"));
+ infoMsg.setText(reply->readAll());
+ infoMsg.setWindowModality(Qt::WindowModal);
+ infoMsg.exec();
+
+ accept();
+
+ return;
+ }
+ else
+ {
+ ShowErrorMessage(QString("Error: ") + reply->readAll());
+ LoadCaptchaImage();
+ }
+}
+
+void FeedbackDialog::SendFeedback()
+{
+ // Get form data
+
+ QString summary = this->summary->text();
+ QString description = this->description->toPlainText();
+ QString email = this->email->text();
+ QString captchaCode = this->captcha_code->text();
+ QString captchaID = QString::number(this->captchaID);
+ QString version = "HedgewarsFoundation-Hedgewars-" + (cVersionString?(*cVersionString):QString(""));
+
+ if (summary.isEmpty() || description.isEmpty())
+ {
+ ShowErrorMessage(QMessageBox::tr("Please fill out all fields. Email is optional."));
+ return;
+ }
+
+ // Submit issue to PHP script
+
+ QByteArray body;
+ body.append("captcha=");
+ body.append(captchaID);
+ body.append("&code=");
+ body.append(captchaCode);
+ body.append("&version=");
+ body.append(QUrl::toPercentEncoding(version));
+ body.append("&title=");
+ body.append(QUrl::toPercentEncoding(summary));
+ body.append("&body=");
+ body.append(QUrl::toPercentEncoding(description));
+ body.append("&email=");
+ body.append(QUrl::toPercentEncoding(email));
+ if (CheckSendSpecs->isChecked())
+ {
+ body.append("&specs=");
+ body.append(QUrl::toPercentEncoding(specs));
+ }
+
+ nam = new QNetworkAccessManager(this);
+ connect(nam, SIGNAL(finished(QNetworkReply*)),
+ this, SLOT(finishedSlot(QNetworkReply*)));
+
+ QNetworkRequest header(QUrl("http://hedgewars.org/feedback/?submit"));
+ header.setRawHeader("Content-Length", QString::number(body.size()).toAscii());
+ header.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ nam->post(header, body);
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/feedbackdialog.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/feedbackdialog.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,75 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef FEEDBACKDIALOG_H
+#define FEEDBACKDIALOG_H
+
+#include
+
+class QNetworkReply;
+class QNetworkAccessManager;
+class QCheckBox;
+class QLineEdit;
+class QTextBrowser;
+class QLabel;
+
+class FeedbackDialog : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ FeedbackDialog(QWidget * parent = 0);
+ void EmbedSystemInfo();
+ void LoadCaptchaImage();
+
+ QPushButton * BtnSend;
+ QPushButton * BtnViewInfo;
+ QCheckBox * CheckSendSpecs;
+ QLineEdit * summary;
+ QTextBrowser * description;
+ QLabel * info;
+ QLabel * label_summary;
+ QLabel * label_description;
+ QLabel * label_captcha;
+ QLabel * label_email;
+ QLabel * label_captcha_input;
+ QLineEdit * captcha_code;
+ QLineEdit * email;
+ int captchaID;
+ QString specs;
+
+ private:
+ void GenerateSpecs();
+ QLayout * bodyLayoutDefinition();
+ QLayout * footerLayoutDefinition();
+ QNetworkAccessManager * GetNetManager();
+ void ShowErrorMessage(const QString & msg);
+
+ QNetworkAccessManager * netManager;
+ QNetworkReply * captchaImageRequest;
+ QNetworkReply * genCaptchaRequest;
+ QNetworkAccessManager * nam;
+
+ private slots:
+ virtual void NetReply(QNetworkReply*);
+ virtual void ShowSpecs();
+ void SendFeedback();
+ void finishedSlot(QNetworkReply* reply);
+};
+
+#endif // FEEDBACKDIALOG_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/gamecfgwidget.cpp
--- a/QTfrontend/ui/widget/gamecfgwidget.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/gamecfgwidget.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -24,7 +24,11 @@
#include
#include
#include
+#include
+#include
#include
+#include
+#include
#include "gamecfgwidget.h"
#include "igbox.h"
@@ -33,6 +37,7 @@
#include "ammoSchemeModel.h"
#include "proto.h"
#include "GameStyleModel.h"
+#include "themeprompt.h"
GameCFGWidget::GameCFGWidget(QWidget* parent) :
QGroupBox(parent)
@@ -40,28 +45,76 @@
, seedRegexp("\\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\}")
{
mainLayout.setMargin(0);
-// mainLayout.setSizeConstraint(QLayout::SetMinimumSize);
+ setMinimumHeight(310);
+ setMaximumHeight(447);
+ setMinimumWidth(470);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_master = true;
+
+ // Easy containers for the map/game options in either stacked or tabbed mode
+
+ mapContainerFree = new QWidget();
+ mapContainerTabbed = new QWidget();
+ optionsContainerFree = new QWidget();
+ optionsContainerTabbed = new QWidget();
+ tabbed = false;
+
+ // Container for when in tabbed mode
- pMapContainer = new HWMapContainer(this);
- mainLayout.addWidget(pMapContainer, 0, 0);
+ tabs = new QTabWidget(this);
+ tabs->setFixedWidth(470);
+ tabs->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ tabs->addTab(mapContainerTabbed, tr("Map"));
+ tabs->addTab(optionsContainerTabbed, tr("Game options"));
+ tabs->setObjectName("gameCfgWidgetTabs");
+ mainLayout.addWidget(tabs, 1);
+ tabs->setVisible(false);
+
+ // Container for when in stacked mode
+
+ StackContainer = new QWidget();
+ StackContainer->setObjectName("gameStackContainer");
+ mainLayout.addWidget(StackContainer, 1);
+ QVBoxLayout * stackLayout = new QVBoxLayout(StackContainer);
- IconedGroupBox *GBoxOptions = new IconedGroupBox(this);
- GBoxOptions->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
- mainLayout.addWidget(GBoxOptions, 1, 0);
+ // Map options
+
+ pMapContainer = new HWMapContainer(mapContainerFree);
+ stackLayout->addWidget(mapContainerFree, 0, Qt::AlignHCenter);
+ pMapContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ pMapContainer->setFixedSize(width() - 14, 278);
+ mapContainerFree->setFixedSize(pMapContainer->width(), pMapContainer->height());
+
+ // Horizontal divider
+
+ QFrame * divider = new QFrame();
+ divider->setFrameShape(QFrame::HLine);
+ divider->setFrameShadow(QFrame::Plain);
+ stackLayout->addWidget(divider, 0, Qt::AlignBottom);
+ //stackLayout->setRowMinimumHeight(1, 10);
- QGridLayout *GBoxOptionsLayout = new QGridLayout(GBoxOptions);
+ // Game options
+
+ optionsContainerTabbed->setContentsMargins(0, 0, 0, 0);
+ optionsContainerFree->setFixedSize(width() - 14, 140);
+ stackLayout->addWidget(optionsContainerFree, 0, Qt::AlignHCenter);
- GBoxOptions->setTitle(tr("Game Options"));
- GBoxOptionsLayout->addWidget(new QLabel(QLabel::tr("Style"), GBoxOptions), 1, 0);
+ OptionsInnerContainer = new QWidget(optionsContainerFree);
+ m_childWidgets << OptionsInnerContainer;
+ OptionsInnerContainer->setFixedSize(optionsContainerFree->width(), optionsContainerFree->height());
+ OptionsInnerContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ GBoxOptionsLayout = new QGridLayout(OptionsInnerContainer);
- Scripts = new QComboBox(GBoxOptions);
+ GBoxOptionsLayout->addWidget(new QLabel(QLabel::tr("Style"), this), 1, 0);
+
+ Scripts = new QComboBox(this);
GBoxOptionsLayout->addWidget(Scripts, 1, 1);
Scripts->setModel(DataManager::instance().gameStyleModel());
m_curScript = Scripts->currentText();
connect(Scripts, SIGNAL(currentIndexChanged(int)), this, SLOT(scriptChanged(int)));
- QWidget *SchemeWidget = new QWidget(GBoxOptions);
+ QWidget *SchemeWidget = new QWidget(this);
GBoxOptionsLayout->addWidget(SchemeWidget, 2, 0, 1, 2);
QGridLayout *SchemeWidgetLayout = new QGridLayout(SchemeWidget);
@@ -76,7 +129,7 @@
QPixmap pmEdit(":/res/edit.png");
QPushButton * goToSchemePage = new QPushButton(SchemeWidget);
- goToSchemePage->setToolTip(tr("Edit schemes"));
+ goToSchemePage->setWhatsThis(tr("Edit schemes"));
goToSchemePage->setIconSize(pmEdit.size());
goToSchemePage->setIcon(pmEdit);
goToSchemePage->setMaximumWidth(pmEdit.width() + 6);
@@ -91,7 +144,7 @@
connect(WeaponsName, SIGNAL(currentIndexChanged(int)), this, SLOT(ammoChanged(int)));
QPushButton * goToWeaponPage = new QPushButton(SchemeWidget);
- goToWeaponPage->setToolTip(tr("Edit weapons"));
+ goToWeaponPage->setWhatsThis(tr("Edit weapons"));
goToWeaponPage->setIconSize(pmEdit.size());
goToWeaponPage->setIcon(pmEdit);
goToWeaponPage->setMaximumWidth(pmEdit.width() + 6);
@@ -99,7 +152,7 @@
connect(goToWeaponPage, SIGNAL(clicked()), this, SLOT(jumpToWeapons()));
bindEntries = new QCheckBox(SchemeWidget);
- bindEntries->setToolTip(tr("When this option is enabled selecting a game scheme will auto-select a weapon"));
+ bindEntries->setWhatsThis(tr("Game scheme will auto-select a weapon"));
bindEntries->setChecked(true);
bindEntries->setMaximumWidth(42);
bindEntries->setStyleSheet( "QCheckBox::indicator:checked { image: url(\":/res/lock.png\"); }"
@@ -118,6 +171,42 @@
connect(&DataManager::instance(), SIGNAL(updated()), this, SLOT(updateModelViews()));
}
+void GameCFGWidget::setTabbed(bool tabbed)
+{
+ if (tabbed && !this->tabbed)
+ { // Make tabbed
+ tabs->setCurrentIndex(0);
+ StackContainer->setVisible(false);
+ tabs->setVisible(true);
+ pMapContainer->setParent(mapContainerTabbed);
+ OptionsInnerContainer->setParent(optionsContainerTabbed);
+ pMapContainer->setVisible(true);
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ this->tabbed = true;
+ }
+ else if (!tabbed && this->tabbed)
+ { // Make stacked
+ pMapContainer->setParent(mapContainerFree);
+ OptionsInnerContainer->setParent(optionsContainerFree);
+ tabs->setVisible(false);
+ StackContainer->setVisible(true);
+ pMapContainer->setVisible(true);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ this->tabbed = false;
+ }
+
+ // Restore scrollbar palettes, since Qt seems to forget them easily when switching parents
+ QList allSBars = findChildren();
+ QPalette pal = palette();
+ pal.setColor(QPalette::WindowText, QColor(0xff, 0xcc, 0x00));
+ pal.setColor(QPalette::Button, QColor(0x00, 0x35, 0x1d));
+ pal.setColor(QPalette::Base, QColor(0x00, 0x35, 0x1d));
+ pal.setColor(QPalette::Window, QColor(0x00, 0x00, 0x00));
+
+ for (int i = 0; i < allSBars.size(); ++i)
+ allSBars.at(i)->setPalette(pal);
+}
+
void GameCFGWidget::jumpToSchemes()
{
emit goToSchemes(GameSchemes->currentIndex());
@@ -186,7 +275,7 @@
if (schemeData(24).toBool())
result |= 0x02000000; // tag team
if (schemeData(25).toBool())
- result |= 0x04000000; // bottom border
+ result |= 0x04000000; // bottom
return result;
}
@@ -235,6 +324,8 @@
bcfg << QString("e$template_filter %1").arg(pMapContainer->getTemplateFilter()).toUtf8();
bcfg << QString("e$mapgen %1").arg(mapgen).toUtf8();
+
+
switch (mapgen)
{
case MAPGEN_MAZE:
@@ -271,7 +362,7 @@
bool illegal = ammo.size() != cDefaultAmmoStore->size();
if (illegal)
{
- QMessageBox illegalMsg(this);
+ QMessageBox illegalMsg(parentWidget());
illegalMsg.setIcon(QMessageBox::Warning);
illegalMsg.setWindowTitle(QMessageBox::tr("Error"));
illegalMsg.setText(QMessageBox::tr("Cannot use the ammo '%1'!").arg(name));
@@ -325,10 +416,6 @@
if (param == "SEED")
{
pMapContainer->setSeed(value);
- if (!seedRegexp.exactMatch(value))
- {
- pMapContainer->seedEdit->setVisible(true);
- }
return;
}
if (param == "THEME")
@@ -377,8 +464,6 @@
if (param == "FULLMAPCONFIG")
{
QString seed = slValue[3];
- if (!seedRegexp.exactMatch(seed))
- pMapContainer->seedEdit->setVisible(true);
pMapContainer->setAllMapParameters(
slValue[0],
@@ -586,3 +671,19 @@
Scripts->setCurrentIndex(0);
}
}
+
+bool GameCFGWidget::isMaster()
+{
+ return m_master;
+}
+
+void GameCFGWidget::setMaster(bool master)
+{
+ if (master == m_master) return;
+ m_master = master;
+
+ pMapContainer->setMaster(master);
+
+ foreach (QWidget *widget, m_childWidgets)
+ widget->setEnabled(master);
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/gamecfgwidget.h
--- a/QTfrontend/ui/widget/gamecfgwidget.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/gamecfgwidget.h Fri Feb 22 05:05:32 2013 +0100
@@ -31,11 +31,14 @@
class QVBoxLayout;
class QLabel;
class QTableView;
+class QTabWidget;
class GameCFGWidget : public QGroupBox
{
Q_OBJECT
+ Q_PROPERTY(bool master READ isMaster WRITE setMaster)
+
public:
GameCFGWidget(QWidget* parent);
quint32 getGameFlags() const;
@@ -47,11 +50,14 @@
HWMapContainer* pMapContainer;
QTableView * tv;
QVariant schemeData(int column) const;
+ bool isMaster();
public slots:
void setParam(const QString & param, const QStringList & value);
void fullNetConfig();
void resendSchemeData();
+ void setMaster(bool master);
+ void setTabbed(bool tabbed);
signals:
void paramChanged(const QString & param, const QStringList & value);
@@ -75,12 +81,24 @@
void updateModelViews();
private:
- QGridLayout mainLayout;
+ QVBoxLayout mainLayout;
QCheckBox * bindEntries;
QString curNetAmmoName;
QString curNetAmmo;
QRegExp seedRegexp;
QString m_curScript;
+ bool m_master;
+ QList m_childWidgets;
+ QGridLayout * GBoxOptionsLayout;
+ QWidget * OptionsInnerContainer;
+ QWidget * StackContainer;
+
+ QWidget * mapContainerFree;
+ QWidget * mapContainerTabbed;
+ QWidget * optionsContainerFree;
+ QWidget * optionsContainerTabbed;
+ bool tabbed;
+ QTabWidget * tabs;
void setNetAmmo(const QString& name, const QString& ammo);
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/hatbutton.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/hatbutton.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,72 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include
+
+#include "hatprompt.h"
+#include "DataManager.h"
+#include "HatModel.h"
+#include "hatbutton.h"
+
+HatButton::HatButton(QWidget* parent) : QPushButton(parent)
+{
+ setIconSize(QSize(32, 37));
+ setFixedSize(44, 44);
+
+ m_hatModel = DataManager::instance().hatModel();
+ connect(this, SIGNAL(clicked()), this, SLOT(showPrompt()));
+
+ setCurrentIndex(0);
+}
+
+void HatButton::setCurrentIndex(int index)
+{
+ m_hat = m_hatModel->index(index, 0);
+ setWhatsThis(QString(tr("Change hat (%1)")).arg(m_hat.data(Qt::DisplayRole).toString()));
+ setToolTip(m_hat.data(Qt::DisplayRole).toString());
+ setIcon(m_hat.data(Qt::DecorationRole).value());
+}
+
+int HatButton::currentIndex()
+{
+ return m_hat.row();
+}
+
+void HatButton::setCurrentHat(const QString & name)
+{
+ QList hats = m_hatModel->findItems(name);
+
+ if (hats.count() > 0)
+ setCurrentIndex(hats[0]->row());
+}
+
+QString HatButton::currentHat() const
+{
+ return m_hat.data(Qt::DisplayRole).toString();
+}
+
+void HatButton::showPrompt()
+{
+ HatPrompt prompt(currentIndex(), this);
+ int hatID = prompt.exec() - 1; // Since 0 means canceled, so all indexes are +1'd
+ if (hatID < 0) return;
+
+ setCurrentIndex(hatID);
+ emit currentIndexChanged(hatID);
+ emit currentHatChanged(currentHat());
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/hatbutton.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/hatbutton.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,55 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef HATBUTTON_H
+#define HATBUTTON_H
+
+#include
+#include
+#include
+
+class HatModel;
+
+class HatButton : public QPushButton
+{
+ Q_OBJECT
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex)
+ Q_PROPERTY(QString currentHat READ currentHat WRITE setCurrentHat)
+
+ public:
+ HatButton(QWidget* parent);
+ int currentIndex();
+ QString currentHat() const;
+
+ private:
+ QModelIndex m_hat;
+ HatModel * m_hatModel;
+
+ signals:
+ void currentIndexChanged(int);
+ void currentHatChanged(const QString &);
+
+ public slots:
+ void setCurrentIndex(int index);
+ void setCurrentHat(const QString & name);
+
+ private slots:
+ void showPrompt();
+};
+
+#endif // HATBUTTON_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/hatprompt.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/hatprompt.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,165 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "DataManager.h"
+#include "lineeditcursor.h"
+#include "HatModel.h"
+#include "hatprompt.h"
+
+HatPrompt::HatPrompt(int currentIndex, QWidget* parent) : QDialog(parent)
+{
+ setModal(true);
+ setWindowFlags(Qt::Sheet);
+ setWindowModality(Qt::WindowModal);
+ setMinimumSize(550, 430);
+ resize(550, 430);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+ setStyleSheet("QPushButton { padding: 5px; margin-top: 10px; }");
+
+ // Hat model, and a model for setting a filter
+ HatModel * hatModel = DataManager::instance().hatModel();
+ filterModel = new QSortFilterProxyModel();
+ filterModel->setSourceModel(hatModel);
+ filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+
+ // Grid
+ QGridLayout * dialogLayout = new QGridLayout(this);
+ dialogLayout->setSpacing(0);
+ dialogLayout->setColumnStretch(1, 1);
+
+ QHBoxLayout * topLayout = new QHBoxLayout();
+
+ // Help/prompt message at top
+ QLabel * lblDesc = new QLabel(tr("Search for a hat:"));
+ lblDesc->setObjectName("lblDesc");
+ lblDesc->setStyleSheet("#lblDesc { color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; padding: 4px 10px;}");
+ lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ lblDesc->setFixedHeight(24);
+ lblDesc->setMinimumWidth(0);
+
+ // Filter text box
+ QWidget * filterContainer = new QWidget();
+ filterContainer->setFixedHeight(24);
+ filterContainer->setObjectName("filterContainer");
+ filterContainer->setStyleSheet("#filterContainer { background: #F6CB1C; border-top-right-radius: 10px; padding: 3px; }");
+ filterContainer->setFixedWidth(150);
+ txtFilter = new LineEditCursor(filterContainer);
+ txtFilter->setFixedWidth(150);
+ txtFilter->setFocus();
+ txtFilter->setFixedHeight(22);
+ txtFilter->setStyleSheet("LineEditCursor { border-width: 0px; border-radius: 6px; margin-top: 3px; margin-right: 3px; padding-left: 4px; padding-bottom: 2px; background-color: rgb(23, 11, 54); } LineEditCursor:hover, LineEditCursor:focus { background-color: rgb(13, 5, 68); }");
+ connect(txtFilter, SIGNAL(textChanged(const QString &)), this, SLOT(filterChanged(const QString &)));
+ connect(txtFilter, SIGNAL(moveUp()), this, SLOT(moveUp()));
+ connect(txtFilter, SIGNAL(moveDown()), this, SLOT(moveDown()));
+ connect(txtFilter, SIGNAL(moveLeft()), this, SLOT(moveLeft()));
+ connect(txtFilter, SIGNAL(moveRight()), this, SLOT(moveRight()));
+
+ // Corner widget
+ QLabel * corner = new QLabel();
+ corner->setPixmap(QPixmap(QString::fromUtf8(":/res/inverse-corner-bl.png")));
+ corner->setFixedSize(10, 10);
+
+ // Add widgets to top layout
+ topLayout->addWidget(lblDesc);
+ topLayout->addWidget(filterContainer);
+ topLayout->addWidget(corner, 0, Qt::AlignBottom);
+ topLayout->addStretch(1);
+
+ // Cancel button (closes dialog)
+ QPushButton * btnCancel = new QPushButton(tr("Cancel"));
+ connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+
+ // Select button
+ QPushButton * btnSelect = new QPushButton(tr("Use selected hat"));
+ btnSelect->setDefault(true);
+ connect(btnSelect, SIGNAL(clicked()), this, SLOT(onAccepted()));
+
+ // Add hats
+ list = new HatListView();
+ list->setModel(filterModel);
+ list->setViewMode(QListView::IconMode);
+ list->setResizeMode(QListView::Adjust);
+ list->setMovement(QListView::Static);
+ list->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ list->setSpacing(8);
+ list->setWordWrap(true);
+ list->setSelectionMode(QAbstractItemView::SingleSelection);
+ list->setObjectName("hatList");
+ list->setCurrentIndex(filterModel->index(currentIndex, 0));
+ connect(list, SIGNAL(activated(const QModelIndex &)), this, SLOT(hatChosen(const QModelIndex &)));
+ connect(list, SIGNAL(clicked(const QModelIndex &)), this, SLOT(hatChosen(const QModelIndex &)));
+
+ // Add elements to layouts
+ dialogLayout->addLayout(topLayout, 0, 0, 1, 3);
+ dialogLayout->addWidget(list, 1, 0, 1, 3);
+ dialogLayout->addWidget(btnCancel, 2, 0, 1, 1, Qt::AlignLeft);
+ dialogLayout->addWidget(btnSelect, 2, 2, 1, 1, Qt::AlignRight);
+}
+
+void HatPrompt::moveUp()
+{
+ list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier));
+}
+
+void HatPrompt::moveDown()
+{
+ list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier));
+}
+
+void HatPrompt::moveLeft()
+{
+ list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveLeft, Qt::NoModifier));
+}
+
+void HatPrompt::moveRight()
+{
+ list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveRight, Qt::NoModifier));
+}
+
+void HatPrompt::onAccepted()
+{
+ hatChosen(list->currentIndex());
+}
+
+// When a hat is selected
+void HatPrompt::hatChosen(const QModelIndex & index)
+{
+ done(filterModel->mapToSource(index).row() + 1); // Since returning 0 means canceled
+}
+
+// When the text in the filter text box is changed
+void HatPrompt::filterChanged(const QString & text)
+{
+ filterModel->setFilterFixedString(text);
+ list->setCurrentIndex(filterModel->index(0, 0));
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/hatprompt.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/hatprompt.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,61 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef HATPROMPT_H
+#define HATPROMPT_H
+
+#include
+#include
+#include
+
+class QLineEdit;
+class QModelIndex;
+class QSortFilterProxyModel;
+class LineEditCursor;
+
+class HatListView : public QListView
+{
+ friend class HatPrompt;
+
+ public:
+ HatListView(QWidget* parent = 0) : QListView(parent){}
+};
+
+class HatPrompt : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ HatPrompt(int currentIndex = 0, QWidget* parent = 0);
+
+ private:
+ LineEditCursor * txtFilter;
+ HatListView * list;
+ QSortFilterProxyModel * filterModel;
+
+ private slots:
+ void onAccepted();
+ void hatChosen(const QModelIndex & index);
+ void filterChanged(const QString & text);
+ void moveUp();
+ void moveDown();
+ void moveLeft();
+ void moveRight();
+};
+
+#endif // HATPROMPT_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/keybinder.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/keybinder.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,301 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "keybinder.h"
+#include "HWApplication.h"
+#include "DataManager.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+KeyBinder::KeyBinder(QWidget * parent, const QString & helpText, const QString & defaultText, const QString & resetButtonText) : QWidget(parent)
+{
+ this->defaultText = defaultText;
+ enableSignal = false;
+
+ // Two-column tab layout
+ QHBoxLayout * pageKeysLayout = new QHBoxLayout(this);
+ pageKeysLayout->setSpacing(0);
+ pageKeysLayout->setContentsMargins(0, 0, 0, 0);
+
+ // Table for category list
+ QVBoxLayout * catListContainer = new QVBoxLayout();
+ catListContainer->setContentsMargins(10, 10, 10, 10);
+ catList = new QListWidget();
+ catList->setFixedWidth(180);
+ catList->setStyleSheet("QListWidget::item { font-size: 14px; } QListWidget:hover { border-color: #F6CB1C; } QListWidget::item:selected { background: #150A61; color: yellow; }");
+ catList->setFocusPolicy(Qt::NoFocus);
+ connect(catList, SIGNAL(currentRowChanged(int)), this, SLOT(changeBindingsPage(int)));
+ catListContainer->addWidget(catList);
+ pageKeysLayout->addLayout(catListContainer);
+
+ // Reset all binds button
+ if (!resetButtonText.isEmpty())
+ {
+ QPushButton * btnResetAll = new QPushButton(resetButtonText);
+ catListContainer->addWidget(btnResetAll);
+ btnResetAll->setFixedHeight(40);
+ catListContainer->setStretch(1, 0);
+ catListContainer->setSpacing(10);
+ connect(btnResetAll, SIGNAL(clicked()), this, SIGNAL(resetAllBinds()));
+ }
+
+ // Container for pages of key bindings
+ QWidget * bindingsPagesContainer = new QWidget();
+ QVBoxLayout * rightLayout = new QVBoxLayout(bindingsPagesContainer);
+
+ // Scroll area for key bindings
+ QScrollArea * scrollArea = new QScrollArea();
+ scrollArea->setContentsMargins(0, 0, 0, 0);
+ scrollArea->setWidget(bindingsPagesContainer);
+ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ scrollArea->setWidgetResizable(true);
+ scrollArea->setFrameShape(QFrame::NoFrame);
+ scrollArea->setStyleSheet("background: #130F2A;");
+
+ // Add key binding pages to bindings tab
+ pageKeysLayout->addWidget(scrollArea);
+ pageKeysLayout->setStretch(1, 1);
+
+ // Custom help text
+ QLabel * helpLabel = new QLabel();
+ helpLabel->setText(helpText);
+ helpLabel->setStyleSheet("color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-radius: 10px; padding: auto 20px;");
+ helpLabel->setFixedHeight(24);
+ rightLayout->addWidget(helpLabel, 0, Qt::AlignCenter);
+
+ // Category list and bind table row heights
+ const int rowHeight = 20;
+ QSize catSize, headerSize;
+ catSize.setHeight(36);
+ headerSize.setHeight(24);
+
+ // Category list header
+ QListWidgetItem * catListHeader = new QListWidgetItem(tr("Category"));
+ catListHeader->setSizeHint(headerSize);
+ catListHeader->setFlags(Qt::NoItemFlags);
+ catListHeader->setForeground(QBrush(QColor("#130F2A")));
+ catListHeader->setBackground(QBrush(QColor("#F6CB1C")));
+ catListHeader->setTextAlignment(Qt::AlignCenter);
+ catList->addItem(catListHeader);
+
+ // Populate
+ bindingsPages = new QHBoxLayout();
+ bindingsPages->setContentsMargins(0, 0, 0, 0);
+ rightLayout->addLayout(bindingsPages);
+ QWidget * curPage = NULL;
+ QVBoxLayout * curLayout = NULL;
+ QTableWidget * curTable = NULL;
+ bool bFirstPage = true;
+ selectedBindTable = NULL;
+ bindComboBoxCellMappings = new QHash();
+ bindCellComboBoxMappings = new QHash();
+ for (int i = 0; i < BINDS_NUMBER; i++)
+ {
+ if (cbinds[i].category != NULL)
+ {
+ // Add stretch at end of previous layout
+ if (curLayout != NULL) curLayout->insertStretch(-1, 1);
+
+ // Category list item
+ QListWidgetItem * catItem = new QListWidgetItem(HWApplication::translate("binds (categories)", cbinds[i].category));
+ catItem->setSizeHint(catSize);
+ catList->addItem(catItem);
+
+ // Create new page
+ curPage = new QWidget();
+ curLayout = new QVBoxLayout(curPage);
+ curLayout->setSpacing(2);
+ bindingsPages->addWidget(curPage);
+ if (!bFirstPage) curPage->setVisible(false);
+ }
+
+ // Description
+ if (cbinds[i].description != NULL)
+ {
+ QLabel * desc = new QLabel(HWApplication::translate("binds (descriptions)", cbinds[i].description));
+ curLayout->addWidget(desc, 0);
+ QFrame * divider = new QFrame();
+ divider->setFrameShape(QFrame::HLine);
+ divider->setFrameShadow(QFrame::Plain);
+ curLayout->addWidget(divider, 0);
+ }
+
+ // New table
+ if (cbinds[i].category != NULL || cbinds[i].description != NULL)
+ {
+ curTable = new QTableWidget(0, 2);
+ curTable->verticalHeader()->setVisible(false);
+ curTable->horizontalHeader()->setVisible(false);
+ curTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
+ curTable->verticalHeader()->setDefaultSectionSize(rowHeight);
+ curTable->setShowGrid(false);
+ curTable->setStyleSheet("QTableWidget { border: none; } ");
+ curTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ curTable->setSelectionMode(QAbstractItemView::SingleSelection);
+ curTable->setFocusPolicy(Qt::NoFocus);
+ connect(curTable, SIGNAL(itemSelectionChanged()), this, SLOT(bindSelectionChanged()));
+ connect(curTable, SIGNAL(itemClicked(QTableWidgetItem *)), this, SLOT(bindCellClicked(QTableWidgetItem *)));
+ curLayout->addWidget(curTable, 0);
+ }
+
+ // Hidden combo box
+ QComboBox * comboBox = CBBind[i] = new QComboBox(curTable);
+ comboBox->setModel((QAbstractItemModel*)DataManager::instance().bindsModel());
+ comboBox->setVisible(false);
+ comboBox->setFixedWidth(200);
+
+ // Table row
+ int row = curTable->rowCount();
+ QTableWidgetItem * nameCell = new QTableWidgetItem(HWApplication::translate("binds", cbinds[i].name));
+ nameCell->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ curTable->insertRow(row);
+ curTable->setItem(row, 0, nameCell);
+ QTableWidgetItem * bindCell = new QTableWidgetItem(comboBox->currentText());
+ bindCell->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ curTable->setItem(row, 1, bindCell);
+ curTable->resizeColumnsToContents();
+ curTable->setFixedHeight(curTable->verticalHeader()->length() + 10);
+
+ // Updates the text in the table cell
+ connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(bindChanged(const QString &)));
+
+ // Map combo box and that row's cells to each other
+ bindComboBoxCellMappings->insert(comboBox, bindCell);
+ bindCellComboBoxMappings->insert(nameCell, comboBox);
+ bindCellComboBoxMappings->insert(bindCell, comboBox);
+ }
+
+ // Add stretch at end of last layout
+ if (curLayout != NULL) curLayout->insertStretch(-1, 1);
+
+ // Go to first page
+ catList->setCurrentItem(catList->item(1));
+
+ enableSignal = true;
+}
+
+KeyBinder::~KeyBinder()
+{
+ delete bindComboBoxCellMappings;
+ delete bindCellComboBoxMappings;
+}
+
+// Switches between different pages of key binds
+void KeyBinder::changeBindingsPage(int page)
+{
+ page--; // Disregard first item (the list header)
+ int pages = bindingsPages->count();
+ for (int i = 0; i < pages; i++)
+ bindingsPages->itemAt(i)->widget()->setVisible(false);
+ bindingsPages->itemAt(page)->widget()->setVisible(true);
+}
+
+// When a key bind combobox value is changed, updates the table cell text
+void KeyBinder::bindChanged(const QString & text)
+{
+ bindComboBoxCellMappings->value(sender())->setText(text);
+
+ if (enableSignal)
+ {
+ for (int i = 0; i < BINDS_NUMBER; i++)
+ {
+ if (CBBind[i] == sender())
+ {
+ emit bindUpdate(i);
+ break;
+ }
+ }
+ }
+}
+
+// When a row in a key bind table is clicked, this shows the popup
+void KeyBinder::bindCellClicked(QTableWidgetItem * item)
+{
+ QComboBox * box = bindCellComboBoxMappings->value(item);
+ QTableWidget * table = item->tableWidget();
+ QFrame * frame = box->findChild();
+
+ box->showPopup();
+ frame->move(
+ frame->x() + table->horizontalHeader()->sectionSize(0),
+ frame->y() + (table->verticalHeader()->defaultSectionSize() * item->row())
+ );
+}
+
+// When a new row in a bind table is *selected*, this clears selection in any other table
+void KeyBinder::bindSelectionChanged()
+{
+ QTableWidget * theSender = (QTableWidget*)sender();
+ if (theSender != selectedBindTable)
+ {
+ if (selectedBindTable != NULL)
+ selectedBindTable->clearSelection();
+ selectedBindTable = theSender;
+ }
+}
+
+// Set a combobox's index
+void KeyBinder::setBindIndex(int keyIndex, int bindIndex)
+{
+ enableSignal = false;
+ CBBind[keyIndex]->setCurrentIndex(bindIndex);
+ enableSignal = true;
+}
+
+// Return a combobox's selected index
+int KeyBinder::bindIndex(int keyIndex)
+{
+ return CBBind[keyIndex]->currentIndex();
+}
+
+// Clears selection and goes to first category
+void KeyBinder::resetInterface()
+{
+ enableSignal = false;
+
+ catList->setCurrentItem(catList->item(1));
+ changeBindingsPage(1);
+ if (selectedBindTable != NULL)
+ {
+ selectedBindTable->clearSelection();
+ selectedBindTable = NULL;
+ }
+
+ // Default bind text
+ DataManager::instance().bindsModel()->item(0)->setData(defaultText, Qt::DisplayRole);
+ for (int i = 0; i < BINDS_NUMBER; i++)
+ {
+ CBBind[i]->setModel(DataManager::instance().bindsModel());
+ CBBind[i]->setCurrentIndex(0);
+ bindComboBoxCellMappings->value(CBBind[i])->setText(defaultText);
+ }
+
+ enableSignal = true;
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/keybinder.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/keybinder.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,68 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef _KEY_BINDER_H
+#define _KEY_BINDER_H
+
+#include
+#include
+
+#include "binds.h"
+
+class QListWidget;
+class QTableWidgetItem;
+class QTableWidget;
+class QBoxLayout;
+class QComboBox;
+
+// USAGE NOTE: Every time the widget comes into view, you must call resetInterface()
+
+class KeyBinder : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ KeyBinder(QWidget * parent = NULL, const QString & helpText = QString(), const QString & defaultText = QString(), const QString & resetButtonText = QString());
+ ~KeyBinder();
+
+ void setBindIndex(int keyIndex, int bindIndex);
+ int bindIndex(int keyIndex);
+ void resetInterface();
+
+ private:
+ QHash * bindComboBoxCellMappings;
+ QHash * bindCellComboBoxMappings;
+ QTableWidget * selectedBindTable;
+ QListWidget * catList;
+ QBoxLayout *bindingsPages;
+ QComboBox * CBBind[BINDS_NUMBER];
+ QString defaultText;
+ bool enableSignal;
+
+ signals:
+ void bindUpdate(int bindID);
+ void resetAllBinds();
+
+ private slots:
+ void changeBindingsPage(int page);
+ void bindChanged(const QString &);
+ void bindCellClicked(QTableWidgetItem * item);
+ void bindSelectionChanged();
+};
+
+#endif // _KEY_BINDER_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/lineeditcursor.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/lineeditcursor.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include
+
+#include "lineeditcursor.h"
+
+void LineEditCursor::keyPressEvent(QKeyEvent * event)
+{
+ if (event->key() == Qt::Key_Up)
+ emit moveUp();
+ else if (event->key() == Qt::Key_Down)
+ emit moveDown();
+ else if (event->key() == Qt::Key_Left)
+ emit moveLeft();
+ else if (event->key() == Qt::Key_Right)
+ emit moveRight();
+ else
+ QLineEdit::keyPressEvent(event);
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/lineeditcursor.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/lineeditcursor.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,41 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef LINEEDITCURSOR_H
+#define LINEEDITCURSOR_H
+
+#include
+
+class LineEditCursor : public QLineEdit
+{
+ Q_OBJECT
+
+ public:
+ LineEditCursor(QWidget* parent = 0) : QLineEdit(parent) {}
+
+ signals:
+ void moveUp();
+ void moveDown();
+ void moveLeft();
+ void moveRight();
+
+ private:
+ void keyPressEvent(QKeyEvent * event);
+};
+
+#endif // LINEEDITCURSOR_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/mapContainer.cpp
--- a/QTfrontend/ui/widget/mapContainer.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/mapContainer.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -30,13 +30,24 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include "hwconsts.h"
#include "mapContainer.h"
+#include "themeprompt.h"
+#include "seedprompt.h"
#include "igbox.h"
#include "HWApplication.h"
#include "ThemeModel.h"
+
+
HWMapContainer::HWMapContainer(QWidget * parent) :
QWidget(parent),
mainLayout(this),
@@ -47,145 +58,205 @@
hhSmall.load(":/res/hh_small.png");
hhLimit = 18;
templateFilter = 0;
+ m_master = true;
linearGrad = QLinearGradient(QPoint(128, 0), QPoint(128, 128));
linearGrad.setColorAt(1, QColor(0, 0, 192));
linearGrad.setColorAt(0, QColor(66, 115, 225));
mainLayout.setContentsMargins(HWApplication::style()->pixelMetric(QStyle::PM_LayoutLeftMargin),
- 1,
+ 10,
HWApplication::style()->pixelMetric(QStyle::PM_LayoutRightMargin),
HWApplication::style()->pixelMetric(QStyle::PM_LayoutBottomMargin));
- QWidget* mapWidget = new QWidget(this);
- mainLayout.addWidget(mapWidget, 0, 0, Qt::AlignHCenter);
+ m_staticMapModel = DataManager::instance().staticMapModel();
+ m_missionMapModel = DataManager::instance().missionMapModel();
+ m_themeModel = DataManager::instance().themeModel();
- QGridLayout* mapLayout = new QGridLayout(mapWidget);
- mapLayout->setMargin(0);
+ /* Layouts */
- imageButt = new QPushButton(mapWidget);
- imageButt->setObjectName("imageButt");
- imageButt->setFixedSize(256 + 6, 128 + 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(setRandomMap()));
+ QHBoxLayout * typeLayout = new QHBoxLayout();
+ QHBoxLayout * seedLayout = new QHBoxLayout();
+ QHBoxLayout * twoColumnLayout = new QHBoxLayout();
+ QVBoxLayout * leftLayout = new QVBoxLayout();
+ QVBoxLayout * rightLayout = new QVBoxLayout();
+ twoColumnLayout->addLayout(leftLayout, 0);
+ twoColumnLayout->addStretch(1);
+ twoColumnLayout->addLayout(rightLayout, 0);
+ QVBoxLayout * drawnControls = new QVBoxLayout();
+ leftLayout->addLayout(typeLayout, 0);
+ rightLayout->addLayout(seedLayout, 0);
+
+ /* Map type combobox */
- chooseMap = new QComboBox(mapWidget);
- chooseMap->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
- m_mapModel = DataManager::instance().mapModel();
- chooseMap->setEditable(false);
- chooseMap->setModel(m_mapModel);
+ typeLayout->setSpacing(10);
+ typeLayout->addWidget(new QLabel(tr("Map type:")), 0);
+ cType = new QComboBox(this);
+ typeLayout->addWidget(cType, 1);
+ cType->insertItem(0, tr("Image map"), MapModel::StaticMap);
+ cType->insertItem(1, tr("Mission map"), MapModel::MissionMap);
+ cType->insertItem(2, tr("Hand-drawn"), MapModel::HandDrawnMap);
+ cType->insertItem(3, tr("Randomly generated"), MapModel::GeneratedMap);
+ cType->insertItem(4, tr("Random maze"), MapModel::GeneratedMaze);
+ connect(cType, SIGNAL(currentIndexChanged(int)), this, SLOT(mapTypeChanged(int)));
+ m_childWidgets << cType;
- mapLayout->addWidget(chooseMap, 1, 1);
-
- QLabel * lblMap = new QLabel(tr("Map"), mapWidget);
- mapLayout->addWidget(lblMap, 1, 0);
+ /* Randomize button */
- lblFilter = new QLabel(tr("Filter"), mapWidget);
- mapLayout->addWidget(lblFilter, 2, 0);
+ seedLayout->addStretch(1);
+ const QIcon& lp = QIcon(":/res/dice.png");
+ QSize sz = lp.actualSize(QSize(65535, 65535));
+ btnRandomize = new QPushButton();
+ btnRandomize->setText(tr("Random"));
+ btnRandomize->setIcon(lp);
+ btnRandomize->setFixedHeight(30);
+ btnRandomize->setIconSize(sz);
+ btnRandomize->setFlat(true);
+ btnRandomize->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ connect(btnRandomize, SIGNAL(clicked()), this, SLOT(setRandomMap()));
+ m_childWidgets << btnRandomize;
+ btnRandomize->setStyleSheet("padding: 5px;");
+ btnRandomize->setFixedHeight(cType->height());
+ seedLayout->addWidget(btnRandomize, 1);
- cbTemplateFilter = new QComboBox(mapWidget);
- cbTemplateFilter->addItem(tr("All"), 0);
- cbTemplateFilter->addItem(tr("Small"), 1);
- cbTemplateFilter->addItem(tr("Medium"), 2);
- cbTemplateFilter->addItem(tr("Large"), 3);
- cbTemplateFilter->addItem(tr("Cavern"), 4);
- cbTemplateFilter->addItem(tr("Wacky"), 5);
- mapLayout->addWidget(cbTemplateFilter, 2, 1);
-
- connect(cbTemplateFilter, SIGNAL(activated(int)), this, SLOT(setTemplateFilter(int)));
+ /* Seed button */
+ btnSeed = new QPushButton(parentWidget()->parentWidget());
+ btnSeed->setText(tr("Seed"));
+ btnSeed->setStyleSheet("padding: 5px;");
+ btnSeed->setFixedHeight(cType->height());
+ connect(btnSeed, SIGNAL(clicked()), this, SLOT(showSeedPrompt()));
+ seedLayout->addWidget(btnSeed, 0);
- maze_size_label = new QLabel(tr("Type"), mapWidget);
- mapLayout->addWidget(maze_size_label, 2, 0);
- maze_size_label->hide();
- cbMazeSize = new QComboBox(mapWidget);
- cbMazeSize->addItem(tr("Small tunnels"), 0);
- cbMazeSize->addItem(tr("Medium tunnels"), 1);
- cbMazeSize->addItem(tr("Large tunnels"), 2);
- cbMazeSize->addItem(tr("Small floating islands"), 3);
- cbMazeSize->addItem(tr("Medium floating islands"), 4);
- cbMazeSize->addItem(tr("Large floating islands"), 5);
- cbMazeSize->setCurrentIndex(1);
+ /* Map preview label */
+
+ QLabel * lblMapPreviewText = new QLabel(this);
+ lblMapPreviewText->setText(tr("Map preview:"));
+ leftLayout->addWidget(lblMapPreviewText, 0);
+
+ /* Map Preview */
- mapLayout->addWidget(cbMazeSize, 2, 1);
- cbMazeSize->hide();
- connect(cbMazeSize, SIGNAL(activated(int)), this, SLOT(setMazeSize(int)));
+ mapPreview = new QPushButton(this);
+ mapPreview->setObjectName("mapPreview");
+ mapPreview->setFixedSize(256, 128);
+ mapPreview->setContentsMargins(0, 0, 0, 0);
+ leftLayout->addWidget(mapPreview, 0);
+ connect(mapPreview, SIGNAL(clicked()), this, SLOT(previewClicked()));
+
+ /* Bottom-Left layout */
+
+ QVBoxLayout * bottomLeftLayout = new QVBoxLayout();
+ leftLayout->addLayout(bottomLeftLayout, 1);
+
+ /* Map list label */
+
+ lblMapList = new QLabel();
+ rightLayout->addWidget(lblMapList, 0);
+
+ /* Static maps list */
- gbThemes = new IconedGroupBox(mapWidget);
- gbThemes->setTitleTextPadding(80);
- gbThemes->setContentTopPadding(15);
- gbThemes->setTitle(tr("Themes"));
+ staticMapList = new QListView;
+ staticMapList->setModel(m_staticMapModel);
+ rightLayout->addWidget(staticMapList, 1);
+ staticMapList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ m_childWidgets << staticMapList;
+ QItemSelectionModel * staticSelectionModel = staticMapList->selectionModel();
+ connect(staticSelectionModel,
+ SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)),
+ this,
+ SLOT(staticMapChanged(const QModelIndex &, const QModelIndex &)));
+
+ /* Mission maps list */
- //gbThemes->setStyleSheet("padding: 0px"); // doesn't work - stylesheet is set with icon
- mapLayout->addWidget(gbThemes, 0, 2, 3, 1);
- // disallow row to be collapsed (so it can't get ignored when Qt applies rowSpan of gbThemes)
- mapLayout->setRowMinimumHeight(2, 13);
- QVBoxLayout * gbTLayout = new QVBoxLayout(gbThemes);
- gbTLayout->setContentsMargins(0, 0, 0 ,0);
- gbTLayout->setSpacing(0);
- lvThemes = new QListView(mapWidget);
- lvThemes->setMinimumHeight(30);
- lvThemes->setFixedWidth(140);
- m_themeModel = DataManager::instance().themeModel();
- lvThemes->setModel(m_themeModel);
- lvThemes->setIconSize(QSize(16, 16));
- lvThemes->setEditTriggers(QListView::NoEditTriggers);
+ missionMapList = new QListView;
+ missionMapList->setModel(m_missionMapModel);
+ missionMapList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ rightLayout->addWidget(missionMapList, 1);
+ m_childWidgets << missionMapList;
+ QItemSelectionModel * missionSelectionModel = missionMapList->selectionModel();
+ connect(missionSelectionModel,
+ SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)),
+ this,
+ SLOT(missionMapChanged(const QModelIndex &, const QModelIndex &)));
+
+ /* Map load and edit buttons */
+
+ drawnControls->addStretch(1);
- connect(lvThemes->selectionModel(), SIGNAL(currentRowChanged( const QModelIndex &, const QModelIndex &)), this, SLOT(themeSelected( const QModelIndex &, const QModelIndex &)));
+ btnLoadMap = new QPushButton(tr("Load map drawing"));
+ btnLoadMap->setStyleSheet("padding: 20px;");
+ drawnControls->addWidget(btnLoadMap, 0);
+ m_childWidgets << btnLoadMap;
+ connect(btnLoadMap, SIGNAL(clicked()), this, SLOT(loadDrawing()));
+
+ btnEditMap = new QPushButton(tr("Edit map drawing"));
+ btnEditMap->setStyleSheet("padding: 20px;");
+ drawnControls->addWidget(btnEditMap, 0);
+ m_childWidgets << btnEditMap;
+ connect(btnEditMap, SIGNAL(clicked()), this, SIGNAL(drawMapRequested()));
+
+ drawnControls->addStretch(1);
+
+ rightLayout->addLayout(drawnControls);
+
+ /* Generator style list */
- // override default style to tighten up theme scroller
- lvThemes->setStyleSheet(QString(
- "QListView{"
- "border: solid;"
- "border-width: 0px;"
- "border-radius: 0px;"
- "border-color: transparent;"
- "background-color: #0d0544;"
- "color: #ffcc00;"
- "font: bold 13px;"
- "}"
- )
- );
+ generationStyles = new QListWidget();
+ new QListWidgetItem(tr("All"), generationStyles);
+ new QListWidgetItem(tr("Small"), generationStyles);
+ new QListWidgetItem(tr("Medium"), generationStyles);
+ new QListWidgetItem(tr("Large"), generationStyles);
+ new QListWidgetItem(tr("Cavern"), generationStyles);
+ new QListWidgetItem(tr("Wacky"), generationStyles);
+ connect(generationStyles, SIGNAL(currentRowChanged(int)), this, SLOT(setTemplateFilter(int)));
+ m_childWidgets << generationStyles;
+ rightLayout->addWidget(generationStyles, 1);
- gbTLayout->addWidget(lvThemes);
- lvThemes->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
+ /* Maze style list */
- mapLayout->setSizeConstraint(QLayout::SetFixedSize);
+ mazeStyles = new QListWidget();
+ new QListWidgetItem(tr("Small tunnels"), mazeStyles);
+ new QListWidgetItem(tr("Medium tunnels"), mazeStyles);
+ new QListWidgetItem(tr("Largetunnels"), mazeStyles);
+ new QListWidgetItem(tr("Small islands"), mazeStyles);
+ new QListWidgetItem(tr("Medium islands"), mazeStyles);
+ new QListWidgetItem(tr("Large islands"), mazeStyles);
+ connect(mazeStyles, SIGNAL(currentRowChanged(int)), this, SLOT(setMazeSize(int)));
+ m_childWidgets << mazeStyles;
+ rightLayout->addWidget(mazeStyles, 1);
- QWidget* seedWidget = new QWidget(this);
- mainLayout.addWidget(seedWidget, 1, 0);
+ /* Mission description */
- QGridLayout* seedLayout = new QGridLayout(seedWidget);
- seedLayout->setMargin(0);
+ lblDesc = new QLabel();
+ lblDesc->setWordWrap(true);
+ lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ lblDesc->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ lblDesc->setStyleSheet("font: 10px;");
+ bottomLeftLayout->addWidget(lblDesc, 100);
+
+ /* Add stretch above theme button */
+
+ bottomLeftLayout->addStretch(1);
- seedLabel = new QLabel(tr("Seed"), seedWidget);
- seedLayout->addWidget(seedLabel, 3, 0);
- seedEdit = new QLineEdit(seedWidget);
- seedEdit->setMaxLength(54);
- connect(seedEdit, SIGNAL(returnPressed()), this, SLOT(seedEdited()));
- seedLayout->addWidget(seedEdit, 3, 1);
- seedLayout->setColumnStretch(1, 5);
- seedSet = new QPushButton(seedWidget);
- seedSet->setText(QPushButton::tr("more"));
- connect(seedSet, SIGNAL(clicked()), this, SLOT(seedEdited()));
- seedLayout->setColumnStretch(2, 1);
- seedLayout->addWidget(seedSet, 3, 2);
+ /* Theme chooser */
- seedLabel->setVisible(false);
- seedEdit->setVisible(false);
+ btnTheme = new QPushButton();
+ connect(btnTheme, SIGNAL(clicked()), this, SLOT(showThemePrompt()));
+ m_childWidgets << btnTheme;
+ bottomLeftLayout->addWidget(btnTheme, 0);
+
+ /* Add everything to main layout */
+
+ mainLayout.addLayout(twoColumnLayout, 0);
+
+ /* Set defaults */
setRandomSeed();
+ setMazeSize(0);
+ setTemplateFilter(0);
+ staticMapChanged(m_staticMapModel->index(0, 0));
+ missionMapChanged(m_missionMapModel->index(0, 0));
+ changeMapType(MapModel::GeneratedMap);
setRandomTheme();
-
- chooseMap->setCurrentIndex(0);
- mapChanged(0);
- // use signal "activated" rather than currentIndexChanged
- // because index is somtimes changed a few times in a row programmatically
- connect(chooseMap, SIGNAL(activated(int)), this, SLOT(mapChanged(int)));
-
- // update model views after model changes (to e.g. re-adjust separators)
- connect(&DataManager::instance(), SIGNAL(updated()), this, SLOT(updateModelViews()));
}
void HWMapContainer::setImage(const QImage newImage)
@@ -199,11 +270,12 @@
px.setMask(bm);
p.fillRect(pxres.rect(), linearGrad);
- p.drawPixmap(QPoint(0, 0), px);
+ p.drawPixmap(0, 0, px);
addInfoToPreview(pxres);
- //chooseMap->setCurrentIndex(mapgen);
pMap = 0;
+
+ cType->setEnabled(isMaster());
}
void HWMapContainer::setHHLimit(int newHHLimit)
@@ -211,70 +283,6 @@
hhLimit = newHHLimit;
}
-void HWMapContainer::mapChanged(int index)
-{
- if (chooseMap->currentIndex() != index)
- chooseMap->setCurrentIndex(index);
-
- if (index < 0)
- {
- m_mapInfo.type = MapModel::Invalid;
- updatePreview();
- return;
- }
-
- Q_ASSERT(chooseMap->itemData(index, Qt::UserRole + 1).canConvert());
- m_mapInfo = chooseMap->itemData(index, Qt::UserRole + 1).value();
- m_curMap = m_mapInfo.name;
-
- switch(m_mapInfo.type)
- {
- case MapModel::GeneratedMap:
- mapgen = MAPGEN_REGULAR;
- gbThemes->show();
- lblFilter->show();
- cbTemplateFilter->show();
- maze_size_label->hide();
- cbMazeSize->hide();
- break;
- case MapModel::GeneratedMaze:
- mapgen = MAPGEN_MAZE;
- gbThemes->show();
- lblFilter->hide();
- cbTemplateFilter->hide();
- maze_size_label->show();
- cbMazeSize->show();
- break;
- case MapModel::HandDrawnMap:
- mapgen = MAPGEN_DRAWN;
- gbThemes->show();
- lblFilter->hide();
- cbTemplateFilter->hide();
- maze_size_label->hide();
- cbMazeSize->hide();
- break;
- default:
- mapgen = MAPGEN_MAP;
- gbThemes->hide();
- lblFilter->hide();
- cbTemplateFilter->hide();
- maze_size_label->hide();
- cbMazeSize->hide();
- m_theme = m_mapInfo.theme;
- }
-
- // the map has no pre-defined theme, so let's use the selected one
- if (m_mapInfo.theme.isEmpty())
- {
- m_theme = lvThemes->currentIndex().data().toString();
- emit themeChanged(m_theme);
- }
-
- updatePreview();
- emit mapChanged(m_curMap);
- emit mapgenChanged(mapgen);
-}
-
// Should this add text to identify map size?
void HWMapContainer::addInfoToPreview(QPixmap image)
{
@@ -292,13 +300,19 @@
p.drawText(image.rect().width() - hhSmall.rect().width() - 14 - (hhLimit > 9 ? 10 : 0), 18, text);
p.drawPixmap(image.rect().width() - hhSmall.rect().width() - 5, 5, hhSmall.rect().width(), hhSmall.rect().height(), hhSmall);
- imageButt->setIcon(finalImage);
- imageButt->setIconSize(image.size());
+ // Shrink, crop, and center preview image
+ QPixmap centered(QSize(m_previewSize.width() - 6, m_previewSize.height() - 6));
+ QPainter pc(¢ered);
+ pc.fillRect(centered.rect(), linearGrad);
+ pc.drawPixmap(-3, -3, finalImage);
+
+ mapPreview->setIcon(QIcon(centered));
+ mapPreview->setIconSize(centered.size());
}
void HWMapContainer::askForGeneratedPreview()
{
- pMap = new HWMap();
+ pMap = new HWMap(this);
connect(pMap, SIGNAL(ImageReceived(const QImage)), this, SLOT(setImage(const QImage)));
connect(pMap, SIGNAL(HHLimitReceived(int)), this, SLOT(setHHLimit(int)));
connect(pMap, SIGNAL(destroyed(QObject *)), this, SLOT(onPreviewMapDestroyed(QObject *)));
@@ -322,14 +336,21 @@
p.drawPixmap(QPoint(x, y), waitIcon);
addInfoToPreview(waitImage);
+
+ cType->setEnabled(false);
}
-void HWMapContainer::themeSelected(const QModelIndex & current, const QModelIndex &)
+void HWMapContainer::previewClicked()
{
- m_theme = current.data().toString();
-
- gbThemes->setIcon(qVariantValue(current.data(Qt::UserRole)));
- emit themeChanged(m_theme);
+ switch (m_mapInfo.type)
+ {
+ case MapModel::HandDrawnMap:
+ emit drawMapRequested();
+ break;
+ default:
+ setRandomMap();
+ break;
+ }
}
QString HWMapContainer::getCurrentSeed() const
@@ -339,8 +360,14 @@
QString HWMapContainer::getCurrentMap() const
{
- if(chooseMap->currentIndex() < MAPGEN_MAP) return QString();
- return(m_curMap);
+ switch (m_mapInfo.type)
+ {
+ case MapModel::StaticMap:
+ case MapModel::MissionMap:
+ return m_curMap;
+ default:
+ return QString();
+ }
}
QString HWMapContainer::getCurrentTheme() const
@@ -370,20 +397,17 @@
quint32 HWMapContainer::getTemplateFilter() const
{
- return cbTemplateFilter->itemData(cbTemplateFilter->currentIndex()).toInt();
+ return generationStyles->currentRow();
}
void HWMapContainer::resizeEvent ( QResizeEvent * event )
{
Q_UNUSED(event);
- //imageButt->setIconSize(imageButt->size());
}
void HWMapContainer::intSetSeed(const QString & seed)
{
m_seed = seed;
- if (seed != seedEdit->text())
- seedEdit->setText(seed);
}
void HWMapContainer::setSeed(const QString & seed)
@@ -395,11 +419,29 @@
void HWMapContainer::intSetMap(const QString & map)
{
- m_curMap = map;
-
- int id = m_mapModel->indexOf(map);
-
- mapChanged(id);
+ if (map == "+rnd+")
+ {
+ changeMapType(MapModel::GeneratedMap);
+ }
+ else if (map == "+maze+")
+ {
+ changeMapType(MapModel::GeneratedMaze);
+ }
+ else if (map == "+drawn+")
+ {
+ changeMapType(MapModel::HandDrawnMap);
+ }
+ else if (m_staticMapModel->mapExists(map))
+ {
+ changeMapType(MapModel::StaticMap, m_staticMapModel->index(m_staticMapModel->findMap(map), 0));
+ }
+ else if (m_missionMapModel->mapExists(map))
+ {
+ changeMapType(MapModel::MissionMap, m_missionMapModel->index(m_missionMapModel->findMap(map), 0));
+ } else
+ {
+ qDebug() << "HWMapContainer::intSetMap: Map doesn't exist: " << map;
+ }
}
void HWMapContainer::setMap(const QString & map)
@@ -410,16 +452,16 @@
void HWMapContainer::setTheme(const QString & theme)
{
- QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), Qt::DisplayRole, theme);
+ QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), ThemeModel::ActualNameRole, theme);
if(mdl.size())
- lvThemes->setCurrentIndex(mdl.at(0));
+ updateTheme(mdl.at(0));
+ else
+ intSetIconlessTheme(theme);
}
void HWMapContainer::setRandomMap()
{
- int idx;
-
setRandomSeed();
switch(m_mapInfo.type)
{
@@ -427,21 +469,17 @@
case MapModel::GeneratedMaze:
setRandomTheme();
break;
- case MapModel::HandDrawnMap:
- emit drawMapRequested();
+ case MapModel::MissionMap:
+ missionMapChanged(m_missionMapModel->index(rand() % m_missionMapModel->rowCount(), 0));
break;
- case MapModel::MissionMap:
case MapModel::StaticMap:
- // get random map of same type
- idx = m_mapModel->randomMap(m_mapInfo.type);
- mapChanged(idx);
+ staticMapChanged(m_staticMapModel->index(rand() % m_staticMapModel->rowCount(), 0));
break;
- case MapModel::Invalid:
- mapChanged(0);
+ default:
+ break;
}
}
-
void HWMapContainer::setRandomSeed()
{
setSeed(QUuid::createUuid().toString());
@@ -452,12 +490,13 @@
{
if(!m_themeModel->rowCount()) return;
quint32 themeNum = rand() % m_themeModel->rowCount();
- lvThemes->setCurrentIndex(m_themeModel->index(themeNum));
+ updateTheme(m_themeModel->index(themeNum));
+ qDebug() << "RANDOM THEME:" << themeNum;
}
void HWMapContainer::intSetTemplateFilter(int filter)
{
- cbTemplateFilter->setCurrentIndex(filter);
+ generationStyles->setCurrentRow(filter);
emit newTemplateFilter(filter);
}
@@ -475,12 +514,12 @@
int HWMapContainer::getMazeSize(void) const
{
- return cbMazeSize->currentIndex();
+ return mazeStyles->currentRow();
}
void HWMapContainer::intSetMazeSize(int size)
{
- cbMazeSize->setCurrentIndex(size);
+ mazeStyles->setCurrentRow(size);
emit mazeSizeChanged(size);
}
@@ -521,9 +560,6 @@
break;
}
- if(m != MAPGEN_MAP)
- chooseMap->setCurrentIndex(m);
-
emit mapgenChanged(m);
}
}
@@ -546,23 +582,10 @@
return drawMapScene.encode();
}
-void HWMapContainer::seedEdited()
+void HWMapContainer::setNewSeed(const QString & newSeed)
{
- if (seedLabel->isVisible() == false )
- {
- seedLabel->setVisible(true);
- seedEdit->setVisible(true);
- seedSet->setText(tr("Set"));
- return;
- }
-
- if (seedEdit->text().isEmpty())
- seedEdit->setText(m_seed);
- else
- {
- setSeed(seedEdit->text());
- emit seedChanged(seedEdit->text());
- }
+ setSeed(newSeed);
+ emit seedChanged(newSeed);
}
DrawMapScene * HWMapContainer::getDrawMapScene()
@@ -592,8 +615,8 @@
{
case MapModel::Invalid:
failIcon = QPixmap(":/res/btnDisabled.png");
- imageButt->setIcon(failIcon);
- imageButt->setIconSize(failIcon.size());
+ mapPreview->setIcon(QIcon(failIcon));
+ mapPreview->setIconSize(failIcon.size());
break;
case MapModel::GeneratedMap:
askForGeneratedPreview();
@@ -610,7 +633,7 @@
if(!success)
{
- imageButt->setIcon(QIcon());
+ mapPreview->setIcon(QIcon());
return;
}
@@ -629,7 +652,6 @@
intSetMap(map);
}
-
void HWMapContainer::updateModelViews()
{
// restore theme selection
@@ -638,13 +660,13 @@
{
QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), Qt::DisplayRole, m_theme);
if (mdl.size() > 0)
- lvThemes->setCurrentIndex(mdl.at(0));
+ updateTheme(mdl.at(0));
else
setRandomTheme();
}
// restore map selection
- if ((!m_curMap.isEmpty()) && (chooseMap->currentIndex() < 0))
+ if (!m_curMap.isEmpty())
intSetMap(m_curMap);
else
updatePreview();
@@ -656,3 +678,252 @@
if (map == pMap)
pMap = 0;
}
+
+void HWMapContainer::mapTypeChanged(int index)
+{
+ changeMapType((MapModel::MapType)cType->itemData(index).toInt());
+}
+
+void HWMapContainer::changeMapType(MapModel::MapType type, const QModelIndex & newMap)
+{
+ staticMapList->hide();
+ missionMapList->hide();
+ lblMapList->hide();
+ generationStyles->hide();
+ mazeStyles->hide();
+ lblDesc->hide();
+ btnLoadMap->hide();
+ btnEditMap->hide();
+
+ switch (type)
+ {
+ case MapModel::GeneratedMap:
+ mapgen = MAPGEN_REGULAR;
+ setMapInfo(MapModel::MapInfoRandom);
+ lblMapList->setText(tr("Map size:"));
+ lblMapList->show();
+ generationStyles->show();
+ break;
+ case MapModel::GeneratedMaze:
+ mapgen = MAPGEN_MAZE;
+ setMapInfo(MapModel::MapInfoMaze);
+ lblMapList->setText(tr("Maze style:"));
+ lblMapList->show();
+ mazeStyles->show();
+ break;
+ case MapModel::HandDrawnMap:
+ mapgen = MAPGEN_DRAWN;
+ setMapInfo(MapModel::MapInfoDrawn);
+ btnLoadMap->show();
+ btnEditMap->show();
+ break;
+ case MapModel::MissionMap:
+ mapgen = MAPGEN_MAP;
+ missionMapChanged(newMap.isValid() ? newMap : missionMapList->currentIndex());
+ lblMapList->setText(tr("Mission:"));
+ lblMapList->show();
+ missionMapList->show();
+ lblDesc->setText(m_mapInfo.desc);
+ lblDesc->show();
+ emit mapChanged(m_curMap);
+ break;
+ case MapModel::StaticMap:
+ mapgen = MAPGEN_MAP;
+ staticMapChanged(newMap.isValid() ? newMap : staticMapList->currentIndex());
+ lblMapList->setText(tr("Map:"));
+ lblMapList->show();
+ staticMapList->show();
+ emit mapChanged(m_curMap);
+ break;
+ default:
+ break;
+ }
+
+ // Update theme button size
+ updateThemeButtonSize();
+
+ // Update cType combobox
+ for (int i = 0; i < cType->count(); i++)
+ {
+ if ((MapModel::MapType)cType->itemData(i).toInt() == type)
+ {
+ cType->setCurrentIndex(i);
+ break;
+ }
+ }
+
+ repaint();
+
+ emit mapgenChanged(mapgen);
+}
+
+void HWMapContainer::updateThemeButtonSize()
+{
+ if (m_mapInfo.type == MapModel::MissionMap)
+ {
+ btnTheme->setIconSize(QSize(30, 30));
+ btnTheme->setFixedHeight(30);
+ }
+ else
+ {
+ QSize iconSize = btnTheme->icon().actualSize(QSize(65535, 65535));
+ btnTheme->setFixedHeight(64);
+ btnTheme->setIconSize(iconSize);
+ }
+
+ repaint();
+}
+
+void HWMapContainer::showThemePrompt()
+{
+ ThemePrompt prompt(m_themeID, this);
+ int theme = prompt.exec() - 1; // Since 0 means canceled, so all indexes are +1'd
+ if (theme < 0) return;
+
+ QModelIndex current = m_themeModel->index(theme, 0);
+ updateTheme(current);
+ emit themeChanged(m_theme);
+}
+
+void HWMapContainer::updateTheme(const QModelIndex & current)
+{
+ m_theme = selectedTheme = current.data(ThemeModel::ActualNameRole).toString();
+ m_themeID = current.row();
+ QIcon icon = qVariantValue(current.data(Qt::DecorationRole));
+ QSize iconSize = icon.actualSize(QSize(65535, 65535));
+ btnTheme->setFixedHeight(64);
+ btnTheme->setIconSize(iconSize);
+ btnTheme->setIcon(icon);
+ btnTheme->setText(tr("Theme: ") + current.data(Qt::DisplayRole).toString());
+ updateThemeButtonSize();
+}
+
+void HWMapContainer::staticMapChanged(const QModelIndex & map, const QModelIndex & old)
+{
+ mapChanged(map, 0, old);
+}
+
+void HWMapContainer::missionMapChanged(const QModelIndex & map, const QModelIndex & old)
+{
+ mapChanged(map, 1, old);
+}
+
+// Type: 0 = static, 1 = mission
+void HWMapContainer::mapChanged(const QModelIndex & map, int type, const QModelIndex & old)
+{
+ QListView * mapList;
+
+ if (type == 0) mapList = staticMapList;
+ else if (type == 1) mapList = missionMapList;
+ else return;
+
+ // Make sure it is a valid index
+ if (!map.isValid())
+ {
+ if (old.isValid())
+ {
+ mapList->setCurrentIndex(old);
+ mapList->scrollTo(old);
+ }
+ else
+ {
+ m_mapInfo.type = MapModel::Invalid;
+ updatePreview();
+ }
+
+ return;
+ }
+
+ // If map changed, update list selection
+ if (mapList->currentIndex() != map)
+ {
+ mapList->setCurrentIndex(map);
+ mapList->scrollTo(map);
+ }
+
+ if (map.data(Qt::UserRole + 1).canConvert())
+ setMapInfo(map.data(Qt::UserRole + 1).value());
+ else
+ Q_ASSERT(false); // Houston, we have a problem.
+
+}
+
+void HWMapContainer::setMapInfo(MapModel::MapInfo mapInfo)
+{
+ m_mapInfo = mapInfo;
+ m_curMap = m_mapInfo.name;
+
+ // the map has no pre-defined theme, so let's use the selected one
+ if (m_mapInfo.theme.isEmpty())
+ {
+ if (!selectedTheme.isEmpty())
+ {
+ setTheme(selectedTheme);
+ emit themeChanged(selectedTheme);
+ }
+ }
+ else
+ {
+ setTheme(m_mapInfo.theme);
+ emit themeChanged(m_mapInfo.theme);
+ }
+
+ lblDesc->setText(mapInfo.desc);
+
+ updatePreview();
+ emit mapChanged(m_curMap);
+}
+
+void HWMapContainer::loadDrawing()
+{
+ QString fileName = QFileDialog::getOpenFileName(NULL, tr("Load drawn map"), ".", tr("Drawn Maps") + " (*.hwmap);;" + tr("All files") + " (*)");
+
+ if(fileName.isEmpty()) return;
+
+ QFile f(fileName);
+
+ if(!f.open(QIODevice::ReadOnly))
+ {
+ QMessageBox errorMsg(parentWidget());
+ errorMsg.setIcon(QMessageBox::Warning);
+ errorMsg.setWindowTitle(QMessageBox::tr("File error"));
+ errorMsg.setText(QMessageBox::tr("Cannot open '%1' for reading").arg(fileName));
+ errorMsg.setWindowModality(Qt::WindowModal);
+ errorMsg.exec();
+ }
+ else
+ {
+ drawMapScene.decode(qUncompress(QByteArray::fromBase64(f.readAll())));
+ mapDrawingFinished();
+ }
+}
+
+void HWMapContainer::showSeedPrompt()
+{
+ SeedPrompt prompt(parentWidget()->parentWidget(), getCurrentSeed(), isMaster());
+ connect(&prompt, SIGNAL(seedSelected(const QString &)), this, SLOT(setNewSeed(const QString &)));
+ prompt.exec();
+}
+
+bool HWMapContainer::isMaster()
+{
+ return m_master;
+}
+
+void HWMapContainer::setMaster(bool master)
+{
+ if (master == m_master) return;
+ m_master = master;
+
+ foreach (QWidget *widget, m_childWidgets)
+ widget->setEnabled(master);
+}
+
+void HWMapContainer::intSetIconlessTheme(const QString & name)
+{
+ if (name.isEmpty()) return;
+
+ m_theme = name;
+ btnTheme->setIcon(QIcon());
+ btnTheme->setText(tr("Theme: ") + name);
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/mapContainer.h
--- a/QTfrontend/ui/widget/mapContainer.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/mapContainer.h Fri Feb 22 05:05:32 2013 +0100
@@ -22,6 +22,7 @@
#include
#include
+#include
#include
#include
#include
@@ -37,6 +38,7 @@
class IconedGroupBox;
class QListView;
class SeparatorPainter;
+class QListWidget;
class MapFileErrorException
{
@@ -46,6 +48,8 @@
{
Q_OBJECT
+ Q_PROPERTY(bool master READ isMaster WRITE setMaster)
+
public:
HWMapContainer(QWidget * parent=0);
QString getCurrentSeed() const;
@@ -62,6 +66,7 @@
DrawMapScene * getDrawMapScene();
void mapDrawingFinished();
QLineEdit* seedEdit;
+ bool isMaster();
public slots:
void askForGeneratedPreview();
@@ -75,6 +80,7 @@
void setAllMapParameters(const QString & map, MapGenerator m, int mazesize, const QString & seed, int tmpl);
void updateModelViews();
void onPreviewMapDestroyed(QObject * map);
+ void setMaster(bool master);
signals:
void seedChanged(const QString & seed);
@@ -89,22 +95,29 @@
private slots:
void setImage(const QImage newImage);
void setHHLimit(int hhLimit);
- void mapChanged(int index);
void setRandomSeed();
void setRandomTheme();
void setRandomMap();
- void themeSelected(const QModelIndex & current, const QModelIndex &);
void addInfoToPreview(QPixmap image);
- void seedEdited();
+ void setNewSeed(const QString & newSeed);
+ void mapTypeChanged(int);
+ void showThemePrompt();
+ void updateTheme(const QModelIndex & current);
+ void staticMapChanged(const QModelIndex & map, const QModelIndex & old = QModelIndex());
+ void missionMapChanged(const QModelIndex & map, const QModelIndex & old = QModelIndex());
+ void loadDrawing();
+ void showSeedPrompt();
+ void previewClicked();
protected:
virtual void resizeEvent ( QResizeEvent * event );
private:
- QGridLayout mainLayout;
- QPushButton* imageButt;
+ QVBoxLayout mainLayout;
+ QPushButton* mapPreview;
QComboBox* chooseMap;
- MapModel * m_mapModel;
+ MapModel * m_staticMapModel;
+ MapModel * m_missionMapModel;
IconedGroupBox* gbThemes;
QListView* lvThemes;
ThemeModel * m_themeModel;
@@ -121,15 +134,36 @@
QComboBox *cbMazeSize;
MapGenerator mapgen;
DrawMapScene drawMapScene;
+ QComboBox * cType;
+ QListView * staticMapList;
+ QListView * missionMapList;
+ QListWidget * generationStyles;
+ QListWidget * mazeStyles;
+ QLabel * lblMapList;
+ QLabel * lblDesc;
+ QPushButton * btnTheme;
+ QPushButton * btnLoadMap;
+ QPushButton * btnEditMap;
+ QPushButton * btnRandomize;
+ QString selectedTheme;
+ QPushButton * btnSeed;
+ bool m_master;
+ QList m_childWidgets;
void intSetSeed(const QString & seed);
void intSetMap(const QString & map);
void intSetMapgen(MapGenerator m);
void intSetTemplateFilter(int);
void intSetMazeSize(int size);
+ void intSetIconlessTheme(const QString & name);
+ void mapChanged(const QModelIndex & map, int type, const QModelIndex & old = QModelIndex());
+ void setMapInfo(MapModel::MapInfo mapInfo);
+ void changeMapType(MapModel::MapType type, const QModelIndex & newMap = QModelIndex());
void updatePreview();
+ void updateThemeButtonSize();
MapModel::MapInfo m_mapInfo;
+ int m_themeID;
QString m_theme;
QString m_curMap;
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/qpushbuttonwithsound.cpp
--- a/QTfrontend/ui/widget/qpushbuttonwithsound.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/qpushbuttonwithsound.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -33,7 +33,7 @@
void QPushButtonWithSound::buttonClicked()
{
- if ( !isSoundEnabled || !HWForm::config->isFrontendSoundEnabled())
+ if ( !isSoundEnabled )
return;
if (this->isEnabled())
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/roomnameprompt.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/roomnameprompt.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,77 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "roomnameprompt.h"
+
+RoomNamePrompt::RoomNamePrompt(QWidget* parent, const QString & roomName) : QDialog(parent)
+{
+ setModal(true);
+ setWindowFlags(Qt::Sheet);
+ setWindowModality(Qt::WindowModal);
+ setMinimumSize(360, 130);
+ resize(360, 130);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+
+ // Layout
+ QVBoxLayout * dialogLayout = new QVBoxLayout(this);
+
+ // Label
+ label = new QLabel(tr("Enter a name for your room."));
+ label->setWordWrap(true);
+ dialogLayout->addWidget(label, 0);
+
+ // Input box
+ editBox = new QLineEdit();
+ editBox->setText(roomName);
+ editBox->setMaxLength(59); // It didn't like 60 :(
+ editBox->setStyleSheet("QLineEdit { padding: 3px; }");
+ editBox->selectAll();
+ dialogLayout->addWidget(editBox, 1);
+
+ dialogLayout->addStretch(1);
+
+ // Buttons
+ QHBoxLayout * buttonLayout = new QHBoxLayout();
+ buttonLayout->addStretch(1);
+ dialogLayout->addLayout(buttonLayout);
+
+ QPushButton * btnCancel = new QPushButton(tr("Cancel"));
+ QPushButton * btnOkay = new QPushButton(tr("Create room"));
+ connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(btnOkay, SIGNAL(clicked()), this, SLOT(accept()));
+ buttonLayout->addWidget(btnCancel);
+ buttonLayout->addWidget(btnOkay);
+ btnOkay->setDefault(true);
+
+ setStyleSheet("QPushButton { padding: 5px; }");
+
+ connect(btnOkay, SIGNAL(clicked()), this, SLOT(setRoomName()));
+}
+
+void RoomNamePrompt::setRoomName()
+{
+ emit roomNameChosen(editBox->text());
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/roomnameprompt.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/roomnameprompt.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,45 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef ROOMNAMEPROMPT_H
+#define ROOMNAMEPROMPT_H
+
+#include
+
+class QLineEdit;
+class QLabel;
+
+class RoomNamePrompt : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ RoomNamePrompt(QWidget* parent, const QString & roomName);
+
+ signals:
+ void roomNameChosen(const QString & roomName);
+
+ private slots:
+ void setRoomName();
+
+ private:
+ QLineEdit * editBox;
+ QLabel * label;
+};
+
+#endif // ROOMNAMEPROMPT_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/seedprompt.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/seedprompt.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,85 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "seedprompt.h"
+
+SeedPrompt::SeedPrompt(QWidget* parent, const QString & seed, bool editable) : QDialog(parent)
+{
+ setModal(true);
+ setWindowFlags(Qt::Sheet);
+ setWindowModality(Qt::WindowModal);
+ setMinimumSize(360, 160);
+ resize(360, 160);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+ // Layout
+ QVBoxLayout * dialogLayout = new QVBoxLayout(this);
+
+ // Label
+ QLabel * label = new QLabel(tr("The map seed is the basis for all random values generated by the game."));
+ label->setWordWrap(true);
+ dialogLayout->addWidget(label, 0);
+
+ // Input box
+ editBox = new QLineEdit();
+ editBox->setText(seed);
+ editBox->setReadOnly(!editable);
+ editBox->setStyleSheet("QLineEdit { padding: 3px; }");
+ dialogLayout->addWidget(editBox, 1);
+
+ dialogLayout->addStretch(1);
+
+ // Buttons
+ QHBoxLayout * buttonLayout = new QHBoxLayout();
+ buttonLayout->addStretch(1);
+ dialogLayout->addLayout(buttonLayout);
+ if (editable)
+ {
+ QPushButton * btnCancel = new QPushButton(tr("Cancel"));
+ QPushButton * btnOkay = new QPushButton(tr("Set seed"));
+ connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(btnOkay, SIGNAL(clicked()), this, SLOT(accept()));
+ buttonLayout->addWidget(btnCancel);
+ buttonLayout->addWidget(btnOkay);
+ btnOkay->setDefault(true);
+ }
+ else
+ {
+ QPushButton * btnClose = new QPushButton(tr("Close"));
+ connect(btnClose, SIGNAL(clicked()), this, SLOT(reject()));
+ buttonLayout->addWidget(btnClose);
+ btnClose->setDefault(true);
+ }
+
+ setStyleSheet("QPushButton { padding: 5px; }");
+
+ connect(this, SIGNAL(accepted()), this, SLOT(setSeed()));
+}
+
+void SeedPrompt::setSeed()
+{
+ emit seedSelected(editBox->text());
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/seedprompt.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/seedprompt.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,43 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef SEEDPROMPT_H
+#define SEEDPROMPT_H
+
+#include
+
+class QLineEdit;
+
+class SeedPrompt : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ SeedPrompt(QWidget* parent, const QString & seed, bool editable);
+
+ signals:
+ void seedSelected(const QString & seed);
+
+ private slots:
+ void setSeed();
+
+ private:
+ QLineEdit * editBox;
+};
+
+#endif // SEEDPROMPT_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/teamselect.cpp
--- a/QTfrontend/ui/widget/teamselect.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/teamselect.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -36,8 +36,6 @@
{
framePlaying->addTeam(team, true);
curPlayingTeams.push_back(team);
- connect(framePlaying->getTeamWidget(team), SIGNAL(teamStatusChanged(HWTeam)),
- this, SLOT(netTeamStatusChanged(const HWTeam&)));
connect(framePlaying->getTeamWidget(team), SIGNAL(hhNmChanged(const HWTeam&)),
this, SLOT(hhNumChanged(const HWTeam&)));
dynamic_cast(framePlaying->getTeamWidget(team))->hhNumChanged();
@@ -59,6 +57,7 @@
this, SLOT(changeTeamStatus(HWTeam)));
}
}
+
emit setEnabledGameStart(curPlayingTeams.size()>1);
}
@@ -144,17 +143,6 @@
emit setEnabledGameStart(curPlayingTeams.size()>1);
}
-void TeamSelWidget::netTeamStatusChanged(const HWTeam& team)
-{
- QList::iterator itPlay=std::find(curPlayingTeams.begin(), curPlayingTeams.end(), team);
-
-}
-
-//void TeamSelWidget::removeTeam(__attribute__ ((unused)) HWTeam team)
-//{
-//curDontPlayingTeams.erase(std::find(curDontPlayingTeams.begin(), curDontPlayingTeams.end(), team));
-//}
-
void TeamSelWidget::changeTeamStatus(HWTeam team)
{
QList::iterator itDontPlay=std::find(m_curNotPlayingTeams.begin(), m_curNotPlayingTeams.end(), team);
@@ -168,6 +156,12 @@
m_curNotPlayingTeams.push_back(*itPlay);
emit teamNotPlaying(*itPlay);
curPlayingTeams.erase(itPlay);
+
+ // Show team notice if less than two teams.
+ if (curPlayingTeams.size() < 2)
+ {
+ numTeamNotice->show();
+ }
}
else
{
@@ -179,6 +173,12 @@
curPlayingTeams.push_back(*itDontPlay);
if(!m_acceptOuter) emit teamWillPlay(*itDontPlay);
m_curNotPlayingTeams.erase(itDontPlay);
+
+ // Hide team notice if at least two teams.
+ if (curPlayingTeams.size() >= 2)
+ {
+ numTeamNotice->hide();
+ }
}
FrameTeams* pRemoveTeams;
@@ -224,6 +224,8 @@
pRemoveTeams->resize(pRemoveTeams->size().width(), szh1.height());
}
+ repaint();
+
emit setEnabledGameStart(curPlayingTeams.size()>1);
}
@@ -254,9 +256,13 @@
framePlaying = new FrameTeams();
frameDontPlaying = new FrameTeams();
+ // Add notice about number of required teams.
+ numTeamNotice = new QLabel("Two teams are required to play!");
+ mainLayout.addWidget(numTeamNotice);
+
QPalette p;
p.setColor(QPalette::Window, QColor(0x00, 0x00, 0x00));
- addScrArea(framePlaying, p.color(QPalette::Window).light(105), 250);
+ addScrArea(framePlaying, p.color(QPalette::Window).light(105), 150);
addScrArea(frameDontPlaying, p.color(QPalette::Window).dark(105), 0);
}
@@ -280,7 +286,9 @@
m_curNotPlayingTeams.clear();
foreach(HWTeam team, teamslist)
- addTeam(team);
+ addTeam(team);
+
+ repaint();
}
bool TeamSelWidget::isPlaying(const HWTeam &team) const
@@ -303,3 +311,10 @@
//team.setColor(framePlaying->getNextColor());
emit acceptRequested(team);
}
+
+void TeamSelWidget::repaint()
+{
+ QWidget::repaint();
+ framePlaying->repaint();
+ frameDontPlaying->repaint();
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/teamselect.h
--- a/QTfrontend/ui/widget/teamselect.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/teamselect.h Fri Feb 22 05:05:32 2013 +0100
@@ -20,6 +20,7 @@
#ifndef _TEAM_SELECT_INCLUDED
#define _TEAM_SELECT_INCLUDED
+#include
#include
#include
#include
@@ -50,7 +51,6 @@
public slots:
void addTeam(HWTeam team);
- void netTeamStatusChanged(const HWTeam& team);
void changeHHNum(const HWTeam&);
void changeTeamColor(const HWTeam&);
void changeTeamStatus(HWTeam team);
@@ -74,7 +74,9 @@
FrameTeams* framePlaying;
QVBoxLayout mainLayout;
+ QLabel *numTeamNotice;
bool m_acceptOuter;
+ void repaint();
QList curPlayingTeams;
QList m_curNotPlayingTeams;
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/teamselhelper.cpp
--- a/QTfrontend/ui/widget/teamselhelper.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui/widget/teamselhelper.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -55,7 +55,7 @@
butt = new QPushButton(difficultyIcon, team.name().replace("&","&&"), this);
butt->setFlat(true);
- butt->setToolTip(team.owner());
+ butt->setWhatsThis(tr("%1's team").arg(team.owner()));
mainLayout.addWidget(butt);
butt->setStyleSheet("QPushButton{"
"icon-size: 48px;"
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/themeprompt.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/themeprompt.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,165 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "DataManager.h"
+#include "lineeditcursor.h"
+#include "ThemeModel.h"
+#include "themeprompt.h"
+
+ThemePrompt::ThemePrompt(int currentIndex, QWidget* parent) : QDialog(parent)
+{
+ setModal(true);
+ setWindowFlags(Qt::Sheet);
+ setWindowModality(Qt::WindowModal);
+ setMinimumSize(550, 430);
+ resize(550, 430);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+ setStyleSheet("QPushButton { padding: 5px; margin-top: 10px; }");
+
+ // Theme model, and a model for setting a filter
+ ThemeModel * themeModel = DataManager::instance().themeModel();
+ filterModel = new QSortFilterProxyModel();
+ filterModel->setSourceModel(themeModel);
+ filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+
+ // Grid
+ QGridLayout * dialogLayout = new QGridLayout(this);
+ dialogLayout->setSpacing(0);
+ dialogLayout->setColumnStretch(1, 1);
+
+ QHBoxLayout * topLayout = new QHBoxLayout();
+
+ // Help/prompt message at top
+ QLabel * lblDesc = new QLabel(tr("Search for a theme:"));
+ lblDesc->setObjectName("lblDesc");
+ lblDesc->setStyleSheet("#lblDesc { color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; padding: 4px 10px;}");
+ lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ lblDesc->setFixedHeight(24);
+ lblDesc->setMinimumWidth(0);
+
+ // Filter text box
+ QWidget * filterContainer = new QWidget();
+ filterContainer->setFixedHeight(24);
+ filterContainer->setObjectName("filterContainer");
+ filterContainer->setStyleSheet("#filterContainer { background: #F6CB1C; border-top-right-radius: 10px; padding: 3px; }");
+ filterContainer->setFixedWidth(150);
+ txtFilter = new LineEditCursor(filterContainer);
+ txtFilter->setFixedWidth(150);
+ txtFilter->setFocus();
+ txtFilter->setFixedHeight(22);
+ txtFilter->setStyleSheet("LineEditCursor { border-width: 0px; border-radius: 6px; margin-top: 3px; margin-right: 3px; padding-left: 4px; padding-bottom: 2px; background-color: rgb(23, 11, 54); } LineEditCursor:hover, LineEditCursor:focus { background-color: rgb(13, 5, 68); }");
+ connect(txtFilter, SIGNAL(textChanged(const QString &)), this, SLOT(filterChanged(const QString &)));
+ connect(txtFilter, SIGNAL(moveUp()), this, SLOT(moveUp()));
+ connect(txtFilter, SIGNAL(moveDown()), this, SLOT(moveDown()));
+ connect(txtFilter, SIGNAL(moveLeft()), this, SLOT(moveLeft()));
+ connect(txtFilter, SIGNAL(moveRight()), this, SLOT(moveRight()));
+
+ // Corner widget
+ QLabel * corner = new QLabel();
+ corner->setPixmap(QPixmap(QString::fromUtf8(":/res/inverse-corner-bl.png")));
+ corner->setFixedSize(10, 10);
+
+ // Add widgets to top layout
+ topLayout->addWidget(lblDesc);
+ topLayout->addWidget(filterContainer);
+ topLayout->addWidget(corner, 0, Qt::AlignBottom);
+ topLayout->addStretch(1);
+
+ // Cancel button (closes dialog)
+ QPushButton * btnCancel = new QPushButton(tr("Cancel"));
+ connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+
+ // Select button
+ QPushButton * btnSelect = new QPushButton(tr("Use selected theme"));
+ btnSelect->setDefault(true);
+ connect(btnSelect, SIGNAL(clicked()), this, SLOT(onAccepted()));
+
+ // Add themes
+ list = new ThemeListView();
+ list->setModel(filterModel);
+ list->setViewMode(QListView::IconMode);
+ list->setResizeMode(QListView::Adjust);
+ list->setMovement(QListView::Static);
+ list->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ list->setSpacing(8);
+ list->setWordWrap(true);
+ list->setSelectionMode(QAbstractItemView::SingleSelection);
+ list->setObjectName("themeList");
+ list->setCurrentIndex(filterModel->index(currentIndex, 0));
+ connect(list, SIGNAL(activated(const QModelIndex &)), this, SLOT(themeChosen(const QModelIndex &)));
+ connect(list, SIGNAL(clicked(const QModelIndex &)), this, SLOT(themeChosen(const QModelIndex &)));
+
+ // Add elements to layouts
+ dialogLayout->addLayout(topLayout, 0, 0, 1, 3);
+ dialogLayout->addWidget(list, 1, 0, 1, 3);
+ dialogLayout->addWidget(btnCancel, 2, 0, 1, 1, Qt::AlignLeft);
+ dialogLayout->addWidget(btnSelect, 2, 2, 1, 1, Qt::AlignRight);
+}
+
+void ThemePrompt::moveUp()
+{
+ list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier));
+}
+
+void ThemePrompt::moveDown()
+{
+ list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier));
+}
+
+void ThemePrompt::moveLeft()
+{
+ list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveLeft, Qt::NoModifier));
+}
+
+void ThemePrompt::moveRight()
+{
+ list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveRight, Qt::NoModifier));
+}
+
+void ThemePrompt::onAccepted()
+{
+ themeChosen(list->currentIndex());
+}
+
+// When a theme is selected
+void ThemePrompt::themeChosen(const QModelIndex & index)
+{
+ done(filterModel->mapToSource(index).row() + 1); // Since returning 0 means canceled
+}
+
+// When the text in the filter text box is changed
+void ThemePrompt::filterChanged(const QString & text)
+{
+ filterModel->setFilterFixedString(text);
+ list->setCurrentIndex(filterModel->index(0, 0));
+}
\ No newline at end of file
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui/widget/themeprompt.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/themeprompt.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,61 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef THEMEPROMPT_H
+#define THEMEPROMPT_H
+
+#include
+#include
+#include
+
+class QLineEdit;
+class QModelIndex;
+class QSortFilterProxyModel;
+class LineEditCursor;
+
+class ThemeListView : public QListView
+{
+ friend class ThemePrompt;
+
+ public:
+ ThemeListView(QWidget* parent = 0) : QListView(parent){}
+};
+
+class ThemePrompt : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ ThemePrompt(int currentIndex = 0, QWidget* parent = 0);
+
+ private:
+ LineEditCursor * txtFilter;
+ ThemeListView * list;
+ QSortFilterProxyModel * filterModel;
+
+ private slots:
+ void onAccepted();
+ void themeChosen(const QModelIndex & index);
+ void filterChanged(const QString & text);
+ void moveUp();
+ void moveDown();
+ void moveLeft();
+ void moveRight();
+};
+
+#endif // THEMEPROMPT_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui_hwform.cpp
--- a/QTfrontend/ui_hwform.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui_hwform.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -27,10 +27,8 @@
#include "pagetraining.h"
#include "pagenetserver.h"
#include "pageoptions.h"
-#include "pagefeedback.h"
#include "pageingame.h"
#include "pagescheme.h"
-#include "pagenettype.h"
#include "pageroomslist.h"
#include "pageinfo.h"
#include "pagenetgame.h"
@@ -60,7 +58,7 @@
centralWidget = new QWidget(HWForm);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
- SetupPages(centralWidget, HWForm);
+ SetupPages(centralWidget);
HWForm->setCentralWidget(centralWidget);
@@ -74,7 +72,7 @@
font14 = new QFont("MS Shell Dlg", 14);
}
-void Ui_HWForm::SetupPages(QWidget *Parent, HWForm *HWForm)
+void Ui_HWForm::SetupPages(QWidget *Parent)
{
Pages = new QStackedLayout(Parent);
@@ -93,7 +91,7 @@
pageNet = new PageNet();
Pages->addWidget(pageNet);
- pageNetGame = new PageNetGame(Parent, HWForm->gameSettings);
+ pageNetGame = new PageNetGame(Parent);
Pages->addWidget(pageNetGame);
pageInfo = new PageInfo();
@@ -120,7 +118,7 @@
pageInGame = new PageInGame();
Pages->addWidget(pageInGame);
- pageRoomsList = new PageRoomsList(Parent, HWForm->gameSettings);
+ pageRoomsList = new PageRoomsList(Parent);
Pages->addWidget(pageRoomsList);
pageConnecting = new PageConnecting();
@@ -132,9 +130,6 @@
pageAdmin = new PageAdmin();
Pages->addWidget(pageAdmin);
- pageNetType = new PageNetType();
- Pages->addWidget(pageNetType);
-
pageCampaign = new PageCampaign();
Pages->addWidget(pageCampaign);
@@ -144,9 +139,6 @@
pageDataDownload = new PageDataDownload();
Pages->addWidget(pageDataDownload);
- pageFeedback = new PageFeedback();
- Pages->addWidget(pageFeedback);
-
pageVideos = new PageVideos();
Pages->addWidget(pageVideos);
}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/ui_hwform.h
--- a/QTfrontend/ui_hwform.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/ui_hwform.h Fri Feb 22 05:05:32 2013 +0100
@@ -24,7 +24,6 @@
class PageMultiplayer;
class PagePlayDemo;
class PageOptions;
-class PageFeedback;
class PageNet;
class PageNetServer;
class PageNetChat;
@@ -41,7 +40,6 @@
class PageConnecting;
class PageScheme;
class PageAdmin;
-class PageNetType;
class PageDrawMap;
class PageVideos;
class QStackedLayout;
@@ -60,7 +58,6 @@
PageMultiplayer *pageMultiplayer;
PagePlayDemo *pagePlayDemo;
PageOptions *pageOptions;
- PageFeedback *pageFeedback;
PageNet *pageNet;
PageNetServer * pageNetServer;
PageNetChat *pageNetChat;
@@ -76,7 +73,6 @@
PageConnecting *pageConnecting;
PageScheme *pageScheme;
PageAdmin *pageAdmin;
- PageNetType *pageNetType;
PageCampaign *pageCampaign;
PageDrawMap *pageDrawMap;
PageVideos *pageVideos;
@@ -86,7 +82,7 @@
void setupUi(HWForm *HWForm);
void SetupFonts();
- void SetupPages(QWidget *Parent, HWForm *HWForm);
+ void SetupPages(QWidget *Parent);
};
#endif // UI_HWFORM_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/DataManager.cpp
--- a/QTfrontend/util/DataManager.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/util/DataManager.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -40,7 +40,8 @@
DataManager::DataManager()
{
m_hatModel = NULL;
- m_mapModel = NULL;
+ m_staticMapModel = NULL;
+ m_missionMapModel = NULL;
m_themeModel = NULL;
m_colorsModel = NULL;
m_bindsModel = NULL;
@@ -92,13 +93,22 @@
return m_hatModel;
}
-MapModel * DataManager::mapModel()
+MapModel * DataManager::staticMapModel()
{
- if (m_mapModel == NULL) {
- m_mapModel = new MapModel();
- m_mapModel->loadMaps();
+ if (m_staticMapModel == NULL) {
+ m_staticMapModel = new MapModel();
+ m_staticMapModel->loadMaps(MapModel::StaticMap);
}
- return m_mapModel;
+ return m_staticMapModel;
+}
+
+MapModel * DataManager::missionMapModel()
+{
+ if (m_missionMapModel == NULL) {
+ m_missionMapModel = new MapModel();
+ m_missionMapModel->loadMaps(MapModel::MissionMap);
+ }
+ return m_missionMapModel;
}
ThemeModel * DataManager::themeModel()
@@ -135,6 +145,11 @@
{
m_bindsModel = new QStandardItemModel();
+ QStandardItem * firstItem = new QStandardItem();
+ firstItem->setData(tr("Use Default"), Qt::DisplayRole);
+ firstItem->setData("default", Qt::UserRole + 1);
+ m_bindsModel->appendRow(firstItem);
+
for(int j = 0; sdlkeys[j][1][0] != '\0'; j++)
{
QStandardItem * item = new QStandardItem();
@@ -161,3 +176,12 @@
m_colorsModel->item(i)->setData(QColor(colors[i]));
}
}
+
+bool DataManager::ensureFileExists(const QString &fileName)
+{
+ QFile tmpfile(fileName);
+ if (!tmpfile.exists())
+ return tmpfile.open(QFile::WriteOnly);
+ else
+ return true;
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/DataManager.h
--- a/QTfrontend/util/DataManager.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/util/DataManager.h Fri Feb 22 05:05:32 2013 +0100
@@ -88,13 +88,22 @@
HatModel * hatModel();
/**
- * @brief Returns pointer to a model of available maps.
+ * @brief Returns pointer to a model of available static maps.
*
* The model is updated automatically on data reload.
*
* @return map model pointer.
*/
- MapModel * mapModel();
+ MapModel * staticMapModel();
+
+ /**
+ * @brief Returns pointer to a model of available mission maps.
+ *
+ * The model is updated automatically on data reload.
+ *
+ * @return map model pointer.
+ */
+ MapModel * missionMapModel();
/**
* @brief Returns pointer to a model of available themes.
@@ -108,6 +117,8 @@
QStandardItemModel * colorsModel();
QStandardItemModel * bindsModel();
+ static bool ensureFileExists(const QString & fileName);
+
public slots:
/// Reloads data from storage.
void reload();
@@ -132,7 +143,8 @@
GameStyleModel * m_gameStyleModel; ///< game style model instance
HatModel * m_hatModel; ///< hat model instance
- MapModel * m_mapModel; ///< map model instance
+ MapModel * m_staticMapModel; ///< static map model instance
+ MapModel * m_missionMapModel; ///< mission map model instance
ThemeModel * m_themeModel; ///< theme model instance
QStandardItemModel * m_colorsModel;
QStandardItemModel * m_bindsModel;
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/FileEngine.cpp
--- a/QTfrontend/util/FileEngine.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/util/FileEngine.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -1,306 +1,380 @@
-/* borrowed from https://github.com/skhaz/qt-physfs-wrapper
- * TODO: add copyright header, determine license
- */
-
-
-#include "hwpacksmounter.h"
-#include "FileEngine.h"
-
-
-const QString FileEngineHandler::scheme = "physfs:/";
-
-FileEngine::FileEngine(const QString& filename)
-: _handler(NULL)
-, _flags(0)
-{
- setFileName(filename);
-}
-
-FileEngine::~FileEngine()
-{
- close();
-}
-
-bool FileEngine::open(QIODevice::OpenMode openMode)
-{
- close();
-
- if (openMode & QIODevice::WriteOnly) {
- _handler = PHYSFS_openWrite(_filename.toUtf8().constData());
- _flags = QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::FileType;
- }
-
- else if (openMode & QIODevice::ReadOnly) {
- _handler = PHYSFS_openRead(_filename.toUtf8().constData());
- }
-
- else if (openMode & QIODevice::Append) {
- _handler = PHYSFS_openAppend(_filename.toUtf8().constData());
- }
-
- else {
- qWarning("Bad file open mode: %d", (int)openMode);
- }
-
- if (!_handler) {
- qWarning("Failed to open %s, reason: %s", _filename.toUtf8().constData(), PHYSFS_getLastError());
- return false;
- }
-
- return true;
-}
-
-bool FileEngine::close()
-{
- if (isOpened()) {
- int result = PHYSFS_close(_handler);
- _handler = NULL;
- return result != 0;
- }
-
- return true;
-}
-
-bool FileEngine::flush()
-{
- return PHYSFS_flush(_handler) != 0;
-}
-
-qint64 FileEngine::size() const
-{
- return _size;
-}
-
-qint64 FileEngine::pos() const
-{
- return PHYSFS_tell(_handler);
-}
-
-bool FileEngine::seek(qint64 pos)
-{
- return PHYSFS_seek(_handler, pos) != 0;
-}
-
-bool FileEngine::isSequential() const
-{
- return false;
-}
-
-bool FileEngine::remove()
-{
- return PHYSFS_delete(_filename.toUtf8().constData()) != 0;
-}
-
-bool FileEngine::mkdir(const QString &dirName, bool createParentDirectories) const
-{
- Q_UNUSED(createParentDirectories);
- return PHYSFS_mkdir(dirName.toUtf8().constData()) != 0;
-}
-
-bool FileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
-{
- Q_UNUSED(recurseParentDirectories);
- return PHYSFS_delete(dirName.toUtf8().constData()) != 0;
-}
-
-bool FileEngine::caseSensitive() const
-{
- return true;
-}
-
-bool FileEngine::isRelativePath() const
-{
- return true;
-}
-
-QAbstractFileEngineIterator * FileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
-{
- return new FileEngineIterator(filters, filterNames, entryList(filters, filterNames));
-}
-
-QStringList FileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
-{
- Q_UNUSED(filters);
-
- QString file;
- QStringList result;
- char **files = PHYSFS_enumerateFiles(_filename.toUtf8().constData());
-
- for (char **i = files; *i != NULL; i++) {
- file = QString::fromUtf8(*i);
-
- if (filterNames.isEmpty() || QDir::match(filterNames, file)) {
- result << file;
- }
- }
-
- PHYSFS_freeList(files);
-
- return result;
-}
-
-QAbstractFileEngine::FileFlags FileEngine::fileFlags(FileFlags type) const
-{
- return type & _flags;
-}
-
-QString FileEngine::fileName(FileName file) const
-{
- if (file == QAbstractFileEngine::AbsolutePathName)
- return PHYSFS_getWriteDir();
-
- return QString("physfs://%1").arg(_filename);
-}
-
-QDateTime FileEngine::fileTime(FileTime time) const
-{
-
- switch (time)
- {
- case QAbstractFileEngine::ModificationTime:
- default:
- return _datetime;
- break;
- };
-}
-
-void FileEngine::setFileName(const QString &file)
-{
- if(file.startsWith(FileEngineHandler::scheme))
- _filename = file.mid(FileEngineHandler::scheme.size());
- else
- _filename = file;
-
- PHYSFS_Stat stat;
- if (PHYSFS_stat(_filename.toUtf8().constData(), &stat) != 0) {
- _size = stat.filesize;
- _datetime = QDateTime::fromTime_t(stat.modtime);
-// _flags |= QAbstractFileEngine::WriteUserPerm;
- _flags |= QAbstractFileEngine::ReadUserPerm;
- _flags |= QAbstractFileEngine::ExistsFlag;
-
- switch (stat.filetype)
- {
- case PHYSFS_FILETYPE_REGULAR:
- _flags |= QAbstractFileEngine::FileType;
- break;
-
- case PHYSFS_FILETYPE_DIRECTORY:
- _flags |= QAbstractFileEngine::DirectoryType;
- break;
- case PHYSFS_FILETYPE_SYMLINK:
- _flags |= QAbstractFileEngine::LinkType;
- break;
- default: ;
- }
- }
-}
-
-bool FileEngine::atEnd() const
-{
- return PHYSFS_eof(_handler) != 0;
-}
-
-qint64 FileEngine::read(char *data, qint64 maxlen)
-{
- return PHYSFS_readBytes(_handler, data, maxlen);
-}
-
-qint64 FileEngine::write(const char *data, qint64 len)
-{
- return PHYSFS_writeBytes(_handler, data, len);
-}
-
-bool FileEngine::isOpened() const
-{
- return _handler != NULL;
-}
-
-QFile::FileError FileEngine::error() const
-{
- return QFile::UnspecifiedError;
-}
-
-QString FileEngine::errorString() const
-{
- return PHYSFS_getLastError();
-}
-
-bool FileEngine::supportsExtension(Extension extension) const
-{
- return extension == QAbstractFileEngine::AtEndExtension;
-}
-
-
-
-FileEngineHandler::FileEngineHandler(char *argv0)
-{
- PHYSFS_init(argv0);
-}
-
-FileEngineHandler::~FileEngineHandler()
-{
- PHYSFS_deinit();
-}
-
-QAbstractFileEngine* FileEngineHandler::create(const QString &filename) const
-{
- if (filename.startsWith(scheme))
- return new FileEngine(filename.mid(scheme.size()));
- else
- return NULL;
-}
-
-void FileEngineHandler::mount(const QString &path)
-{
- PHYSFS_mount(path.toUtf8().constData(), NULL, 1);
-}
-
-void FileEngineHandler::mount(const QString & path, const QString & mountPoint)
-{
- PHYSFS_mount(path.toUtf8().constData(), mountPoint.toUtf8().constData(), 1);
-}
-
-void FileEngineHandler::setWriteDir(const QString &path)
-{
- PHYSFS_setWriteDir(path.toUtf8().constData());
-}
-
-void FileEngineHandler::mountPacks()
-{
- hedgewarsMountPackages();
-}
-
-
-FileEngineIterator::FileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, const QStringList &entries)
- : QAbstractFileEngineIterator(filters, nameFilters)
-{
- m_entries = entries;
-
- /* heck.. docs are unclear on this
- * QDirIterator puts iterator before first entry
- * but QAbstractFileEngineIterator example puts iterator on first entry
- * though QDirIterator approach seems to be the right one
- */
-
- m_index = -1;
-}
-
-bool FileEngineIterator::hasNext() const
-{
- return m_index < m_entries.size() - 1;
-}
-
-QString FileEngineIterator::next()
-{
- if (!hasNext())
- return QString();
-
- ++m_index;
- return currentFilePath();
-}
-
-QString FileEngineIterator::currentFileName() const
-{
- return m_entries.at(m_index);
-}
+/* borrowed from https://github.com/skhaz/qt-physfs-wrapper
+ * TODO: add copyright header, determine license
+ */
+
+#include "hwpacksmounter.h"
+#include "FileEngine.h"
+
+
+const QString FileEngineHandler::scheme = "physfs:/";
+
+FileEngine::FileEngine(const QString& filename)
+ : m_handle(NULL)
+ , m_size(0)
+ , m_flags(0)
+ , m_bufferSet(false)
+ , m_readWrite(false)
+{
+ setFileName(filename);
+}
+
+FileEngine::~FileEngine()
+{
+ close();
+}
+
+bool FileEngine::open(QIODevice::OpenMode openMode)
+{
+ close();
+
+ if ((openMode & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
+ m_handle = PHYSFS_openAppend(m_fileName.toUtf8().constData());
+ if(m_handle)
+ {
+ m_readWrite = true;
+ seek(0);
+ }
+ }
+
+ else if (openMode & QIODevice::WriteOnly) {
+ m_handle = PHYSFS_openWrite(m_fileName.toUtf8().constData());
+ m_flags = QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::FileType;
+ }
+
+ else if (openMode & QIODevice::ReadOnly) {
+ m_handle = PHYSFS_openRead(m_fileName.toUtf8().constData());
+ }
+
+ else if (openMode & QIODevice::Append) {
+ m_handle = PHYSFS_openAppend(m_fileName.toUtf8().constData());
+ }
+
+ else {
+ qWarning("[PHYSFS] Bad file open mode: %d", (int)openMode);
+ }
+
+ if (!m_handle) {
+ qWarning("[PHYSFS] Failed to open %s, reason: %s", m_fileName.toUtf8().constData(), PHYSFS_getLastError());
+ return false;
+ }
+
+ return true;
+}
+
+bool FileEngine::close()
+{
+ if (isOpened()) {
+ int result = PHYSFS_close(m_handle);
+ m_handle = NULL;
+ return result != 0;
+ }
+
+ return true;
+}
+
+bool FileEngine::flush()
+{
+ return PHYSFS_flush(m_handle) != 0;
+}
+
+qint64 FileEngine::size() const
+{
+ return m_size;
+}
+
+qint64 FileEngine::pos() const
+{
+ return PHYSFS_tell(m_handle);
+}
+
+bool FileEngine::setSize(qint64 size)
+{
+ if(size == 0)
+ {
+ m_size = 0;
+ return open(QIODevice::WriteOnly);
+ }
+ else
+ return false;
+}
+
+bool FileEngine::seek(qint64 pos)
+{
+ bool ok = PHYSFS_seek(m_handle, pos) != 0;
+
+ return ok;
+}
+
+bool FileEngine::isSequential() const
+{
+ return false;
+}
+
+bool FileEngine::remove()
+{
+ return PHYSFS_delete(m_fileName.toUtf8().constData()) != 0;
+}
+
+bool FileEngine::mkdir(const QString &dirName, bool createParentDirectories) const
+{
+ Q_UNUSED(createParentDirectories);
+
+ return PHYSFS_mkdir(dirName.toUtf8().constData()) != 0;
+}
+
+bool FileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
+{
+ Q_UNUSED(recurseParentDirectories);
+
+ return PHYSFS_delete(dirName.toUtf8().constData()) != 0;
+}
+
+bool FileEngine::caseSensitive() const
+{
+ return true;
+}
+
+bool FileEngine::isRelativePath() const
+{
+ return false;
+}
+
+QAbstractFileEngineIterator * FileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+{
+ return new FileEngineIterator(filters, filterNames, entryList(filters, filterNames));
+}
+
+QStringList FileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
+{
+ Q_UNUSED(filters);
+
+ QString file;
+ QStringList result;
+ char **files = PHYSFS_enumerateFiles(m_fileName.toUtf8().constData());
+
+ for (char **i = files; *i != NULL; i++) {
+ file = QString::fromUtf8(*i);
+
+ if (filterNames.isEmpty() || QDir::match(filterNames, file)) {
+ result << file;
+ }
+ }
+
+ PHYSFS_freeList(files);
+
+ return result;
+}
+
+QAbstractFileEngine::FileFlags FileEngine::fileFlags(FileFlags type) const
+{
+ return type & m_flags;
+}
+
+QString FileEngine::fileName(FileName file) const
+{
+ switch(file)
+ {
+ case QAbstractFileEngine::AbsolutePathName:
+ {
+ QString s(PHYSFS_getWriteDir());
+ return s;
+ }
+ case QAbstractFileEngine::BaseName:
+ {
+ int l = m_fileName.lastIndexOf('/');
+ QString s = m_fileName.mid(l + 1);
+ return s;
+ }
+ case QAbstractFileEngine::DefaultName:
+ case QAbstractFileEngine::AbsoluteName:
+ default:
+ {
+ QString s = "physfs:/" + m_fileName;
+ return s;
+ }
+ }
+}
+
+QDateTime FileEngine::fileTime(FileTime time) const
+{
+ switch (time)
+ {
+ case QAbstractFileEngine::ModificationTime:
+ default:
+ return m_date;
+ break;
+ };
+}
+
+void FileEngine::setFileName(const QString &file)
+{
+ if(file.startsWith(FileEngineHandler::scheme))
+ m_fileName = file.mid(FileEngineHandler::scheme.size());
+ else
+ m_fileName = file;
+ PHYSFS_Stat stat;
+ if (PHYSFS_stat(m_fileName.toUtf8().constData(), &stat) != 0) {
+ m_size = stat.filesize;
+ m_date = QDateTime::fromTime_t(stat.modtime);
+// m_flags |= QAbstractFileEngine::WriteOwnerPerm;
+ m_flags |= QAbstractFileEngine::ReadOwnerPerm;
+ m_flags |= QAbstractFileEngine::ReadUserPerm;
+ m_flags |= QAbstractFileEngine::ExistsFlag;
+ m_flags |= QAbstractFileEngine::LocalDiskFlag;
+
+ switch (stat.filetype)
+ {
+ case PHYSFS_FILETYPE_REGULAR:
+ m_flags |= QAbstractFileEngine::FileType;
+ break;
+ case PHYSFS_FILETYPE_DIRECTORY:
+ m_flags |= QAbstractFileEngine::DirectoryType;
+ break;
+ case PHYSFS_FILETYPE_SYMLINK:
+ m_flags |= QAbstractFileEngine::LinkType;
+ break;
+ default: ;
+ }
+ }
+}
+
+bool FileEngine::atEnd() const
+{
+ return PHYSFS_eof(m_handle) != 0;
+}
+
+qint64 FileEngine::read(char *data, qint64 maxlen)
+{
+ if(m_readWrite)
+ {
+ if(pos() == 0)
+ open(QIODevice::ReadOnly);
+ else
+ return -1;
+ }
+
+ qint64 len = PHYSFS_readBytes(m_handle, data, maxlen);
+ return len;
+}
+
+qint64 FileEngine::readLine(char *data, qint64 maxlen)
+{
+ if(!m_bufferSet)
+ {
+ PHYSFS_setBuffer(m_handle, 4096);
+ m_bufferSet = true;
+ }
+
+ qint64 bytesRead = 0;
+ while(PHYSFS_readBytes(m_handle, data, 1)
+ && maxlen
+ && (*data == '\n'))
+ {
+ ++data;
+ --maxlen;
+ ++bytesRead;
+ }
+
+ return bytesRead;
+}
+
+qint64 FileEngine::write(const char *data, qint64 len)
+{
+ return PHYSFS_writeBytes(m_handle, data, len);
+}
+
+bool FileEngine::isOpened() const
+{
+ return m_handle != NULL;
+}
+
+QFile::FileError FileEngine::error() const
+{
+ return QFile::UnspecifiedError;
+}
+
+QString FileEngine::errorString() const
+{
+ return PHYSFS_getLastError();
+}
+
+bool FileEngine::supportsExtension(Extension extension) const
+{
+ return
+ (extension == QAbstractFileEngine::AtEndExtension)
+ || (extension == QAbstractFileEngine::FastReadLineExtension)
+ ;
+}
+
+
+FileEngineHandler::FileEngineHandler(char *argv0)
+{
+ PHYSFS_init(argv0);
+}
+
+FileEngineHandler::~FileEngineHandler()
+{
+ PHYSFS_deinit();
+}
+
+QAbstractFileEngine* FileEngineHandler::create(const QString &filename) const
+{
+ if (filename.startsWith(scheme))
+ return new FileEngine(filename);
+ else
+ return NULL;
+}
+
+void FileEngineHandler::mount(const QString &path)
+{
+ PHYSFS_mount(path.toUtf8().constData(), NULL, 1);
+}
+
+void FileEngineHandler::mount(const QString & path, const QString & mountPoint)
+{
+ PHYSFS_mount(path.toUtf8().constData(), mountPoint.toUtf8().constData(), 1);
+}
+
+void FileEngineHandler::setWriteDir(const QString &path)
+{
+ PHYSFS_setWriteDir(path.toUtf8().constData());
+}
+
+void FileEngineHandler::mountPacks()
+{
+ hedgewarsMountPackages();
+}
+
+
+FileEngineIterator::FileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, const QStringList &entries)
+ : QAbstractFileEngineIterator(filters, nameFilters)
+{
+ m_entries = entries;
+
+ /* heck.. docs are unclear on this
+ * QDirIterator puts iterator before first entry
+ * but QAbstractFileEngineIterator example puts iterator on first entry
+ * though QDirIterator approach seems to be the right one
+ */
+
+ m_index = -1;
+}
+
+bool FileEngineIterator::hasNext() const
+{
+ return m_index < m_entries.size() - 1;
+}
+
+QString FileEngineIterator::next()
+{
+ if (!hasNext())
+ return QString();
+
+ ++m_index;
+ return currentFilePath();
+}
+
+QString FileEngineIterator::currentFileName() const
+{
+ return m_entries.at(m_index);
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/FileEngine.h
--- a/QTfrontend/util/FileEngine.h Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/util/FileEngine.h Fri Feb 22 05:05:32 2013 +0100
@@ -22,6 +22,7 @@
virtual bool flush();
virtual qint64 size() const;
virtual qint64 pos() const;
+ virtual bool setSize(qint64 size);
virtual bool seek(qint64 pos);
virtual bool isSequential() const;
virtual bool remove();
@@ -38,6 +39,7 @@
bool atEnd() const;
virtual qint64 read(char *data, qint64 maxlen);
+ virtual qint64 readLine(char *data, qint64 maxlen);
virtual qint64 write(const char *data, qint64 len);
bool isOpened() const;
@@ -48,11 +50,13 @@
virtual bool supportsExtension(Extension extension) const;
private:
- PHYSFS_file *_handler;
- qint64 _size;
- FileFlags _flags;
- QString _filename;
- QDateTime _datetime;
+ PHYSFS_file *m_handle;
+ qint64 m_size;
+ FileFlags m_flags;
+ QString m_fileName;
+ QDateTime m_date;
+ bool m_bufferSet;
+ bool m_readWrite;
};
class FileEngineHandler : public QAbstractFileEngineHandler
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/LibavInteraction.cpp
--- a/QTfrontend/util/LibavInteraction.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/util/LibavInteraction.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -70,7 +70,7 @@
// get list of all codecs
AVCodec* pCodec = NULL;
- while (pCodec = av_codec_next(pCodec))
+ while ((pCodec = av_codec_next(pCodec)))
{
#if LIBAVCODEC_VERSION_MAJOR >= 54
if (!av_codec_is_encoder(pCodec))
@@ -162,7 +162,7 @@
// get list of all formats
AVOutputFormat* pFormat = NULL;
- while (pFormat = av_oformat_next(pFormat))
+ while ((pFormat = av_oformat_next(pFormat)))
{
if (!pFormat->extensions)
continue;
@@ -270,7 +270,7 @@
QByteArray utf8path = filepath.toUtf8();
if (avformat_open_input(&pContext, utf8path.data(), NULL, NULL) < 0)
return "";
-#if LIBAVFORMAT_VERSION_MAJOR < 54
+#if LIBAVFORMAT_VERSION_MAJOR < 53
if (av_find_stream_info(pContext) < 0)
#else
if (avformat_find_stream_info(pContext, NULL) < 0)
@@ -302,13 +302,13 @@
else
continue;
AVCodec* pDecoder = avcodec_find_decoder(pCodec->codec_id);
- desc += pDecoder? pDecoder->name : "unknown";
+ desc += pDecoder? pDecoder->name : tr("unknown");
desc += "\n";
}
AVDictionaryEntry* pComment = av_dict_get(pContext->metadata, "comment", NULL, 0);
if (pComment)
desc += QString("\n") + pComment->value;
-#if LIBAVFORMAT_VERSION_MAJOR < 54
+#if LIBAVFORMAT_VERSION_MAJOR < 53
av_close_input_file(pContext);
#else
avformat_close_input(&pContext);
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/MessageDialog.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/MessageDialog.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,39 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "MessageDialog.h"
+
+int MessageDialog::ShowErrorMessage(const QString & msg, QWidget * parent)
+{
+ return ShowMessage(msg, QMessageBox::tr("Hedgewars - Warning"), QMessageBox::Warning, parent);
+}
+
+int MessageDialog::ShowInfoMessage(const QString & msg, QWidget * parent)
+{
+ return ShowMessage(msg, QMessageBox::tr("Hedgewars - Information"), QMessageBox::Information, parent);
+}
+
+int MessageDialog::ShowMessage(const QString & msg, const QString & title, QMessageBox::Icon icon, QWidget * parent)
+{
+ QMessageBox msgMsg(parent);
+ msgMsg.setIcon(icon);
+ msgMsg.setWindowTitle(title.isEmpty() ? QMessageBox::tr("Hedgewars") : title);
+ msgMsg.setText(msg);
+ msgMsg.setWindowModality(Qt::WindowModal);
+ return msgMsg.exec();
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/MessageDialog.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/MessageDialog.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef MESSAGEDIALOG_H
+#define MESSAGEDIALOG_H
+
+#include
+#include
+
+class QWidget;
+
+class MessageDialog
+{
+ public:
+ static int ShowErrorMessage(const QString & msg, QWidget * parent = 0);
+ static int ShowInfoMessage(const QString & msg, QWidget * parent = 0);
+ static int ShowMessage(const QString & msg, const QString & title = QString(), QMessageBox::Icon icon = QMessageBox::NoIcon, QWidget * parent = 0);
+};
+
+#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/SDLInteraction.cpp
--- a/QTfrontend/util/SDLInteraction.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/util/SDLInteraction.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -25,9 +25,13 @@
#include "SDL_mixer.h"
#include "HWApplication.h"
+#include "hwform.h" /* you know, we could just put a config singleton lookup function in gameuiconfig or something... */
+#include "gameuiconfig.h"
#include "SDLInteraction.h"
+#include "physfsrwops.h"
+
extern char sdlkeys[1024][2][128];
extern char xb360buttons[][128];
extern char xb360dpad[128];
@@ -184,16 +188,18 @@
return;
SDL_Init(SDL_INIT_AUDIO);
- Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024);
- m_audioInitialized = true;
+ if(!Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)) /* should we keep trying, or just turn off permanently? */
+ m_audioInitialized = true;
}
void SDLInteraction::playSoundFile(const QString & soundFile)
{
+ if (!HWForm::config || !HWForm::config->isFrontendSoundEnabled()) return;
SDLAudioInit();
+ if (!m_audioInitialized) return;
if (!m_soundMap->contains(soundFile))
- m_soundMap->insert(soundFile, Mix_LoadWAV(soundFile.toLocal8Bit().constData()));
+ m_soundMap->insert(soundFile, Mix_LoadWAV_RW(PHYSFSRWOPS_openRead(soundFile.toLocal8Bit().constData()), 1));
//FIXME: this is a hack, but works as long as we have few concurrent playing sounds
if (Mix_Playing(lastchannel) == false)
@@ -230,9 +236,10 @@
return;
SDLAudioInit();
+ if (!m_audioInitialized) return;
if (m_music == NULL)
- m_music = Mix_LoadMUS(m_musicTrack.toLocal8Bit().constData());
+ m_music = Mix_LoadMUS_RW(PHYSFSRWOPS_openRead(m_musicTrack.toLocal8Bit().constData()));
Mix_VolumeMusic(MIX_MAX_VOLUME - 28);
Mix_FadeInMusic(m_music, -1, 1750);
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/namegen.cpp
--- a/QTfrontend/util/namegen.cpp Sun Nov 18 01:06:01 2012 +0400
+++ b/QTfrontend/util/namegen.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -125,22 +125,21 @@
QStringList list;
// find .txt to load the names from
- QFile * file = new QFile(QString("physfs://Names/%1.txt").arg(filename));
+ QFile file(QString("physfs://Names/%1.txt").arg(filename));
- if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text))
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
- QTextStream in(file);
- while (!in.atEnd())
+ QTextStream in(&file);
+ QString line;
+ do
{
- QString line = in.readLine();
+ line = in.readLine();
+
if(!line.isEmpty())
list.append(line);
- }
+ } while (!line.isNull());
}
- // this QFile isn't needed any further
- delete file;
-
if (list.size() == 0)
list.append(filename);
@@ -153,22 +152,21 @@
QStringList list;
// find .cfg to load the dicts from
- QFile * file = new QFile(QString("physfs://Names/%1.cfg").arg(hatname));
+ QFile file(QString("physfs://Names/%1.cfg").arg(hatname));
- if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text))
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
- QTextStream in(file);
- while (!in.atEnd())
+ QTextStream in(&file);
+ QString line;
+ do
{
- QString line = in.readLine();
+ line = in.readLine();
+
if(!line.isEmpty())
list.append(line);
- }
+ } while (!line.isNull());
}
- // this QFile isn't needed any further
- delete file;
-
if (list.size() == 0)
list.append(QString("generic"));
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/AutoUpdater.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/AutoUpdater.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2008 Remko Troncon
+ */
+
+#include "AutoUpdater.h"
+
+AutoUpdater::~AutoUpdater()
+{
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/AutoUpdater.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/AutoUpdater.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2008 Remko Troncon
+ */
+
+#ifndef AUTOUPDATER_H
+#define AUTOUPDATER_H
+
+class AutoUpdater
+{
+ public:
+ virtual ~AutoUpdater();
+
+ virtual void checkForUpdates() = 0;
+ virtual void checkForUpdatesNow() = 0;
+};
+
+#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/CocoaInitializer.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/CocoaInitializer.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+// see original example here http://el-tramo.be/blog/mixing-cocoa-and-qt
+
+#ifndef COCOAINITIALIZER_H
+#define COCOAINITIALIZER_H
+
+class CocoaInitializer
+{
+ public:
+ CocoaInitializer();
+ ~CocoaInitializer();
+
+ private:
+ class Private;
+ Private* c;
+};
+
+#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/CocoaInitializer.mm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/CocoaInitializer.mm Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,44 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+// see original example here http://el-tramo.be/blog/mixing-cocoa-and-qt
+
+#include "CocoaInitializer.h"
+
+#include
+#include
+#include
+
+class CocoaInitializer::Private
+{
+ public:
+ NSAutoreleasePool* pool;
+};
+
+CocoaInitializer::CocoaInitializer()
+{
+ c = new CocoaInitializer::Private();
+ c->pool = [[NSAutoreleasePool alloc] init];
+ NSApplicationLoad();
+}
+
+CocoaInitializer::~CocoaInitializer()
+{
+ [c->pool release];
+ delete c;
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/InstallController.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/InstallController.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,23 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "InstallController.h"
+
+InstallController::~InstallController()
+{
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/InstallController.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/InstallController.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,30 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef INSTALLCONTROLLER_H
+#define INSTALLCONTROLLER_H
+
+class InstallController
+{
+ public:
+ virtual ~InstallController();
+
+ virtual void showInstallController() = 0;
+};
+
+#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/M3InstallController.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/M3InstallController.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,53 @@
+/*****************************************************************
+ M3InstallController.m
+
+ Created by Martin Pilkington on 02/06/2007.
+
+ Copyright (c) 2006-2009 M Cubed Software
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+ *****************************************************************/
+
+#import
+#import
+
+//#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
+#if __LP64__ || NS_BUILD_32_LIKE_64
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+#else
+typedef int NSInteger;
+typedef unsigned int NSUInteger;
+#endif
+//#endif
+
+
+@interface M3InstallController :
+NSObject
+{
+ NSAlert *alert;
+}
+
+- (void)displayInstaller;
+- (void)installApp;
+@end
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/M3InstallController.m
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/M3InstallController.m Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,119 @@
+/*****************************************************************
+ M3InstallController.m
+
+ Created by Martin Pilkington on 02/06/2007.
+
+ Copyright (c) 2006-2009 M Cubed Software
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+ *****************************************************************/
+
+#import "M3InstallController.h"
+#import "NSWorkspace_RBAdditions.h"
+
+#import
+
+@implementation M3InstallController
+
+- (id) init {
+ if ((self = [super init])) {
+ NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
+ NSString *title = [NSString stringWithFormat:NSLocalizedString(@"%@ is currently running from a disk image", @"AppName is currently running from a disk image"), appName];
+ NSString *body = [NSString stringWithFormat:NSLocalizedString(@"Would you like to install %@ in your applications folder before quitting?", @"Would you like to install App Name in your applications folder before quitting?"), appName];
+ alert = [[NSAlert alertWithMessageText:title
+ defaultButton:NSLocalizedString(@"Install", @"Install")
+ alternateButton:NSLocalizedString(@"Don't Install", @"Don't Install")
+ otherButton:nil
+ informativeTextWithFormat:body] retain];
+ //[alert setShowsSuppressionButton:YES];
+ }
+ return self;
+}
+
+- (void)displayInstaller {
+ NSString *imageFilePath = [[[NSWorkspace sharedWorkspace] propertiesForPath:[[NSBundle mainBundle] bundlePath]] objectForKey:NSWorkspace_RBimagefilepath];
+ if (imageFilePath && ![imageFilePath isEqualToString:[NSString stringWithFormat:@"/Users/.%@/%@.sparseimage", NSUserName(), NSUserName()]] && ![[NSUserDefaults standardUserDefaults] boolForKey:@"M3DontAskInstallAgain"]) {
+ NSInteger returnValue = [alert runModal];
+ if (returnValue == NSAlertDefaultReturn) {
+ [self installApp];
+ }
+ if ([[alert suppressionButton] state] == NSOnState) {
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"M3DontAskInstallAgain"];
+ }
+ }
+}
+
+- (void)installApp {
+ NSString *appsPath = [[NSString stringWithString:@"/Applications"] stringByAppendingPathComponent:[[[NSBundle mainBundle] bundlePath] lastPathComponent]];
+ NSString *userAppsPath = [[[NSString stringWithString:@"~/Applications"] stringByAppendingPathComponent:[[[NSBundle mainBundle] bundlePath] lastPathComponent]] stringByExpandingTildeInPath];
+ NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
+
+ //Delete the app that is installed
+ if ([[NSFileManager defaultManager] fileExistsAtPath:appsPath]) {
+ if ([NSFileManager instancesRespondToSelector:@selector(removeItemAtPath:error:)])
+ [[NSFileManager defaultManager] removeItemAtPath:appsPath error:nil];
+ else
+ //casting hides the deprecation warning
+ [(id)[NSFileManager defaultManager] removeFileAtPath:appsPath handler:nil];
+ }
+ //Delete the app that is installed
+ BOOL success = NO;
+ if ([NSFileManager instancesRespondToSelector:@selector(copyItemAtPath:toPath:error:)])
+ success = [[NSFileManager defaultManager] copyItemAtPath:[[NSBundle mainBundle] bundlePath]
+ toPath:appsPath
+ error:nil];
+ else
+ success = [(id)[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath]
+ toPath:appsPath
+ handler:nil];
+ if (success) {
+ NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"App Name installed successfully"), appName],
+ [NSString stringWithFormat:NSLocalizedString(@"%@ was installed in /Applications", @"App Name was installed in /Applications"), appName],
+ NSLocalizedString(@"Quit", @"Quit"), nil, nil);
+ } else {
+ if ([[NSFileManager defaultManager] fileExistsAtPath:userAppsPath]) {
+ if ([NSFileManager instancesRespondToSelector:@selector(removeItemAtPath:error:)])
+ [[NSFileManager defaultManager] removeItemAtPath:userAppsPath error:nil];
+ else
+ [(id)[NSFileManager defaultManager] removeFileAtPath:userAppsPath handler:nil];
+ }
+ if ([NSFileManager instancesRespondToSelector:@selector(copyItemAtPath:toPath:error:)])
+ success = [[NSFileManager defaultManager] copyItemAtPath:[[NSBundle mainBundle] bundlePath]
+ toPath:userAppsPath
+ error:nil];
+ else
+ success = [(id)[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath]
+ toPath:userAppsPath
+ handler:nil];
+ if (success) {
+ NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"AppName installed successfully"), appName],
+ [NSString stringWithFormat:NSLocalizedString(@"%@ was installed in %@", @"App Name was installed in %@"), appName, [[NSString stringWithString:@"~/Applications"] stringByExpandingTildeInPath]],
+ NSLocalizedString(@"Quit", @"Quit"), nil, nil);
+ } else {
+ NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"Could not install %@", @"Could not install App Name"), appName],
+ NSLocalizedString(@"An error occurred when installing", @"An error occurred when installing"), NSLocalizedString(@"Quit", @"Quit"), nil, nil);
+ }
+ }
+}
+
+@end
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/M3Panel.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/M3Panel.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,37 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef M3PANEL_H
+#define M3PANEL_H
+
+#include "InstallController.h"
+
+class M3Panel : public InstallController
+{
+ public:
+ M3Panel(void);
+ ~M3Panel();
+
+ void showInstallController();
+
+ private:
+ class Private;
+ Private* m;
+};
+
+#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/M3Panel.mm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/M3Panel.mm Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,47 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "M3Panel.h"
+#include "M3InstallController.h"
+
+#include
+
+class M3Panel::Private
+{
+ public:
+ M3InstallController *install;
+};
+
+M3Panel::M3Panel(void)
+{
+ m = new M3Panel::Private();
+
+ m->install = [[M3InstallController alloc] init];
+ [m->install retain];
+}
+
+M3Panel::~M3Panel()
+{
+ [m->install release];
+ delete m;
+}
+
+void M3Panel::showInstallController()
+{
+ [m->install displayInstaller];
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/NSWorkspace_RBAdditions.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/NSWorkspace_RBAdditions.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,38 @@
+//
+// NSWorkspace_RBAdditions.h
+// PathProps
+//
+// Created by Rainer Brockerhoff on 10/04/2007.
+// Copyright 2007 Rainer Brockerhoff. All rights reserved.
+//
+
+#import
+
+extern NSString* NSWorkspace_RBfstypename;
+extern NSString* NSWorkspace_RBmntonname;
+extern NSString* NSWorkspace_RBmntfromname;
+extern NSString* NSWorkspace_RBdeviceinfo;
+extern NSString* NSWorkspace_RBimagefilepath;
+extern NSString* NSWorkspace_RBconnectiontype;
+extern NSString* NSWorkspace_RBpartitionscheme;
+extern NSString* NSWorkspace_RBserverURL;
+
+@interface NSWorkspace (NSWorkspace_RBAdditions)
+
+// This method will return nil if the input path is invalid. Otherwise, the returned NSDictionary may contain
+// the following keys:
+//- NSWorkspace_RBfstypename: will always be present.Shows the filesystem type (usually "hfs"), from statfs.
+//- NSWorkspace_RBmntonname: will always be present. Shows the volume mount point.
+//- NSWorkspace_RBmntfromname: will always be present. Shows the BSD device path for local volumes; info for
+// remote volumes depends on the filesystem type.
+//- NSWorkspace_RBconnectiontype: should always be present for local volumes. Shows the connection type ("SATA", "USB", etc.).
+//- NSWorkspace_RBpartitionscheme: should always be present for local volumes. Shows the partition scheme.
+//- NSWorkspace_RBdeviceinfo: should always be present for local volumes. Shows some information about the
+// physical device; varies widely.
+//- NSWorkspace_RBimagefilepath: should be present for disk images only. Shows the path of the disk image file.
+//- NSWorkspace_RBserverURL: should be present for remote volumes only. Shows the server URL.
+
+- (NSDictionary*)propertiesForPath:
+(NSString*)path;
+
+@end
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/NSWorkspace_RBAdditions.m
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/NSWorkspace_RBAdditions.m Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,263 @@
+//
+// NSWorkspace_RBAdditions.m
+// PathProps
+//
+// Created by Rainer Brockerhoff on 10/04/2007.
+// Copyright 2007 Rainer Brockerhoff. All rights reserved.
+//
+
+#import "NSWorkspace_RBAdditions.h"
+#include
+#include
+#include
+
+NSString* NSWorkspace_RBfstypename = @"NSWorkspace_RBfstypename";
+NSString* NSWorkspace_RBmntonname = @"NSWorkspace_RBmntonname";
+NSString* NSWorkspace_RBmntfromname = @"NSWorkspace_RBmntfromname";
+NSString* NSWorkspace_RBdeviceinfo = @"NSWorkspace_RBdeviceinfo";
+NSString* NSWorkspace_RBimagefilepath = @"NSWorkspace_RBimagefilepath";
+NSString* NSWorkspace_RBconnectiontype = @"NSWorkspace_RBconnectiontype";
+NSString* NSWorkspace_RBpartitionscheme = @"NSWorkspace_RBpartitionscheme";
+NSString* NSWorkspace_RBserverURL = @"NSWorkspace_RBserverURL";
+
+// This static funtion concatenates two strings, but first checks several possibilities...
+// like one or the other nil, or one containing the other already.
+
+static NSString* AddPart(NSString* first,NSString* second) {
+ if (!second) {
+ return first;
+ }
+ second = [second stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ if (first) {
+ if ([first rangeOfString:second options:NSCaseInsensitiveSearch].location==NSNotFound) {
+ if ([second rangeOfString:first options:NSCaseInsensitiveSearch].location==NSNotFound) {
+ return [NSString stringWithFormat:@"%@; %@",first,second];
+ }
+ return second;
+ }
+ return first;
+ }
+ return second;
+}
+
+// This static functions recurses "upwards" over the IO registry. Returns strings that are concatenated
+// and ultimately end up under the NSWorkspace_RBdeviceinfo key.
+// This isn't too robust in that it assumes that objects returned by the objectForKey methods are
+// either strings or dictionaries. A "standard" implementations would use either only CoreFoundation and
+// IOKit calls for this, or do more robust type checking on the returned objects.
+//
+// Also notice that this works as determined experimentally in 10.4.9, there's no official docs I could find.
+// YMMV, and it may stop working in any new version of Mac OS X.
+
+static NSString* CheckParents(io_object_t thing,NSString* part,NSMutableDictionary* dict) {
+ NSString* result = part;
+ io_iterator_t parentsIterator = 0;
+ kern_return_t kernResult = IORegistryEntryGetParentIterator(thing,kIOServicePlane,&parentsIterator);
+ if ((kernResult==KERN_SUCCESS)&&parentsIterator) {
+ io_object_t nextParent = 0;
+ while ((nextParent = IOIteratorNext(parentsIterator))) {
+ NSDictionary* props = nil;
+ NSString* image = nil;
+ NSString* partition = nil;
+ NSString* connection = nil;
+ kernResult = IORegistryEntryCreateCFProperties(nextParent,(CFMutableDictionaryRef*)&props,kCFAllocatorDefault,0);
+ if (IOObjectConformsTo(nextParent,"IOApplePartitionScheme")) {
+ partition = [props objectForKey:@"Content Mask"];
+ } else if (IOObjectConformsTo(nextParent,"IOMedia")) {
+ partition = [props objectForKey:@"Content"];
+ } else if (IOObjectConformsTo(nextParent,"IODiskImageBlockStorageDeviceOutKernel")) {
+ NSData* data = nil;
+ if ((data = [[props objectForKey:@"Protocol Characteristics"] objectForKey:@"Virtual Interface Location Path"])) {
+ image = [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding] autorelease];
+ }
+ } else if (IOObjectConformsTo(nextParent,"IOHDIXHDDriveInKernel")) {
+ image = [props objectForKey:@"KDIURLPath"];
+ }
+ NSDictionary* subdict;
+ if ((subdict = [props objectForKey:@"Protocol Characteristics"])) {
+ connection = [subdict objectForKey:@"Physical Interconnect"];
+ } else {
+ connection = [props objectForKey:@"Physical Interconnect"];
+ }
+ if (connection) {
+ [dict setObject:AddPart([dict objectForKey:NSWorkspace_RBconnectiontype],connection) forKey:NSWorkspace_RBconnectiontype];
+ }
+ if (partition) {
+ [dict setObject:partition forKey:NSWorkspace_RBpartitionscheme];
+ }
+ if (image) {
+ [dict setObject:image forKey:NSWorkspace_RBimagefilepath];
+ }
+ NSString* value;
+ if ((subdict = [props objectForKey:@"Device Characteristics"])) {
+ if ((value = [subdict objectForKey:@"Product Name"])) {
+ result = AddPart(result,value);
+ }
+ if ((value = [subdict objectForKey:@"Product Revision Level"])) {
+ result = AddPart(result,value);
+ }
+ if ((value = [subdict objectForKey:@"Vendor Name"])) {
+ result = AddPart(result,value);
+ }
+ }
+ if ((value = [props objectForKey:@"USB Serial Number"])) {
+ result = AddPart(result,value);
+ }
+ if ((value = [props objectForKey:@"USB Vendor Name"])) {
+ result = AddPart(result,value);
+ }
+ NSString* cls = [(NSString*)IOObjectCopyClass(nextParent) autorelease];
+ if (![cls isEqualToString:@"IOPCIDevice"]) {
+
+// Uncomment the following line to have the device tree dumped to the console.
+// NSLog(@"=================================> %@:%@\n",cls,props);
+
+ result = CheckParents(nextParent,result,dict);
+ }
+ IOObjectRelease(nextParent);
+ }
+ }
+ if (parentsIterator) {
+ IOObjectRelease(parentsIterator);
+ }
+ return result;
+}
+
+// This formats the (partially undocumented) AFPXMountInfo info into a string.
+
+/*
+static NSString* FormatAFPURL(AFPXVolMountInfoPtr mountInfo,NSString** devdesc) {
+ UInt8* work = ((UInt8*)mountInfo)+mountInfo->serverNameOffset;
+ if (devdesc) {
+ *devdesc = [[[NSString alloc] initWithBytes:&work[1] length:work[0] encoding:NSUTF8StringEncoding] autorelease];
+ }
+ work = ((UInt8*)mountInfo)+mountInfo->volNameOffset;
+ NSString* volname = [[[NSString alloc] initWithBytes:&work[1] length:work[0] encoding:NSUTF8StringEncoding] autorelease];
+ work = ((UInt8*)mountInfo)+mountInfo->alternateAddressOffset;
+ AFPAlternateAddress* afpa = (AFPAlternateAddress*)work;
+ AFPTagData* afpta = (AFPTagData*)(&afpa->fAddressList);
+ NSString* ip = nil;
+ NSString* dns = nil;
+ int i = afpa->fAddressCount;
+ while ((i-->0)) {
+ switch (afpta->fType) {
+ case kAFPTagTypeIP:
+ if (!ip) {
+ ip = [[[NSString alloc] initWithBytes:&afpta->fData[0] length:afpta->fLength-2 encoding:NSUTF8StringEncoding] autorelease];
+ }
+ break;
+ case kAFPTagTypeIPPort:
+ ip = [NSString stringWithFormat:@"%u.%u.%u.%u:%u",afpta->fData[0],afpta->fData[1],afpta->fData[2],afpta->fData[3],OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[4])];
+ break;
+ case kAFPTagTypeDNS:
+ dns = [[[NSString alloc] initWithBytes:&afpta->fData[0] length:afpta->fLength-2 encoding:NSUTF8StringEncoding] autorelease];
+ break;
+ case 0x07:
+ ip = [NSString stringWithFormat:@"[%x:%x:%x:%x:%x:%x:%x:%x]",OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[0]),
+ OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[2]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[4]),
+ OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[6]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[8]),
+ OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[10]),OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[12]),
+ OSSwapBigToHostInt16(*(UInt16*)&afpta->fData[14])];
+ break;
+ }
+ afpta = (AFPTagData*)((char*)afpta+afpta->fLength);
+ }
+ return [NSString stringWithFormat:@"afp://%@/%@",dns?:(ip?:@""),volname];
+}
+*/
+
+@implementation NSWorkspace (NSWorkspace_RBAdditions)
+
+// Returns a NSDictionary with properties for the path. See details in the .h file.
+// This assumes that the length of path is less than PATH_MAX (currently 1024 characters).
+
+- (NSDictionary*)propertiesForPath:(NSString*)path {
+ const char* ccpath = (const char*)[path fileSystemRepresentation];
+ NSMutableDictionary* result = nil;
+ struct statfs fs;
+ if (!statfs(ccpath,&fs)) {
+ NSString* from = [NSString stringWithUTF8String:fs.f_mntfromname];
+ result = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ [NSString stringWithUTF8String:fs.f_fstypename],NSWorkspace_RBfstypename,
+ [NSString stringWithUTF8String:fs.f_mntonname],NSWorkspace_RBmntonname,
+ nil];
+ if (strncmp(fs.f_mntfromname,"/dev/",5)==0) {
+// For a local volume,get the IO registry tree and search it for further info.
+ mach_port_t masterPort = 0;
+ io_iterator_t mediaIterator = 0;
+ kern_return_t kernResult = IOMasterPort(bootstrap_port,&masterPort);
+ if (kernResult==KERN_SUCCESS) {
+ CFMutableDictionaryRef classesToMatch = IOBSDNameMatching(masterPort,0,&fs.f_mntfromname[5]);
+ if (classesToMatch) {
+ kernResult = IOServiceGetMatchingServices(masterPort,classesToMatch,&mediaIterator);
+ if ((kernResult==KERN_SUCCESS)&&mediaIterator) {
+ io_object_t firstMedia = 0;
+ while ((firstMedia = IOIteratorNext(mediaIterator))) {
+ NSString* stuff = CheckParents(firstMedia,nil,result);
+ if (stuff) {
+ [result setObject:stuff forKey:NSWorkspace_RBdeviceinfo];
+ }
+ IOObjectRelease(firstMedia);
+ }
+ }
+ }
+ }
+ if (mediaIterator) {
+ IOObjectRelease(mediaIterator);
+ }
+ if (masterPort) {
+ mach_port_deallocate(mach_task_self(),masterPort);
+ }
+ }
+ //Don't need this for disk images, gets around warnings for some deprecated functions
+
+ /* else {
+// For a network volume, get the volume reference number and use to get the server URL.
+ FSRef ref;
+ if (FSPathMakeRef((const UInt8*)ccpath,&ref,NULL)==noErr) {
+ FSCatalogInfo info;
+ if (FSGetCatalogInfo(&ref,kFSCatInfoVolume,&info,NULL,NULL,NULL)==noErr) {
+ ParamBlockRec pb;
+ UInt16 vmisize = 0;
+ VolumeMountInfoHeaderPtr mountInfo = NULL;
+ pb.ioParam.ioCompletion = NULL;
+ pb.ioParam.ioNamePtr = NULL;
+ pb.ioParam.ioVRefNum = info.volume;
+ pb.ioParam.ioBuffer = (Ptr)&vmisize;
+ pb.ioParam.ioReqCount = sizeof(vmisize);
+ if ((PBGetVolMountInfoSize(&pb)==noErr)&&vmisize) {
+ mountInfo = (VolumeMountInfoHeaderPtr)malloc(vmisize);
+ if (mountInfo) {
+ pb.ioParam.ioBuffer = (Ptr)mountInfo;
+ pb.ioParam.ioReqCount = vmisize;
+ if (PBGetVolMountInfo(&pb)==noErr) {
+ NSString* url = nil;
+ switch (mountInfo->media) {
+ case AppleShareMediaType:
+ url = FormatAFPURL((AFPXVolMountInfoPtr)mountInfo,&from);
+ break;
+ case 'http':
+ url = from;
+ break;
+ case 'crbm':
+ case 'nfs_':
+ case 'cifs':
+ url = [NSString stringWithUTF8String:(char*)mountInfo+sizeof(VolumeMountInfoHeader)+sizeof(OSType)];
+ break;
+ }
+ if (url) {
+ [result setObject:url forKey:NSWorkspace_RBserverURL];
+ }
+ }
+ }
+ free(mountInfo);
+ }
+ }
+ }
+ }*/
+ [result setObject:from forKey:NSWorkspace_RBmntfromname];
+ }
+ return result;
+}
+
+@end
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/SparkleAutoUpdater.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/SparkleAutoUpdater.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 Remko Troncon
+ */
+
+#ifndef SPARKLEAUTOUPDATER_H
+#define SPARKLEAUTOUPDATER_H
+
+#include
+
+#include "AutoUpdater.h"
+
+class SparkleAutoUpdater : public AutoUpdater
+{
+ public:
+ SparkleAutoUpdater();
+ ~SparkleAutoUpdater();
+
+ void checkForUpdates();
+ void checkForUpdatesNow();
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/SparkleAutoUpdater.mm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/SparkleAutoUpdater.mm Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,54 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+// see original example here http://el-tramo.be/blog/mixing-cocoa-and-qt
+
+#include "SparkleAutoUpdater.h"
+
+#include
+#include
+
+class SparkleAutoUpdater::Private
+{
+ public:
+ SUUpdater* updater;
+};
+
+SparkleAutoUpdater::SparkleAutoUpdater()
+{
+ d = new SparkleAutoUpdater::Private();
+
+ d->updater = [SUUpdater sharedUpdater];
+ [d->updater retain];
+}
+
+SparkleAutoUpdater::~SparkleAutoUpdater()
+{
+ [d->updater release];
+ delete d;
+}
+
+void SparkleAutoUpdater::checkForUpdates()
+{
+ [d->updater checkForUpdatesInBackground];
+}
+
+void SparkleAutoUpdater::checkForUpdatesNow()
+{
+ [d->updater checkForUpdates:NULL];
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/Xfire Game SDK.url
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/Xfire Game SDK.url Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,5 @@
+[{000214A0-0000-0000-C000-000000000046}]
+Prop3=19,2
+[InternetShortcut]
+URL=http://www.xfire.com/cms/xf_game_sdk
+IDList=
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/xfire.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/xfire.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,85 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include
+#include
+#include
+
+#include "xfire.h"
+#include "xfiregameclient.h"
+
+#ifdef USE_XFIRE
+// use_xfire: stores if xfire is loaded and functions should do something at all
+bool use_xfire = false;
+char *keys[XFIRE_KEY_COUNT];
+char *values[XFIRE_KEY_COUNT];
+
+// xfire_init(): used to initialize all variables and set their default values
+void xfire_init(void)
+{
+ if(use_xfire)
+ return;
+ use_xfire = XfireIsLoaded() == 1;
+
+ if(!use_xfire)
+ return;
+
+ for(int i = 0; i < XFIRE_KEY_COUNT; i++)
+ {
+ keys[i] = new char[256];
+ values[i] = new char[256];
+ strcpy(keys[i], "");
+ strcpy(values[i], "");
+ }
+
+ strcpy(keys[XFIRE_NICKNAME], "Nickname");
+ strcpy(keys[XFIRE_ROOM], "Room");
+ strcpy(keys[XFIRE_SERVER], "Server");
+ strcpy(keys[XFIRE_STATUS], "Status");
+ xfire_update();
+}
+
+// xfire_free(): used to free up ressources used etc.
+void xfire_free(void)
+{
+ if(!use_xfire)
+ return;
+
+ for(int i = 0; i < XFIRE_KEY_COUNT; i++)
+ {
+ delete [] keys[i];
+ delete [] values[i];
+ }
+}
+
+// xfire_setvalue(): set a specific value
+void xfire_setvalue(const XFIRE_KEYS status, const char *value)
+{
+ if(!use_xfire || strlen(value) > 255)
+ return;
+ strcpy(values[status], value);
+}
+
+// xfire_update(): submits current values to the xfire app
+void xfire_update(void)
+{
+ if(!use_xfire)
+ return;
+ XfireSetCustomGameDataA(XFIRE_KEY_COUNT, (const char**)keys, (const char**)values);
+}
+#endif // USE_XFIRE
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/xfire.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/xfire.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,39 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef XFIRE_H
+#define XFIRE_H
+
+
+#ifdef USE_XFIRE
+enum XFIRE_KEYS
+{
+ XFIRE_STATUS = 0,
+ XFIRE_NICKNAME,
+ XFIRE_SERVER,
+ XFIRE_ROOM,
+ XFIRE_KEY_COUNT,
+};
+
+void xfire_init(void);
+void xfire_free(void);
+void xfire_setvalue(const XFIRE_KEYS status, const char *value);
+void xfire_update(void);
+#endif
+
+#endif // XFIRE_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/xfire_license.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/xfire_license.txt Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,103 @@
+Terms and Conditions
+AGREEMENT BETWEEN USER AND XFIRE INC.
+This is a legal agreement between you and Xfire Inc. ("Xfire") with respect to your access and use of the Xfire Service, which may also include Xfire software, content and related documentation and information (collectively, the "Service"). You must accept without modification all of the terms, conditions, and notices contained in these Terms of Use in order to access and/or use the Service (collectively, the "Terms of Use" or "Agreement"). If you do not accept these Terms of Use in their entirety, you may not access or use the Service.
+
+Portions of the Service may be governed by posted guidelines, rules, or other terms and conditions. All such guidelines, rules, terms and conditions are hereby incorporated by reference into these Terms of Use. In the event of a conflict between such other guidelines, rules, terms and conditions and these Terms of Use, the Terms of Use shall control, except that the Xfire Service Privacy Policy, referenced below, supersedes any conflicting language in these Terms of Use and/or any other guidelines, rules, terms and conditions published in connection with the Service with respect to the subject matter covered by such privacy policy.
+
+MODIFICATION OF THESE TERMS OF USE; UPDATES
+Xfire may change the Terms of Use at any time and such changes shall be effective immediately. You are responsible for regularly reviewing the Terms of Use. The most recent version of the Terms of Use can be found at http://www.xfire.com/xf/terms.php. Your continued use of the Service affirms your agreement to the Terms of Use and any changes.
+
+Xfire is not obligated to provide updates or improvements to the Service. However, if Xfire, in its sole discretion, updates or improves the Service, these Terms of Use shall apply to such updates and improvements unless expressly noted otherwise.
+
+CLIENT SOFTWARE USE LIMITATION
+YOU MAY ONLY USE XFIRE CLIENT SOFTWARE OR AUTHORIZED THIRD-PARTY SOFTWARE TO ACCESS AND/OR USE THE SERVICE. You may not use any software or services in conjunction with the Xfire software or authorized third-party software which modifies or reroutes, or attempts to modify or reroute, the Service. You may not authorize any third party to access and/or use the Service on your behalf using any automated process such as a BOT, a spider or periodic caching of information stored by the Xfire Service on your behalf without a separate written agreement with Xfire. You may not use any software or hardware that reduces the number of users directly accessing or using the Service (sometimes called 'multiplexing' or 'pooling' software or hardware).
+
+You may not modify, copy, distribute, transmit, display, perform, reproduce, publish, license, create derivative works from, transfer, or sell any information, software, products or services that are part of the Service except as expressly provided in these Terms of Use.
+
+NO UNLAWFUL OR PROHIBITED USE; RESPONSIBILITY FOR YOUR ACCOUNT
+As a condition of your use of the Service, you will not use the Service for any purpose that is unlawful or prohibited by these Terms of Use. You may not use the Service in any manner that could damage, disable, overburden, or impair the Service or interfere with any other party's use and enjoyment of it. You may not attempt to gain unauthorized access to any account, computer systems or networks associated with the Service or to otherwise interfere with or disrupt any accounts, computer systems or networks connected to the Service. You may not obtain or attempt to obtain any materials or information through any means not intentionally made available or provided for through the Service. You may not use access to the Service to obtain information necessary for you to design, develop or update unauthorized software that you use or provide to others to use to access the Service. You may not charge others to use the Service either directly or indirectly without the express written agreement of Xfire.
+Subject to these Terms of Use, you may use the Service within your commercial organization, but you may not use the Service to advertise or offer to buy or sell any goods or services, or to run a business or commercial entity without the express written agreement of Xfire.
+You agree to use the Service only to send, receive, and transfer appropriate messages and material. By way of example, and not as a limitation, you agree that when using the Service, you will not:
+
+
+ Use the Service in connection with surveys, contests, pyramid schemes, chain letters, junk email, spamming or any duplicative, bulk or unsolicited messages (commercial or otherwise).
+
+ Defame, abuse, harass, stalk, threaten or otherwise violate the legal rights (such as rights of privacy and publicity) of others.
+
+ Create a false identity for the purpose of misleading others.
+
+ Publish, transfer, distribute or disseminate any inappropriate, profane, defamatory, obscene, indecent or unlawful topic, name, material or information.
+
+ Transfer, stream, or otherwise make available, files or other material that contain images, photographs, software or other material protected by intellectual property laws, including, by way of example, and not as limitation, copyright or trademark laws (or by rights of privacy or publicity) unless you own or control the rights thereto or have received all necessary consents to do the same.
+
+ Use any material or information, including images or photographs, which is made available through the Service in any manner that infringes any copyright, trademark, patent, trade secret, or other proprietary right of any party.
+
+ Transfer, stream or otherwise make available, files or other material that contain viruses, Trojan horses, worms, time bombs, cancelbots, corrupted files, or any other similar software or programs that may damage the operation of another's computer or property of another.
+
+ Download any file or other material transferred by another user of the Service that you know, or reasonably should know, cannot be legally distributed in such manner.
+
+ Use, download or otherwise copy, or provide (whether or not for a fee) to a person or entity any directory of users of the Service or other user or usage information or any portion thereof.
+
+ Falsify or delete any author attributions, legal or other proper notices or proprietary designations or labels of the origin or source of software or other material contained in a file that is transferred.
+
+ Violate any code of conduct or other guidelines which may be applicable to the Service.
+
+ Use any portion of the Service to harvest or otherwise collect information about others, including e-mail addresses.
+
+Xfire reserves the right at all times to monitor communications on the Service and disclose any information Xfire deems necessary to (i) ensure your compliance with this Agreement; (ii) satisfy any applicable law, regulation or legal process; or (iii) protect the rights, property, and interests of Xfire, its employees or the public. Xfire also reserves the right to edit, refuse to transfer or to remove any information or materials, in whole or in part, in Xfire's sole discretion.
+
+Always use caution when giving out any personally identifiable information about yourself or your children in the Service. Xfire does not control or endorse the content, messages or information exchanged by means of the Service and, therefore, Xfire specifically disclaims any liability with regard to the Service and any actions resulting from your participation in the Service.
+
+You are responsible for all activities that occur in your Service account. You agree to notify Xfire immediately of any unauthorized use of your account or breach in security known to you related to the Service.
+
+
+PRIVACY
+See the Xfire Service Privacy Statement at http://www.xfire.com/xf/privacy.php for disclosures relating to the collection and use of your information.
+
+
+INTERACTION WITH THIRD PARTY SITES AND SERVICES
+The Service may allow you to interact with third-party Web sites and Web services ("Link(s)"). The Links are not under the control of Xfire and Xfire is not responsible for the contents of any Links, including without limitation any link contained in a Link, or any changes or updates to a Link. Xfire is not responsible for any form of transmission received from any Link, nor is Xfire responsible if the Link is not working appropriately. Xfire is providing these Links to you only as a convenience, and the inclusion of any Link does not imply endorsement by Xfire of the Link or any association with its operators. You are responsible for viewing and abiding by any privacy statements and terms of use posted in connection with the Links.
+
+You are solely responsible for any dealings with third parties (including advertisers) who support the Service, including the delivery of and payment for goods and services.
+
+TERMS OF USE FOR SERVICE-ENABLED PROPERTIES
+For the terms and conditions governing your use of any Xfire or authorized third party Web site or service that enables you to use the Service other than the Service itself ("Service-Enabled Properties"), please refer to the applicable Terms of Use for such Service-Enabled Properties.
+
+SOFTWARE AND CONTENT AVAILABLE ON THE SERVICE
+All Xfire content and software (if any) that is made available to view and/or download in connection with the Service ("Software") is owned by and is the copyrighted work of Xfire and/or its suppliers and is licensed, not sold. Your use of the Software is governed by the terms of the license agreement, if any, which accompanies or is included with the Software ("License Agreement"). You may not install or use any Software that is accompanied by or includes a License Agreement unless you first agree to the License Agreement terms. For any Software not accompanied by a license agreement, Xfire hereby grants to you, the user, a non-exclusive, revocable, personal, non-transferable license to use the Software solely in connection with the Service in accordance with these Terms of Use. You may not lend, lease, rent or sublicense the Software or any aspect of the Service.
+
+You will not disassemble, decompile, or reverse engineer the Software. All Software is protected by copyright laws and international treaty provisions. Any unauthorized reproduction or redistribution of the Software is expressly prohibited by law, and may result in severe civil and criminal penalties. WITHOUT LIMITING THE FOREGOING, COPYING OR REPRODUCTION OF THE SOFTWARE TO ANY OTHER SERVER OR LOCATION FOR FURTHER REPRODUCTION OR REDISTRIBUTION IS EXPRESSLY PROHIBITED. THE SOFTWARE IS WARRANTED, IF AT ALL, ONLY ACCORDING TO THE TERMS OF THE LICENSE AGREEMENT. You acknowledge that the Software, and any accompanying documentation and/or technical information, is subject to applicable export control laws and regulations of the U.S.A. You agree not to export or re-export the Software, directly or indirectly, to any countries that are subject to U.S.A. export restrictions.
+
+Your license to use the Software with the Service terminates when you terminate your use of the Service. Your license to use the Software with the Service may also terminate if Xfire, in its sole discretion, modifies the Service to no longer support such Software.
+
+NO WARRANTIES; LIABILITY DISCLAIMER; EXCLUSIVE REMEDY
+XFIRE PROVIDES THE SERVICE AND THE SOFTWARE "AS IS," "WITH ALL FAULTS" AND "AS AVAILABLE," AND THE ENTIRE RISK AS TO SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH YOU. XFIRE, ITS AFFILIATES, ITS RESELLERS, DISTRIBUTORS, SERVICE PROVIDERS AND/OR SUPPLIERS (COLLECTIVELY, THE "XFIRE PARTIES") MAKE NO WARRANTIES. THE XFIRE PARTIES DISCLAIM ANY AND ALL WARRANTIES, EXPRESS, STATUTORY AND IMPLIED, INCLUDING WITHOUT LIMITATION (1) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, WORKMANLIKE EFFORT, ACCURACY, TITLE, QUIET ENJOYMENT, NO ENCUMBRANCES, NO LIENS AND NON-INFRINGEMENT, (2) WARRANTIES ARISING THROUGH COURSE OF DEALING OR USAGE OF TRADE, AND (3) WARRANTIES THAT ACCESS TO OR USE OF THE SERVICE WILL BE UNINTERRUPTED OR ERROR-FREE. THERE ARE NO WARRANTIES THAT EXTEND BEYOND THE FACE OF THIS AGREEMENT. XFIRE MAY CHANGE THE SERVICE OR THE FEATURES IN ANY WAY, AND AT ANY TIME AND FOR ANY REASON.
+
+IN NO EVENT SHALL ANY OF THE XFIRE PARTIES BE LIABLE FOR ANY DIRECT, INDIRECT, CONSEQUENTIAL, SPECIAL, INCIDENTAL, OR PUNITIVE DAMAGES ARISING OUT OF, BASED ON, OR RESULTING FROM THIS AGREEMENT OR YOUR USE OF THE SERVICE, INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF USE, DATA OR PROFITS, WITH THE DELAY OR INABILITY TO USE THE SERVICE, THE PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, OR FOR ANY INFORMATION, SOFTWARE, PRODUCTS, OR SERVICES OBTAINED THROUGH THE SERVICE, OR OTHERWISE ARISING OUT OF THE USE OF THE SERVICE, WHETHER BASED ON CONTRACT, TORT, NEGLIGENCE, STRICT LIABILITY OR OTHERWISE, EVEN IF XFIREOR ANY OF ITS SUPPLIERS HAS BEEN ADVISED OF THE POSSIBILITY OF DAMAGES. BECAUSE SOME STATES/JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO YOU.
+
+IF YOU ARE DISSATISFIED WITH ANY PORTION OF THE SERVICE, OR WITH ANY OF THESE TERMS OF USE, YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USING THE SERVICE.
+
+INDEMNITY
+You agree to indemnify and hold Xfire, its officers, and employees, harmless from any claim or demand, including reasonable attorneys' fees, made by any third party due to or arising out of your use of the Services, the violation of these Terms of Use by you, or the infringement by you, or other user of the Services using your computer or identity, of any intellectual property or other right of any person or entity.
+
+CUSTOMER SUPPORT
+Xfire may, but is not required to, provide you with customer support ("Support"). Unless you have entered into a separate written support agreement with Xfire with respect to the Service, Xfire may terminate any Support it provides at any time in its sole discretion.
+
+Authorized third-party software that uses the Service is not supported by Xfire and you should contact the provider of such software for support, if any.
+
+TERMINATION/ACCESS RESTRICTION
+Unless you, or a third party on your behalf, have entered into a separate written agreement with Xfire that modifies these Terms of Use, Xfire reserves the right, in its sole discretion, to terminate your access to and use of the Service or any portion thereof at any time, without notice. Also, unless you or a third party on your behalf have entered into a separate agreement with Xfire, Xfire may terminate or suspend your access to the Service for inactivity, which is defined as failing to log onto the Service for an extended period of time, as determined by Xfire.
+ELECTRONIC NOTICES
+You consent to Xfire providing you any information regarding the Service in electronic form. Xfire may provide such information to you via e-mail at the e-mail address you specified when you registered for the Service, by instant message to your account, or by access to a Xfire web site. As long as you access and use the Service, you will have the necessary software and hardware to receive such notices. If you do not consent to receive any notices electronically, you must discontinue your use of the Service.
+
+GENERAL
+If you reside in the United States, claims for enforcement, breach or violation of duties or rights under these Terms of Use are governed by the laws of the State of California, without reference to conflict of laws principles. All other claims, including, without limitation, claims under or for violation of state consumer protection laws, unfair competition laws, and in tort, are governed by the laws of your state of residence in the United States. If you reside outside of the United States, these Terms of Use are governed by the laws of the State of California, without reference to conflict of laws principles. You hereby irrevocably consent to the exclusive jurisdiction and venue of courts in San Mateo County, California, U.S.A. in all disputes arising out of or relating to the use of the Service.
+
+YOU AND XFIRE AGREE THAT ANY CAUSE OF ACTION ARISING OUT OF OR RELATED TO THE SERVICE MUST COMMENCE WITHIN ONE (1) YEAR AFTER THE CAUSE OF ACTION ACCRUES. OTHERWISE, SUCH CAUSE OF ACTION IS PERMANENTLY BARRED.
+
+Xfire may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in any Web pages that are part of the Service. Except as expressly provided in these Terms of Use, the furnishing of such Web pages to you does not give you any license to these patents, trademarks, copyrights, or other intellectual property. Any rights not expressly granted herein are reserved.
+
+June 2004
+
+
+
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/xfiregameclient.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/xfiregameclient.cpp Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,121 @@
+/* This file is NOT open source. See "license.txt" to read the full license provided with the Xfire SDK. */
+
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+
+#include "xfiregameclient.h"
+
+static HMODULE g_toucan_dll = NULL;
+static void HelperInit();
+static HMODULE HelperGetToucanDLL();
+
+typedef int (*XfireSetCustomGameDataAFunction)(int , const char **, const char **);
+typedef int (*XfireSetCustomGameDataWFunction)(int , const wchar_t **, const wchar_t **);
+typedef int (*XfireSetCustomGameDataUTF8Function)(int , const char **, const char **);
+
+static XfireSetCustomGameDataAFunction ptr_XfireSetCustomGameDataA = NULL;
+static XfireSetCustomGameDataWFunction ptr_XfireSetCustomGameDataW = NULL;
+static XfireSetCustomGameDataUTF8Function ptr_XfireSetCustomGameDataUTF8 = NULL;
+
+/* make sure we are going to call the ANSI version */
+#ifdef MODULEENTRY32
+#undef MODULEENTRY32
+#endif
+
+#ifdef Module32First
+#undef Module32First
+#endif
+
+#ifdef Module32Next
+#undef Module32Next
+#endif
+
+
+int XfireIsLoaded()
+{
+ HelperInit();
+ if (ptr_XfireSetCustomGameDataA &&
+ ptr_XfireSetCustomGameDataW &&
+ ptr_XfireSetCustomGameDataUTF8)
+ return 1;
+ return 0;
+}
+
+int XfireSetCustomGameDataA(int num_keys, const char **keys, const char **values)
+{
+ HelperInit();
+ if (ptr_XfireSetCustomGameDataA)
+ return ptr_XfireSetCustomGameDataA(num_keys, keys, values);
+ return 1;
+}
+
+int XfireSetCustomGameDataW(int num_keys, const wchar_t **keys, const wchar_t **values)
+{
+ HelperInit();
+ if (ptr_XfireSetCustomGameDataW)
+ return ptr_XfireSetCustomGameDataW(num_keys, keys, values);
+ return 1;
+}
+
+int XfireSetCustomGameDataUTF8(int num_keys, const char **keys, const char **values)
+{
+ HelperInit();
+ if (ptr_XfireSetCustomGameDataUTF8)
+ return ptr_XfireSetCustomGameDataUTF8(num_keys, keys, values);
+ return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+static void HelperInit()
+{
+ if (!ptr_XfireSetCustomGameDataA ||
+ !ptr_XfireSetCustomGameDataW ||
+ !ptr_XfireSetCustomGameDataUTF8)
+ {
+ HMODULE toucan_dll = HelperGetToucanDLL();
+ if (toucan_dll)
+ {
+ ptr_XfireSetCustomGameDataA = (XfireSetCustomGameDataAFunction)::GetProcAddress(toucan_dll, "ToucanSendGameClientDataA_V1");
+ ptr_XfireSetCustomGameDataW = (XfireSetCustomGameDataWFunction)::GetProcAddress(toucan_dll, "ToucanSendGameClientDataW_V1");
+ ptr_XfireSetCustomGameDataUTF8 = (XfireSetCustomGameDataUTF8Function)::GetProcAddress(toucan_dll, "ToucanSendGameClientDataUTF8_V1");
+ }
+ }
+}
+
+
+static HMODULE HelperGetToucanDLL()
+{
+ if (g_toucan_dll)
+ return g_toucan_dll;
+
+ /*
+ ** We need to enumerate the DLLs loaded to find toucan dll.
+ ** This is done because the toucan dll changes with each update.
+ ** The toucan dll has the following format. "xfire_toucan_{BUILD_NUMBER}.dll"
+ ** We simply try to find a dll w/ the prefix "xfire_toucan"
+ */
+ HANDLE snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
+ if (snapshot_handle != INVALID_HANDLE_VALUE)
+ {
+ MODULEENTRY32 module_entry;
+ module_entry.dwSize = sizeof(MODULEENTRY32);
+
+ BOOL result = Module32First(snapshot_handle, &module_entry);
+ char module_name[] = "xfire_toucan";
+ DWORD module_name_len = sizeof(module_name)-1;
+ while (result)
+ {
+ if (CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, module_entry.szModule, module_name_len, module_name, module_name_len) == CSTR_EQUAL)
+ {
+ g_toucan_dll = module_entry.hModule;
+ break;
+ }
+ result = Module32Next(snapshot_handle, &module_entry);
+ }
+
+ CloseHandle(snapshot_handle);
+ }
+
+ return g_toucan_dll;
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/util/platform/xfiregameclient.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/platform/xfiregameclient.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,49 @@
+/* This file is NOT open source. See "license.txt" to read the full license provided with the Xfire SDK. */
+
+#ifndef __XFIREGAMECLIENT_H__
+#define __XFIREGAMECLIENT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** XfireIsLoaded()
+**
+** returns 1 if application can talk to Xfire, 0 otherwise
+*/
+int XfireIsLoaded();
+
+/*
+** XfireSetCustomGameDataA()
+**
+** ANSI version to tell xfire of custom game data
+*/
+int XfireSetCustomGameDataA(int num_keys, const char **keys, const char **values);
+
+/*
+** XfireSetCustomGameDataA()
+**
+** UNICODE version to tell xfire of custom game data
+*/
+int XfireSetCustomGameDataW(int num_keys, const wchar_t **keys, const wchar_t **values);
+
+/*
+** XfireSetCustomGameDataUTF8()
+**
+** UTF8 version to tell xfire of custom game data
+*/
+int XfireSetCustomGameDataUTF8(int num_keys, const char **keys, const char **values);
+
+#ifdef UNICODE
+#define XfireSetCustomGameData XfireSetCustomGameDataW
+#else
+#define XfireSetCustomGameData XfireSetCustomGameDataA
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XFIREGAMECLIENT_H__ */
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/xfire.cpp
--- a/QTfrontend/xfire.cpp Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include
-#include
-#include
-
-#include "xfire.h"
-#include "../misc/xfire/xfiregameclient.h"
-
-#ifdef USE_XFIRE
-// use_xfire: stores if xfire is loaded and functions should do something at all
-bool use_xfire = false;
-char *keys[XFIRE_KEY_COUNT];
-char *values[XFIRE_KEY_COUNT];
-
-// xfire_init(): used to initialize all variables and set their default values
-void xfire_init(void)
-{
- if(use_xfire)
- return;
- use_xfire = XfireIsLoaded() == 1;
-
- if(!use_xfire)
- return;
-
- for(int i = 0; i < XFIRE_KEY_COUNT; i++)
- {
- keys[i] = new char[256];
- values[i] = new char[256];
- strcpy(keys[i], "");
- strcpy(values[i], "");
- }
-
- strcpy(keys[XFIRE_NICKNAME], "Nickname");
- strcpy(keys[XFIRE_ROOM], "Room");
- strcpy(keys[XFIRE_SERVER], "Server");
- strcpy(keys[XFIRE_STATUS], "Status");
- xfire_update();
-}
-
-// xfire_free(): used to free up ressources used etc.
-void xfire_free(void)
-{
- if(!use_xfire)
- return;
-
- for(int i = 0; i < XFIRE_KEY_COUNT; i++)
- {
- delete [] keys[i];
- delete [] values[i];
- }
-}
-
-// xfire_setvalue(): set a specific value
-void xfire_setvalue(const XFIRE_KEYS status, const char *value)
-{
- if(!use_xfire || strlen(value) > 255)
- return;
- strcpy(values[status], value);
-}
-
-// xfire_update(): submits current values to the xfire app
-void xfire_update(void)
-{
- if(!use_xfire)
- return;
- XfireSetCustomGameDataA(XFIRE_KEY_COUNT, (const char**)keys, (const char**)values);
-}
-#endif // USE_XFIRE
diff -r d5d5e1698554 -r 1dedcc37bfe8 QTfrontend/xfire.h
--- a/QTfrontend/xfire.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef XFIRE_H
-#define XFIRE_H
-
-
-#ifdef USE_XFIRE
-enum XFIRE_KEYS
-{
- XFIRE_STATUS = 0,
- XFIRE_NICKNAME,
- XFIRE_SERVER,
- XFIRE_ROOM,
- XFIRE_KEY_COUNT,
-};
-
-void xfire_init(void);
-void xfire_free(void);
-void xfire_setvalue(const XFIRE_KEYS status, const char *value);
-void xfire_update(void);
-#endif
-
-#endif // XFIRE_H
diff -r d5d5e1698554 -r 1dedcc37bfe8 README
--- a/README Sun Nov 18 01:06:01 2012 +0400
+++ b/README Fri Feb 22 05:05:32 2013 +0100
@@ -5,3 +5,10 @@
Source:
Copyright 2004-2011 Andrey Korotaev
Portions copyright 2006-2008 Igor Ulyanov aka Displacer
+
+Instructions:
+depending on your system, consult our wiki at:
+- http://code.google.com/p/hedgewars/wiki/BuildingOnLinux
+- http://code.google.com/p/hedgewars/wiki/BuildingOnWindows
+- http://code.google.com/p/hedgewars/wiki/BuildingOnMac
+
diff -r d5d5e1698554 -r 1dedcc37bfe8 README_WINDOWS
--- a/README_WINDOWS Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-For instructions, please visit: http://code.google.com/p/hedgewars/wiki/BuildingOnWindows
diff -r d5d5e1698554 -r 1dedcc37bfe8 bin/CMakeLists.txt
--- a/bin/CMakeLists.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/bin/CMakeLists.txt Fri Feb 22 05:05:32 2013 +0100
@@ -1,9 +1,9 @@
if(WIN32 AND NOT UNIX)
- file(GLOB DLLs *.dll)
- file(GLOB ICOs *.ico)
-
- install(FILES
- ${DLLs}
- ${ICOs}
- DESTINATION bin)
+ file(GLOB DLLs *.dll)
+ file(GLOB ICOs *.ico)
+
+ install(FILES
+ ${DLLs}
+ ${ICOs}
+ DESTINATION ${target_library_install_dir})
endif(WIN32 AND NOT UNIX)
diff -r d5d5e1698554 -r 1dedcc37bfe8 cmake_modules/FindFFMPEG.cmake
--- a/cmake_modules/FindFFMPEG.cmake Sun Nov 18 01:06:01 2012 +0400
+++ b/cmake_modules/FindFFMPEG.cmake Fri Feb 22 05:05:32 2013 +0100
@@ -16,17 +16,23 @@
# BSD license.
#
+set(FFMPEG_FOUND FALSE)
+
if (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
# in cache already
set(FFMPEG_FOUND TRUE)
else (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
+ # silence output option
+ if (FFMPEG_FIND_QUIETLY)
+ set(VERBOSITY "QUIET")
+ endif ()
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
- pkg_check_modules(_FFMPEG_AVCODEC libavcodec)
- pkg_check_modules(_FFMPEG_AVFORMAT libavformat)
- pkg_check_modules(_FFMPEG_AVUTIL libavutil)
+ pkg_check_modules(_FFMPEG_AVCODEC libavcodec ${VERBOSITY})
+ pkg_check_modules(_FFMPEG_AVFORMAT libavformat ${VERBOSITY})
+ pkg_check_modules(_FFMPEG_AVUTIL libavutil ${VERBOSITY})
endif (PKG_CONFIG_FOUND)
find_path(FFMPEG_AVCODEC_INCLUDE_DIR
@@ -74,10 +80,6 @@
${FFMPEG_LIBAVFORMAT}
${FFMPEG_LIBAVUTIL}
)
- if (APPLE)
- set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} "bz2" "-framework CoreVideo" "-framework VideoDecodeAcceleration")
- endif(APPLE)
-
endif (FFMPEG_FOUND)
if (FFMPEG_FOUND)
diff -r d5d5e1698554 -r 1dedcc37bfe8 cmake_modules/FindFreepascal.cmake
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake_modules/FindFreepascal.cmake Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,37 @@
+# Load Freepascal
+if (FPC)
+ set(FPC_EXECUTABLE ${FPC})
+else()
+ find_program(FPC_EXECUTABLE
+ NAMES fpc
+ PATHS /opt/local/bin /usr/local/bin /usr/bin)
+endif()
+
+# Check Freepascal version
+if (FPC_EXECUTABLE)
+ exec_program(${FPC_EXECUTABLE} ARGS "-v" OUTPUT_VARIABLE FPC_VERSION_FULL)
+
+ string(REGEX MATCH "[0-9]+\\.[0-9]+" FPC_VERSION_LONG "${FPC_VERSION_FULL}")
+ string(REGEX REPLACE "([0-9]+\\.[0-9]+)" "\\1" FPC_VERSION "${FPC_VERSION_LONG}")
+ message(STATUS "Found Freepascal: ${FPC_EXECUTABLE} (version ${FPC_VERSION})")
+else()
+ message(FATAL_ERROR "Could NOT find Freepascal")
+endif()
+
+# Check for noexecstack flag support
+message(STATUS "Checking whether linker needs explicit noexecstack")
+set(NOEXECSTACK_FLAGS "-k-z" "-knoexecstack")
+file(WRITE ${EXECUTABLE_OUTPUT_PATH}/checkstack.pas "begin end.")
+
+execute_process(COMMAND ${FPC_EXECUTABLE} ${NOEXECSTACK_FLAGS} checkstack.pas
+ WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
+ RESULT_VARIABLE TEST_NOEXECSTACK
+ OUTPUT_QUIET ERROR_QUIET)
+
+if (TEST_NOEXECSTACK)
+ set(NOEXECSTACK_FLAGS "")
+ message(STATUS "Checking whether linker needs explicit noexecstack -- no")
+else(TEST_NOEXECSTACK)
+ message(STATUS "Checking whether linker needs explicit noexecstack -- yes")
+endif(TEST_NOEXECSTACK)
+
diff -r d5d5e1698554 -r 1dedcc37bfe8 cmake_modules/FindLibraryWithDebug.cmake
--- a/cmake_modules/FindLibraryWithDebug.cmake Sun Nov 18 01:06:01 2012 +0400
+++ b/cmake_modules/FindLibraryWithDebug.cmake Fri Feb 22 05:05:32 2013 +0100
@@ -100,7 +100,7 @@
SET(${var_name} ${${var_name}_DEBUG})
ENDIF(${var_name}_RELEASE)
-
+
ENDIF(${var_name}_RELEASE AND ${var_name}_DEBUG)
MARK_AS_ADVANCED(${var_name}_RELEASE)
diff -r d5d5e1698554 -r 1dedcc37bfe8 cmake_modules/FindLua.cmake
--- a/cmake_modules/FindLua.cmake Sun Nov 18 01:06:01 2012 +0400
+++ b/cmake_modules/FindLua.cmake Fri Feb 22 05:05:32 2013 +0100
@@ -6,6 +6,7 @@
# the bundled one when nothing is found
set(LUA_FOUND false)
+set(LUA_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/misc/liblua)
if (ANDROID)
SET(LUA_DEFAULT "liblua5.1.so")
@@ -19,10 +20,11 @@
#locate the system's lua library
FIND_LIBRARY(LUA_DEFAULT NAMES lua51 lua5.1 lua-5.1 lua PATHS /lib /usr/lib /usr/local/lib /usr/pkg/lib)
IF(${LUA_DEFAULT} MATCHES "LUA_DEFAULT-NOTFOUND")
- set(LUA_DEFAULT lua)
+ set(LUA_DEFAULT lua)
ELSE()
set(LUA_FOUND true)
message(STATUS "LibLua 5.1 found at ${LUA_DEFAULT}")
+ find_path(LUA_INCLUDE_DIR lua.h)
#remove the path (fpc doesn't like it - why?)
GET_FILENAME_COMPONENT(LUA_DEFAULT ${LUA_DEFAULT} NAME)
ENDIF()
@@ -32,3 +34,4 @@
SET(LUA_LIBRARY ${LUA_DEFAULT} CACHE STRING "Lua library to link to; file name without path only!")
+
diff -r d5d5e1698554 -r 1dedcc37bfe8 cmake_modules/FindSDL_Extras.cmake
--- a/cmake_modules/FindSDL_Extras.cmake Sun Nov 18 01:06:01 2012 +0400
+++ b/cmake_modules/FindSDL_Extras.cmake Fri Feb 22 05:05:32 2013 +0100
@@ -13,7 +13,7 @@
if(sdlmixer_version GREATER "10209")
message(STATUS "Mix_Init() is present")
- set(pascal_flags "-dSDL_MIXER_NEWER" ${pascal_flags})
+ list(APPEND pascal_flags "-dSDL_MIXER_NEWER")
endif()
endif()
@@ -30,7 +30,7 @@
if(sdlimage_version GREATER "010207")
message(STATUS "IMG_Init() is present")
- set(pascal_flags "-dSDL_IMAGE_NEWER" ${pascal_flags})
+ list(APPEND pascal_flags "-dSDL_IMAGE_NEWER")
endif()
endif()
diff -r d5d5e1698554 -r 1dedcc37bfe8 doc/protocol.txt
--- a/doc/protocol.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/doc/protocol.txt Fri Feb 22 05:05:32 2013 +0100
@@ -1,34 +1,35 @@
- '?' ping?
- '!' pong!
- 'l','L' срабатывание команд -left, +left
- 'r','R' -right, +right
- 'u','U' -up, +up
- 'd','D' -down, +down
- 'z', 'Z' -precise, +precise
- 'N' срабатывание команды /nextturn
- 'S' /switch
- 's' + <текст> /say
- '+' пустой пакет для постоянности лага
- '1'..'5' /timer 1..5
- chr(128+№) /slot №
- 'w' /setweap
- 'p' /put
- 'j' /ljump
- 'J' /hjump
- 'E' + <текст> сообщение об ошибке
- ',' /skip
- 'K' вывести сообщение из KB
- 'Q' выход через команду /quit
- 'q' выход по причине окончания игры
- 't' + № /taunt №
- 'F' + команда team вылетела в сетевой игре
+ '?' ping?
+ '!' pong!
+ 'l','L' срабатывание команд -left, +left
+ 'r','R' -right, +right
+ 'u','U' -up, +up
+ 'd','D' -down, +down
+ 'z', 'Z' -precise, +precise
+ 'N' срабатывание команды /nextturn
+ 'S' /switch
+ 's' + <текст> /say
+ '+' пустой пакет для постоянности лага
+ '1'..'5' /timer 1..5
+ chr(128+№) /slot №
+ 'w' /setweap
+ 'p' /put
+ 'j' /ljump
+ 'J' /hjump
+ 'E' + <текст> сообщение об ошибке
+ ',' /skip
+ 't' + № /taunt №
фронтенд клиенту:
- 'e' + <команда> выполнить "/<команда>"
- 'T' + {L,N,D} тип игры (локальная, сетевая, просмотр демо)
- 'W' + <текст> сообщение о нефатальной ошибке
+ 'e' + <команда> выполнить "/<команда>"
+ 'T' + {L,N,D} тип игры (локальная, сетевая, просмотр демо)
+ 'W' + <текст> сообщение о нефатальной ошибке
+ 'F' + команда team вылетела в сетевой игре
+ 'o' stop syncing, game over!
Клиент фронтенду:
- 'C' запрос текущего конфига игры
- 'q' выход по причине окончания демки
- 'i' статистика
+ 'C' запрос текущего конфига игры
+ 'q' выход по причине окончания демки
+ 'i' статистика
+ 'K' вывести сообщение из KB
+ 'Q' выход через команду /quit
+ 'q' выход по причине окончания игры
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/Actions.hs
--- a/gameServer/Actions.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/Actions.hs Fri Feb 22 05:05:32 2013 +0100
@@ -1,10 +1,10 @@
-{-# LANGUAGE CPP, OverloadedStrings #-}
+{-# LANGUAGE CPP, OverloadedStrings, ScopedTypeVariables #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Actions where
import Control.Concurrent
import qualified Data.Set as Set
-import qualified Data.Sequence as Seq
+import qualified Data.Map as Map
import qualified Data.List as L
import qualified Control.Exception as Exception
import System.Log.Logger
@@ -52,10 +52,11 @@
| KickRoomClient ClientIndex
| BanClient NominalDiffTime B.ByteString ClientIndex
| BanIP B.ByteString NominalDiffTime B.ByteString
+ | BanNick B.ByteString NominalDiffTime B.ByteString
| BanList
| Unban B.ByteString
- | ChangeMaster
- | RemoveClientTeams ClientIndex
+ | ChangeMaster (Maybe ClientIndex)
+ | RemoveClientTeams
| ModifyClient (ClientInfo -> ClientInfo)
| ModifyClient2 ClientIndex (ClientInfo -> ClientInfo)
| ModifyRoomClients (ClientInfo -> ClientInfo)
@@ -73,8 +74,12 @@
| RestartServer
| AddNick2Bans B.ByteString B.ByteString UTCTime
| AddIP2Bans B.ByteString B.ByteString UTCTime
- | CheckBanned
+ | CheckBanned Bool
| SaveReplay
+ | Stats
+ | CheckRecord
+ | CheckFailed B.ByteString
+ | CheckSuccess [B.ByteString]
type CmdHandler = [B.ByteString] -> Reader (ClientIndex, IRnC) [Action]
@@ -83,7 +88,10 @@
rnf (AnswerClients chans msg) = chans `deepseq` msg `deepseq` ()
rnf a = a `seq` ()
+#if __GLASGOW_HASKELL__ < 706
instance NFData B.ByteString
+#endif
+
instance NFData (Chan a)
@@ -142,22 +150,22 @@
chan <- client's sendChan
clNick <- client's nick
- loggedIn <- client's logonPassed
+ loggedIn <- client's isVisible
when (ri /= lobbyId) $ do
processAction $ MoveToLobby ("quit: " `B.append` msg)
return ()
- clientsChans <- liftM (Prelude.map sendChan . Prelude.filter logonPassed) $! allClientsS
+ clientsChans <- liftM (Prelude.map sendChan . Prelude.filter isVisible) $! allClientsS
io $
infoM "Clients" (show ci ++ " quits: " ++ B.unpack msg)
when loggedIn $ processAction $ AnswerClients clientsChans ["LOBBY:LEFT", clNick, msg]
- mapM processAction
+ mapM_ processAction
[
AnswerClients [chan] ["BYE", msg]
- , ModifyClient (\c -> c{nick = "", logonPassed = False}) -- this will effectively hide client from others while he isn't deleted from list
+ , ModifyClient (\c -> c{nick = "", isVisible = False}) -- this will effectively hide client from others while he isn't deleted from list
]
s <- get
@@ -212,7 +220,7 @@
rnc <- gets roomsClients
io $ do
- modifyClient rnc (\cl -> cl{teamsInGame = 0, isReady = False, isMaster = False, isInGame = False}) ci
+ modifyClient rnc (\cl -> cl{teamsInGame = 0, isReady = False, isMaster = False, isInGame = False, clientClan = Nothing}) ci
modifyRoom rnc (\r -> r{playersIn = playersIn r + 1}) ri
moveClientToRoom rnc ri ci
@@ -234,11 +242,11 @@
if master then
if playersNum > 1 then
- mapM_ processAction [ChangeMaster, NoticeMessage AdminLeft, RemoveClientTeams ci, AnswerClients chans ["LEFT", clNick, msg]]
+ mapM_ processAction [ChangeMaster Nothing, NoticeMessage AdminLeft, RemoveClientTeams, AnswerClients chans ["LEFT", clNick, msg]]
else
processAction RemoveRoom
else
- mapM_ processAction [RemoveClientTeams ci, AnswerClients chans ["LEFT", clNick, msg]]
+ mapM_ processAction [RemoveClientTeams, AnswerClients chans ["LEFT", clNick, msg]]
-- when not removing room
ready <- client's isReady
@@ -250,26 +258,27 @@
moveClientToLobby rnc ci
-processAction ChangeMaster = do
+processAction (ChangeMaster delegateId)= do
(Just ci) <- gets clientIndex
proto <- client's clientProto
ri <- clientRoomA
rnc <- gets roomsClients
- newMasterId <- liftM (last . filter (/= ci)) . io $ roomClientsIndicesM rnc ri
+ newMasterId <- liftM (\ids -> fromMaybe (last . filter (/= ci) $ ids) delegateId) . io $ roomClientsIndicesM rnc ri
newMaster <- io $ client'sM rnc id newMasterId
oldRoomName <- io $ room'sM rnc name ri
oldMaster <- client's nick
+ kicked <- client's isKickedFromServer
thisRoomChans <- liftM (map sendChan) $ roomClientsS ri
- let newRoomName = if proto < 42 then nick newMaster else oldRoomName
+ let newRoomName = if (proto < 42) || kicked then nick newMaster else oldRoomName
mapM_ processAction [
ModifyRoom (\r -> r{masterID = newMasterId
, name = newRoomName
, isRestrictedJoins = False
, isRestrictedTeams = False
+ , isRegisteredOnly = False
, readyPlayers = if isReady newMaster then readyPlayers r else readyPlayers r + 1})
, ModifyClient2 newMasterId (\c -> c{isMaster = True, isReady = True})
, AnswerClients [sendChan newMaster] ["ROOM_CONTROL_ACCESS", "1"]
- , AnswerClients thisRoomChans ["WARNING", "New room admin is " `B.append` nick newMaster]
, AnswerClients thisRoomChans ["CLIENT_FLAGS", "-h", oldMaster]
, AnswerClients thisRoomChans ["CLIENT_FLAGS", "+hr", nick newMaster]
]
@@ -361,6 +370,7 @@
)
: UnreadyRoomClients
: SendUpdateOnThisRoom
+ : AnswerClients thisRoomChans ["ROUND_FINISHED"]
: answerRemovedTeams
@@ -371,7 +381,7 @@
ModifyRoom (\r -> r{
gameInfo = liftM (\g -> g{
teamsInGameNumber = teamsInGameNumber g - 1
- , roundMsgs = roundMsgs g Seq.|> rmTeamMsg
+ , roundMsgs = rmTeamMsg : roundMsgs g
}) $ gameInfo r
})
]
@@ -379,16 +389,20 @@
rnc <- gets roomsClients
ri <- clientRoomA
gi <- io $ room'sM rnc gameInfo ri
- when (isJust gi && 0 == teamsInGameNumber (fromJust gi)) $
+ when (0 == teamsInGameNumber (fromJust gi)) $
processAction FinishGame
where
rmTeamMsg = toEngineMsg $ 'F' `B.cons` teamName
processAction (RemoveTeam teamName) = do
+ (Just ci) <- gets clientIndex
rnc <- gets roomsClients
ri <- clientRoomA
- inGame <- io $ room'sM rnc (isJust . gameInfo) ri
+ inGame <- io $ do
+ r <- room'sM rnc (isJust . gameInfo) ri
+ c <- client'sM rnc isInGame ci
+ return $ r && c
chans <- othersChans
mapM_ processAction $
ModifyRoom (\r -> r{
@@ -400,14 +414,14 @@
: [SendTeamRemovalMessage teamName | inGame]
-processAction (RemoveClientTeams clId) = do
+processAction RemoveClientTeams = do
+ (Just ci) <- gets clientIndex
rnc <- gets roomsClients
removeTeamActions <- io $ do
- clNick <- client'sM rnc nick clId
- rId <- clientRoomM rnc clId
+ rId <- clientRoomM rnc ci
roomTeams <- room'sM rnc teams rId
- return . Prelude.map (RemoveTeam . teamname) . Prelude.filter (\t -> teamowner t == clNick) $ roomTeams
+ return . Prelude.map (RemoveTeam . teamname) . Prelude.filter (\t -> teamownerId t == ci) $ roomTeams
mapM_ processAction removeTeamActions
@@ -418,21 +432,20 @@
n <- client's nick
h <- client's host
p <- client's clientProto
+ checker <- client's isChecker
uid <- client's clUID
- haveSameNick <- liftM (not . null . tail . filter (\c -> caseInsensitiveCompare (nick c) n)) allClientsS
- if haveSameNick then
+ -- allow multiple checker logins
+ haveSameNick <- liftM (not . null . tail . filter (\c -> (not $ isChecker c) && caseInsensitiveCompare (nick c) n)) allClientsS
+ if (not checker) && haveSameNick then
if p < 38 then
- mapM_ processAction [ByeClient "Nickname is already in use", removeNick]
+ processAction $ ByeClient $ loc "Nickname is already in use"
else
- mapM_ processAction [NoticeMessage NickAlreadyInUse, removeNick]
+ processAction $ NoticeMessage NickAlreadyInUse
else
do
db <- gets (dbQueries . serverInfo)
io $ writeChan db $ CheckAccount ci (hashUnique uid) n h
return ()
- where
- removeNick = ModifyClient (\c -> c{nick = ""})
-
processAction ClearAccountsCache = do
dbq <- gets (dbQueries . serverInfo)
@@ -440,25 +453,39 @@
return ()
-processAction (ProcessAccountInfo info) =
+processAction (ProcessAccountInfo info) = do
case info of
HasAccount passwd isAdmin -> do
- chan <- client's sendChan
- mapM_ processAction [AnswerClients [chan] ["ASKPASSWORD"], ModifyClient (\c -> c{webPassword = passwd, isAdministrator = isAdmin})]
- Guest ->
- processAction JoinLobby
+ b <- isBanned
+ c <- client's isChecker
+ when (not b) $ (if c then checkerLogin else playerLogin) passwd isAdmin
+ Guest -> do
+ b <- isBanned
+ when (not b) $
+ processAction JoinLobby
Admin -> do
mapM_ processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby]
chan <- client's sendChan
processAction $ AnswerClients [chan] ["ADMIN_ACCESS"]
-
+ where
+ isBanned = do
+ processAction $ CheckBanned False
+ liftM B.null $ client's nick
+ checkerLogin _ False = processAction $ ByeClient $ loc "No checker rights"
+ checkerLogin p True = do
+ wp <- client's webPassword
+ processAction $
+ if wp == p then ModifyClient $ \c -> c{logonPassed = True} else ByeClient $ loc "Authentication failed"
+ playerLogin p a = do
+ chan <- client's sendChan
+ mapM_ processAction [AnswerClients [chan] ["ASKPASSWORD"], ModifyClient (\c -> c{webPassword = p, isAdministrator = a})]
processAction JoinLobby = do
chan <- client's sendChan
clientNick <- client's nick
isAuthenticated <- liftM (not . B.null) $ client's webPassword
isAdmin <- client's isAdministrator
- loggedInClients <- liftM (Prelude.filter logonPassed) $! allClientsS
+ loggedInClients <- liftM (Prelude.filter isVisible) $! allClientsS
let (lobbyNicks, clientsChans) = unzip . L.map (nick &&& sendChan) $ loggedInClients
let authenticatedNicks = L.map nick . L.filter (not . B.null . webPassword) $ loggedInClients
let adminsNicks = L.map nick . L.filter isAdministrator $ loggedInClients
@@ -469,7 +496,7 @@
, [AnswerClients [chan] ("CLIENT_FLAGS" : "+u" : authenticatedNicks) | not $ null authenticatedNicks]
, [AnswerClients [chan] ("CLIENT_FLAGS" : "+a" : adminsNicks) | not $ null adminsNicks]
, [AnswerClients (chan : clientsChans) ["CLIENT_FLAGS", B.concat["+" , clFlags], clientNick] | not $ B.null clFlags]
- , [ModifyClient (\cl -> cl{logonPassed = True})]
+ , [ModifyClient (\cl -> cl{logonPassed = True, isVisible = True})]
, [SendServerMessage]
]
@@ -479,8 +506,9 @@
clHost <- client's host
currentTime <- io getCurrentTime
mapM_ processAction [
- AddIP2Bans clHost "60 seconds cooldown after kick" (addUTCTime 60 currentTime),
- ByeClient "Kicked"
+ AddIP2Bans clHost (loc "60 seconds cooldown after kick") (addUTCTime 60 currentTime)
+ , ModifyClient (\c -> c{isKickedFromServer = True})
+ , ByeClient "Kicked"
]
@@ -494,28 +522,47 @@
, KickClient banId
]
+
processAction (BanIP ip seconds reason) = do
currentTime <- io getCurrentTime
let msg = B.concat ["Ban for ", B.pack . show $ seconds, " (", reason, ")"]
processAction $
AddIP2Bans ip msg (addUTCTime seconds currentTime)
+
+processAction (BanNick n seconds reason) = do
+ currentTime <- io getCurrentTime
+ let msg =
+ if seconds > 60 * 60 * 24 * 365 then
+ B.concat ["Permanent ban (", reason, ")"]
+ else
+ B.concat ["Ban for ", B.pack . show $ seconds, " (", reason, ")"]
+ processAction $
+ AddNick2Bans n msg (addUTCTime seconds currentTime)
+
+
processAction BanList = do
+ time <- io $ getCurrentTime
ch <- client's sendChan
- b <- gets (B.pack . unlines . map show . bans . serverInfo)
+ b <- gets (B.intercalate "\n" . concatMap (ban2Str time) . bans . serverInfo)
processAction $
AnswerClients [ch] ["BANLIST", b]
+ where
+ ban2Str time (BanByIP b r t) = ["I", b, r, B.pack . show $ t `diffUTCTime` time]
+ ban2Str time (BanByNick b r t) = ["N", b, r, B.pack . show $ t `diffUTCTime` time]
+
processAction (Unban entry) = do
- processAction $ ModifyServerInfo (\s -> s{bans = filter f $ bans s})
+ processAction $ ModifyServerInfo (\s -> s{bans = filter (not . f) $ bans s})
where
f (BanByIP bip _ _) = bip == entry
f (BanByNick bn _ _) = bn == entry
+
processAction (KickRoomClient kickId) = do
modify (\s -> s{clientIndex = Just kickId})
ch <- client's sendChan
- mapM_ processAction [AnswerClients [ch] ["KICKED"], MoveToLobby "kicked"]
+ mapM_ processAction [AnswerClients [ch] ["KICKED"], MoveToLobby $ loc "kicked"]
processAction (AddClient cl) = do
@@ -533,7 +580,7 @@
mapM_ processAction
[
AnswerClients [sendChan cl] ["CONNECTED", "Hedgewars server http://www.hedgewars.org/", serverVersion]
- , CheckBanned
+ , CheckBanned True
, AddIP2Bans (host cl) "Reconnected too fast" (addUTCTime 10 $ connectTime cl)
]
@@ -547,21 +594,22 @@
when (not $ ci `Set.member` rc)
$ processAction $ ModifyServerInfo (\s -> s{bans = BanByIP ip reason expiring : bans s})
-processAction CheckBanned = do
+processAction (CheckBanned byIP) = do
clTime <- client's connectTime
clNick <- client's nick
clHost <- client's host
si <- gets serverInfo
let validBans = filter (checkNotExpired clTime) $ bans si
- let ban = L.find (checkBan clHost clNick) $ validBans
+ let ban = L.find (checkBan byIP clHost clNick) $ validBans
mapM_ processAction $
ModifyServerInfo (\s -> s{bans = validBans})
: [ByeClient (getBanReason $ fromJust ban) | isJust ban]
where
checkNotExpired testTime (BanByIP _ _ time) = testTime `diffUTCTime` time <= 0
checkNotExpired testTime (BanByNick _ _ time) = testTime `diffUTCTime` time <= 0
- checkBan ip _ (BanByIP bip _ _) = bip `B.isPrefixOf` ip
- checkBan _ n (BanByNick bn _ _) = bn == n
+ checkBan True ip _ (BanByIP bip _ _) = bip `B.isPrefixOf` ip
+ checkBan False _ n (BanByNick bn _ _) = caseInsensitiveCompare bn n
+ checkBan _ _ _ _ = False
getBanReason (BanByIP _ msg _) = msg
getBanReason (BanByNick _ msg _) = msg
@@ -577,7 +625,7 @@
pq <- io $ client'sM rnc pingsQueue ci
when (pq > 0) $ do
withStateT (\as -> as{clientIndex = Just ci}) $
- processAction (ByeClient "Ping timeout")
+ processAction (ByeClient $ loc "Ping timeout")
-- when (pq > 1) $
-- processAction $ DeleteClient ci -- smth went wrong with client io threads, issue DeleteClient here
@@ -604,13 +652,53 @@
return ()
processAction $ ModifyServerInfo (\s -> s{shutdownPending = True})
+processAction Stats = do
+ cls <- allClientsS
+ rms <- allRoomsS
+ let clientsMap = Map.fromListWith (+) . map (\c -> (clientProto c, 1 :: Int)) $ cls
+ let roomsMap = Map.fromListWith (+) . map (\c -> (roomProto c, 1 :: Int)) . filter ((/=) 0 . roomProto) $ rms
+ let keys = Map.keysSet clientsMap `Set.union` Map.keysSet roomsMap
+ let versionsStats = B.concat . ((:) ""])
+ . concatMap (\p -> [
+ "", protoNumber2ver p
+ , " | ", showB $ Map.findWithDefault 0 p clientsMap
+ , " | ", showB $ Map.findWithDefault 0 p roomsMap
+ , " |
"])
+ . Set.toList $ keys
+ processAction $ Warning versionsStats
+
+
#if defined(OFFICIAL_SERVER)
processAction SaveReplay = do
ri <- clientRoomA
rnc <- gets roomsClients
+
io $ do
r <- room'sM rnc id ri
saveReplay r
+
+
+processAction CheckRecord = do
+ p <- client's clientProto
+ c <- client's sendChan
+ (cinfo, l) <- io $ loadReplay (fromIntegral p)
+ when (not . null $ l) $
+ mapM_ processAction [
+ AnswerClients [c] ("REPLAY" : l)
+ , ModifyClient $ \c -> c{checkInfo = cinfo}
+ ]
+
+processAction (CheckFailed msg) = do
+ Just (CheckInfo fileName _) <- client's checkInfo
+ io $ moveFailedRecord fileName
+
+processAction (CheckSuccess info) = do
+ Just (CheckInfo fileName _) <- client's checkInfo
+ io $ moveCheckedRecord fileName
+
#else
processAction SaveReplay = return ()
+processAction CheckRecord = return ()
+processAction (CheckFailed _) = return ()
+processAction (CheckSuccess _) = return ()
#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/CMakeLists.txt
--- a/gameServer/CMakeLists.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/CMakeLists.txt Fri Feb 22 05:05:32 2013 +0100
@@ -42,4 +42,4 @@
add_custom_target(hedgewars-server ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}")
-install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_dir})
+install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_binary_install_dir})
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/ClientIO.hs
--- a/gameServer/ClientIO.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/ClientIO.hs Fri Feb 22 05:05:32 2013 +0100
@@ -30,25 +30,26 @@
return (B.splitWith (== '\n') packet : packets)
listenLoop :: Socket -> Chan CoreMessage -> ClientIndex -> IO ()
-listenLoop sock chan ci = recieveWithBufferLoop B.empty
+listenLoop sock chan ci = receiveWithBufferLoop B.empty
where
- recieveWithBufferLoop recvBuf = do
+ receiveWithBufferLoop recvBuf = do
recvBS <- recv sock 4096
unless (B.null recvBS) $ do
let (packets, newrecvBuf) = bs2Packets $ B.append recvBuf recvBS
forM_ packets sendPacket
- recieveWithBufferLoop newrecvBuf
+ receiveWithBufferLoop $ B.copy newrecvBuf
sendPacket packet = writeChan chan $ ClientMessage (ci, packet)
clientRecvLoop :: Socket -> Chan CoreMessage -> Chan [B.ByteString] -> ClientIndex -> (forall a. IO a -> IO a) -> IO ()
clientRecvLoop s chan clChan ci restore =
(myThreadId >>=
- \t -> (restore $ forkIO (clientSendLoop s t clChan ci) >>
+ (\t -> (restore $ forkIO (clientSendLoop s t clChan ci) >>
listenLoop s chan ci >> return "Connection closed")
`Exception.catch` (\(e :: ShutdownThreadException) -> return . B.pack . show $ e)
`Exception.catch` (\(e :: Exception.IOException) -> return . B.pack . show $ e)
`Exception.catch` (\(e :: Exception.SomeException) -> return . B.pack . show $ e)
+ )
>>= clientOff) `Exception.finally` remove
where
clientOff msg = writeChan chan $ ClientMessage (ci, ["QUIT", msg])
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/ConfigFile.hs
--- a/gameServer/ConfigFile.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/ConfigFile.hs Fri Feb 22 05:05:32 2013 +0100
@@ -58,4 +58,3 @@
, ("sv_message", sm)
, ("sv_messageOld", smo)
]
-
\ No newline at end of file
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/CoreTypes.hs
--- a/gameServer/CoreTypes.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/CoreTypes.hs Fri Feb 22 05:05:32 2013 +0100
@@ -4,7 +4,6 @@
import Control.Concurrent
import Data.Word
import qualified Data.Map as Map
-import Data.Sequence(Seq, empty)
import Data.Time
import Network
import Data.Function
@@ -18,6 +17,13 @@
type ClientChan = Chan [B.ByteString]
+data CheckInfo =
+ CheckInfo
+ {
+ recordFileName :: String,
+ recordTeams :: [TeamInfo]
+ }
+
data ClientInfo =
ClientInfo
{
@@ -29,6 +35,7 @@
nick :: B.ByteString,
webPassword :: B.ByteString,
logonPassed :: Bool,
+ isVisible :: Bool,
clientProto :: !Word16,
roomID :: RoomIndex,
pingsQueue :: !Word,
@@ -36,7 +43,10 @@
isReady :: !Bool,
isInGame :: Bool,
isAdministrator :: Bool,
- clientClan :: Maybe B.ByteString,
+ isChecker :: Bool,
+ isKickedFromServer :: Bool,
+ clientClan :: !(Maybe B.ByteString),
+ checkInfo :: Maybe CheckInfo,
teamsInGame :: Word
}
@@ -64,14 +74,17 @@
}
deriving (Show, Read)
+instance Eq TeamInfo where
+ (==) = (==) `on` teamname
+
data GameInfo =
GameInfo
{
- roundMsgs :: Seq B.ByteString,
+ roundMsgs :: [B.ByteString],
leftTeams :: [B.ByteString],
teamsAtStart :: [TeamInfo],
teamsInGameNumber :: Int,
- allPlayersHaveRegisteredAccounts :: Bool,
+ allPlayersHaveRegisteredAccounts :: !Bool,
giMapParams :: Map.Map B.ByteString B.ByteString,
giParams :: Map.Map B.ByteString [B.ByteString]
} deriving (Show, Read)
@@ -84,7 +97,7 @@
-> GameInfo
newGameInfo =
GameInfo
- Data.Sequence.empty
+ []
[]
data RoomInfo =
@@ -100,6 +113,7 @@
readyPlayers :: !Int,
isRestrictedJoins :: Bool,
isRestrictedTeams :: Bool,
+ isRegisteredOnly :: Bool,
roomBansList :: ![B.ByteString],
mapParams :: Map.Map B.ByteString B.ByteString,
params :: Map.Map B.ByteString [B.ByteString]
@@ -118,6 +132,7 @@
0
False
False
+ False
[]
(
Map.fromList $ Prelude.zipWith (,)
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/EngineInteraction.hs
--- a/gameServer/EngineInteraction.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/EngineInteraction.hs Fri Feb 22 05:05:32 2013 +0100
@@ -1,3 +1,5 @@
+{-# LANGUAGE OverloadedStrings #-}
+
module EngineInteraction where
import qualified Data.Set as Set
@@ -5,8 +7,14 @@
import qualified Codec.Binary.Base64 as Base64
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString as BW
+import qualified Data.Map as Map
+import qualified Data.List as L
+import Data.Word
+import Data.Bits
+import Control.Arrow
-------------
import CoreTypes
+import Utils
toEngineMsg :: B.ByteString -> B.ByteString
@@ -20,19 +28,130 @@
removeLength _ = Nothing
-checkNetCmd :: B.ByteString -> (Bool, Bool)
+splitMessages :: B.ByteString -> [B.ByteString]
+splitMessages = L.unfoldr (\b -> if B.null b then Nothing else Just $ B.splitAt (1 + fromIntegral (BW.head b)) b)
+
+
+checkNetCmd :: B.ByteString -> (B.ByteString, B.ByteString)
checkNetCmd msg = check decoded
where
- decoded = fromEngineMsg msg
- check Nothing = (False, False)
- check (Just ms) | B.length ms > 0 = let m = B.head ms in (m `Set.member` legalMessages, m == '+')
- | otherwise = (False, False)
+ decoded = liftM (splitMessages . BW.pack) $ Base64.decode $ B.unpack msg
+ check Nothing = (B.empty, B.empty)
+ check (Just msgs) = let (a, b) = (filter isLegal msgs, filter isNonEmpty a) in (encode a, encode b)
+ encode = B.pack . Base64.encode . BW.unpack . B.concat
+ isLegal m = (B.length m > 1) && (flip Set.member legalMessages . B.head . B.tail $ m)
+ isNonEmpty = (/=) '+' . B.head . B.tail
legalMessages = Set.fromList $ "M#+LlRrUuDdZzAaSjJ,sNpPwtghbc12345" ++ slotMessages
slotMessages = "\128\129\130\131\132\133\134\135\136\137\138"
-gameInfo2Replay :: GameInfo -> B.ByteString
-gameInfo2Replay GameInfo{roundMsgs = rm,
- teamsAtStart = teams,
- giMapParams = params1,
- giParams = params2} = undefined
+replayToDemo :: [TeamInfo]
+ -> Map.Map B.ByteString B.ByteString
+ -> Map.Map B.ByteString [B.ByteString]
+ -> [B.ByteString]
+ -> [B.ByteString]
+replayToDemo teams mapParams params msgs = concat [
+ [em "TD"]
+ , maybeScript
+ , maybeMap
+ , [eml ["etheme ", head $ params Map.! "THEME"]]
+ , [eml ["eseed ", mapParams Map.! "SEED"]]
+ , [eml ["e$gmflags ", showB gameFlags]]
+ , schemeFlags
+ , [eml ["e$template_filter ", mapParams Map.! "TEMPLATE"]]
+ , [eml ["e$mapgen ", mapgen]]
+ , mapgenSpecific
+ , concatMap teamSetup teams
+ , msgs
+ , [em "!"]
+ ]
+ where
+ em = toEngineMsg
+ eml = em . B.concat
+ mapGenTypes = ["+rnd+", "+maze+", "+drawn+"]
+ maybeScript = let s = head $ params Map.! "SCRIPT" in if s == "Normal" then [] else [eml ["escript Scripts/Multiplayer/", s, ".lua"]]
+ maybeMap = let m = mapParams Map.! "MAP" in if m `elem` mapGenTypes then [] else [eml ["emap ", m]]
+ scheme = tail $ params Map.! "SCHEME"
+ mapgen = mapParams Map.! "MAPGEN"
+ mapgenSpecific = case mapgen of
+ "+maze+" -> [eml ["e$maze_size ", head $ params Map.! "MAZE_SIZE"]]
+ "+drawn" -> drawnMapData . head $ params Map.! "DRAWNMAP"
+ _ -> []
+ gameFlags :: Word32
+ gameFlags = foldl (\r (b, f) -> if b == "false" then r else r .|. f) 0 $ zip scheme gameFlagConsts
+ schemeFlags = map (\(v, (n, m)) -> eml [n, " ", showB $ (readInt_ v) * m])
+ $ filter (\(_, (n, _)) -> not $ B.null n)
+ $ zip (drop (length gameFlagConsts) scheme) schemeParams
+ ammoStr :: B.ByteString
+ ammoStr = head . tail $ params Map.! "AMMO"
+ ammo = let l = B.length ammoStr `div` 4; ((a, b), (c, d)) = (B.splitAt l . fst &&& B.splitAt l . snd) . B.splitAt (l * 2) $ ammoStr in
+ (map (\(x, y) -> eml [x, " ", y]) $ zip ["eammloadt", "eammprob", "eammdelay", "eammreinf"] [a, b, c, d])
+ ++ [em "eammstore" | scheme !! 14 == "true" || scheme !! 20 == "false"]
+ initHealth = scheme !! 27
+ teamSetup :: TeamInfo -> [B.ByteString]
+ teamSetup t = (++) ammo $
+ eml ["eaddteam ", showB $ (1 + (readInt_ $ teamcolor t) :: Int) * 1234, " ", teamname t]
+ : em "erdriven"
+ : eml ["efort ", teamfort t]
+ : take (hhnum t) (
+ concatMap (\(HedgehogInfo hname hhat) -> [
+ eml ["eaddhh ", showB $ difficulty t, " ", initHealth, " ", hname]
+ , eml ["ehat ", hhat]
+ ])
+ $ hedgehogs t
+ )
+
+drawnMapData :: B.ByteString -> [B.ByteString]
+drawnMapData = error "drawnMapData"
+
+schemeParams :: [(B.ByteString, Int)]
+schemeParams = [
+ ("e$damagepct", 1)
+ , ("e$turntime", 1000)
+ , ("", 0)
+ , ("e$sd_turns", 1)
+ , ("e$casefreq", 1)
+ , ("e$minestime", 1000)
+ , ("e$minesnum", 1)
+ , ("e$minedudpct", 1)
+ , ("e$explosives", 1)
+ , ("e$healthprob", 1)
+ , ("e$hcaseamount", 1)
+ , ("e$waterrise", 1)
+ , ("e$healthdec", 1)
+ , ("e$ropepct", 1)
+ , ("e$getawaytime", 1)
+ ]
+
+
+gameFlagConsts :: [Word32]
+gameFlagConsts = [
+ 0x00001000
+ , 0x00000010
+ , 0x00000004
+ , 0x00000008
+ , 0x00000020
+ , 0x00000040
+ , 0x00000080
+ , 0x00000100
+ , 0x00000200
+ , 0x00000400
+ , 0x00000800
+ , 0x00002000
+ , 0x00004000
+ , 0x00008000
+ , 0x00010000
+ , 0x00020000
+ , 0x00040000
+ , 0x00080000
+ , 0x00100000
+ , 0x00200000
+ , 0x00400000
+ , 0x00800000
+ , 0x01000000
+ , 0x02000000
+ , 0x04000000
+ ]
+
+
+
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/HWProtoChecker.hs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gameServer/HWProtoChecker.hs Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,36 @@
+{-# LANGUAGE OverloadedStrings #-}
+module HWProtoChecker where
+
+import qualified Data.Map as Map
+import Data.Maybe
+import Data.List
+import Control.Monad.Reader
+--------------------------------------
+import CoreTypes
+import Actions
+import Utils
+import HandlerUtils
+import RoomsAndClients
+import EngineInteraction
+
+
+handleCmd_checker :: CmdHandler
+
+handleCmd_checker ["READY"] = return [CheckRecord]
+
+handleCmd_checker ["CHECKED", "FAIL", msg] = do
+ isChecking <- liftM (isJust . checkInfo) thisClient
+ if not isChecking then
+ return []
+ else
+ return [CheckFailed msg, ModifyClient $ \c -> c{checkInfo = Nothing}]
+
+
+handleCmd_checker ("CHECKED" : "OK" : info) = do
+ isChecking <- liftM (isJust . checkInfo) thisClient
+ if not isChecking then
+ return []
+ else
+ return [CheckSuccess info, ModifyClient $ \c -> c{checkInfo = Nothing}]
+
+handleCmd_checker _ = return [ProtocolError "Unknown command"]
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/HWProtoCore.hs
--- a/gameServer/HWProtoCore.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/HWProtoCore.hs Fri Feb 22 05:05:32 2013 +0100
@@ -4,12 +4,14 @@
import Control.Monad.Reader
import Data.Maybe
import qualified Data.ByteString.Char8 as B
+import qualified Data.List as L
--------------------------------------
import CoreTypes
import Actions
import HWProtoNEState
import HWProtoLobbyState
import HWProtoInRoomState
+import HWProtoChecker
import HandlerUtils
import RoomsAndClients
import Utils
@@ -22,7 +24,7 @@
handleCmd ("QUIT" : xs) = return [ByeClient msg]
where
- msg = if not $ null xs then head xs else "bye"
+ msg = if not $ null xs then head xs else loc "bye"
handleCmd ["PONG"] = do
@@ -32,10 +34,27 @@
else
return [ModifyClient (\c -> c{pingsQueue = pingsQueue c - 1})]
+handleCmd ("CMD" : params) =
+ let c = concatMap B.words params in
+ if not $ null c then
+ h $ (upperCase . head $ c) : tail c
+ else
+ return []
+ where
+ h ["DELEGATE", n] = handleCmd ["DELEGATE", n]
+ h ["STATS"] = handleCmd ["STATS"]
+ h ["PART", msg] = handleCmd ["PART", msg]
+ h ["QUIT", msg] = handleCmd ["QUIT", msg]
+ h c = return [Warning . B.concat . L.intersperse " " $ "Unknown cmd" : c]
+
handleCmd cmd = do
(ci, irnc) <- ask
- if logonPassed (irnc `client` ci) then
- handleCmd_loggedin cmd
+ let cl = irnc `client` ci
+ if logonPassed cl then
+ if isChecker cl then
+ handleCmd_checker cmd
+ else
+ handleCmd_loggedin cmd
else
handleCmd_NotEntered cmd
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/HWProtoInRoomState.hs
--- a/gameServer/HWProtoInRoomState.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/HWProtoInRoomState.hs Fri Feb 22 05:05:32 2013 +0100
@@ -2,13 +2,11 @@
module HWProtoInRoomState where
import qualified Data.Map as Map
-import Data.Sequence((|>))
import Data.List as L
import Data.Maybe
import qualified Data.ByteString.Char8 as B
import Control.Monad
import Control.Monad.Reader
-import Control.DeepSeq
--------------------------------------
import CoreTypes
import Actions
@@ -29,7 +27,7 @@
handleCmd_inRoom ("CFG" : paramName : paramStrs)
- | null paramStrs = return [ProtocolError "Empty config entry"]
+ | null paramStrs = return [ProtocolError $ loc "Empty config entry"]
| otherwise = do
chans <- roomOthersChans
cl <- thisClient
@@ -38,7 +36,7 @@
ModifyRoom f,
AnswerClients chans ("CFG" : paramName : paramStrs)]
else
- return [ProtocolError "Not room master"]
+ return [ProtocolError $ loc "Not room master"]
where
f r = if paramName `Map.member` (mapParams r) then
r{mapParams = Map.insert paramName (head paramStrs) (mapParams r)}
@@ -46,7 +44,7 @@
r{params = Map.insert paramName paramStrs (params r)}
handleCmd_inRoom ("ADD_TEAM" : tName : color : grave : fort : voicepack : flag : difStr : hhsInfo)
- | length hhsInfo /= 16 = return [ProtocolError "Corrupted hedgehogs info"]
+ | length hhsInfo /= 16 = return [ProtocolError $ loc "Corrupted hedgehogs info"]
| otherwise = do
(ci, _) <- ask
rm <- thisRoom
@@ -60,34 +58,37 @@
return color
else
liftM (head . (L.\\) (map B.singleton ['0'..]) . map teamcolor . teams) thisRoom
- let newTeam = clNick `seq` TeamInfo ci clNick tName teamColor grave fort voicepack flag dif (newTeamHHNum rm) (hhsList hhsInfo)
+ let roomTeams = teams rm
+ let hhNum = let p = if not $ null roomTeams then hhnum $ head roomTeams else 4 in newTeamHHNum roomTeams p
+ let newTeam = clNick `seq` TeamInfo ci clNick tName teamColor grave fort voicepack flag dif hhNum (hhsList hhsInfo)
return $
- if not . null . drop (maxTeams rm - 1) $ teams rm then
- [Warning "too many teams"]
- else if canAddNumber rm <= 0 then
- [Warning "too many hedgehogs"]
+ if not . null . drop (maxTeams rm - 1) $ roomTeams then
+ [Warning $ loc "too many teams"]
+ else if canAddNumber roomTeams <= 0 then
+ [Warning $ loc "too many hedgehogs"]
else if isJust $ findTeam rm then
- [Warning "There's already a team with same name in the list"]
+ [Warning $ loc "There's already a team with same name in the list"]
else if isJust $ gameInfo rm then
- [Warning "round in progress"]
+ [Warning $ loc "round in progress"]
else if isRestrictedTeams rm then
- [Warning "restricted"]
+ [Warning $ loc "restricted"]
else
[ModifyRoom (\r -> r{teams = teams r ++ [newTeam]}),
SendUpdateOnThisRoom,
ModifyClient (\c -> c{teamsInGame = teamsInGame c + 1, clientClan = Just teamColor}),
AnswerClients clChan ["TEAM_ACCEPTED", tName],
+ AnswerClients clChan ["HH_NUM", tName, showB $ hhnum newTeam],
AnswerClients othChans $ teamToNet $ newTeam,
AnswerClients roomChans ["TEAM_COLOR", tName, teamColor]
]
where
- canAddNumber r = 48 - (sum . map hhnum $ teams r)
+ canAddNumber rt = (48::Int) - (sum $ map hhnum rt)
findTeam = find (\t -> tName == teamname t) . teams
dif = readInt_ difStr
hhsList [] = []
hhsList [_] = error "Hedgehogs list with odd elements number"
hhsList (n:h:hhs) = HedgehogInfo n h : hhsList hhs
- newTeamHHNum r = min 4 (canAddNumber r)
+ newTeamHHNum rt p = min p (canAddNumber rt)
maxTeams r
| roomProto r < 38 = 6
| otherwise = 8
@@ -96,42 +97,44 @@
handleCmd_inRoom ["REMOVE_TEAM", tName] = do
(ci, _) <- ask
r <- thisRoom
- clNick <- clientNick
let maybeTeam = findTeam r
let team = fromJust maybeTeam
return $
- if isNothing $ findTeam r then
- [Warning "REMOVE_TEAM: no such team"]
- else if clNick /= teamowner team then
- [ProtocolError "Not team owner!"]
+ if isNothing $ maybeTeam then
+ [Warning $ loc "REMOVE_TEAM: no such team"]
+ else if ci /= teamownerId team then
+ [ProtocolError $ loc "Not team owner!"]
else
[RemoveTeam tName,
ModifyClient
(\c -> c{
teamsInGame = teamsInGame c - 1,
- clientClan = if teamsInGame c == 1 then Nothing else Just $ anotherTeamClan ci r
+ clientClan = if teamsInGame c == 1 then Nothing else Just $ anotherTeamClan ci team r
})
]
where
- anotherTeamClan ci = teamcolor . fromJust . find (\t -> teamownerId t == ci) . teams
+ anotherTeamClan ci team = teamcolor . fromMaybe (error "CHECKPOINT 011") . find (\t -> (teamownerId t == ci) && (t /= team)) . teams
findTeam = find (\t -> tName == teamname t) . teams
handleCmd_inRoom ["HH_NUM", teamName, numberStr] = do
cl <- thisClient
+ r <- thisRoom
+ clChan <- thisClientChans
others <- roomOthersChans
- r <- thisRoom
let maybeTeam = findTeam r
let team = fromJust maybeTeam
return $
if not $ isMaster cl then
- [ProtocolError "Not room master"]
- else if hhNumber < 1 || hhNumber > 8 || isNothing maybeTeam || hhNumber > canAddNumber r + hhnum team then
+ [ProtocolError $ loc "Not room master"]
+ else if isNothing maybeTeam then
[]
+ else if hhNumber < 1 || hhNumber > 8 || hhNumber > canAddNumber r + hhnum team then
+ [AnswerClients clChan ["HH_NUM", teamName, showB $ hhnum team]]
else
[ModifyRoom $ modifyTeam team{hhnum = hhNumber},
AnswerClients others ["HH_NUM", teamName, showB hhNumber]]
@@ -152,7 +155,7 @@
return $
if not $ isMaster cl then
- [ProtocolError "Not room master"]
+ [ProtocolError $ loc "Not room master"]
else if isNothing maybeTeam then
[]
else
@@ -178,6 +181,7 @@
["CLIENT_FLAGS", if isReady cl then "-r" else "+r", nick cl]
]
+
handleCmd_inRoom ["START_GAME"] = do
(ci, rnc) <- ask
cl <- thisClient
@@ -187,7 +191,7 @@
let nicks = map (nick . client rnc) . roomClients rnc $ clientRoom rnc ci
let allPlayersRegistered = all ((<) 0 . B.length . webPassword . client rnc . teamownerId) $ teams rm
- if isMaster cl && playersIn rm == readyPlayers rm && not (isJust $ gameInfo rm) then
+ if isMaster cl && (playersIn rm == readyPlayers rm || clientProto cl > 43) && not (isJust $ gameInfo rm) then
if enoughClans rm then
return [
ModifyRoom
@@ -201,7 +205,7 @@
, ModifyRoomClients (\c -> c{isInGame = True})
]
else
- return [Warning "Less than two clans!"]
+ return [Warning $ loc "Less than two clans!"]
else
return []
where
@@ -213,12 +217,13 @@
rm <- thisRoom
chans <- roomOthersChans
- if teamsInGame cl > 0 && (isJust $ gameInfo rm) && isLegal then
- return $ AnswerClients chans ["EM", msg] : [ModifyRoom (\r -> r{gameInfo = liftM (\g -> g{roundMsgs = roundMsgs g |> msg}) $ gameInfo r}) | not isKeepAlive]
+ if teamsInGame cl > 0 && (isJust $ gameInfo rm) && (not $ B.null legalMsgs) then
+ return $ AnswerClients chans ["EM", legalMsgs]
+ : [ModifyRoom (\r -> r{gameInfo = liftM (\g -> g{roundMsgs = nonEmptyMsgs : roundMsgs g}) $ gameInfo r}) | not $ B.null nonEmptyMsgs]
else
return []
where
- (isLegal, isKeepAlive) = checkNetCmd msg
+ (legalMsgs, nonEmptyMsgs) = checkNetCmd msg
handleCmd_inRoom ["ROUNDFINISHED", correctly] = do
@@ -231,10 +236,7 @@
if isInGame cl then
if isJust $ gameInfo rm then
- if (isMaster cl && isCorrect) then
- return $ FinishGame : unsetInGameState
- else
- return $ unsetInGameState ++ map SendTeamRemovalMessage clTeams
+ return $ unsetInGameState ++ map SendTeamRemovalMessage clTeams
else
return unsetInGameState
else
@@ -250,7 +252,7 @@
cl <- thisClient
return $
if not $ isMaster cl then
- [ProtocolError "Not room master"]
+ [ProtocolError $ loc "Not room master"]
else
[ModifyRoom (\r -> r{isRestrictedJoins = not $ isRestrictedJoins r})]
@@ -259,11 +261,20 @@
cl <- thisClient
return $
if not $ isMaster cl then
- [ProtocolError "Not room master"]
+ [ProtocolError $ loc "Not room master"]
else
[ModifyRoom (\r -> r{isRestrictedTeams = not $ isRestrictedTeams r})]
+handleCmd_inRoom ["TOGGLE_REGISTERED_ONLY"] = do
+ cl <- thisClient
+ return $
+ if not $ isMaster cl then
+ [ProtocolError $ loc "Not room master"]
+ else
+ [ModifyRoom (\r -> r{isRegisteredOnly = not $ isRegisteredOnly r})]
+
+
handleCmd_inRoom ["ROOM_NAME", newName] = do
cl <- thisClient
rs <- allRoomInfos
@@ -272,10 +283,10 @@
return $
if not $ isMaster cl then
- [ProtocolError "Not room master"]
+ [ProtocolError $ loc "Not room master"]
else
if isJust $ find (\r -> newName == name r) rs then
- [Warning "Room with such name already exists"]
+ [Warning $ loc "Room with such name already exists"]
else
[ModifyRoom roomUpdate,
AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo (nick cl) (roomUpdate rm))]
@@ -287,10 +298,34 @@
(thisClientId, rnc) <- ask
maybeClientId <- clientByNick kickNick
master <- liftM isMaster thisClient
+ rm <- thisRoom
let kickId = fromJust maybeClientId
+ let kickCl = rnc `client` kickId
let sameRoom = clientRoom rnc thisClientId == clientRoom rnc kickId
+ let notOnly2Clans = (length . group . sort . map teamcolor . teams $ rm) > 2
return
- [KickRoomClient kickId | master && isJust maybeClientId && (kickId /= thisClientId) && sameRoom]
+ [KickRoomClient kickId |
+ master
+ && isJust maybeClientId
+ && (kickId /= thisClientId)
+ && sameRoom
+ && ((isNothing $ gameInfo rm) || notOnly2Clans || teamsInGame kickCl == 0)
+ ]
+
+
+handleCmd_inRoom ["DELEGATE", newAdmin] = do
+ (thisClientId, rnc) <- ask
+ maybeClientId <- clientByNick newAdmin
+ master <- liftM isMaster thisClient
+ serverAdmin <- liftM isAdministrator thisClient
+ let newAdminId = fromJust maybeClientId
+ let sameRoom = clientRoom rnc thisClientId == clientRoom rnc newAdminId
+ return
+ [ChangeMaster (Just newAdminId) |
+ (master || serverAdmin)
+ && isJust maybeClientId
+ && ((newAdminId /= thisClientId) || (serverAdmin && not master))
+ && sameRoom]
handleCmd_inRoom ["TEAMCHAT", msg] = do
@@ -300,6 +335,7 @@
where
engineMsg cl = toEngineMsg $ B.concat ["b", nick cl, "(team): ", msg, "\x20\x20"]
+
handleCmd_inRoom ["BAN", banNick] = do
(thisClientId, rnc) <- ask
maybeClientId <- clientByNick banNick
@@ -308,8 +344,8 @@
let sameRoom = clientRoom rnc thisClientId == clientRoom rnc banId
if master && isJust maybeClientId && (banId /= thisClientId) && sameRoom then
return [
- ModifyRoom (\r -> r{roomBansList = let h = host $ rnc `client` banId in h `deepseq` h : roomBansList r})
- , KickRoomClient banId
+-- ModifyRoom (\r -> r{roomBansList = let h = host $ rnc `client` banId in h `deepseq` h : roomBansList r})
+ KickRoomClient banId
]
else
return []
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/HWProtoLobbyState.hs
--- a/gameServer/HWProtoLobbyState.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/HWProtoLobbyState.hs Fri Feb 22 05:05:32 2013 +0100
@@ -2,11 +2,9 @@
module HWProtoLobbyState where
import qualified Data.Map as Map
-import qualified Data.Foldable as Foldable
import Data.Maybe
import Data.List
import Control.Monad.Reader
-import qualified Data.ByteString.Char8 as B
--------------------------------------
import CoreTypes
import Actions
@@ -43,7 +41,7 @@
return [AnswerClients s ["CHAT", n, msg]]
handleCmd_lobby ["CREATE_ROOM", rName, roomPassword]
- | illegalName rName = return [Warning "Illegal room name"]
+ | illegalName rName = return [Warning $ loc "Illegal room name"]
| otherwise = do
rs <- allRoomInfos
cl <- thisClient
@@ -77,11 +75,13 @@
let isBanned = host cl `elem` roomBansList jRoom
return $
if isNothing maybeRI || not sameProto then
- [Warning "No such room"]
+ [Warning $ loc "No such room"]
else if isRestrictedJoins jRoom then
- [Warning "Joining restricted"]
+ [Warning $ loc "Joining restricted"]
+ else if isRegisteredOnly jRoom then
+ [Warning $ loc "Registered users only"]
else if isBanned then
- [Warning "You are banned in this room"]
+ [Warning $ loc "You are banned in this room"]
else if roomPassword /= password jRoom then
[NoticeMessage WrongPassword]
else
@@ -89,20 +89,21 @@
MoveToRoom jRI
, AnswerClients [sendChan cl] $ "JOINED" : nicks
, AnswerClients chans ["CLIENT_FLAGS", "-r", nick cl]
- , AnswerClients [sendChan cl] $ ["WARNING", "Room admin is " `B.append` ownerNick]
, AnswerClients [sendChan cl] $ ["CLIENT_FLAGS", "+h", ownerNick]
]
- ++ map (readynessMessage cl) jRoomClients
+ ++ (if clientProto cl < 38 then map (readynessMessage cl) jRoomClients else [sendStateFlags cl jRoomClients])
++ answerFullConfig cl (mapParams jRoom) (params jRoom)
++ answerTeams cl jRoom
- ++ watchRound cl jRoom
+ ++ watchRound cl jRoom chans
where
- readynessMessage cl c = AnswerClients [sendChan cl] $
- if clientProto cl < 38 then
- [if isReady c then "READY" else "NOT_READY", nick c]
- else
- ["CLIENT_FLAGS", if isReady c then "+r" else "-r", nick c]
+ readynessMessage cl c = AnswerClients [sendChan cl] [if isReady c then "READY" else "NOT_READY", nick c]
+ sendStateFlags cl clients = AnswerClients [sendChan cl] . concat . intersperse [""] . filter (not . null) . concat $
+ [f "+r" ready, f "-r" unready, f "+g" ingame, f "-g" inroomlobby]
+ where
+ (ready, unready) = partition isReady clients
+ (ingame, inroomlobby) = partition isInGame clients
+ f fl lst = ["CLIENT_FLAGS" : fl : map nick lst | not $ null lst]
toAnswer cl (paramName, paramStrs) = AnswerClients [sendChan cl] $ "CFG" : paramName : paramStrs
@@ -119,11 +120,13 @@
answerTeams cl jRoom = let f = if isJust $ gameInfo jRoom then teamsAtStart . fromJust . gameInfo else teams in answerAllTeams cl $ f jRoom
- watchRound cl jRoom = if isNothing $ gameInfo jRoom then
+ watchRound cl jRoom chans = if isNothing $ gameInfo jRoom then
[]
else
- [AnswerClients [sendChan cl] ["RUN_GAME"],
- AnswerClients [sendChan cl] $ "EM" : toEngineMsg "e$spectate 1" : Foldable.toList (roundMsgs . fromJust . gameInfo $ jRoom)]
+ [AnswerClients [sendChan cl] ["RUN_GAME"]
+ , AnswerClients chans ["CLIENT_FLAGS", "+g", nick cl]
+ , ModifyClient (\c -> c{isInGame = True})
+ , AnswerClients [sendChan cl] $ "EM" : toEngineMsg "e$spectate 1" : (reverse . roundMsgs . fromJust . gameInfo $ jRoom)]
handleCmd_lobby ["JOIN_ROOM", roomName] =
@@ -132,13 +135,14 @@
handleCmd_lobby ["FOLLOW", asknick] = do
(_, rnc) <- ask
+ clChan <- liftM sendChan thisClient
ci <- clientByNick asknick
let ri = clientRoom rnc $ fromJust ci
- let clRoom = room rnc ri
+ let roomName = name $ room rnc ri
if isNothing ci || ri == lobbyId then
return []
else
- handleCmd_lobby ["JOIN_ROOM", name clRoom]
+ liftM ((:) (AnswerClients [clChan] ["JOINING", roomName])) $ handleCmd_lobby ["JOIN_ROOM", roomName]
---------------------------
-- Administrator's stuff --
@@ -150,16 +154,20 @@
return [KickClient $ fromJust kickId | isAdministrator cl && isJust kickId && fromJust kickId /= ci]
-handleCmd_lobby ["BAN", banNick, reason] = do
+handleCmd_lobby ["BAN", banNick, reason, duration] = do
(ci, _) <- ask
cl <- thisClient
banId <- clientByNick banNick
- return [BanClient 60 reason (fromJust banId) | isAdministrator cl && isJust banId && fromJust banId /= ci]
+ return [BanClient (readInt_ duration) reason (fromJust banId) | isAdministrator cl && isJust banId && fromJust banId /= ci]
handleCmd_lobby ["BANIP", ip, reason, duration] = do
cl <- thisClient
return [BanIP ip (readInt_ duration) reason | isAdministrator cl]
+handleCmd_lobby ["BANNICK", n, reason, duration] = do
+ cl <- thisClient
+ return [BanNick n (readInt_ duration) reason | isAdministrator cl]
+
handleCmd_lobby ["BANLIST"] = do
cl <- thisClient
return [BanList | isAdministrator cl]
@@ -196,5 +204,8 @@
cl <- thisClient
return [RestartServer | isAdministrator cl]
+handleCmd_lobby ["STATS"] = do
+ cl <- thisClient
+ return [Stats | isAdministrator cl]
handleCmd_lobby _ = return [ProtocolError "Incorrect command (state: in lobby)"]
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/HWProtoNEState.hs
--- a/gameServer/HWProtoNEState.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/HWProtoNEState.hs Fri Feb 22 05:05:32 2013 +0100
@@ -1,4 +1,4 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, CPP #-}
module HWProtoNEState where
import Control.Monad.Reader
@@ -14,9 +14,9 @@
handleCmd_NotEntered ["NICK", newNick] = do
(ci, irnc) <- ask
let cl = irnc `client` ci
- if not . B.null $ nick cl then return [ProtocolError "Nickname already chosen"]
+ if not . B.null $ nick cl then return [ProtocolError $ loc "Nickname already chosen"]
else
- if illegalName newNick then return [ByeClient "Illegal nickname"]
+ if illegalName newNick then return [ByeClient $ loc "Illegal nickname"]
else
return $
ModifyClient (\c -> c{nick = newNick}) :
@@ -26,9 +26,9 @@
handleCmd_NotEntered ["PROTO", protoNum] = do
(ci, irnc) <- ask
let cl = irnc `client` ci
- if clientProto cl > 0 then return [ProtocolError "Protocol already known"]
+ if clientProto cl > 0 then return [ProtocolError $ loc "Protocol already known"]
else
- if parsedProto == 0 then return [ProtocolError "Bad number"]
+ if parsedProto == 0 then return [ProtocolError $ loc "Bad number"]
else
return $
ModifyClient (\c -> c{clientProto = parsedProto}) :
@@ -48,4 +48,18 @@
return [ByeClient "Authentication failed"]
+#if defined(OFFICIAL_SERVER)
+handleCmd_NotEntered ["CHECKER", protoNum, newNick, password] = do
+ (ci, irnc) <- ask
+ let cl = irnc `client` ci
+
+ if parsedProto == 0 then return [ProtocolError $ loc "Bad number"]
+ else
+ return $ [
+ ModifyClient (\c -> c{clientProto = parsedProto, nick = newNick, webPassword = password, isChecker = True})
+ , CheckRegistered]
+ where
+ parsedProto = readInt_ protoNum
+#endif
+
handleCmd_NotEntered _ = return [ProtocolError "Incorrect command (state: not entered)"]
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/NetRoutines.hs
--- a/gameServer/NetRoutines.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/NetRoutines.hs Fri Feb 22 05:05:32 2013 +0100
@@ -34,6 +34,7 @@
""
""
False
+ False
0
lobbyId
0
@@ -41,6 +42,9 @@
False
False
False
+ False
+ False
+ Nothing
Nothing
0
)
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/OfficialServer/GameReplayStore.hs
--- a/gameServer/OfficialServer/GameReplayStore.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/OfficialServer/GameReplayStore.hs Fri Feb 22 05:05:32 2013 +0100
@@ -9,18 +9,57 @@
import Data.Maybe
import Data.Unique
import Control.Monad
+import Data.List
+import qualified Data.ByteString as B
+import System.Directory
---------------
import CoreTypes
+import EngineInteraction
+pickReplayFile :: Int -> IO String
+pickReplayFile p = do
+ files <- liftM (filter (isSuffixOf ('.' : show p))) $ getDirectoryContents "replays"
+ if (not $ null files) then
+ return $ "replays/" ++ head files
+ else
+ return ""
+
saveReplay :: RoomInfo -> IO ()
saveReplay r = do
- time <- getCurrentTime
- u <- liftM hashUnique newUnique
- let fileName = "replays/" ++ show time ++ "-" ++ show u
let gi = fromJust $ gameInfo r
- let replayInfo = (teamsAtStart gi, Map.toList $ mapParams r, Map.toList $ params r, roundMsgs gi)
- E.catch
- (writeFile fileName (show replayInfo))
- (\(e :: IOException) -> warningM "REPLAYS" $ "Couldn't write to " ++ fileName ++ ": " ++ show e)
-
\ No newline at end of file
+ when (allPlayersHaveRegisteredAccounts gi) $ do
+ time <- getCurrentTime
+ u <- liftM hashUnique newUnique
+ let fileName = "replays/" ++ show time ++ "-" ++ show u ++ "." ++ show (roomProto r)
+ let replayInfo = (teamsAtStart gi, Map.toList $ mapParams r, Map.toList $ params r, roundMsgs gi)
+ E.catch
+ (writeFile fileName (show replayInfo))
+ (\(e :: IOException) -> warningM "REPLAYS" $ "Couldn't write to " ++ fileName ++ ": " ++ show e)
+
+
+loadReplay :: Int -> IO (Maybe CheckInfo, [B.ByteString])
+loadReplay p = E.handle (\(e :: SomeException) -> warningM "REPLAYS" "Problems reading replay" >> return (Nothing, [])) $ do
+ fileName <- pickReplayFile p
+ if (not $ null fileName) then
+ loadFile fileName
+ else
+ return (Nothing, [])
+ where
+ loadFile :: String -> IO (Maybe CheckInfo, [B.ByteString])
+ loadFile fileName = E.handle (\(e :: SomeException) ->
+ warningM "REPLAYS" ("Problems reading " ++ fileName ++ ": " ++ show e) >> return (Nothing, [])) $ do
+ (teams, params1, params2, roundMsgs) <- liftM read $ readFile fileName
+ return $ (
+ Just (CheckInfo fileName teams)
+ , replayToDemo teams (Map.fromList params1) (Map.fromList params2) (reverse roundMsgs)
+ )
+
+moveFailedRecord :: String -> IO ()
+moveFailedRecord fn = E.handle (\(e :: SomeException) -> warningM "REPLAYS" $ show e) $
+ renameFile fn ("failed/" ++ drop 8 fn)
+
+
+moveCheckedRecord :: String -> IO ()
+moveCheckedRecord fn = E.handle (\(e :: SomeException) -> warningM "REPLAYS" $ show e) $
+ renameFile fn ("checked/" ++ drop 8 fn)
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/OfficialServer/checker.hs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gameServer/OfficialServer/checker.hs Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,171 @@
+{-# LANGUAGE CPP, ScopedTypeVariables, OverloadedStrings #-}
+module Main where
+
+import qualified Control.Exception as Exception
+import System.IO
+import System.Log.Logger
+import qualified Data.ConfigFile as CF
+import Control.Monad.Error
+import System.Directory
+import Control.Monad.State
+import Control.Concurrent.Chan
+import Control.Concurrent
+import Network
+import Network.BSD
+import Network.Socket hiding (recv)
+import Network.Socket.ByteString
+import qualified Data.ByteString.Char8 as B
+import qualified Data.ByteString as BW
+import qualified Codec.Binary.Base64 as Base64
+import System.Process
+import Data.Maybe
+import qualified Data.List as L
+#if !defined(mingw32_HOST_OS)
+import System.Posix
+#endif
+
+data Message = Packet [B.ByteString]
+ | CheckFailed B.ByteString
+ | CheckSuccess [B.ByteString]
+ deriving Show
+
+serverAddress = "netserver.hedgewars.org"
+protocolNumber = "43"
+
+
+engineListener :: Chan Message -> Handle -> IO ()
+engineListener coreChan h = do
+ output <- liftM lines $ hGetContents h
+ debugM "Engine" $ show output
+ if isNothing $ L.find start output then
+ writeChan coreChan $ CheckFailed "No stats msg"
+ else
+ writeChan coreChan $ CheckSuccess []
+ where
+ start = flip L.elem ["WINNERS", "DRAW"]
+
+
+checkReplay :: Chan Message -> [B.ByteString] -> IO ()
+checkReplay coreChan msgs = do
+ tempDir <- getTemporaryDirectory
+ (fileName, h) <- openBinaryTempFile tempDir "checker-demo"
+ B.hPut h . BW.pack . concat . map (fromJust . Base64.decode . B.unpack) $ msgs
+ hFlush h
+ hClose h
+
+ (_, Just hOut, _, _) <- createProcess (proc "/usr/home/unC0Rr/Sources/Hedgewars/Releases/0.9.18/bin/hwengine"
+ ["/usr/home/unC0Rr/.hedgewars"
+ , "/usr/home/unC0Rr/Sources/Hedgewars/Releases/0.9.18/share/hedgewars/Data"
+ , fileName
+ , "--set-audio"
+ , "0"
+ , "0"
+ , "0"
+ ])
+ {std_out = CreatePipe}
+ hSetBuffering hOut LineBuffering
+ void $ forkIO $ engineListener coreChan hOut
+
+
+takePacks :: State B.ByteString [[B.ByteString]]
+takePacks = do
+ modify (until (not . B.isPrefixOf pDelim) (B.drop 2))
+ packet <- state $ B.breakSubstring pDelim
+ buf <- get
+ if B.null buf then put packet >> return [] else
+ if B.null packet then return [] else do
+ packets <- takePacks
+ return (B.splitWith (== '\n') packet : packets)
+ where
+ pDelim = "\n\n"
+
+
+recvLoop :: Socket -> Chan Message -> IO ()
+recvLoop s chan =
+ ((receiveWithBufferLoop B.empty >> return "Connection closed")
+ `Exception.catch` (\(e :: Exception.SomeException) -> return . B.pack . show $ e)
+ )
+ >>= disconnected
+ where
+ disconnected msg = writeChan chan $ Packet ["BYE", msg]
+ receiveWithBufferLoop recvBuf = do
+ recvBS <- recv s 4096
+ unless (B.null recvBS) $ do
+ let (packets, newrecvBuf) = runState takePacks $ B.append recvBuf recvBS
+ forM_ packets sendPacket
+ receiveWithBufferLoop $ B.copy newrecvBuf
+
+ sendPacket packet = writeChan chan $ Packet packet
+
+
+session :: B.ByteString -> B.ByteString -> Socket -> IO ()
+session l p s = do
+ noticeM "Core" "Connected"
+ coreChan <- newChan
+ forkIO $ recvLoop s coreChan
+ forever $ do
+ p <- readChan coreChan
+ case p of
+ Packet p -> do
+ debugM "Network" $ "Recv: " ++ show p
+ onPacket coreChan p
+ CheckFailed msg -> do
+ warningM "Check" "Check failed"
+ answer ["CHECKED", "FAIL", msg]
+ answer ["READY"]
+ CheckSuccess msgs -> do
+ warningM "Check" "Check succeeded"
+ answer ("CHECKED" : "OK" : msgs)
+ answer ["READY"]
+ where
+ answer :: [B.ByteString] -> IO ()
+ answer p = do
+ debugM "Network" $ "Send: " ++ show p
+ sendAll s $ B.unlines p `B.snoc` '\n'
+ onPacket :: Chan Message -> [B.ByteString] -> IO ()
+ onPacket _ ("CONNECTED":_) = do
+ answer ["CHECKER", protocolNumber, l, p]
+ answer ["READY"]
+ onPacket _ ["PING"] = answer ["PONG"]
+ onPacket chan ("REPLAY":msgs) = do
+ checkReplay chan msgs
+ warningM "Check" "Started check"
+ onPacket _ ("BYE" : xs) = error $ show xs
+ onPacket _ _ = return ()
+
+
+main :: IO ()
+main = withSocketsDo $ do
+#if !defined(mingw32_HOST_OS)
+ installHandler sigPIPE Ignore Nothing
+ installHandler sigCHLD Ignore Nothing
+#endif
+
+ updateGlobalLogger "Core" (setLevel DEBUG)
+ updateGlobalLogger "Network" (setLevel DEBUG)
+ updateGlobalLogger "Check" (setLevel DEBUG)
+ updateGlobalLogger "Engine" (setLevel DEBUG)
+
+ Right (login, password) <- runErrorT $ do
+ d <- liftIO $ getHomeDirectory
+ conf <- join . liftIO . CF.readfile CF.emptyCP $ d ++ "/.hedgewars/hedgewars.ini"
+ l <- CF.get conf "net" "nick"
+ p <- CF.get conf "net" "passwordhash"
+ return (B.pack l, B.pack p)
+
+
+ Exception.bracket
+ setupConnection
+ (\s -> noticeM "Core" "Shutting down" >> sClose s)
+ (session login password)
+ where
+ setupConnection = do
+ noticeM "Core" "Connecting to the server..."
+
+ proto <- getProtocolNumber "tcp"
+ let hints = defaultHints { addrFlags = [AI_ADDRCONFIG, AI_CANONNAME] }
+ (addr:_) <- getAddrInfo (Just hints) (Just serverAddress) Nothing
+ let (SockAddrInet _ host) = addrAddress addr
+ sock <- socket AF_INET Stream proto
+ connect sock (SockAddrInet 46631 host)
+ return sock
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/RoomsAndClients.hs
--- a/gameServer/RoomsAndClients.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/RoomsAndClients.hs Fri Feb 22 05:05:32 2013 +0100
@@ -23,6 +23,7 @@
room'sM,
allClientsM,
clientsM,
+ roomsM,
roomClientsM,
roomClientsIndicesM,
withRoomsAndClients,
@@ -160,6 +161,9 @@
clientsM :: MRoomsAndClients r c -> IO [c]
clientsM (MRoomsAndClients (_, clients)) = indicesM clients >>= mapM (liftM client' . readElem clients)
+roomsM :: MRoomsAndClients r c -> IO [r]
+roomsM (MRoomsAndClients (rooms, _)) = indicesM rooms >>= mapM (liftM room' . readElem rooms)
+
roomClientsIndicesM :: MRoomsAndClients r c -> RoomIndex -> IO [ClientIndex]
roomClientsIndicesM (MRoomsAndClients (rooms, _)) (RoomIndex ri) = liftM roomClients' (rooms `readElem` ri)
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/ServerState.hs
--- a/gameServer/ServerState.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/ServerState.hs Fri Feb 22 05:05:32 2013 +0100
@@ -5,6 +5,7 @@
ServerState(..),
client's,
allClientsS,
+ allRoomsS,
roomClientsS,
sameProtoClientsS,
io
@@ -40,6 +41,9 @@
allClientsS :: StateT ServerState IO [ClientInfo]
allClientsS = gets roomsClients >>= liftIO . clientsM
+allRoomsS :: StateT ServerState IO [RoomInfo]
+allRoomsS = gets roomsClients >>= liftIO . roomsM
+
roomClientsS :: RoomIndex -> StateT ServerState IO [ClientInfo]
roomClientsS ri = do
rnc <- gets roomsClients
@@ -49,6 +53,6 @@
sameProtoClientsS p = liftM f allClientsS
where
f = filter (\c -> clientProto c == p)
-
+
io :: IO a -> StateT ServerState IO a
io = liftIO
diff -r d5d5e1698554 -r 1dedcc37bfe8 gameServer/Utils.hs
--- a/gameServer/Utils.hs Sun Nov 18 01:06:01 2012 +0400
+++ b/gameServer/Utils.hs Fri Feb 22 05:05:32 2013 +0100
@@ -118,10 +118,10 @@
cutHost = B.intercalate "." . flip (++) ["*","*"] . List.take 2 . B.split '.'
caseInsensitiveCompare :: B.ByteString -> B.ByteString -> Bool
-caseInsensitiveCompare a b = f a == f b
- where
- f = map Char.toUpper . UTF8.toString
+caseInsensitiveCompare a b = upperCase a == upperCase b
+upperCase :: B.ByteString -> B.ByteString
+upperCase = UTF8.fromString . map Char.toUpper . UTF8.toString
roomInfo :: B.ByteString -> RoomInfo -> [B.ByteString]
roomInfo n r = [
@@ -134,3 +134,6 @@
head (Map.findWithDefault ["Default"] "SCHEME" (params r)),
head (Map.findWithDefault ["Default"] "AMMO" (params r))
]
+
+loc :: B.ByteString -> B.ByteString
+loc = id
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/ArgParsers.inc
--- a/hedgewars/ArgParsers.inc Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/ArgParsers.inc Fri Feb 22 05:05:32 2013 +0100
@@ -16,232 +16,333 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*)
+procedure GciEasterEgg;
+begin
+ WriteLn(stdout, ' ');
+ WriteLn(stdout, ' /\\\\\\\\\\\\ /\\\\\\\\\ /\\\\\\\\\\\ ');
+ WriteLn(stdout, ' /\\\////////// /\\\//////// \/////\\\/// ');
+ WriteLn(stdout, ' /\\\ /\\\/ \/\\\ ');
+ WriteLn(stdout, ' \/\\\ /\\\\\\\ /\\\ \/\\\ ');
+ WriteLn(stdout, ' \/\\\ \/////\\\ \/\\\ \/\\\ ');
+ WriteLn(stdout, ' \/\\\ \/\\\ \//\\\ \/\\\ ');
+ WriteLn(stdout, ' \/\\\ \/\\\ \///\\\ \/\\\ ');
+ WriteLn(stdout, ' \/\\\\\\\\\\\\\/ \////\\\\\\\\\ /\\\\\\\\\\\ ');
+ WriteLn(stdout, ' \///////////// \///////// \/////////// ');
+ WriteLn(stdout, ' ');
+ WriteLn(stdout, ' Command Line Parser Implementation by a Google Code-In Student ');
+ WriteLn(stdout, ' ASCII Art easter egg idea by @sheepluva ');
+ WriteLn(stdout, ' ');
+end;
-procedure internalStartGameWithParameters();
-var tmp: LongInt;
+procedure DisplayUsage;
+begin
+ WriteLn(stdout, 'Usage: hwengine [options]');
+ WriteLn(stdout, '');
+ WriteLn(stdout, 'where [options] can be any of the following:');
+ WriteLn(stdout, ' --prefix [path to folder]');
+ WriteLn(stdout, ' --user-prefix [path to folder]');
+ WriteLn(stdout, ' --locale [name of language file]');
+ WriteLn(stdout, ' --nick [string]');
+ WriteLn(stdout, ' --fullscreen-width [fullscreen width in pixels]');
+ WriteLn(stdout, ' --fullscreen-height [fullscreen height in pixels]');
+ WriteLn(stdout, ' --width [window width in pixels]');
+ WriteLn(stdout, ' --height [window height in pixels]');
+ WriteLn(stdout, ' --volume [sound level]');
+ WriteLn(stdout, ' --frame-interval [milliseconds]');
+ Writeln(stdout, ' --stereo [value]');
+ WriteLn(stdout, ' --raw-quality [flags]');
+ WriteLn(stdout, ' --low-quality');
+ WriteLn(stdout, ' --nomusic');
+ WriteLn(stdout, ' --nosound');
+ WriteLn(stdout, ' --fullscreen');
+ WriteLn(stdout, ' --showfps');
+ WriteLn(stdout, ' --altdmg');
+ WriteLn(stdout, ' --stats-only');
+ WriteLn(stdout, ' --help');
+ WriteLn(stdout, '');
+ WriteLn(stdout, 'For more detailed help and examples go to:');
+ WriteLn(stdout, 'http://code.google.com/p/hedgewars/wiki/CommandLineOptions');
+ GameType:= gmtSyntax;
+end;
+
+procedure setDepth(var paramIndex: LongInt);
+begin
+ WriteLn(stdout, 'WARNING: --depth is a deprecated command, which could be removed in a future version!');
+ WriteLn(stdout, ' This option no longer does anything, please consider removing it');
+ WriteLn(stdout, '');
+ inc(ParamIndex);
+end;
+
+procedure statsOnlyGame;
+begin
+ cOnlyStats:= true;
+ cReducedQuality:= $FFFFFFFF xor rqLowRes;
+ SetSound(false);
+ SetMusic(false);
+ SetVolume(0);
+end;
+
+procedure setIpcPort(port: LongInt; var wrongParameter:Boolean);
begin
- UserPathPrefix:= ParamStr(1);
- cScreenWidth:= StrToInt(ParamStr(2));
- cScreenHeight:= StrToInt(ParamStr(3));
- cBits:= StrToInt(ParamStr(4));
- ipcPort:= StrToInt(ParamStr(5));
- cFullScreen:= ParamStr(6) = '1';
- SetSound(ParamStr(7) = '1');
- SetMusic(ParamStr(8) = '1');
- SetVolume(StrToInt(ParamStr(9)));
- cTimerInterval:= StrToInt(ParamStr(10));
- PathPrefix:= ParamStr(11);
- cShowFPS:= ParamStr(12) = '1';
- cAltDamage:= ParamStr(13) = '1';
- UserNick:= DecodeBase64(ParamStr(14));
- cReducedQuality:= StrToInt(ParamStr(15));
- tmp:= StrToInt(ParamStr(16));
+ if isInternal then
+ ipcPort := port
+ else
+ begin
+ WriteLn(stderr, 'ERROR: use of --port is not allowed');
+ wrongParameter := true;
+ end
+end;
+
+function parseNick(nick: String): String;
+begin
+ if isInternal then
+ parseNick:= DecodeBase64(nick)
+ else
+ parseNick:= nick;
+end;
+
+procedure setStereoMode(tmp: LongInt);
+begin
GrayScale:= false;
- if (tmp > 9) and (tmp < 16) then
+{$IFDEF USE_S3D_RENDERING}
+ if (tmp > 6) and (tmp < 13) then
begin
+ // set the gray anaglyph rendering
GrayScale:= true;
- cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp-9)))
+ cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp-6)))
end
- else if tmp <= 9 then
+ else if tmp <= 6 then
+ // set the fullcolor anaglyph
cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp)))
- else
+ else
+ // any other mode
cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp-6)));
- cLocaleFName:= ParamStr(17);
+{$ELSE}
+ tmp:= tmp;
+ cStereoMode:= smNone;
+{$ENDIF}
+end;
+
+procedure startVideoRecording(var paramIndex: LongInt);
+begin
+ // Silence the hint that appears when USE_VIDEO_RECORDING is not defined
+ paramIndex:= paramIndex;
+{$IFDEF USE_VIDEO_RECORDING}
+ GameType:= gmtRecord;
+ inc(paramIndex);
+ cVideoFramerateNum:= StrToInt(ParamStr(paramIndex)); inc(paramIndex);
+ cVideoFramerateDen:= StrToInt(ParamStr(paramIndex)); inc(paramIndex);
+ RecPrefix:= ParamStr(paramIndex); inc(paramIndex);
+ cAVFormat:= ParamStr(paramIndex); inc(paramIndex);
+ cVideoCodec:= ParamStr(paramIndex); inc(paramIndex);
+ cVideoQuality:= StrToInt(ParamStr(paramIndex)); inc(paramIndex);
+ cAudioCodec:= ParamStr(paramIndex); inc(paramIndex);
+{$ENDIF}
+end;
+
+function getLongIntParameter(str:String; var paramIndex:LongInt; var wrongParameter:Boolean): LongInt;
+var tmpInt, c: LongInt;
+begin
+ inc(paramIndex);
+ val(str, tmpInt, c);
+ wrongParameter:= c <> 0;
+ if wrongParameter then
+ WriteLn(stderr, 'ERROR: '+ParamStr(paramIndex-1)+' expects a number, you passed "'+str+'"');
+ getLongIntParameter:= tmpInt;
+end;
+
+function getStringParameter(str:String; var paramIndex:LongInt; var wrongParameter:Boolean): String;
+begin
+ inc(paramIndex);
+ wrongParameter:= (str='') or (Copy(str,1,2) = '--');
+ if wrongParameter then
+ WriteLn(stderr, 'ERROR: '+ParamStr(paramIndex-1)+' expects a string, you passed "'+str+'"');
+ getStringParameter:= str;
end;
-{$IFDEF USE_VIDEO_RECORDING}
-procedure internalStartVideoRecordingWithParameters();
+
+procedure parseClassicParameter(cmdArray: Array of String; size:LongInt; var paramIndex:LongInt); Forward;
+
+function parseParameter(cmd:String; arg:String; var paramIndex:LongInt): Boolean;
+const videoArray: Array [1..5] of String = ('--fullscreen-width','--fullscreen-height', '--width', '--height', '--depth');
+ audioArray: Array [1..3] of String = ('--volume','--nomusic','--nosound');
+ otherArray: Array [1..3] of String = ('--locale','--fullscreen','--showfps');
+ mediaArray: Array [1..10] of String = ('--fullscreen-width', '--fullscreen-height', '--width', '--height', '--depth', '--volume','--nomusic','--nosound','--locale','--fullscreen');
+ allArray: Array [1..14] of String = ('--fullscreen-width','--fullscreen-height', '--width', '--height', '--depth','--volume','--nomusic','--nosound','--locale','--fullscreen','--showfps','--altdmg','--frame-interval','--low-quality');
+ reallyAll: array[0..30] of shortstring = (
+ '--prefix', '--user-prefix', '--locale', '--fullscreen-width', '--fullscreen-height', '--width',
+ '--height', '--frame-interval', '--volume','--nomusic', '--nosound',
+ '--fullscreen', '--showfps', '--altdmg', '--low-quality', '--raw-quality', '--stereo', '--nick',
+ {deprecated} '--depth', '--set-video', '--set-audio', '--set-other', '--set-multimedia', '--set-everything',
+ {internal} '--internal', '--port', '--recorder', '--landpreview',
+ {misc} '--stats-only', '--gci', '--help');
+var cmdIndex: byte;
+begin
+ parseParameter:= false;
+ cmdIndex:= 0;
+
+ //NOTE: Any update to the list of parameters must be reflected in the case statement below, the reallyAll array above,
+ // the the DisplayUsage() procedure, the HWForm::getDemoArguments() function, and the online wiki
+
+ while (cmdIndex <= High(reallyAll)) and (cmd <> reallyAll[cmdIndex]) do inc(cmdIndex);
+ case cmdIndex of
+ {--prefix} 0 : PathPrefix := getStringParameter (arg, paramIndex, parseParameter);
+ {--user-prefix} 1 : UserPathPrefix := getStringParameter (arg, paramIndex, parseParameter);
+ {--locale} 2 : cLocaleFName := getStringParameter (arg, paramIndex, parseParameter);
+ {--fullscreen-width} 3 : cFullscreenWidth := getLongIntParameter(arg, paramIndex, parseParameter);
+ {--fullscreen-height} 4 : cFullscreenHeight := getLongIntParameter(arg, paramIndex, parseParameter);
+ {--width} 5 : cWindowedWidth := getLongIntParameter(arg, paramIndex, parseParameter);
+ {--height} 6 : cWindowedHeight := getLongIntParameter(arg, paramIndex, parseParameter);
+ {--frame-interval} 7 : cTimerInterval := getLongIntParameter(arg, paramIndex, parseParameter);
+ {--volume} 8 : SetVolume ( getLongIntParameter(arg, paramIndex, parseParameter) );
+ {--nomusic} 9 : SetMusic ( false );
+ {--nosound} 10 : SetSound ( false );
+ {--fullscreen} 11 : cFullScreen := true;
+ {--showfps} 12 : cShowFPS := true;
+ {--altdmg} 13 : cAltDamage := true;
+ {--low-quality} 14 : cReducedQuality := $FFFFFFFF xor rqLowRes;
+ {--raw-quality} 15 : cReducedQuality := getLongIntParameter(arg, paramIndex, parseParameter);
+ {--stereo} 16 : setStereoMode ( getLongIntParameter(arg, paramIndex, parseParameter) );
+ {--nick} 17 : UserNick := parseNick( getStringParameter(arg, paramIndex, parseParameter) );
+ {deprecated options}
+ {--depth} 18 : setDepth(paramIndex);
+ {--set-video} 19 : parseClassicParameter(videoArray,5,paramIndex);
+ {--set-audio} 20 : parseClassicParameter(audioArray,3,paramIndex);
+ {--set-other} 21 : parseClassicParameter(otherArray,3,paramIndex);
+ {--set-multimedia} 22 : parseClassicParameter(mediaArray,10,paramIndex);
+ {--set-everything} 23 : parseClassicParameter(allArray,14,paramIndex);
+ {"internal" options}
+ {--internal} 24 : {$IFDEF HWLIBRARY}isInternal:= true{$ENDIF};
+ {--port} 25 : setIpcPort( getLongIntParameter(arg, paramIndex, parseParameter), parseParameter );
+ {--recorder} 26 : startVideoRecording(paramIndex);
+ {--landpreview} 27 : GameType := gmtLandPreview;
+ {anything else}
+ {--stats-only} 28 : statsOnlyGame();
+ {--gci} 29 : GciEasterEgg();
+ {--help} 30 : DisplayUsage();
+ else
+ begin
+ //Asusme the first "non parameter" is the replay file, anything else is invalid
+ if (recordFileName = '') and (Copy(cmd,1,2) <> '--') then
+ recordFileName := cmd
+ else
+ begin
+ WriteLn(stderr, '"'+cmd+'" is not a valid option');
+ parseParameter:= true;
+ end;
+ end;
+ end;
+end;
+
+procedure parseClassicParameter(cmdArray: Array of String; size:LongInt; var paramIndex:LongInt);
+var index, tmpInt: LongInt;
+ isBool, isValid: Boolean;
+ cmd, arg, newSyntax: String;
begin
- internalStartGameWithParameters();
- GameType:= gmtRecord;
- cVideoFramerateNum:= StrToInt(ParamStr(18));
- cVideoFramerateDen:= StrToInt(ParamStr(19));
- RecPrefix:= ParamStr(20);
- cAVFormat:= ParamStr(21);
- cVideoCodec:= ParamStr(22);
- cVideoQuality:= StrToInt(ParamStr(23));
- cAudioCodec:= ParamStr(24);
+ WriteLn(stdout, 'WARNING: you are using a deprecated command, which could be removed in a future version!');
+ WriteLn(stdout, ' Consider updating to the latest syntax, which is much more flexible!');
+ WriteLn(stdout, ' Run `hwegine --help` to learn it!');
+ WriteLn(stdout, '');
+
+ index:= 0;
+ tmpInt:= 1;
+ while (index < size) do
+ begin
+ newSyntax:= '';
+ inc(paramIndex);
+ cmd:= cmdArray[index];
+ arg:= ParamStr(paramIndex);
+ isValid:= (cmd<>'--depth');
+
+ // check if the parameter is a boolean one
+ isBool:= (cmd = '--nomusic') or (cmd = '--nosound') or (cmd = '--fullscreen') or (cmd = '--showfps') or (cmd = '--altdmg');
+ if isBool and (arg='0') then
+ isValid:= false;
+ if (cmd='--nomusic') or (cmd='--nosound') then
+ isValid:= not isValid;
+
+ if isValid then
+ begin
+ parseParameter(cmd, arg, tmpInt);
+ newSyntax := newSyntax + cmd + ' ';
+ if not isBool then
+ newSyntax := newSyntax + arg + ' ';
+ end;
+ inc(index);
+ end;
+
+ WriteLn(stdout, 'Attempted to automatically convert to the new syntax:');
+ WriteLn(stdout, newSyntax);
+ WriteLn(stdout, '');
+end;
+
+procedure parseCommandLine{$IFDEF HWLIBRARY}(argc: LongInt; argv: PPChar){$ENDIF};
+var paramIndex: LongInt;
+ paramTotal: LongInt;
+ index, nextIndex: LongInt;
+ wrongParameter: boolean;
+//var tmpInt: LongInt;
+begin
+ paramIndex:= {$IFDEF HWLIBRARY}0{$ELSE}1{$ENDIF};
+ paramTotal:= {$IFDEF HWLIBRARY}argc-1{$ELSE}ParamCount{$ENDIF}; //-1 because pascal enumeration is inclusive
+ (*
+ WriteLn(stdout, 'total parameters: ' + inttostr(paramTotal));
+ tmpInt:= 0;
+ while (tmpInt <= paramTotal) do
+ begin
+ WriteLn(stdout, inttostr(tmpInt) + ': ' + {$IFDEF HWLIBRARY}argv[tmpInt]{$ELSE}paramCount(tmpInt){$ENDIF});
+ inc(tmpInt);
+ end;
+ *)
+ wrongParameter:= false;
+ while (paramIndex <= paramTotal) do
+ begin
+ // avoid going past the number of paramTotal (esp. w/ library)
+ index:= paramIndex;
+ if index = paramTotal then nextIndex:= index
+ else nextIndex:= index+1;
+ {$IFDEF HWLIBRARY}
+ wrongParameter:= parseParameter( argv[index], argv[nextIndex], paramIndex);
+ {$ELSE}
+ wrongParameter:= parseParameter( ParamStr(index), ParamStr(nextIndex), paramIndex);
+ {$ENDIF}
+ inc(paramIndex);
+ end;
+ if wrongParameter = true then
+ GameType:= gmtSyntax;
+end;
+
+{$IFNDEF HWLIBRARY}
+procedure GetParams;
+begin
+ isInternal:= (ParamStr(1) = '--internal');
+
+ UserPathPrefix := '.';
+ PathPrefix := cDefaultPathPrefix;
+ recordFileName := '';
+ parseCommandLine();
+
+ if (isInternal) and (ParamCount<=1) then
+ begin
+ WriteLn(stderr, '--internal should not be manually used');
+ GameType := gmtSyntax;
+ end;
+
+ if (not isInternal) and (recordFileName = '') then
+ begin
+ WriteLn(stderr, 'You must specify a replay file');
+ GameType := gmtSyntax;
+ end
+ else if (recordFileName <> '') then
+ WriteLn(stdout, 'Attempting to play demo file "' + recordFilename + '"');
+
+ if (GameType = gmtSyntax) then
+ WriteLn(stderr, 'Please use --help to see possible arguments and their usage');
+
+ (*
+ WriteLn(stdout,'PathPrefix: ' + PathPrefix);
+ WriteLn(stdout,'UserPathPrefix: ' + UserPathPrefix);
+ *)
end;
{$ENDIF}
-procedure setVideo(screenWidth: LongInt; screenHeight: LongInt; bitsStr: LongInt);
-begin
- cScreenWidth:= screenWidth;
- cScreenHeight:= screenHeight;
- cBits:= bitsStr
-end;
-
-procedure setVideoWithParameters(screenWidthParam: string; screenHeightParam: string; bitsParam: string);
-var screenWidthAsInt, screenHeightAsInt, bitsStrAsInt, c: LongInt;
-begin
- val(screenWidthParam, screenWidthAsInt, c);
- val(screenHeightParam, screenHeightAsInt, c);
- val(bitsParam, bitsStrAsInt, c);
- setVideo(screenWidthAsInt,screenHeightAsInt,bitsStrAsInt)
-end;
-
-procedure setOtherOptions(languageFile: string; fullScreen: boolean);
-begin
- cLocaleFName:= languageFile;
- cFullScreen:= fullScreen
-end;
-
-procedure setShowFPS(showFPS: boolean);
-begin
- cShowFPS:= showFPS
-end;
-
-procedure setOtherOptionsWithParameters(languageFileParam: string; fullScreenParam: string; showFPSParam: string);
-var fullScreen, showFPS: boolean;
-begin
- fullScreen:= fullScreenParam = '1';
- showFPS:= showFPSParam = '1';
- setOtherOptions(languageFileParam,fullScreen);
- setShowFPS(showFPS)
-end;
-
-procedure setAudio(initialVolume: LongInt; musicEnabled: boolean; soundEnabled: boolean);
-begin
- SetVolume(initialVolume);
- SetMusic(musicEnabled);
- SetSound(soundEnabled);
-end;
-
-procedure setAudioWithParameters(initialVolumeParam: string; musicEnabledParam: string; soundEnabledParam: string);
-var initialVolumeAsInt, c: LongInt;
- musicEnabled, soundEnabled: boolean;
-begin
- val(initialVolumeParam, initialVolumeAsInt, c);
- musicEnabled:= musicEnabledParam = '1';
- soundEnabled:= soundEnabledParam = '1';
- setAudio(initialVolumeAsInt,musicEnabled, soundEnabled)
-end;
-
-procedure setMultimediaOptionsWithParameters(screenWidthParam, screenHeightParam, bitsParam: string;
- initialVolumeParam, musicEnabledParam, soundEnabledParam: string;
- languageFileParam, fullScreenParam: string);
-begin
- setVideoWithParameters(screenWidthParam,screenHeightParam, bitsParam);
- setAudioWithParameters(initialVolumeParam,musicEnabledParam,soundEnabledParam);
- setOtherOptions(languageFileParam,fullScreenParam = '1')
-end;
-
-procedure setAltDamageTimerValueAndQuality(altDamage: boolean; timeIterval: LongInt; reducedQuality: boolean);
-begin
- cAltDamage:= altDamage;
- cTimerInterval:= timeIterval;
- if (reducedQuality) then //HACK
- cReducedQuality:= $FFFFFFFF xor rqLowRes
-end;
-
-procedure setAllOptionsWithParameters(screenWidthParam:string; screenHeightParam:string; bitsParam:string;
- initialVolumeParam:string; musicEnabledParam:string; soundEnabledParam:string;
- languageFileParam:string; fullScreenParam:string; showFPSParam:string;
- altDamageParam:string; timeItervalParam:string; reducedQualityParam: string);
-var showFPS, altDamage, reducedQuality: boolean;
- timeIterval, c: LongInt;
-begin
- setMultimediaOptionsWithParameters(screenWidthParam,screenHeightParam, bitsParam,
- initialVolumeParam,musicEnabledParam,soundEnabledParam,
- languageFileParam,fullScreenParam);
- showFPS := showFPSParam = '1';
- setShowFPS(showFPS);
-
- altDamage:= altDamageParam = '1';
- val(timeItervalParam, timeIterval, c);
- reducedQuality:= reducedQualityParam = '1';
- setAltDamageTimerValueAndQuality(altDamage,timeIterval,reducedQuality);
-end;
-
-procedure playReplayFileWithParameters();
-var paramIndex: LongInt;
- wrongParameter: boolean;
-begin
- UserPathPrefix:= ParamStr(1);
- PathPrefix:= ParamStr(2);
- recordFileName:= ParamStr(3);
- paramIndex:= 4;
- wrongParameter:= false;
- while (paramIndex <= ParamCount) and (not wrongParameter) do
- begin
- if ParamStr(paramIndex) = '--set-video' then
-//--set-video [screen width] [screen height] [color dept]
- begin
- if(ParamCount-paramIndex < 3) then
- begin
- wrongParameter:= true;
- GameType:= gmtSyntax
- end;
- setVideoWithParameters(ParamStr(paramIndex+1), ParamStr(paramIndex+2), ParamStr(paramIndex+3));
- paramIndex:= paramIndex + 4
- end
- else
-//--set-audio [volume] [enable music] [enable sounds]
- if ParamStr(paramIndex) = '--set-audio' then
- begin
- if(ParamCount-paramIndex < 3) then
- begin
- wrongParameter := true;
- GameType:= gmtSyntax
- end;
- setAudioWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2), ParamStr(paramIndex+3));
- paramIndex:= paramIndex + 4
- end
- else
-// --set-other [language file] [full screen] [show FPS]
- if ParamStr(paramIndex) = '--set-other' then
- begin
- if(ParamCount-paramIndex < 3) then
- begin
- wrongParameter:= true;
- GameType:= gmtSyntax
- end;
- setOtherOptionsWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2), ParamStr(paramIndex+3));
- paramIndex:= paramIndex + 4
- end
- else
-//--set-multimedia [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen]
- if ParamStr(paramIndex) = '--set-multimedia' then
- begin
- if ParamCount-paramIndex < 8 then
- begin
- wrongParameter:= true;
- GameType:= gmtSyntax
- end;
- setMultimediaOptionsWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2),ParamStr(paramIndex+3),
- ParamStr(paramIndex+4),ParamStr(paramIndex+5),ParamStr(paramIndex+6),
- ParamStr(paramIndex+7),ParamStr(paramIndex+8));
- paramIndex:= paramIndex + 9
- end
- else
-//--set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]
- if ParamStr(paramIndex) = '--set-everything' then
- begin
- if ParamCount-paramIndex < 12 then
- begin
- wrongParameter:= true;
- GameType:= gmtSyntax
- end;
- setAllOptionsWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2),ParamStr(paramIndex+3),
- ParamStr(paramIndex+4),ParamStr(paramIndex+5),ParamStr(paramIndex+6),
- ParamStr(paramIndex+7),ParamStr(paramIndex+8),ParamStr(paramIndex+9),
- ParamStr(paramIndex+10),ParamStr(paramIndex+11),ParamStr(paramIndex+12));
- paramIndex:= paramIndex + 13
- end
- else
- if ParamStr(paramIndex) = '--stats-only' then
- begin
- cOnlyStats:= true;
- SetSound(false);
- SetMusic(false);
- cReducedQuality:= $FFFFFFFF xor rqLowRes; // HACK
- paramIndex:= paramIndex + 1
- end
- else
- begin
- wrongParameter:= true;
- GameType:= gmtSyntax
- end
- end
-end;
-
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/CMakeLists.txt
--- a/hedgewars/CMakeLists.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/CMakeLists.txt Fri Feb 22 05:05:32 2013 +0100
@@ -4,13 +4,24 @@
find_package(SDL_ttf)
find_package(SDL_mixer)
-include(${CMAKE_MODULE_PATH}/FindSDL_Extras.cmake)
+include(${CMAKE_SOURCE_DIR}/cmake_modules/FindSDL_Extras.cmake)
configure_file(${hedgewars_SOURCE_DIR}/hedgewars/config.inc.in ${CMAKE_CURRENT_BINARY_DIR}/config.inc)
#SOURCE AND PROGRAMS SECTION
-set(hwengine_project ${hedgewars_SOURCE_DIR}/hedgewars/hwengine.pas)
-set(engine_output_name "hwengine")
+if(${BUILD_ENGINE_LIBRARY})
+ set(engine_output_name "${CMAKE_SHARED_LIBRARY_PREFIX}hwengine${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ set(hwengine_project ${hedgewars_SOURCE_DIR}/hedgewars/hwLibrary.pas)
+else()
+ set(engine_output_name "hwengine${CMAKE_EXECUTABLE_SUFFIX}")
+ set(hwengine_project ${hedgewars_SOURCE_DIR}/hedgewars/hwengine.pas)
+endif()
+
+if (APPLE)
+ set(required_fpc_version 2.6)
+else()
+ set(required_fpc_version 2.2)
+endif()
set(engine_sources
${hwengine_project}
@@ -53,7 +64,6 @@
uLandTexture.pas
uLocale.pas
uMisc.pas
- uMobile.pas
uPhysFSLayer.pas
uRandom.pas
uRender.pas
@@ -80,53 +90,34 @@
${CMAKE_CURRENT_BINARY_DIR}/config.inc
)
-if(BUILD_ENGINE_LIBRARY)
- message(STATUS "Engine will be built as library (experimental)")
- set(hwengine_project ${hedgewars_SOURCE_DIR}/hedgewars/hwLibrary.pas)
- set(pascal_flags "-dHWLIBRARY" ${pascal_flags})
+if(${BUILD_ENGINE_LIBRARY})
+ message(WARNING "Engine will be built as library (experimental)")
+ list(APPEND pascal_flags "-dHWLIBRARY")
# create position independent code, only required for x68_64 builds, similar to -fPIC
if(CMAKE_SIZEOF_VOID_P MATCHES "8")
- set(pascal_flags "-Cg" ${pascal_flags})
+ list(APPEND pascal_flags "-Cg")
endif(CMAKE_SIZEOF_VOID_P MATCHES "8")
# due to compiler/linker issues on Max OS X 10.6 -k-no_order_inits is needed to avoid linking fail
- if(APPLE AND current_macosx_version GREATER "10.5")
- set(pascal_flags "-k-no_order_inits" ${pascal_flags})
+ if(APPLE AND current_macosx_version VERSION_GREATER "10.5")
+ list(APPEND pascal_flags "-k-no_order_inits")
endif()
-
- if (APPLE)
- set(engine_output_name "hwengine.dylib")
- endif (APPLE)
-endif(BUILD_ENGINE_LIBRARY)
-
-# doesn't work for some reason (doesn't find symbols)
-#set(pascal_flags "-k${LIBRARY_OUTPUT_PATH}/libphysfs.a" ${pascal_flags})
-
-IF(FPC)
- set(fpc_executable ${FPC})
-ELSE()
- find_program(fpc_executable fpc)
-ENDIF()
-
-if(fpc_executable)
- exec_program(${fpc_executable} ARGS "-iV" OUTPUT_VARIABLE fpc_output)
-endif(fpc_executable)
-
-set(noexecstack_flags "-k-z" "-knoexecstack")
-file(WRITE ${EXECUTABLE_OUTPUT_PATH}/checkstack.pas "begin end.")
-
-exec_program(${fpc_executable} ${EXECUTABLE_OUTPUT_PATH}
- ARGS ${noexecstack_flags} checkstack.pas
- OUTPUT_VARIABLE noout
- RETURN_VALUE testnoexecstack
- )
-
-if(${testnoexecstack})
- set (noexecstack_flags "")
-endif(${testnoexecstack})
+ set(destination_dir ${target_library_install_dir})
+else(${BUILD_ENGINE_LIBRARY})
+ set(destination_dir ${target_binary_install_dir})
+endif(${BUILD_ENGINE_LIBRARY})
+# Check Freepascal version
+find_package(Freepascal)
+
+if (FPC_VERSION VERSION_LESS required_fpc_version)
+ message(FATAL_ERROR "Freepascal is too old, minimum version required is ${required_fpc_version}")
+endif()
+
+
+#DEPENDECIES AND EXECUTABLES SECTION
if(APPLE)
string(REGEX MATCH "[pP][pP][cC]+" powerpc_build "${CMAKE_OSX_ARCHITECTURES}")
string(REGEX MATCH "[iI]386+" i386_build "${CMAKE_OSX_ARCHITECTURES}")
@@ -137,68 +128,48 @@
endif()
#on OSX we need to provide the SDL_main() function when building as executable
- if(NOT BUILD_ENGINE_LIBRARY)
+ if(NOT ${BUILD_ENGINE_LIBRARY})
#let's look for the installed sdlmain file; if it is not found, let's build our own
find_package(SDL REQUIRED)
#remove the ";-framework Cocoa" from the SDL_LIBRARY variable
- string(REGEX REPLACE "(.*);-.*" "\\1" sdl_dir "${SDL_LIBRARY}")
+ string(REGEX REPLACE "(.*);-.*" "\\1" sdl_library_only "${SDL_LIBRARY}")
#find libsdmain.a
- find_file(SDLMAIN_LIB libSDLMain.a PATHS ${sdl_dir}/Resources/)
+ find_file(SDLMAIN_LIB libSDLMain.a PATHS ${sdl_library_only}/Resources/)
if(SDLMAIN_LIB MATCHES "SDLMAIN_LIB-NOTFOUND")
include_directories(${SDL_INCLUDE_DIR})
add_library (SDLmain STATIC SDLMain.m)
#add a dependency to the hwengine target
- set(engine_sources ${engine_sources} SDLmain)
+ list(APPEND engine_sources SDLmain)
set(SDLMAIN_LIB "${LIBRARY_OUTPUT_PATH}/libSDLmain.a")
endif()
- set(pascal_flags "-k${SDLMAIN_LIB}" ${pascal_flags})
+ list(APPEND pascal_flags "-k${SDLMAIN_LIB}")
endif()
+
+ #when you have multiple ld installation make sure you get the one bundled with the compiler
+ get_filename_component(compiler_dir ${CMAKE_C_COMPILER} PATH)
+ list(APPEND pascal_flags "-FD${compiler_dir}")
endif(APPLE)
-
-#PASCAL DETECTION SECTION
-string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" fpc_version "${fpc_output}")
-
-if(fpc_version)
- string(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" fpc_vers_major "${fpc_version}")
- string(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" fpc_vers_minor "${fpc_version}")
- string(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" fpc_vers_patch "${fpc_version}")
- message(STATUS "Found Freepascal: ${fpc_executable} (version ${fpc_vers_major}.${fpc_vers_minor})")
- math(EXPR fpc_version "${fpc_vers_major}*10000 + ${fpc_vers_minor}*100 + ${fpc_vers_patch}")
-
- if(fpc_version LESS "020200")
- message(FATAL_ERROR "Minimum required version of FreePascal is 2.2.0")
- elseif(APPLE AND (fpc_version LESS "020600"))
- message(FATAL_ERROR "Minimum required version of FreePascal is 2.6.0 on Mac OS X")
- endif()
-else()
- message(FATAL_ERROR "No FreePascal compiler found!")
-endif()
-
-
-#DEPENDECIES AND EXECUTABLES SECTION
if(NOT NOPNG)
find_package(PNG)
if(${PNG_FOUND})
- set(pascal_flags "-dPNG_SCREENSHOTS" ${pascal_flags})
+ list(APPEND pascal_flags "-dPNG_SCREENSHOTS")
if(APPLE) # fpc png unit doesn't pull the library (see bug 21833)
- set(pascal_flags "-k${PNG_LIBRARY}" ${pascal_flags})
+ list(APPEND pascal_flags "-k${PNG_LIBRARY}")
endif()
else()
- message(STATUS "Screenshots will be in BMP format because libpng was not found")
+ message(WARNING "Screenshots will be in BMP format because libpng was not found")
endif()
else()
message(STATUS "Screenshots will be in BMP format per user request")
endif()
-
#this command is a workaround to some inlining issues present in older FreePascal versions and fixed in 2.6
-if(fpc_version LESS "020600")
+if(FPC_VERSION VERSION_LESS "2.6")
#under some configurations CMAKE_BUILD_TOOL fails to pass on the jobserver, breaking parallel compilation
- #TODO: check if this is needed on windows too
if(UNIX)
set(SAFE_BUILD_TOOL $(MAKE))
else()
@@ -218,44 +189,50 @@
#TODO: convert avwrapper to .pas unit so we can skip this step
include_directories(${FFMPEG_INCLUDE_DIR})
- set(pascal_flags "-dUSE_VIDEO_RECORDING" ${pascal_flags})
+ list(APPEND pascal_flags "-dUSE_VIDEO_RECORDING")
IF (WIN32)
# there are some problems with linking our avwrapper as static lib, so link it as shared
add_library(avwrapper SHARED avwrapper.c)
target_link_libraries(avwrapper ${FFMPEG_LIBRARIES})
- install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}avwrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION ${target_dir})
+ install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}avwrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION ${target_library_install_dir})
ELSE()
add_library(avwrapper STATIC avwrapper.c)
- set(pascal_flags "-k${FFMPEG_LIBAVCODEC}" "-k${FFMPEG_LIBAVFORMAT}" "-k${FFMPEG_LIBAVUTIL}" ${pascal_flags})
+ list(APPEND pascal_flags "-k${FFMPEG_LIBAVCODEC}" "-k${FFMPEG_LIBAVFORMAT}" "-k${FFMPEG_LIBAVUTIL}")
ENDIF()
else()
- message(STATUS "Could NOT find FFMPEG/LibAV, video recording will be disabled")
+ message(WARNING "Could NOT find FFMPEG/LibAV, video recording will be disabled")
endif()
else()
message(STATUS "Video recording disabled by user")
endif()
-set(fpc_flags ${noexecstack_flags} ${pascal_flags} ${hwengine_project})
-IF(NOT APPLE)
+set(fpc_flags ${NOEXECSTACK_FLAGS} ${pascal_flags} ${hwengine_project})
+
+if(NOT APPLE)
#here is the command for standard executables or for shared library
- add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}${CMAKE_EXECUTABLE_SUFFIX}"
- COMMAND "${fpc_executable}"
- ARGS ${fpc_flags}
+ add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}"
+ COMMAND "${FPC_EXECUTABLE}"
+ ARGS ${fpc_flags} -o${engine_output_name}
MAIN_DEPENDENCY ${hwengine_project}
DEPENDS ${engine_sources}
)
-ELSE()
+else()
#these are the dependencies for building a universal binary on Mac OS X
foreach (build_arch ${powerpc_build} ${i386_build} ${x86_64_build})
- set(lipo_args_list "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}" ${lipo_args_list})
+ list(APPEND lipo_args_list "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}")
add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}"
- COMMAND "${fpc_executable}"
+ COMMAND "${FPC_EXECUTABLE}"
ARGS ${fpc_flags} -ohwengine.${build_arch} -P${build_arch}
MAIN_DEPENDENCY ${hwengine_project}
DEPENDS ${engine_sources}
)
add_custom_target(hwengine.${build_arch} ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}")
+ add_custom_command(TARGET hwengine.${build_arch} POST_BUILD
+ COMMAND "install_name_tool"
+ ARGS -id @executable_path/../Frameworks/${engine_output_name}
+ ${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}
+ )
endforeach()
add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}"
@@ -263,29 +240,28 @@
ARGS ${lipo_args_list} -create -output ${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}
DEPENDS ${lipo_args_list}
)
-ENDIF()
+endif()
-add_custom_target(${engine_output_name} ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}${CMAKE_EXECUTABLE_SUFFIX}")
+add_custom_target(hwengine ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}")
#when system Lua is not found we need to compile it before engine
if(NOT LUA_FOUND)
- add_dependencies(${engine_output_name} lua)
+ add_dependencies(hwengine lua)
endif()
# compile physfs before engine
-add_dependencies(${engine_output_name} physfs)
-add_dependencies(${engine_output_name} physfsrwops)
+add_dependencies(hwengine physfs)
#when ffmpeg/libav is found we need to compile it before engine
#TODO: convert avwrapper to .pas unit so we can skip this step
if(${FFMPEG_FOUND})
- add_dependencies(${engine_output_name} avwrapper)
+ add_dependencies(hwengine avwrapper)
endif()
#this command is a workaround to some inlining issues present in older FreePascal versions and fixed in 2.6
-if((fpc_version LESS "020600") AND (NOVIDEOREC OR NOT ${FFMPEG_FOUND}))
- add_dependencies(${engine_output_name} ENGINECLEAN)
+if((FPC_VERSION VERSION_LESS "2.6") AND (NOVIDEOREC OR NOT ${FFMPEG_FOUND}))
+ add_dependencies(hwengine ENGINECLEAN)
endif()
-install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_dir})
+install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}" DESTINATION ${destination_dir})
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/GSHandlers.inc
--- a/hedgewars/GSHandlers.inc Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/GSHandlers.inc Fri Feb 22 05:05:32 2013 +0100
@@ -298,7 +298,7 @@
procedure doStepBomb(Gear: PGear);
var
i, x, y: LongInt;
- dX, dY: hwFloat;
+ dX, dY, gdX: hwFloat;
vg: PVisualGear;
begin
AllInactive := false;
@@ -338,10 +338,11 @@
begin
x := hwRound(Gear^.X);
y := hwRound(Gear^.Y);
+ gdX:= Gear^.dX;
doMakeExplosion(x, y, 20, Gear^.Hedgehog, EXPLAutoSound);
for i:= 0 to 4 do
begin
- dX := rndSign(GetRandomf * _0_1) + Gear^.dX / 5;
+ dX := rndSign(GetRandomf * _0_1) + gdX / 5;
dY := (GetRandomf - _3) * _0_08;
FollowGear := AddGear(x, y, gtCluster, 0, dX, dY, 25)
end
@@ -350,10 +351,11 @@
begin
x := hwRound(Gear^.X);
y := hwRound(Gear^.Y);
+ gdX:= Gear^.dX;
doMakeExplosion(x, y, 75, Gear^.Hedgehog, EXPLAutoSound);
for i:= 0 to 5 do
begin
- dX := rndSign(GetRandomf * _0_1) + Gear^.dX / 5;
+ dX := rndSign(GetRandomf * _0_1) + gdX / 5;
dY := (GetRandomf - _1_5) * _0_3;
FollowGear:= AddGear(x, y, gtMelonPiece, 0, dX, dY, 75);
FollowGear^.DirAngle := i * 60
@@ -1691,7 +1693,7 @@
end
else
begin
- if (Gear^.Pos <> posCaseHealth) and (GameTicks and $3FF = 0) then // stir it up every second or so
+ if (Gear^.Pos <> posCaseHealth) and (GameTicks and $1FFF = 0) then // stir 'em up periodically
begin
gi := GearsList;
while gi <> nil do
@@ -2223,7 +2225,9 @@
begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
DeleteGear(Gear);
- performRumble();
+ with mobileRecord do
+ if (performRumble <> nil) and (not fastUntilLag) then
+ performRumble(kSystemSoundID_Vibrate);
exit
end;
if (GameTicks and $3F) = 0 then
@@ -2412,7 +2416,7 @@
////////////////////////////////////////////////////////////////////////////////
procedure doStepMortar(Gear: PGear);
var
- dX, dY: hwFloat;
+ dX, dY, gdX, gdY: hwFloat;
i: LongInt;
dxn, dyn: boolean;
begin
@@ -2423,14 +2427,16 @@
doStepFallingGear(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
+ gdX := Gear^.dX;
+ gdY := Gear^.dY;
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLAutoSound);
- Gear^.dX.isNegative := not dxn;
- Gear^.dY.isNegative := not dyn;
+ gdX.isNegative := not dxn;
+ gdY.isNegative := not dyn;
for i:= 0 to 4 do
begin
- dX := Gear^.dX + (GetRandomf - _0_5) * _0_03;
- dY := Gear^.dY + (GetRandomf - _0_5) * _0_03;
+ dX := gdX + (GetRandomf - _0_5) * _0_03;
+ dY := gdY + (GetRandomf - _0_5) * _0_03;
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtCluster, 0, dX, dY, 25);
end;
@@ -2456,6 +2462,12 @@
Gear^.AdvBounce:= 1;
HHGear := Gear^.Hedgehog^.Gear;
+ if HHGear = nil then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+
HHGear^.State := HHGear^.State or gstNoDamage;
DeleteCI(HHGear);
@@ -4302,7 +4314,9 @@
Gear^.dY.isNegative := not Gear^.dY.isNegative;
Gear^.doStep := @doStepSineGunShotWork;
- performRumble();
+ with mobileRecord do
+ if (performRumble <> nil) and (not fastUntilLag) then
+ performRumble(kSystemSoundID_Vibrate);
end;
////////////////////////////////////////////////////////////////////////////////
@@ -5143,6 +5157,7 @@
begin
with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac;
AddRandomness(CheckSum);
+ if gi^.Kind = gtGenericFaller then gi^.State:= gi^.State and not gstTmpFlag;
gi := gi^.NextGear
end;
AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y));
@@ -5160,8 +5175,17 @@
DeleteGear(Gear);
exit
end;
-
-doStepFallingGear(Gear);
+if (Gear^.State and gstTmpFlag <> 0) or (GameTicks and $7 = 0) then
+ begin
+ doStepFallingGear(Gear);
+ if (Gear^.State and gstInvisible <> 0) and (GameTicks and $FF = 0) and (hwRound(Gear^.X) < LongInt(leftX)) or (hwRound(Gear^.X) > LongInt(rightX)) or (hwRound(Gear^.Y) < LongInt(topY)) then
+ begin
+ Gear^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
+ Gear^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
+ Gear^.dX:= _90-(GetRandomf*_360);
+ Gear^.dY:= _90-(GetRandomf*_360)
+ end;
+ end
end;
procedure doStepCreeper(Gear: PGear);
@@ -5247,12 +5271,12 @@
////////////////////////////////////////////////////////////////////////////////
procedure doStepKnife(Gear: PGear);
-var ox, oy: LongInt;
- la: hwFloat;
- a: real;
+//var ox, oy: LongInt;
+// la: hwFloat;
+var a: real;
begin
// Gear is shrunk so it can actually escape the hog without carving into the terrain
- if (Gear^.Radius = 6) and (Gear^.CollisionMask = $FFFF) then Gear^.Radius:= 16;
+ if (Gear^.Radius = 4) and (Gear^.CollisionMask = $FFFF) then Gear^.Radius:= 7;
if Gear^.Damage > 100 then Gear^.CollisionMask:= 0
else if Gear^.Damage > 30 then
if GetRandom(max(4,18-Gear^.Damage div 10)) < 3 then Gear^.CollisionMask:= 0;
@@ -5261,6 +5285,7 @@
if (Gear^.State and gstMoving <> 0) and (Gear^.State and gstCollision = 0) then
begin
DeleteCI(Gear);
+ Gear^.Radius:= 7;
// used for damage and impact calc. needs balancing I think
Gear^.Health:= hwRound(hwSqr((hwAbs(Gear^.dY)+hwAbs(Gear^.dX))*_4));
doStepFallingGear(Gear);
@@ -5271,14 +5296,14 @@
end
else if (Gear^.CollisionIndex = -1) and (Gear^.Timer = 0) then
begin
- ox:= 0; oy:= 0;
+ (*ox:= 0; oy:= 0;
if TestCollisionYwithGear(Gear, -1) <> 0 then oy:= -1;
if TestCollisionXwithGear(Gear, 1) then ox:= 1;
if TestCollisionXwithGear(Gear, -1) then ox:= -1;
if TestCollisionYwithGear(Gear, 1) <> 0 then oy:= 1;
if Gear^.Health > 0 then
PlaySound(sndRopeAttach);
-(*
+
la:= _10000;
if (ox <> 0) or (oy <> 0) then
la:= CalcSlopeNearGear(Gear, ox, oy);
@@ -5296,9 +5321,8 @@
Gear^.dX:= _0;
Gear^.dY:= _0;
Gear^.State:= Gear^.State and (not gstMoving) or gstCollision;
- Gear^.Radius:= 20;
+ Gear^.Radius:= 16;
if Gear^.Health > 0 then AmmoShove(Gear, Gear^.Health, 0);
- Gear^.Radius:= 16;
Gear^.Health:= 0;
Gear^.Timer:= 500;
AddGearCI(Gear)
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/SDLh.pas
--- a/hedgewars/SDLh.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/SDLh.pas Fri Feb 22 05:05:32 2013 +0100
@@ -42,8 +42,8 @@
{$linklib root}
{$ELSE}
{$IFNDEF ANDROID}
- {$linklib pthread}
- {$ENDIF}
+ {$linklib pthread}
+ {$ENDIF}
{$ENDIF}
{$ENDIF}
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/VGSHandlers.inc
--- a/hedgewars/VGSHandlers.inc Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/VGSHandlers.inc Fri Feb 22 05:05:32 2013 +0100
@@ -697,7 +697,9 @@
Gear^.doStep:= @doStepBigExplosionWork;
if Steps > 1 then
Gear^.doStep(Gear, Steps-1);
-performRumble();
+with mobileRecord do
+ if (performRumble <> nil) and (not fastUntilLag) then
+ performRumble(kSystemSoundID_Vibrate);
end;
procedure doStepChunk(Gear: PVisualGear; Steps: Longword);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/avwrapper.c
--- a/hedgewars/avwrapper.c Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/avwrapper.c Fri Feb 22 05:05:32 2013 +0100
@@ -22,6 +22,7 @@
#include
#include
#include "libavformat/avformat.h"
+#include "libavutil/mathematics.h"
#ifndef AVIO_FLAG_WRITE
#define AVIO_FLAG_WRITE AVIO_WRONLY
@@ -47,13 +48,6 @@
static int16_t* g_pSamples;
static int g_NumSamples;
-/*
-Initially I wrote code for latest ffmpeg, but on Linux (Ubuntu)
-only older version is available from repository. That's why you see here
-all of this #if LIBAVCODEC_VERSION_MAJOR < 54.
-Actually, it may be possible to remove code for newer version
-and use only code for older version.
-*/
#if LIBAVCODEC_VERSION_MAJOR < 54
#define OUTBUFFER_SIZE 200000
@@ -65,7 +59,7 @@
static void FatalError(const char* pFmt, ...)
{
- const char Buffer[1024];
+ char Buffer[1024];
va_list VaArgs;
va_start(VaArgs, pFmt);
@@ -83,7 +77,7 @@
// (there is mutex in AddFileLogRaw).
static void LogCallback(void* p, int Level, const char* pFmt, va_list VaArgs)
{
- const char Buffer[1024];
+ char Buffer[1024];
vsnprintf(Buffer, 1024, pFmt, VaArgs);
AddFileLogRaw(Buffer);
@@ -91,7 +85,7 @@
static void Log(const char* pFmt, ...)
{
- const char Buffer[1024];
+ char Buffer[1024];
va_list VaArgs;
va_start(VaArgs, pFmt);
@@ -103,7 +97,7 @@
static void AddAudioStream()
{
-#if LIBAVFORMAT_VERSION_MAJOR >= 54
+#if LIBAVFORMAT_VERSION_MAJOR >= 53
g_pAStream = avformat_new_stream(g_pContainer, g_pACodec);
#else
g_pAStream = av_new_stream(g_pContainer, 1);
@@ -175,7 +169,7 @@
int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile);
-#if LIBAVCODEC_VERSION_MAJOR >= 54
+#if LIBAVCODEC_VERSION_MAJOR >= 53
AVFrame* pFrame = NULL;
if (NumSamples > 0)
{
@@ -215,7 +209,7 @@
// add a video output stream
static void AddVideoStream()
{
-#if LIBAVFORMAT_VERSION_MAJOR >= 54
+#if LIBAVFORMAT_VERSION_MAJOR >= 53
g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
#else
g_pVStream = av_new_stream(g_pContainer, 0);
@@ -254,7 +248,7 @@
if (g_pFormat->flags & AVFMT_GLOBALHEADER)
g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER;
-#if LIBAVCODEC_VERSION_MAJOR < 54
+#if LIBAVCODEC_VERSION_MAJOR < 53
// for some versions of ffmpeg x264 options must be set explicitly
if (strcmp(g_pVCodec->name, "libx264") == 0)
{
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/config.inc.in
--- a/hedgewars/config.inc.in Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/config.inc.in Fri Feb 22 05:05:32 2013 +0100
@@ -24,3 +24,4 @@
const cNetProtoVersion = ${HEDGEWARS_PROTO_VER};
cVersionString = '${HEDGEWARS_VERSION}';
cLuaLibrary = '${LUA_LIBRARY}';
+ cDefaultPathPrefix = '${CMAKE_INSTALL_PREFIX}/${SHAREPATH}/Data';
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/hwengine.pas
--- a/hedgewars/hwengine.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/hwengine.pas Fri Feb 22 05:05:32 2013 +0100
@@ -32,18 +32,19 @@
uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uInputHandler
, uSound, uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uAILandMarks, uLandTexture, uCollisions
, SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers, uLandPainted
- , uPhysFSLayer
+ , uPhysFSLayer, uCursor
{$IFDEF USE_VIDEO_RECORDING}, uVideoRec {$ENDIF}
{$IFDEF USE_TOUCH_INTERFACE}, uTouch {$ENDIF}
{$IFDEF ANDROID}, GLUnit{$ENDIF}
;
+var isInternal: Boolean;
{$IFDEF HWLIBRARY}
procedure preInitEverything();
procedure initEverything(complete:boolean);
procedure freeEverything(complete:boolean);
-procedure Game(gameArgs: PPChar); cdecl; export;
+procedure Game(argc: LongInt; argv: PPChar); cdecl; export;
procedure GenLandPreview(port: Longint); cdecl; export;
implementation
@@ -53,6 +54,8 @@
procedure freeEverything(complete:boolean); forward;
{$ENDIF}
+{$INCLUDE "ArgParsers.inc"}
+
///////////////////////////////////////////////////////////////////////////////
function DoTimer(Lag: LongInt): boolean;
var s: shortstring;
@@ -91,15 +94,15 @@
end;
gsConfirm, gsGame:
begin
- DrawWorld(Lag);
+ if not cOnlyStats then DrawWorld(Lag);
DoGameTick(Lag);
- ProcessVisualGears(Lag);
+ if not cOnlyStats then ProcessVisualGears(Lag);
end;
gsChat:
begin
- DrawWorld(Lag);
+ if not cOnlyStats then DrawWorld(Lag);
DoGameTick(Lag);
- ProcessVisualGears(Lag);
+ if not cOnlyStats then ProcessVisualGears(Lag);
end;
gsExit:
begin
@@ -109,7 +112,7 @@
exit(false);
end;
- SwapBuffers;
+ if not cOnlyStats then SwapBuffers;
{$IFDEF USE_VIDEO_RECORDING}
if flagPrerecording then
@@ -217,7 +220,13 @@
ProcessKey(event.key);
SDL_MOUSEBUTTONDOWN:
- ProcessMouse(event.button, true);
+ if GameState = gsConfirm then
+ begin
+ resetPosition();
+ ParseCommand('quit', true);
+ end
+ else
+ ProcessMouse(event.button, true);
SDL_MOUSEBUTTONUP:
ProcessMouse(event.button, false);
@@ -255,18 +264,24 @@
end; //end case event.type_ of
end; //end while SDL_PollEvent(@event) <> 0 do
+ if (CursorMovementX <> 0) or (CursorMovementY <> 0) then
+ handlePositionUpdate(CursorMovementX * cameraKeyboardSpeed, CursorMovementY * cameraKeyboardSpeed);
+
if (cScreenResizeDelay <> 0) and (cScreenResizeDelay < RealTicks) and
((cNewScreenWidth <> cScreenWidth) or (cNewScreenHeight <> cScreenHeight)) then
begin
cScreenResizeDelay:= 0;
- cScreenWidth:= cNewScreenWidth;
- cScreenHeight:= cNewScreenHeight;
+ cWindowedWidth:= cNewScreenWidth;
+ cWindowedHeight:= cNewScreenHeight;
+ cScreenWidth:= cWindowedWidth;
+ cScreenHeight:= cWindowedHeight;
ParseCommand('fullscr '+intToStr(LongInt(cFullScreen)), true);
WriteLnToConsole('window resize: ' + IntToStr(cScreenWidth) + ' x ' + IntToStr(cScreenHeight));
ScriptOnScreenResize();
InitCameraBorders();
InitTouchInterface();
+ SendIPC('W' + IntToStr(cScreenWidth) + 'x' + IntToStr(cScreenHeight));
end;
CurrTime:= SDL_GetTicks();
@@ -314,29 +329,16 @@
{$ENDIF}
///////////////////////////////////////////////////////////////////////////////
-procedure Game{$IFDEF HWLIBRARY}(gameArgs: PPChar); cdecl; export{$ENDIF};
-var p: TPathType;
- s: shortstring;
+procedure Game{$IFDEF HWLIBRARY}(argc: LongInt; argv: PPChar); cdecl; export{$ENDIF};
+//var p: TPathType;
+var s: shortstring;
i: LongInt;
begin
{$IFDEF HWLIBRARY}
preInitEverything();
- cShowFPS:= {$IFDEF DEBUGFILE}true{$ELSE}false{$ENDIF};
- ipcPort:= StrToInt(gameArgs[0]);
- cScreenWidth:= StrToInt(gameArgs[1]);
- cScreenHeight:= StrToInt(gameArgs[2]);
- cReducedQuality:= StrToInt(gameArgs[3]);
- cLocaleFName:= gameArgs[4];
- UserNick:= gameArgs[5];
- SetSound(gameArgs[6] = '1');
- SetMusic(gameArgs[7] = '1');
- cAltDamage:= gameArgs[8] = '1';
- PathPrefix:= gameArgs[9];
- UserPathPrefix:= '../Documents';
- recordFileName:= gameArgs[10];
+ parseCommandLine(argc, argv);
{$ENDIF}
initEverything(true);
-
WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (network protocol: ' + inttostr(cNetProtoVersion) + ')');
AddFileLog('Prefix: "' + PathPrefix +'"');
AddFileLog('UserPrefix: "' + UserPathPrefix +'"');
@@ -345,7 +347,7 @@
AddFileLog(inttostr(i) + ': ' + ParamStr(i));
WriteToConsole('Init SDL... ');
- SDLTry(SDL_Init(SDL_INIT_VIDEO or SDL_INIT_NOPARACHUTE) >= 0, true);
+ if not cOnlyStats then SDLTry(SDL_Init(SDL_INIT_VIDEO or SDL_INIT_NOPARACHUTE) >= 0, true);
WriteLnToConsole(msgOK);
SDL_EnableUNICODE(1);
@@ -437,7 +439,6 @@
begin
uUtils.initModule(complete); // opens the debug file, must be the first
uVariables.initModule; // inits all global variables
- uConsole.initModule; // opens stdout
uCommands.initModule; // helps below
uCommandHandlers.initModule; // registers all messages from frontend
@@ -508,7 +509,6 @@
uCommandHandlers.freeModule;
uCommands.freeModule;
- uConsole.freeModule; // closes stdout
uVariables.freeModule;
uUtils.freeModule; // closes debug file
end;
@@ -536,60 +536,6 @@
end;
{$IFNDEF HWLIBRARY}
-///////////////////////////////////////////////////////////////////////////////
-procedure DisplayUsage;
-var i: LongInt;
-begin
- WriteLn(stdout, 'Wrong argument format: correct configurations is');
- WriteLn(stdout, '');
- WriteLn(stdout, ' hwengine [options]');
- WriteLn(stdout, '');
- WriteLn(stdout, 'where [options] must be specified either as:');
- WriteLn(stdout, ' --set-video [screen width] [screen height] [color dept]');
- WriteLn(stdout, ' --set-audio [volume] [enable music] [enable sounds]');
- WriteLn(stdout, ' --set-other [language file] [full screen] [show FPS]');
- WriteLn(stdout, ' --set-multimedia [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen]');
- WriteLn(stdout, ' --set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]');
- WriteLn(stdout, ' --stats-only');
- WriteLn(stdout, '');
- WriteLn(stdout, 'Read documentation online at http://code.google.com/p/hedgewars/wiki/CommandLineOptions for more information');
- WriteLn(stdout, '');
- Write(stdout, 'PARSED COMMAND: ');
-
- for i:=0 to ParamCount do
- Write(stdout, ParamStr(i) + ' ');
-
- WriteLn(stdout, '');
-end;
-
-///////////////////////////////////////////////////////////////////////////////
-{$INCLUDE "ArgParsers.inc"}
-
-procedure GetParams;
-begin
- if (ParamCount < 3) then
- GameType:= gmtSyntax
- else
- if (ParamCount = 3) and (ParamStr(3) = 'landpreview') then
- begin
- ipcPort:= StrToInt(ParamStr(2));
- GameType:= gmtLandPreview;
- end
- else
- begin
- if (ParamCount = 3) and (ParamStr(3) = '--stats-only') then
- playReplayFileWithParameters()
- else
- if ParamCount = cDefaultParamNum then
- internalStartGameWithParameters()
-{$IFDEF USE_VIDEO_RECORDING}
- else if ParamCount = cVideorecParamNum then
- internalStartVideoRecordingWithParameters()
-{$ENDIF}
- else
- playReplayFileWithParameters();
- end
-end;
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// m a i n ///////////////////////////////////
@@ -600,9 +546,8 @@
if GameType = gmtLandPreview then
GenLandPreview()
- else if GameType = gmtSyntax then
- DisplayUsage()
- else Game();
+ else if GameType <> gmtSyntax then
+ Game();
// return 1 when engine is not called correctly
halt(LongInt(GameType = gmtSyntax));
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/options.inc
--- a/hedgewars/options.inc Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/options.inc Fri Feb 22 05:05:32 2013 +0100
@@ -43,12 +43,12 @@
{$IFDEF MOBILE}
{$DEFINE HWLIBRARY}
- {$DEFINE S3D_DISABLED}
{$DEFINE GLunit:=gles11}
{$DEFINE USE_LANDSCAPE_AMMOMENU}
{$DEFINE USE_TOUCH_INTERFACE}
{$ELSE}
{$DEFINE USE_AM_NUMCOLUMN}
+ {$DEFINE USE_S3D_RENDERING}
{$ENDIF}
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uAI.pas
--- a/hedgewars/uAI.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uAI.pas Fri Feb 22 05:05:32 2013 +0100
@@ -291,18 +291,13 @@
begin
with Stack.States[Pred(Stack.Count)] do
begin
- if Me^.dX.isNegative then
+ if (Me^.Message and gmLeft) <> 0 then
AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0)
else
AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0);
AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0);
AddAction(MadeActions, aia_HJump, 0, 350, 0, 0);
-
- if Me^.dX.isNegative then
- AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0)
- else
- AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0);
end;
// but first check walking forward
Push(ticks, Stack.States[Pred(Stack.Count)].MadeActions, AltMe, Me^.Message)
@@ -318,7 +313,7 @@
if Push(ticks, Actions, AltMe, Me^.Message xor 3) then
with Stack.States[Pred(Stack.Count)] do
begin
- if Me^.dX.isNegative then
+ if (Me^.Message and gmLeft) <> 0 then
AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0)
else
AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uAIAmmoTests.pas
--- a/hedgewars/uAIAmmoTests.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uAIAmmoTests.pas Fri Feb 22 05:05:32 2013 +0100
@@ -40,6 +40,7 @@
function TestMolotov(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
function TestClusterBomb(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
function TestWatermelon(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestDrillRocket(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
function TestMortar(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
function TestShotgun(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
function TestDesertEagle(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
@@ -91,7 +92,7 @@
(proc: @TestWatermelon; flags: 0), // amWatermelon
(proc: nil; flags: 0), // amHellishBomb
(proc: nil; flags: 0), // amNapalm
- (proc: nil; flags: 0), // amDrill
+ (proc: @TestDrillRocket; flags: 0), // amDrill
(proc: nil; flags: 0), // amBallgun
(proc: nil; flags: 0), // amRCPlane
(proc: nil; flags: 0), // amLowGravity
@@ -115,7 +116,7 @@
(proc: nil; flags: 0), // amDrillStrike
(proc: nil; flags: 0), // amSnowball
(proc: nil; flags: 0), // amTardis
- (proc: nil; flags: 0), // amStructure
+ //(proc: nil; flags: 0), // amStructure
(proc: nil; flags: 0), // amLandGun
(proc: nil; flags: 0), // amIceGun
(proc: nil; flags: 0) // amKnife
@@ -187,6 +188,65 @@
TestBazooka:= valueResult
end;
+
+function TestDrillRocket(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+var Vx, Vy, r, mX, mY: real;
+ rTime: LongInt;
+ EX, EY: LongInt;
+ valueResult: LongInt;
+ x, y, dX, dY: real;
+ t: LongInt;
+ value: LongInt;
+begin
+ mX:= hwFloat2Float(Me^.X);
+ mY:= hwFloat2Float(Me^.Y);
+ ap.Time:= 0;
+ rTime:= 350;
+ ap.ExplR:= 0;
+ valueResult:= BadTurn;
+ repeat
+ rTime:= rTime + 300 + Level * 50 + random(300);
+ Vx:= - windSpeed * rTime * 0.5 + (Targ.X + AIrndSign(2) - mX) / rTime;
+ Vy:= cGravityf * rTime * 0.5 - (Targ.Y - 35 - mY) / rTime;
+ r:= sqr(Vx) + sqr(Vy);
+ if not (r > 1) then
+ begin
+ x:= mX;
+ y:= mY;
+ dX:= Vx;
+ dY:= -Vy;
+ t:= rTime;
+ repeat
+ x:= x + dX;
+ y:= y + dY;
+ dX:= dX + windSpeed;
+ dY:= dY + cGravityf;
+ dec(t)
+ until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
+ ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (y > cWaterLine);
+
+ EX:= trunc(x);
+ EY:= trunc(y);
+ if Level = 1 then
+ value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
+ else value:= RateExplosion(Me, EX, EY, 101);
+ if value = 0 then
+ value:= 1024 - Metric(Targ.X, Targ.Y, EX, EY) div 64;
+ if valueResult <= value then
+ begin
+ ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
+ ap.Power:= trunc(sqrt(r) * cMaxPower) - random((Level - 1) * 17 + 1);
+ ap.ExplR:= 100;
+ ap.ExplX:= EX;
+ ap.ExplY:= EY;
+ valueResult:= value
+ end;
+ end
+ until rTime > 4250;
+ TestDrillRocket:= valueResult
+end;
+
+
function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
var Vx, Vy, r: real;
rTime: LongInt;
@@ -1080,7 +1140,7 @@
var i: Longword;
v: LongInt;
begin
-while (not TestColl(hwRound(Gear^.X), hwRound(Gear^.Y), 6)) and (Gear^.Y.Round < LAND_HEIGHT) do
+while (not TestColl(hwRound(Gear^.X), hwRound(Gear^.Y), 6)) and (Gear^.Y.Round < LongWord(LAND_HEIGHT)) do
Gear^.Y:= Gear^.Y + _1;
for i:= 0 to 2040 do
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uCaptions.pas
--- a/hedgewars/uCaptions.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uCaptions.pas Fri Feb 22 05:05:32 2013 +0100
@@ -44,6 +44,7 @@
procedure AddCaption(s: shortstring; Color: Longword; Group: TCapGroup);
begin
+ if cOnlyStats then exit;
if Captions[Group].Text <> s then
begin
FreeTexture(Captions[Group].Tex);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uChat.pas
--- a/hedgewars/uChat.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uChat.pas Fri Feb 22 05:05:32 2013 +0100
@@ -41,6 +41,7 @@
Width: LongInt;
s: shortstring;
end;
+ TChatCmd = (quit, pause, finish, fullscreen);
var Strs: array[0 .. MaxStrIndex] of TChatLine;
MStrs: array[0 .. MaxStrIndex] of shortstring;
@@ -52,15 +53,25 @@
ChatReady: boolean;
showAll: boolean;
-const colors: array[#0..#6] of TSDL_Color = (
- (r:$FF; g:$FF; b:$FF; unused:$FF), // unused, feel free to take it for anything
- (r:$FF; g:$FF; b:$FF; unused:$FF), // chat message [White]
- (r:$FF; g:$00; b:$FF; unused:$FF), // action message [Purple]
- (r:$90; g:$FF; b:$90; unused:$FF), // join/leave message [Lime]
- (r:$FF; g:$FF; b:$A0; unused:$FF), // team message [Light Yellow]
- (r:$FF; g:$00; b:$00; unused:$FF), // error messages [Red]
- (r:$00; g:$FF; b:$FF; unused:$FF) // input line [Light Blue]
- );
+const
+ colors: array[#0..#6] of TSDL_Color = (
+ (r:$FF; g:$FF; b:$FF; unused:$FF), // unused, feel free to take it for anything
+ (r:$FF; g:$FF; b:$FF; unused:$FF), // chat message [White]
+ (r:$FF; g:$00; b:$FF; unused:$FF), // action message [Purple]
+ (r:$90; g:$FF; b:$90; unused:$FF), // join/leave message [Lime]
+ (r:$FF; g:$FF; b:$A0; unused:$FF), // team message [Light Yellow]
+ (r:$FF; g:$00; b:$00; unused:$FF), // error messages [Red]
+ (r:$00; g:$FF; b:$FF; unused:$FF) // input line [Light Blue]
+ );
+ ChatCommandz: array [TChatCmd] of record
+ ChatCmd: string[31];
+ ProcedureCallChatCmd: string[31];
+ end = (
+ (ChatCmd: '/quit'; ProcedureCallChatCmd: 'halt'),
+ (ChatCmd: '/pause'; ProcedureCallChatCmd: 'pause'),
+ (ChatCmd: '/finish'; ProcedureCallChatCmd: 'finish'),
+ (ChatCmd: '/fullscreen'; ProcedureCallChatCmd: 'fullscr')
+ );
procedure SetLine(var cl: TChatLine; str: shortstring; isInput: boolean);
var strSurface, resSurface: PSDL_Surface;
@@ -197,6 +208,7 @@
procedure AcceptChatString(s: shortstring);
var i: TWave;
+ j: TChatCmd;
c, t: LongInt;
x: byte;
begin
@@ -267,6 +279,13 @@
ParseCommand('/taunt ' + char(i), true);
exit
end;
+
+ for j:= Low(TChatCmd) to High(TChatCmd) do
+ if (s = ChatCommandz[j].ChatCmd) then
+ begin
+ ParseCommand(ChatCommandz[j].ProcedureCallChatCmd, true);
+ exit
+ end;
end
else
ParseCommand('/say ' + s, true);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uCommandHandlers.pas
--- a/hedgewars/uCommandHandlers.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uCommandHandlers.pas Fri Feb 22 05:05:32 2013 +0100
@@ -30,6 +30,8 @@
{$IFDEF USE_VIDEO_RECORDING}, uVideoRec {$ENDIF};
var prevGState: TGameState = gsConfirm;
+ cTagsMasks : array[0..15] of byte = (7, 0, 0, 0, 15, 6, 4, 5, 0, 0, 0, 0, 0, 14, 12, 13);
+ cTagsMasksNoHealth: array[0..15] of byte = (3, 2, 11, 1, 0, 0, 0, 0, 0, 10, 0, 9, 0, 0, 0, 0);
procedure chGenCmd(var s: shortstring);
begin
@@ -87,11 +89,11 @@
end;
procedure chCheckProto(var s: shortstring);
-var i, c: LongInt;
+var i: LongInt;
begin
if isDeveloperMode then
begin
- val(s, i, c);
+ i:= StrToInt(s);
TryDo(i <= cNetProtoVersion, 'Protocol version mismatch: engine is too old (got '+intToStr(i)+', expecting '+intToStr(cNetProtoVersion)+')', true);
TryDo(i >= cNetProtoVersion, 'Protocol version mismatch: engine is too new (got '+intToStr(i)+', expecting '+intToStr(cNetProtoVersion)+')', true);
end
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uCommands.pas
--- a/hedgewars/uCommands.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uCommands.pas Fri Feb 22 05:05:32 2013 +0100
@@ -88,12 +88,14 @@
//WriteLnToConsole(CmdStr);
if CmdStr[0]=#0 then
exit;
+
+AddFileLog('[Cmd] ' + sanitizeForLog(CmdStr));
+
c:= CmdStr[1];
if (c = '/') or (c = '$') then
Delete(CmdStr, 1, 1);
s:= '';
SplitBySpace(CmdStr, s);
-AddFileLog('[Cmd] ' + CmdStr + ' (' + inttostr(length(s)) + ')');
t:= Variables;
while t <> nil do
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uConsole.pas
--- a/hedgewars/uConsole.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uConsole.pas Fri Feb 22 05:05:32 2013 +0100
@@ -21,61 +21,26 @@
unit uConsole;
interface
-procedure initModule;
-procedure freeModule;
-procedure WriteToConsole(s: shortstring);
-procedure WriteLnToConsole(s: shortstring);
-function GetLastConsoleLine: shortstring;
-function ShortStringAsPChar(s: shortstring): PChar;
-
-implementation
-uses Types, uVariables, uUtils {$IFDEF ANDROID}, log in 'log.pas'{$ENDIF};
-
-const cLinesCount = 8;
-var cLineWidth: LongInt;
-
-type
- TTextLine = record
- s: shortstring
- end;
-
-var ConsoleLines: array[byte] of TTextLine;
- CurrLine: LongInt;
-
-procedure SetLine(var tl: TTextLine; str: shortstring);
-begin
-with tl do
- s:= str;
-end;
procedure WriteToConsole(s: shortstring);
-{$IFNDEF NOCONSOLE}
-var Len: LongInt;
- done: boolean;
-{$ENDIF}
+procedure WriteLnToConsole(s: shortstring);
+function ShortStringAsPChar(s: shortstring): PChar;
+
+var lastConsoleline : shortstring;
+
+implementation
+uses Types, uUtils {$IFDEF ANDROID}, log in 'log.pas'{$ENDIF};
+
+
+procedure WriteToConsole(s: shortstring);
begin
{$IFNDEF NOCONSOLE}
-AddFileLog('[Con] ' + s);
+ AddFileLog('[Con] ' + s);
{$IFDEF ANDROID}
+ //TODO integrate this function in the uMobile record
Log.__android_log_write(Log.Android_LOG_DEBUG, 'HW_Engine', ShortStringAsPChar('[Con]' + s));
{$ELSE}
-Write(stderr, s);
-done:= false;
-
-while not done do
- begin
- Len:= cLineWidth - Length(ConsoleLines[CurrLine].s);
- SetLine(ConsoleLines[CurrLine], ConsoleLines[CurrLine].s + copy(s, 1, Len));
- Delete(s, 1, Len);
- if byte(ConsoleLines[CurrLine].s[0]) = cLineWidth then
- begin
- inc(CurrLine);
- if CurrLine = cLinesCount then
- CurrLine:= 0;
- PByte(@ConsoleLines[CurrLine].s)^:= 0
- end;
- done:= (Length(s) = 0);
- end;
+ Write(stderr, s);
{$ENDIF}
{$ENDIF}
end;
@@ -83,13 +48,10 @@
procedure WriteLnToConsole(s: shortstring);
begin
{$IFNDEF NOCONSOLE}
-WriteToConsole(s);
+ WriteToConsole(s);
+ lastConsoleline:= s;
{$IFNDEF ANDROID}
-WriteLn(stderr, '');
-inc(CurrLine);
-if CurrLine = cLinesCount then
- CurrLine:= 0;
-PByte(@ConsoleLines[CurrLine].s)^:= 0
+ WriteLn(stderr, '');
{$ENDIF}
{$ENDIF}
end;
@@ -102,37 +64,5 @@
ShortStringAsPChar:= @s[1];
end;
-function GetLastConsoleLine: shortstring;
-var valueStr: shortstring;
- i: LongWord;
-begin
-i:= (CurrLine + cLinesCount - 2) mod cLinesCount;
-valueStr:= ConsoleLines[i].s;
-
-valueStr:= valueStr + #10;
-
-i:= (CurrLine + cLinesCount - 1) mod cLinesCount;
-valueStr:= valueStr + ConsoleLines[i].s;
-
-GetLastConsoleLine:= valueStr;
-end;
-
-procedure initModule;
-var i: LongInt;
-begin
- CurrLine:= 0;
-
- // initConsole
- cLineWidth:= cScreenWidth div 10;
- if cLineWidth > 255 then
- cLineWidth:= 255;
- for i:= 0 to Pred(cLinesCount) do
- PByte(@ConsoleLines[i])^:= 0;
-end;
-
-procedure freeModule;
-begin
-
-end;
end.
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uConsts.pas
--- a/hedgewars/uConsts.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uConsts.pas Fri Feb 22 05:05:32 2013 +0100
@@ -27,8 +27,6 @@
const
sfMax = 1000;
- cDefaultParamNum = 17;
- cVideorecParamNum = cDefaultParamNum + 7;
// message constants
errmsgCreateSurface = 'Error creating SDL surface';
@@ -45,6 +43,9 @@
msgFailedSize = 'failed due to size';
msgGettingConfig = 'Getting game config...';
+ // camera movement multipliers
+ cameraKeyboardSpeed : ShortInt = 10;
+
// color constants
cWhiteColorChannels : TSDL_Color = (r:$FF; g:$FF; b:$FF; unused:$FF);
cNearBlackColorChannels : TSDL_Color = (r:$00; g:$00; b:$10; unused:$FF);
@@ -112,9 +113,7 @@
GL_TEXTURE_PRIORITY = $8066;
{$ENDIF}
- cSendCursorPosTime : LongWord = 50;
cVisibleWater : LongInt = 128;
- cCursorEdgesDist : LongInt = 100;
cTeamHealthWidth : LongInt = 128;
cifRandomize = $00000001;
@@ -122,8 +121,6 @@
cifMap = $00000002; // either theme or map (or map+theme)
cifAllInited = cifRandomize or cifTheme or cifMap;
- cTransparentColor: Longword = $00000000;
-
RGB_LUMINANCE_RED = 0.212671;
RGB_LUMINANCE_GREEN = 0.715160;
RGB_LUMINANCE_BLUE = 0.072169;
@@ -131,18 +128,14 @@
cMaxTeams = 8;
cMaxHHIndex = 7;
cMaxHHs = 48;
- cMaxSpawnPoints = 1024;
cMaxEdgePoints = 16384;
cHHRadius = 9;
cHHStepTicks = 29;
- cUsualZ = 500;
- cSmokeZ = 499;
cHHZ = 1000;
cCurrHHZ = Succ(cHHZ);
- cOnHHZ = 2000;
cBarrelHealth = 60;
cShotgunRadius = 22;
@@ -152,18 +145,11 @@
cKeyMaxIndex = 1023;
cKbdMaxIndex = 65536;//need more room for the modifier keys
- cHHFileName = 'Hedgehog';
- cCHFileName = 'Crosshair';
- cThemeCFGFilename = 'theme.cfg';
-
cFontBorder = 2;
// do not change this value
cDefaultZoomLevel = 2.0;
- cSendEmptyPacketTime = 1000;
- trigTurns = $80000001;
-
// game flags
gfAny = $FFFFFFFF;
gfOneClanMode = $00000001; // used in trainings
@@ -290,40 +276,8 @@
NoPointX = Low(LongInt);
cTargetPointRef : TPoint = (X: NoPointX; Y: 0);
- // hog tag mask
- htNone = $00;
- htTeamName = $01;
- htName = $02;
- htHealth = $04;
- htTransparent = $08;
-
- AMAnimDuration = 200;
- AMHidden = 0;//AMState values
- AMShowingUp = 1;
- AMShowing = 2;
- AMHiding = 3;
+ kSystemSoundID_Vibrate = $00000FFF;
- AMTypeMaskX = $00000001;
- AMTypeMaskY = $00000002;
- AMTypeMaskAlpha = $00000004;
- AMTypeMaskSlide = $00000008;
-
-{$IFDEF MOBILE}
- AMSlotSize = 48;
- AMTITLE = 30;
-{$ELSE}
- AMSlotSize = 32;
-{$ENDIF}
- AMSlotPadding = (AMSlotSize - 32) shr 1;
-
-{$IFDEF USE_TOUCH_INTERFACE}
- FADE_ANIM_TIME = 500;
- MOVE_ANIM_TIME = 500;
-{$ENDIF}
-
- cTagsMasks : array[0..15] of byte = (7, 0, 0, 0, 15, 6, 4, 5, 0, 0, 0, 0, 0, 14, 12, 13);
- cTagsMasksNoHealth: array[0..15] of byte = (3, 2, 11, 1, 0, 0, 0, 0, 0, 10, 0, 9, 0, 0, 0, 0);
-
implementation
end.
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uCursor.pas
--- a/hedgewars/uCursor.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uCursor.pas Fri Feb 22 05:05:32 2013 +0100
@@ -3,7 +3,9 @@
interface
procedure init;
+procedure resetPosition;
procedure updatePosition;
+procedure handlePositionUpdate(x, y: LongInt);
implementation
@@ -11,6 +13,11 @@
procedure init;
begin
+ resetPosition();
+end;
+
+procedure resetPosition;
+begin
SDL_WarpMouse(cScreenWidth div 2, cScreenHeight div 2);
end;
@@ -18,15 +25,20 @@
var x, y: LongInt;
begin
SDL_GetMouseState(@x, @y);
-
+
if(x <> cScreenWidth div 2) or (y <> cScreenHeight div 2) then
- begin
- CursorPoint.X:= CursorPoint.X + x - cScreenWidth div 2;
- CursorPoint.Y:= CursorPoint.Y - y + cScreenHeight div 2;
+ begin
+ handlePositionUpdate(x - cScreenWidth div 2, y - cScreenHeight div 2);
if cHasFocus then
SDL_WarpMouse(cScreenWidth div 2, cScreenHeight div 2);
- end
+ end
+end;
+
+procedure handlePositionUpdate(x, y: LongInt);
+begin
+ CursorPoint.X:= CursorPoint.X + x;
+ CursorPoint.Y:= CursorPoint.Y - y;
end;
end.
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uDebug.pas
--- a/hedgewars/uDebug.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uDebug.pas Fri Feb 22 05:05:32 2013 +0100
@@ -34,7 +34,7 @@
WriteLnToConsole(Msg);
if isFatalError then
begin
- ParseCommand('fatal ' + GetLastConsoleLine, true);
+ ParseCommand('fatal ' + lastConsoleline, true);
SDL_Quit;
halt(1)
end
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uGame.pas
--- a/hedgewars/uGame.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uGame.pas Fri Feb 22 05:05:32 2013 +0100
@@ -26,21 +26,24 @@
////////////////////
implementation
////////////////////
-uses uInputHandler, uTeams, uIO, uAI, uGears, uSound, uMobile,
+uses uInputHandler, uTeams, uIO, uAI, uGears, uSound, uLocale, uCaptions,
uVisualGears, uTypes, uVariables, uCommands, uConsts
{$IFDEF USE_TOUCH_INTERFACE}, uTouch{$ENDIF};
procedure DoGameTick(Lag: LongInt);
-var i: LongInt;
+var i,j : LongInt;
+ s: shortstring;
begin
if isPaused then
exit;
+
if (not CurrentTeam^.ExtDriven) then
begin
NetGetNextCmd; // its for the case of receiving "/say" message
isInLag:= false;
- SendKeepAliveMessage(Lag)
+ FlushMessages(Lag)
end;
+
if GameType <> gmtRecord then
begin
if Lag > 100 then
@@ -50,17 +53,33 @@
if (GameType = gmtDemo) then
if isSpeed then
- begin
+ begin
i:= RealTicks-SpeedStart;
if i < 2000 then Lag:= Lag*5
else if i < 4000 then Lag:= Lag*10
else if i < 6000 then Lag:= Lag*20
else if i < 8000 then Lag:= Lag*40
else Lag:= Lag*80;
- end
- else
- if cOnlyStats then
- Lag:= High(LongInt);
+ end
+ else if cOnlyStats then
+ Lag:= High(LongInt)
+ end;
+inc(SoundTimerTicks, Lag);
+if SoundTimerTicks >= 50 then
+ begin
+ SoundTimerTicks:= 0;
+ if cVolumeDelta <> 0 then
+ begin
+ j:= Volume;
+ i:= ChangeVolume(cVolumeDelta);
+ if isAudioMuted and (j<>i) then
+ AddCaption(trmsg[sidMute], cWhiteColor, capgrpVolume)
+ else if not isAudioMuted then
+ begin
+ str(i, s);
+ AddCaption(Format(trmsg[sidVolume], s), cWhiteColor, capgrpVolume)
+ end
+ end;
end;
PlayNextVoice;
i:= 1;
@@ -97,7 +116,9 @@
AddVisualGear(0, 0, vgtTeamHealthSorter);
AddVisualGear(0, 0, vgtSmoothWindBar);
{$IFDEF IPHONEOS}InitIPC;{$ENDIF}
- uMobile.SaveLoadingEnded();
+ with mobileRecord do
+ if SaveLoadingEnded <> nil then
+ SaveLoadingEnded();
end;
end
else ProcessGears
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uGears.pas
--- a/hedgewars/uGears.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uGears.pas Fri Feb 22 05:05:32 2013 +0100
@@ -56,8 +56,8 @@
implementation
-uses uStore, uSound, uTeams, uRandom, uCollisions, uIO, uLandGraphics,
- uLocale, uAI, uAmmos, uStats, uVisualGears, uScript, GLunit, uMobile, uVariables,
+uses uStore, uSound, uTeams, uRandom, uCollisions, uIO, uLandGraphics, {$IFDEF SDL13}uTouch,{$ENDIF}
+ uLocale, uAI, uAmmos, uStats, uVisualGears, uScript, GLunit, uVariables,
uCommands, uUtils, uTextures, uRenderUtils, uGearsRender, uCaptions, uDebug, uLandTexture,
uGearsHedgehog, uGearsUtils, uGearsList, uGearsHandlers, uGearsHandlersRope;
@@ -78,6 +78,7 @@
stSpawn, stNTurn);
upd: Longword;
snowLeft,snowRight: LongInt;
+ NewTurnTick: LongWord;
//SDMusic: shortstring;
// For better maintainability the step handlers of gears are stored in
@@ -189,6 +190,16 @@
i, AliveCount: LongInt;
s: shortstring;
begin
+ScriptCall('onGameTick');
+if GameTicks mod 20 = 0 then ScriptCall('onGameTick20');
+if GameTicks = NewTurnTick then
+ begin
+ ScriptCall('onNewTurn');
+{$IFDEF SDL13}
+ uTouch.NewTurnBeginning();
+{$ENDIF}
+ end;
+
PrvInactive:= AllInactive;
AllInactive:= true;
@@ -383,7 +394,8 @@
SwitchHedgehog;
AfterSwitchHedgehog;
- bBetweenTurns:= false
+ bBetweenTurns:= false;
+ NewTurnTick:= GameTicks + 1
end;
step:= Low(step)
end;
@@ -430,8 +442,7 @@
if TurnTimeLeft > 0 then
if CurrentHedgehog^.Gear <> nil then
- if ((CurrentHedgehog^.Gear^.State and gstAttacking) = 0)
- and (not isInMultiShoot) then
+ if ((CurrentHedgehog^.Gear^.State and gstAttacking) = 0) then
begin
if (TurnTimeLeft = 5000)
and (cHedgehogTurnTime >= 10000)
@@ -470,8 +481,6 @@
inc(hiTicks) // we do not recieve a message for this
end;
AddRandomness(CheckSum);
-ScriptCall('onGameTick');
-if GameTicks mod 20 = 0 then ScriptCall('onGameTick20');
inc(GameTicks)
end;
@@ -643,7 +652,7 @@
if (GameFlags and gfArtillery) <> 0 then
cArtillery:= true;
-for i:= GetRandom(10)+30 downto 0 do
+for i:= (LAND_WIDTH*LAND_HEIGHT) div 524288+2 downto 0 do
begin
rx:= GetRandom(rightX-leftX)+leftX;
ry:= GetRandom(LAND_HEIGHT-topY)+topY;
@@ -677,8 +686,8 @@
gtKnife,
gtCase,
gtTarget,
- gtExplosives,
- gtStructure: begin
+ gtExplosives: begin//,
+// gtStructure: begin
//addFileLog('ShotgunShot radius: ' + inttostr(Gear^.Radius) + ', t^.Radius = ' + inttostr(t^.Radius) + ', distance = ' + inttostr(dist) + ', dmg = ' + inttostr(dmg));
dmg:= 0;
r:= Gear^.Radius + t^.Radius;
@@ -777,8 +786,8 @@
gtKnife,
gtTarget,
gtCase,
- gtExplosives,
- gtStructure:
+ gtExplosives: //,
+ //gtStructure:
begin
if (Ammo^.Kind = gtDrill) then
begin
@@ -906,10 +915,6 @@
inc(Count)
end;
end;
- // unC0Rr, while it is true user can watch value on map screen, IMO this (and check above) should be enforced in UI
- // - is there a good place to put values for the different widgets to check? Right now they are kind of disconnected.
- //it would be nice if divide teams, forts mode and hh per map could all be checked by the team widget, or maybe disable start button
- TryDo(Count <= MaxHedgehogs, 'Too many hedgehogs for this map! (max # is ' + inttostr(MaxHedgehogs) + ')', true);
while (Count > 0) do
begin
i:= GetRandom(Count);
@@ -1367,7 +1372,7 @@
@doStepNapalmBomb,
@doStepSnowball,
@doStepSnowflake,
- @doStepStructure,
+ //@doStepStructure,
@doStepLandGun,
@doStepTardis,
@doStepIceGun,
@@ -1400,6 +1405,7 @@
upd:= 0;
//SDMusic:= 'hell.ogg';
+ NewTurnTick:= $FFFFFFFF;
end;
procedure freeModule;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uGearsHandlersRope.pas
--- a/hedgewars/uGearsHandlersRope.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uGearsHandlersRope.pas Fri Feb 22 05:05:32 2013 +0100
@@ -165,12 +165,12 @@
if ((Gear^.Message and gmDown) <> 0) and (Gear^.Elasticity < Gear^.Friction) then
if not (TestCollisionXwithGear(HHGear, hwSign(ropeDx))
- or (TestCollisionYwithGear(HHGear, hwSign(ropeDy)) <> 0)) then
+ or ((ropeDy.QWordValue <> 0) and TestCollisionYwithXYShift(HHGear, 0, 1, hwSign(ropeDy)))) then
Gear^.Elasticity := Gear^.Elasticity + _1_2;
if ((Gear^.Message and gmUp) <> 0) and (Gear^.Elasticity > _30) then
if not (TestCollisionXwithGear(HHGear, -hwSign(ropeDx))
- or (TestCollisionYwithGear(HHGear, -hwSign(ropeDy)) <> 0)) then
+ or ((ropeDy.QWordValue <> 0) and TestCollisionYwithXYShift(HHGear, 0, 1, -hwSign(ropeDy)))) then
Gear^.Elasticity := Gear^.Elasticity - _1_2;
HHGear^.X := Gear^.X + mdX * Gear^.Elasticity;
@@ -196,10 +196,10 @@
ly := hwRound(ny);
if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and ((Land[ly, lx] and $FF00) <> 0) then
begin
- ny := _1 / Distance(ropeDx, ropeDy);
+ tx := _1 / Distance(ropeDx, ropeDy);
// old rope pos
- nx := ropeDx * ny;
- ny := ropeDy * ny;
+ nx := ropeDx * tx;
+ ny := ropeDy * tx;
with RopePoints.ar[RopePoints.Count] do
begin
@@ -210,7 +210,7 @@
b := (nx * HHGear^.dY) > (ny * HHGear^.dX);
dLen := len
end;
-
+
with RopePoints.rounded[RopePoints.Count] do
begin
X := hwRound(Gear^.X);
@@ -264,7 +264,7 @@
HHGear^.dX := -_0_6 * HHGear^.dX;
haveCollision := true
end;
- if TestCollisionYwithGear(HHGear, hwSign(HHGear^.dY)) <> 0 then
+ if TestCollisionYwithXYShift(HHGear, 0, 1, hwSign(HHGear^.dY)) then
begin
HHGear^.dY := -_0_6 * HHGear^.dY;
haveCollision := true
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uGearsHedgehog.pas
--- a/hedgewars/uGearsHedgehog.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uGearsHedgehog.pas Fri Feb 22 05:05:32 2013 +0100
@@ -103,6 +103,13 @@
LoadHedgehogHat(HHGear^.Hedgehog^, 'Reserved/chef')
else if prevAmmo = amKnife then
LoadHedgehogHat(HHGear^.Hedgehog^, Hat);
+ end;
+ // Try again in the next slot
+ if CurAmmoType = prevAmmo then
+ begin
+ if slot >= cMaxSlotIndex then slot:= 0 else inc(slot);
+ HHGear^.MsgParam:= slot;
+ ChangeAmmo(HHGear)
end
end
end;
@@ -204,9 +211,7 @@
and ((TargetPoint.X <> NoPointX) or ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) = 0)) then
begin
State:= State or gstAttacking;
- if Power = cMaxPower then
- Message:= Message and (not gmAttack)
- else if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) = 0 then
+ if (Power = cMaxPower) or ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) = 0) then
Message:= Message and (not gmAttack)
else
begin
@@ -217,44 +222,44 @@
end;
inc(Power)
end;
- if ((Message and gmAttack) <> 0) then
- exit;
+ if ((Message and gmAttack) <> 0) then
+ exit;
- if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0 then
- begin
- StopSound(sndThrowPowerUp);
- PlaySound(sndThrowRelease);
- end;
+ if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0 then
+ begin
+ StopSound(sndThrowPowerUp);
+ PlaySound(sndThrowRelease);
+ end;
- xx:= SignAs(AngleSin(Angle), dX);
- yy:= -AngleCos(Angle);
+ xx:= SignAs(AngleSin(Angle), dX);
+ yy:= -AngleCos(Angle);
- lx:= X + int2hwfloat(round(GetLaunchX(CurAmmoType, hwSign(dX), Angle)));
- ly:= Y + int2hwfloat(round(GetLaunchY(CurAmmoType, Angle)));
+ lx:= X + int2hwfloat(round(GetLaunchX(CurAmmoType, hwSign(dX), Angle)));
+ ly:= Y + int2hwfloat(round(GetLaunchY(CurAmmoType, Angle)));
- if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then
- xx:= - xx;
- if Ammoz[CurAmmoType].Ammo.AttackVoice <> sndNone then
- AddVoice(Ammoz[CurAmmoType].Ammo.AttackVoice, CurrentTeam^.voicepack);
+ if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then
+ xx:= - xx;
+ if Ammoz[CurAmmoType].Ammo.AttackVoice <> sndNone then
+ AddVoice(Ammoz[CurAmmoType].Ammo.AttackVoice, CurrentTeam^.voicepack);
// Initiating alt attack
- if (CurAmmoGear <> nil)
- and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
- and ((Gear^.Message and gmLJump) <> 0)
- and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
- begin
- newDx:= dX;
- newDy:= dY;
- altUse:= true
- end
- else
- begin
- newDx:= xx*Power/cPowerDivisor;
- newDy:= yy*Power/cPowerDivisor;
- altUse:= false
- end;
+ if (CurAmmoGear <> nil)
+ and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
+ and ((Gear^.Message and gmLJump) <> 0)
+ and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
+ begin
+ newDx:= dX;
+ newDy:= dY;
+ altUse:= true
+ end
+ else
+ begin
+ newDx:= xx*Power/cPowerDivisor;
+ newDy:= yy*Power/cPowerDivisor;
+ altUse:= false
+ end;
- case CurAmmoType of
+ case CurAmmoType of
amGrenade: newGear:= AddGear(hwRound(lx), hwRound(ly), gtGrenade, 0, newDx, newDy, CurWeapon^.Timer);
amMolotov: newGear:= AddGear(hwRound(lx), hwRound(ly), gtMolotov, 0, newDx, newDy, 0);
amClusterBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtClusterBomb, 0, newDx, newDy, CurWeapon^.Timer);
@@ -274,7 +279,7 @@
amKnife: begin
newGear:= AddGear(hwRound(lx), hwRound(ly), gtKnife, 0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
newGear^.State:= newGear^.State or gstMoving;
- newGear^.Radius:= 6 // temporarily shrink so it doesn't instantly embed in the ground
+ newGear^.Radius:= 4 // temporarily shrink so it doesn't instantly embed in the ground
end;
amDEagle: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtDEagleShot, 0, xx * _0_5, yy * _0_5, 0);
amSineGun: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSineGunShot, 0, xx * _0_5, yy * _0_5, 0);
@@ -358,7 +363,7 @@
Unplaced:= true;
X:= _0;
Y:= _0;
- newGear:= AddGear(TargetPoint.X, 0, gtPiano, 0, _0, _0, 0);
+ newGear:= AddGear(TargetPoint.X, -1024, gtPiano, 0, _0, _0, 0);
PauseMusic
end;
amFlamethrower: newGear:= AddGear(hwRound(X), hwRound(Y), gtFlamethrower, 0, xx * _0_5, yy * _0_5, 0);
@@ -367,102 +372,102 @@
newGear:= AddGear(hwRound(lx), hwRound(ly), gtResurrector, 0, _0, _0, 0);
newGear^.SoundChannel := LoopSound(sndResurrector);
end;
- amStructure: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtStructure, gstWait, SignAs(_0_02, dX), _0, 3000);
+ //amStructure: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtStructure, gstWait, SignAs(_0_02, dX), _0, 3000);
amTardis: newGear:= AddGear(hwRound(X), hwRound(Y), gtTardis, 0, _0, _0, 5000);
amIceGun: newGear:= AddGear(hwRound(X), hwRound(Y), gtIceGun, 0, _0, _0, 0);
- end;
- if altUse and (newGear <> nil) then
- begin
- newGear^.dX:= newDx / newGear^.Density;
- newGear^.dY:= newDY / newGear^.Density
- end;
+ end;
+ if altUse and (newGear <> nil) then
+ begin
+ newGear^.dX:= newDx / newGear^.Density;
+ newGear^.dY:= newDY / newGear^.Density
+ end;
- case CurAmmoType of
- amGrenade, amMolotov,
- amClusterBomb, amGasBomb,
- amBazooka, amSnowball,
- amBee, amSMine,
- amMortar, amWatermelon,
- amHellishBomb, amDrill: FollowGear:= newGear;
+ case CurAmmoType of
+ amGrenade, amMolotov,
+ amClusterBomb, amGasBomb,
+ amBazooka, amSnowball,
+ amBee, amSMine,
+ amMortar, amWatermelon,
+ amHellishBomb, amDrill: FollowGear:= newGear;
- amShotgun, amPickHammer,
- amRope, amDEagle,
- amSineGun, amSniperRifle,
- amFirePunch, amWhip,
- amHammer, amBaseballBat,
- amParachute, amBlowTorch,
- amGirder, amTeleport,
- amSwitch, amRCPlane,
- amKamikaze, amCake,
- amSeduction, amBallgun,
- amJetpack, amBirdy,
- amFlamethrower, amLandGun,
- amResurrector, amStructure,
- amTardis, amPiano,
- amIceGun: CurAmmoGear:= newGear;
- end;
+ amShotgun, amPickHammer,
+ amRope, amDEagle,
+ amSineGun, amSniperRifle,
+ amFirePunch, amWhip,
+ amHammer, amBaseballBat,
+ amParachute, amBlowTorch,
+ amGirder, amTeleport,
+ amSwitch, amRCPlane,
+ amKamikaze, amCake,
+ amSeduction, amBallgun,
+ amJetpack, amBirdy,
+ amFlamethrower, amLandGun,
+ amResurrector, //amStructure,
+ amTardis, amPiano,
+ amIceGun: CurAmmoGear:= newGear;
+ end;
if ((CurAmmoType = amMine) or (CurAmmoType = amSMine)) and (GameFlags and gfInfAttack <> 0) then
newGear^.FlightTime:= GameTicks + 1000
else if CurAmmoType = amDrill then
newGear^.FlightTime:= GameTicks + 250;
- if Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then
- begin
- newGear^.Target.X:= TargetPoint.X;
- newGear^.Target.Y:= TargetPoint.Y
- end;
- if (newGear <> nil) and (newGear^.CollisionMask and $80 <> 0) then newGear^.CollisionMask:= newGear^.CollisionMask and (not $80);
+ if Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then
+ begin
+ newGear^.Target.X:= TargetPoint.X;
+ newGear^.Target.Y:= TargetPoint.Y
+ end;
+ if (newGear <> nil) and (newGear^.CollisionMask and $80 <> 0) then newGear^.CollisionMask:= newGear^.CollisionMask and (not $80);
- // Clear FollowGear if using on a rope/parachute/saucer etc so focus stays with the hog's movement
- if altUse then
- FollowGear:= nil;
+ // Clear FollowGear if using on a rope/parachute/saucer etc so focus stays with the hog's movement
+ if altUse then
+ FollowGear:= nil;
- if (newGear <> nil) and ((Ammoz[newGear^.AmmoType].Ammo.Propz and ammoprop_SetBounce) <> 0) then
- begin
- elastic:= int2hwfloat(CurWeapon^.Bounciness) / _1000;
+ if (newGear <> nil) and ((Ammoz[newGear^.AmmoType].Ammo.Propz and ammoprop_SetBounce) <> 0) then
+ begin
+ elastic:= int2hwfloat(CurWeapon^.Bounciness) / _1000;
- if elastic < _1 then
- newGear^.Elasticity:= newGear^.Elasticity * elastic
- else if elastic > _1 then
- newGear^.Elasticity:= _1 - ((_1-newGear^.Elasticity) / elastic);
-(* Experimented with friction modifier. Didn't seem helpful
- fric:= int2hwfloat(CurWeapon^.Bounciness) / _250;
- if fric < _1 then newGear^.Friction:= newGear^.Friction * fric
- else if fric > _1 then newGear^.Friction:= _1 - ((_1-newGear^.Friction) / fric)*)
- end;
+ if elastic < _1 then
+ newGear^.Elasticity:= newGear^.Elasticity * elastic
+ else if elastic > _1 then
+ newGear^.Elasticity:= _1 - ((_1-newGear^.Elasticity) / elastic);
+ (* Experimented with friction modifier. Didn't seem helpful
+ fric:= int2hwfloat(CurWeapon^.Bounciness) / _250;
+ if fric < _1 then newGear^.Friction:= newGear^.Friction * fric
+ else if fric > _1 then newGear^.Friction:= _1 - ((_1-newGear^.Friction) / fric)*)
+ end;
- uStats.AmmoUsed(CurAmmoType);
+ uStats.AmmoUsed(CurAmmoType);
- if not (SpeechText = '') then
- begin
- speech:= AddVisualGear(0, 0, vgtSpeechBubble);
- if speech <> nil then
+ if not (SpeechText = '') then
begin
- speech^.Text:= SpeechText;
- speech^.Hedgehog:= Gear^.Hedgehog;
- speech^.FrameTicks:= SpeechType;
+ speech:= AddVisualGear(0, 0, vgtSpeechBubble);
+ if speech <> nil then
+ begin
+ speech^.Text:= SpeechText;
+ speech^.Hedgehog:= Gear^.Hedgehog;
+ speech^.FrameTicks:= SpeechType;
+ end;
+ SpeechText:= ''
end;
- SpeechText:= ''
- end;
- Power:= 0;
- if (CurAmmoGear <> nil)
- and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) = 0){check for dropping ammo from rope} then
- begin
- Message:= Message or gmAttack;
- CurAmmoGear^.Message:= Message
+ Power:= 0;
+ if (CurAmmoGear <> nil)
+ and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) = 0){check for dropping ammo from rope} then
+ begin
+ if CurAmmoType = amRope then Message:= Message or gmAttack;
+ CurAmmoGear^.Message:= Message
+ end
+ else
+ begin
+ if not CurrentTeam^.ExtDriven
+ and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0) then
+ SendIPC(_S'a');
+ AfterAttack;
+ end
end
- else
- begin
- if not CurrentTeam^.ExtDriven
- and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0) then
- SendIPC(_S'a');
- AfterAttack;
- end
- end
- else
- Message:= Message and (not gmAttack);
+ else
+ Message:= Message and (not gmAttack);
end;
TargetPoint.X := NoPointX;
ScriptCall('onHogAttack');
@@ -641,9 +646,10 @@
gi := GearsList;
while gi <> nil do
begin
- if gi^.Kind = gtGenericFaller then
+ if (gi^.Kind = gtGenericFaller) and (gi^.State and gstInvisible <> 0) then
begin
gi^.Active:= true;
+ gi^.State:= gi^.State or gstTmpFlag;
gi^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
gi^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
gi^.dX:= _90-(GetRandomf*_360);
@@ -992,16 +998,25 @@
Hedgehog: PHedgehog;
begin
Hedgehog:= HHGear^.Hedgehog;
+// Some weapons, deagle in particular, wouldn't play so nice in infinite attack mode if hogs were still moving. Most likely scenario
+// is trying to shoot them twice while rolling. This is mostly about not wasting ammo, but shouldn't apply to gears not using AmmoShove (portal
+// Should we rethink AmmoShove? Presumably we'd need a way of knowing if current gear had already attacked a gear
+if isInMultiShoot and not AllInactive and (Hedgehog^.CurAmmoType in [amShotgun, amDEagle, amSniperRifle]) then HHGear^.Message:= HHGear^.Message and not gmAttack;
+(*
if isInMultiShoot then
HHGear^.Message:= 0;
+*)
-if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_Utility) <> 0) and isInMultiShoot then
+(*if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_Utility) <> 0) and isInMultiShoot then
AllInactive:= true
else if not isInMultiShoot then
- AllInactive:= false;
+ AllInactive:= false;*)
+ AllInactive:= false;
if (TurnTimeLeft = 0) or (HHGear^.Damage > 0) then
begin
+ if (Hedgehog^.CurAmmoType = amKnife) then
+ LoadHedgehogHat(Hedgehog^, Hedgehog^.Hat);
if TagTurnTimeLeft = 0 then
TagTurnTimeLeft:= TurnTimeLeft;
TurnTimeLeft:= 0;
@@ -1078,7 +1093,6 @@
exit
end;
-if not isInMultiShoot then
HedgehogChAngle(HHGear);
if (HHGear^.State and gstMoving) <> 0 then
@@ -1114,7 +1128,7 @@
exit
end;
- if not isInMultiShoot and (Hedgehog^.Gear <> nil) then
+ if Hedgehog^.Gear <> nil then
begin
if GHStepTicks > 0 then
dec(GHStepTicks);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uGearsList.pas
--- a/hedgewars/uGearsList.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uGearsList.pas Fri Feb 22 05:05:32 2013 +0100
@@ -35,8 +35,83 @@
uTextures, uScript, uRenderUtils, uAI, uCollisions,
uGearsRender, uGearsUtils, uDebug;
+const
+ GearKindAmmoTypeMap : array [TGearType] of TAmmoType = (
+(* gtFlame *) amNothing
+(* gtHedgehog *) , amNothing
+(* gtMine *) , amMine
+(* gtCase *) , amNothing
+(* gtExplosives *) , amNothing
+(* gtGrenade *) , amGrenade
+(* gtShell *) , amBazooka
+(* gtGrave *) , amNothing
+(* gtBee *) , amBee
+(* gtShotgunShot *) , amShotgun
+(* gtPickHammer *) , amPickHammer
+(* gtRope *) , amRope
+(* gtDEagleShot *) , amDEagle
+(* gtDynamite *) , amDynamite
+(* gtClusterBomb *) , amClusterBomb
+(* gtCluster *) , amClusterBomb
+(* gtShover *) , amBaseballBat // Shover is only used for baseball bat right now
+(* gtFirePunch *) , amFirePunch
+(* gtATStartGame *) , amNothing
+(* gtATFinishGame *) , amNothing
+(* gtParachute *) , amParachute
+(* gtAirAttack *) , amAirAttack
+(* gtAirBomb *) , amAirAttack
+(* gtBlowTorch *) , amBlowTorch
+(* gtGirder *) , amGirder
+(* gtTeleport *) , amTeleport
+(* gtSwitcher *) , amSwitch
+(* gtTarget *) , amNothing
+(* gtMortar *) , amMortar
+(* gtWhip *) , amWhip
+(* gtKamikaze *) , amKamikaze
+(* gtCake *) , amCake
+(* gtSeduction *) , amSeduction
+(* gtWatermelon *) , amWatermelon
+(* gtMelonPiece *) , amWatermelon
+(* gtHellishBomb *) , amHellishBomb
+(* gtWaterUp *) , amNothing
+(* gtDrill *) , amDrill
+(* gtBallGun *) , amBallgun
+(* gtBall *) , amBallgun
+(* gtRCPlane *) , amRCPlane
+(*gtSniperRifleShot *) , amSniperRifle
+(* gtJetpack *) , amJetpack
+(* gtMolotov *) , amMolotov
+(* gtBirdy *) , amBirdy
+(* gtEgg *) , amBirdy
+(* gtPortal *) , amPortalGun
+(* gtPiano *) , amPiano
+(* gtGasBomb *) , amGasBomb
+(* gtSineGunShot *) , amSineGun
+(* gtFlamethrower *) , amFlamethrower
+(* gtSMine *) , amSMine
+(* gtPoisonCloud *) , amNothing
+(* gtHammer *) , amHammer
+(* gtHammerHit *) , amHammer
+(* gtResurrector *) , amResurrector
+(* gtPoisonCloud *) , amNothing
+(* gtSnowball *) , amSnowball
+(* gtFlake *) , amNothing
+//(* gtStructure *) , amStructure // TODO - This will undoubtedly change once there is more than one structure
+(* gtLandGun *) , amLandGun
+(* gtTardis *) , amTardis
+(* gtIceGun *) , amIceGun
+(* gtAddAmmo *) , amNothing
+(* gtGenericFaller *) , amNothing
+(* gtKnife *) , amKnife
+ );
+
+
var GCounter: LongWord = 0; // this does not get re-initialized, but should be harmless
+const
+ cUsualZ = 500;
+ cOnHHZ = 2000;
+
procedure InsertGearToList(Gear: PGear);
var tmp, ptmp: PGear;
begin
@@ -252,7 +327,7 @@
end;
gtKnife: begin
gear^.Density:= _4;
- gear^.Radius:= 16
+ gear^.Radius:= 7
end;
gtCase: begin
gear^.ImpactSound:= sndGraveImpact;
@@ -461,6 +536,7 @@
gear^.Radius:= 5;
gear^.Density:= _1_5;
end;
+{
gtStructure: begin
gear^.Elasticity:= _0_55;
gear^.Friction:= _0_995;
@@ -471,6 +547,7 @@
gear^.Tag:= TotalRounds + 3;
gear^.Pos:= 1;
end;
+}
gtIceGun: gear^.Health:= 1000;
gtGenericFaller:begin
gear^.AdvBounce:= 1;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uGearsRender.pas
--- a/hedgewars/uGearsRender.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uGearsRender.pas Fri Feb 22 05:05:32 2013 +0100
@@ -39,6 +39,14 @@
implementation
uses uRender, uUtils, uVariables, uAmmos, Math, uVisualGears;
+const
+ // hog tag mask
+ //htNone = $00;
+ htTeamName = $01;
+ htName = $02;
+ htHealth = $04;
+ htTransparent = $08;
+
procedure DrawRopeLinesRQ(Gear: PGear);
begin
with RopePoints do
@@ -1098,8 +1106,8 @@
startX:= max(max(LAND_WIDTH,4096) + 1024, endX + 2048)
else
startX:= max(-max(LAND_WIDTH,4096) - 1024, endX - 2048);
- startY:= endY - 256;
- DrawTextureF(SpritesData[sprBirdy].Texture, 1, startX + WorldDx + LongInt(round((endX - startX) * (-power(2, -10 * LongInt(Gear^.Timer)/2000) + 1))), startY + WorldDy + LongInt(round((endY - startY) * sqrt(1 - power((LongInt(Gear^.Timer)/2000)-1, 2)))), ((Gear^.Pos shr 6) or (RealTicks shr 8)) mod 2, Gear^.Tag, 75, 75);
+ startY:= endY - 1024;
+ DrawTextureF(SpritesData[sprBirdy].Texture, min(Gear^.Timer/750,1), startX + WorldDx + LongInt(round((endX - startX) * (-power(2, -10 * LongInt(Gear^.Timer)/2000) + 1))), startY + WorldDy + LongInt(round((endY - startY) * sqrt(1 - power((LongInt(Gear^.Timer)/2000)-1, 2)))), ((Gear^.Pos shr 6) or (RealTicks shr 8)) mod 2, Gear^.Tag, 75, 75);
end
else // Disappearing
begin
@@ -1109,8 +1117,8 @@
endX:= max(max(LAND_WIDTH,4096) + 1024, startX + 2048)
else
endX:= max(-max(LAND_WIDTH,4096) - 1024, startX - 2048);
- endY:= startY + 256;
- DrawTextureF(SpritesData[sprBirdy].Texture, 1, startX + WorldDx + LongInt(round((endX - startX) * power(2, 10 * (LongInt(Gear^.Timer)/2000 - 1)))) + hwRound(Gear^.dX * Gear^.Timer), startY + WorldDy + LongInt(round((endY - startY) * cos(LongInt(Gear^.Timer)/2000 * (Pi/2)) - (endY - startY))) + hwRound(Gear^.dY * Gear^.Timer), ((Gear^.Pos shr 6) or (RealTicks shr 8)) mod 2, Gear^.Tag, 75, 75);
+ endY:= startY + 1024;
+ DrawTextureF(SpritesData[sprBirdy].Texture, min((2000-Gear^.Timer)/750,1), startX + WorldDx + LongInt(round((endX - startX) * power(2, 10 * (LongInt(Gear^.Timer)/2000 - 1)))) + hwRound(Gear^.dX * Gear^.Timer), startY + WorldDy + LongInt(round((endY - startY) * cos(LongInt(Gear^.Timer)/2000 * (Pi/2)) - (endY - startY))) + hwRound(Gear^.dY * Gear^.Timer), ((Gear^.Pos shr 6) or (RealTicks shr 8)) mod 2, Gear^.Tag, 75, 75);
end;
end
else
@@ -1178,7 +1186,7 @@
if Gear^.FlightTime > 0 then
Tint($FF, $FF, $FF, $FF);
end;
- gtStructure: DrawSprite(sprTarget, x - 16, y - 16, 0);
+ //gtStructure: DrawSprite(sprTarget, x - 16, y - 16, 0);
gtTardis: if Gear^.Pos <> 4 then
begin
if Gear^.Pos = 2 then
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uGearsUtils.pas
--- a/hedgewars/uGearsUtils.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uGearsUtils.pas Fri Feb 22 05:05:32 2013 +0100
@@ -106,8 +106,8 @@
gtTarget,
gtFlame,
gtKnife,
- gtExplosives,
- gtStructure: begin
+ gtExplosives: begin //,
+ //gtStructure: begin
// Run the calcs only once we know we have a type that will need damage
tdX:= Gear^.X-fX;
tdY:= Gear^.Y-fY;
@@ -243,8 +243,8 @@
end;
uStats.HedgehogDamaged(Gear, AttackerHog, Damage, false);
end;
- end
- else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure
+ end else
+ //else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure
Gear^.Hedgehog:= AttackerHog;
inc(Gear^.Damage, Damage);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uIO.pas
--- a/hedgewars/uIO.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uIO.pas Fri Feb 22 05:05:32 2013 +0100
@@ -30,7 +30,7 @@
procedure SendIPCXY(cmd: char; X, Y: LongInt);
procedure SendIPCRaw(p: pointer; len: Longword);
procedure SendIPCAndWaitReply(s: shortstring);
-procedure SendKeepAliveMessage(Lag: Longword);
+procedure FlushMessages(Lag: Longword);
procedure LoadRecordFromFile(fileName: shortstring);
procedure SendStat(sit: TStatInfoType; s: shortstring);
procedure IPCWaitPongEvent;
@@ -41,6 +41,10 @@
implementation
uses uConsole, uConsts, uVariables, uCommands, uUtils, uDebug;
+const
+ cSendEmptyPacketTime = 1000;
+ cSendBufferSize = 1024;
+
type PCmd = ^TCmd;
TCmd = packed record
Next: PCmd;
@@ -60,7 +64,11 @@
headcmd: PCmd;
lastcmd: PCmd;
- SendEmptyPacketTicks: LongWord;
+ flushDelayTicks: LongWord;
+ sendBuffer: record
+ buf: array[0..Pred(cSendBufferSize)] of byte;
+ count: Word;
+ end;
function AddCmd(Time: Word; str: shortstring): PCmd;
var command: PCmd;
@@ -121,6 +129,7 @@
'E': OutError(copy(s, 2, Length(s) - 1), true);
'W': OutError(copy(s, 2, Length(s) - 1), false);
'M': ParseCommand('landcheck ' + s, true);
+ 'o': if fastUntilLag then ParseCommand('forcequit', true);
'T': case s[2] of
'L': GameType:= gmtLocal;
'D': GameType:= gmtDemo;
@@ -135,7 +144,7 @@
else
loTicks:= SDLNet_Read16(@s[byte(s[0]) - 1]);
AddCmd(loTicks, s);
- AddFileLog('[IPC in] '+s[1]+' ticks '+IntToStr(lastcmd^.loTime));
+ AddFileLog('[IPC in] ' + sanitizeCharForLog(s[1]) + ' ticks ' + IntToStr(lastcmd^.loTime));
end
end;
@@ -210,19 +219,39 @@
SendIPCRaw(@buf[0], length(buf) + 1)
end;
+function isSyncedCommand(c: char): boolean;
+begin
+ isSyncedCommand:= (c in ['+', '#', 'L', 'l', 'R', 'r', 'U', 'u', 'D', 'd', 'Z', 'z', 'A', 'a', 'S', 'j', 'J', ',', 'c', 's', 'b', 'F', 'N', 'p', 'P', 'w', 't', 'h', '1', '2', '3', '4', '5']) or ((c >= #128) and (c <= char(128 + cMaxSlotIndex)))
+end;
+
+procedure flushBuffer();
+begin
+ SDLNet_TCP_Send(IPCSock, @sendBuffer.buf, sendBuffer.count);
+ flushDelayTicks:= 0;
+ sendBuffer.count:= 0
+end;
procedure SendIPC(s: shortstring);
begin
if IPCSock <> nil then
begin
- SendEmptyPacketTicks:= 0;
- if s[0]>#251 then
+ if s[0] > #251 then
s[0]:= #251;
SDLNet_Write16(GameTicks, @s[Succ(byte(s[0]))]);
- AddFileLog('[IPC out] '+ s[1]);
+
+ AddFileLog('[IPC out] '+ sanitizeCharForLog(s[1]));
inc(s[0], 2);
- SDLNet_TCP_Send(IPCSock, @s, Succ(byte(s[0])))
+
+ if isSyncedCommand(s[1]) then
+ begin
+ if sendBuffer.count + byte(s[0]) >= cSendBufferSize then
+ flushBuffer();
+
+ Move(s, sendBuffer.buf[sendBuffer.count], byte(s[0]) + 1);
+ inc(sendBuffer.count, byte(s[0]) + 1)
+ end else
+ SDLNet_TCP_Send(IPCSock, @s, Succ(byte(s[0])))
end
end;
@@ -237,10 +266,10 @@
procedure SendIPCXY(cmd: char; X, Y: LongInt);
var s: shortstring;
begin
-s[0]:= #5;
+s[0]:= #9;
s[1]:= cmd;
SDLNet_Write32(X, @s[2]);
-SDLNet_Write32(Y, @s[4]);
+SDLNet_Write32(Y, @s[6]);
SendIPC(s)
end;
@@ -260,11 +289,16 @@
IPCWaitPongEvent
end;
-procedure SendKeepAliveMessage(Lag: Longword);
+procedure FlushMessages(Lag: Longword);
begin
-inc(SendEmptyPacketTicks, Lag);
-if (SendEmptyPacketTicks >= cSendEmptyPacketTime) then
- SendIPC(_S'+')
+inc(flushDelayTicks, Lag);
+if (flushDelayTicks >= cSendEmptyPacketTime) then
+ begin
+ if sendBuffer.count = 0 then
+ SendIPC(_S'+');
+
+ flushBuffer()
+ end
end;
procedure NetGetNextCmd;
@@ -335,10 +369,12 @@
// these are equations solved for CursorPoint
// SDLNet_Read16(@(headcmd^.X)) == CursorPoint.X - WorldDx;
// SDLNet_Read16(@(headcmd^.Y)) == cScreenHeight - CursorPoint.Y - WorldDy;
- if not (CurrentTeam^.ExtDriven and bShowAmmoMenu) then
+ if CurrentTeam^.ExtDriven then
begin
- CursorPoint.X:= LongInt(SDLNet_Read32(@(headcmd^.X))) + WorldDx;
- CursorPoint.Y:= cScreenHeight - LongInt(SDLNet_Read32(@(headcmd^.Y))) - WorldDy
+ TargetCursorPoint.X:= LongInt(SDLNet_Read32(@(headcmd^.X))) + WorldDx;
+ TargetCursorPoint.Y:= cScreenHeight - LongInt(SDLNet_Read32(@(headcmd^.Y))) - WorldDy;
+ if not bShowAmmoMenu and autoCameraOn then
+ CursorPoint:= TargetCursorPoint
end
end;
'w': ParseCommand('setweap ' + headcmd^.str[2], true);
@@ -428,7 +464,8 @@
SocketString:= '';
hiTicks:= 0;
- SendEmptyPacketTicks:= 0;
+ flushDelayTicks:= 0;
+ sendBuffer.count:= 0;
end;
procedure freeModule;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uInputHandler.pas
--- a/hedgewars/uInputHandler.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uInputHandler.pas Fri Feb 22 05:05:32 2013 +0100
@@ -39,6 +39,7 @@
procedure SetBinds(var binds: TBinds);
procedure SetDefaultBinds;
+procedure chDefaultBind(var id: shortstring);
procedure ControllerInit;
procedure ControllerAxisEvent(joy, axis: Byte; value: Integer);
@@ -60,6 +61,17 @@
quitKeyCode, closeKeyCode: Byte;
KeyNames: array [0..cKeyMaxIndex] of string[15];
CurrentBinds: TBinds;
+ ControllerNumControllers: Integer;
+ ControllerEnabled: Integer;
+ ControllerNumAxes: array[0..5] of Integer;
+ //ControllerNumBalls: array[0..5] of Integer;
+ ControllerNumHats: array[0..5] of Integer;
+ ControllerNumButtons: array[0..5] of Integer;
+ //ControllerAxes: array[0..5] of array[0..19] of Integer;
+ //ControllerBalls: array[0..5] of array[0..19] of array[0..1] of Integer;
+ //ControllerHats: array[0..5] of array[0..19] of Byte;
+ //ControllerButtons: array[0..5] of array[0..19] of Byte;
+ usingDBinds: boolean;
function KeyNameToCode(name: shortstring): LongInt; inline;
begin
@@ -319,9 +331,9 @@
binds:= binds; // avoid hint
CurrentBinds:= DefaultBinds;
{$ELSE}
-for t:= 0 to cKbdMaxIndex do
- if (CurrentBinds[t] <> binds[t]) and tkbd[t] then
- ProcessKey(t, False);
+ for t:= 0 to cKbdMaxIndex do
+ if (CurrentBinds[t] <> binds[t]) and tkbd[t] then
+ ProcessKey(t, False);
CurrentBinds:= binds;
{$ENDIF}
@@ -343,7 +355,7 @@
var Controller: array [0..5] of PSDL_Joystick;
procedure ControllerInit;
-var i, j: Integer;
+var j: Integer;
begin
ControllerEnabled:= 0;
{$IFDEF IPHONE}
@@ -388,18 +400,18 @@
if ControllerNumButtons[j] > 20 then
ControllerNumButtons[j]:= 20;
- // reset all buttons/axes
+ (*// reset all buttons/axes
for i:= 0 to pred(ControllerNumAxes[j]) do
ControllerAxes[j][i]:= 0;
- (*for i:= 0 to pred(ControllerNumBalls[j]) do
+ for i:= 0 to pred(ControllerNumBalls[j]) do
begin
ControllerBalls[j][i][0]:= 0;
ControllerBalls[j][i][1]:= 0;
- end;*)
+ end;
for i:= 0 to pred(ControllerNumHats[j]) do
ControllerHats[j][i]:= SDL_HAT_CENTERED;
for i:= 0 to pred(ControllerNumButtons[j]) do
- ControllerButtons[j][i]:= 0;
+ ControllerButtons[j][i]:= 0;*)
end;
end;
// enable event generation/controller updating
@@ -440,8 +452,45 @@
ProcessKey(k + ControllerNumAxes[joy]*2 + ControllerNumHats[joy]*4 + button, pressed);
end;
+// Bind that isn't a team bind, but overrides defaultbinds.
+// When first called, DefaultBinds is cleared, because we assume we are getting a full list of dbinds.
+procedure chDefaultBind(var id: shortstring);
+var KeyName, Modifier, tmp: shortstring;
+ b: LongInt;
+begin
+KeyName:= '';
+Modifier:= '';
+
+if (not usingDBinds) then
+ begin
+ usingDBinds:= true;
+ FillByte(DefaultBinds, SizeOf(DefaultBinds), 0);
+ end;
+
+if (Pos('mod:', id) <> 0) then
+ begin
+ tmp:= '';
+ SplitBySpace(id, tmp);
+ Modifier:= id;
+ id:= tmp;
+ end;
+
+SplitBySpace(id, KeyName);
+if KeyName[1]='"' then
+ Delete(KeyName, 1, 1);
+if KeyName[byte(KeyName[0])]='"' then
+ Delete(KeyName, byte(KeyName[0]), 1);
+b:= KeyNameToCode(id, Modifier);
+if b = 0 then
+ OutError(errmsgUnknownVariable + ' "' + id + '"', false)
+else
+ DefaultBinds[b]:= KeyName;
+end;
+
procedure initModule;
begin
+ usingDBinds:= false;
+ RegisterVariable('dbind', @chDefaultBind, true );
end;
procedure freeModule;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uLand.pas
--- a/hedgewars/uLand.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uLand.pas Fri Feb 22 05:05:32 2013 +0100
@@ -31,7 +31,7 @@
implementation
uses uConsole, uStore, uRandom, uLandObjects, uIO, uLandTexture, SysUtils,
uVariables, uUtils, uCommands, adler32, uDebug, uLandPainted, uTextures,
- uLandGenMaze, uLandOutline;
+ uLandGenMaze, uLandOutline, uPhysFSLayer;
var digest: shortstring;
@@ -423,26 +423,26 @@
end;
procedure LoadMapConfig;
-var f: textfile;
+var f: PFSFile;
s: shortstring;
begin
s:= cPathz[ptMapCurrent] + '/map.cfg';
WriteLnToConsole('Fetching map HH limit');
-{$I-}
-Assign(f, s);
-filemode:= 0; // readonly
-Reset(f);
-if IOResult <> 0 then
+
+f:= pfsOpenRead(s);
+if f <> nil then
begin
- s:= cPathz[ptMissionMaps] + '/' + ExtractFileName(cPathz[ptMapCurrent]) + '/map.cfg';
- Assign(f, s);
- Reset(f);
+ pfsReadLn(f, s);
+ if not pfsEof(f) then
+ begin
+ pfsReadLn(f, s);
+ val(s, MaxHedgehogs)
+ end;
+
+ pfsClose(f)
end;
-Readln(f);
-if not eof(f) then
- Readln(f, MaxHedgehogs);
-{$I+}
+
if (MaxHedgehogs = 0) then
MaxHedgehogs:= 18;
end;
@@ -523,7 +523,6 @@
procedure LoadMap;
var tmpsurf: PSDL_Surface;
- s: shortstring;
mapName: shortstring = '';
begin
WriteLnToConsole('Loading land from file...');
@@ -596,7 +595,7 @@
begin
map:= cPathz[ptMapCurrent] + '/map.png';
mask:= cPathz[ptMapCurrent] + '/mask.png';
- if (not(FileExists(map)) and FileExists(mask)) then
+ if (not(pfsExists(map)) and pfsExists(mask)) then
begin
maskOnly:= true;
LoadMask;
@@ -631,7 +630,7 @@
if Land[y, x] <> 0 then
begin
inc(c);
- if c > 1000 then // avoid accidental triggering
+ if c > LongWord((LAND_WIDTH div 2)) then // avoid accidental triggering
begin
hasBorder:= true;
break;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uLandObjects.pas
--- a/hedgewars/uLandObjects.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uLandObjects.pas Fri Feb 22 05:05:32 2013 +0100
@@ -37,6 +37,7 @@
const MaxRects = 512;
MAXOBJECTRECTS = 16;
MAXTHEMEOBJECTS = 32;
+ cThemeCFGFilename = 'theme.cfg';
type TRectsArray = array[0..MaxRects] of TSDL_Rect;
PRectArray = ^TRectsArray;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uLandOutline.pas
--- a/hedgewars/uLandOutline.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uLandOutline.pas Fri Feb 22 05:05:32 2013 +0100
@@ -27,6 +27,9 @@
end
end;
+const
+ cMaxEdgePoints = 16384;
+
procedure Push(_xl, _xr, _y, _dir: LongInt);
begin
TryDo(Stack.Count <= 8192, 'FillLand: stack overflow', true);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uLandTexture.pas
--- a/hedgewars/uLandTexture.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uLandTexture.pas Fri Feb 22 05:05:32 2013 +0100
@@ -66,6 +66,7 @@
procedure UpdateLandTexture(X, Width, Y, Height: LongInt; landAdded: boolean);
var tx, ty: Longword;
begin
+ if cOnlyStats then exit;
if (Width <= 0) or (Height <= 0) then
exit;
TryDo((X >= 0) and (X < LAND_WIDTH), 'UpdateLandTexture: wrong X parameter', true);
@@ -93,6 +94,7 @@
var x, y, ty, tx, lx, ly : LongWord;
isEmpty: boolean;
begin
+ if cOnlyStats then exit;
(*
if LandTextures[0, 0].tex = nil then
for x:= 0 to LANDTEXARW -1 do
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uLocale.pas
--- a/hedgewars/uLocale.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uLocale.pas Fri Feb 22 05:05:32 2013 +0100
@@ -40,14 +40,12 @@
trevt_n: array[TEventId] of integer;
procedure LoadLocale(FileName: shortstring);
-var s: shortstring;
+var s: ansistring = '';
f: pfsFile;
a, b, c: LongInt;
first: array[TEventId] of boolean;
e: TEventId;
- loaded: boolean;
begin
-loaded:= false;
for e:= Low(TEventId) to High(TEventId) do
first[e]:= true;
@@ -58,7 +56,7 @@
begin
while not pfsEof(f) do
begin
- pfsReadLn(f, s);
+ pfsReadLnA(f, s);
if Length(s) = 0 then
continue;
if (s[1] < '0') or (s[1] > '9') then
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uMobile.pas
--- a/hedgewars/uMobile.pas Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-(*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- *)
-
-{$INCLUDE "options.inc"}
-
-(*
- * This unit contains a lot of useful functions when hw is running on mobile
- * Unlike HwLibrary when you declare functions that you will call from your code,
- * here you need to provide functions that Pascall code will call.
- *)
-
-unit uMobile;
-interface
-
-function isPhone: Boolean; inline;
-function getScreenDPI: Double; inline;
-procedure performRumble; inline;
-
-procedure GameLoading; inline;
-procedure GameLoaded; inline;
-procedure SaveLoadingEnded; inline;
-
-implementation
-uses uVariables, uConsole, SDLh;
-
-// add here any external call that you need
-{$IFDEF IPHONEOS}
-(* iOS calls written in ObjcExports.m *)
-procedure startLoadingIndicator; cdecl; external;
-procedure stopLoadingIndicator; cdecl; external;
-procedure saveFinishedSynching; cdecl; external;
-function isApplePhone: Boolean; cdecl; external;
-procedure AudioServicesPlaySystemSound(num: LongInt); cdecl; external;
-{$ENDIF}
-
-// this function is just to determine whether we are running on a limited screen device
-function isPhone: Boolean; inline;
-begin
- isPhone:= false;
-{$IFDEF IPHONEOS}
- isPhone:= isApplePhone();
-{$ENDIF}
-{$IFDEF ANDROID}
- //nasty nasty hack. TODO: implement callback to java to have a unified way of determining if it is a tablet
- if (cScreenWidth < 1000) and (cScreenHeight < 500) then
- isPhone:= true;
-{$ENDIF}
-end;
-
-function getScreenDPI: Double; inline;
-begin
-{$IFDEF ANDROID}
-// getScreenDPI:= Android_JNI_getDensity();
- getScreenDPI:= 1;
-{$ELSE}
- getScreenDPI:= 1;
-{$ENDIF}
-end;
-
-// this function should make the device vibrate in some way
-procedure PerformRumble; inline;
-{$IFDEF IPHONEOS}const kSystemSoundID_Vibrate = $00000FFF;{$ENDIF}
-begin
- // do not vibrate while synchronising a demo/save
- if not fastUntilLag then
- begin
-{$IFDEF IPHONEOS}
- AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
-{$ENDIF}
- end;
-end;
-
-procedure GameLoading; inline;
-begin
-{$IFDEF IPHONEOS}
- startLoadingIndicator();
-{$ENDIF}
-end;
-
-procedure GameLoaded; inline;
-begin
-{$IFDEF IPHONEOS}
- stopLoadingIndicator();
-{$ENDIF}
-end;
-
-procedure SaveLoadingEnded; inline;
-begin
-{$IFDEF IPHONEOS}
- saveFinishedSynching();
-{$ENDIF}
-end;
-
-
-end.
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uPhysFSLayer.pas
--- a/hedgewars/uPhysFSLayer.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uPhysFSLayer.pas Fri Feb 22 05:05:32 2013 +0100
@@ -1,10 +1,22 @@
unit uPhysFSLayer;
-{$LINKLIB ../bin/libphysfs.a}
-{$LINKLIB ../bin/libphysfsrwops.a}
+interface
+uses SDLh, LuaPas;
-interface
-uses SDLh;
+{$IFDEF ANDROID}
+ {$linklib physfs}
+{$ELSE}
+ {$IFDEF DARWIN}
+ {$LINKFRAMEWORK IOKit}
+ {$ENDIF}
+{$ENDIF}
+
+const
+{$IFDEF WIN32}
+ PhysfsLibName = 'libphysfs';
+{$ELSE}
+ PhysfsLibName = 'physfs';
+{$ENDIF}
procedure initModule;
procedure freeModule;
@@ -18,27 +30,31 @@
function pfsClose(f: PFSFile): boolean;
procedure pfsReadLn(f: PFSFile; var s: shortstring);
+procedure pfsReadLnA(f: PFSFile; var s: ansistring);
function pfsBlockRead(f: PFSFile; buf: pointer; size: Int64): Int64;
function pfsEOF(f: PFSFile): boolean;
function pfsExists(fname: shortstring): boolean;
-implementation
-uses uUtils, uVariables;
+function physfsReader(L: Plua_State; f: PFSFile; sz: Psize_t) : PChar; cdecl; external PhysfsLibName;
+procedure physfsReaderSetBuffer(buf: pointer); cdecl; external PhysfsLibName;
-function PHYSFS_init(argv0: PChar) : LongInt; cdecl; external;
-function PHYSFS_deinit() : LongInt; cdecl; external;
-function PHYSFSRWOPS_openRead(fname: PChar): PSDL_RWops; cdecl; external;
-function PHYSFSRWOPS_openWrite(fname: PChar): PSDL_RWops; cdecl; external;
+implementation
+uses uUtils, uVariables, sysutils;
-function PHYSFS_mount(newDir, mountPoint: PChar; appendToPath: LongBool) : LongInt; cdecl; external;
-function PHYSFS_openRead(fname: PChar): PFSFile; cdecl; external;
-function PHYSFS_eof(f: PFSFile): LongBool; cdecl; external;
-function PHYSFS_readBytes(f: PFSFile; buffer: pointer; len: Int64): Int64; cdecl; external;
-function PHYSFS_close(f: PFSFile): LongBool; cdecl; external;
-function PHYSFS_exists(fname: PChar): LongBool; cdecl; external;
+function PHYSFS_init(argv0: PChar) : LongInt; cdecl; external PhysfsLibName;
+function PHYSFS_deinit() : LongInt; cdecl; external PhysfsLibName;
+function PHYSFSRWOPS_openRead(fname: PChar): PSDL_RWops; cdecl ; external PhysfsLibName;
+function PHYSFSRWOPS_openWrite(fname: PChar): PSDL_RWops; cdecl; external PhysfsLibName;
-procedure hedgewarsMountPackages(); cdecl; external;
+function PHYSFS_mount(newDir, mountPoint: PChar; appendToPath: LongBool) : LongInt; cdecl; external PhysfsLibName;
+function PHYSFS_openRead(fname: PChar): PFSFile; cdecl; external PhysfsLibName;
+function PHYSFS_eof(f: PFSFile): LongBool; cdecl; external PhysfsLibName;
+function PHYSFS_readBytes(f: PFSFile; buffer: pointer; len: Int64): Int64; cdecl; external PhysfsLibName;
+function PHYSFS_close(f: PFSFile): LongBool; cdecl; external PhysfsLibName;
+function PHYSFS_exists(fname: PChar): LongBool; cdecl; external PhysfsLibName;
+
+procedure hedgewarsMountPackages(); cdecl; external PhysfsLibName;
function rwopsOpenRead(fname: shortstring): PSDL_RWops;
begin
@@ -84,6 +100,28 @@
end
end;
+procedure pfsReadLnA(f: PFSFile; var s: ansistring);
+var c: char;
+ b: shortstring;
+begin
+s:= '';
+b[0]:= #0;
+
+while (PHYSFS_readBytes(f, @c, 1) = 1) and (c <> #10) do
+ if (c <> #13) then
+ begin
+ inc(b[0]);
+ b[byte(b[0])]:= c;
+ if b[0] = #255 then
+ begin
+ s:= s + b;
+ b[0]:= #0
+ end
+ end;
+
+s:= s + b
+end;
+
function pfsBlockRead(f: PFSFile; buf: pointer; size: Int64): Int64;
var r: Int64;
begin
@@ -97,8 +135,16 @@
procedure initModule;
var i: LongInt;
+ cPhysfsId: shortstring;
begin
- i:= PHYSFS_init(Str2PChar(ParamStr(0)));
+{$IFDEF HWLIBRARY}
+ //TODO: http://icculus.org/pipermail/physfs/2011-August/001006.html
+ cPhysfsId:= GetCurrentDir() + {$IFDEF DARWIN}'/Hedgewars.app/Contents/MacOS/' + {$ENDIF} ' hedgewars';
+{$ELSE}
+ cPhysfsId:= ParamStr(0);
+{$ENDIF}
+
+ i:= PHYSFS_init(Str2PChar(cPhysfsId));
AddFileLog('[PhysFS] init: ' + inttostr(i));
i:= PHYSFS_mount(Str2PChar(PathPrefix), nil, true);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uRender.pas
--- a/hedgewars/uRender.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uRender.pas Fri Feb 22 05:05:32 2013 +0100
@@ -55,6 +55,12 @@
implementation
uses uVariables;
+{$IFDEF USE_TOUCH_INTERFACE}
+const
+ FADE_ANIM_TIME = 500;
+ MOVE_ANIM_TIME = 500;
+{$ENDIF}
+
var LastTint: LongWord = 0;
procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uScript.pas
--- a/hedgewars/uScript.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uScript.pas Fri Feb 22 05:05:32 2013 +0100
@@ -37,6 +37,7 @@
procedure ScriptLoad(name : shortstring);
procedure ScriptOnGameInit;
procedure ScriptOnScreenResize;
+procedure ScriptSetInteger(name : shortstring; value : LongInt);
procedure ScriptCall(fname : shortstring);
function ScriptCall(fname : shortstring; par1: LongInt) : LongInt;
@@ -224,6 +225,35 @@
lc_hidemission:= 0;
end;
+function lc_enablegameflags(L : Plua_State) : LongInt; Cdecl;
+var i : integer;
+begin
+ for i:= 1 to lua_gettop(L) do
+ if (GameFlags and lua_tointeger(L, i)) = 0 then
+ GameFlags := GameFlags + LongWord(lua_tointeger(L, i));
+ ScriptSetInteger('GameFlags', GameFlags);
+ lc_enablegameflags:= 0;
+end;
+
+function lc_disablegameflags(L : Plua_State) : LongInt; Cdecl;
+var i : integer;
+begin
+ for i:= 1 to lua_gettop(L) do
+ if (GameFlags and lua_tointeger(L, i)) <> 0 then
+ GameFlags := GameFlags - LongWord(lua_tointeger(L, i));
+ ScriptSetInteger('GameFlags', GameFlags);
+ lc_disablegameflags:= 0;
+end;
+
+function lc_cleargameflags(L : Plua_State) : LongInt; Cdecl;
+begin
+ // Silence hint
+ L:= L;
+ GameFlags:= 0;
+ ScriptSetInteger('GameFlags', GameFlags);
+ lc_cleargameflags:= 0;
+end;
+
function lc_addcaption(L : Plua_State) : LongInt; Cdecl;
begin
if lua_gettop(L) = 1 then
@@ -690,7 +720,7 @@
else
begin
gear := GearByUID(lua_tointeger(L, 1));
- if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+ if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
lua_pushinteger(L, gear^.Hedgehog^.BotLevel)
else
lua_pushnil(L);
@@ -723,7 +753,7 @@
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
- if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+ if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
begin
lua_pushinteger(L, gear^.Hedgehog^.Team^.Clan^.ClanIndex)
end
@@ -805,7 +835,7 @@
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
- if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+ if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
begin
lua_pushstring(L, str2pchar(gear^.Hedgehog^.Team^.TeamName))
end
@@ -826,7 +856,7 @@
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
- if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+ if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
begin
lua_pushstring(L, str2pchar(gear^.Hedgehog^.Name))
end
@@ -1251,7 +1281,7 @@
function lc_endgame(L : Plua_State) : LongInt; Cdecl;
begin
L:= L; // avoid compiler hint
- GameState:= gsExit;
+ AddGear(0, 0, gtATFinishGame, 0, _0, _0, 3000);
lc_endgame:= 0
end;
@@ -1648,7 +1678,7 @@
LuaError('Lua: Wrong number of parameters passed to GetHogHat!')
else begin
gear := GearByUID(lua_tointeger(L, 1));
- if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+ if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
lua_pushstring(L, str2pchar(gear^.Hedgehog^.Hat))
else
lua_pushnil(L);
@@ -1735,8 +1765,7 @@
end;
function lc_restorehog(L: Plua_State): LongInt; Cdecl;
-var hog: PHedgehog;
- i, h: LongInt;
+var i, h: LongInt;
uid: LongWord;
begin
if lua_gettop(L) <> 1 then
@@ -1980,9 +2009,6 @@
// custom script loader via physfs, passed to lua_load
const BUFSIZE = 1024;
-var physfsReaderBuffer: pointer; external;
-function physfsReader(L: Plua_State; f: PFSFile; sz: Psize_t) : PChar; cdecl; external;
-
procedure ScriptLoad(name : shortstring);
var ret : LongInt;
@@ -1998,7 +2024,7 @@
if f = nil then
exit;
-physfsReaderBuffer:= @buf;
+physfsReaderSetBuffer(@buf);
ret:= lua_load(luaState, @physfsReader, f, Str2PChar(s));
pfsClose(f);
@@ -2020,7 +2046,6 @@
begin
ScriptSetInteger('TurnTimeLeft', TurnTimeLeft);
ScriptSetInteger('GameTime', GameTicks);
-ScriptSetInteger('RealTime', RealTicks);
ScriptSetInteger('TotalRounds', TotalRounds);
ScriptSetInteger('WaterLine', cWaterLine);
if GameTicks = 0 then
@@ -2322,6 +2347,7 @@
ScriptSetInteger('gstHHGone' ,$00100000);
ScriptSetInteger('gstInvisible' ,$00200000);
+// ai hints
ScriptSetInteger('aihUsualProcessing' ,$00000000);
ScriptSetInteger('aihDoesntMatter' ,$00000001);
@@ -2337,6 +2363,9 @@
lua_register(luaState, _P'GetInputMask', @lc_getinputmask);
lua_register(luaState, _P'SetInputMask', @lc_setinputmask);
lua_register(luaState, _P'AddGear', @lc_addgear);
+lua_register(luaState, _P'EnableGameFlags', @lc_enablegameflags);
+lua_register(luaState, _P'DisableGameFlags', @lc_disablegameflags);
+lua_register(luaState, _P'ClearGameFlags', @lc_cleargameflags);
lua_register(luaState, _P'DeleteGear', @lc_deletegear);
lua_register(luaState, _P'AddVisualGear', @lc_addvisualgear);
lua_register(luaState, _P'DeleteVisualGear', @lc_deletevisualgear);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uSound.pas
--- a/hedgewars/uSound.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uSound.pas Fri Feb 22 05:05:32 2013 +0100
@@ -21,7 +21,7 @@
unit uSound;
(*
* This unit controls the sounds and music of the game.
- * Doesn't really do anything if isSoundEnabled = false.
+ * Doesn't really do anything if isSoundEnabled = false and isMusicEnabled = false
*
* There are three basic types of sound controls:
* Music - The background music of the game:
@@ -105,12 +105,13 @@
function AskForVoicepack(name: shortstring): Pointer;
+var Volume: LongInt;
+ SoundTimerTicks: Longword;
implementation
-uses uVariables, uConsole, uUtils, uCommands, uDebug, uPhysFSLayer;
+uses uVariables, uConsole, uCommands, uDebug, uPhysFSLayer;
const chanTPU = 32;
-var Volume: LongInt;
- cInitVolume: LongInt;
+var cInitVolume: LongInt;
previousVolume: LongInt; // cached volume value
lastChan: array [TSound] of LongInt;
voicepacks: array[0..cMaxTeams] of TVoicepack;
@@ -120,6 +121,136 @@
isMusicEnabled: boolean;
isSoundEnabled: boolean;
isSEBackup: boolean;
+ VoiceList : array[0..7] of TVoice = (
+ ( snd: sndNone; voicepack: nil),
+ ( snd: sndNone; voicepack: nil),
+ ( snd: sndNone; voicepack: nil),
+ ( snd: sndNone; voicepack: nil),
+ ( snd: sndNone; voicepack: nil),
+ ( snd: sndNone; voicepack: nil),
+ ( snd: sndNone; voicepack: nil),
+ ( snd: sndNone; voicepack: nil));
+ Soundz: array[TSound] of record
+ FileName: string[31];
+ Path : TPathType;
+ end = (
+ (FileName: ''; Path: ptNone ),// sndNone
+ (FileName: 'grenadeimpact.ogg'; Path: ptSounds),// sndGrenadeImpact
+ (FileName: 'explosion.ogg'; Path: ptSounds),// sndExplosion
+ (FileName: 'throwpowerup.ogg'; Path: ptSounds),// sndThrowPowerUp
+ (FileName: 'throwrelease.ogg'; Path: ptSounds),// sndThrowRelease
+ (FileName: 'splash.ogg'; Path: ptSounds),// sndSplash
+ (FileName: 'shotgunreload.ogg'; Path: ptSounds),// sndShotgunReload
+ (FileName: 'shotgunfire.ogg'; Path: ptSounds),// sndShotgunFire
+ (FileName: 'graveimpact.ogg'; Path: ptSounds),// sndGraveImpact
+ (FileName: 'mineimpact.ogg'; Path: ptSounds),// sndMineImpact
+ (FileName: 'minetick.ogg'; Path: ptSounds),// sndMineTicks
+ (FileName: 'Droplet1.ogg'; Path: ptSounds),// sndMudballImpact
+ (FileName: 'pickhammer.ogg'; Path: ptSounds),// sndPickhammer
+ (FileName: 'gun.ogg'; Path: ptSounds),// sndGun
+ (FileName: 'bee.ogg'; Path: ptSounds),// sndBee
+ (FileName: 'Jump1.ogg'; Path: ptVoices),// sndJump1
+ (FileName: 'Jump2.ogg'; Path: ptVoices),// sndJump2
+ (FileName: 'Jump3.ogg'; Path: ptVoices),// sndJump3
+ (FileName: 'Yessir.ogg'; Path: ptVoices),// sndYesSir
+ (FileName: 'Laugh.ogg'; Path: ptVoices),// sndLaugh
+ (FileName: 'Illgetyou.ogg'; Path: ptVoices),// sndIllGetYou
+ (FileName: 'JustYouWait.ogg'; Path: ptVoices),// sndJustYouWait
+ (FileName: 'Incoming.ogg'; Path: ptVoices),// sndIncoming
+ (FileName: 'Missed.ogg'; Path: ptVoices),// sndMissed
+ (FileName: 'Stupid.ogg'; Path: ptVoices),// sndStupid
+ (FileName: 'Firstblood.ogg'; Path: ptVoices),// sndFirstBlood
+ (FileName: 'Boring.ogg'; Path: ptVoices),// sndBoring
+ (FileName: 'Byebye.ogg'; Path: ptVoices),// sndByeBye
+ (FileName: 'Sameteam.ogg'; Path: ptVoices),// sndSameTeam
+ (FileName: 'Nutter.ogg'; Path: ptVoices),// sndNutter
+ (FileName: 'Reinforcements.ogg'; Path: ptVoices),// sndReinforce
+ (FileName: 'Traitor.ogg'; Path: ptVoices),// sndTraitor
+ (FileName: 'Youllregretthat.ogg'; Path: ptVoices),// sndRegret
+ (FileName: 'Enemydown.ogg'; Path: ptVoices),// sndEnemyDown
+ (FileName: 'Coward.ogg'; Path: ptVoices),// sndCoward
+ (FileName: 'Hurry.ogg'; Path: ptVoices),// sndHurry
+ (FileName: 'Watchit.ogg'; Path: ptVoices),// sndWatchIt
+ (FileName: 'Kamikaze.ogg'; Path: ptVoices),// sndKamikaze
+ (FileName: 'cake2.ogg'; Path: ptSounds),// sndCake
+ (FileName: 'Ow1.ogg'; Path: ptVoices),// sndOw1
+ (FileName: 'Ow2.ogg'; Path: ptVoices),// sndOw2
+ (FileName: 'Ow3.ogg'; Path: ptVoices),// sndOw3
+ (FileName: 'Ow4.ogg'; Path: ptVoices),// sndOw4
+ (FileName: 'Firepunch1.ogg'; Path: ptVoices),// sndFirepunch1
+ (FileName: 'Firepunch2.ogg'; Path: ptVoices),// sndFirepunch2
+ (FileName: 'Firepunch3.ogg'; Path: ptVoices),// sndFirepunch3
+ (FileName: 'Firepunch4.ogg'; Path: ptVoices),// sndFirepunch4
+ (FileName: 'Firepunch5.ogg'; Path: ptVoices),// sndFirepunch5
+ (FileName: 'Firepunch6.ogg'; Path: ptVoices),// sndFirepunch6
+ (FileName: 'Melon.ogg'; Path: ptVoices),// sndMelon
+ (FileName: 'Hellish.ogg'; Path: ptSounds),// sndHellish
+ (FileName: 'Yoohoo.ogg'; Path: ptSounds),// sndYoohoo
+ (FileName: 'rcplane.ogg'; Path: ptSounds),// sndRCPlane
+ (FileName: 'whipcrack.ogg'; Path: ptSounds),// sndWhipCrack
+ (FileName:'ride_of_the_valkyries.ogg'; Path: ptSounds),// sndRideOfTheValkyries
+ (FileName: 'denied.ogg'; Path: ptSounds),// sndDenied
+ (FileName: 'placed.ogg'; Path: ptSounds),// sndPlaced
+ (FileName: 'baseballbat.ogg'; Path: ptSounds),// sndBaseballBat
+ (FileName: 'steam.ogg'; Path: ptSounds),// sndVaporize
+ (FileName: 'warp.ogg'; Path: ptSounds),// sndWarp
+ (FileName: 'suddendeath.ogg'; Path: ptSounds),// sndSuddenDeath
+ (FileName: 'mortar.ogg'; Path: ptSounds),// sndMortar
+ (FileName: 'shutterclick.ogg'; Path: ptSounds),// sndShutter
+ (FileName: 'homerun.ogg'; Path: ptSounds),// sndHomerun
+ (FileName: 'molotov.ogg'; Path: ptSounds),// sndMolotov
+ (FileName: 'Takecover.ogg'; Path: ptVoices),// sndCover
+ (FileName: 'Uh-oh.ogg'; Path: ptVoices),// sndUhOh
+ (FileName: 'Oops.ogg'; Path: ptVoices),// sndOops
+ (FileName: 'Nooo.ogg'; Path: ptVoices),// sndNooo
+ (FileName: 'Hello.ogg'; Path: ptVoices),// sndHello
+ (FileName: 'ropeshot.ogg'; Path: ptSounds),// sndRopeShot
+ (FileName: 'ropeattach.ogg'; Path: ptSounds),// sndRopeAttach
+ (FileName: 'roperelease.ogg'; Path: ptSounds),// sndRopeRelease
+ (FileName: 'switchhog.ogg'; Path: ptSounds),// sndSwitchHog
+ (FileName: 'Victory.ogg'; Path: ptVoices),// sndVictory
+ (FileName: 'Flawless.ogg'; Path: ptVoices),// sndFlawless
+ (FileName: 'sniperreload.ogg'; Path: ptSounds),// sndSniperReload
+ (FileName: 'steps.ogg'; Path: ptSounds),// sndSteps
+ (FileName: 'lowgravity.ogg'; Path: ptSounds),// sndLowGravity
+ (FileName: 'hell_growl.ogg'; Path: ptSounds),// sndHellishImpact1
+ (FileName: 'hell_ooff.ogg'; Path: ptSounds),// sndHellishImpact2
+ (FileName: 'hell_ow.ogg'; Path: ptSounds),// sndHellishImpact3
+ (FileName: 'hell_ugh.ogg'; Path: ptSounds),// sndHellishImpact4
+ (FileName: 'melonimpact.ogg'; Path: ptSounds),// sndMelonImpact
+ (FileName: 'Droplet1.ogg'; Path: ptSounds),// sndDroplet1
+ (FileName: 'Droplet2.ogg'; Path: ptSounds),// sndDroplet2
+ (FileName: 'Droplet3.ogg'; Path: ptSounds),// sndDroplet3
+ (FileName: 'egg.ogg'; Path: ptSounds),// sndEggBreak
+ (FileName: 'drillgun.ogg'; Path: ptSounds),// sndDrillRocket
+ (FileName: 'PoisonCough.ogg'; Path: ptVoices),// sndPoisonCough
+ (FileName: 'PoisonMoan.ogg'; Path: ptVoices),// sndPoisonMoan
+ (FileName: 'BirdyLay.ogg'; Path: ptSounds),// sndBirdyLay
+ (FileName: 'Whistle.ogg'; Path: ptSounds),// sndWhistle
+ (FileName: 'beewater.ogg'; Path: ptSounds),// sndBeeWater
+ (FileName: '1C.ogg'; Path: ptSounds),// sndPiano0
+ (FileName: '2D.ogg'; Path: ptSounds),// sndPiano1
+ (FileName: '3E.ogg'; Path: ptSounds),// sndPiano2
+ (FileName: '4F.ogg'; Path: ptSounds),// sndPiano3
+ (FileName: '5G.ogg'; Path: ptSounds),// sndPiano4
+ (FileName: '6A.ogg'; Path: ptSounds),// sndPiano5
+ (FileName: '7B.ogg'; Path: ptSounds),// sndPiano6
+ (FileName: '8C.ogg'; Path: ptSounds),// sndPiano7
+ (FileName: '9D.ogg'; Path: ptSounds),// sndPiano8
+ (FileName: 'skip.ogg'; Path: ptSounds),// sndSkip
+ (FileName: 'sinegun.ogg'; Path: ptSounds),// sndSineGun
+ (FileName: 'Ooff1.ogg'; Path: ptVoices),// sndOoff1
+ (FileName: 'Ooff2.ogg'; Path: ptVoices),// sndOoff2
+ (FileName: 'Ooff3.ogg'; Path: ptVoices),// sndOoff3
+ (FileName: 'hammer.ogg'; Path: ptSounds),// sndWhack
+ (FileName: 'Comeonthen.ogg'; Path: ptVoices),// sndComeonthen
+ (FileName: 'parachute.ogg'; Path: ptSounds),// sndParachute
+ (FileName: 'bump.ogg'; Path: ptSounds),// sndBump
+ (FileName: 'hogchant3.ogg'; Path: ptSounds),// sndResurrector
+ (FileName: 'plane.ogg'; Path: ptSounds),// sndPlane
+ (FileName: 'TARDIS.ogg'; Path: ptSounds) // sndTardis
+ );
+
function AskForVoicepack(name: shortstring): Pointer;
@@ -157,19 +288,24 @@
procedure InitSound;
const channels: LongInt = {$IFDEF MOBILE}1{$ELSE}2{$ENDIF};
+var success: boolean;
begin
- if not isSoundEnabled then
+ if not (isSoundEnabled or isMusicEnabled) then
exit;
WriteToConsole('Init sound...');
- isSoundEnabled:= SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0;
+ success:= SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0;
- if isSoundEnabled then
- isSoundEnabled:= Mix_OpenAudio(44100, $8010, channels, 1024) = 0;
+ if success then
+ success:= Mix_OpenAudio(44100, $8010, channels, 1024) = 0;
- if isSoundEnabled then
+ if success then
WriteLnToConsole(msgOK)
else
+ begin
WriteLnToConsole(msgFailed);
+ isSoundEnabled:= false;
+ isMusicEnabled:= false;
+ end;
WriteToConsole('Init SDL_mixer... ');
SDLTry(Mix_Init(MIX_INIT_OGG) <> 0, true);
@@ -256,7 +392,7 @@
if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then
begin
s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
- if (not FileExists(s)) and (snd in [sndFirePunch2, sndFirePunch3, sndFirePunch4, sndFirePunch5, sndFirePunch6]) then
+ if (not pfsExists(s)) and (snd in [sndFirePunch2, sndFirePunch3, sndFirePunch4, sndFirePunch5, sndFirePunch6]) then
s:= cPathz[Soundz[sndFirePunch1].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
WriteToConsole(msgLoading + s + ' ');
voicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwopsOpenRead(s), 1);
@@ -289,7 +425,7 @@
if (snd = sndVictory) or (snd = sndFlawless) then
begin
Mix_FadeOutChannel(-1, 800);
- for i:= 0 to 7 do
+ for i:= 0 to High(VoiceList) do
VoiceList[i].snd:= sndNone;
LastVoice.snd:= sndNone;
end;
@@ -311,7 +447,7 @@
if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd <> sndNone) and (lastChan[LastVoice.snd] <> -1) and (Mix_Playing(lastChan[LastVoice.snd]) <> 0)) then
exit;
i:= 0;
- while (i<8) and (VoiceList[i].snd = sndNone) do
+ while (i sndNone) then
@@ -413,7 +549,7 @@
procedure PlayMusic;
var s: shortstring;
begin
- if (not isSoundEnabled) or (MusicFN = '') or (not isMusicEnabled) then
+ if (MusicFN = '') or (not isMusicEnabled) then
exit;
s:= '/Music/' + MusicFN;
@@ -434,7 +570,7 @@
function ChangeVolume(voldelta: LongInt): LongInt;
begin
ChangeVolume:= 0;
- if (not isSoundEnabled) or ((voldelta = 0) and (not (cInitVolume = 0))) then
+ if not (isSoundEnabled or isMusicEnabled) or ((voldelta = 0) and (not (cInitVolume = 0))) then
exit;
inc(Volume, voldelta);
@@ -474,7 +610,7 @@
procedure MuteAudio;
begin
- if not isSoundEnabled then
+ if not (isSoundEnabled or isMusicEnabled) then
exit;
if (isAudioMuted) then
@@ -577,6 +713,7 @@
isAudioMuted:= false;
isSEBackup:= isSoundEnabled;
Volume:= 0;
+ SoundTimerTicks:= 0;
defVoicepack:= AskForVoicepack('Default');
for i:= Low(TSound) to High(TSound) do
@@ -589,7 +726,7 @@
voicepacks[t].chunks[i]:= nil;
(* on MOBILE SDL_mixer has to be compiled against Tremor (USE_OGG_TREMOR)
- or sound files bigger than 32k will lockup the game *)
+ or sound files bigger than 32k will lockup the game on slow cpu *)
for i:= Low(TSound) to High(TSound) do
defVoicepack^.chunks[i]:= nil;
@@ -597,7 +734,7 @@
procedure freeModule;
begin
- if isSoundEnabled then
+ if isSoundEnabled or isMusicEnabled then
ReleaseSound(true);
end;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uStore.pas
--- a/hedgewars/uStore.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uStore.pas Fri Feb 22 05:05:32 2013 +0100
@@ -33,7 +33,7 @@
procedure FinishProgress;
function LoadImage(const filename: shortstring; imageFlags: LongInt): PSDL_Surface;
-// loads an image from the game's data files
+// loads an image from the games data files
function LoadDataImage(const path: TPathType; const filename: shortstring; imageFlags: LongInt): PSDL_Surface;
// like LoadDataImage but uses altPath as fallback-path if file not found/loadable in path
function LoadDataImageAltPath(const path, altPath: TPathType; const filename: shortstring; imageFlags: LongInt): PSDL_Surface;
@@ -56,7 +56,7 @@
procedure SwapBuffers; {$IFDEF USE_VIDEO_RECORDING}cdecl{$ELSE}inline{$ENDIF};
implementation
-uses uMisc, uConsole, uMobile, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands
+uses uMisc, uConsole, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands
, uPhysFSLayer
, uDebug
{$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF}
@@ -71,6 +71,13 @@
{$ELSE}
SDLPrimSurface: PSDL_Surface;
{$ENDIF}
+ squaresize : LongInt;
+ numsquares : LongInt;
+ ProgrTex: PTexture;
+
+const
+ cHHFileName = 'Hedgehog';
+ cCHFileName = 'Crosshair';
function WriteInRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring): TSDL_Rect;
var w, h: LongInt;
@@ -148,6 +155,7 @@
texsurf, flagsurf, iconsurf: PSDL_Surface;
foundBot: boolean;
begin
+ if cOnlyStats then exit;
r.x:= 0;
r.y:= 0;
drY:= - 4;
@@ -436,7 +444,7 @@
IMG_Quit();
end;
-{$IF NOT DEFINED(S3D_DISABLED) OR DEFINED(USE_VIDEO_RECORDING)}
+{$IF DEFINED(USE_S3D_RENDERING) OR DEFINED(USE_VIDEO_RECORDING)}
procedure CreateFramebuffer(var frame, depth, tex: GLuint);
begin
glGenFramebuffersEXT(1, @frame);
@@ -538,8 +546,8 @@
if defaultFrame <> 0 then
DeleteFramebuffer(defaultFrame, depthv, texv);
{$ENDIF}
-{$IFNDEF S3D_DISABLED}
- if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then
+{$IFDEF USE_S3D_RENDERING}
+ if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
begin
DeleteFramebuffer(framel, depthl, texl);
DeleteFramebuffer(framer, depthr, texr);
@@ -575,7 +583,7 @@
if ((imageFlags and ifIgnoreCaps) = 0) and ((tmpsurf^.w > MaxTextureSize) or (tmpsurf^.h > MaxTextureSize)) then
begin
SDL_FreeSurface(tmpsurf);
- OutError(msgFailedSize, (imageFlags and ifCritical) <> 0);
+ OutError(msgFailedSize, ((not cOnlyStats) and ((imageFlags and ifCritical) <> 0)));
// dummy surface to replace non-critical textures that failed to load due to their size
LoadImage:= SDL_CreateRGBSurface(SDL_SWSURFACE, 2, 2, 32, RMask, GMask, BMask, AMask);
exit;
@@ -597,6 +605,8 @@
begin
// check for file in user dir (never critical)
tmpsurf:= LoadImage(cPathz[path] + '/' + filename, imageFlags);
+
+ LoadDataImage:= tmpsurf;
end;
@@ -804,8 +814,8 @@
end;
{$ENDIF}
-{$IFNDEF S3D_DISABLED}
- if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then
+{$IFDEF USE_S3D_RENDERING}
+ if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
begin
// prepare left and right frame buffers and associated textures
if glLoadExtension('GL_EXT_framebuffer_object') then
@@ -867,6 +877,7 @@
var r: TSDL_Rect;
texsurf: PSDL_Surface;
begin
+ if cOnlyStats then exit;
if Step = 0 then
begin
WriteToConsole(msgLoading + 'progress sprite: ');
@@ -877,8 +888,10 @@
squaresize:= texsurf^.w shr 1;
numsquares:= texsurf^.h div squaresize;
SDL_FreeSurface(texsurf);
-
- uMobile.GameLoading();
+ with mobileRecord do
+ if GameLoading <> nil then
+ GameLoading();
+
end;
TryDo(ProgrTex <> nil, 'Error - Progress Texure is nil!', true);
@@ -901,7 +914,9 @@
procedure FinishProgress;
begin
- uMobile.GameLoaded();
+ with mobileRecord do
+ if GameLoaded <> nil then
+ GameLoaded();
WriteLnToConsole('Freeing progress surface... ');
FreeTexture(ProgrTex);
ProgrTex:= nil;
@@ -1121,10 +1136,25 @@
{$IFNDEF DARWIN}ico: PSDL_Surface;{$ENDIF}
{$IFDEF SDL13}x, y: LongInt;{$ENDIF}
begin
+ if cOnlyStats then
+ begin
+ MaxTextureSize:= 1024;
+ exit
+ end;
if Length(s) = 0 then
- cFullScreen:= (not cFullScreen)
+ cFullScreen:= (not cFullScreen)
+ else cFullScreen:= s = '1';
+
+ if cFullScreen then
+ begin
+ cScreenWidth:= cFullscreenWidth;
+ cScreenHeight:= cFullscreenHeight;
+ end
else
- cFullScreen:= s = '1';
+ begin
+ cScreenWidth:= cWindowedWidth;
+ cScreenHeight:= cWindowedHeight;
+ end;
AddFileLog('Preparing to change video parameters...');
{$IFDEF SDL13}
@@ -1202,22 +1232,25 @@
if SDLwindow = nil then
if cFullScreen then
- SDLwindow:= SDL_CreateWindow('Hedgewars', x, y, cOrigScreenWidth, cOrigScreenHeight, flags or SDL_WINDOW_FULLSCREEN)
+ SDLwindow:= SDL_CreateWindow('Hedgewars', x, y, cScreenWidth, cScreenHeight, flags or SDL_WINDOW_FULLSCREEN)
else
+ begin
SDLwindow:= SDL_CreateWindow('Hedgewars', x, y, cScreenWidth, cScreenHeight, flags);
+ end;
SDLTry(SDLwindow <> nil, true);
{$ELSE}
flags:= SDL_OPENGL or SDL_RESIZABLE;
if cFullScreen then
+ begin
flags:= flags or SDL_FULLSCREEN;
-
+ end;
if not cOnlyStats then
begin
{$IFDEF WIN32}
s:= SDL_getenv('SDL_VIDEO_CENTERED');
SDL_putenv('SDL_VIDEO_CENTERED=1');
{$ENDIF}
- SDLPrimSurface:= SDL_SetVideoMode(cScreenWidth, cScreenHeight, cBits, flags);
+ SDLPrimSurface:= SDL_SetVideoMode(cScreenWidth, cScreenHeight, 0, flags);
SDLTry(SDLPrimSurface <> nil, true);
{$IFDEF WIN32}SDL_putenv(str2pchar('SDL_VIDEO_CENTERED=' + s));{$ENDIF}
end;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uTeams.pas
--- a/hedgewars/uTeams.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uTeams.pas Fri Feb 22 05:05:32 2013 +0100
@@ -40,12 +40,13 @@
procedure SwitchCurrentHedgehog(newHog: PHedgehog);
implementation
-uses uLocale, uAmmos, uChat, uVariables, uUtils, uIO, uCaptions, uCommands, uDebug, uScript,
+uses uLocale, uAmmos, uChat, uVariables, uUtils, uIO, uCaptions, uCommands, uDebug,
uGearsUtils, uGearsList
{$IFDEF USE_TOUCH_INTERFACE}, uTouch{$ENDIF};
var MaxTeamHealth: LongInt;
GameOver: boolean;
+ NextClan: boolean;
function CheckForWin: boolean;
var AliveClan: PClan;
@@ -302,7 +303,10 @@
else AddVoice(sndJustYouWait, CurrentTeam^.voicepack)
end
else
+ begin
+ GetRandom(2); // needed to avoid extdriven desync
AddVoice(sndYesSir, CurrentTeam^.voicepack);
+ end;
if cHedgehogTurnTime < 1000000 then
ReadyTimeLeft:= cReadyDelay;
AddCaption(Format(shortstring(trmsg[sidReady]), CurrentTeam^.TeamName), cWhiteColor, capgrpGameState)
@@ -317,16 +321,11 @@
end;
ReadyTimeLeft:= 0
end;
-
-{$IFDEF SDL13}
-uTouch.NewTurnBeginning();
-{$ENDIF}
-ScriptCall('onNewTurn');
end;
function AddTeam(TeamColor: Longword): PTeam;
var team: PTeam;
- c: LongInt;
+ c, t: LongInt;
begin
TryDo(TeamsCount < cMaxTeams, 'Too many teams', true);
New(team);
@@ -339,6 +338,9 @@
TeamsArray[TeamsCount]:= team;
inc(TeamsCount);
+for t:= 0 to cKbdMaxIndex do
+ team^.Binds[t]:= '';
+
c:= Pred(ClansCount);
while (c >= 0) and (ClansArray[c]^.Color <> TeamColor) do dec(c);
if c < 0 then
@@ -501,7 +503,6 @@
procedure chAddHH(var id: shortstring);
var s: shortstring;
Gear: PGear;
- c: LongInt;
begin
s:= '';
if (not isDeveloperMode) or (CurrentTeam = nil) then
@@ -510,10 +511,10 @@
begin
SplitBySpace(id, s);
SwitchCurrentHedgehog(@Hedgehogs[HedgehogsNumber]);
- val(id, CurrentHedgehog^.BotLevel, c);
+ CurrentHedgehog^.BotLevel:= StrToInt(id);
Gear:= AddGear(0, 0, gtHedgehog, 0, _0, _0, 0);
SplitBySpace(s, id);
- val(s, Gear^.Health, c);
+ Gear^.Health:= StrToInt(s);
TryDo(Gear^.Health > 0, 'Invalid hedgehog health', true);
Gear^.Hedgehog^.Team:= CurrentTeam;
if (GameFlags and gfSharedAmmo) <> 0 then
@@ -534,7 +535,6 @@
procedure chAddTeam(var s: shortstring);
var Color: Longword;
- c: LongInt;
ts, cs: shortstring;
begin
cs:= '';
@@ -543,7 +543,7 @@
begin
SplitBySpace(s, cs);
SplitBySpace(cs, ts);
- val(cs, Color, c);
+ Color:= StrToInt(cs);
TryDo(Color <> 0, 'Error: black team color', true);
// color is always little endian so the mask must be constant also in big endian archs
@@ -560,16 +560,16 @@
procedure chSetHHCoords(var x: shortstring);
var y: shortstring;
- t, c: Longint;
+ t: Longint;
begin
-y:= '';
-if (not isDeveloperMode) or (CurrentHedgehog = nil) or (CurrentHedgehog^.Gear = nil) then
- exit;
-SplitBySpace(x, y);
-val(x, t, c);
-CurrentHedgehog^.Gear^.X:= int2hwFloat(t);
-val(y, t, c);
-CurrentHedgehog^.Gear^.Y:= int2hwFloat(t)
+ y:= '';
+ if (not isDeveloperMode) or (CurrentHedgehog = nil) or (CurrentHedgehog^.Gear = nil) then
+ exit;
+ SplitBySpace(x, y);
+ t:= StrToInt(x);
+ CurrentHedgehog^.Gear^.X:= int2hwFloat(t);
+ t:= StrToInt(y);
+ CurrentHedgehog^.Gear^.Y:= int2hwFloat(t)
end;
procedure chBind(var id: shortstring);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uTextures.pas
--- a/hedgewars/uTextures.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uTextures.pas Fri Feb 22 05:05:32 2013 +0100
@@ -126,6 +126,7 @@
tmpp: pointer;
fromP4, toP4: PLongWordArray;
begin
+if cOnlyStats then exit(nil);
new(Surface2Tex);
Surface2Tex^.PrevTexture:= nil;
Surface2Tex^.NextTexture:= nil;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uTouch.pas
--- a/hedgewars/uTouch.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uTouch.pas Fri Feb 22 05:05:32 2013 +0100
@@ -22,7 +22,7 @@
interface
-uses SysUtils, uConsole, uVariables, SDLh, uFloat, uConsts, uCommands, GLUnit, uTypes, uCaptions, uAmmos, uWorld, uMobile;
+uses SysUtils, uConsole, uVariables, SDLh, uFloat, uConsts, uCommands, GLUnit, uTypes, uCaptions, uAmmos, uWorld;
procedure initModule;
@@ -558,7 +558,7 @@
isOnCrosshair:= isOnRect((x-HalfRectSize), (y-HalfRectSize), RectSize, RectSize, finger);
printFinger(finger);
WriteLnToConsole(inttostr(finger.x) + ' ' + inttostr(x));
- WriteLnToConsole(inttostr(x) + ' ' + inttostr(y) + ' ' + inttostr(round(uMobile.getScreenDPI * 10)));
+ WriteLnToConsole(inttostr(x) + ' ' + inttostr(y) + ' ' + inttostr(round(mobileRecord.getScreenDPI() * 10)));
end;
function isOnCurrentHog(finger: TTouch_Data): boolean;
@@ -640,7 +640,7 @@
for index := 0 to High(fingers) do
fingers[index].id := nilFingerId;
- rectSize:= round(baseRectSize * uMobile.getScreenDPI);
+ rectSize:= round(baseRectSize * mobileRecord.getScreenDPI());
halfRectSize:= rectSize shl 1;
end;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uTypes.pas
--- a/hedgewars/uTypes.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uTypes.pas Fri Feb 22 05:05:32 2013 +0100
@@ -102,7 +102,7 @@
gtSniperRifleShot, gtJetpack, gtMolotov, gtBirdy, // 44
gtEgg, gtPortal, gtPiano, gtGasBomb, gtSineGunShot, gtFlamethrower, // 50
gtSMine, gtPoisonCloud, gtHammer, gtHammerHit, gtResurrector, // 55
- gtNapalmBomb, gtSnowball, gtFlake, gtStructure, gtLandGun, gtTardis, // 61
+ gtNapalmBomb, gtSnowball, gtFlake, {gtStructure,} gtLandGun, gtTardis, // 61
gtIceGun, gtAddAmmo, gtGenericFaller, gtKnife); // 65
// Gears that are _only_ of visual nature (e.g. background stuff, visual effects, speechbubbles, etc.)
@@ -151,7 +151,7 @@
amRCPlane, amLowGravity, amExtraDamage, amInvulnerable, amExtraTime, // 35
amLaserSight, amVampiric, amSniperRifle, amJetpack, amMolotov, amBirdy, amPortalGun, // 42
amPiano, amGasBomb, amSineGun, amFlamethrower, amSMine, amHammer, // 48
- amResurrector, amDrillStrike, amSnowball, amTardis, amStructure, amLandGun, amIceGun, amKnife); // 54
+ amResurrector, amDrillStrike, amSnowball, amTardis, {amStructure,} amLandGun, amIceGun, amKnife); // 54
// Different kind of crates that e.g. hedgehogs can pick up
TCrateType = (HealthCrate, AmmoCrate, UtilityCrate);
@@ -169,7 +169,7 @@
TWave = (waveRollup, waveSad, waveWave, waveHurrah, waveLemonade, waveShrug, waveJuggle);
TRenderMode = (rmDefault, rmLeftEye, rmRightEye);
- TStereoMode = (smNone, smRedCyan, smCyanRed, smRedBlue, smBlueRed, smRedGreen, smGreenRed, smHorizontal, smVertical, smAFR);
+ TStereoMode = (smNone, smRedCyan, smCyanRed, smRedBlue, smBlueRed, smRedGreen, smGreenRed, smHorizontal, smVertical);
THHFont = record
Handle: PTTF_Font;
@@ -399,6 +399,18 @@
Flawless: boolean;
end;
+ cdeclPtr = procedure; cdecl;
+ cdeclIntPtr = procedure(num: LongInt); cdecl;
+ functionDoublePtr = function: Double;
+
+ TMobileRecord = record
+ getScreenDPI: functionDoublePtr;
+ PerformRumble: cdeclIntPtr;
+ GameLoading: cdeclPtr;
+ GameLoaded: cdeclPtr;
+ SaveLoadingEnded: cdeclPtr;
+ end;
+
TAmmoStrId = (sidGrenade, sidClusterBomb, sidBazooka, sidBee, sidShotgun,
sidPickHammer, sidSkip, sidRope, sidMine, sidDEagle,
sidDynamite, sidBaseballBat, sidFirePunch, sidSeconds,
@@ -411,7 +423,7 @@
sidMolotov, sidBirdy, sidPortalGun, sidPiano, sidGasBomb,
sidSineGun, sidFlamethrower,sidSMine, sidHammer, sidResurrector,
sidDrillStrike, sidSnowball, sidNothing, sidTardis,
- sidStructure, sidLandGun, sidIceGun, sidKnife);
+ {sidStructure,} sidLandGun, sidIceGun, sidKnife);
TMsgStrId = (sidStartFight, sidDraw, sidWinner, sidVolume, sidPaused,
sidConfirm, sidSuddenDeath, sidRemaining, sidFuel, sidSync,
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uUtils.pas
--- a/hedgewars/uUtils.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uUtils.pas Fri Feb 22 05:05:32 2013 +0100
@@ -73,6 +73,20 @@
procedure WriteLn(var f: textfile; s: shortstring);
{$ENDIF}
+function isPhone: Boolean; inline;
+function getScreenDPI: Double; inline; //cdecl; external;
+
+{$IFDEF IPHONEOS}
+procedure startLoadingIndicator; cdecl; external;
+procedure stopLoadingIndicator; cdecl; external;
+procedure saveFinishedSynching; cdecl; external;
+function isApplePhone: Boolean; cdecl; external;
+procedure AudioServicesPlaySystemSound(num: LongInt); cdecl; external;
+{$ENDIF}
+
+function sanitizeForLog(s: shortstring): shortstring;
+function sanitizeCharForLog(c: char): shortstring;
+
procedure initModule(isNotPreview: boolean);
procedure freeModule;
@@ -177,7 +191,11 @@
function StrToInt(s: shortstring): LongInt;
var c: LongInt;
begin
-val(s, StrToInt, c)
+val(s, StrToInt, c);
+{$IFDEF DEBUGFILE}
+if c <> 0 then
+ writeln(f, 'Error at position ' + IntToStr(c) + ' : ' + s[c])
+{$ENDIF}
end;
function FloatToStr(n: hwFloat): shortstring;
@@ -401,10 +419,60 @@
end;
{$ENDIF}
+// this function is just to determine whether we are running on a limited screen device
+function isPhone: Boolean; inline;
+begin
+ isPhone:= false;
+{$IFDEF IPHONEOS}
+ isPhone:= isApplePhone();
+{$ENDIF}
+{$IFDEF ANDROID}
+ //nasty nasty hack. TODO: implement callback to java to have a unified way of determining if it is a tablet
+ if (cScreenWidth < 1000) and (cScreenHeight < 500) then
+ isPhone:= true;
+{$ENDIF}
+end;
+
+//This dummy function should be reimplemented (externally).
+function getScreenDPI: Double; inline;
+begin
+{$IFDEF ANDROID}
+// getScreenDPI:= Android_JNI_getDensity();
+ getScreenDPI:= 1;
+{$ELSE}
+ getScreenDPI:= 1;
+{$ENDIF}
+end;
+
+function sanitizeForLog(s: shortstring): shortstring;
+var i: byte;
+ r: shortstring;
+begin
+ r[0]:= s[0];
+ for i:= 1 to length(s) do
+ if (s[i] < #32) or (s[i] > #127) then
+ r[i]:= '?'
+ else
+ r[i]:= s[i];
+
+ sanitizeForLog:= r
+end;
+
+function sanitizeCharForLog(c: char): shortstring;
+var r: shortstring;
+begin
+ if (c < #32) or (c > #127) then
+ r:= '#' + inttostr(byte(c))
+ else
+ r:= c;
+
+ sanitizeCharForLog:= r
+end;
+
procedure initModule(isNotPreview: boolean);
{$IFDEF DEBUGFILE}
var logfileBase: shortstring;
-{$IFNDEF MOBILE}var i: LongInt;{$ENDIF}
+ i: LongInt;
{$ENDIF}
begin
{$IFDEF DEBUGFILE}
@@ -421,28 +489,24 @@
InitCriticalSection(logMutex);
{$ENDIF}
{$I-}
-{$IFDEF MOBILE}
- {$IFDEF IPHONEOS} Assign(f, UserPathPrefix + '/hw-' + logfileBase + '.log'); {$ENDIF}
- {$IFDEF ANDROID} Assign(f,pathPrefix + '/' + logfileBase + '.log'); {$ENDIF}
- Rewrite(f);
-{$ELSE}
+ f:= stderr; // if everything fails, write to stderr
if (UserPathPrefix <> '') then
begin
- i:= 0;
- while(i < 7) do
+ // create directory if it doesn't exist
+ if not FileExists(UserPathPrefix + '/Logs/') then
+ CreateDir(UserPathPrefix + '/Logs/');
+
+ // if log is locked, write to the next one
+ i:= 0;
+ while(i < 7) do
begin
- assign(f, UserPathPrefix + '/Logs/' + logfileBase + inttostr(i) + '.log');
- rewrite(f);
- if IOResult = 0 then
- break;
- inc(i)
+ assign(f, UserPathPrefix + '/Logs/' + logfileBase + inttostr(i) + '.log');
+ if IOResult = 0 then
+ break;
+ inc(i)
end;
- if i = 7 then
- f:= stderr; // if everything fails, write to stderr
- end
- else
- f:= stderr;
-{$ENDIF}
+ end;
+ Rewrite(f);
{$I+}
{$ENDIF}
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uVariables.pas
--- a/hedgewars/uVariables.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uVariables.pas Fri Feb 22 05:05:32 2013 +0100
@@ -21,20 +21,21 @@
unit uVariables;
interface
-uses SDLh, uTypes, uFloat, GLunit, uConsts, Math, uMobile, uUtils;
+uses SDLh, uTypes, uFloat, GLunit, uConsts, Math, uUtils;
var
/////// init flags ///////
cMinScreenWidth : LongInt;
cMinScreenHeight : LongInt;
+ cFullscreenWidth : LongInt;
+ cFullscreenHeight : LongInt;
+ cWindowedWidth : LongInt;
+ cWindowedHeight : LongInt;
cScreenWidth : LongInt;
cScreenHeight : LongInt;
- cOrigScreenWidth : LongInt;
- cOrigScreenHeight : LongInt;
cNewScreenWidth : LongInt;
cNewScreenHeight : LongInt;
cScreenResizeDelay : LongWord;
- cBits : LongInt;
ipcPort : Word;
cFullScreen : boolean;
cLocaleFName : shortstring;
@@ -157,7 +158,6 @@
cVampiric : boolean;
cArtillery : boolean;
WeaponTooltipTex: PTexture;
- AmmoMenuTex : PTexture;
AmmoMenuInvalidated: boolean;
AmmoRect : TSDL_Rect;
HHTexture : PTexture;
@@ -177,8 +177,9 @@
SDWaterColorArray : array[0..3] of HwColor4f;
SDTint : LongInt;
- CursorPoint : TPoint;
- TargetPoint : TPoint;
+ TargetCursorPoint : TPoint;
+ CursorPoint : TPoint;
+ TargetPoint : TPoint;
ScreenFade : TScreenFade;
ScreenFadeValue : LongInt;
@@ -196,17 +197,10 @@
LuaTemplateNumber : LongWord;
- VoiceList : array[0..7] of TVoice = (
- ( snd: sndNone; voicepack: nil),
- ( snd: sndNone; voicepack: nil),
- ( snd: sndNone; voicepack: nil),
- ( snd: sndNone; voicepack: nil),
- ( snd: sndNone; voicepack: nil),
- ( snd: sndNone; voicepack: nil),
- ( snd: sndNone; voicepack: nil),
- ( snd: sndNone; voicepack: nil));
LastVoice : TVoice = ( snd: sndNone; voicepack: nil );
+ mobileRecord: TMobileRecord;
+
/////////////////////////////////////
//Buttons
{$IFDEF USE_TOUCH_INTERFACE}
@@ -690,126 +684,6 @@
(Sprite: sprJuggle; FramesCount: 49; Interval: 38; cmd: '/juggle'; Voice: sndNone; VoiceDelay: 0)
);
- Soundz: array[TSound] of record
- FileName: string[31];
- Path : TPathType;
- end = (
- (FileName: ''; Path: ptNone ),// sndNone
- (FileName: 'grenadeimpact.ogg'; Path: ptSounds),// sndGrenadeImpact
- (FileName: 'explosion.ogg'; Path: ptSounds),// sndExplosion
- (FileName: 'throwpowerup.ogg'; Path: ptSounds),// sndThrowPowerUp
- (FileName: 'throwrelease.ogg'; Path: ptSounds),// sndThrowRelease
- (FileName: 'splash.ogg'; Path: ptSounds),// sndSplash
- (FileName: 'shotgunreload.ogg'; Path: ptSounds),// sndShotgunReload
- (FileName: 'shotgunfire.ogg'; Path: ptSounds),// sndShotgunFire
- (FileName: 'graveimpact.ogg'; Path: ptSounds),// sndGraveImpact
- (FileName: 'mineimpact.ogg'; Path: ptSounds),// sndMineImpact
- (FileName: 'minetick.ogg'; Path: ptSounds),// sndMineTicks
- (FileName: 'Droplet1.ogg'; Path: ptSounds),// sndMudballImpact
- (FileName: 'pickhammer.ogg'; Path: ptSounds),// sndPickhammer
- (FileName: 'gun.ogg'; Path: ptSounds),// sndGun
- (FileName: 'bee.ogg'; Path: ptSounds),// sndBee
- (FileName: 'Jump1.ogg'; Path: ptVoices),// sndJump1
- (FileName: 'Jump2.ogg'; Path: ptVoices),// sndJump2
- (FileName: 'Jump3.ogg'; Path: ptVoices),// sndJump3
- (FileName: 'Yessir.ogg'; Path: ptVoices),// sndYesSir
- (FileName: 'Laugh.ogg'; Path: ptVoices),// sndLaugh
- (FileName: 'Illgetyou.ogg'; Path: ptVoices),// sndIllGetYou
- (FileName: 'JustYouWait.ogg'; Path: ptVoices),// sndJustYouWait
- (FileName: 'Incoming.ogg'; Path: ptVoices),// sndIncoming
- (FileName: 'Missed.ogg'; Path: ptVoices),// sndMissed
- (FileName: 'Stupid.ogg'; Path: ptVoices),// sndStupid
- (FileName: 'Firstblood.ogg'; Path: ptVoices),// sndFirstBlood
- (FileName: 'Boring.ogg'; Path: ptVoices),// sndBoring
- (FileName: 'Byebye.ogg'; Path: ptVoices),// sndByeBye
- (FileName: 'Sameteam.ogg'; Path: ptVoices),// sndSameTeam
- (FileName: 'Nutter.ogg'; Path: ptVoices),// sndNutter
- (FileName: 'Reinforcements.ogg'; Path: ptVoices),// sndReinforce
- (FileName: 'Traitor.ogg'; Path: ptVoices),// sndTraitor
- (FileName: 'Youllregretthat.ogg'; Path: ptVoices),// sndRegret
- (FileName: 'Enemydown.ogg'; Path: ptVoices),// sndEnemyDown
- (FileName: 'Coward.ogg'; Path: ptVoices),// sndCoward
- (FileName: 'Hurry.ogg'; Path: ptVoices),// sndHurry
- (FileName: 'Watchit.ogg'; Path: ptVoices),// sndWatchIt
- (FileName: 'Kamikaze.ogg'; Path: ptVoices),// sndKamikaze
- (FileName: 'cake2.ogg'; Path: ptSounds),// sndCake
- (FileName: 'Ow1.ogg'; Path: ptVoices),// sndOw1
- (FileName: 'Ow2.ogg'; Path: ptVoices),// sndOw2
- (FileName: 'Ow3.ogg'; Path: ptVoices),// sndOw3
- (FileName: 'Ow4.ogg'; Path: ptVoices),// sndOw4
- (FileName: 'Firepunch1.ogg'; Path: ptVoices),// sndFirepunch1
- (FileName: 'Firepunch2.ogg'; Path: ptVoices),// sndFirepunch2
- (FileName: 'Firepunch3.ogg'; Path: ptVoices),// sndFirepunch3
- (FileName: 'Firepunch4.ogg'; Path: ptVoices),// sndFirepunch4
- (FileName: 'Firepunch5.ogg'; Path: ptVoices),// sndFirepunch5
- (FileName: 'Firepunch6.ogg'; Path: ptVoices),// sndFirepunch6
- (FileName: 'Melon.ogg'; Path: ptVoices),// sndMelon
- (FileName: 'Hellish.ogg'; Path: ptSounds),// sndHellish
- (FileName: 'Yoohoo.ogg'; Path: ptSounds),// sndYoohoo
- (FileName: 'rcplane.ogg'; Path: ptSounds),// sndRCPlane
- (FileName: 'whipcrack.ogg'; Path: ptSounds),// sndWhipCrack
- (FileName:'ride_of_the_valkyries.ogg'; Path: ptSounds),// sndRideOfTheValkyries
- (FileName: 'denied.ogg'; Path: ptSounds),// sndDenied
- (FileName: 'placed.ogg'; Path: ptSounds),// sndPlaced
- (FileName: 'baseballbat.ogg'; Path: ptSounds),// sndBaseballBat
- (FileName: 'steam.ogg'; Path: ptSounds),// sndVaporize
- (FileName: 'warp.ogg'; Path: ptSounds),// sndWarp
- (FileName: 'suddendeath.ogg'; Path: ptSounds),// sndSuddenDeath
- (FileName: 'mortar.ogg'; Path: ptSounds),// sndMortar
- (FileName: 'shutterclick.ogg'; Path: ptSounds),// sndShutter
- (FileName: 'homerun.ogg'; Path: ptSounds),// sndHomerun
- (FileName: 'molotov.ogg'; Path: ptSounds),// sndMolotov
- (FileName: 'Takecover.ogg'; Path: ptVoices),// sndCover
- (FileName: 'Uh-oh.ogg'; Path: ptVoices),// sndUhOh
- (FileName: 'Oops.ogg'; Path: ptVoices),// sndOops
- (FileName: 'Nooo.ogg'; Path: ptVoices),// sndNooo
- (FileName: 'Hello.ogg'; Path: ptVoices),// sndHello
- (FileName: 'ropeshot.ogg'; Path: ptSounds),// sndRopeShot
- (FileName: 'ropeattach.ogg'; Path: ptSounds),// sndRopeAttach
- (FileName: 'roperelease.ogg'; Path: ptSounds),// sndRopeRelease
- (FileName: 'switchhog.ogg'; Path: ptSounds),// sndSwitchHog
- (FileName: 'Victory.ogg'; Path: ptVoices),// sndVictory
- (FileName: 'Flawless.ogg'; Path: ptVoices),// sndFlawless
- (FileName: 'sniperreload.ogg'; Path: ptSounds),// sndSniperReload
- (FileName: 'steps.ogg'; Path: ptSounds),// sndSteps
- (FileName: 'lowgravity.ogg'; Path: ptSounds),// sndLowGravity
- (FileName: 'hell_growl.ogg'; Path: ptSounds),// sndHellishImpact1
- (FileName: 'hell_ooff.ogg'; Path: ptSounds),// sndHellishImpact2
- (FileName: 'hell_ow.ogg'; Path: ptSounds),// sndHellishImpact3
- (FileName: 'hell_ugh.ogg'; Path: ptSounds),// sndHellishImpact4
- (FileName: 'melonimpact.ogg'; Path: ptSounds),// sndMelonImpact
- (FileName: 'Droplet1.ogg'; Path: ptSounds),// sndDroplet1
- (FileName: 'Droplet2.ogg'; Path: ptSounds),// sndDroplet2
- (FileName: 'Droplet3.ogg'; Path: ptSounds),// sndDroplet3
- (FileName: 'egg.ogg'; Path: ptSounds),// sndEggBreak
- (FileName: 'drillgun.ogg'; Path: ptSounds),// sndDrillRocket
- (FileName: 'PoisonCough.ogg'; Path: ptVoices),// sndPoisonCough
- (FileName: 'PoisonMoan.ogg'; Path: ptVoices),// sndPoisonMoan
- (FileName: 'BirdyLay.ogg'; Path: ptSounds),// sndBirdyLay
- (FileName: 'Whistle.ogg'; Path: ptSounds),// sndWhistle
- (FileName: 'beewater.ogg'; Path: ptSounds),// sndBeeWater
- (FileName: '1C.ogg'; Path: ptSounds),// sndPiano0
- (FileName: '2D.ogg'; Path: ptSounds),// sndPiano1
- (FileName: '3E.ogg'; Path: ptSounds),// sndPiano2
- (FileName: '4F.ogg'; Path: ptSounds),// sndPiano3
- (FileName: '5G.ogg'; Path: ptSounds),// sndPiano4
- (FileName: '6A.ogg'; Path: ptSounds),// sndPiano5
- (FileName: '7B.ogg'; Path: ptSounds),// sndPiano6
- (FileName: '8C.ogg'; Path: ptSounds),// sndPiano7
- (FileName: '9D.ogg'; Path: ptSounds),// sndPiano8
- (FileName: 'skip.ogg'; Path: ptSounds),// sndSkip
- (FileName: 'sinegun.ogg'; Path: ptSounds),// sndSineGun
- (FileName: 'Ooff1.ogg'; Path: ptVoices),// sndOoff1
- (FileName: 'Ooff2.ogg'; Path: ptVoices),// sndOoff2
- (FileName: 'Ooff3.ogg'; Path: ptVoices),// sndOoff3
- (FileName: 'hammer.ogg'; Path: ptSounds),// sndWhack
- (FileName: 'Comeonthen.ogg'; Path: ptVoices),// sndComeonthen
- (FileName: 'parachute.ogg'; Path: ptSounds),// sndParachute
- (FileName: 'bump.ogg'; Path: ptSounds),// sndBump
- (FileName: 'hogchant3.ogg'; Path: ptSounds),// sndResurrector
- (FileName: 'plane.ogg'; Path: ptSounds),// sndPlane
- (FileName: 'TARDIS.ogg'; Path: ptSounds) // sndTardis
- );
var
Ammoz: array [TAmmoType] of record
NameId: TAmmoStrId;
@@ -2257,6 +2131,7 @@
ejectY: 0),
// Structure
+{
(NameId: sidStructure;
NameTex: nil;
Probability: 0;
@@ -2282,6 +2157,7 @@
PosSprite: sprWater;
ejectX: 0;
ejectY: 0),
+}
// Land Gun
(NameId: sidLandGun;
@@ -2359,76 +2235,6 @@
ejectY: 0)
);
-const
- GearKindAmmoTypeMap : array [TGearType] of TAmmoType = (
-(* gtFlame *) amNothing
-(* gtHedgehog *) , amNothing
-(* gtMine *) , amMine
-(* gtCase *) , amNothing
-(* gtExplosives *) , amNothing
-(* gtGrenade *) , amGrenade
-(* gtShell *) , amBazooka
-(* gtGrave *) , amNothing
-(* gtBee *) , amBee
-(* gtShotgunShot *) , amShotgun
-(* gtPickHammer *) , amPickHammer
-(* gtRope *) , amRope
-(* gtDEagleShot *) , amDEagle
-(* gtDynamite *) , amDynamite
-(* gtClusterBomb *) , amClusterBomb
-(* gtCluster *) , amClusterBomb
-(* gtShover *) , amBaseballBat // Shover is only used for baseball bat right now
-(* gtFirePunch *) , amFirePunch
-(* gtATStartGame *) , amNothing
-(* gtATFinishGame *) , amNothing
-(* gtParachute *) , amParachute
-(* gtAirAttack *) , amAirAttack
-(* gtAirBomb *) , amAirAttack
-(* gtBlowTorch *) , amBlowTorch
-(* gtGirder *) , amGirder
-(* gtTeleport *) , amTeleport
-(* gtSwitcher *) , amSwitch
-(* gtTarget *) , amNothing
-(* gtMortar *) , amMortar
-(* gtWhip *) , amWhip
-(* gtKamikaze *) , amKamikaze
-(* gtCake *) , amCake
-(* gtSeduction *) , amSeduction
-(* gtWatermelon *) , amWatermelon
-(* gtMelonPiece *) , amWatermelon
-(* gtHellishBomb *) , amHellishBomb
-(* gtWaterUp *) , amNothing
-(* gtDrill *) , amDrill
-(* gtBallGun *) , amBallgun
-(* gtBall *) , amBallgun
-(* gtRCPlane *) , amRCPlane
-(*gtSniperRifleShot *) , amSniperRifle
-(* gtJetpack *) , amJetpack
-(* gtMolotov *) , amMolotov
-(* gtBirdy *) , amBirdy
-(* gtEgg *) , amBirdy
-(* gtPortal *) , amPortalGun
-(* gtPiano *) , amPiano
-(* gtGasBomb *) , amGasBomb
-(* gtSineGunShot *) , amSineGun
-(* gtFlamethrower *) , amFlamethrower
-(* gtSMine *) , amSMine
-(* gtPoisonCloud *) , amNothing
-(* gtHammer *) , amHammer
-(* gtHammerHit *) , amHammer
-(* gtResurrector *) , amResurrector
-(* gtPoisonCloud *) , amNothing
-(* gtSnowball *) , amSnowball
-(* gtFlake *) , amNothing
-(* gtStructure *) , amStructure // TODO - This will undoubtedly change once there is more than one structure
-(* gtLandGun *) , amLandGun
-(* gtTardis *) , amTardis
-(* gtIceGun *) , amIceGun
-(* gtAddAmmo *) , amNothing
-(* gtGenericFaller *) , amNothing
-(* gtKnife *) , amKnife
- );
-
var
Land: TCollisionArray;
LandPixels: TLandArray;
@@ -2462,7 +2268,6 @@
LocalTeam: LongInt; // last non-bot, non-extdriven clan first team
LocalAmmo: LongInt; // last non-bot, non-extdriven clan's first team's ammo index, updated to next upcoming hog for per-hog-ammo
CurMinAngle, CurMaxAngle: Longword;
- NextClan: boolean;
FollowGear: PGear;
WindBarWidth: LongInt;
@@ -2473,13 +2278,9 @@
WaterColor, DeepWaterColor: TSDL_Color;
SkyColor, RQSkyColor, SDSkyColor: TSDL_Color;
SkyOffset: LongInt;
- HorizontOffset: LongInt;
{$IFDEF COUNTTICKS}
cntTicks: LongWord;
{$ENDIF}
- cOffsetY: LongInt;
- AFRToggle: Boolean;
- bAFRRight: Boolean;
PauseTexture,
@@ -2488,9 +2289,6 @@
cScaleFactor: GLfloat;
SupportNPOTT: Boolean;
Step: LongInt;
- squaresize : LongInt;
- numsquares : LongInt;
- ProgrTex: PTexture;
MissionIcons: PSDL_Surface;
ropeIconTex: PTexture;
@@ -2502,24 +2300,12 @@
defaultFrame, depthv: GLuint;
texv: GLuint;
- VisualGearLayers: array[0..6] of PVisualGear;
lastVisualGearByUID: PVisualGear;
vobFrameTicks, vobFramesCount, vobCount: Longword;
vobVelocity, vobFallSpeed: LongInt;
vobSDFrameTicks, vobSDFramesCount, vobSDCount: Longword;
vobSDVelocity, vobSDFallSpeed: LongInt;
- ControllerNumControllers: Integer;
- ControllerEnabled: Integer;
- ControllerNumAxes: array[0..5] of Integer;
- //ControllerNumBalls: array[0..5] of Integer;
- ControllerNumHats: array[0..5] of Integer;
- ControllerNumButtons: array[0..5] of Integer;
- ControllerAxes: array[0..5] of array[0..19] of Integer;
- //ControllerBalls: array[0..5] of array[0..19] of array[0..1] of Integer;
- ControllerHats: array[0..5] of array[0..19] of Byte;
- ControllerButtons: array[0..5] of array[0..19] of Byte;
-
DefaultBinds : TBinds;
lastTurnChecksum : Longword;
@@ -2541,9 +2327,13 @@
begin
// initialisation flags - they are going to be overwritten by program args
- cScreenWidth := 1024;
- cScreenHeight := 768;
- cBits := 32;
+ cFullscreenWidth := 0;
+ cFullscreenHeight := 0;
+ cWindowedWidth := 1024;
+ cWindowedHeight := 768;
+ cScreenWidth := cWindowedWidth;
+ cScreenHeight := cWindowedHeight;
+
cShowFPS := false;
cAltDamage := true;
cTimerInterval := 8;
@@ -2559,6 +2349,7 @@
GrayScale := false;
PathPrefix := './';
GameType := gmtLocal;
+ cOnlyStats := False;
{$IFDEF USE_VIDEO_RECORDING}
RecPrefix := '';
@@ -2579,7 +2370,6 @@
cFlattenFlakes := false;
cFlattenClouds := false;
- cOnlyStats := False;
lastVisualGearByUID := nil;
lastGearByUID := nil;
cReadyDelay := 5000;
@@ -2724,19 +2514,37 @@
vobSDVelocity:= 15;
vobSDFallSpeed:= 250;
- cMinScreenWidth:= min(cScreenWidth, 640);
- cMinScreenHeight:= min(cScreenHeight, 480);
- cOrigScreenWidth:= cScreenWidth;
- cOrigScreenHeight:= cScreenHeight;
+ cMinScreenWidth := min(cScreenWidth, 640);
+ cMinScreenHeight := min(cScreenHeight, 480);
cNewScreenWidth := cScreenWidth;
cNewScreenHeight := cScreenHeight;
cScreenResizeDelay := 0;
+ // make sure fullscreen resolution is always initialised somehow
+ if cFullscreenWidth = 0 then
+ cFullscreenWidth:= min(cWindowedWidth, 640);
+ if cFullscreenHeight = 0 then
+ cFullscreenHeight:= min(cWindowedHeight, 480);
+
+
LuaGoals:= '';
cMapName:= '';
LuaTemplateNumber:= 0;
+
+ mobileRecord.getScreenDPI:= @getScreenDPI; //TODO: define external function.
+ {$IFDEF IPHONEOS}
+ mobileRecord.PerformRumble:= @AudioServicesPlaySystemSound;
+ mobileRecord.GameLoading:= @startLoadingIndicator;
+ mobileRecord.GameLoaded:= @stopLoadingIndicator;
+ mobileRecord.SaveLoadingEnded:= @saveFinishedSynching;
+ {$ELSE}
+ mobileRecord.PerformRumble:= nil;
+ mobileRecord.GameLoading:= nil;
+ mobileRecord.GameLoaded:= nil;
+ mobileRecord.SaveLoadingEnded:= nil;
+ {$ENDIF}
end;
procedure freeModule;
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uVideoRec.pas
--- a/hedgewars/uVideoRec.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uVideoRec.pas Fri Feb 22 05:05:32 2013 +0100
@@ -30,11 +30,6 @@
{$IFNDEF WIN32}
{$LINKLIB ../bin/libavwrapper.a}
{$ENDIF}
-{$IFDEF DARWIN}
- {$LINKLIB bz2}
- {$LINKFRAMEWORK CoreVideo}
- {$LINKFRAMEWORK VideoDecodeAcceleration}
-{$ENDIF}
interface
@@ -201,7 +196,7 @@
end;
function LoadNextCameraPosition(out newRealTicks, newGameTicks: LongInt): Boolean;
-var frame: TFrame;
+var frame: TFrame = (realTicks: 0; gameTicks: 0; CamX: 0; CamY: 0; zoom: 0);
begin
// we need to skip or duplicate frames to match target framerate
while Int64(curTime)*cVideoFramerateNum <= Int64(numFrames)*cVideoFramerateDen*1000 do
@@ -249,9 +244,12 @@
var inF, outF: file;
buffer: array[0..1023] of byte;
result: LongInt;
+ i: integer;
begin
{$IOCHECKS OFF}
- result:= 0; // avoid compiler hint
+ result:= 0; // avoid compiler hint and warning
+ for i:= 0 to 1023 do
+ buffer[i]:= 0;
Assign(inF, src);
Reset(inF, 1);
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uVisualGears.pas
--- a/hedgewars/uVisualGears.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uVisualGears.pas Fri Feb 22 05:05:32 2013 +0100
@@ -53,10 +53,13 @@
procedure KickFlakes(Radius, X, Y: LongInt);
implementation
-uses uSound, uMobile, uVariables, uTextures, uRender, Math, uRenderUtils, uStore, uUtils;
+uses uSound, uVariables, uTextures, uRender, Math, uRenderUtils, uStore, uUtils;
-const cExplFrameTicks = 110;
+const
+ cExplFrameTicks = 110;
+ //cSmokeZ = 499;
var VGCounter: LongWord;
+ VisualGearLayers: array[0..6] of PVisualGear;
// For better maintainability the step handlers of visual gears are stored
// in a separate file.
diff -r d5d5e1698554 -r 1dedcc37bfe8 hedgewars/uWorld.pas
--- a/hedgewars/uWorld.pas Sun Nov 18 01:06:01 2012 +0400
+++ b/hedgewars/uWorld.pas Fri Feb 22 05:05:32 2013 +0100
@@ -60,7 +60,6 @@
, uCaptions
, uCursor
, uCommands
- , uMobile
{$IFDEF USE_VIDEO_RECORDING}
, uVideoRec
{$ENDIF}
@@ -75,8 +74,7 @@
timeTexture: PTexture;
FPS: Longword;
CountTicks: Longword;
- SoundTimerTicks: Longword;
- prevPoint: TPoint;
+ prevPoint, prevTargetPoint: TPoint;
amSel: TAmmoType = amNothing;
missionTex: PTexture;
missionTimer: LongInt;
@@ -84,6 +82,9 @@
isFirstFrame: boolean;
AMAnimType: LongInt;
recTexture: PTexture;
+ AmmoMenuTex : PTexture;
+ HorizontOffset: LongInt;
+ cOffsetY: LongInt;
const cStereo_Sky = 0.0500;
cStereo_Horizon = 0.0250;
@@ -93,6 +94,27 @@
cStereo_Water_near = 0.0025;
cStereo_Outside = -0.0400;
+ AMAnimDuration = 200;
+ AMHidden = 0;//AMState values
+ AMShowingUp = 1;
+ AMShowing = 2;
+ AMHiding = 3;
+
+ AMTypeMaskX = $00000001;
+ AMTypeMaskY = $00000002;
+ AMTypeMaskAlpha = $00000004;
+ //AMTypeMaskSlide = $00000008;
+
+{$IFDEF MOBILE}
+ AMSlotSize = 48;
+{$ELSE}
+ AMSlotSize = 32;
+{$ENDIF}
+ AMSlotPadding = (AMSlotSize - 32) shr 1;
+
+ cSendCursorPosTime = 50;
+ cCursorEdgesDist = 100;
+
// helper functions to create the goal/game mode string
function AddGoal(s: ansistring; gf: longword; si: TGoalStrId; i: LongInt): ansistring;
var t: ansistring;
@@ -199,6 +221,8 @@
uCursor.init();
prevPoint.X:= 0;
prevPoint.Y:= cScreenHeight div 2;
+prevTargetPoint.X:= 0;
+prevTargetPoint.Y:= 0;
WorldDx:= -(LAND_WIDTH div 2) + cScreenWidth div 2;
WorldDy:= -(LAND_HEIGHT - (playHeight div 2)) + (cScreenHeight div 2);
@@ -220,7 +244,7 @@
{$IFDEF USE_TOUCH_INTERFACE}
//positioning of the buttons
-buttonScale:= uMobile.getScreenDPI/cDefaultZoomLevel;
+buttonScale:= mobileRecord.getScreenDPI()/cDefaultZoomLevel;
with JumpWidget do
@@ -618,6 +642,7 @@
AMShiftX:= AMShiftTargetX;
AMShiftY:= AMShiftTargetY;
prevPoint:= CursorPoint;
+ prevTargetPoint:= TargetCursorPoint;
AMState:= AMHidden;
end;
end;
@@ -961,16 +986,7 @@
glClear(GL_COLOR_BUFFER_BIT);
DrawWorldStereo(Lag, rmDefault)
end
-{$IFNDEF S3D_DISABLED}
- else if (cStereoMode = smAFR) then
- begin
- AFRToggle:= not AFRToggle;
- glClear(GL_COLOR_BUFFER_BIT);
- if AFRToggle then
- DrawWorldStereo(Lag, rmLeftEye)
- else
- DrawWorldStereo(Lag, rmRightEye)
- end
+{$IFDEF USE_S3D_RENDERING}
else if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
begin
// create left fb
@@ -1074,7 +1090,7 @@
procedure ChangeDepth(rm: TRenderMode; d: GLfloat);
begin
-{$IFDEF S3D_DISABLED}
+{$IFNDEF USE_S3D_RENDERING}
rm:= rm; d:= d; // avoid hint
exit;
{$ELSE}
@@ -1092,7 +1108,7 @@
procedure ResetDepth(rm: TRenderMode);
begin
-{$IFDEF S3D_DISABLED}
+{$IFNDEF USE_S3D_RENDERING}
rm:= rm; // avoid hint
exit;
{$ELSE}
@@ -1497,22 +1513,8 @@
if fpsTexture <> nil then
DrawTexture((cScreenWidth shr 1) - 60 - offsetY, offsetX, fpsTexture);
end;
-
- // lag warning (?)
- inc(SoundTimerTicks, Lag);
end;
-if SoundTimerTicks >= 50 then
-begin
- SoundTimerTicks:= 0;
- if cVolumeDelta <> 0 then
- begin
- str(ChangeVolume(cVolumeDelta), s);
- AddCaption(Format(trmsg[sidVolume], s), cWhiteColor, capgrpVolume);
- end;
- if isAudioMuted then
- AddCaption(trmsg[sidMute], cWhiteColor, capgrpVolume)
-end;
if GameState = gsConfirm then
DrawTextureCentered(0, (cScreenHeight shr 1), ConfirmTexture);
@@ -1615,6 +1617,7 @@
begin
if not bShowAmmoMenu then
begin
+ if not CurrentTeam^.ExtDriven then TargetCursorPoint:= CursorPoint;
with CurrentHedgehog^ do
if (Gear <> nil) and ((Gear^.State and gstHHChooseTarget) <> 0) then
begin
@@ -1623,9 +1626,9 @@
i:= GetCurAmmoEntry(CurrentHedgehog^)^.Pos;
with Ammoz[CurAmmoType] do
if PosCount > 1 then
- DrawSprite(PosSprite, CursorPoint.X - (SpritesData[PosSprite].Width shr 1), cScreenHeight - CursorPoint.Y - (SpritesData[PosSprite].Height shr 1),i);
+ DrawSprite(PosSprite, TargetCursorPoint.X - (SpritesData[PosSprite].Width shr 1), cScreenHeight - TargetCursorPoint.Y - (SpritesData[PosSprite].Height shr 1),i);
end;
- DrawSprite(sprArrow, CursorPoint.X, cScreenHeight - CursorPoint.Y, (RealTicks shr 6) mod 8)
+ DrawSprite(sprArrow, TargetCursorPoint.X, cScreenHeight - TargetCursorPoint.Y, (RealTicks shr 6) mod 8)
end
end;
isFirstFrame:= false
@@ -1637,7 +1640,7 @@
var EdgesDist, wdy, shs,z, amNumOffsetX, amNumOffsetY: LongInt;
begin
{$IFNDEF MOBILE}
-if (not (CurrentTeam^.ExtDriven and isCursorVisible and (not bShowAmmoMenu))) and cHasFocus and (GameState <> gsConfirm) then
+if (not (CurrentTeam^.ExtDriven and isCursorVisible and (not bShowAmmoMenu) and autoCameraOn)) and cHasFocus and (GameState <> gsConfirm) then
uCursor.updatePosition();
{$ENDIF}
z:= round(200/zoom);
@@ -1708,7 +1711,8 @@
EdgesDist:= cGearScrEdgesDist;
// this generates the border around the screen that moves the camera when cursor is near it
-if isCursorVisible or ((FollowGear <> nil) and autoCameraOn) then
+if (CurrentTeam^.ExtDriven and isCursorVisible and autoCameraOn) or
+ (not CurrentTeam^.ExtDriven and isCursorVisible) or ((FollowGear <> nil) and autoCameraOn) then
begin
if CursorPoint.X < - cScreenWidth div 2 + EdgesDist then
begin
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/Android.mk
--- a/misc/Android.mk Sun Nov 18 01:06:01 2012 +0400
+++ b/misc/Android.mk Fri Feb 22 05:05:32 2013 +0100
@@ -4,3 +4,4 @@
include $(MISC_DIR)/libfreetype/Android.mk
include $(MISC_DIR)/liblua/Android.mk
include $(MISC_DIR)/libtremor/Android.mk
+include $(MISC_DIR)/physfs/Android.mk
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/liblua/CMakeLists.txt
--- a/misc/liblua/CMakeLists.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/misc/liblua/CMakeLists.txt Fri Feb 22 05:05:32 2013 +0100
@@ -9,7 +9,7 @@
set(LUA_LIBRARY lua.dll)
set_target_properties(lua PROPERTIES PREFIX "")
- install(TARGETS lua RUNTIME DESTINATION ${target_dir})
+ install(TARGETS lua RUNTIME DESTINATION ${target_library_install_dir})
else(WIN32)
add_definitions(-DLUA_USE_LINUX)
add_library(lua STATIC ${lua_src})
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/libopenalbridge/CMakeLists.txt
--- a/misc/libopenalbridge/CMakeLists.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/misc/libopenalbridge/CMakeLists.txt Fri Feb 22 05:05:32 2013 +0100
@@ -30,7 +30,7 @@
if(WIN32)
if(MSVC)
- SET_TARGET_PROPERTIES(openalbridge PROPERTIES LINK_FLAGS /DEF:openalbridge.def)
+ set_target_properties(openalbridge PROPERTIES LINK_FLAGS /DEF:openalbridge.def)
endif(MSVC)
#install it in the executable directory
install(TARGETS openalbridge DESTINATION bin)
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/physfs/Android.mk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/Android.mk Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,1 @@
+include $(call all-subdir-makefiles)
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/physfs/CMakeLists.txt
--- a/misc/physfs/CMakeLists.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/misc/physfs/CMakeLists.txt Fri Feb 22 05:05:32 2013 +0100
@@ -3,60 +3,65 @@
#
# Please see the file LICENSE.txt in the source's root directory.
-CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
-
-PROJECT(PhysicsFS)
-SET(PHYSFS_VERSION 2.1.0)
+## lines starting with '##' are lines overridden/modified/added by Hedgewars configuration
+##CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
+##PROJECT(PhysicsFS)
+set(PHYSFS_VERSION 2.1.0)
# Increment this if/when we break backwards compatibility.
-SET(PHYSFS_SOVERSION 1)
+set(PHYSFS_SOVERSION 1)
# I hate that they define "WIN32" ... we're about to move to Win64...I hope!
-IF(WIN32 AND NOT WINDOWS)
- SET(WINDOWS TRUE)
-ENDIF(WIN32 AND NOT WINDOWS)
+if(WIN32 AND NOT WINDOWS)
+ set(WINDOWS TRUE)
+endif(WIN32 AND NOT WINDOWS)
# Bleh, let's do it for "APPLE" too.
-IF(APPLE AND NOT MACOSX)
- SET(MACOSX TRUE)
-ENDIF(APPLE AND NOT MACOSX)
+if(APPLE AND NOT MACOSX)
+ set(MACOSX TRUE)
+endif(APPLE AND NOT MACOSX)
# For now, Haiku and BeOS are the same, as far as the build system cares.
-IF(HAIKU AND NOT BEOS)
- SET(BEOS TRUE)
-ENDIF(HAIKU AND NOT BEOS)
+if(HAIKU AND NOT BEOS)
+ set(BEOS TRUE)
+endif(HAIKU AND NOT BEOS)
-IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
- SET(SOLARIS TRUE)
-ENDIF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ set(SOLARIS TRUE)
+endif(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+
+include(CheckIncludeFile)
+include(CheckLibraryExists)
+include(CheckCSourceCompiles)
-INCLUDE(CheckIncludeFile)
-INCLUDE(CheckLibraryExists)
-INCLUDE(CheckCSourceCompiles)
-
-INCLUDE_DIRECTORIES(./src)
+## SDL is needed by extra
+find_package(SDL REQUIRED)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) ##
+include_directories(${SDL_INCLUDE_DIR}) ##
+include_directories(${LUA_INCLUDE_DIR}) ##
-IF(MACOSX)
+if(MACOSX)
# Fallback to older OS X on PowerPC to support wider range of systems...
- IF(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
- ADD_DEFINITIONS(-DMAC_OS_X_VERSION_MIN_REQUIRED=1020)
- SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -mmacosx-version-min=10.2")
- ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
+ if(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
+ add_definitions(-DMAC_OS_X_VERSION_MIN_REQUIRED=1020)
+ set(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -mmacosx-version-min=10.2")
+ endif(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
# Need these everywhere...
- ADD_DEFINITIONS(-fno-common)
- SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} "-framework Carbon -framework IOKit")
-ENDIF(MACOSX)
+ add_definitions(-fno-common)
+ find_library(iokit_framework NAMES IOKit)
+ list(APPEND OTHER_LDFLAGS ${iokit_framework})
+endif(MACOSX)
# Add some gcc-specific command lines.
-IF(CMAKE_COMPILER_IS_GNUCC)
+if(CMAKE_COMPILER_IS_GNUCC)
# Always build with debug symbols...you can strip it later.
- ADD_DEFINITIONS(-g -pipe -Werror -fsigned-char)
+ add_definitions(-g -pipe -Werror -fsigned-char)
# Stupid BeOS generates warnings in the system headers.
- IF(NOT BEOS)
- ADD_DEFINITIONS(-Wall)
- ENDIF(NOT BEOS)
+ if(NOT BEOS)
+ add_definitions(-Wall)
+ endif(NOT BEOS)
CHECK_C_SOURCE_COMPILES("
#if ((defined(__GNUC__)) && (__GNUC__ >= 4))
@@ -66,31 +71,31 @@
#endif
" PHYSFS_IS_GCC4)
- IF(PHYSFS_IS_GCC4)
+ if(PHYSFS_IS_GCC4)
# Not supported on several operating systems at this time.
- IF(NOT SOLARIS AND NOT WINDOWS)
- ADD_DEFINITIONS(-fvisibility=hidden)
- ENDIF(NOT SOLARIS AND NOT WINDOWS)
- ENDIF(PHYSFS_IS_GCC4)
+ if(NOT SOLARIS AND NOT WINDOWS)
+ add_definitions(-fvisibility=hidden)
+ endif(NOT SOLARIS AND NOT WINDOWS)
+ endif(PHYSFS_IS_GCC4)
# Don't use -rpath.
- SET(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE)
-ENDIF(CMAKE_COMPILER_IS_GNUCC)
+ set(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE)
+endif(CMAKE_COMPILER_IS_GNUCC)
-IF(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
- ADD_DEFINITIONS(-erroff=E_EMPTY_TRANSLATION_UNIT)
- ADD_DEFINITIONS(-xldscope=hidden)
-ENDIF(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
+if(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
+ add_definitions(-erroff=E_EMPTY_TRANSLATION_UNIT)
+ add_definitions(-xldscope=hidden)
+endif(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
-IF(MSVC)
+if(MSVC)
# VS.NET 8.0 got really really anal about strcpy, etc, which even if we
# cleaned up our code, zlib, etc still use...so disable the warning.
- ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS=1)
-ENDIF(MSVC)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
+endif(MSVC)
+
# Basic chunks of source code ...
-
-SET(LZMA_SRCS
+set(LZMA_SRCS
src/lzma/C/7zCrc.c
src/lzma/C/Archive/7z/7zBuffer.c
src/lzma/C/Archive/7z/7zDecode.c
@@ -104,20 +109,28 @@
src/lzma/C/Compress/Lzma/LzmaDecode.c
)
-IF(BEOS)
+if(BEOS)
# We add this explicitly, since we don't want CMake to think this
# is a C++ project unless we're on BeOS.
- SET(PHYSFS_BEOS_SRCS src/platform_beos.cpp)
- FIND_LIBRARY(BE_LIBRARY be)
- FIND_LIBRARY(ROOT_LIBRARY root)
- SET(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY})
-ENDIF(BEOS)
+ set(PHYSFS_BEOS_SRCS src/platform_beos.cpp)
+ find_library(BE_LIBRARY be)
+ find_library(ROOT_LIBRARY root)
+ set(optionAL_LIBRARY_LIBS ${optionAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY})
+endif(BEOS)
+
+## extra functions needed by Hedgewars
+## TODO: maybe it's better to have them in a separate library?
+set(PHYSFS_HEDGE_SRCS
+ extras/physfsrwops.c
+ extras/physfslualoader.c
+ extras/hwpacksmounter.c
+)
# Almost everything is "compiled" here, but things that don't apply to the
# build are #ifdef'd out. This is to make it easy to embed PhysicsFS into
# another project or bring up a new build system: just compile all the source
# code and #define the things you want.
-SET(PHYSFS_SRCS
+set(PHYSFS_SRCS
src/physfs.c
src/physfs_byteorder.c
src/physfs_unicode.c
@@ -136,28 +149,29 @@
src/archiver_zip.c
src/archiver_iso9660.c
${PHYSFS_BEOS_SRCS}
+ ${PHYSFS_HEDGE_SRCS} ##
)
# platform layers ...
-IF(UNIX)
- IF(BEOS)
- SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
- SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
- SET(HAVE_PTHREAD_H TRUE)
- ELSE(BEOS)
+if(UNIX)
+ if(BEOS)
+ set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+ set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+ set(HAVE_PTHREAD_H TRUE)
+ else(BEOS)
CHECK_INCLUDE_FILE(sys/ucred.h HAVE_UCRED_H)
- IF(HAVE_UCRED_H)
- ADD_DEFINITIONS(-DPHYSFS_HAVE_SYS_UCRED_H=1)
- SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
- ENDIF(HAVE_UCRED_H)
+ if(HAVE_UCRED_H)
+ add_definitions(-DPHYSFS_HAVE_SYS_UCRED_H=1)
+ set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+ endif(HAVE_UCRED_H)
CHECK_INCLUDE_FILE(mntent.h HAVE_MNTENT_H)
- IF(HAVE_MNTENT_H)
- ADD_DEFINITIONS(-DPHYSFS_HAVE_MNTENT_H=1)
- SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
- ENDIF(HAVE_MNTENT_H)
+ if(HAVE_MNTENT_H)
+ add_definitions(-DPHYSFS_HAVE_MNTENT_H=1)
+ set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+ endif(HAVE_MNTENT_H)
# !!! FIXME: Solaris fails this, because mnttab.h implicitly
# !!! FIXME: depends on other system headers. :(
@@ -168,379 +182,134 @@
int main(int argc, char **argv) { return 0; }
" HAVE_SYS_MNTTAB_H)
- IF(HAVE_SYS_MNTTAB_H)
- ADD_DEFINITIONS(-DPHYSFS_HAVE_SYS_MNTTAB_H=1)
- SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
- ENDIF(HAVE_SYS_MNTTAB_H)
+ if(HAVE_SYS_MNTTAB_H)
+ add_definitions(-DPHYSFS_HAVE_SYS_MNTTAB_H=1)
+ set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+ endif(HAVE_SYS_MNTTAB_H)
CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
- IF(HAVE_PTHREAD_H)
- SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
- ENDIF(HAVE_PTHREAD_H)
- ENDIF(BEOS)
-ENDIF(UNIX)
+ if(HAVE_PTHREAD_H)
+ set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+ endif(HAVE_PTHREAD_H)
+ endif(BEOS)
+endif(UNIX)
-IF(WINDOWS)
- SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
- SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
-ENDIF(WINDOWS)
+if(WINDOWS)
+ set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+ set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+endif(WINDOWS)
-IF(NOT PHYSFS_HAVE_CDROM_SUPPORT)
- ADD_DEFINITIONS(-DPHYSFS_NO_CDROM_SUPPORT=1)
- MESSAGE(WARNING " ***")
- MESSAGE(WARNING " *** There is no CD-ROM support in this build!")
- MESSAGE(WARNING " *** PhysicsFS will just pretend there are no discs.")
- MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
- MESSAGE(WARNING " *** but is this what you REALLY wanted?")
- MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
- MESSAGE(WARNING " ***")
-ENDIF(NOT PHYSFS_HAVE_CDROM_SUPPORT)
+if(NOT PHYSFS_HAVE_CDROM_SUPPORT)
+ add_definitions(-DPHYSFS_NO_CDROM_SUPPORT=1)
+ message(WARNING " ***")
+ message(WARNING " *** There is no CD-ROM support in this build!")
+ message(WARNING " *** PhysicsFS will just pretend there are no discs.")
+ message(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
+ message(WARNING " *** but is this what you REALLY wanted?")
+ message(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
+ message(WARNING " ***")
+endif(NOT PHYSFS_HAVE_CDROM_SUPPORT)
-IF(PHYSFS_HAVE_THREAD_SUPPORT)
- ADD_DEFINITIONS(-D_REENTRANT -D_THREAD_SAFE)
-ELSE(PHYSFS_HAVE_THREAD_SUPPORT)
- ADD_DEFINITIONS(-DPHYSFS_NO_THREAD_SUPPORT=1)
- MESSAGE(WARNING " ***")
- MESSAGE(WARNING " *** There is no thread support in this build!")
- MESSAGE(WARNING " *** PhysicsFS will NOT be reentrant!")
- MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
- MESSAGE(WARNING " *** but is this what you REALLY wanted?")
- MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
- MESSAGE(WARNING " ***")
-ENDIF(PHYSFS_HAVE_THREAD_SUPPORT)
+if(PHYSFS_HAVE_THREAD_SUPPORT)
+ add_definitions(-D_REENTRANT -D_THREAD_SAFE)
+else(PHYSFS_HAVE_THREAD_SUPPORT)
+ add_definitions(-DPHYSFS_NO_THREAD_SUPPORT=1)
+ message(WARNING " ***")
+ message(WARNING " *** There is no thread support in this build!")
+ message(WARNING " *** PhysicsFS will NOT be reentrant!")
+ message(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
+ message(WARNING " *** but is this what you REALLY wanted?")
+ message(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
+ message(WARNING " ***")
+endif(PHYSFS_HAVE_THREAD_SUPPORT)
# Archivers ...
-OPTION(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE)
-IF(PHYSFS_ARCHIVE_ZIP)
- ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_ZIP=1)
-ENDIF(PHYSFS_ARCHIVE_ZIP)
+option(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE)
+if(PHYSFS_ARCHIVE_ZIP)
+ add_definitions(-DPHYSFS_SUPPORTS_ZIP=1)
+ set(PHYSFS_FEATURES "ZIP")
+endif(PHYSFS_ARCHIVE_ZIP)
-OPTION(PHYSFS_ARCHIVE_7Z "Enable 7zip support" FALSE)
-IF(PHYSFS_ARCHIVE_7Z)
- ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_7Z=1)
- # !!! FIXME: rename to 7z.c?
- SET(PHYSFS_SRCS ${PHYSFS_SRCS} ${LZMA_SRCS})
-ENDIF(PHYSFS_ARCHIVE_7Z)
+option(PHYSFS_ARCHIVE_7Z "Enable 7zip support" FALSE)
+if(PHYSFS_ARCHIVE_7Z)
+ add_definitions(-DPHYSFS_SUPPORTS_7Z=1)
+ list(APPEND PHYSFS_SRCS ${LZMA_SRCS})
+ set(PHYSFS_FEATURES "${PHYSFS_FEATURES} 7zip")
+endif(PHYSFS_ARCHIVE_7Z)
-OPTION(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE)
-IF(PHYSFS_ARCHIVE_GRP)
- ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_GRP=1)
-ENDIF(PHYSFS_ARCHIVE_GRP)
+option(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE)
+if(PHYSFS_ARCHIVE_GRP)
+ add_definitions(-DPHYSFS_SUPPORTS_GRP=1)
+ set(PHYSFS_FEATURES "${PHYSFS_FEATURES} GRP")
+endif(PHYSFS_ARCHIVE_GRP)
-OPTION(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE)
-IF(PHYSFS_ARCHIVE_WAD)
- ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_WAD=1)
-ENDIF(PHYSFS_ARCHIVE_WAD)
+option(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE)
+if(PHYSFS_ARCHIVE_WAD)
+ add_definitions(-DPHYSFS_SUPPORTS_WAD=1)
+ set(PHYSFS_FEATURES "${PHYSFS_FEATURES} WAD")
+endif(PHYSFS_ARCHIVE_WAD)
-OPTION(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE)
-IF(PHYSFS_ARCHIVE_HOG)
- ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_HOG=1)
-ENDIF(PHYSFS_ARCHIVE_HOG)
+option(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE)
+if(PHYSFS_ARCHIVE_HOG)
+ add_definitions(-DPHYSFS_SUPPORTS_HOG=1)
+ set(PHYSFS_FEATURES "${PHYSFS_FEATURES} HOG")
+endif(PHYSFS_ARCHIVE_HOG)
-OPTION(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE)
-IF(PHYSFS_ARCHIVE_MVL)
- ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_MVL=1)
-ENDIF(PHYSFS_ARCHIVE_MVL)
+option(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE)
+if(PHYSFS_ARCHIVE_MVL)
+ add_definitions(-DPHYSFS_SUPPORTS_MVL=1)
+ set(PHYSFS_FEATURES "${PHYSFS_FEATURES} MVL")
+endif(PHYSFS_ARCHIVE_MVL)
-OPTION(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE)
-IF(PHYSFS_ARCHIVE_QPAK)
- ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_QPAK=1)
-ENDIF(PHYSFS_ARCHIVE_QPAK)
+option(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE)
+if(PHYSFS_ARCHIVE_QPAK)
+ add_definitions(-DPHYSFS_SUPPORTS_QPAK=1)
+ set(PHYSFS_FEATURES "${PHYSFS_FEATURES} QPAK")
+endif(PHYSFS_ARCHIVE_QPAK)
-OPTION(PHYSFS_ARCHIVE_ISO9660 "Enable ISO9660 support" TRUE)
-IF(PHYSFS_ARCHIVE_ISO9660)
- ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_ISO9660=1)
-ENDIF(PHYSFS_ARCHIVE_ISO9660)
-
+option(PHYSFS_ARCHIVE_ISO9660 "Enable ISO9660 support" TRUE)
+if(PHYSFS_ARCHIVE_ISO9660)
+ add_definitions(-DPHYSFS_SUPPORTS_ISO9660=1)
+ set(PHYSFS_FEATURES "${PHYSFS_FEATURES} CD-ROM")
+endif(PHYSFS_ARCHIVE_ISO9660)
-OPTION(PHYSFS_BUILD_STATIC "Build static library" TRUE)
-IF(PHYSFS_BUILD_STATIC)
- ADD_LIBRARY(physfs STATIC ${PHYSFS_SRCS})
- SET_TARGET_PROPERTIES(physfs PROPERTIES OUTPUT_NAME "physfs")
- SET(PHYSFS_LIB_TARGET physfs)
- SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs")
-ENDIF(PHYSFS_BUILD_STATIC)
+##as needed by Hedgewars configuration
+if(WINDOWS)
+ option(PHYSFS_BUILD_STATIC "Build static library" FALSE)
+ option(PHYSFS_BUILD_SHARED "Build shared library" TRUE)
+ list(APPEND OTHER_LDFLAGS ${SDL_LIBRARY})
+else(WINDOWS)
+ option(PHYSFS_BUILD_STATIC "Build static library" TRUE)
+ option(PHYSFS_BUILD_SHARED "Build shared library" FALSE)
+endif(WINDOWS)
-#OPTION(PHYSFS_BUILD_SHARED "Build shared library" FALSE)
-#IF(PHYSFS_BUILD_SHARED)
-# ADD_LIBRARY(physfs SHARED ${PHYSFS_SRCS})
-# SET_TARGET_PROPERTIES(physfs PROPERTIES VERSION ${PHYSFS_VERSION})
-# SET_TARGET_PROPERTIES(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION})
-# TARGET_LINK_LIBRARIES(physfs ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS})
-# SET(PHYSFS_LIB_TARGET physfs)
-# SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs")
-#ENDIF(PHYSFS_BUILD_SHARED)
+if(PHYSFS_BUILD_STATIC)
+ add_library(physfs STATIC ${PHYSFS_SRCS})
+ set_target_properties(physfs PROPERTIES OUTPUT_NAME "physfs")
+endif(PHYSFS_BUILD_STATIC)
-IF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
- MESSAGE(FATAL "Both shared and static libraries are disabled!")
-ENDIF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
+if(PHYSFS_BUILD_SHARED)
+ add_library(physfs SHARED ${PHYSFS_SRCS})
+ set_target_properties(physfs PROPERTIES VERSION ${PHYSFS_VERSION})
+ set_target_properties(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION})
+ target_link_libraries(physfs ${optionAL_LIBRARY_LIBS} ${OTHER_LDFLAGS})
+ install(TARGETS physfs RUNTIME DESTINATION ${target_library_install_dir}) ##
+endif(PHYSFS_BUILD_SHARED)
+
+if(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
+ message(FATAL "Both shared and static libraries are disabled!")
+endif(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
# CMake FAQ says I need this...
-IF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
- SET_TARGET_PROPERTIES(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
- SET_TARGET_PROPERTIES(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
-ENDIF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
-
-OPTION(PHYSFS_BUILD_TEST "Build stdio test program." FALSE)
-MARK_AS_ADVANCED(PHYSFS_BUILD_TEST)
-IF(PHYSFS_BUILD_TEST)
- FIND_PATH(READLINE_H readline/readline.h)
- FIND_PATH(HISTORY_H readline/history.h)
- IF(READLINE_H AND HISTORY_H)
- FIND_LIBRARY(CURSES_LIBRARY NAMES curses ncurses)
- SET(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY})
- FIND_LIBRARY(READLINE_LIBRARY readline)
- IF(READLINE_LIBRARY)
- SET(HAVE_SYSTEM_READLINE TRUE)
- SET(TEST_PHYSFS_LIBS ${TEST_PHYSFS_LIBS} ${READLINE_LIBRARY} ${CURSES_LIBRARY})
- INCLUDE_DIRECTORIES(${READLINE_H} ${HISTORY_H})
- ADD_DEFINITIONS(-DPHYSFS_HAVE_READLINE=1)
- ENDIF(READLINE_LIBRARY)
- ENDIF(READLINE_H AND HISTORY_H)
- ADD_EXECUTABLE(test_physfs test/test_physfs.c)
- TARGET_LINK_LIBRARIES(test_physfs ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS})
- SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs")
-ENDIF(PHYSFS_BUILD_TEST)
+if(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
+ set_target_properties(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+endif(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
-# Scripting language bindings...
-
-#CMake's SWIG support is basically useless.
-#FIND_PACKAGE(SWIG)
-
-OPTION(PHYSFS_BUILD_SWIG "Build ${_LANG} bindings." FALSE)
-MARK_AS_ADVANCED(PHYSFS_BUILD_SWIG)
-
-FIND_PROGRAM(SWIG swig DOC "Path to swig command line app: http://swig.org/")
-IF(NOT SWIG)
- MESSAGE(STATUS "SWIG not found. You won't be able to build scripting language bindings.")
-ELSE(NOT SWIG)
- MARK_AS_ADVANCED(SWIG)
- IF(DEFINED CMAKE_BUILD_TYPE)
- IF((NOT CMAKE_BUILD_TYPE STREQUAL "") AND (NOT CMAKE_BUILD_TYPE STREQUAL "Debug"))
- IF(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
- SET(SWIG_OPT_CFLAGS "-small")
- ELSE(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
- SET(SWIG_OPT_CFLAGS "-O")
- ENDIF(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
- ENDIF((NOT CMAKE_BUILD_TYPE STREQUAL "") AND (NOT CMAKE_BUILD_TYPE STREQUAL "Debug"))
- ENDIF(DEFINED CMAKE_BUILD_TYPE)
-
- SET(SWIG_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/physfs-swig-bindings")
-
- MACRO(CONFIGURE_SWIG_BINDING _LANG _INSTALLPATH _EXTRAOUTPUTS _EXTRACFLAGS _EXTRALDFLAGS)
- STRING(TOUPPER "${_LANG}" _UPPERLANG)
- STRING(TOLOWER "${_LANG}" _LOWERLANG)
- SET(_TARGET "physfs-${_LOWERLANG}")
- SET(_TARGETDIR "${SWIG_OUTPUT_DIR}/${_LOWERLANG}")
-
- IF(NOT EXISTS "${_TARGETDIR}")
- FILE(MAKE_DIRECTORY "${_TARGETDIR}")
- ENDIF(NOT EXISTS "${_TARGETDIR}")
-
- IF(PHYSFS_BUILD_${_UPPERLANG})
- ADD_CUSTOM_COMMAND(
- OUTPUT "${_TARGETDIR}/${_TARGET}.c" ${_EXTRAOUTPUTS}
- MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/extras/physfs-swig.i"
- COMMAND "${SWIG}"
- ARGS ${SWIG_OPT_CFLAGS} -${_LOWERLANG} -outdir "${_TARGETDIR}" -o "${_TARGETDIR}/${_TARGET}.c" "${CMAKE_CURRENT_SOURCE_DIR}/extras/physfs-swig.i"
- COMMENT "Generating ${_LANG} bindings..."
- )
-
- ADD_LIBRARY(${_TARGET} SHARED "${_TARGETDIR}/${_TARGET}.c")
- TARGET_LINK_LIBRARIES(${_TARGET} ${PHYSFS_LIB_TARGET})
- SET_TARGET_PROPERTIES(${_TARGET} PROPERTIES
- COMPILE_FLAGS "${_EXTRACFLAGS}"
- LINK_FLAGS "${_EXTRALDFLAGS}"
- LIBRARY_OUTPUT_NAME "physfs"
- LIBRARY_OUTPUT_DIRECTORY "${_TARGETDIR}"
- CLEAN_DIRECT_OUTPUT 1
- )
- INSTALL(TARGETS ${_TARGET} LIBRARY DESTINATION "${_INSTALLPATH}")
- MESSAGE(STATUS "${_LANG} bindings configured!")
- ELSE(PHYSFS_BUILD_${_UPPERLANG})
- MESSAGE(STATUS "Couldn't figure out ${_LANG} configuration. Skipping ${_LANG} bindings.")
- ENDIF(PHYSFS_BUILD_${_UPPERLANG})
- ENDMACRO(CONFIGURE_SWIG_BINDING)
-
- MACRO(ADD_SCRIPT_BINDING_OPTION _VAR _LANG _DEFVAL)
- SET(BUILDSWIGVAL ${_DEFVAL})
- IF(NOT PHYSFS_BUILD_SWIG)
- SET(BUILDSWIGVAL FALSE)
- ENDIF(NOT PHYSFS_BUILD_SWIG)
- OPTION(${_VAR} "Build ${_LANG} bindings." ${BUILDSWIGVAL})
- MARK_AS_ADVANCED(${_VAR})
- ENDMACRO(ADD_SCRIPT_BINDING_OPTION)
-
- ADD_SCRIPT_BINDING_OPTION(PHYSFS_BUILD_PERL "Perl" TRUE)
- ADD_SCRIPT_BINDING_OPTION(PHYSFS_BUILD_RUBY "Ruby" TRUE)
-ENDIF(NOT SWIG)
-
-IF(PHYSFS_BUILD_PERL)
- MESSAGE(STATUS "Configuring Perl bindings...")
- FIND_PROGRAM(PERL perl DOC "Path to perl command line app: http://perl.org/")
- IF(NOT PERL)
- MESSAGE(STATUS "Perl not found. You won't be able to build perl bindings.")
- SET(PHYSFS_BUILD_PERL FALSE)
- ENDIF(NOT PERL)
- MARK_AS_ADVANCED(PERL)
-
- MACRO(GET_PERL_CONFIG _KEY _VALUE)
- IF(PHYSFS_BUILD_PERL)
- MESSAGE(STATUS "Figuring out perl config value '${_KEY}' ...")
- EXECUTE_PROCESS(
- COMMAND ${PERL} -w -e "use Config; print \$Config{${_KEY}};"
- RESULT_VARIABLE GET_PERL_CONFIG_RC
- OUTPUT_VARIABLE ${_VALUE}
- )
- IF(NOT GET_PERL_CONFIG_RC EQUAL 0)
- MESSAGE(STATUS "Perl executable ('${PERL}') reported failure: ${GET_PERL_CONFIG_RC}")
- SET(PHYSFS_BUILD_PERL FALSE)
- ENDIF(NOT GET_PERL_CONFIG_RC EQUAL 0)
- IF(NOT ${_VALUE})
- MESSAGE(STATUS "Perl executable ('${PERL}') didn't have a value for '${_KEY}'")
- SET(PHYSFS_BUILD_PERL FALSE)
- ENDIF(NOT ${_VALUE})
-
- IF(PHYSFS_BUILD_PERL)
- MESSAGE(STATUS "Perl says: '${${_VALUE}}'.")
- ENDIF(PHYSFS_BUILD_PERL)
- ENDIF(PHYSFS_BUILD_PERL)
- ENDMACRO(GET_PERL_CONFIG)
-
- # !!! FIXME: installsitearch might be the wrong location.
- GET_PERL_CONFIG("archlibexp" PERL_INCLUDE_PATH)
- GET_PERL_CONFIG("ccflags" PERL_CCFLAGS)
- GET_PERL_CONFIG("ldflags" PERL_LDFLAGS)
- GET_PERL_CONFIG("installsitearch" PERL_INSTALL_PATH)
+## removed install, language bindings and test program
+## simplified configuration output
- # !!! FIXME: this test for Mac OS X is wrong.
- IF(MACOSX)
- GET_PERL_CONFIG("libperl" PERL_LIBPERL)
- SET(TMPLIBPERL "${PERL_LIBPERL}")
- STRING(REGEX REPLACE "^lib" "" TMPLIBPERL "${TMPLIBPERL}")
- STRING(REGEX REPLACE "\\.so$" "" TMPLIBPERL "${TMPLIBPERL}")
- STRING(REGEX REPLACE "\\.dylib$" "" TMPLIBPERL "${TMPLIBPERL}")
- STRING(REGEX REPLACE "\\.dll$" "" TMPLIBPERL "${TMPLIBPERL}")
- IF(NOT "${TMPLIBPERL}" STREQUAL "${PERL_LIBPERL}")
- MESSAGE(STATUS "Stripped '${PERL_LIBPERL}' down to '${TMPLIBPERL}'.")
- SET(PERL_LIBPERL "${TMPLIBPERL}")
- ENDIF(NOT "${TMPLIBPERL}" STREQUAL "${PERL_LIBPERL}")
- SET(PERL_LIBPERL "-l${PERL_LIBPERL}")
- ENDIF(MACOSX)
-
- CONFIGURE_SWIG_BINDING(Perl "${PERL_INSTALL_PATH}" "${SWIG_OUTPUT_DIR}/perl/physfs.pm" "\"-I${PERL_INCLUDE_PATH}/CORE\" ${PERL_CCFLAGS} -w" "\"-L${PERL_INCLUDE_PATH}/CORE\" ${PERL_LIBPERL} ${PERL_LDFLAGS}")
- INSTALL(FILES "${SWIG_OUTPUT_DIR}/perl/physfs.pm" DESTINATION "${PERL_INSTALL_PATH}")
- INSTALL(
- FILES test/test_physfs.pl
- DESTINATION bin
- PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
- GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
- )
-ENDIF(PHYSFS_BUILD_PERL)
-
-# !!! FIXME: lots of cut-and-paste from perl bindings.
-IF(PHYSFS_BUILD_RUBY)
- MESSAGE(STATUS "Configuring Ruby bindings...")
- FIND_PROGRAM(RUBY ruby DOC "Path to ruby command line app: http://ruby-lang.org/")
- IF(NOT RUBY)
- MESSAGE(STATUS "Ruby not found. You won't be able to build ruby bindings.")
- SET(PHYSFS_BUILD_RUBY FALSE)
- ENDIF(NOT RUBY)
- MARK_AS_ADVANCED(RUBY)
-
- MACRO(GET_RUBY_CONFIG _KEY _VALUE)
- IF(PHYSFS_BUILD_RUBY)
- MESSAGE(STATUS "Figuring out ruby config value '${_KEY}' ...")
- EXECUTE_PROCESS(
- COMMAND ${RUBY} -e "require 'rbconfig'; puts RbConfig::CONFIG['${_KEY}'];"
- RESULT_VARIABLE GET_RUBY_CONFIG_RC
- OUTPUT_VARIABLE ${_VALUE}
- OUTPUT_STRIP_TRAILING_WHITESPACE
- )
- IF(NOT GET_RUBY_CONFIG_RC EQUAL 0)
- MESSAGE(STATUS "Ruby executable ('${RUBY}') reported failure: ${GET_RUBY_CONFIG_RC}")
- SET(PHYSFS_BUILD_RUBY FALSE)
- ENDIF(NOT GET_RUBY_CONFIG_RC EQUAL 0)
- IF(NOT ${_VALUE})
- MESSAGE(STATUS "Ruby executable ('${RUBY}') didn't have a value for '${_KEY}'")
- SET(PHYSFS_BUILD_RUBY FALSE)
- ENDIF(NOT ${_VALUE})
-
- IF(PHYSFS_BUILD_RUBY)
- MESSAGE(STATUS "Ruby says: '${${_VALUE}}'.")
- ENDIF(PHYSFS_BUILD_RUBY)
- ENDIF(PHYSFS_BUILD_RUBY)
- ENDMACRO(GET_RUBY_CONFIG)
+message(STATUS "PhysicsFS will build with ${PHYSFS_FEATURES} support")
- GET_RUBY_CONFIG("archdir" RUBY_INCLUDE_PATH)
- GET_RUBY_CONFIG("CFLAGS" RUBY_CCFLAGS)
- GET_RUBY_CONFIG("LDFLAGS" RUBY_LDFLAGS)
- GET_RUBY_CONFIG("sitearchdir" RUBY_INSTALL_PATH)
- GET_RUBY_CONFIG("LIBRUBYARG_SHARED" RUBY_LIBRUBY)
- GET_RUBY_CONFIG("libdir" RUBY_LIBDIR)
-
- CONFIGURE_SWIG_BINDING(Ruby "${RUBY_INSTALL_PATH}" "" "\"-I${RUBY_INCLUDE_PATH}\" ${RUBY_CCFLAGS} -w" "\"-L${RUBY_LIBDIR}\" ${RUBY_LIBRUBY} ${RUBY_LDFLAGS}")
- SET_TARGET_PROPERTIES(physfs-ruby PROPERTIES PREFIX "")
- INSTALL(
- FILES test/test_physfs.rb
- DESTINATION bin
- PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
- GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
- )
-ENDIF(PHYSFS_BUILD_RUBY)
-
-
-INSTALL(TARGETS ${PHYSFS_INSTALL_TARGETS}
- RUNTIME DESTINATION bin
- LIBRARY DESTINATION lib${LIB_SUFFIX}
- ARCHIVE DESTINATION lib${LIB_SUFFIX})
-INSTALL(FILES src/physfs.h DESTINATION include)
-
-IF(UNIX)
- SET(PHYSFS_TARBALL "${CMAKE_CURRENT_SOURCE_DIR}/../physfs-${PHYSFS_VERSION}.tar.gz")
- ADD_CUSTOM_TARGET(
- dist
- hg archive -t tgz "${PHYSFS_TARBALL}"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- COMMENT "Building source tarball '${PHYSFS_TARBALL}'..."
- )
-# ADD_CUSTOM_TARGET(
-# uninstall
-# "${CMAKE_CURRENT_SOURCE_DIR}/extras/uninstall.sh"
-# WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
-# COMMENT "Uninstall the project..."
-# )
-ENDIF(UNIX)
-
-MACRO(MESSAGE_BOOL_OPTION _NAME _VALUE)
- IF(${_VALUE})
- MESSAGE(STATUS " ${_NAME}: enabled")
- ELSE(${_VALUE})
- MESSAGE(STATUS " ${_NAME}: disabled")
- ENDIF(${_VALUE})
-ENDMACRO(MESSAGE_BOOL_OPTION)
-
-MESSAGE(STATUS "PhysicsFS will build with the following options:")
-MESSAGE_BOOL_OPTION("ZIP support" PHYSFS_ARCHIVE_ZIP)
-MESSAGE_BOOL_OPTION("7zip support" PHYSFS_ARCHIVE_7Z)
-MESSAGE_BOOL_OPTION("GRP support" PHYSFS_ARCHIVE_GRP)
-MESSAGE_BOOL_OPTION("WAD support" PHYSFS_ARCHIVE_WAD)
-MESSAGE_BOOL_OPTION("HOG support" PHYSFS_ARCHIVE_HOG)
-MESSAGE_BOOL_OPTION("MVL support" PHYSFS_ARCHIVE_MVL)
-MESSAGE_BOOL_OPTION("QPAK support" PHYSFS_ARCHIVE_QPAK)
-MESSAGE_BOOL_OPTION("CD-ROM drive support" PHYSFS_HAVE_CDROM_SUPPORT)
-MESSAGE_BOOL_OPTION("Thread safety" PHYSFS_HAVE_THREAD_SUPPORT)
-MESSAGE_BOOL_OPTION("Build static library" PHYSFS_BUILD_STATIC)
-MESSAGE_BOOL_OPTION("Build shared library" PHYSFS_BUILD_SHARED)
-MESSAGE_BOOL_OPTION("Build Perl bindings" PHYSFS_BUILD_PERL)
-MESSAGE_BOOL_OPTION("Build Ruby bindings" PHYSFS_BUILD_RUBY)
-MESSAGE_BOOL_OPTION("Build stdio test program" PHYSFS_BUILD_TEST)
-IF(PHYSFS_BUILD_TEST)
- MESSAGE_BOOL_OPTION(" Use readline in test program" HAVE_SYSTEM_READLINE)
-ENDIF(PHYSFS_BUILD_TEST)
-
-# end of CMakeLists.txt ...
-
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/physfs/Xcode/Physfs.xcodeproj/project.pbxproj
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/Xcode/Physfs.xcodeproj/project.pbxproj Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,354 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 610FB79016613776002FB2A7 /* archiver_dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77916613776002FB2A7 /* archiver_dir.c */; };
+ 610FB79116613776002FB2A7 /* archiver_grp.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77A16613776002FB2A7 /* archiver_grp.c */; };
+ 610FB79216613776002FB2A7 /* archiver_hog.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77B16613776002FB2A7 /* archiver_hog.c */; };
+ 610FB79316613776002FB2A7 /* archiver_iso9660.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77C16613776002FB2A7 /* archiver_iso9660.c */; };
+ 610FB79416613776002FB2A7 /* archiver_lzma.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77D16613776002FB2A7 /* archiver_lzma.c */; };
+ 610FB79516613776002FB2A7 /* archiver_mvl.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77E16613776002FB2A7 /* archiver_mvl.c */; };
+ 610FB79616613776002FB2A7 /* archiver_qpak.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77F16613776002FB2A7 /* archiver_qpak.c */; };
+ 610FB79716613776002FB2A7 /* archiver_unpacked.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78016613776002FB2A7 /* archiver_unpacked.c */; };
+ 610FB79816613776002FB2A7 /* archiver_wad.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78116613776002FB2A7 /* archiver_wad.c */; };
+ 610FB79916613776002FB2A7 /* archiver_zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78216613776002FB2A7 /* archiver_zip.c */; };
+ 610FB79A16613776002FB2A7 /* physfs_byteorder.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78316613776002FB2A7 /* physfs_byteorder.c */; };
+ 610FB79B16613776002FB2A7 /* physfs_casefolding.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB78416613776002FB2A7 /* physfs_casefolding.h */; };
+ 610FB79C16613776002FB2A7 /* physfs_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB78516613776002FB2A7 /* physfs_internal.h */; };
+ 610FB79D16613776002FB2A7 /* physfs_miniz.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB78616613776002FB2A7 /* physfs_miniz.h */; };
+ 610FB79E16613776002FB2A7 /* physfs_platforms.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB78716613776002FB2A7 /* physfs_platforms.h */; };
+ 610FB79F16613776002FB2A7 /* physfs_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78816613776002FB2A7 /* physfs_unicode.c */; };
+ 610FB7A016613776002FB2A7 /* physfs.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78916613776002FB2A7 /* physfs.c */; };
+ 610FB7A116613776002FB2A7 /* physfs.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB78A16613776002FB2A7 /* physfs.h */; };
+ 610FB7A216613776002FB2A7 /* platform_beos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78B16613776002FB2A7 /* platform_beos.cpp */; };
+ 610FB7A316613776002FB2A7 /* platform_macosx.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78C16613776002FB2A7 /* platform_macosx.c */; };
+ 610FB7A416613776002FB2A7 /* platform_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78D16613776002FB2A7 /* platform_posix.c */; };
+ 610FB7A516613776002FB2A7 /* platform_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78E16613776002FB2A7 /* platform_unix.c */; };
+ 610FB7A616613776002FB2A7 /* platform_windows.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78F16613776002FB2A7 /* platform_windows.c */; };
+ 610FB7AE16613813002FB2A7 /* hwpacksmounter.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB7A916613813002FB2A7 /* hwpacksmounter.c */; };
+ 610FB7AF16613813002FB2A7 /* hwpacksmounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB7AA16613813002FB2A7 /* hwpacksmounter.h */; };
+ 610FB7B016613813002FB2A7 /* physfslualoader.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB7AB16613813002FB2A7 /* physfslualoader.c */; };
+ 610FB7B116613813002FB2A7 /* physfsrwops.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB7AC16613813002FB2A7 /* physfsrwops.c */; };
+ 610FB7B216613813002FB2A7 /* physfsrwops.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB7AD16613813002FB2A7 /* physfsrwops.h */; };
+ AA747D9F0F9514B9006C5449 /* Physfs_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* Physfs_Prefix.pch */; };
+ AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 610FB77916613776002FB2A7 /* archiver_dir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_dir.c; path = ../src/archiver_dir.c; sourceTree = SOURCE_ROOT; };
+ 610FB77A16613776002FB2A7 /* archiver_grp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_grp.c; path = ../src/archiver_grp.c; sourceTree = SOURCE_ROOT; };
+ 610FB77B16613776002FB2A7 /* archiver_hog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_hog.c; path = ../src/archiver_hog.c; sourceTree = SOURCE_ROOT; };
+ 610FB77C16613776002FB2A7 /* archiver_iso9660.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_iso9660.c; path = ../src/archiver_iso9660.c; sourceTree = SOURCE_ROOT; };
+ 610FB77D16613776002FB2A7 /* archiver_lzma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_lzma.c; path = ../src/archiver_lzma.c; sourceTree = SOURCE_ROOT; };
+ 610FB77E16613776002FB2A7 /* archiver_mvl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_mvl.c; path = ../src/archiver_mvl.c; sourceTree = SOURCE_ROOT; };
+ 610FB77F16613776002FB2A7 /* archiver_qpak.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_qpak.c; path = ../src/archiver_qpak.c; sourceTree = SOURCE_ROOT; };
+ 610FB78016613776002FB2A7 /* archiver_unpacked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_unpacked.c; path = ../src/archiver_unpacked.c; sourceTree = SOURCE_ROOT; };
+ 610FB78116613776002FB2A7 /* archiver_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_wad.c; path = ../src/archiver_wad.c; sourceTree = SOURCE_ROOT; };
+ 610FB78216613776002FB2A7 /* archiver_zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_zip.c; path = ../src/archiver_zip.c; sourceTree = SOURCE_ROOT; };
+ 610FB78316613776002FB2A7 /* physfs_byteorder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfs_byteorder.c; path = ../src/physfs_byteorder.c; sourceTree = SOURCE_ROOT; };
+ 610FB78416613776002FB2A7 /* physfs_casefolding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_casefolding.h; path = ../src/physfs_casefolding.h; sourceTree = SOURCE_ROOT; };
+ 610FB78516613776002FB2A7 /* physfs_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_internal.h; path = ../src/physfs_internal.h; sourceTree = SOURCE_ROOT; };
+ 610FB78616613776002FB2A7 /* physfs_miniz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_miniz.h; path = ../src/physfs_miniz.h; sourceTree = SOURCE_ROOT; };
+ 610FB78716613776002FB2A7 /* physfs_platforms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_platforms.h; path = ../src/physfs_platforms.h; sourceTree = SOURCE_ROOT; };
+ 610FB78816613776002FB2A7 /* physfs_unicode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfs_unicode.c; path = ../src/physfs_unicode.c; sourceTree = SOURCE_ROOT; };
+ 610FB78916613776002FB2A7 /* physfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfs.c; path = ../src/physfs.c; sourceTree = SOURCE_ROOT; };
+ 610FB78A16613776002FB2A7 /* physfs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs.h; path = ../src/physfs.h; sourceTree = SOURCE_ROOT; };
+ 610FB78B16613776002FB2A7 /* platform_beos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = platform_beos.cpp; path = ../src/platform_beos.cpp; sourceTree = SOURCE_ROOT; };
+ 610FB78C16613776002FB2A7 /* platform_macosx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_macosx.c; path = ../src/platform_macosx.c; sourceTree = SOURCE_ROOT; };
+ 610FB78D16613776002FB2A7 /* platform_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_posix.c; path = ../src/platform_posix.c; sourceTree = SOURCE_ROOT; };
+ 610FB78E16613776002FB2A7 /* platform_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_unix.c; path = ../src/platform_unix.c; sourceTree = SOURCE_ROOT; };
+ 610FB78F16613776002FB2A7 /* platform_windows.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_windows.c; path = ../src/platform_windows.c; sourceTree = SOURCE_ROOT; };
+ 610FB7A916613813002FB2A7 /* hwpacksmounter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hwpacksmounter.c; path = ../extras/hwpacksmounter.c; sourceTree = SOURCE_ROOT; };
+ 610FB7AA16613813002FB2A7 /* hwpacksmounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hwpacksmounter.h; path = ../extras/hwpacksmounter.h; sourceTree = SOURCE_ROOT; };
+ 610FB7AB16613813002FB2A7 /* physfslualoader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfslualoader.c; path = ../extras/physfslualoader.c; sourceTree = SOURCE_ROOT; };
+ 610FB7AC16613813002FB2A7 /* physfsrwops.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfsrwops.c; path = ../extras/physfsrwops.c; sourceTree = SOURCE_ROOT; };
+ 610FB7AD16613813002FB2A7 /* physfsrwops.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfsrwops.h; path = ../extras/physfsrwops.h; sourceTree = SOURCE_ROOT; };
+ AA747D9E0F9514B9006C5449 /* Physfs_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Physfs_Prefix.pch; sourceTree = SOURCE_ROOT; };
+ AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ D2AAC07E0554694100DB518D /* libPhysfs.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPhysfs.a; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ D2AAC07C0554694100DB518D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DFFF38A50411DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ D2AAC07E0554694100DB518D /* libPhysfs.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 0867D691FE84028FC02AAC07 /* Physfs */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB77AEFE84172EC02AAC07 /* Sources */,
+ 610FB77116613730002FB2A7 /* Extras */,
+ 32C88DFF0371C24200C91783 /* Other Sources */,
+ 0867D69AFE84028FC02AAC07 /* Frameworks */,
+ 034768DFFF38A50411DB9C8B /* Products */,
+ );
+ name = Physfs;
+ sourceTree = "";
+ };
+ 0867D69AFE84028FC02AAC07 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ AACBBE490F95108600F1A2B1 /* Foundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 08FB77AEFE84172EC02AAC07 /* Sources */ = {
+ isa = PBXGroup;
+ children = (
+ 610FB77916613776002FB2A7 /* archiver_dir.c */,
+ 610FB77A16613776002FB2A7 /* archiver_grp.c */,
+ 610FB77B16613776002FB2A7 /* archiver_hog.c */,
+ 610FB77C16613776002FB2A7 /* archiver_iso9660.c */,
+ 610FB77D16613776002FB2A7 /* archiver_lzma.c */,
+ 610FB77E16613776002FB2A7 /* archiver_mvl.c */,
+ 610FB77F16613776002FB2A7 /* archiver_qpak.c */,
+ 610FB78016613776002FB2A7 /* archiver_unpacked.c */,
+ 610FB78116613776002FB2A7 /* archiver_wad.c */,
+ 610FB78216613776002FB2A7 /* archiver_zip.c */,
+ 610FB78316613776002FB2A7 /* physfs_byteorder.c */,
+ 610FB78416613776002FB2A7 /* physfs_casefolding.h */,
+ 610FB78516613776002FB2A7 /* physfs_internal.h */,
+ 610FB78616613776002FB2A7 /* physfs_miniz.h */,
+ 610FB78716613776002FB2A7 /* physfs_platforms.h */,
+ 610FB78816613776002FB2A7 /* physfs_unicode.c */,
+ 610FB78916613776002FB2A7 /* physfs.c */,
+ 610FB78A16613776002FB2A7 /* physfs.h */,
+ 610FB78B16613776002FB2A7 /* platform_beos.cpp */,
+ 610FB78C16613776002FB2A7 /* platform_macosx.c */,
+ 610FB78D16613776002FB2A7 /* platform_posix.c */,
+ 610FB78E16613776002FB2A7 /* platform_unix.c */,
+ 610FB78F16613776002FB2A7 /* platform_windows.c */,
+ );
+ name = Sources;
+ sourceTree = "";
+ };
+ 32C88DFF0371C24200C91783 /* Other Sources */ = {
+ isa = PBXGroup;
+ children = (
+ AA747D9E0F9514B9006C5449 /* Physfs_Prefix.pch */,
+ );
+ name = "Other Sources";
+ sourceTree = "";
+ };
+ 610FB77116613730002FB2A7 /* Extras */ = {
+ isa = PBXGroup;
+ children = (
+ 610FB7A916613813002FB2A7 /* hwpacksmounter.c */,
+ 610FB7AA16613813002FB2A7 /* hwpacksmounter.h */,
+ 610FB7AB16613813002FB2A7 /* physfslualoader.c */,
+ 610FB7AC16613813002FB2A7 /* physfsrwops.c */,
+ 610FB7AD16613813002FB2A7 /* physfsrwops.h */,
+ );
+ name = Extras;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ D2AAC07A0554694100DB518D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AA747D9F0F9514B9006C5449 /* Physfs_Prefix.pch in Headers */,
+ 610FB79B16613776002FB2A7 /* physfs_casefolding.h in Headers */,
+ 610FB79C16613776002FB2A7 /* physfs_internal.h in Headers */,
+ 610FB79D16613776002FB2A7 /* physfs_miniz.h in Headers */,
+ 610FB79E16613776002FB2A7 /* physfs_platforms.h in Headers */,
+ 610FB7A116613776002FB2A7 /* physfs.h in Headers */,
+ 610FB7AF16613813002FB2A7 /* hwpacksmounter.h in Headers */,
+ 610FB7B216613813002FB2A7 /* physfsrwops.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ D2AAC07D0554694100DB518D /* Physfs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Physfs" */;
+ buildPhases = (
+ D2AAC07A0554694100DB518D /* Headers */,
+ D2AAC07B0554694100DB518D /* Sources */,
+ D2AAC07C0554694100DB518D /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Physfs;
+ productName = Physfs;
+ productReference = D2AAC07E0554694100DB518D /* libPhysfs.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Physfs" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* Physfs */;
+ productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ D2AAC07D0554694100DB518D /* Physfs */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ D2AAC07B0554694100DB518D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 610FB79016613776002FB2A7 /* archiver_dir.c in Sources */,
+ 610FB79116613776002FB2A7 /* archiver_grp.c in Sources */,
+ 610FB79216613776002FB2A7 /* archiver_hog.c in Sources */,
+ 610FB79316613776002FB2A7 /* archiver_iso9660.c in Sources */,
+ 610FB79416613776002FB2A7 /* archiver_lzma.c in Sources */,
+ 610FB79516613776002FB2A7 /* archiver_mvl.c in Sources */,
+ 610FB79616613776002FB2A7 /* archiver_qpak.c in Sources */,
+ 610FB79716613776002FB2A7 /* archiver_unpacked.c in Sources */,
+ 610FB79816613776002FB2A7 /* archiver_wad.c in Sources */,
+ 610FB79916613776002FB2A7 /* archiver_zip.c in Sources */,
+ 610FB79A16613776002FB2A7 /* physfs_byteorder.c in Sources */,
+ 610FB79F16613776002FB2A7 /* physfs_unicode.c in Sources */,
+ 610FB7A016613776002FB2A7 /* physfs.c in Sources */,
+ 610FB7A216613776002FB2A7 /* platform_beos.cpp in Sources */,
+ 610FB7A316613776002FB2A7 /* platform_macosx.c in Sources */,
+ 610FB7A416613776002FB2A7 /* platform_posix.c in Sources */,
+ 610FB7A516613776002FB2A7 /* platform_unix.c in Sources */,
+ 610FB7A616613776002FB2A7 /* platform_windows.c in Sources */,
+ 610FB7AE16613813002FB2A7 /* hwpacksmounter.c in Sources */,
+ 610FB7B016613813002FB2A7 /* physfslualoader.c in Sources */,
+ 610FB7B116613813002FB2A7 /* physfsrwops.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB921F08733DC00010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ COPY_PHASE_STRIP = NO;
+ DSTROOT = /tmp/Physfs.dst;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = Physfs_Prefix.pch;
+ INSTALL_PATH = /usr/local/lib;
+ PRODUCT_NAME = Physfs;
+ };
+ name = Debug;
+ };
+ 1DEB922008733DC00010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ DSTROOT = /tmp/Physfs.dst;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = Physfs_Prefix.pch;
+ INSTALL_PATH = /usr/local/lib;
+ PRODUCT_NAME = Physfs;
+ };
+ name = Release;
+ };
+ 1DEB922308733DC00010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "\"$(SRCROOT)/../../liblua\"",
+ "\"$(SRCROOT)/../../../../Library/SDL/include\"",
+ );
+ OTHER_LDFLAGS = "-ObjC";
+ PREBINDING = NO;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 1DEB922408733DC00010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "\"$(SRCROOT)/../../liblua\"",
+ "\"$(SRCROOT)/../../../../Library/SDL/include\"",
+ );
+ OTHER_LDFLAGS = "-ObjC";
+ PREBINDING = NO;
+ SDKROOT = iphoneos;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Physfs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB921F08733DC00010E9CD /* Debug */,
+ 1DEB922008733DC00010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Physfs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB922308733DC00010E9CD /* Debug */,
+ 1DEB922408733DC00010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/physfs/Xcode/Physfs_Prefix.pch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/Xcode/Physfs_Prefix.pch Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,7 @@
+//
+// Prefix header for all source files of the 'CocoaTouchStaticLibrary' target in the 'CocoaTouchStaticLibrary' project.
+//
+
+#ifdef __OBJC__
+ #import
+#endif
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/physfs/extras/CMakeLists.txt
--- a/misc/physfs/extras/CMakeLists.txt Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-find_package(SDL REQUIRED)
-
-include_directories(${SDL_INCLUDE_DIR})
-include_directories(${CMAKE_SOURCE_DIR}/misc/liblua)
-include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/src)
-
-add_library(physfsrwops STATIC physfsrwops.c physfslualoader.c hwpacksmounter.c)
-
-add_dependencies(physfsrwops lua)
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/physfs/extras/hwpacksmounter.c
--- a/misc/physfs/extras/hwpacksmounter.c Sun Nov 18 01:06:01 2012 +0400
+++ b/misc/physfs/extras/hwpacksmounter.c Fri Feb 22 05:05:32 2013 +0100
@@ -1,11 +1,10 @@
#include
#include
#include
-#include
#include "hwpacksmounter.h"
-void hedgewarsMountPackages()
+PHYSFS_DECL void hedgewarsMountPackages()
{
char ** filesList = PHYSFS_enumerateFiles("/");
char **i;
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/physfs/extras/hwpacksmounter.h
--- a/misc/physfs/extras/hwpacksmounter.h Sun Nov 18 01:06:01 2012 +0400
+++ b/misc/physfs/extras/hwpacksmounter.h Fri Feb 22 05:05:32 2013 +0100
@@ -1,11 +1,13 @@
#ifndef HEDGEWARS_PACKAGES_MOUNTER_H
#define HEDGEWARS_PACKAGES_MOUNTER_H
+#include "physfs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-void hedgewarsMountPackages();
+PHYSFS_DECL void hedgewarsMountPackages();
#ifdef __cplusplus
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/physfs/extras/physfslualoader.c
--- a/misc/physfs/extras/physfslualoader.c Sun Nov 18 01:06:01 2012 +0400
+++ b/misc/physfs/extras/physfslualoader.c Fri Feb 22 05:05:32 2013 +0100
@@ -1,11 +1,11 @@
-#include
-#include
+#include "lua.h"
+#include "physfs.h"
#define BUFSIZE 1024
-void * physfsReaderBuffer;
+void *physfsReaderBuffer;
-const char * physfsReader(lua_State *L, PHYSFS_File *f, size_t *size)
+PHYSFS_DECL const char * physfsReader(lua_State *L, PHYSFS_File *f, size_t *size)
{
if(PHYSFS_eof(f))
@@ -22,3 +22,9 @@
return physfsReaderBuffer;
}
}
+
+PHYSFS_DECL void physfsReaderSetBuffer(void *buffer)
+{
+ physfsReaderBuffer = buffer;
+}
+
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/physfs/src/Android.mk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/Android.mk Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,32 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := physfs
+
+LOCAL_CFLAGS := -O2 -DPHYSFS_NO_CDROM_SUPPORT
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH) $(MISC_DIR)/liblua $(MISC_DIR)/liblua $(JNI_DIR)/SDL/include
+
+LOCAL_SRC_FILES := physfs.c \
+ physfs_byteorder.c \
+ physfs_unicode.c \
+ platform_posix.c \
+ platform_unix.c \
+ platform_macosx.c \
+ platform_windows.c \
+ archiver_dir.c \
+ archiver_grp.c \
+ archiver_hog.c \
+ archiver_lzma.c \
+ archiver_mvl.c \
+ archiver_qpak.c \
+ archiver_wad.c \
+ archiver_zip.c \
+ ../extras/hwpacksmounter.c \
+ ../extras/physfslualoader.c \
+ ../extras/physfsrwops.c \
+
+LOCAL_SHARED_LIBRARIES += SDL lua
+
+include $(BUILD_SHARED_LIBRARY)
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/winutils/Hedgewars.lnk
Binary file misc/winutils/Hedgewars.lnk has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/winutils/include/GL/glut.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/winutils/include/GL/glut.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,716 @@
+#ifndef __glut_h__
+#define __glut_h__
+
+/* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1998. */
+
+/* This program is freely distributable without licensing fees and is
+ provided without guarantee or warrantee expressed or implied. This
+ program is -not- in the public domain. */
+
+#if defined(_WIN32)
+
+/* GLUT 3.7 now tries to avoid including
+ to avoid name space pollution, but Win32's
+ needs APIENTRY and WINGDIAPI defined properly. */
+# if 0
+ /* This would put tons of macros and crap in our clean name space. */
+# define WIN32_LEAN_AND_MEAN
+# include
+# else
+ /* XXX This is from Win32's */
+# ifndef APIENTRY
+# define GLUT_APIENTRY_DEFINED
+# if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__) || defined(__LCC__)
+# define APIENTRY __stdcall
+# else
+# define APIENTRY
+# endif
+# endif
+ /* XXX This is from Win32's */
+# ifndef CALLBACK
+# if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) || defined(__LCC__)
+# define CALLBACK __stdcall
+# else
+# define CALLBACK
+# endif
+# endif
+ /* XXX Hack for lcc compiler. It doesn't support __declspec(dllimport), just __stdcall. */
+# if defined( __LCC__ )
+# undef WINGDIAPI
+# define WINGDIAPI __stdcall
+# else
+ /* XXX This is from Win32's and */
+# ifndef WINGDIAPI
+# define GLUT_WINGDIAPI_DEFINED
+# define WINGDIAPI __declspec(dllimport)
+# endif
+# endif
+ /* XXX This is from Win32's */
+# ifndef _WCHAR_T_DEFINED
+typedef unsigned short wchar_t;
+# define _WCHAR_T_DEFINED
+# endif
+# endif
+
+/* To disable automatic library usage for GLUT, define GLUT_NO_LIB_PRAGMA
+ in your compile preprocessor options. */
+# if !defined(GLUT_BUILDING_LIB) && !defined(GLUT_NO_LIB_PRAGMA)
+# pragma comment (lib, "winmm.lib") /* link with Windows MultiMedia lib */
+/* To enable automatic SGI OpenGL for Windows library usage for GLUT,
+ define GLUT_USE_SGI_OPENGL in your compile preprocessor options. */
+# ifdef GLUT_USE_SGI_OPENGL
+# pragma comment (lib, "opengl.lib") /* link with SGI OpenGL for Windows lib */
+# pragma comment (lib, "glu.lib") /* link with SGI OpenGL Utility lib */
+# pragma comment (lib, "glut.lib") /* link with Win32 GLUT for SGI OpenGL lib */
+# else
+# pragma comment (lib, "opengl32.lib") /* link with Microsoft OpenGL lib */
+# pragma comment (lib, "glu32.lib") /* link with Microsoft OpenGL Utility lib */
+# pragma comment (lib, "glut32.lib") /* link with Win32 GLUT lib */
+# endif
+# endif
+
+/* To disable supression of annoying warnings about floats being promoted
+ to doubles, define GLUT_NO_WARNING_DISABLE in your compile preprocessor
+ options. */
+# ifndef GLUT_NO_WARNING_DISABLE
+# pragma warning (disable:4244) /* Disable bogus VC++ 4.2 conversion warnings. */
+# pragma warning (disable:4305) /* VC++ 5.0 version of above warning. */
+# endif
+
+/* Win32 has an annoying issue where there are multiple C run-time
+ libraries (CRTs). If the executable is linked with a different CRT
+ from the GLUT DLL, the GLUT DLL will not share the same CRT static
+ data seen by the executable. In particular, atexit callbacks registered
+ in the executable will not be called if GLUT calls its (different)
+ exit routine). GLUT is typically built with the
+ "/MD" option (the CRT with multithreading DLL support), but the Visual
+ C++ linker default is "/ML" (the single threaded CRT).
+
+ One workaround to this issue is requiring users to always link with
+ the same CRT as GLUT is compiled with. That requires users supply a
+ non-standard option. GLUT 3.7 has its own built-in workaround where
+ the executable's "exit" function pointer is covertly passed to GLUT.
+ GLUT then calls the executable's exit function pointer to ensure that
+ any "atexit" calls registered by the application are called if GLUT
+ needs to exit.
+
+ Note that the __glut*WithExit routines should NEVER be called directly.
+ To avoid the atexit workaround, #define GLUT_DISABLE_ATEXIT_HACK. */
+
+/* XXX This is from Win32's */
+# if !defined(_MSC_VER) && !defined(__cdecl)
+ /* Define __cdecl for non-Microsoft compilers. */
+# define __cdecl
+# define GLUT_DEFINED___CDECL
+# endif
+# ifndef _CRTIMP
+# ifdef _NTSDK
+ /* Definition compatible with NT SDK */
+# define _CRTIMP
+# else
+ /* Current definition */
+# ifdef _DLL
+# define _CRTIMP __declspec(dllimport)
+# else
+# define _CRTIMP
+# endif
+# endif
+# define GLUT_DEFINED__CRTIMP
+# endif
+
+/* GLUT API entry point declarations for Win32. */
+# ifdef GLUT_BUILDING_LIB
+# define GLUTAPI __declspec(dllexport)
+# else
+# ifdef _DLL
+# define GLUTAPI __declspec(dllimport)
+# else
+# define GLUTAPI extern
+# endif
+# endif
+
+/* GLUT callback calling convention for Win32. */
+# define GLUTCALLBACK __cdecl
+
+#endif /* _WIN32 */
+
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_WIN32)
+# ifndef GLUT_BUILDING_LIB
+extern _CRTIMP void __cdecl exit(int);
+# endif
+#else
+/* non-Win32 case. */
+/* Define APIENTRY and CALLBACK to nothing if we aren't on Win32. */
+# define APIENTRY
+# define GLUT_APIENTRY_DEFINED
+# define CALLBACK
+/* Define GLUTAPI and GLUTCALLBACK as below if we aren't on Win32. */
+# define GLUTAPI extern
+# define GLUTCALLBACK
+/* Prototype exit for the non-Win32 case (see above). */
+extern void exit(int);
+#endif
+
+/**
+ GLUT API revision history:
+
+ GLUT_API_VERSION is updated to reflect incompatible GLUT
+ API changes (interface changes, semantic changes, deletions,
+ or additions).
+
+ GLUT_API_VERSION=1 First public release of GLUT. 11/29/94
+
+ GLUT_API_VERSION=2 Added support for OpenGL/GLX multisampling,
+ extension. Supports new input devices like tablet, dial and button
+ box, and Spaceball. Easy to query OpenGL extensions.
+
+ GLUT_API_VERSION=3 glutMenuStatus added.
+
+ GLUT_API_VERSION=4 glutInitDisplayString, glutWarpPointer,
+ glutBitmapLength, glutStrokeLength, glutWindowStatusFunc, dynamic
+ video resize subAPI, glutPostWindowRedisplay, glutKeyboardUpFunc,
+ glutSpecialUpFunc, glutIgnoreKeyRepeat, glutSetKeyRepeat,
+ glutJoystickFunc, glutForceJoystickFunc (NOT FINALIZED!).
+**/
+#ifndef GLUT_API_VERSION /* allow this to be overriden */
+#define GLUT_API_VERSION 3
+#endif
+
+/**
+ GLUT implementation revision history:
+
+ GLUT_XLIB_IMPLEMENTATION is updated to reflect both GLUT
+ API revisions and implementation revisions (ie, bug fixes).
+
+ GLUT_XLIB_IMPLEMENTATION=1 mjk's first public release of
+ GLUT Xlib-based implementation. 11/29/94
+
+ GLUT_XLIB_IMPLEMENTATION=2 mjk's second public release of
+ GLUT Xlib-based implementation providing GLUT version 2
+ interfaces.
+
+ GLUT_XLIB_IMPLEMENTATION=3 mjk's GLUT 2.2 images. 4/17/95
+
+ GLUT_XLIB_IMPLEMENTATION=4 mjk's GLUT 2.3 images. 6/?/95
+
+ GLUT_XLIB_IMPLEMENTATION=5 mjk's GLUT 3.0 images. 10/?/95
+
+ GLUT_XLIB_IMPLEMENTATION=7 mjk's GLUT 3.1+ with glutWarpPoitner. 7/24/96
+
+ GLUT_XLIB_IMPLEMENTATION=8 mjk's GLUT 3.1+ with glutWarpPoitner
+ and video resize. 1/3/97
+
+ GLUT_XLIB_IMPLEMENTATION=9 mjk's GLUT 3.4 release with early GLUT 4 routines.
+
+ GLUT_XLIB_IMPLEMENTATION=11 Mesa 2.5's GLUT 3.6 release.
+
+ GLUT_XLIB_IMPLEMENTATION=12 mjk's GLUT 3.6 release with early GLUT 4 routines + signal handling.
+
+ GLUT_XLIB_IMPLEMENTATION=13 mjk's GLUT 3.7 beta with GameGLUT support.
+
+ GLUT_XLIB_IMPLEMENTATION=14 mjk's GLUT 3.7 beta with f90gl friend interface.
+
+ GLUT_XLIB_IMPLEMENTATION=15 mjk's GLUT 3.7 beta sync'ed with Mesa
+**/
+#ifndef GLUT_XLIB_IMPLEMENTATION /* Allow this to be overriden. */
+#define GLUT_XLIB_IMPLEMENTATION 15
+#endif
+
+/* Display mode bit masks. */
+#define GLUT_RGB 0
+#define GLUT_RGBA GLUT_RGB
+#define GLUT_INDEX 1
+#define GLUT_SINGLE 0
+#define GLUT_DOUBLE 2
+#define GLUT_ACCUM 4
+#define GLUT_ALPHA 8
+#define GLUT_DEPTH 16
+#define GLUT_STENCIL 32
+#if (GLUT_API_VERSION >= 2)
+#define GLUT_MULTISAMPLE 128
+#define GLUT_STEREO 256
+#endif
+#if (GLUT_API_VERSION >= 3)
+#define GLUT_LUMINANCE 512
+#endif
+
+/* Mouse buttons. */
+#define GLUT_LEFT_BUTTON 0
+#define GLUT_MIDDLE_BUTTON 1
+#define GLUT_RIGHT_BUTTON 2
+
+/* Mouse button state. */
+#define GLUT_DOWN 0
+#define GLUT_UP 1
+
+#if (GLUT_API_VERSION >= 2)
+/* function keys */
+#define GLUT_KEY_F1 1
+#define GLUT_KEY_F2 2
+#define GLUT_KEY_F3 3
+#define GLUT_KEY_F4 4
+#define GLUT_KEY_F5 5
+#define GLUT_KEY_F6 6
+#define GLUT_KEY_F7 7
+#define GLUT_KEY_F8 8
+#define GLUT_KEY_F9 9
+#define GLUT_KEY_F10 10
+#define GLUT_KEY_F11 11
+#define GLUT_KEY_F12 12
+/* directional keys */
+#define GLUT_KEY_LEFT 100
+#define GLUT_KEY_UP 101
+#define GLUT_KEY_RIGHT 102
+#define GLUT_KEY_DOWN 103
+#define GLUT_KEY_PAGE_UP 104
+#define GLUT_KEY_PAGE_DOWN 105
+#define GLUT_KEY_HOME 106
+#define GLUT_KEY_END 107
+#define GLUT_KEY_INSERT 108
+#endif
+
+/* Entry/exit state. */
+#define GLUT_LEFT 0
+#define GLUT_ENTERED 1
+
+/* Menu usage state. */
+#define GLUT_MENU_NOT_IN_USE 0
+#define GLUT_MENU_IN_USE 1
+
+/* Visibility state. */
+#define GLUT_NOT_VISIBLE 0
+#define GLUT_VISIBLE 1
+
+/* Window status state. */
+#define GLUT_HIDDEN 0
+#define GLUT_FULLY_RETAINED 1
+#define GLUT_PARTIALLY_RETAINED 2
+#define GLUT_FULLY_COVERED 3
+
+/* Color index component selection values. */
+#define GLUT_RED 0
+#define GLUT_GREEN 1
+#define GLUT_BLUE 2
+
+#if defined(_WIN32)
+/* Stroke font constants (use these in GLUT program). */
+#define GLUT_STROKE_ROMAN ((void*)0)
+#define GLUT_STROKE_MONO_ROMAN ((void*)1)
+
+/* Bitmap font constants (use these in GLUT program). */
+#define GLUT_BITMAP_9_BY_15 ((void*)2)
+#define GLUT_BITMAP_8_BY_13 ((void*)3)
+#define GLUT_BITMAP_TIMES_ROMAN_10 ((void*)4)
+#define GLUT_BITMAP_TIMES_ROMAN_24 ((void*)5)
+#if (GLUT_API_VERSION >= 3)
+#define GLUT_BITMAP_HELVETICA_10 ((void*)6)
+#define GLUT_BITMAP_HELVETICA_12 ((void*)7)
+#define GLUT_BITMAP_HELVETICA_18 ((void*)8)
+#endif
+#else
+/* Stroke font opaque addresses (use constants instead in source code). */
+GLUTAPI void *glutStrokeRoman;
+GLUTAPI void *glutStrokeMonoRoman;
+
+/* Stroke font constants (use these in GLUT program). */
+#define GLUT_STROKE_ROMAN (&glutStrokeRoman)
+#define GLUT_STROKE_MONO_ROMAN (&glutStrokeMonoRoman)
+
+/* Bitmap font opaque addresses (use constants instead in source code). */
+GLUTAPI void *glutBitmap9By15;
+GLUTAPI void *glutBitmap8By13;
+GLUTAPI void *glutBitmapTimesRoman10;
+GLUTAPI void *glutBitmapTimesRoman24;
+GLUTAPI void *glutBitmapHelvetica10;
+GLUTAPI void *glutBitmapHelvetica12;
+GLUTAPI void *glutBitmapHelvetica18;
+
+/* Bitmap font constants (use these in GLUT program). */
+#define GLUT_BITMAP_9_BY_15 (&glutBitmap9By15)
+#define GLUT_BITMAP_8_BY_13 (&glutBitmap8By13)
+#define GLUT_BITMAP_TIMES_ROMAN_10 (&glutBitmapTimesRoman10)
+#define GLUT_BITMAP_TIMES_ROMAN_24 (&glutBitmapTimesRoman24)
+#if (GLUT_API_VERSION >= 3)
+#define GLUT_BITMAP_HELVETICA_10 (&glutBitmapHelvetica10)
+#define GLUT_BITMAP_HELVETICA_12 (&glutBitmapHelvetica12)
+#define GLUT_BITMAP_HELVETICA_18 (&glutBitmapHelvetica18)
+#endif
+#endif
+
+/* glutGet parameters. */
+#define GLUT_WINDOW_X ((GLenum) 100)
+#define GLUT_WINDOW_Y ((GLenum) 101)
+#define GLUT_WINDOW_WIDTH ((GLenum) 102)
+#define GLUT_WINDOW_HEIGHT ((GLenum) 103)
+#define GLUT_WINDOW_BUFFER_SIZE ((GLenum) 104)
+#define GLUT_WINDOW_STENCIL_SIZE ((GLenum) 105)
+#define GLUT_WINDOW_DEPTH_SIZE ((GLenum) 106)
+#define GLUT_WINDOW_RED_SIZE ((GLenum) 107)
+#define GLUT_WINDOW_GREEN_SIZE ((GLenum) 108)
+#define GLUT_WINDOW_BLUE_SIZE ((GLenum) 109)
+#define GLUT_WINDOW_ALPHA_SIZE ((GLenum) 110)
+#define GLUT_WINDOW_ACCUM_RED_SIZE ((GLenum) 111)
+#define GLUT_WINDOW_ACCUM_GREEN_SIZE ((GLenum) 112)
+#define GLUT_WINDOW_ACCUM_BLUE_SIZE ((GLenum) 113)
+#define GLUT_WINDOW_ACCUM_ALPHA_SIZE ((GLenum) 114)
+#define GLUT_WINDOW_DOUBLEBUFFER ((GLenum) 115)
+#define GLUT_WINDOW_RGBA ((GLenum) 116)
+#define GLUT_WINDOW_PARENT ((GLenum) 117)
+#define GLUT_WINDOW_NUM_CHILDREN ((GLenum) 118)
+#define GLUT_WINDOW_COLORMAP_SIZE ((GLenum) 119)
+#if (GLUT_API_VERSION >= 2)
+#define GLUT_WINDOW_NUM_SAMPLES ((GLenum) 120)
+#define GLUT_WINDOW_STEREO ((GLenum) 121)
+#endif
+#if (GLUT_API_VERSION >= 3)
+#define GLUT_WINDOW_CURSOR ((GLenum) 122)
+#endif
+#define GLUT_SCREEN_WIDTH ((GLenum) 200)
+#define GLUT_SCREEN_HEIGHT ((GLenum) 201)
+#define GLUT_SCREEN_WIDTH_MM ((GLenum) 202)
+#define GLUT_SCREEN_HEIGHT_MM ((GLenum) 203)
+#define GLUT_MENU_NUM_ITEMS ((GLenum) 300)
+#define GLUT_DISPLAY_MODE_POSSIBLE ((GLenum) 400)
+#define GLUT_INIT_WINDOW_X ((GLenum) 500)
+#define GLUT_INIT_WINDOW_Y ((GLenum) 501)
+#define GLUT_INIT_WINDOW_WIDTH ((GLenum) 502)
+#define GLUT_INIT_WINDOW_HEIGHT ((GLenum) 503)
+#define GLUT_INIT_DISPLAY_MODE ((GLenum) 504)
+#if (GLUT_API_VERSION >= 2)
+#define GLUT_ELAPSED_TIME ((GLenum) 700)
+#endif
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13)
+#define GLUT_WINDOW_FORMAT_ID ((GLenum) 123)
+#endif
+
+#if (GLUT_API_VERSION >= 2)
+/* glutDeviceGet parameters. */
+#define GLUT_HAS_KEYBOARD ((GLenum) 600)
+#define GLUT_HAS_MOUSE ((GLenum) 601)
+#define GLUT_HAS_SPACEBALL ((GLenum) 602)
+#define GLUT_HAS_DIAL_AND_BUTTON_BOX ((GLenum) 603)
+#define GLUT_HAS_TABLET ((GLenum) 604)
+#define GLUT_NUM_MOUSE_BUTTONS ((GLenum) 605)
+#define GLUT_NUM_SPACEBALL_BUTTONS ((GLenum) 606)
+#define GLUT_NUM_BUTTON_BOX_BUTTONS ((GLenum) 607)
+#define GLUT_NUM_DIALS ((GLenum) 608)
+#define GLUT_NUM_TABLET_BUTTONS ((GLenum) 609)
+#endif
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13)
+#define GLUT_DEVICE_IGNORE_KEY_REPEAT ((GLenum) 610)
+#define GLUT_DEVICE_KEY_REPEAT ((GLenum) 611)
+#define GLUT_HAS_JOYSTICK ((GLenum) 612)
+#define GLUT_OWNS_JOYSTICK ((GLenum) 613)
+#define GLUT_JOYSTICK_BUTTONS ((GLenum) 614)
+#define GLUT_JOYSTICK_AXES ((GLenum) 615)
+#define GLUT_JOYSTICK_POLL_RATE ((GLenum) 616)
+#endif
+
+#if (GLUT_API_VERSION >= 3)
+/* glutLayerGet parameters. */
+#define GLUT_OVERLAY_POSSIBLE ((GLenum) 800)
+#define GLUT_LAYER_IN_USE ((GLenum) 801)
+#define GLUT_HAS_OVERLAY ((GLenum) 802)
+#define GLUT_TRANSPARENT_INDEX ((GLenum) 803)
+#define GLUT_NORMAL_DAMAGED ((GLenum) 804)
+#define GLUT_OVERLAY_DAMAGED ((GLenum) 805)
+
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
+/* glutVideoResizeGet parameters. */
+#define GLUT_VIDEO_RESIZE_POSSIBLE ((GLenum) 900)
+#define GLUT_VIDEO_RESIZE_IN_USE ((GLenum) 901)
+#define GLUT_VIDEO_RESIZE_X_DELTA ((GLenum) 902)
+#define GLUT_VIDEO_RESIZE_Y_DELTA ((GLenum) 903)
+#define GLUT_VIDEO_RESIZE_WIDTH_DELTA ((GLenum) 904)
+#define GLUT_VIDEO_RESIZE_HEIGHT_DELTA ((GLenum) 905)
+#define GLUT_VIDEO_RESIZE_X ((GLenum) 906)
+#define GLUT_VIDEO_RESIZE_Y ((GLenum) 907)
+#define GLUT_VIDEO_RESIZE_WIDTH ((GLenum) 908)
+#define GLUT_VIDEO_RESIZE_HEIGHT ((GLenum) 909)
+#endif
+
+/* glutUseLayer parameters. */
+#define GLUT_NORMAL ((GLenum) 0)
+#define GLUT_OVERLAY ((GLenum) 1)
+
+/* glutGetModifiers return mask. */
+#define GLUT_ACTIVE_SHIFT 1
+#define GLUT_ACTIVE_CTRL 2
+#define GLUT_ACTIVE_ALT 4
+
+/* glutSetCursor parameters. */
+/* Basic arrows. */
+#define GLUT_CURSOR_RIGHT_ARROW 0
+#define GLUT_CURSOR_LEFT_ARROW 1
+/* Symbolic cursor shapes. */
+#define GLUT_CURSOR_INFO 2
+#define GLUT_CURSOR_DESTROY 3
+#define GLUT_CURSOR_HELP 4
+#define GLUT_CURSOR_CYCLE 5
+#define GLUT_CURSOR_SPRAY 6
+#define GLUT_CURSOR_WAIT 7
+#define GLUT_CURSOR_TEXT 8
+#define GLUT_CURSOR_CROSSHAIR 9
+/* Directional cursors. */
+#define GLUT_CURSOR_UP_DOWN 10
+#define GLUT_CURSOR_LEFT_RIGHT 11
+/* Sizing cursors. */
+#define GLUT_CURSOR_TOP_SIDE 12
+#define GLUT_CURSOR_BOTTOM_SIDE 13
+#define GLUT_CURSOR_LEFT_SIDE 14
+#define GLUT_CURSOR_RIGHT_SIDE 15
+#define GLUT_CURSOR_TOP_LEFT_CORNER 16
+#define GLUT_CURSOR_TOP_RIGHT_CORNER 17
+#define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 18
+#define GLUT_CURSOR_BOTTOM_LEFT_CORNER 19
+/* Inherit from parent window. */
+#define GLUT_CURSOR_INHERIT 100
+/* Blank cursor. */
+#define GLUT_CURSOR_NONE 101
+/* Fullscreen crosshair (if available). */
+#define GLUT_CURSOR_FULL_CROSSHAIR 102
+#endif
+
+/* GLUT initialization sub-API. */
+GLUTAPI void APIENTRY glutInit(int *argcp, char **argv);
+#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK)
+GLUTAPI void APIENTRY __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int));
+#ifndef GLUT_BUILDING_LIB
+static void APIENTRY glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); }
+#define glutInit glutInit_ATEXIT_HACK
+#endif
+#endif
+GLUTAPI void APIENTRY glutInitDisplayMode(unsigned int mode);
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
+GLUTAPI void APIENTRY glutInitDisplayString(const char *string);
+#endif
+GLUTAPI void APIENTRY glutInitWindowPosition(int x, int y);
+GLUTAPI void APIENTRY glutInitWindowSize(int width, int height);
+GLUTAPI void APIENTRY glutMainLoop(void);
+
+/* GLUT window sub-API. */
+GLUTAPI int APIENTRY glutCreateWindow(const char *title);
+#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK)
+GLUTAPI int APIENTRY __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int));
+#ifndef GLUT_BUILDING_LIB
+static int APIENTRY glutCreateWindow_ATEXIT_HACK(const char *title) { return __glutCreateWindowWithExit(title, exit); }
+#define glutCreateWindow glutCreateWindow_ATEXIT_HACK
+#endif
+#endif
+GLUTAPI int APIENTRY glutCreateSubWindow(int win, int x, int y, int width, int height);
+GLUTAPI void APIENTRY glutDestroyWindow(int win);
+GLUTAPI void APIENTRY glutPostRedisplay(void);
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 11)
+GLUTAPI void APIENTRY glutPostWindowRedisplay(int win);
+#endif
+GLUTAPI void APIENTRY glutSwapBuffers(void);
+GLUTAPI int APIENTRY glutGetWindow(void);
+GLUTAPI void APIENTRY glutSetWindow(int win);
+GLUTAPI void APIENTRY glutSetWindowTitle(const char *title);
+GLUTAPI void APIENTRY glutSetIconTitle(const char *title);
+GLUTAPI void APIENTRY glutPositionWindow(int x, int y);
+GLUTAPI void APIENTRY glutReshapeWindow(int width, int height);
+GLUTAPI void APIENTRY glutPopWindow(void);
+GLUTAPI void APIENTRY glutPushWindow(void);
+GLUTAPI void APIENTRY glutIconifyWindow(void);
+GLUTAPI void APIENTRY glutShowWindow(void);
+GLUTAPI void APIENTRY glutHideWindow(void);
+#if (GLUT_API_VERSION >= 3)
+GLUTAPI void APIENTRY glutFullScreen(void);
+GLUTAPI void APIENTRY glutSetCursor(int cursor);
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
+GLUTAPI void APIENTRY glutWarpPointer(int x, int y);
+#endif
+
+/* GLUT overlay sub-API. */
+GLUTAPI void APIENTRY glutEstablishOverlay(void);
+GLUTAPI void APIENTRY glutRemoveOverlay(void);
+GLUTAPI void APIENTRY glutUseLayer(GLenum layer);
+GLUTAPI void APIENTRY glutPostOverlayRedisplay(void);
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 11)
+GLUTAPI void APIENTRY glutPostWindowOverlayRedisplay(int win);
+#endif
+GLUTAPI void APIENTRY glutShowOverlay(void);
+GLUTAPI void APIENTRY glutHideOverlay(void);
+#endif
+
+/* GLUT menu sub-API. */
+GLUTAPI int APIENTRY glutCreateMenu(void (GLUTCALLBACK *func)(int));
+#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK)
+GLUTAPI int APIENTRY __glutCreateMenuWithExit(void (GLUTCALLBACK *func)(int), void (__cdecl *exitfunc)(int));
+#ifndef GLUT_BUILDING_LIB
+static int APIENTRY glutCreateMenu_ATEXIT_HACK(void (GLUTCALLBACK *func)(int)) { return __glutCreateMenuWithExit(func, exit); }
+#define glutCreateMenu glutCreateMenu_ATEXIT_HACK
+#endif
+#endif
+GLUTAPI void APIENTRY glutDestroyMenu(int menu);
+GLUTAPI int APIENTRY glutGetMenu(void);
+GLUTAPI void APIENTRY glutSetMenu(int menu);
+GLUTAPI void APIENTRY glutAddMenuEntry(const char *label, int value);
+GLUTAPI void APIENTRY glutAddSubMenu(const char *label, int submenu);
+GLUTAPI void APIENTRY glutChangeToMenuEntry(int item, const char *label, int value);
+GLUTAPI void APIENTRY glutChangeToSubMenu(int item, const char *label, int submenu);
+GLUTAPI void APIENTRY glutRemoveMenuItem(int item);
+GLUTAPI void APIENTRY glutAttachMenu(int button);
+GLUTAPI void APIENTRY glutDetachMenu(int button);
+
+/* GLUT window callback sub-API. */
+GLUTAPI void APIENTRY glutDisplayFunc(void (GLUTCALLBACK *func)(void));
+GLUTAPI void APIENTRY glutReshapeFunc(void (GLUTCALLBACK *func)(int width, int height));
+GLUTAPI void APIENTRY glutKeyboardFunc(void (GLUTCALLBACK *func)(unsigned char key, int x, int y));
+GLUTAPI void APIENTRY glutMouseFunc(void (GLUTCALLBACK *func)(int button, int state, int x, int y));
+GLUTAPI void APIENTRY glutMotionFunc(void (GLUTCALLBACK *func)(int x, int y));
+GLUTAPI void APIENTRY glutPassiveMotionFunc(void (GLUTCALLBACK *func)(int x, int y));
+GLUTAPI void APIENTRY glutEntryFunc(void (GLUTCALLBACK *func)(int state));
+GLUTAPI void APIENTRY glutVisibilityFunc(void (GLUTCALLBACK *func)(int state));
+GLUTAPI void APIENTRY glutIdleFunc(void (GLUTCALLBACK *func)(void));
+GLUTAPI void APIENTRY glutTimerFunc(unsigned int millis, void (GLUTCALLBACK *func)(int value), int value);
+GLUTAPI void APIENTRY glutMenuStateFunc(void (GLUTCALLBACK *func)(int state));
+#if (GLUT_API_VERSION >= 2)
+GLUTAPI void APIENTRY glutSpecialFunc(void (GLUTCALLBACK *func)(int key, int x, int y));
+GLUTAPI void APIENTRY glutSpaceballMotionFunc(void (GLUTCALLBACK *func)(int x, int y, int z));
+GLUTAPI void APIENTRY glutSpaceballRotateFunc(void (GLUTCALLBACK *func)(int x, int y, int z));
+GLUTAPI void APIENTRY glutSpaceballButtonFunc(void (GLUTCALLBACK *func)(int button, int state));
+GLUTAPI void APIENTRY glutButtonBoxFunc(void (GLUTCALLBACK *func)(int button, int state));
+GLUTAPI void APIENTRY glutDialsFunc(void (GLUTCALLBACK *func)(int dial, int value));
+GLUTAPI void APIENTRY glutTabletMotionFunc(void (GLUTCALLBACK *func)(int x, int y));
+GLUTAPI void APIENTRY glutTabletButtonFunc(void (GLUTCALLBACK *func)(int button, int state, int x, int y));
+#if (GLUT_API_VERSION >= 3)
+GLUTAPI void APIENTRY glutMenuStatusFunc(void (GLUTCALLBACK *func)(int status, int x, int y));
+GLUTAPI void APIENTRY glutOverlayDisplayFunc(void (GLUTCALLBACK *func)(void));
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
+GLUTAPI void APIENTRY glutWindowStatusFunc(void (GLUTCALLBACK *func)(int state));
+#endif
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13)
+GLUTAPI void APIENTRY glutKeyboardUpFunc(void (GLUTCALLBACK *func)(unsigned char key, int x, int y));
+GLUTAPI void APIENTRY glutSpecialUpFunc(void (GLUTCALLBACK *func)(int key, int x, int y));
+GLUTAPI void APIENTRY glutJoystickFunc(void (GLUTCALLBACK *func)(unsigned int buttonMask, int x, int y, int z), int pollInterval);
+#endif
+#endif
+#endif
+
+/* GLUT color index sub-API. */
+GLUTAPI void APIENTRY glutSetColor(int, GLfloat red, GLfloat green, GLfloat blue);
+GLUTAPI GLfloat APIENTRY glutGetColor(int ndx, int component);
+GLUTAPI void APIENTRY glutCopyColormap(int win);
+
+/* GLUT state retrieval sub-API. */
+GLUTAPI int APIENTRY glutGet(GLenum type);
+GLUTAPI int APIENTRY glutDeviceGet(GLenum type);
+#if (GLUT_API_VERSION >= 2)
+/* GLUT extension support sub-API */
+GLUTAPI int APIENTRY glutExtensionSupported(const char *name);
+#endif
+#if (GLUT_API_VERSION >= 3)
+GLUTAPI int APIENTRY glutGetModifiers(void);
+GLUTAPI int APIENTRY glutLayerGet(GLenum type);
+#endif
+
+/* GLUT font sub-API */
+GLUTAPI void APIENTRY glutBitmapCharacter(void *font, int character);
+GLUTAPI int APIENTRY glutBitmapWidth(void *font, int character);
+GLUTAPI void APIENTRY glutStrokeCharacter(void *font, int character);
+GLUTAPI int APIENTRY glutStrokeWidth(void *font, int character);
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
+GLUTAPI int APIENTRY glutBitmapLength(void *font, const unsigned char *string);
+GLUTAPI int APIENTRY glutStrokeLength(void *font, const unsigned char *string);
+#endif
+
+/* GLUT pre-built models sub-API */
+GLUTAPI void APIENTRY glutWireSphere(GLdouble radius, GLint slices, GLint stacks);
+GLUTAPI void APIENTRY glutSolidSphere(GLdouble radius, GLint slices, GLint stacks);
+GLUTAPI void APIENTRY glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint stacks);
+GLUTAPI void APIENTRY glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks);
+GLUTAPI void APIENTRY glutWireCube(GLdouble size);
+GLUTAPI void APIENTRY glutSolidCube(GLdouble size);
+GLUTAPI void APIENTRY glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings);
+GLUTAPI void APIENTRY glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings);
+GLUTAPI void APIENTRY glutWireDodecahedron(void);
+GLUTAPI void APIENTRY glutSolidDodecahedron(void);
+GLUTAPI void APIENTRY glutWireTeapot(GLdouble size);
+GLUTAPI void APIENTRY glutSolidTeapot(GLdouble size);
+GLUTAPI void APIENTRY glutWireOctahedron(void);
+GLUTAPI void APIENTRY glutSolidOctahedron(void);
+GLUTAPI void APIENTRY glutWireTetrahedron(void);
+GLUTAPI void APIENTRY glutSolidTetrahedron(void);
+GLUTAPI void APIENTRY glutWireIcosahedron(void);
+GLUTAPI void APIENTRY glutSolidIcosahedron(void);
+
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
+/* GLUT video resize sub-API. */
+GLUTAPI int APIENTRY glutVideoResizeGet(GLenum param);
+GLUTAPI void APIENTRY glutSetupVideoResizing(void);
+GLUTAPI void APIENTRY glutStopVideoResizing(void);
+GLUTAPI void APIENTRY glutVideoResize(int x, int y, int width, int height);
+GLUTAPI void APIENTRY glutVideoPan(int x, int y, int width, int height);
+
+/* GLUT debugging sub-API. */
+GLUTAPI void APIENTRY glutReportErrors(void);
+#endif
+
+#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13)
+/* GLUT device control sub-API. */
+/* glutSetKeyRepeat modes. */
+#define GLUT_KEY_REPEAT_OFF 0
+#define GLUT_KEY_REPEAT_ON 1
+#define GLUT_KEY_REPEAT_DEFAULT 2
+
+/* Joystick button masks. */
+#define GLUT_JOYSTICK_BUTTON_A 1
+#define GLUT_JOYSTICK_BUTTON_B 2
+#define GLUT_JOYSTICK_BUTTON_C 4
+#define GLUT_JOYSTICK_BUTTON_D 8
+
+GLUTAPI void APIENTRY glutIgnoreKeyRepeat(int ignore);
+GLUTAPI void APIENTRY glutSetKeyRepeat(int repeatMode);
+GLUTAPI void APIENTRY glutForceJoystickFunc(void);
+
+/* GLUT game mode sub-API. */
+/* glutGameModeGet. */
+#define GLUT_GAME_MODE_ACTIVE ((GLenum) 0)
+#define GLUT_GAME_MODE_POSSIBLE ((GLenum) 1)
+#define GLUT_GAME_MODE_WIDTH ((GLenum) 2)
+#define GLUT_GAME_MODE_HEIGHT ((GLenum) 3)
+#define GLUT_GAME_MODE_PIXEL_DEPTH ((GLenum) 4)
+#define GLUT_GAME_MODE_REFRESH_RATE ((GLenum) 5)
+#define GLUT_GAME_MODE_DISPLAY_CHANGED ((GLenum) 6)
+
+GLUTAPI void APIENTRY glutGameModeString(const char *string);
+GLUTAPI int APIENTRY glutEnterGameMode(void);
+GLUTAPI void APIENTRY glutLeaveGameMode(void);
+GLUTAPI int APIENTRY glutGameModeGet(GLenum mode);
+#endif
+
+#ifdef __cplusplus
+}
+
+#endif
+
+#ifdef GLUT_APIENTRY_DEFINED
+# undef GLUT_APIENTRY_DEFINED
+# undef APIENTRY
+#endif
+
+#ifdef GLUT_WINGDIAPI_DEFINED
+# undef GLUT_WINGDIAPI_DEFINED
+# undef WINGDIAPI
+#endif
+
+#ifdef GLUT_DEFINED___CDECL
+# undef GLUT_DEFINED___CDECL
+# undef __cdecl
+#endif
+
+#ifdef GLUT_DEFINED__CRTIMP
+# undef GLUT_DEFINED__CRTIMP
+# undef _CRTIMP
+#endif
+
+#endif /* __glut_h__ */
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/winutils/include/SDL_net.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/winutils/include/SDL_net.h Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,449 @@
+/*
+ SDL_net: An example cross-platform network library for use with SDL
+ Copyright (C) 1997-2012 Sam Lantinga
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* $Id$ */
+
+#ifndef _SDL_NET_H
+#define _SDL_NET_H
+
+#include "SDL.h"
+#include "SDL_endian.h"
+#include "SDL_version.h"
+#include "begin_code.h"
+
+
+
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
+*/
+#define SDL_NET_MAJOR_VERSION 1
+#define SDL_NET_MINOR_VERSION 2
+#define SDL_NET_PATCHLEVEL 8
+
+/* This macro can be used to fill a version structure with the compile-time
+ * version of the SDL_net library.
+ */
+#define SDL_NET_VERSION(X) \
+{ \
+ (X)->major = SDL_NET_MAJOR_VERSION; \
+ (X)->minor = SDL_NET_MINOR_VERSION; \
+ (X)->patch = SDL_NET_PATCHLEVEL; \
+}
+
+/* This function gets the version of the dynamically linked SDL_net library.
+ it should NOT be used to fill a version structure, instead you should
+ use the SDL_NET_VERSION() macro.
+ */
+extern DECLSPEC const SDL_version * SDLCALL SDLNet_Linked_Version(void);
+
+/* Initialize/Cleanup the network API
+ SDL must be initialized before calls to functions in this library,
+ because this library uses utility functions from the SDL library.
+*/
+extern DECLSPEC int SDLCALL SDLNet_Init(void);
+extern DECLSPEC void SDLCALL SDLNet_Quit(void);
+
+/***********************************************************************/
+/* IPv4 hostname resolution API */
+/***********************************************************************/
+
+typedef struct {
+ Uint32 host; /* 32-bit IPv4 host address */
+ Uint16 port; /* 16-bit protocol port */
+} IPaddress;
+
+/* Resolve a host name and port to an IP address in network form.
+ If the function succeeds, it will return 0.
+ If the host couldn't be resolved, the host portion of the returned
+ address will be INADDR_NONE, and the function will return -1.
+ If 'host' is NULL, the resolved host will be set to INADDR_ANY.
+ */
+#ifndef INADDR_ANY
+#define INADDR_ANY 0x00000000
+#endif
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xFFFFFFFF
+#endif
+#ifndef INADDR_BROADCAST
+#define INADDR_BROADCAST 0xFFFFFFFF
+#endif
+extern DECLSPEC int SDLCALL SDLNet_ResolveHost(IPaddress *address, const char *host, Uint16 port);
+
+/* Resolve an ip address to a host name in canonical form.
+ If the ip couldn't be resolved, this function returns NULL,
+ otherwise a pointer to a static buffer containing the hostname
+ is returned. Note that this function is not thread-safe.
+*/
+extern DECLSPEC const char * SDLCALL SDLNet_ResolveIP(const IPaddress *ip);
+
+/* Get the addresses of network interfaces on this system.
+ This returns the number of addresses saved in 'addresses'
+ */
+extern DECLSPEC int SDLCALL SDLNet_GetLocalAddresses(IPaddress *addresses, int maxcount);
+
+/***********************************************************************/
+/* TCP network API */
+/***********************************************************************/
+
+typedef struct _TCPsocket *TCPsocket;
+
+/* Open a TCP network socket
+ If ip.host is INADDR_NONE or INADDR_ANY, this creates a local server
+ socket on the given port, otherwise a TCP connection to the remote
+ host and port is attempted. The address passed in should already be
+ swapped to network byte order (addresses returned from
+ SDLNet_ResolveHost() are already in the correct form).
+ The newly created socket is returned, or NULL if there was an error.
+*/
+extern DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Open(IPaddress *ip);
+
+/* Accept an incoming connection on the given server socket.
+ The newly created socket is returned, or NULL if there was an error.
+*/
+extern DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Accept(TCPsocket server);
+
+/* Get the IP address of the remote system associated with the socket.
+ If the socket is a server socket, this function returns NULL.
+*/
+extern DECLSPEC IPaddress * SDLCALL SDLNet_TCP_GetPeerAddress(TCPsocket sock);
+
+/* Send 'len' bytes of 'data' over the non-server socket 'sock'
+ This function returns the actual amount of data sent. If the return value
+ is less than the amount of data sent, then either the remote connection was
+ closed, or an unknown socket error occurred.
+*/
+extern DECLSPEC int SDLCALL SDLNet_TCP_Send(TCPsocket sock, const void *data,
+ int len);
+
+/* Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
+ and store them in the buffer pointed to by 'data'.
+ This function returns the actual amount of data received. If the return
+ value is less than or equal to zero, then either the remote connection was
+ closed, or an unknown socket error occurred.
+*/
+extern DECLSPEC int SDLCALL SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen);
+
+/* Close a TCP network socket */
+extern DECLSPEC void SDLCALL SDLNet_TCP_Close(TCPsocket sock);
+
+
+/***********************************************************************/
+/* UDP network API */
+/***********************************************************************/
+
+/* The maximum channels on a a UDP socket */
+#define SDLNET_MAX_UDPCHANNELS 32
+/* The maximum addresses bound to a single UDP socket channel */
+#define SDLNET_MAX_UDPADDRESSES 4
+
+typedef struct _UDPsocket *UDPsocket;
+typedef struct {
+ int channel; /* The src/dst channel of the packet */
+ Uint8 *data; /* The packet data */
+ int len; /* The length of the packet data */
+ int maxlen; /* The size of the data buffer */
+ int status; /* packet status after sending */
+ IPaddress address; /* The source/dest address of an incoming/outgoing packet */
+} UDPpacket;
+
+/* Allocate/resize/free a single UDP packet 'size' bytes long.
+ The new packet is returned, or NULL if the function ran out of memory.
+ */
+extern DECLSPEC UDPpacket * SDLCALL SDLNet_AllocPacket(int size);
+extern DECLSPEC int SDLCALL SDLNet_ResizePacket(UDPpacket *packet, int newsize);
+extern DECLSPEC void SDLCALL SDLNet_FreePacket(UDPpacket *packet);
+
+/* Allocate/Free a UDP packet vector (array of packets) of 'howmany' packets,
+ each 'size' bytes long.
+ A pointer to the first packet in the array is returned, or NULL if the
+ function ran out of memory.
+ */
+extern DECLSPEC UDPpacket ** SDLCALL SDLNet_AllocPacketV(int howmany, int size);
+extern DECLSPEC void SDLCALL SDLNet_FreePacketV(UDPpacket **packetV);
+
+
+/* Open a UDP network socket
+ If 'port' is non-zero, the UDP socket is bound to a local port.
+ The 'port' should be given in native byte order, but is used
+ internally in network (big endian) byte order, in addresses, etc.
+ This allows other systems to send to this socket via a known port.
+*/
+extern DECLSPEC UDPsocket SDLCALL SDLNet_UDP_Open(Uint16 port);
+
+/* Set the percentage of simulated packet loss for packets sent on the socket.
+*/
+extern DECLSPEC void SDLCALL SDLNet_UDP_SetPacketLoss(UDPsocket sock, int percent);
+
+/* Bind the address 'address' to the requested channel on the UDP socket.
+ If the channel is -1, then the first unbound channel will be bound with
+ the given address as it's primary address.
+ If the channel is already bound, this new address will be added to the
+ list of valid source addresses for packets arriving on the channel.
+ If the channel is not already bound, then the address becomes the primary
+ address, to which all outbound packets on the channel are sent.
+ This function returns the channel which was bound, or -1 on error.
+*/
+extern DECLSPEC int SDLCALL SDLNet_UDP_Bind(UDPsocket sock, int channel, const IPaddress *address);
+
+/* Unbind all addresses from the given channel */
+extern DECLSPEC void SDLCALL SDLNet_UDP_Unbind(UDPsocket sock, int channel);
+
+/* Get the primary IP address of the remote system associated with the
+ socket and channel. If the channel is -1, then the primary IP port
+ of the UDP socket is returned -- this is only meaningful for sockets
+ opened with a specific port.
+ If the channel is not bound and not -1, this function returns NULL.
+ */
+extern DECLSPEC IPaddress * SDLCALL SDLNet_UDP_GetPeerAddress(UDPsocket sock, int channel);
+
+/* Send a vector of packets to the the channels specified within the packet.
+ If the channel specified in the packet is -1, the packet will be sent to
+ the address in the 'src' member of the packet.
+ Each packet will be updated with the status of the packet after it has
+ been sent, -1 if the packet send failed.
+ This function returns the number of packets sent.
+*/
+extern DECLSPEC int SDLCALL SDLNet_UDP_SendV(UDPsocket sock, UDPpacket **packets, int npackets);
+
+/* Send a single packet to the specified channel.
+ If the channel specified in the packet is -1, the packet will be sent to
+ the address in the 'src' member of the packet.
+ The packet will be updated with the status of the packet after it has
+ been sent.
+ This function returns 1 if the packet was sent, or 0 on error.
+
+ NOTE:
+ The maximum size of the packet is limited by the MTU (Maximum Transfer Unit)
+ of the transport medium. It can be as low as 250 bytes for some PPP links,
+ and as high as 1500 bytes for ethernet.
+*/
+extern DECLSPEC int SDLCALL SDLNet_UDP_Send(UDPsocket sock, int channel, UDPpacket *packet);
+
+/* Receive a vector of pending packets from the UDP socket.
+ The returned packets contain the source address and the channel they arrived
+ on. If they did not arrive on a bound channel, the the channel will be set
+ to -1.
+ The channels are checked in highest to lowest order, so if an address is
+ bound to multiple channels, the highest channel with the source address
+ bound will be returned.
+ This function returns the number of packets read from the network, or -1
+ on error. This function does not block, so can return 0 packets pending.
+*/
+extern DECLSPEC int SDLCALL SDLNet_UDP_RecvV(UDPsocket sock, UDPpacket **packets);
+
+/* Receive a single packet from the UDP socket.
+ The returned packet contains the source address and the channel it arrived
+ on. If it did not arrive on a bound channel, the the channel will be set
+ to -1.
+ The channels are checked in highest to lowest order, so if an address is
+ bound to multiple channels, the highest channel with the source address
+ bound will be returned.
+ This function returns the number of packets read from the network, or -1
+ on error. This function does not block, so can return 0 packets pending.
+*/
+extern DECLSPEC int SDLCALL SDLNet_UDP_Recv(UDPsocket sock, UDPpacket *packet);
+
+/* Close a UDP network socket */
+extern DECLSPEC void SDLCALL SDLNet_UDP_Close(UDPsocket sock);
+
+
+/***********************************************************************/
+/* Hooks for checking sockets for available data */
+/***********************************************************************/
+
+typedef struct _SDLNet_SocketSet *SDLNet_SocketSet;
+
+/* Any network socket can be safely cast to this socket type */
+typedef struct _SDLNet_GenericSocket {
+ int ready;
+} *SDLNet_GenericSocket;
+
+/* Allocate a socket set for use with SDLNet_CheckSockets()
+ This returns a socket set for up to 'maxsockets' sockets, or NULL if
+ the function ran out of memory.
+ */
+extern DECLSPEC SDLNet_SocketSet SDLCALL SDLNet_AllocSocketSet(int maxsockets);
+
+/* Add a socket to a set of sockets to be checked for available data */
+#define SDLNet_TCP_AddSocket(set, sock) \
+ SDLNet_AddSocket(set, SDL_reinterpret_cast(SDLNet_GenericSocket, sock))
+#define SDLNet_UDP_AddSocket(set, sock) \
+ SDLNet_AddSocket(set, SDL_reinterpret_cast(SDLNet_GenericSocket, sock))
+extern DECLSPEC int SDLCALL SDLNet_AddSocket(SDLNet_SocketSet set, SDLNet_GenericSocket sock);
+
+/* Remove a socket from a set of sockets to be checked for available data */
+#define SDLNet_TCP_DelSocket(set, sock) \
+ SDLNet_DelSocket(set, SDL_reinterpret_cast(SDLNet_GenericSocket, sock))
+#define SDLNet_UDP_DelSocket(set, sock) \
+ SDLNet_DelSocket(set, SDL_reinterpret_cast(SDLNet_GenericSocket, sock))
+extern DECLSPEC int SDLCALL SDLNet_DelSocket(SDLNet_SocketSet set, SDLNet_GenericSocket sock);
+
+/* This function checks to see if data is available for reading on the
+ given set of sockets. If 'timeout' is 0, it performs a quick poll,
+ otherwise the function returns when either data is available for
+ reading, or the timeout in milliseconds has elapsed, which ever occurs
+ first. This function returns the number of sockets ready for reading,
+ or -1 if there was an error with the select() system call.
+*/
+extern DECLSPEC int SDLCALL SDLNet_CheckSockets(SDLNet_SocketSet set, Uint32 timeout);
+
+/* After calling SDLNet_CheckSockets(), you can use this function on a
+ socket that was in the socket set, to find out if data is available
+ for reading.
+*/
+#define SDLNet_SocketReady(sock) \
+ ((sock != NULL) && SDL_reinterpret_cast(SDLNet_GenericSocket, sock)->ready)
+
+/* Free a set of sockets allocated by SDL_NetAllocSocketSet() */
+extern DECLSPEC void SDLCALL SDLNet_FreeSocketSet(SDLNet_SocketSet set);
+
+
+/***********************************************************************/
+/* Platform-independent data conversion functions */
+/***********************************************************************/
+
+/* Write a 16/32 bit value to network packet buffer */
+extern DECLSPEC void SDLCALL SDLNet_Write16(Uint16 value, void *area);
+extern DECLSPEC void SDLCALL SDLNet_Write32(Uint32 value, void *area);
+
+/* Read a 16/32 bit value from network packet buffer */
+extern DECLSPEC Uint16 SDLCALL SDLNet_Read16(void *area);
+extern DECLSPEC Uint32 SDLCALL SDLNet_Read32(void *area);
+
+/***********************************************************************/
+/* Error reporting functions */
+/***********************************************************************/
+
+/* We'll use SDL's functions for error reporting */
+#define SDLNet_SetError SDL_SetError
+#define SDLNet_GetError SDL_GetError
+
+/* I'm eventually going to try to disentangle SDL_net from SDL, thus making
+ SDL_net an independent X-platform networking toolkit. Not today though....
+
+extern no_parse_DECLSPEC void SDLCALL SDLNet_SetError(const char *fmt, ...);
+extern no_parse_DECLSPEC char * SDLCALL SDLNet_GetError(void);
+*/
+
+
+/* Inline macro functions to read/write network data */
+
+/* Warning, some systems have data access alignment restrictions */
+#if defined(sparc) || defined(mips)
+#define SDL_DATA_ALIGNED 1
+#endif
+#ifndef SDL_DATA_ALIGNED
+#define SDL_DATA_ALIGNED 0
+#endif
+
+/* Write a 16 bit value to network packet buffer */
+#if !SDL_DATA_ALIGNED
+#define SDLNet_Write16(value, areap) \
+ (*SDL_reinterpret_cast(Uint16 *, areap) = SDL_SwapBE16(value))
+#else
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+#define SDLNet_Write16(value, areap) \
+do \
+{ \
+ Uint8 *area = SDL_reinterpret_cast(Uint8 *, areap); \
+ area[0] = (value >> 8) & 0xFF; \
+ area[1] = value & 0xFF; \
+} while ( 0 )
+#else
+#define SDLNet_Write16(value, areap) \
+do \
+{ \
+ Uint8 *area = SDL_reinterpret_cast(Uint8 *, areap); \
+ area[1] = (value >> 8) & 0xFF; \
+ area[0] = value & 0xFF; \
+} while ( 0 )
+#endif
+#endif /* !SDL_DATA_ALIGNED */
+
+/* Write a 32 bit value to network packet buffer */
+#if !SDL_DATA_ALIGNED
+#define SDLNet_Write32(value, areap) \
+ *SDL_reinterpret_cast(Uint32 *, areap) = SDL_SwapBE32(value);
+#else
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+#define SDLNet_Write32(value, areap) \
+do \
+{ \
+ Uint8 *area = SDL_reinterpret_cast(Uint8 *, areap); \
+ area[0] = (value >> 24) & 0xFF; \
+ area[1] = (value >> 16) & 0xFF; \
+ area[2] = (value >> 8) & 0xFF; \
+ area[3] = value & 0xFF; \
+} while ( 0 )
+#else
+#define SDLNet_Write32(value, areap) \
+do \
+{ \
+ Uint8 *area = SDL_reinterpret_cast(Uint8 *, areap); \
+ area[3] = (value >> 24) & 0xFF; \
+ area[2] = (value >> 16) & 0xFF; \
+ area[1] = (value >> 8) & 0xFF; \
+ area[0] = value & 0xFF; \
+} while ( 0 )
+#endif
+#endif /* !SDL_DATA_ALIGNED */
+
+/* Read a 16 bit value from network packet buffer */
+#if !SDL_DATA_ALIGNED
+#define SDLNet_Read16(areap) \
+ (SDL_SwapBE16(*SDL_reinterpret_cast(Uint16 *, areap)))
+#else
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+#define SDLNet_Read16(areap) \
+ (((SDL_reinterpret_cast(Uint8 *, areap))[0] << 8) | (SDL_reinterpret_cast(Uint8 *, areap))[1] << 0)
+#else
+#define SDLNet_Read16(areap) \
+ (((SDL_reinterpret_cast(Uint8 *, areap))[1] << 8) | (SDL_reinterpret_cast(Uint8 *, areap))[0] << 0)
+#endif
+#endif /* !SDL_DATA_ALIGNED */
+
+/* Read a 32 bit value from network packet buffer */
+#if !SDL_DATA_ALIGNED
+#define SDLNet_Read32(areap) \
+ (SDL_SwapBE32(*SDL_reinterpret_cast(Uint32 *, areap)))
+#else
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+#define SDLNet_Read32(areap) \
+ (((SDL_reinterpret_cast(Uint8 *, areap))[0] << 24) | ((SDL_reinterpret_cast(Uint8 *, areap))[1] << 16) | \
+ ((SDL_reinterpret_cast(Uint8 *, areap))[2] << 8) | (SDL_reinterpret_cast(Uint8 *, areap))[3] << 0)
+#else
+#define SDLNet_Read32(areap) \
+ (((SDL_reinterpret_cast(Uint8 *, areap))[3] << 24) | ((SDL_reinterpret_cast(Uint8 *, areap))[2] << 16) | \
+ ((SDL_reinterpret_cast(Uint8 *, areap))[1] << 8) | (SDL_reinterpret_cast(Uint8 *, areap))[0] << 0)
+#endif
+#endif /* !SDL_DATA_ALIGNED */
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_NET_H */
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/winutils/lib/libSDL.la
--- a/misc/winutils/lib/libSDL.la Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-# libSDL.la - a libtool library file
-# Generated by ltmain.sh (GNU libtool) 2.2.6
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# The name that we can dlopen(3).
-dlname='../bin/SDL.dll'
-
-# Names of this library.
-library_names='libSDL.dll.a'
-
-# The name of the static archive.
-old_library='libSDL.a'
-
-# Linker flags that can not go in dependency_libs.
-inherited_linker_flags=''
-
-# Libraries that this one depends upon.
-dependency_libs=' -luser32 -lgdi32 -lwinmm -ldxguid'
-
-# Names of additional weak libraries provided by this library
-weak_library_names=''
-
-# Version information for libSDL.
-current=11
-age=11
-revision=3
-
-# Is this an already installed library?
-installed=yes
-
-# Should we warn about portability when linking against -modules?
-shouldnotlink=no
-
-# Files to dlopen/dlpreopen
-dlopen=''
-dlpreopen=''
-
-# Directory that this library needs to be installed in:
-libdir='/usr/local/lib'
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/winutils/lib/libSDL_net.dll.a
Binary file misc/winutils/lib/libSDL_net.dll.a has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/xfire/Xfire Game SDK.url
--- a/misc/xfire/Xfire Game SDK.url Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-[{000214A0-0000-0000-C000-000000000046}]
-Prop3=19,2
-[InternetShortcut]
-URL=http://www.xfire.com/cms/xf_game_sdk
-IDList=
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/xfire/license.txt
--- a/misc/xfire/license.txt Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-Terms and Conditions
-AGREEMENT BETWEEN USER AND XFIRE INC.
-This is a legal agreement between you and Xfire Inc. ("Xfire") with respect to your access and use of the Xfire Service, which may also include Xfire software, content and related documentation and information (collectively, the "Service"). You must accept without modification all of the terms, conditions, and notices contained in these Terms of Use in order to access and/or use the Service (collectively, the "Terms of Use" or "Agreement"). If you do not accept these Terms of Use in their entirety, you may not access or use the Service.
-
-Portions of the Service may be governed by posted guidelines, rules, or other terms and conditions. All such guidelines, rules, terms and conditions are hereby incorporated by reference into these Terms of Use. In the event of a conflict between such other guidelines, rules, terms and conditions and these Terms of Use, the Terms of Use shall control, except that the Xfire Service Privacy Policy, referenced below, supersedes any conflicting language in these Terms of Use and/or any other guidelines, rules, terms and conditions published in connection with the Service with respect to the subject matter covered by such privacy policy.
-
-MODIFICATION OF THESE TERMS OF USE; UPDATES
-Xfire may change the Terms of Use at any time and such changes shall be effective immediately. You are responsible for regularly reviewing the Terms of Use. The most recent version of the Terms of Use can be found at http://www.xfire.com/xf/terms.php. Your continued use of the Service affirms your agreement to the Terms of Use and any changes.
-
-Xfire is not obligated to provide updates or improvements to the Service. However, if Xfire, in its sole discretion, updates or improves the Service, these Terms of Use shall apply to such updates and improvements unless expressly noted otherwise.
-
-CLIENT SOFTWARE USE LIMITATION
-YOU MAY ONLY USE XFIRE CLIENT SOFTWARE OR AUTHORIZED THIRD-PARTY SOFTWARE TO ACCESS AND/OR USE THE SERVICE. You may not use any software or services in conjunction with the Xfire software or authorized third-party software which modifies or reroutes, or attempts to modify or reroute, the Service. You may not authorize any third party to access and/or use the Service on your behalf using any automated process such as a BOT, a spider or periodic caching of information stored by the Xfire Service on your behalf without a separate written agreement with Xfire. You may not use any software or hardware that reduces the number of users directly accessing or using the Service (sometimes called 'multiplexing' or 'pooling' software or hardware).
-
-You may not modify, copy, distribute, transmit, display, perform, reproduce, publish, license, create derivative works from, transfer, or sell any information, software, products or services that are part of the Service except as expressly provided in these Terms of Use.
-
-NO UNLAWFUL OR PROHIBITED USE; RESPONSIBILITY FOR YOUR ACCOUNT
-As a condition of your use of the Service, you will not use the Service for any purpose that is unlawful or prohibited by these Terms of Use. You may not use the Service in any manner that could damage, disable, overburden, or impair the Service or interfere with any other party's use and enjoyment of it. You may not attempt to gain unauthorized access to any account, computer systems or networks associated with the Service or to otherwise interfere with or disrupt any accounts, computer systems or networks connected to the Service. You may not obtain or attempt to obtain any materials or information through any means not intentionally made available or provided for through the Service. You may not use access to the Service to obtain information necessary for you to design, develop or update unauthorized software that you use or provide to others to use to access the Service. You may not charge others to use the Service either directly or indirectly without the express written agreement of Xfire.
-Subject to these Terms of Use, you may use the Service within your commercial organization, but you may not use the Service to advertise or offer to buy or sell any goods or services, or to run a business or commercial entity without the express written agreement of Xfire.
-You agree to use the Service only to send, receive, and transfer appropriate messages and material. By way of example, and not as a limitation, you agree that when using the Service, you will not:
-
-
- Use the Service in connection with surveys, contests, pyramid schemes, chain letters, junk email, spamming or any duplicative, bulk or unsolicited messages (commercial or otherwise).
-
- Defame, abuse, harass, stalk, threaten or otherwise violate the legal rights (such as rights of privacy and publicity) of others.
-
- Create a false identity for the purpose of misleading others.
-
- Publish, transfer, distribute or disseminate any inappropriate, profane, defamatory, obscene, indecent or unlawful topic, name, material or information.
-
- Transfer, stream, or otherwise make available, files or other material that contain images, photographs, software or other material protected by intellectual property laws, including, by way of example, and not as limitation, copyright or trademark laws (or by rights of privacy or publicity) unless you own or control the rights thereto or have received all necessary consents to do the same.
-
- Use any material or information, including images or photographs, which is made available through the Service in any manner that infringes any copyright, trademark, patent, trade secret, or other proprietary right of any party.
-
- Transfer, stream or otherwise make available, files or other material that contain viruses, Trojan horses, worms, time bombs, cancelbots, corrupted files, or any other similar software or programs that may damage the operation of another's computer or property of another.
-
- Download any file or other material transferred by another user of the Service that you know, or reasonably should know, cannot be legally distributed in such manner.
-
- Use, download or otherwise copy, or provide (whether or not for a fee) to a person or entity any directory of users of the Service or other user or usage information or any portion thereof.
-
- Falsify or delete any author attributions, legal or other proper notices or proprietary designations or labels of the origin or source of software or other material contained in a file that is transferred.
-
- Violate any code of conduct or other guidelines which may be applicable to the Service.
-
- Use any portion of the Service to harvest or otherwise collect information about others, including e-mail addresses.
-
-Xfire reserves the right at all times to monitor communications on the Service and disclose any information Xfire deems necessary to (i) ensure your compliance with this Agreement; (ii) satisfy any applicable law, regulation or legal process; or (iii) protect the rights, property, and interests of Xfire, its employees or the public. Xfire also reserves the right to edit, refuse to transfer or to remove any information or materials, in whole or in part, in Xfire's sole discretion.
-
-Always use caution when giving out any personally identifiable information about yourself or your children in the Service. Xfire does not control or endorse the content, messages or information exchanged by means of the Service and, therefore, Xfire specifically disclaims any liability with regard to the Service and any actions resulting from your participation in the Service.
-
-You are responsible for all activities that occur in your Service account. You agree to notify Xfire immediately of any unauthorized use of your account or breach in security known to you related to the Service.
-
-
-PRIVACY
-See the Xfire Service Privacy Statement at http://www.xfire.com/xf/privacy.php for disclosures relating to the collection and use of your information.
-
-
-INTERACTION WITH THIRD PARTY SITES AND SERVICES
-The Service may allow you to interact with third-party Web sites and Web services ("Link(s)"). The Links are not under the control of Xfire and Xfire is not responsible for the contents of any Links, including without limitation any link contained in a Link, or any changes or updates to a Link. Xfire is not responsible for any form of transmission received from any Link, nor is Xfire responsible if the Link is not working appropriately. Xfire is providing these Links to you only as a convenience, and the inclusion of any Link does not imply endorsement by Xfire of the Link or any association with its operators. You are responsible for viewing and abiding by any privacy statements and terms of use posted in connection with the Links.
-
-You are solely responsible for any dealings with third parties (including advertisers) who support the Service, including the delivery of and payment for goods and services.
-
-TERMS OF USE FOR SERVICE-ENABLED PROPERTIES
-For the terms and conditions governing your use of any Xfire or authorized third party Web site or service that enables you to use the Service other than the Service itself ("Service-Enabled Properties"), please refer to the applicable Terms of Use for such Service-Enabled Properties.
-
-SOFTWARE AND CONTENT AVAILABLE ON THE SERVICE
-All Xfire content and software (if any) that is made available to view and/or download in connection with the Service ("Software") is owned by and is the copyrighted work of Xfire and/or its suppliers and is licensed, not sold. Your use of the Software is governed by the terms of the license agreement, if any, which accompanies or is included with the Software ("License Agreement"). You may not install or use any Software that is accompanied by or includes a License Agreement unless you first agree to the License Agreement terms. For any Software not accompanied by a license agreement, Xfire hereby grants to you, the user, a non-exclusive, revocable, personal, non-transferable license to use the Software solely in connection with the Service in accordance with these Terms of Use. You may not lend, lease, rent or sublicense the Software or any aspect of the Service.
-
-You will not disassemble, decompile, or reverse engineer the Software. All Software is protected by copyright laws and international treaty provisions. Any unauthorized reproduction or redistribution of the Software is expressly prohibited by law, and may result in severe civil and criminal penalties. WITHOUT LIMITING THE FOREGOING, COPYING OR REPRODUCTION OF THE SOFTWARE TO ANY OTHER SERVER OR LOCATION FOR FURTHER REPRODUCTION OR REDISTRIBUTION IS EXPRESSLY PROHIBITED. THE SOFTWARE IS WARRANTED, IF AT ALL, ONLY ACCORDING TO THE TERMS OF THE LICENSE AGREEMENT. You acknowledge that the Software, and any accompanying documentation and/or technical information, is subject to applicable export control laws and regulations of the U.S.A. You agree not to export or re-export the Software, directly or indirectly, to any countries that are subject to U.S.A. export restrictions.
-
-Your license to use the Software with the Service terminates when you terminate your use of the Service. Your license to use the Software with the Service may also terminate if Xfire, in its sole discretion, modifies the Service to no longer support such Software.
-
-NO WARRANTIES; LIABILITY DISCLAIMER; EXCLUSIVE REMEDY
-XFIRE PROVIDES THE SERVICE AND THE SOFTWARE "AS IS," "WITH ALL FAULTS" AND "AS AVAILABLE," AND THE ENTIRE RISK AS TO SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH YOU. XFIRE, ITS AFFILIATES, ITS RESELLERS, DISTRIBUTORS, SERVICE PROVIDERS AND/OR SUPPLIERS (COLLECTIVELY, THE "XFIRE PARTIES") MAKE NO WARRANTIES. THE XFIRE PARTIES DISCLAIM ANY AND ALL WARRANTIES, EXPRESS, STATUTORY AND IMPLIED, INCLUDING WITHOUT LIMITATION (1) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, WORKMANLIKE EFFORT, ACCURACY, TITLE, QUIET ENJOYMENT, NO ENCUMBRANCES, NO LIENS AND NON-INFRINGEMENT, (2) WARRANTIES ARISING THROUGH COURSE OF DEALING OR USAGE OF TRADE, AND (3) WARRANTIES THAT ACCESS TO OR USE OF THE SERVICE WILL BE UNINTERRUPTED OR ERROR-FREE. THERE ARE NO WARRANTIES THAT EXTEND BEYOND THE FACE OF THIS AGREEMENT. XFIRE MAY CHANGE THE SERVICE OR THE FEATURES IN ANY WAY, AND AT ANY TIME AND FOR ANY REASON.
-
-IN NO EVENT SHALL ANY OF THE XFIRE PARTIES BE LIABLE FOR ANY DIRECT, INDIRECT, CONSEQUENTIAL, SPECIAL, INCIDENTAL, OR PUNITIVE DAMAGES ARISING OUT OF, BASED ON, OR RESULTING FROM THIS AGREEMENT OR YOUR USE OF THE SERVICE, INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF USE, DATA OR PROFITS, WITH THE DELAY OR INABILITY TO USE THE SERVICE, THE PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, OR FOR ANY INFORMATION, SOFTWARE, PRODUCTS, OR SERVICES OBTAINED THROUGH THE SERVICE, OR OTHERWISE ARISING OUT OF THE USE OF THE SERVICE, WHETHER BASED ON CONTRACT, TORT, NEGLIGENCE, STRICT LIABILITY OR OTHERWISE, EVEN IF XFIREOR ANY OF ITS SUPPLIERS HAS BEEN ADVISED OF THE POSSIBILITY OF DAMAGES. BECAUSE SOME STATES/JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO YOU.
-
-IF YOU ARE DISSATISFIED WITH ANY PORTION OF THE SERVICE, OR WITH ANY OF THESE TERMS OF USE, YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USING THE SERVICE.
-
-INDEMNITY
-You agree to indemnify and hold Xfire, its officers, and employees, harmless from any claim or demand, including reasonable attorneys' fees, made by any third party due to or arising out of your use of the Services, the violation of these Terms of Use by you, or the infringement by you, or other user of the Services using your computer or identity, of any intellectual property or other right of any person or entity.
-
-CUSTOMER SUPPORT
-Xfire may, but is not required to, provide you with customer support ("Support"). Unless you have entered into a separate written support agreement with Xfire with respect to the Service, Xfire may terminate any Support it provides at any time in its sole discretion.
-
-Authorized third-party software that uses the Service is not supported by Xfire and you should contact the provider of such software for support, if any.
-
-TERMINATION/ACCESS RESTRICTION
-Unless you, or a third party on your behalf, have entered into a separate written agreement with Xfire that modifies these Terms of Use, Xfire reserves the right, in its sole discretion, to terminate your access to and use of the Service or any portion thereof at any time, without notice. Also, unless you or a third party on your behalf have entered into a separate agreement with Xfire, Xfire may terminate or suspend your access to the Service for inactivity, which is defined as failing to log onto the Service for an extended period of time, as determined by Xfire.
-ELECTRONIC NOTICES
-You consent to Xfire providing you any information regarding the Service in electronic form. Xfire may provide such information to you via e-mail at the e-mail address you specified when you registered for the Service, by instant message to your account, or by access to a Xfire web site. As long as you access and use the Service, you will have the necessary software and hardware to receive such notices. If you do not consent to receive any notices electronically, you must discontinue your use of the Service.
-
-GENERAL
-If you reside in the United States, claims for enforcement, breach or violation of duties or rights under these Terms of Use are governed by the laws of the State of California, without reference to conflict of laws principles. All other claims, including, without limitation, claims under or for violation of state consumer protection laws, unfair competition laws, and in tort, are governed by the laws of your state of residence in the United States. If you reside outside of the United States, these Terms of Use are governed by the laws of the State of California, without reference to conflict of laws principles. You hereby irrevocably consent to the exclusive jurisdiction and venue of courts in San Mateo County, California, U.S.A. in all disputes arising out of or relating to the use of the Service.
-
-YOU AND XFIRE AGREE THAT ANY CAUSE OF ACTION ARISING OUT OF OR RELATED TO THE SERVICE MUST COMMENCE WITHIN ONE (1) YEAR AFTER THE CAUSE OF ACTION ACCRUES. OTHERWISE, SUCH CAUSE OF ACTION IS PERMANENTLY BARRED.
-
-Xfire may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in any Web pages that are part of the Service. Except as expressly provided in these Terms of Use, the furnishing of such Web pages to you does not give you any license to these patents, trademarks, copyrights, or other intellectual property. Any rights not expressly granted herein are reserved.
-
-June 2004
-
-
-
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/xfire/xfiregameclient.cpp
--- a/misc/xfire/xfiregameclient.cpp Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/* This file is NOT open source. See "license.txt" to read the full license provided with the Xfire SDK. */
-
-#define WIN32_LEAN_AND_MEAN
-#include
-#include
-
-#include "xfiregameclient.h"
-
-static HMODULE g_toucan_dll = NULL;
-static void HelperInit();
-static HMODULE HelperGetToucanDLL();
-
-typedef int (*XfireSetCustomGameDataAFunction)(int , const char **, const char **);
-typedef int (*XfireSetCustomGameDataWFunction)(int , const wchar_t **, const wchar_t **);
-typedef int (*XfireSetCustomGameDataUTF8Function)(int , const char **, const char **);
-
-static XfireSetCustomGameDataAFunction ptr_XfireSetCustomGameDataA = NULL;
-static XfireSetCustomGameDataWFunction ptr_XfireSetCustomGameDataW = NULL;
-static XfireSetCustomGameDataUTF8Function ptr_XfireSetCustomGameDataUTF8 = NULL;
-
-/* make sure we are going to call the ANSI version */
-#ifdef MODULEENTRY32
-#undef MODULEENTRY32
-#endif
-
-#ifdef Module32First
-#undef Module32First
-#endif
-
-#ifdef Module32Next
-#undef Module32Next
-#endif
-
-
-int XfireIsLoaded()
-{
- HelperInit();
- if (ptr_XfireSetCustomGameDataA &&
- ptr_XfireSetCustomGameDataW &&
- ptr_XfireSetCustomGameDataUTF8)
- return 1;
- return 0;
-}
-
-int XfireSetCustomGameDataA(int num_keys, const char **keys, const char **values)
-{
- HelperInit();
- if (ptr_XfireSetCustomGameDataA)
- return ptr_XfireSetCustomGameDataA(num_keys, keys, values);
- return 1;
-}
-
-int XfireSetCustomGameDataW(int num_keys, const wchar_t **keys, const wchar_t **values)
-{
- HelperInit();
- if (ptr_XfireSetCustomGameDataW)
- return ptr_XfireSetCustomGameDataW(num_keys, keys, values);
- return 1;
-}
-
-int XfireSetCustomGameDataUTF8(int num_keys, const char **keys, const char **values)
-{
- HelperInit();
- if (ptr_XfireSetCustomGameDataUTF8)
- return ptr_XfireSetCustomGameDataUTF8(num_keys, keys, values);
- return 1;
-}
-
-/* ------------------------------------------------------------------------- */
-static void HelperInit()
-{
- if (!ptr_XfireSetCustomGameDataA ||
- !ptr_XfireSetCustomGameDataW ||
- !ptr_XfireSetCustomGameDataUTF8)
- {
- HMODULE toucan_dll = HelperGetToucanDLL();
- if (toucan_dll)
- {
- ptr_XfireSetCustomGameDataA = (XfireSetCustomGameDataAFunction)::GetProcAddress(toucan_dll, "ToucanSendGameClientDataA_V1");
- ptr_XfireSetCustomGameDataW = (XfireSetCustomGameDataWFunction)::GetProcAddress(toucan_dll, "ToucanSendGameClientDataW_V1");
- ptr_XfireSetCustomGameDataUTF8 = (XfireSetCustomGameDataUTF8Function)::GetProcAddress(toucan_dll, "ToucanSendGameClientDataUTF8_V1");
- }
- }
-}
-
-
-static HMODULE HelperGetToucanDLL()
-{
- if (g_toucan_dll)
- return g_toucan_dll;
-
- /*
- ** We need to enumerate the DLLs loaded to find toucan dll.
- ** This is done because the toucan dll changes with each update.
- ** The toucan dll has the following format. "xfire_toucan_{BUILD_NUMBER}.dll"
- ** We simply try to find a dll w/ the prefix "xfire_toucan"
- */
- HANDLE snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
- if (snapshot_handle != INVALID_HANDLE_VALUE)
- {
- MODULEENTRY32 module_entry;
- module_entry.dwSize = sizeof(MODULEENTRY32);
-
- BOOL result = Module32First(snapshot_handle, &module_entry);
- char module_name[] = "xfire_toucan";
- DWORD module_name_len = sizeof(module_name)-1;
- while (result)
- {
- if (CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, module_entry.szModule, module_name_len, module_name, module_name_len) == CSTR_EQUAL)
- {
- g_toucan_dll = module_entry.hModule;
- break;
- }
- result = Module32Next(snapshot_handle, &module_entry);
- }
-
- CloseHandle(snapshot_handle);
- }
-
- return g_toucan_dll;
-}
diff -r d5d5e1698554 -r 1dedcc37bfe8 misc/xfire/xfiregameclient.h
--- a/misc/xfire/xfiregameclient.h Sun Nov 18 01:06:01 2012 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/* This file is NOT open source. See "license.txt" to read the full license provided with the Xfire SDK. */
-
-#ifndef __XFIREGAMECLIENT_H__
-#define __XFIREGAMECLIENT_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-** XfireIsLoaded()
-**
-** returns 1 if application can talk to Xfire, 0 otherwise
-*/
-int XfireIsLoaded();
-
-/*
-** XfireSetCustomGameDataA()
-**
-** ANSI version to tell xfire of custom game data
-*/
-int XfireSetCustomGameDataA(int num_keys, const char **keys, const char **values);
-
-/*
-** XfireSetCustomGameDataA()
-**
-** UNICODE version to tell xfire of custom game data
-*/
-int XfireSetCustomGameDataW(int num_keys, const wchar_t **keys, const wchar_t **values);
-
-/*
-** XfireSetCustomGameDataUTF8()
-**
-** UTF8 version to tell xfire of custom game data
-*/
-int XfireSetCustomGameDataUTF8(int num_keys, const char **keys, const char **values);
-
-#ifdef UNICODE
-#define XfireSetCustomGameData XfireSetCustomGameDataW
-#else
-#define XfireSetCustomGameData XfireSetCustomGameDataA
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __XFIREGAMECLIENT_H__ */
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/CMakeLists.txt
--- a/project_files/Android-build/CMakeLists.txt Sun Nov 18 01:06:01 2012 +0400
+++ b/project_files/Android-build/CMakeLists.txt Fri Feb 22 05:05:32 2013 +0100
@@ -18,7 +18,7 @@
find_program(ANT ant DOC "Path to the java package creator: ant")
if(NOT EXISTS ${ANT})
- MESSAGE(FATAL_ERROR "Couldn't detect the Ant build tool")
+ message(FATAL_ERROR "Couldn't detect the Ant build tool")
endif()
if(NOT ANDROID_NDK)
@@ -26,9 +26,9 @@
endif()
if(IS_DIRECTORY "${ANDROID_NDK}")
- MESSAGE(STATUS "Detected the android NDK directory at: " ${ANDROID_NDK})
+ message(STATUS "Detected the android NDK directory at: " ${ANDROID_NDK})
else ()
- MESSAGE(FATAL_ERROR "Couldn't detect the Android NDK directory")
+ message(FATAL_ERROR "Couldn't detect the Android NDK directory")
endif()
if(NOT ANDROID_NDK_TOOLCHAINDIR)
@@ -39,9 +39,9 @@
endif()
if(IS_DIRECTORY "${ANDROID_NDK_TOOLCHAINDIR}")
- MESSAGE(STATUS "Detected the Android NDK toolchain at: ${ANDROID_NDK_TOOLCHAINDIR}")
+ message(STATUS "Detected the Android NDK toolchain at: ${ANDROID_NDK_TOOLCHAINDIR}")
else ()
- MESSAGE(FATAL_ERROR "Couldn't detect the Android NDK toolchain directory: ${ANDROID_NDK_TOOLCHAINDIR}")
+ message(FATAL_ERROR "Couldn't detect the Android NDK toolchain directory: ${ANDROID_NDK_TOOLCHAINDIR}")
endif()
if(NOT ANDROID_SDK)#Check if its defined at the cmdline
@@ -52,9 +52,9 @@
endif()
if( IS_DIRECTORY "${ANDROID_SDK}")
- MESSAGE(STATUS "Detected the android SDK directory at: " ${ANDROID_SDK})
+ message(STATUS "Detected the android SDK directory at: " ${ANDROID_SDK})
else ()
- MESSAGE(FATAL_ERROR "Couldn't detect the Android SDK directory")
+ message(FATAL_ERROR "Couldn't detect the Android SDK directory")
endif()
if( NOT FPC_DIR)
@@ -66,18 +66,18 @@
endif()
if( IS_DIRECTORY "${FPC_DIR}")
- MESSAGE(STATUS "Detected the FreePascal directory at: " "${FPC_DIR}")
+ message(STATUS "Detected the FreePascal directory at: " "${FPC_DIR}")
else ()
- MESSAGE(FATAL_ERROR "Couldn't detect the FreePascal directory")
+ message(FATAL_ERROR "Couldn't detect the FreePascal directory")
endif()
set(SDL_DIR /home/richard/Downloads/android-project)
-set(ANDROID_SDK_API_LVL 14)
+set(ANDROID_SDK_API_LVL 16)
set(ANDROID_NDK_API_LVL 5)
-MESSAGE(STATUS "Creating Makefile.android...")
+message(STATUS "Creating Makefile.android...")
configure_file(Templates/Makefile.android .)
@@ -89,9 +89,9 @@
"--target android-${ANDROID_SDK_API_LVL}"
OUTPUT_VARIABLE androidoutput
)
- MESSAGE(STATUS "Updating android project config...\n" ${androidoutput})
+ message(STATUS "Updating android project config...\n" ${androidoutput})
else()
- MESSAGE(FATAL_ERROR "Couldn't find the android executable in ${ANDROID_SDK}/platform-tools or ${ANDROID_SDK}/tools.")
+ message(FATAL_ERROR "Couldn't find the android executable in ${ANDROID_SDK}/platform-tools or ${ANDROID_SDK}/tools.")
endif()
exec_program(${HGCOMMAND}
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/SDL-android-project/jni/jnidispatch/Android.mk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/jni/jnidispatch/Android.mk Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,6 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libjnidispatch
+LOCAL_SRC_FILES := libjnidispatch.so
+include $(PREBUILT_SHARED_LIBRARY)
\ No newline at end of file
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/SDL-android-project/jni/jnidispatch/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/jni/jnidispatch/README Fri Feb 22 05:05:32 2013 +0100
@@ -0,0 +1,1 @@
+This library is part of JNA and just needs to be copied into the libs/armeabi folder. However, putting it there directly will get it cleaned away on build.
\ No newline at end of file
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/SDL-android-project/jni/jnidispatch/libjnidispatch.so
Binary file project_files/Android-build/SDL-android-project/jni/jnidispatch/libjnidispatch.so has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/SDL-android-project/jni/src/hedgewars_main.c
--- a/project_files/Android-build/SDL-android-project/jni/src/hedgewars_main.c Sun Nov 18 01:06:01 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/jni/src/hedgewars_main.c Fri Feb 22 05:05:32 2013 +0100
@@ -1,3 +1,4 @@
+#include
#include "android/log.h"
#include "SDL.h"
@@ -6,7 +7,7 @@
#define TAG "HWEngine Loader"
-typedef (*HWEngine_Game)(char**);
+typedef (*HWEngine_Game)(int32_t argc, char** argv);
main(int argc, char *argv[]){
void *handle;
@@ -33,7 +34,7 @@
exit(EXIT_FAILURE);
}
__android_log_print(ANDROID_LOG_INFO, TAG, "dlsym succeeded");
- Game(argv);
+ Game(argc, argv);
__android_log_print(ANDROID_LOG_INFO, TAG, "Game() ended");
dlclose(handle);
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/SDL-android-project/libs/armeabi/libjnidispatch.so
Binary file project_files/Android-build/SDL-android-project/libs/armeabi/libjnidispatch.so has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/SDL-android-project/libs/jna-3.5.1.jar
Binary file project_files/Android-build/SDL-android-project/libs/jna-3.5.1.jar has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/SDL-android-project/libs/jna.jar
Binary file project_files/Android-build/SDL-android-project/libs/jna.jar has changed
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java Sun Nov 18 01:06:01 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java Fri Feb 22 05:05:32 2013 +0100
@@ -31,6 +31,7 @@
System.loadLibrary("SDL_mixer");
System.loadLibrary("SDL_ttf");
System.loadLibrary("lua5.1");
+ System.loadLibrary("physfs");
System.loadLibrary("hwengine");
}
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Flib.java
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Flib.java Sun Nov 18 01:06:01 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Flib.java Fri Feb 22 05:05:32 2013 +0100
@@ -28,6 +28,7 @@
public class Flib {
static {
+ System.loadLibrary("SDL");
System.loadLibrary("SDL_net");
System.setProperty("jna.encoding", "UTF8"); // Ugly global setting, but it seems JNA doesn't allow setting this per-library...
}
@@ -58,4 +59,4 @@
INSTANCE.flib_log_setLevel(Frontlib.FLIB_LOGLEVEL_INFO);
INSTANCE.flib_log_setCallback(logCb);
}
-}
\ No newline at end of file
+}
diff -r d5d5e1698554 -r 1dedcc37bfe8 project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java Sun Nov 18 01:06:01 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java Fri Feb 22 05:05:32 2013 +0100
@@ -21,6 +21,7 @@
package org.hedgewars.hedgeroid.frontlib;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -350,10 +351,14 @@
static class HogStruct extends Structure {
public static class ByVal extends HogStruct implements Structure.ByValue {}
public static class ByRef extends HogStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"name", "hat", "rounds", "kills", "deaths", "suicides", "difficulty", "initialHealth", "weaponset"};
- public HogStruct() { super(); setFieldOrder(FIELD_ORDER); }
- public HogStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ public HogStruct() { super(); }
+ public HogStruct(Pointer ptr) { super(ptr); }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList("name", "hat", "rounds", "kills", "deaths", "suicides", "difficulty", "initialHealth", "weaponset");
+ }
public void fillFrom(Hog hog) {
difficulty = hog.level;
@@ -382,10 +387,14 @@
static class TeamStruct extends Structure {
public static class ByVal extends TeamStruct implements Structure.ByValue {}
public static class ByRef extends TeamStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"hogs", "name", "grave", "fort", "voicepack", "flag", "bindings", "bindingCount", "rounds", "wins", "campaignProgress", "colorIndex", "hogsInGame", "remoteDriven", "ownerName"};
- public TeamStruct() { super(); setFieldOrder(FIELD_ORDER); }
- public TeamStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ public TeamStruct() { super(); }
+ public TeamStruct(Pointer ptr) { super(ptr); }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList("hogs", "name", "grave", "fort", "voicepack", "flag", "bindings", "bindingCount", "rounds", "wins", "campaignProgress", "colorIndex", "hogsInGame", "remoteDriven", "ownerName");
+ }
public void fillFrom(Team team, TeamIngameAttributes attrs) {
if(team != null) {
@@ -458,10 +467,14 @@
static class WeaponsetStruct extends Structure {
public static class ByVal extends WeaponsetStruct implements Structure.ByValue {}
public static class ByRef extends WeaponsetStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"loadout", "crateprob", "crateammo", "delay", "name"};
+
+ public WeaponsetStruct() { super(); }
+ public WeaponsetStruct(Pointer ptr) { super(ptr); }
- public WeaponsetStruct() { super(); setFieldOrder(FIELD_ORDER); }
- public WeaponsetStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList("loadout", "crateprob", "crateammo", "delay", "name");
+ }
public void fillFrom(Weaponset weaponset) {
fillWeaponInfo(loadout, weaponset.loadout);
@@ -501,10 +514,13 @@
* Represents a flib_weaponset*, for use as part of a flib_weaponset**
*/
static class WeaponsetPointerByReference extends Structure implements Structure.ByReference {
- private static String[] FIELD_ORDER = new String[] {"weaponset"};
+ public WeaponsetPointerByReference() { super(); }
+ public WeaponsetPointerByReference(Pointer ptr) { super(ptr); }
- public WeaponsetPointerByReference() { super(); setFieldOrder(FIELD_ORDER); }
- public WeaponsetPointerByReference(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList("weaponset");
+ }
public WeaponsetStruct.ByRef weaponset;
}
@@ -512,10 +528,14 @@
static class WeaponsetListStruct extends Structure {
public static class ByVal extends WeaponsetListStruct implements Structure.ByValue {}
public static class ByRef extends WeaponsetListStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"weaponsetCount", "weaponsets"};
+
+ public WeaponsetListStruct() { super(); }
+ public WeaponsetListStruct(Pointer ptr) { super(ptr); }
- public WeaponsetListStruct() { super(); setFieldOrder(FIELD_ORDER); }
- public WeaponsetListStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList("weaponsetCount", "weaponsets");
+ }
public void fillFrom(List list) {
weaponsetCount = list.size();
@@ -560,11 +580,15 @@
static class RoomStruct extends Structure {
public static class ByVal extends RoomStruct implements Structure.ByValue {}
public static class ByRef extends RoomStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"inProgress", "name", "playerCount", "teamCount", "owner", "map", "scheme", "weapons"};
- public RoomStruct() { super(); setFieldOrder(FIELD_ORDER); }
- public RoomStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ public RoomStruct() { super(); }
+ public RoomStruct(Pointer ptr) { super(ptr); }
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList("inProgress", "name", "playerCount", "teamCount", "owner", "map", "scheme", "weapons");
+ }
+
public Room toRoomlistRoom() {
return new Room(name, map, scheme, weapons, owner, playerCount, teamCount, inProgress);
}
@@ -582,10 +606,14 @@
static class MapRecipeStruct extends Structure {
public static class ByVal extends MapRecipeStruct implements Structure.ByValue {}
public static class ByRef extends MapRecipeStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"mapgen", "name", "seed", "theme", "drawData", "drawDataSize", "templateFilter", "mazeSize"};
+
+ public MapRecipeStruct() { super(); }
+ public MapRecipeStruct(Pointer ptr) { super(ptr); }
- public MapRecipeStruct() { super(); setFieldOrder(FIELD_ORDER); }
- public MapRecipeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList("mapgen", "name", "seed", "theme", "drawData", "drawDataSize", "templateFilter", "mazeSize");
+ }
public void fillFrom(MapRecipe map) {
mapgen = map.mapgen;
@@ -593,24 +621,14 @@
seed = map.seed;
theme = map.theme;
byte[] buf = map.getDrawData();
- if(buf==null || buf.length==0) {
- drawData = null;
- } else {
- drawData = ByteArrayPtr.createJavaOwned(buf).getPointer();
- }
+ drawData = ByteArrayPtr.createJavaOwned(buf);
drawDataSize = NativeSizeT.valueOf(buf==null ? 0 : buf.length);
templateFilter = map.templateFilter;
mazeSize = map.mazeSize;
}
public MapRecipe toMapRecipe() {
- byte[] buf;
- int size = drawDataSize.intValue();
- if(size>0) {
- buf = drawData.getByteArray(0, size);
- } else {
- buf = null;
- }
+ byte[] buf = ByteArrayPtr.deref(drawData, drawDataSize.intValue());
return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, buf);
}
@@ -618,7 +636,7 @@
public String name;
public String seed;
public String theme;
- public Pointer drawData; // We can't use ByteArrayPtr in a struct because JNA will overwrite the value with NULL - probably a bug.
+ public ByteArrayPtr drawData;
public NativeSizeT drawDataSize;
public int templateFilter;
public int mazeSize;
@@ -627,10 +645,14 @@
static class MetaschemeSettingStruct extends Structure {
public static class ByVal extends MetaschemeSettingStruct implements Structure.ByValue {}
public static class ByRef extends MetaschemeSettingStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"name", "engineCommand", "maxMeansInfinity", "times1000", "min", "max", "def"};
+
+ public MetaschemeSettingStruct() { super(); }
+ public MetaschemeSettingStruct(Pointer ptr) { super(ptr); }
- public MetaschemeSettingStruct() { super(); setFieldOrder(FIELD_ORDER); }
- public MetaschemeSettingStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList("name", "engineCommand", "maxMeansInfinity", "times1000", "min", "max", "def");
+ }
public void fillFrom(Setting setting) {
name = setting.name;
@@ -658,10 +680,14 @@
static class MetaschemeModStruct extends Structure {
public static class ByVal extends MetaschemeModStruct implements Structure.ByValue {}
public static class ByRef extends MetaschemeModStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"name", "bitmaskIndex"};
+
+ public MetaschemeModStruct() { super(); }
+ public MetaschemeModStruct(Pointer ptr) { super(ptr); }
- public MetaschemeModStruct() { super(); setFieldOrder(FIELD_ORDER); }
- public MetaschemeModStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList("name", "bitmaskIndex");
+ }
public void fillFrom(Mod mod) {
name = mod.name;
@@ -681,10 +707,13 @@
public static class ByVal extends MetaschemeStruct implements Structure.ByValue {}
public static class ByRef extends MetaschemeStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"settingCount", "modCount", "settings", "mods"};
+ public MetaschemeStruct() { super(); }
+ public MetaschemeStruct(Pointer ptr) { super(ptr); }
- public MetaschemeStruct() { super(); setFieldOrder(FIELD_ORDER); }
- public MetaschemeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ @Override
+ protected List