diff -Nru hedgewars-0.9.19.3/CMakeLists.txt hedgewars-0.9.20.5/CMakeLists.txt
--- hedgewars-0.9.19.3/CMakeLists.txt 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/CMakeLists.txt 2014-01-08 16:25:16.000000000 +0000
@@ -1,200 +1,60 @@
project(hedgewars)
#initialise cmake environment
-cmake_minimum_required(VERSION 2.6.0)
-if(CMAKE_VERSION VERSION_LESS "2.8")
- set(WARNING "WARNING: ")
- set(allow_parse_args FALSE)
-else()
- set(WARNING WARNING)
- set(allow_parse_args TRUE)
-endif()
-foreach(hwpolicy CMP0003 CMP0012 CMP0017)
+cmake_minimum_required(VERSION 2.6.4)
+foreach(hwpolicy CMP0003 CMP0012 CMP0017 CMP0018)
if(POLICY ${hwpolicy})
cmake_policy(SET ${hwpolicy} NEW)
endif()
endforeach()
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules")
-
+include(${CMAKE_MODULE_PATH}/utils.cmake)
#possible cmake configuration
option(NOSERVER "Disable gameServer build (off)]" OFF)
option(NOPNG "Disable screenshoot compression (off)" OFF)
option(NOVIDEOREC "Disable video recording (off)" OFF)
+#libraries are built shared unless explicitly added as a static
+option(BUILD_SHARED_LIBS "Build libraries as shared modules (on)" ON)
#set this to ON when 2.1.0 becomes more widespread (and only for linux)
option(PHYSFS_SYSTEM "Use system physfs (off)" OFF)
+if(WIN32 OR APPLE)
+ option(LUA_SYSTEM "Use system lua (off)" OFF)
+else()
+ option(LUA_SYSTEM "Use system lua (on)" ON)
+endif()
+
option(BUILD_ENGINE_LIBRARY "Enable hwengine library (off)" OFF)
option(ANDROID "Enable Android build (off)" OFF)
-if(UNIX AND NOT APPLE)
- option(MINIMAL_FLAGS "Respect system flags as much as possible (off)" OFF)
-else()
- option(NOAUTOUPDATE "Disable OS X Sparkle update checking" OFF)
-endif()
+option(MINIMAL_FLAGS "Respect system flags as much as possible (off)" OFF)
+option(NOAUTOUPDATE "Disable OS X Sparkle update checking (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 and init rev/hash information
-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" HEDGEWARS_REVISION ${internal_version})
- string(REGEX REPLACE "([0-9a-zA-Z]+)(.*) [0-9]+(.*)" "\\1" HEDGEWARS_HASH ${internal_version})
-
- if(HGCHANGED)
- message(${WARNING} "You have uncommitted changes in your repository!")
- endif()
- #let's assume that if you have hg you might be interested in debugging
- set(default_build_type "DEBUG")
- #write down hash and rev for easy picking should hg be missing
- file(WRITE "${CMAKE_SOURCE_DIR}/share/version_info.txt" "Hedgewars versioning information, do not modify\nrev ${HEDGEWARS_REVISION}\nhash ${HEDGEWARS_HASH}\n")
-else()
- set(default_build_type "RELEASE")
- # when compiling outside rev control, fetch revision and hash information from version_info.txt
- find_file(version_info version_info.txt PATH ${CMAKE_SOURCE_DIR}/share)
- if(version_info)
- file(STRINGS ${version_info} internal_version REGEX "rev")
- string(REGEX REPLACE "rev ([0-9]*)" "\\1" HEDGEWARS_REVISION ${internal_version})
- file(STRINGS ${version_info} internal_version REGEX "hash")
- string(REGEX REPLACE "hash ([a-zA-Z0-9]*)" "\\1" HEDGEWARS_HASH ${internal_version})
- else()
- message(${WARNING} "${CMAKE_SOURCE_DIR}/share/version_info.txt not found, revision information "
- "will be incorrect!!! Contact your source provider to fix this!")
- set(HEDGEWARS_REVISION "0000")
- set(HEDGEWARS_HASH "unknown")
- endif()
-endif()
-
-
#versioning
set(CPACK_PACKAGE_VERSION_MAJOR 0)
set(CPACK_PACKAGE_VERSION_MINOR 9)
-set(CPACK_PACKAGE_VERSION_PATCH 19)
-set(HEDGEWARS_PROTO_VER 45)
+set(CPACK_PACKAGE_VERSION_PATCH 20)
+set(HEDGEWARS_PROTO_VER 47)
set(HEDGEWARS_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+include(${CMAKE_MODULE_PATH}/revinfo.cmake)
message(STATUS "Building ${HEDGEWARS_VERSION}-r${HEDGEWARS_REVISION} (${HEDGEWARS_HASH})")
-
-#where to build libs and bins
-set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
-set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
-
-#resource paths
-if(UNIX AND NOT APPLE)
- set(target_binary_install_dir "bin")
- set(target_library_install_dir "lib")
-
- string(SUBSTRING "${DATA_INSTALL_DIR}" 0 1 sharepath_start)
- if (NOT (${sharepath_start} MATCHES "/"))
- set(HEDGEWARS_DATADIR "${CMAKE_INSTALL_PREFIX}/${DATA_INSTALL_DIR}/")
- else()
- set(HEDGEWARS_DATADIR "${DATA_INSTALL_DIR}/")
- endif()
- set(HEDGEWARS_FULL_DATADIR "${HEDGEWARS_DATADIR}")
-else()
- set(target_binary_install_dir "./")
-
- if(APPLE)
- set(target_library_install_dir "../Frameworks/")
- set(CMAKE_INSTALL_PREFIX "Hedgewars.app/Contents/MacOS/")
- set(HEDGEWARS_DATADIR "../Resources/")
- set(HEDGEWARS_FULL_DATADIR "/Applications/${CMAKE_INSTALL_PREFIX}/${HEDGEWARS_DATADIR}")
- elseif(WIN32)
- set(target_library_install_dir "./")
- set(HEDGEWARS_DATADIR "./")
- set(HEDGEWARS_FULL_DATADIR "${CMAKE_INSTALL_PREFIX}/")
- link_directories("${EXECUTABLE_OUTPUT_PATH}" "${CMAKE_SOURCE_DIR}/misc/winutils/bin")
- endif()
-endif()
-
-
-if(APPLE)
- set(CMAKE_FIND_FRAMEWORK "FIRST")
-
- #what system are we building for
- set(minimum_macosx_version $ENV{MACOSX_DEPLOYMENT_TARGET})
-
- #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)
- 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()
- 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()
-
- #if nothing is set, we deploy only for the current system
- if(NOT minimum_macosx_version)
- set(minimum_macosx_version ${current_macosx_version})
- endif()
-
- #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 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(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 VERSION_LESS "10.6")
- if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "powerpc*")
- set(CMAKE_OSX_ARCHITECTURES "ppc7400")
- else()
- set(CMAKE_OSX_ARCHITECTURES "i386")
- endif()
- else()
- set(CMAKE_OSX_ARCHITECTURES "x86_64")
- endif()
- endif()
-
- #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} 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 "/Developer/usr/bin/gcc-4.0")
- set(CMAKE_CXX_COMPILER "/Developer/usr/bin/g++-4.0")
- else()
- string(REGEX REPLACE "([0-9]+.[0-9]+).[0-9]+" "\\1" sdk_version ${minimum_macosx_version})
- set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX${sdk_version}.sdk/")
- endif()
- endif()
-
- #add user framework directory, other paths can be passed via FPFLAGS
- list(APPEND pascal_flags "-Ff~/Library/Frameworks")
- #set deployment target
- list(APPEND pascal_flags "-k-macosx_version_min" "-k${minimum_macosx_version}" "-XR${CMAKE_OSX_SYSROOT}")
-endif(APPLE)
+#general utilities
+include(${CMAKE_MODULE_PATH}/utils.cmake)
+#paths initialization
+include(${CMAKE_MODULE_PATH}/paths.cmake)
+#platform specific init code
+include(${CMAKE_MODULE_PATH}/platform.cmake)
#when build type is not specified, assume Debug/Release according to build version information
@@ -209,108 +69,70 @@
endif (CMAKE_BUILD_TYPE)
-#set default flags values for all projects (unless MINIMAL_FLAGS is true)
-if(NOT ${MINIMAL_FLAGS})
- if(WINDOWS)
- #this flags prevents a few dll hell problems
- set(CMAKE_C_FLAGS "-static-libgcc ${CMAKE_C_FLAGS}")
- endif(WINDOWS)
- 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})
-else()
- #CMake adds a lot of additional configuration flags, so let's clear them up
- set(CMAKE_C_FLAGS_RELEASE "")
- set(CMAKE_C_FLAGS_DEBUG "-Wall -DDEBUG")
- set(CMAKE_CXX_FLAGS_RELEASE "")
- set(CMAKE_CXX_FLAGS_DEBUG "-Wall -DDEBUG")
-endif()
-
-
-#TESTING TIME
-include(CheckCCompilerFlag)
+#perform safe check that enable/disable compilation features
+include(${CMAKE_MODULE_PATH}/compilerchecks.cmake)
-#check for noexecstack on ELF, should be set on Gentoo and similar
-set(CMAKE_REQUIRED_FLAGS "-Wl,-z -Wl,noexecstack")
-check_c_compiler_flag("" HAVE_NOEXECSTACK) #empty because we are testing a linker flag
-if(HAVE_NOEXECSTACK)
- list(APPEND pascal_flags "-k-z" "-knoexecstack")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_REQUIRED_FLAGS}")
+#set default compiler flags
+add_flag_append(CMAKE_C_FLAGS "-Wall -pipe")
+add_flag_append(CMAKE_C_FLAGS_RELEASE "-O2")
+add_flag_append(CMAKE_C_FLAGS_DEBUG "-Wextra -O0")
+add_flag_append(CMAKE_CXX_FLAGS "-Wall -pipe")
+add_flag_append(CMAKE_CXX_FLAGS_RELEASE "-O2")
+add_flag_append(CMAKE_CXX_FLAGS_DEBUG "-Wextra -O0")
+
+#CMake adds a lot of additional configuration flags, so let's clear them up
+if(${MINIMAL_FLAGS})
+ unset(CMAKE_C_FLAGS_RELEASE)
+ unset(CMAKE_C_FLAGS_DEBUG)
+ unset(CMAKE_CXX_FLAGS_RELEASE)
+ unset(CMAKE_CXX_FLAGS_DEBUG)
endif()
-unset(CMAKE_REQUIRED_FLAGS)
-#check for ASLR and DEP security features on Windows
-#both supported in binutils >= 2.20, available since Vista and XP SP2 respectively
-set(CMAKE_REQUIRED_FLAGS "-Wl,--nxcompat -Wl,--dynamicbase")
-check_c_compiler_flag("" HAVE_WINASLRDEP) #empty because we are testing a linker flag
-if(HAVE_WINASLRDEP)
- list(APPEND pascal_flags "-k--nxcompat" "-k--dynamicbase")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_REQUIRED_FLAGS}")
-endif()
-unset(CMAKE_REQUIRED_FLAGS)
#parse additional parameters
-if(FPFLAGS OR GHFLAGS)
- if(${allow_parse_args})
- separate_arguments(fpflags_parsed UNIX_COMMAND ${FPFLAGS})
+if(GHFLAGS)
+ if(${CMAKE_VERSION} VERSION_GREATER 2.6)
separate_arguments(ghflags_parsed UNIX_COMMAND ${GHFLAGS})
else()
- message(${WARNING} "FPFLAGS and GHFLAGS are available only when using CMake >= 2.8")
+ message(${WARNING} "GHFLAGS are available only when using CMake >= 2.8")
endif()
endif()
-list(APPEND pascal_flags ${fpflags_parsed} # user flags
- "-B" # compile all units
- "-vm4079,4080,4081" # fpc verbosity output format
- "-FE${PROJECT_BINARY_DIR}/bin" # fpc binaries output directory
- "-FU${PROJECT_BINARY_DIR}/hedgewars" # fpc units output directory
- "-Fl${PROJECT_BINARY_DIR}/bin" # fpc linking directory (win/unix)
- "-Fi${PROJECT_BINARY_DIR}/hedgewars" # fpc .inc path (for out of source builds)
- "-k-L${PROJECT_BINARY_DIR}/bin" # ld linking directory (unix/osx)
- "-Cs2000000" # stack size
- "-vewnq" # fpc output verbosity
- "-dDEBUGFILE" # macro for engine output
- )
-list(APPEND haskell_flags ${ghflags_parsed} # user flags
- "-O2" # optimise for faster code
- )
-
+list(APPEND haskell_flags ${ghflags_parsed} "-O2")
#get BUILD_TYPE and enable/disable optimisation
message(STATUS "Using ${CMAKE_BUILD_TYPE} configuration")
if(CMAKE_BUILD_TYPE MATCHES "DEBUG")
- list(APPEND pascal_flags "-O-" # disable all optimisations
- "-g" # enable debug symbols
- "-gl" # add line info to bt
- "-gv" # allow valgrind
- )
list(APPEND haskell_flags "-Wall" # all warnings
"-debug" # debug mode
"-dcore-lint" # internal sanity check
)
else()
- list(APPEND pascal_flags "-Os" # optimise for size
- "-Xs" # strip binary
- "-Si" # turn on inlining
- )
list(APPEND haskell_flags "-w" # no warnings
)
endif()
-include(${CMAKE_MODULE_PATH}/utils.cmake)
#lua discovery
-find_package(Lua)
-if(LUA_FOUND)
- message(STATUS "Found LUA: ${LUA_DEFAULT}")
+if (${LUA_SYSTEM})
+ if (NOT LUA_LIBRARY OR NOT LUA_INCLUDE_DIR)
+ find_package(Lua)
+ endif()
+
+ if (LUA_LIBRARY AND LUA_INCLUDE_DIR)
+ set(LUA_FOUND TRUE)
+ #use an IMPORTED tharget so that we can just use 'lua' to link
+ add_library(lua UNKNOWN IMPORTED)
+ set_target_properties(lua PROPERTIES IMPORTED_LOCATION ${LUA_LIBRARY})
+ else()
+ message(FATAL_ERROR "Missing Lua! Rerun cmake with -DLUA_SYSTEM=off to build the internal version")
+ endif()
else()
- message(STATUS "LUA will be provided by the bundled sources")
+ if (NOT LUA_LIBRARY OR NOT LUA_INCLUDE_DIR)
+ message(STATUS "LUA will be provided by the bundled sources")
+ endif()
+ set(lua_output_name "hwlua")
add_subdirectory(misc/liblua)
- #linking with liblua.a requires system readline
- list(APPEND pascal_flags "-k${EXECUTABLE_OUTPUT_PATH}/lib${LUA_LIBRARY}.a" "-k-lreadline")
endif()
@@ -338,15 +160,17 @@
if (NOT PHYSFS_LIBRARY OR NOT PHYSFS_INCLUDE_DIR)
message(FATAL_ERROR "Missing PhysFS! Rerun cmake with -DPHYSFS_SYSTEM=off to build the internal version")
+ else()
+ #use an IMPORTED tharget so that we can just use 'physfs' to link
+ add_library(physfs UNKNOWN IMPORTED)
+ set_target_properties(physfs PROPERTIES IMPORTED_LOCATION ${PHYSFS_LIBRARY})
endif()
else()
- message(STATUS "PhysFS will be provided by the bundled sources")
- set(physfs_output_name "hw_physfs")
+ if (NOT PHYSFS_LIBRARY OR NOT PHYSFS_INCLUDE_DIR)
+ message(STATUS "PhysFS will be provided by the bundled sources")
+ endif()
+ set(physfs_output_name "hwphysfs")
add_subdirectory(misc/libphysfs)
- #-XLA is a beta fpc flag that renames libraries before passing them to the linker
- #we also have to pass PHYSFS_INTERNAL to satisfy windows runtime requirements
- #(should be harmless on other platforms)
- list(APPEND pascal_flags "-XLAphysfs=${physfs_output_name}" "-dPHYSFS_INTERNAL")
endif()
find_package_or_disable_msg(FFMPEG NOVIDEOREC "Video recording will not be built")
diff -Nru hedgewars-0.9.19.3/COPYING hedgewars-0.9.20.5/COPYING
--- hedgewars-0.9.19.3/COPYING 2012-12-19 16:09:04.000000000 +0000
+++ hedgewars-0.9.20.5/COPYING 2013-10-31 20:21:49.000000000 +0000
@@ -1,12 +1,12 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
- Preamble
+ Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -56,7 +56,7 @@
The precise terms and conditions for copying, distribution and
modification follow.
- GNU GENERAL PUBLIC LICENSE
+ GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@@ -255,7 +255,7 @@
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
- NO WARRANTY
+ NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@@ -277,9 +277,9 @@
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
- END OF TERMS AND CONDITIONS
+ END OF TERMS AND CONDITIONS
- How to Apply These Terms to Your New Programs
+ How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@@ -338,3 +338,362 @@
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+
+
+
+ GNU Free Documentation License
+ Version 1.2, November 2002
+
+ Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other functional
+and useful document "free" in the sense of freedom: to assure everyone the
+effective freedom to copy and redistribute it, with or without modifying it,
+either commercially or noncommercially. Secondarily, this License preserves for
+the author and publisher a way to get credit for their work, while not being
+considered responsible for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative works of the
+document must themselves be free in the same sense. It complements the GNU
+General Public License, which is a copyleft license designed for free software.
+
+We have designed this License in order to use it for manuals for free software,
+because free software needs free documentation: a free program should come with
+manuals providing the same freedoms that the software does. But this License is
+not limited to software manuals; it can be used for any textual work,
+regardless of subject matter or whether it is published as a printed book. We
+recommend this License principally for works whose purpose is instruction or
+reference.
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that contains
+a notice placed by the copyright holder saying it can be distributed under the
+terms of this License. Such a notice grants a world-wide, royalty-free license,
+unlimited in duration, to use that work under the conditions stated herein. The
+"Document", below, refers to any such manual or work. Any member of the public
+is a licensee, and is addressed as "you". You accept the license if you copy,
+modify or distribute the work in a way requiring permission under copyright
+law.
+
+A "Modified Version" of the Document means any work containing the Document or
+a portion of it, either copied verbatim, or with modifications and/or
+translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of the
+Document that deals exclusively with the relationship of the publishers or
+authors of the Document to the Document's overall subject (or to related
+matters) and contains nothing that could fall directly within that overall
+subject. (Thus, if the Document is in part a textbook of mathematics, a
+Secondary Section may not explain any mathematics.) The relationship could be a
+matter of historical connection with the subject or with related matters, or of
+legal, commercial, philosophical, ethical or political position regarding them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles are
+designated, as being those of Invariant Sections, in the notice that says that
+the Document is released under this License. If a section does not fit the
+above definition of Secondary then it is not allowed to be designated as
+Invariant. The Document may contain zero Invariant Sections. If the Document
+does not identify any Invariant Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed, as
+Front-Cover Texts or Back-Cover Texts, in the notice that says that the
+Document is released under this License. A Front-Cover Text may be at most 5
+words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy, represented
+in a format whose specification is available to the general public, that is
+suitable for revising the document straightforwardly with generic text editors
+or (for images composed of pixels) generic paint programs or (for drawings)
+some widely available drawing editor, and that is suitable for input to text
+formatters or for automatic translation to a variety of formats suitable for
+input to text formatters. A copy made in an otherwise Transparent file format
+whose markup, or absence of markup, has been arranged to thwart or discourage
+subsequent modification by readers is not Transparent. An image format is not
+Transparent if used for any substantial amount of text. A copy that is not
+"Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain ASCII without
+markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly
+available DTD, and standard-conforming simple HTML, PostScript or PDF designed
+for human modification. Examples of transparent image formats include PNG, XCF
+and JPG. Opaque formats include proprietary formats that can be read and edited
+only by proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the machine-generated HTML,
+PostScript or PDF produced by some word processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself, plus such
+following pages as are needed to hold, legibly, the material this License
+requires to appear in the title page. For works in formats which do not have
+any title page as such, "Title Page" means the text near the most prominent
+appearance of the work's title, preceding the beginning of the body of the text.
+
+A section "Entitled XYZ" means a named subunit of the Document whose title
+either is precisely XYZ or contains XYZ in parentheses following text that
+translates XYZ in another language. (Here XYZ stands for a specific section
+name mentioned below, such as "Acknowledgements", "Dedications",
+"Endorsements", or "History".) To "Preserve the Title" of such a section when
+you modify the Document means that it remains a section "Entitled XYZ"
+according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which states
+that this License applies to the Document. These Warranty Disclaimers are
+considered to be included by reference in this License, but only as regards
+disclaiming warranties: any other implication that these Warranty Disclaimers
+may have is void and has no effect on the meaning of this License.
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either commercially or
+noncommercially, provided that this License, the copyright notices, and the
+license notice saying this License applies to the Document are reproduced in
+all copies, and that you add no other conditions whatsoever to those of this
+License. You may not use technical measures to obstruct or control the reading
+or further copying of the copies you make or distribute. However, you may
+accept compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and you may
+publicly display copies.
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have printed
+covers) of the Document, numbering more than 100, and the Document's license
+notice requires Cover Texts, you must enclose the copies in covers that carry,
+clearly and legibly, all these Cover Texts: Front-Cover Texts on the front
+cover, and Back-Cover Texts on the back cover. Both covers must also clearly
+and legibly identify you as the publisher of these copies. The front cover must
+present the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition. Copying with
+changes limited to the covers, as long as they preserve the title of the
+Document and satisfy these conditions, can be treated as verbatim copying in
+other respects.
+
+If the required texts for either cover are too voluminous to fit legibly, you
+should put the first ones listed (as many as fit reasonably) on the actual
+cover, and continue the rest onto adjacent pages.
+
+If you publish or distribute Opaque copies of the Document numbering more than
+100, you must either include a machine-readable Transparent copy along with each
+Opaque copy, or state in or with each Opaque copy a computer-network location
+from which the general network-using public has access to download using
+public-standard network protocols a complete Transparent copy of the Document,
+free of added material. If you use the latter option, you must take reasonably
+prudent steps, when you begin distribution of Opaque copies in quantity, to
+ensure that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an Opaque
+copy (directly or through your agents or retailers) of that edition to the
+public.
+
+It is requested, but not required, that you contact the authors of the Document
+well before redistributing any large number of copies, to give them a chance to
+provide you with an updated version of the Document.
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under the
+conditions of sections 2 and 3 above, provided that you release the Modified
+Version under precisely this License, with the Modified Version filling the role
+of the Document, thus licensing distribution and modification of the Modified
+Version to whoever possesses a copy of it. In addition, you must do these things
+in the Modified Version:
+
+ A. Use in the Title Page (and on the covers, if any) a title distinct from
+ that of the Document, and from those of previous versions (which should,
+ if there were any, be listed in the History section of the Document).
+ You may use the same title as a previous version if the original
+ publisher of that version gives permission.
+ B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified Version,
+ together with at least five of the principal authors of the Document
+ (all of its principal authors, if it has fewer than five), unless they
+ release you from this requirement.
+ C. State on the Title page the name of the publisher of the Modified
+ Version, as the publisher.
+ D. Preserve all the copyright notices of the Document.
+ E. Add an appropriate copyright notice for your modifications adjacent to
+ the other copyright notices.
+ F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the terms
+ of this License, in the form shown in the Addendum below.
+ G. Preserve in that license notice the full lists of Invariant Sections and
+ required Cover Texts given in the Document's license notice.
+ H. Include an unaltered copy of this License.
+ I. Preserve the section Entitled "History", Preserve its Title, and add to
+ it an item stating at least the title, year, new authors, and publisher
+ of the Modified Version as given on the Title Page. If there is no
+ section Entitled "History" in the Document, create one stating the
+ title, year, authors, and publisher of the Document as given on its
+ Title Page, then add an item describing the Modified Version as stated
+ in the previous sentence.
+ J. Preserve the network location, if any, given in the Document for public
+ access to a Transparent copy of the Document, and likewise the network
+ locations given in the Document for previous versions it was based on.
+ These may be placed in the "History" section. You may omit a network
+ location for a work that was published at least four years before the
+ Document itself, or if the original publisher of the version it refers
+ to gives permission.
+ K. For any section Entitled "Acknowledgements" or "Dedications", Preserve
+ the Title of the section, and preserve in the section all the substance
+ and tone of each of the contributor acknowledgements and/or dedications
+ given therein.
+ L. Preserve all the Invariant Sections of the Document, unaltered in their
+ text and in their titles. Section numbers or the equivalent are not
+ considered part of the section titles.
+ M. Delete any section Entitled "Endorsements". Such a section may not be
+ included in the Modified Version.
+ N. Do not retitle any existing section to be Entitled "Endorsements" or to
+ conflict in title with any Invariant Section.
+ O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or appendices that
+qualify as Secondary Sections and contain no material copied from the Document,
+you may at your option designate some or all of these sections as invariant. To
+do this, add their titles to the list of Invariant Sections in the Modified
+Version's license notice. These titles must be distinct from any other section
+titles.
+
+You may add a section Entitled "Endorsements", provided it contains nothing but
+endorsements of your Modified Version by various parties--for example,
+statements of peer review or that the text has been approved by an organization
+as the authoritative definition of a standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a passage
+of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in
+the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover
+Text may be added by (or through arrangements made by) any one entity. If the
+Document already includes a cover text for the same cover, previously added by
+you or by arrangement made by the same entity you are acting on behalf of, you
+may not add another; but you may replace the old one, on explicit permission
+from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License give
+permission to use their names for publicity for or to assert or imply
+endorsement of any Modified Version.
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this License,
+under the terms defined in section 4 above for modified versions, provided that
+you include in the combination all of the Invariant Sections of all of the
+original documents, unmodified, and list them all as Invariant Sections of your
+combined work in its license notice, and that you preserve all their Warranty
+Disclaimers.
+
+The combined work need only contain one copy of this License, and multiple
+identical Invariant Sections may be replaced with a single copy. If there are
+multiple Invariant Sections with the same name but different contents, make the
+title of each such section unique by adding at the end of it, in parentheses,
+the name of the original author or publisher of that section if known, or else
+a unique number. Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History" in the
+various original documents, forming one section Entitled "History"; likewise
+combine any sections Entitled "Acknowledgements", and any sections Entitled
+"Dedications". You must delete all sections Entitled "Endorsements."
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this License
+in the various documents with a single copy that is included in the collection,
+provided that you follow the rules of this License for verbatim copying of each
+of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute it
+individually under this License, provided you insert a copy of this License into
+the extracted document, and follow this License in all other respects regarding
+verbatim copying of that document.
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate and
+independent documents or works, in or on a volume of a storage or distribution
+medium, is called an "aggregate" if the copyright resulting from the compilation
+is not used to limit the legal rights of the compilation's users beyond what the
+individual works permit. When the Document is included in an aggregate, this
+License does not apply to the other works in the aggregate which are not
+themselves derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these copies of the
+Document, then if the Document is less than one half of the entire aggregate,
+the Document's Cover Texts may be placed on covers that bracket the Document
+within the aggregate, or the electronic equivalent of covers if the Document is
+in electronic form. Otherwise they must appear on printed covers that bracket
+the whole aggregate.
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may distribute
+translations of the Document under the terms of section 4. Replacing Invariant
+Sections with translations requires special permission from their copyright
+holders, but you may include translations of some or all Invariant Sections in
+addition to the original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the Document, and
+any Warranty Disclaimers, provided that you also include the original English
+version of this License and the original versions of those notices and
+disclaimers. In case of a disagreement between the translation and the original
+version of this License or a notice or disclaimer, the original version will
+prevail.
+
+If a section in the Document is Entitled "Acknowledgements", "Dedications", or
+"History", the requirement (section 4) to Preserve its Title (section 1) will
+typically require changing the actual title.
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except as
+expressly provided for under this License. Any other attempt to copy, modify,
+sublicense or distribute the Document is void, and will automatically terminate
+your rights under this License. However, parties who have received copies, or
+rights, from you under this License will not have their licenses terminated so
+long as such parties remain in full compliance.
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions of the GNU Free
+Documentation License from time to time. Such new versions will be similar in
+spirit to the present version, but may differ in detail to address new problems
+or concerns. See http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number. If the
+Document specifies that a particular numbered version of this License "or any
+later version" applies to it, you have the option of following the terms and
+conditions either of that specified version or of any later version that has
+been published (not as a draft) by the Free Software Foundation. If the Document
+does not specify a version number of this License, you may choose any version
+ever published (not as a draft) by the Free Software Foundation. How to use
+this License for your documents
+
+To use this License in a document you have written, include a copy of the
+License in the document and put the following copyright and license notices just
+after the title page:
+
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.2
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ Texts. A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace
+the "with...Texts." line with this:
+
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other combination of
+the three, merge those two alternatives to suit the situation.
+
+If your document contains nontrivial examples of program code, we recommend
+releasing these examples in parallel under your choice of free software license,
+such as the GNU General Public License, to permit their use in free software.
+
diff -Nru hedgewars-0.9.19.3/CREDITS hedgewars-0.9.20.5/CREDITS
--- hedgewars-0.9.19.3/CREDITS 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/CREDITS 2013-12-25 05:19:21.000000000 +0000
@@ -17,8 +17,7 @@
==========
- Robinator -> Terminator (2010)
- shingo666 -> Samus (2010)
-- MeinCookie95 -> InfernalHorns (2010)
-- MeinCookie95 -> Mummy (2010)
+- MeinCookie95 -> InfernalHorns (2010), Mummy (2010), war_* (2010-2011)
- thuban -> Elvis (2010)
- Miphica -> Disguise (2010)
- Blayde -> Deer (2010), Moose (2010)
diff -Nru hedgewars-0.9.19.3/ChangeLog.txt hedgewars-0.9.20.5/ChangeLog.txt
--- hedgewars-0.9.19.3/ChangeLog.txt 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/ChangeLog.txt 2013-12-25 05:19:21.000000000 +0000
@@ -1,6 +1,35 @@
+ features
* bugfixes
+0.9.19 -> 0.9.20:
+ + New campaign, A Space Adventure!
+ + Password protected rooms
+ + Shapes on drawn maps (ellipses, rectangles) - constrain dimensions with ctrl, as with straight line tool.
+ + New rubber utility, lfBouncy mask (green) for maps. lfBouncy is also anti-portal.
+ + Lazy loading of many aspects of frontend to improve startup time under Windows
+ + Set hog/team/health label defaults in config, toggle team health display using delete (left shift + delete for labels now)
+ + Usernames next to teams when playing online.
+ + Can now filter rooms by game style (such as Highlander). Filtering simplified since it is mostly unused.
+ + AFK mode. Press p when not your turn online to trigger autoskip of your turn.
+ + Russian localisation of Default voice.
+ + Map edges can wrap or bounce. Also a silly "connect to the sea" mode
+ + Sticky fire kicks you a bit less, fire interacts with frozen land/ice
+ + Generated map stays same if the template is the same between groups (all/large for example)
+ + Visual enhancements for whip and crosshair
+ + Option to draw maps with a "shoppa" border - used by ShoppaMap lua at present
+ + New hats
+ + Translation updates
+ + New lua script to control gravity. May have unpredictable effects. Try zero g shoppa. Changes to allow lua to spawn poison clouds without interrupting turn.
+ + Speech bubbles are now echoed to chat for logging purposes with the hog's name.
+ * You should now thaw on your turn, not enemy's. AI frozen/unfrozen crate movement fix. Blowtorch can thaw frozen hogs.
+ * Prevent target crosshair moving around unpredictably when doing multiple airstrikes
+ * Rope should kick along surfaces more reliably, fix rope aim speed if you miss a shot, firing rope does not freeze timer, fix aiming on last rope
+ * Remember bounce/timer in reset wep modes like Highlander
+ * Increase precision in damage calcs; extra damage affects fire properly now
+ * Fixed video recording resolution
+ * Fixed context menu/cursor in text areas
+ * Many bugfixes. Keypad enter in chat, hog sliding freezing game, team name flaws in Windows, localisation of tips, crasher in slots with no weapons, frontend holiday css.
+
0.9.18 -> 0.9.19:
+ New Freezer weapon - freezes terrain, water, hedgehogs, mines, cases, explosives
+ Saucer can aim weapons and fire underwater
@@ -59,6 +88,7 @@
+ Reduce amount of memory needed for engine to store land data
+ Countless other small fixes and improvements
+ Detect desyncs early
+ + Mudball will not cause any direct damage anymore
* Fix cake getting stuck in barrels, crates and hedgehogs
* 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
diff -Nru hedgewars-0.9.19.3/QTfrontend/CMakeLists.txt hedgewars-0.9.20.5/QTfrontend/CMakeLists.txt
--- hedgewars-0.9.19.3/QTfrontend/CMakeLists.txt 2013-06-10 07:29:43.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/CMakeLists.txt 2014-01-08 16:25:16.000000000 +0000
@@ -13,7 +13,13 @@
find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
-find_package(SDL REQUIRED) #video in SDLInteraction
+if(APPLE AND
+ ${QTVERSION} VERSION_GREATER "4.7.0" AND
+ ${QTVERSION} VERSION_LESS "4.7.4")
+ message(FATAL_ERROR "This version of QT is known *not* to work, please update or use a lower version")
+endif()
+
+find_package(SDL1or2) #video in SDLInteraction
find_package(SDL_mixer REQUIRED) #audio in SDLInteraction
if(${FFMPEG_FOUND})
@@ -55,8 +61,8 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/util/platform)
include_directories(${SDL_INCLUDE_DIR})
include_directories(${SDLMIXER_INCLUDE_DIR})
-include_directories(${PHYSFS_INCLUDE_DIR})
-include_directories(${PHYSLAYER_INCLUDE_DIR})
+include_directories(BEFORE ${PHYSFS_INCLUDE_DIR})
+include_directories(BEFORE ${PHYSLAYER_INCLUDE_DIR})
if(UNIX)
@@ -189,13 +195,8 @@
${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()
-
list(APPEND HW_LINK_LIBS
- ${PHYSFS_LIBRARY}
- ${PHYSLAYER_LIBRARY}
+ physfs physlayer
${QT_LIBRARIES}
${SDL_LIBRARY}
${SDLMIXER_LIBRARY}
diff -Nru hedgewars-0.9.19.3/QTfrontend/HWApplication.cpp hedgewars-0.9.20.5/QTfrontend/HWApplication.cpp
--- hedgewars-0.9.19.3/QTfrontend/HWApplication.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/HWApplication.cpp 2013-10-31 20:21:49.000000000 +0000
@@ -23,11 +23,11 @@
#include "hwform.h"
#include "MessageDialog.h"
-#if !defined(Q_WS_WIN)
+#if !defined(Q_OS_WIN)
#include "signal.h"
#endif
-#if !defined(Q_WS_WIN)
+#if !defined(Q_OS_WIN)
void terminateFrontend(int signal)
{
Q_UNUSED(signal);
@@ -38,7 +38,9 @@
HWApplication::HWApplication(int &argc, char **argv) :
QApplication(argc, argv)
{
-#if !defined(Q_WS_WIN)
+ form = 0;
+
+#if !defined(Q_OS_WIN)
signal(SIGINT, &terminateFrontend);
#endif
#if 0
diff -Nru hedgewars-0.9.19.3/QTfrontend/campaign.cpp hedgewars-0.9.20.5/QTfrontend/campaign.cpp
--- hedgewars-0.9.19.3/QTfrontend/campaign.cpp 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/campaign.cpp 2013-12-25 05:19:21.000000000 +0000
@@ -17,36 +17,94 @@
*/
#include "campaign.h"
-
#include "hwconsts.h"
-
+#include "DataManager.h"
#include
+#include
+#include
-
-QStringList getCampMissionList(QString & campaign)
+QList getCampMissionList(QString & campaignName, QString & teamName)
{
- 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++)
- {
- missionList += campfile.value(QString("Mission %1/Name").arg(i + 1)).toString();
- }
- return missionList;
-}
-
-unsigned int getCampProgress(QString & teamName, QString & campName)
-{
- QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + teamName + ".hwt", QSettings::IniFormat, 0);
+ QList missionInfoList;
+ QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + teamName + ".hwt", QSettings::IniFormat, 0);
teamfile.setIniCodec("UTF-8");
- return teamfile.value("Campaign " + campName + "/Progress", 0).toInt();
-}
-
-QString getCampaignScript(QString campaign, unsigned int mNum)
-{
- QSettings campfile("physfs://Missions/Campaign/" + campaign + "/campaign.ini", QSettings::IniFormat, 0);
+
+ // if entry not found check if there is written without _
+ // if then is found rename it to use _
+ QString spaceCampName = campaignName;
+ spaceCampName = spaceCampName.replace(QString("_"),QString(" "));
+ if (!teamfile.childGroups().contains("Campaign " + campaignName) and
+ teamfile.childGroups().contains("Campaign " + spaceCampName)){
+ teamfile.beginGroup("Campaign " + spaceCampName);
+ QStringList keys = teamfile.childKeys();
+ teamfile.endGroup();
+ for (int i=0;i=0 and unlockedMissions==0)
+ {
+ for(unsigned int i=progress+1;i>0;i--)
+ {
+ MissionInfo missionInfo;
+ missionInfo.name = campfile.value(QString("Mission %1/Name").arg(i)).toString();
+ QString script = campfile.value(QString("Mission %1/Script").arg(i)).toString();
+ missionInfo.script = script;
+ missionInfo.description = m_info.value(campaignName+"-"+ script.replace(QString(".lua"),QString("")) + ".desc",
+ QObject::tr("No description available")).toString();
+ QString image = campfile.value(QString("Mission %1/Script").arg(i)).toString().replace(QString(".lua"),QString(".png"));
+ missionInfo.image = ":/res/campaign/"+campaignName+"/"+image;
+ if (!QFile::exists(missionInfo.image))
+ missionInfo.image = ":/res/CampaignDefault.png";
+ missionInfoList.append(missionInfo);
+ }
+ }
+ else if(unlockedMissions>0)
+ {
+ for(int i=1;i<=unlockedMissions;i++)
+ {
+ QString missionNum = QString("%1").arg(i);
+ int missionNumber = teamfile.value("Campaign " + campaignName + "/Mission"+missionNum, -1).toInt();
+ MissionInfo missionInfo;
+ missionInfo.name = campfile.value(QString("Mission %1/Name").arg(missionNumber)).toString();
+ QString script = campfile.value(QString("Mission %1/Script").arg(missionNumber)).toString();
+ missionInfo.script = script;
+ missionInfo.description = m_info.value(campaignName+"-"+ script.replace(QString(".lua"),QString("")) + ".desc",
+ QObject::tr("No description available")).toString();
+ QString image = campfile.value(QString("Mission %1/Script").arg(missionNumber)).toString().replace(QString(".lua"),QString(".png"));
+ missionInfo.image = ":/res/campaign/"+campaignName+"/"+image;
+ if (!QFile::exists(missionInfo.image))
+ missionInfo.image = ":/res/CampaignDefault.png";
+ missionInfoList.append(missionInfo);
+ }
+ }
+ return missionInfoList;
}
diff -Nru hedgewars-0.9.19.3/QTfrontend/campaign.h hedgewars-0.9.20.5/QTfrontend/campaign.h
--- hedgewars-0.9.19.3/QTfrontend/campaign.h 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/campaign.h 2013-10-31 20:21:50.000000000 +0000
@@ -20,10 +20,16 @@
#define CAMPAIGN_H
#include
-#include
-QStringList getCampMissionList(QString & campaign);
-unsigned int getCampProgress(QString & teamName, QString & campName);
-QString getCampaignScript(QString campaign, unsigned int mNum);
+class MissionInfo
+{
+ public:
+ QString name;
+ QString description;
+ QString script;
+ QString image;
+};
+
+QList getCampMissionList(QString & campaignName, QString & teamName);
#endif
diff -Nru hedgewars-0.9.19.3/QTfrontend/drawmapscene.cpp hedgewars-0.9.20.5/QTfrontend/drawmapscene.cpp
--- hedgewars-0.9.19.3/QTfrontend/drawmapscene.cpp 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/drawmapscene.cpp 2014-01-08 16:26:48.000000000 +0000
@@ -20,6 +20,8 @@
#include
#include
#include
+#include
+#include
#include "drawmapscene.h"
@@ -44,6 +46,8 @@
setBackgroundBrush(m_eraser);
m_isErasing = false;
+ m_pathType = Polyline;
+
m_pen.setWidth(76);
m_pen.setJoinStyle(Qt::RoundJoin);
m_pen.setCapStyle(Qt::RoundCap);
@@ -60,19 +64,45 @@
if(m_currPath && (mouseEvent->buttons() & Qt::LeftButton))
{
QPainterPath path = m_currPath->path();
+ QPointF currentPos = mouseEvent->scenePos();
if(mouseEvent->modifiers() & Qt::ControlModifier)
+ currentPos = putSomeConstraints(paths.first().initialPoint, currentPos);
+
+ switch (m_pathType)
{
- int c = path.elementCount();
- QPointF pos = mouseEvent->scenePos();
- path.setElementPositionAt(c - 1, pos.x(), pos.y());
+ case Polyline:
+ if(mouseEvent->modifiers() & Qt::ControlModifier)
+ {
+ int c = path.elementCount();
+ path.setElementPositionAt(c - 1, currentPos.x(), currentPos.y());
+ }
+ else
+ {
+ path.lineTo(currentPos);
+ paths.first().points.append(mouseEvent->scenePos().toPoint());
+ }
+ break;
+ case Rectangle: {
+ path = QPainterPath();
+ QPointF p1 = paths.first().initialPoint;
+ QPointF p2 = currentPos;
+ path.moveTo(p1);
+ path.lineTo(p1.x(), p2.y());
+ path.lineTo(p2);
+ path.lineTo(p2.x(), p1.y());
+ path.lineTo(p1);
+ break;
+ }
+ case Ellipse: {
+ path = QPainterPath();
+ QList points = makeEllipse(paths.first().initialPoint, currentPos);
+ path.addPolygon(QPolygonF(QVector::fromList(points)));
+ break;
}
- else
- {
- path.lineTo(mouseEvent->scenePos());
- paths.first().points.append(mouseEvent->scenePos().toPoint());
}
+
m_currPath->setPath(path);
emit pathChanged();
@@ -96,7 +126,8 @@
PathParams params;
params.width = serializePenWidth(m_pen.width());
params.erasing = m_isErasing;
- params.points = QList() << mouseEvent->scenePos().toPoint();
+ params.initialPoint = mouseEvent->scenePos().toPoint();
+ params.points = QList() << params.initialPoint;
paths.prepend(params);
m_currPath->setPath(path);
@@ -107,14 +138,43 @@
{
if (m_currPath)
{
- QPainterPath path = m_currPath->path();
- path.lineTo(mouseEvent->scenePos());
- paths.first().points.append(mouseEvent->scenePos().toPoint());
- m_currPath->setPath(path);
+ QPointF currentPos = mouseEvent->scenePos();
- simplifyLast();
+ if(mouseEvent->modifiers() & Qt::ControlModifier)
+ currentPos = putSomeConstraints(paths.first().initialPoint, currentPos);
+
+ switch (m_pathType)
+ {
+ case Polyline: {
+ QPainterPath path = m_currPath->path();
+ path.lineTo(mouseEvent->scenePos());
+ paths.first().points.append(currentPos.toPoint());
+ m_currPath->setPath(path);
+ simplifyLast();
+ break;
+ }
+ case Rectangle: {
+ QPoint p1 = paths.first().initialPoint;
+ QPoint p2 = currentPos.toPoint();
+ QList rpoints;
+ rpoints << p1 << QPoint(p1.x(), p2.y()) << p2 << QPoint(p2.x(), p1.y()) << p1;
+ paths.first().points = rpoints;
+ break;
+ }
+ case Ellipse:
+ QPoint p1 = paths.first().initialPoint;
+ QPoint p2 = currentPos.toPoint();
+ QList points = makeEllipse(p1, p2);
+ QList epoints;
+ foreach(const QPointF & p, points)
+ epoints.append(p.toPoint());
+ paths.first().points = epoints;
+ break;
+ }
m_currPath = 0;
+
+ emit pathChanged();
}
}
@@ -156,7 +216,7 @@
if(m_isCursorShown)
return;
- if(items().size())
+ if(paths.size())
{
removeItem(items().first());
paths.removeFirst();
@@ -183,15 +243,18 @@
if(!items().size())
return;
+ m_specialPoints.clear();
oldItems.clear();
// do this since clear() would _destroy_ all items
- while(items().size())
+ for(int i = paths.size() - 1; i >= 0; --i)
{
oldItems.push_front(items().first());
removeItem(items().first());
}
+ items().clear();
+
oldPaths = paths;
paths.clear();
@@ -211,7 +274,7 @@
QByteArray DrawMapScene::encode()
{
- QByteArray b;
+ QByteArray b(m_specialPoints);
for(int i = paths.size() - 1; i >= 0; --i)
{
@@ -247,9 +310,12 @@
oldPaths.clear();
clear();
paths.clear();
+ m_specialPoints.clear();
PathParams params;
+ bool isSpecial = true;
+
while(data.size() >= 5)
{
qint16 px = qFromBigEndian(*(qint16 *)data.data());
@@ -258,9 +324,11 @@
data.remove(0, 2);
quint8 flags = *(quint8 *)data.data();
data.remove(0, 1);
-
+ qDebug() << px << py;
if(flags & 0x80)
{
+ isSpecial = false;
+
if(params.points.size())
{
addPath(pointsToPath(params.points), m_pen);
@@ -278,9 +346,23 @@
else
m_pen.setBrush(m_brush);
params.width = penWidth;
- }
+ } else
+ if(isSpecial)
+ {
+ QPainterPath path;
+ path.addEllipse(QPointF(px, py), 10, 10);
- params.points.append(QPoint(px, py));
+ addPath(path);
+
+ qint16 x = qToBigEndian(px);
+ qint16 y = qToBigEndian(py);
+ m_specialPoints.append((const char *)&x, 2);
+ m_specialPoints.append((const char *)&y, 2);
+ m_specialPoints.append((const char *)&flags, 1);
+ }
+
+ if(!isSpecial)
+ params.points.append(QPoint(px, py));
}
if(params.points.size())
@@ -323,8 +405,6 @@
QGraphicsPathItem * pathItem = static_cast(items()[m_isCursorShown ? 1 : 0]);
pathItem->setPath(pointsToPath(paths[0].points));
}
-
- emit pathChanged();
}
int DrawMapScene::pointsCount()
@@ -361,3 +441,47 @@
{
return width * 10 + 6;
}
+
+void DrawMapScene::setPathType(PathType pathType)
+{
+ m_pathType = pathType;
+}
+
+QList DrawMapScene::makeEllipse(const QPointF ¢er, const QPointF &corner)
+{
+ QList l;
+ qreal rx = qAbs(center.x() - corner.x());
+ qreal ry = qAbs(center.y() - corner.y());
+ qreal r = qMax(rx, ry);
+
+ if(r < 4)
+ {
+ l.append(center);
+ } else
+ {
+ qreal angleDelta = qMax(static_cast (0.1), qMin(static_cast (0.7), 120 / r));
+ for(qreal angle = 0.0; angle < 2*M_PI; angle += angleDelta)
+ l.append(center + QPointF(rx * cos(angle), ry * sin(angle)));
+ l.append(l.first());
+ }
+
+ return l;
+}
+
+QPointF DrawMapScene::putSomeConstraints(const QPointF &initialPoint, const QPointF &point)
+{
+ QPointF vector = point - initialPoint;
+
+ for(int angle = 0; angle < 180; angle += 15)
+ {
+ QTransform transform;
+ transform.rotate(angle);
+
+ QPointF rotated = transform.map(vector);
+
+ if(rotated.x() == 0) return point;
+ if(qAbs(rotated.y() / rotated.x()) < 0.05) return initialPoint + transform.inverted().map(QPointF(rotated.x(), 0));
+ }
+
+ return point;
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/drawmapscene.h hedgewars-0.9.20.5/QTfrontend/drawmapscene.h
--- hedgewars-0.9.19.3/QTfrontend/drawmapscene.h 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/drawmapscene.h 2013-10-31 20:21:50.000000000 +0000
@@ -29,6 +29,7 @@
{
quint8 width;
bool erasing;
+ QPoint initialPoint;
QList points;
};
@@ -38,6 +39,12 @@
{
Q_OBJECT
public:
+ enum PathType {
+ Polyline = 0,
+ Rectangle = 1,
+ Ellipse = 2
+ };
+
explicit DrawMapScene(QObject *parent = 0);
QByteArray encode();
@@ -54,6 +61,7 @@
void setErasing(bool erasing);
void showCursor();
void hideCursor();
+ void setPathType(PathType pathType);
private:
QPen m_pen;
@@ -66,6 +74,8 @@
QList oldItems;
QGraphicsEllipseItem * m_cursor;
bool m_isCursorShown;
+ QByteArray m_specialPoints;
+ PathType m_pathType;
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent);
virtual void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent);
@@ -76,6 +86,8 @@
quint8 serializePenWidth(int width);
int deserializePenWidth(quint8 width);
+ QList makeEllipse(const QPointF & center, const QPointF & corner);
+ QPointF putSomeConstraints(const QPointF & initialPoint, const QPointF & point);
};
#endif // DRAWMAPSCENE_H
diff -Nru hedgewars-0.9.19.3/QTfrontend/game.cpp hedgewars-0.9.20.5/QTfrontend/game.cpp
--- hedgewars-0.9.19.3/QTfrontend/game.cpp 2013-06-11 07:16:49.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/game.cpp 2014-01-08 16:25:16.000000000 +0000
@@ -17,6 +17,7 @@
*/
#include
+#include
#include
#include
#include
@@ -88,18 +89,6 @@
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;
@@ -117,8 +106,6 @@
}
HWProto::addStringToBuffer(buf, gt);
- addKeyBindings(&buf);
-
buf += gamecfg->getFullConfig();
if (m_pTeamSelWidget)
@@ -131,7 +118,7 @@
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(), config));
+ team.teamGameConfig(gamecfg->getInitHealth()));
;
}
}
@@ -149,8 +136,6 @@
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(ThemeModel::ActualNameRole).toString() : "steel"));
@@ -164,7 +149,7 @@
team1.setNumHedgehogs(4);
HWNamegen::teamRandomNames(team1,true);
HWProto::addStringListToBuffer(teamscfg,
- team1.teamGameConfig(100, config));
+ team1.teamGameConfig(100));
HWTeam team2;
team2.setDifficulty(4);
@@ -174,7 +159,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, config));
+ team2.teamGameConfig(100));
HWProto::addStringToBuffer(teamscfg, QString("eammloadt %1").arg(cDefaultAmmoStore->mid(0, cAmmoNumber)));
HWProto::addStringToBuffer(teamscfg, QString("eammprob %1").arg(cDefaultAmmoStore->mid(cAmmoNumber, cAmmoNumber)));
@@ -193,8 +178,6 @@
HWProto::addStringToBuffer(traincfg, "eseed " + QUuid::createUuid().toString());
HWProto::addStringToBuffer(traincfg, "escript " + training);
- addKeyBindings(&traincfg);
-
RawSendIPC(traincfg);
}
@@ -206,8 +189,6 @@
HWProto::addStringToBuffer(campaigncfg, "escript " + campaignScript);
- addKeyBindings(&campaigncfg);
-
RawSendIPC(campaigncfg);
}
@@ -415,6 +396,15 @@
arguments << nick;
}
+ if (!config->Form->ui.pageOptions->CBTeamTag->isChecked())
+ arguments << "--no-teamtag";
+ if (!config->Form->ui.pageOptions->CBHogTag->isChecked())
+ arguments << "--no-hogtag";
+ if (!config->Form->ui.pageOptions->CBHealthTag->isChecked())
+ arguments << "--no-healthtag";
+ if (config->Form->ui.pageOptions->CBTagOpacity->isChecked())
+ arguments << "--translucent-tags";
+
return arguments;
}
@@ -516,7 +506,7 @@
void HWGame::sendCampaignVar(const QByteArray &varToSend)
{
- QString varToFind(varToSend);
+ QString varToFind = QString::fromUtf8(varToSend);
QSettings teamfile(QString("physfs://Teams/%1.hwt").arg(campaignTeam), QSettings::IniFormat, 0);
teamfile.setIniCodec("UTF-8");
QString varValue = teamfile.value("Campaign " + campaign + "/" + varToFind, "").toString();
diff -Nru hedgewars-0.9.19.3/QTfrontend/game.h hedgewars-0.9.20.5/QTfrontend/game.h
--- hedgewars-0.9.19.3/QTfrontend/game.h 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/game.h 2013-10-31 20:21:52.000000000 +0000
@@ -113,7 +113,6 @@
GameType gameType;
QByteArray m_netSendBuffer;
- void addKeyBindings(QByteArray * buf);
void commonConfig();
void SendConfig();
void SendQuickConfig();
diff -Nru hedgewars-0.9.19.3/QTfrontend/gameuiconfig.cpp hedgewars-0.9.20.5/QTfrontend/gameuiconfig.cpp
--- hedgewars-0.9.19.3/QTfrontend/gameuiconfig.cpp 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/gameuiconfig.cpp 2014-01-08 16:25:16.000000000 +0000
@@ -139,9 +139,14 @@
Form->ui.pageOptions->CBShowFPS->setChecked(value("fps/show", false).toBool());
Form->ui.pageOptions->fpsedit->setValue(value("fps/limit", 27).toUInt());
- Form->ui.pageOptions->CBAltDamage->setChecked(value("misc/altdamage", false).toBool());
+ Form->ui.pageOptions->CBAltDamage->setChecked(value("misc/altdamage", true).toBool());
Form->ui.pageOptions->CBNameWithDate->setChecked(value("misc/appendTimeToRecords", false).toBool());
+ Form->ui.pageOptions->CBTeamTag->setChecked(value("misc/teamtag", true).toBool());
+ Form->ui.pageOptions->CBHogTag->setChecked(value("misc/hogtag", true).toBool());
+ Form->ui.pageOptions->CBHealthTag->setChecked(value("misc/healthtag", true).toBool());
+ Form->ui.pageOptions->CBTagOpacity->setChecked(value("misc/tagopacity", false).toBool());
+
#ifdef SPARKLE_ENABLED
Form->ui.pageOptions->CBAutoUpdate->setChecked(value("misc/autoUpdate", true).toBool());
#endif
@@ -154,6 +159,8 @@
Form->ui.pageOptions->leProxyLogin->setText(value("proxy/login", "").toString());
Form->ui.pageOptions->leProxyPassword->setText(value("proxy/password", "").toString());
+ applyProxySettings();
+
{ // load colors
QStandardItemModel * model = DataManager::instance().colorsModel();
for(int i = model->rowCount() - 1; i >= 0; --i)
@@ -280,6 +287,12 @@
setValue("fps/limit", Form->ui.pageOptions->fpsedit->value());
setValue("misc/altdamage", isAltDamageEnabled());
+
+ setValue("misc/teamtag", Form->ui.pageOptions->CBTeamTag->isChecked());
+ setValue("misc/hogtag", Form->ui.pageOptions->CBHogTag->isChecked());
+ setValue("misc/healthtag", Form->ui.pageOptions->CBHealthTag->isChecked());
+ setValue("misc/tagopacity",Form->ui.pageOptions->CBTagOpacity->isChecked());
+
setValue("misc/appendTimeToRecords", appendDateTimeToRecordName());
setValue("misc/locale", language());
@@ -299,22 +312,7 @@
setValue("proxy/password", Form->ui.pageOptions->leProxyPassword->text());
}
- QNetworkProxy proxy;
-
- if(proxyType == PageOptions::SystemProxy)
- {
- // use system proxy settings
- proxy = QNetworkProxyFactory::systemProxyForQuery().at(0);
- } else
- {
- proxy.setType(proxyTypesMap[proxyType]);
- proxy.setHostName(Form->ui.pageOptions->leProxy->text());
- proxy.setPort(Form->ui.pageOptions->sbProxyPort->value());
- proxy.setUser(Form->ui.pageOptions->leProxyLogin->text());
- proxy.setPassword(Form->ui.pageOptions->leProxyPassword->text());
- }
-
- QNetworkProxy::setApplicationProxy(proxy);
+ applyProxySettings();
}
{ // save colors
@@ -654,3 +652,25 @@
m_binds[bindID].strbind = strbind;
setValue(QString("Binds/%1").arg(m_binds[bindID].action), strbind);
}
+
+void GameUIConfig::applyProxySettings()
+{
+ QNetworkProxy proxy;
+
+ int proxyType = Form->ui.pageOptions->cbProxyType->currentIndex();
+
+ if(proxyType == PageOptions::SystemProxy)
+ {
+ // use system proxy settings
+ proxy = QNetworkProxyFactory::systemProxyForQuery().at(0);
+ } else
+ {
+ proxy.setType(proxyTypesMap[proxyType]);
+ proxy.setHostName(Form->ui.pageOptions->leProxy->text());
+ proxy.setPort(Form->ui.pageOptions->sbProxyPort->value());
+ proxy.setUser(Form->ui.pageOptions->leProxyLogin->text());
+ proxy.setPassword(Form->ui.pageOptions->leProxyPassword->text());
+ }
+
+ QNetworkProxy::setApplicationProxy(proxy);
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/gameuiconfig.h hedgewars-0.9.20.5/QTfrontend/gameuiconfig.h
--- hedgewars-0.9.19.3/QTfrontend/gameuiconfig.h 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/gameuiconfig.h 2014-01-08 16:25:16.000000000 +0000
@@ -99,6 +99,8 @@
bool eventFilter(QObject *object, QEvent *event);
QString temphash;
QList m_binds;
+
+ void applyProxySettings();
};
#endif
diff -Nru hedgewars-0.9.19.3/QTfrontend/hedgewars.qrc hedgewars-0.9.20.5/QTfrontend/hedgewars.qrc
--- hedgewars-0.9.19.3/QTfrontend/hedgewars.qrc 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/hedgewars.qrc 2013-12-25 05:19:21.000000000 +0000
@@ -28,12 +28,37 @@
res/botlevels/net3.png
res/botlevels/net4.png
res/botlevels/net5.png
+ res/campaign/A_Classic_Fairytale/first_blood.png
+ res/campaign/A_Classic_Fairytale/shadow.png
+ res/campaign/A_Classic_Fairytale/journey.png
+ res/campaign/A_Classic_Fairytale/united.png
+ res/campaign/A_Classic_Fairytale/backstab.png
+ res/campaign/A_Classic_Fairytale/dragon.png
+ res/campaign/A_Classic_Fairytale/family.png
+ res/campaign/A_Classic_Fairytale/queen.png
+ res/campaign/A_Classic_Fairytale/enemy.png
+ res/campaign/A_Classic_Fairytale/epil.png
+ res/campaign/A_Space_Adventure/cosmos.png
+ res/campaign/A_Space_Adventure/moon01.png
+ res/campaign/A_Space_Adventure/moon02.png
+ res/campaign/A_Space_Adventure/ice01.png
+ res/campaign/A_Space_Adventure/ice02.png
+ res/campaign/A_Space_Adventure/desert01.png
+ res/campaign/A_Space_Adventure/desert02.png
+ res/campaign/A_Space_Adventure/desert03.png
+ res/campaign/A_Space_Adventure/fruit01.png
+ res/campaign/A_Space_Adventure/fruit02.png
+ res/campaign/A_Space_Adventure/fruit03.png
+ res/campaign/A_Space_Adventure/death01.png
+ res/campaign/A_Space_Adventure/death02.png
+ res/campaign/A_Space_Adventure/final.png
res/bonus.png
res/Hedgehog.png
res/net.png
res/About.png
res/SimpleGame.png
res/Campaign.png
+ res/CampaignDefault.png
res/Multiplayer.png
res/Trainings.png
res/Background.png
@@ -103,6 +128,7 @@
res/iconMine.png
res/iconDud.png
res/iconRope.png
+ res/iconEarth.png
res/dice.png
res/Star.png
res/inverse-corner-bl.png
@@ -133,6 +159,7 @@
res/StatsMostSelfDamage.png
res/StatsSelfKilled.png
res/StatsSkipped.png
+ res/StatsCustomAchievement.png
res/Start.png
res/mapRandom.png
res/mapMaze.png
@@ -152,6 +179,9 @@
res/chat/ingame.png
res/splash.png
res/html/about.html
- res/xml/tips.xml
+ res/chat/hedgehogcontributor.png
+ res/chat/hedgehogcontributor_gray.png
+ res/chat/roomadmincontributor.png
+ res/chat/roomadmincontributor_gray.png
diff -Nru hedgewars-0.9.19.3/QTfrontend/hwform.cpp hedgewars-0.9.20.5/QTfrontend/hwform.cpp
--- hedgewars-0.9.19.3/QTfrontend/hwform.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/hwform.cpp 2014-01-08 16:25:16.000000000 +0000
@@ -102,7 +102,7 @@
#include "DataManager.h"
#include "AutoUpdater.h"
-#ifdef Q_WS_WIN
+#ifdef Q_OS_WIN
#define WINVER 0x0500
#include
#else
@@ -110,7 +110,7 @@
#include
#endif
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
#include
#endif
@@ -165,14 +165,13 @@
#endif
#ifdef __APPLE__
- AutoUpdater* updater = NULL;
if (config->isAutoUpdateEnabled())
{
-#ifdef __APPLE__
+ AutoUpdater* updater = NULL;
+
#ifdef SPARKLE_ENABLED
updater = new SparkleAutoUpdater();
#endif
-#endif
if (updater)
{
updater->checkForUpdates();
@@ -194,9 +193,12 @@
//connect (updateData, SIGNAL(activated()), &DataManager::instance(), SLOT(reload()));
#endif
+ previousCampaignName = "";
+ previousTeamName = "";
UpdateTeamsLists();
InitCampaignPage();
UpdateCampaignPage(0);
+ UpdateCampaignPageMission(0);
UpdateWeapons();
// connect all goBack signals
@@ -304,9 +306,10 @@
connect(ui.pageTraining, SIGNAL(startMission(const QString&)), this, SLOT(startTraining(const QString&)));
connect(ui.pageCampaign->BtnStartCampaign, SIGNAL(clicked()), this, SLOT(StartCampaign()));
+ connect(ui.pageCampaign->btnPreview, SIGNAL(clicked()), this, SLOT(StartCampaign()));
connect(ui.pageCampaign->CBTeam, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPage(int)));
connect(ui.pageCampaign->CBCampaign, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPage(int)));
-
+ connect(ui.pageCampaign->CBMission, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPageMission(int)));
connect(ui.pageSelectWeapon->BtnDelete, SIGNAL(clicked()),
ui.pageSelectWeapon->pWeapons, SLOT(deleteWeaponsName())); // executed first
@@ -595,7 +598,9 @@
updateXfire();
#endif
+#ifdef QT_DEBUG
qDebug("Leaving %s, entering %s", qPrintable(stringifyPageId(lastid)), qPrintable(stringifyPageId(id)));
+#endif
if (lastid == ID_PAGE_MAIN)
{
ui.pageMain->resetNetworkChoice();
@@ -654,7 +659,7 @@
}
QList teamsList;
- for (QStringList::iterator it = tmNames.begin(); it != tmNames.end(); it++)
+ for (QStringList::iterator it = tmNames.begin(); it != tmNames.end(); ++it)
{
HWTeam team(*it);
team.loadFromFile();
@@ -700,7 +705,7 @@
void HWForm::GoToPage(int id)
{
- bool stopAnim = false;
+ //bool stopAnim = false;
int lastid = ui.Pages->currentIndex();
PagesStack.push(ui.Pages->currentIndex());
@@ -717,7 +722,7 @@
#if (QT_VERSION >= 0x040600)
- if (!stopAnim)
+ //if (!stopAnim)
{
/**Start animation :**/
int coeff = 1;
@@ -813,7 +818,7 @@
stopAnim = true; */
if ((!hwnet) || (!hwnet->isInRoom()))
- if (id == ID_PAGE_NETGAME || id == ID_PAGE_NETGAME)
+ if (id == ID_PAGE_NETGAME)
{
stopAnim = true;
GoBack();
@@ -1125,7 +1130,7 @@
//ForcedDisconnect(tr("No nickname supplied."));
bool retry = RetryDialog(tr("Hedgewars - Empty nickname"), tr("No nickname supplied."));
GoBack();
- if (retry) {
+ if (retry && hwnet) {
if (hwnet->m_private_game) {
QStringList list = hwnet->getHost().split(":");
NetConnectServer(list.at(0), list.at(1).toShort());
@@ -1135,7 +1140,8 @@
return;
}
- hwnet->NewNick(newNick);
+ if(hwnet)
+ hwnet->NewNick(newNick);
config->setValue("net/nick", newNick);
config->updNetNick();
@@ -1159,6 +1165,13 @@
}
}
+void HWForm::askRoomPassword()
+{
+ QString password = QInputDialog::getText(this, tr("Room password"), tr("The room is protected with password.\nPlease, enter the password:"));
+ if(hwnet && !password.isEmpty())
+ hwnet->roomPasswordEntered(password);
+}
+
bool HWForm::RetryDialog(const QString & title, const QString & label)
{
QMessageBox retryMsg(this);
@@ -1238,6 +1251,7 @@
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()));
+ connect(hwnet, SIGNAL(askForRoomPassword()), this, SLOT(askRoomPassword()), Qt::QueuedConnection);
ui.pageRoomsList->chatWidget->setUsersModel(hwnet->lobbyPlayersModel());
ui.pageNetGame->chatWidget->setUsersModel(hwnet->roomPlayersModel());
@@ -1252,10 +1266,10 @@
connect(hwnet, SIGNAL(serverMessage(const QString&)),
ui.pageRoomsList->chatWidget, SLOT(onServerMessage(const QString&)), Qt::QueuedConnection);
- connect(ui.pageRoomsList, SIGNAL(askForCreateRoom(const QString &)),
- hwnet, SLOT(CreateRoom(const QString&)));
- connect(ui.pageRoomsList, SIGNAL(askForJoinRoom(const QString &)),
- hwnet, SLOT(JoinRoom(const QString&)));
+ connect(ui.pageRoomsList, SIGNAL(askForCreateRoom(const QString &, const QString &)),
+ hwnet, SLOT(CreateRoom(const QString&, const QString &)));
+ connect(ui.pageRoomsList, SIGNAL(askForJoinRoom(const QString &, const QString &)),
+ hwnet, SLOT(JoinRoom(const QString&, const QString &)));
// connect(ui.pageRoomsList, SIGNAL(askForCreateRoom(const QString &)),
// this, SLOT(NetGameMaster()));
// connect(ui.pageRoomsList, SIGNAL(askForJoinRoom(const QString &)),
@@ -1717,13 +1731,9 @@
void HWForm::StartCampaign()
{
CreateGame(0, 0, 0);
-
- QComboBox *combo = ui.pageCampaign->CBMission;
- QString camp = ui.pageCampaign->CBCampaign->currentText();
- unsigned int mNum = combo->count() - combo->currentIndex();
- QString miss = getCampaignScript(camp, mNum);
+ QString camp = ui.pageCampaign->CBCampaign->currentText().replace(QString(" "),QString("_"));
+ QString miss = campaignMissionInfo[ui.pageCampaign->CBMission->currentIndex()].script;
QString campTeam = ui.pageCampaign->CBTeam->currentText();
-
game->StartCampaign(camp, miss, campTeam);
}
@@ -1884,27 +1894,36 @@
unsigned int n = entries.count();
for(unsigned int i = 0; i < n; i++)
{
- ui.pageCampaign->CBCampaign->addItem(QString(entries[i]), QString(entries[i]));
+ ui.pageCampaign->CBCampaign->addItem(QString(entries[i]).replace(QString("_"),QString(" ")), QString(entries[i]).replace(QString("_"),QString(" ")));
}
}
-
void HWForm::UpdateCampaignPage(int index)
{
Q_UNUSED(index);
-
HWTeam team(ui.pageCampaign->CBTeam->currentText());
- ui.pageCampaign->CBMission->clear();
-
- QString campaignName = ui.pageCampaign->CBCampaign->currentText();
- QStringList missionEntries = getCampMissionList(campaignName);
- QString tName = team.name();
- unsigned int n = missionEntries.count();
- unsigned int m = getCampProgress(tName, campaignName);
-
- for (unsigned int i = qMin(m + 1, n); i > 0; i--)
- {
- ui.pageCampaign->CBMission->addItem(QString("Mission %1: ").arg(i) + QString(missionEntries[i-1]), QString(missionEntries[i-1]));
+ QString campaignName = ui.pageCampaign->CBCampaign->currentText().replace(QString(" "),QString("_"));
+ QString tName = team.name();
+
+ campaignMissionInfo = getCampMissionList(campaignName,tName);
+ ui.pageCampaign->CBMission->clear();
+
+ for(int i=0;iCBMission->addItem(QString(campaignMissionInfo[i].name), QString(campaignMissionInfo[i].name));
+ }
+}
+
+void HWForm::UpdateCampaignPageMission(int index)
+{
+ // update thumbnail and description
+ QString campaignName = ui.pageCampaign->CBCampaign->currentText().replace(QString(" "),QString("_"));
+ // when campaign changes the UpdateCampaignPageMission is triggered with wrong values
+ // this will cause segfault. This check prevents illegal memory reads
+ if(index > -1 && index < campaignMissionInfo.count()) {
+ ui.pageCampaign->lbltitle->setText(""+ui.pageCampaign->CBMission->currentText()+" ");
+ ui.pageCampaign->lbldescription->setText(campaignMissionInfo[index].description);
+ ui.pageCampaign->btnPreview->setIcon(QIcon(campaignMissionInfo[index].image));
}
}
@@ -1912,9 +1931,16 @@
{
Q_UNUSED(index);
- int missionIndex = ui.pageCampaign->CBMission->currentIndex();
+ QString missionTitle = ui.pageCampaign->CBMission->currentText();
UpdateCampaignPage(0);
- ui.pageCampaign->CBMission->setCurrentIndex(missionIndex);
+ for(int i=0;iCBMission->count();i++)
+ {
+ if (ui.pageCampaign->CBMission->itemText(i)==missionTitle)
+ {
+ ui.pageCampaign->CBMission->setCurrentIndex(i);
+ break;
+ }
+ }
}
// 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]
@@ -1923,7 +1949,7 @@
QString prefix = "\"" + datadir->absolutePath() + "\"";
QString userPrefix = "\"" + cfgdir->absolutePath() + "\"";
-#ifdef Q_WS_WIN
+#ifdef Q_OS_WIN
prefix = prefix.replace("/","\\");
userPrefix = userPrefix.replace("/","\\");
#endif
@@ -1943,7 +1969,11 @@
+ (config->isShowFPSEnabled() ? " --showfps" : "")
+ (config->isAltDamageEnabled() ? " --altdmg" : "")
+ " --frame-interval " + QString::number(config->timerInterval())
- + " --raw-quality " + QString::number(config->translateQuality()));
+ + " --raw-quality " + QString::number(config->translateQuality()))
+ + (!config->Form->ui.pageOptions->CBTeamTag->isChecked() ? " --no-teamtag" : "")
+ + (!config->Form->ui.pageOptions->CBHogTag->isChecked() ? " --no-hogtag" : "")
+ + (!config->Form->ui.pageOptions->CBHealthTag->isChecked() ? " --no-healthtag" : "")
+ + (config->Form->ui.pageOptions->CBTagOpacity->isChecked() ? " --translucent-tags" : "");
}
void HWForm::AssociateFiles()
diff -Nru hedgewars-0.9.19.3/QTfrontend/hwform.h hedgewars-0.9.20.5/QTfrontend/hwform.h
--- hedgewars-0.9.19.3/QTfrontend/hwform.h 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/hwform.h 2014-01-08 16:25:16.000000000 +0000
@@ -34,6 +34,7 @@
#include "ui_hwform.h"
#include "SDLInteraction.h"
#include "bgwidget.h"
+#include "campaign.h"
#ifdef __APPLE__
#include "InstallController.h"
@@ -111,6 +112,7 @@
void NetNickNotRegistered(const QString & nick);
void NetNickTaken(const QString & nick);
void NetAuthFailed();
+ void askRoomPassword();
bool RetryDialog(const QString & title, const QString & label);
void NetTeamAccepted(const QString& team);
void AddNetTeam(const HWTeam& team);
@@ -127,6 +129,7 @@
void Music(bool checked);
void UpdateCampaignPage(int index);
void UpdateCampaignPageProgress(int index);
+ void UpdateCampaignPageMission(int index);
void InitCampaignPage();
void showFeedbackDialog();
void showFeedbackDialogNetChecked();
@@ -192,6 +195,9 @@
HWNamegen * namegen;
AmmoSchemeModel * ammoSchemeModel;
QStack PagesStack;
+ QString previousCampaignName;
+ QString previousTeamName;
+ QList campaignMissionInfo;
QTime eggTimer;
BGWidget * wBackground;
QSignalMapper * pageSwitchMapper;
diff -Nru hedgewars-0.9.19.3/QTfrontend/main.cpp hedgewars-0.9.20.5/QTfrontend/main.cpp
--- hedgewars-0.9.19.3/QTfrontend/main.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/main.cpp 2013-10-31 20:21:53.000000000 +0000
@@ -135,7 +135,7 @@
HWApplication app(argc, argv);
QLabel *splash = NULL;
-#if defined Q_WS_WIN
+#if defined Q_OS_WIN
QPixmap pixmap(":res/splash.png");
splash = new QLabel(0, Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
splash->setAttribute(Qt::WA_TranslucentBackground);
diff -Nru hedgewars-0.9.19.3/QTfrontend/model/HatModel.cpp hedgewars-0.9.20.5/QTfrontend/model/HatModel.cpp
--- hedgewars-0.9.19.3/QTfrontend/model/HatModel.cpp 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/model/HatModel.cpp 2013-12-25 05:19:21.000000000 +0000
@@ -37,6 +37,8 @@
void HatModel::loadHats()
{
+ qDebug("HatModel::loadHats()");
+
// this method resets the contents of this model (important to know for views).
QStandardItemModel::beginResetModel();
QStandardItemModel::clear();
diff -Nru hedgewars-0.9.19.3/QTfrontend/model/MapModel.cpp hedgewars-0.9.20.5/QTfrontend/model/MapModel.cpp
--- hedgewars-0.9.19.3/QTfrontend/model/MapModel.cpp 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/model/MapModel.cpp 2013-12-25 05:19:21.000000000 +0000
@@ -28,12 +28,26 @@
#include "HWApplication.h"
#include "hwconsts.h"
-MapModel::MapInfo MapModel::MapInfoRandom = {MapModel::GeneratedMap, "+rnd+", "", 0, "", "", ""};
-MapModel::MapInfo MapModel::MapInfoMaze = {MapModel::GeneratedMaze, "+maze+", "", 0, "", "", ""};
-MapModel::MapInfo MapModel::MapInfoDrawn = {MapModel::HandDrawnMap, "+drawn+", "", 0, "", "", ""};
+MapModel::MapInfo MapModel::MapInfoRandom = {MapModel::GeneratedMap, "+rnd+", "", 0, "", "", "", false};
+MapModel::MapInfo MapModel::MapInfoMaze = {MapModel::GeneratedMaze, "+maze+", "", 0, "", "", "", false};
+MapModel::MapInfo MapModel::MapInfoDrawn = {MapModel::HandDrawnMap, "+drawn+", "", 0, "", "", "", false};
-void MapModel::loadMaps(MapType maptype)
+
+MapModel::MapModel(MapType maptype, QObject *parent) : QStandardItemModel(parent)
{
+ m_maptype = maptype;
+ m_loaded = false;
+}
+
+bool MapModel::loadMaps()
+{
+ if(m_loaded)
+ return false;
+
+ m_loaded = true;
+
+ qDebug("[LAZINESS] MapModel::loadMaps()");
+
// this method resets the contents of this model (important to know for views).
beginResetModel();
@@ -75,7 +89,7 @@
MapType type = isMission ? MissionMap : StaticMap;
// if we're supposed to ignore this type, continue
- if (type != maptype) continue;
+ if (type != m_maptype) continue;
// load map info from file
QTextStream input(&mapCfgFile);
@@ -149,15 +163,19 @@
QStandardItemModel::appendColumn(mapList);
endResetModel();
+
+ return true;
}
-bool MapModel::mapExists(const QString & map) const
+bool MapModel::mapExists(const QString & map)
{
return findMap(map) >= 0;
}
-int MapModel::findMap(const QString & map) const
+int MapModel::findMap(const QString & map)
{
+ loadMaps();
+
return m_mapIndexes.value(map, -1);
}
diff -Nru hedgewars-0.9.19.3/QTfrontend/model/MapModel.h hedgewars-0.9.20.5/QTfrontend/model/MapModel.h
--- hedgewars-0.9.19.3/QTfrontend/model/MapModel.h 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/model/MapModel.h 2013-12-25 05:19:21.000000000 +0000
@@ -67,12 +67,14 @@
bool dlc; ///< True if this map was not packaged with the game
};
+ MapModel(MapType maptype, QObject *parent = 0);
+
/**
* @brief Searches maps in model to find out if one exists
* @param map map of which to check existence
* @return true if it exists
*/
- bool mapExists(const QString & map) const;
+ bool mapExists(const QString & map);
/**
* @brief Finds a map index (column, row) for a map name
@@ -86,7 +88,7 @@
* @param map map of which to find index
* @return int of index, or -1 if map not found
*/
- int findMap(const QString & map) const;
+ int findMap(const QString & map);
/**
* @brief Finds and returns a map item for a map name
@@ -98,16 +100,16 @@
// Static MapInfos for drawn and generated maps
static MapInfo MapInfoRandom, MapInfoMaze, MapInfoDrawn;
- public slots:
- /// Reloads the maps using the DataManager.
- /// Accepts two map types: StaticMap or MissionMap.
- void loadMaps(MapType maptype);
+ /// Loads the maps
+ bool loadMaps();
private:
/// map index lookup table. QPair contains:
//QHash > m_mapIndexes;
QHash m_mapIndexes;
+ MapType m_maptype;
+ bool m_loaded;
/**
* @brief Creates a QStandardItem, that holds the map info and item appearance.
diff -Nru hedgewars-0.9.19.3/QTfrontend/model/ThemeModel.cpp hedgewars-0.9.20.5/QTfrontend/model/ThemeModel.cpp
--- hedgewars-0.9.19.3/QTfrontend/model/ThemeModel.cpp 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/model/ThemeModel.cpp 2013-12-25 05:19:21.000000000 +0000
@@ -29,6 +29,8 @@
QAbstractListModel(parent)
{
m_data = QList >();
+
+ m_themesLoaded = false;
}
int ThemeModel::rowCount(const QModelIndex &parent) const
@@ -36,7 +38,11 @@
if(parent.isValid())
return 0;
else
+ {
+ if(!m_themesLoaded)
+ loadThemes();
return m_data.size();
+ }
}
@@ -45,13 +51,21 @@
if(index.column() > 0 || index.row() >= m_data.size())
return QVariant();
else
+ {
+ if(!m_themesLoaded)
+ loadThemes();
+
return m_data.at(index.row()).value(role);
+ }
}
-void ThemeModel::loadThemes()
+void ThemeModel::loadThemes() const
{
- beginResetModel();
+ qDebug("[LAZINESS] ThemeModel::loadThemes()");
+
+ m_themesLoaded = true;
+
DataManager & datamgr = DataManager::instance();
@@ -94,7 +108,4 @@
m_data.append(dataset);
}
-
-
- endResetModel();
}
diff -Nru hedgewars-0.9.19.3/QTfrontend/model/ThemeModel.h hedgewars-0.9.20.5/QTfrontend/model/ThemeModel.h
--- hedgewars-0.9.19.3/QTfrontend/model/ThemeModel.h 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/model/ThemeModel.h 2013-12-25 05:19:21.000000000 +0000
@@ -45,14 +45,11 @@
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
-
- public slots:
- /// reloads the themes from the DataManager
- void loadThemes();
-
-
private:
- QList > m_data;
+ mutable QList > m_data;
+ mutable bool m_themesLoaded;
+
+ void loadThemes() const;
};
#endif // HEDGEWARS_THEMEMODEL_H
diff -Nru hedgewars-0.9.19.3/QTfrontend/model/ammoSchemeModel.cpp hedgewars-0.9.20.5/QTfrontend/model/ammoSchemeModel.cpp
--- hedgewars-0.9.19.3/QTfrontend/model/ammoSchemeModel.cpp 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/model/ammoSchemeModel.cpp 2014-01-08 16:25:16.000000000 +0000
@@ -64,6 +64,7 @@
<< QVariant(5) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
AmmoSchemeModel::AmmoSchemeModel(QObject* parent, const QString & fileName) :
@@ -128,6 +129,7 @@
<< "healthdecrease" // 38
<< "ropepct" // 39
<< "getawaytime" // 40
+ << "worldedge" // 41
;
QList proMode;
@@ -173,6 +175,7 @@
<< QVariant(5) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
QList shoppa;
@@ -218,6 +221,7 @@
<< QVariant(5) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
QList cleanslate;
@@ -263,6 +267,7 @@
<< QVariant(5) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
QList minefield;
@@ -308,6 +313,7 @@
<< QVariant(5) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
QList barrelmayhem;
@@ -353,6 +359,7 @@
<< QVariant(5) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
QList tunnelhogs;
@@ -398,6 +405,7 @@
<< QVariant(5) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
QList forts;
@@ -443,6 +451,7 @@
<< QVariant(5) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
QList timeless;
@@ -488,6 +497,7 @@
<< QVariant(0) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
QList thinkingportals;
@@ -533,6 +543,7 @@
<< QVariant(5) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
QList kingmode;
@@ -578,6 +589,7 @@
<< QVariant(5) // health dec amt 38
<< QVariant(100) // rope modfier 39
<< QVariant(100) // get away time 40
+ << QVariant(0) // world edge 41
;
diff -Nru hedgewars-0.9.19.3/QTfrontend/model/playerslistmodel.cpp hedgewars-0.9.20.5/QTfrontend/model/playerslistmodel.cpp
--- hedgewars-0.9.19.3/QTfrontend/model/playerslistmodel.cpp 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/model/playerslistmodel.cpp 2013-12-25 05:19:21.000000000 +0000
@@ -11,7 +11,8 @@
PlayersListModel::PlayersListModel(QObject *parent) :
QAbstractListModel(parent)
{
-
+ m_fontInRoom = QFont();
+ m_fontInRoom.setItalic(true);
}
@@ -83,6 +84,15 @@
return true;
}
+QModelIndex PlayersListModel::nicknameIndex(const QString & nickname)
+{
+ QModelIndexList mil = match(index(0), Qt::DisplayRole, nickname, 1, Qt::MatchExactly);
+
+ if(mil.size() > 0)
+ return mil[0];
+ else
+ return QModelIndex();
+}
void PlayersListModel::addPlayer(const QString & nickname, bool notify)
{
@@ -104,22 +114,22 @@
else
emit nickRemovedLobby(nickname, msg);
- QModelIndexList mil = match(index(0), Qt::DisplayRole, nickname, 1, Qt::MatchExactly);
+ QModelIndex mi = nicknameIndex(nickname);
- if(mil.size())
- removeRow(mil[0].row());
+ if(mi.isValid())
+ removeRow(mi.row());
}
void PlayersListModel::playerJoinedRoom(const QString & nickname, bool notify)
{
- QModelIndexList mil = match(index(0), Qt::DisplayRole, nickname, 1, Qt::MatchExactly);
+ QModelIndex mi = nicknameIndex(nickname);
- if(mil.size())
+ if(mi.isValid())
{
- setData(mil[0], true, RoomFilterRole);
- updateIcon(mil[0]);
- updateSortData(mil[0]);
+ setData(mi, true, RoomFilterRole);
+ updateIcon(mi);
+ updateSortData(mi);
}
emit nickAdded(nickname, notify);
@@ -130,62 +140,65 @@
{
emit nickRemoved(nickname);
- QModelIndexList mil = match(index(0), Qt::DisplayRole, nickname, 1, Qt::MatchExactly);
+ QModelIndex mi = nicknameIndex(nickname);
- if(mil.size())
+ if(mi.isValid())
{
- setData(mil[0], false, RoomFilterRole);
- setData(mil[0], false, RoomAdmin);
- setData(mil[0], false, Ready);
- setData(mil[0], false, InGame);
- updateIcon(mil[0]);
+ setData(mi, false, RoomFilterRole);
+ setData(mi, false, RoomAdmin);
+ setData(mi, false, Ready);
+ setData(mi, false, InGame);
+ updateIcon(mi);
}
}
void PlayersListModel::setFlag(const QString &nickname, StateFlag flagType, bool isSet)
{
- QModelIndexList mil = match(index(0), Qt::DisplayRole, nickname, 1, Qt::MatchExactly);
-
- if(mil.size())
+ if(flagType == Friend)
{
- setData(mil[0], isSet, flagType);
+ if(isSet)
+ m_friendsSet.insert(nickname.toLower());
+ else
+ m_friendsSet.remove(nickname.toLower());
- if(flagType == Friend || flagType == ServerAdmin
- || flagType == Ignore || flagType == RoomAdmin)
- updateSortData(mil[0]);
+ saveSet(m_friendsSet, "friends");
+ }
+ else if(flagType == Ignore)
+ {
+ if(isSet)
+ m_ignoredSet.insert(nickname.toLower());
+ else
+ m_ignoredSet.remove(nickname.toLower());
- if(flagType == Friend)
- {
- if(isSet)
- m_friendsSet.insert(nickname.toLower());
- else
- m_friendsSet.remove(nickname.toLower());
+ saveSet(m_ignoredSet, "ignore");
+ }
- saveSet(m_friendsSet, "friends");
- }
+ QModelIndex mi = nicknameIndex(nickname);
- if(flagType == Ignore)
- {
- if(isSet)
- m_ignoredSet.insert(nickname.toLower());
- else
- m_ignoredSet.remove(nickname.toLower());
+ if(mi.isValid())
+ {
+ setData(mi, isSet, flagType);
- saveSet(m_ignoredSet, "ignore");
- }
+ if(flagType == Friend || flagType == ServerAdmin
+ || flagType == Ignore || flagType == RoomAdmin)
+ updateSortData(mi);
- updateIcon(mil[0]);
+ updateIcon(mi);
}
}
bool PlayersListModel::isFlagSet(const QString & nickname, StateFlag flagType)
{
- QModelIndexList mil = match(index(0), Qt::DisplayRole, nickname, 1, Qt::MatchExactly);
+ QModelIndex mi = nicknameIndex(nickname);
- if(mil.size())
- return mil[0].data(flagType).toBool();
+ if(mi.isValid())
+ return mi.data(flagType).toBool();
+ else if(flagType == Friend)
+ return isFriend(nickname);
+ else if(flagType == Ignore)
+ return isIgnored(nickname);
else
return false;
}
@@ -223,6 +236,7 @@
<< index.data(Ignore).toBool()
<< index.data(InGame).toBool()
<< index.data(RoomFilterRole).toBool()
+ << index.data(InRoom).toBool()
;
for(int i = flags.size() - 1; i >= 0; --i)
@@ -253,16 +267,26 @@
else
painter.drawPixmap(0, 0, 16, 16, QPixmap(":/res/chat/lamp_off.png"));
}
+ } else
+ { // we're in lobby
+ if(!index.data(InRoom).toBool())
+ painter.drawPixmap(0, 0, 16, 16, QPixmap(":/res/Flake.png"));
}
QString mainIconName(":/res/chat/");
- if(index.data(RoomAdmin).toBool())
- mainIconName += "roomadmin";
- else if(index.data(ServerAdmin).toBool())
+ if(index.data(ServerAdmin).toBool())
mainIconName += "serveradmin";
else
- mainIconName += "hedgehog";
+ {
+ if(index.data(RoomAdmin).toBool())
+ mainIconName += "roomadmin";
+ else
+ mainIconName += "hedgehog";
+
+ if(index.data(Contributor).toBool())
+ mainIconName += "contributor";
+ }
if(!index.data(Registered).toBool())
mainIconName += "_gray";
@@ -332,11 +356,20 @@
checkFriendIgnore(index(i));
}
+bool PlayersListModel::isFriend(const QString & nickname)
+{
+ return m_friendsSet.contains(nickname.toLower());
+}
+
+bool PlayersListModel::isIgnored(const QString & nickname)
+{
+ return m_ignoredSet.contains(nickname.toLower());
+}
void PlayersListModel::checkFriendIgnore(const QModelIndex &mi)
{
- setData(mi, m_friendsSet.contains(mi.data().toString().toLower()), Friend);
- setData(mi, m_ignoredSet.contains(mi.data().toString().toLower()), Ignore);
+ setData(mi, isFriend(mi.data().toString()), Friend);
+ setData(mi, isIgnored(mi.data().toString()), Ignore);
updateIcon(mi);
updateSortData(mi);
diff -Nru hedgewars-0.9.19.3/QTfrontend/model/playerslistmodel.h hedgewars-0.9.20.5/QTfrontend/model/playerslistmodel.h
--- hedgewars-0.9.19.3/QTfrontend/model/playerslistmodel.h 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/model/playerslistmodel.h 2013-12-25 05:19:21.000000000 +0000
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
class PlayersListModel : public QAbstractListModel
{
@@ -19,7 +20,9 @@
Registered = Qt::UserRole + 3,
Friend = Qt::UserRole + 4,
Ignore = Qt::UserRole + 5,
- InGame = Qt::UserRole + 6
+ InGame = Qt::UserRole + 6,
+ InRoom = Qt::UserRole + 7,
+ Contributor = Qt::UserRole + 8
};
enum SpecialRoles {
@@ -40,6 +43,8 @@
bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ QModelIndex nicknameIndex(const QString & nickname);
+
public slots:
void addPlayer(const QString & nickname, bool notify);
void removePlayer(const QString & nickname, const QString & msg = QString());
@@ -61,12 +66,15 @@
QList m_data;
QSet m_friendsSet, m_ignoredSet;
QString m_nickname;
+ QFont m_fontInRoom;
void updateIcon(const QModelIndex & index);
void updateSortData(const QModelIndex & index);
void loadSet(QSet & set, const QString & suffix);
void saveSet(const QSet & set, const QString & suffix);
void checkFriendIgnore(const QModelIndex & mi);
+ bool isFriend(const QString & nickname);
+ bool isIgnored(const QString & nickname);
};
#endif // PLAYERSLISTMODEL_H
diff -Nru hedgewars-0.9.19.3/QTfrontend/model/roomslistmodel.cpp hedgewars-0.9.20.5/QTfrontend/model/roomslistmodel.cpp
--- hedgewars-0.9.19.3/QTfrontend/model/roomslistmodel.cpp 2013-06-04 14:09:27.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/model/roomslistmodel.cpp 2013-11-18 07:03:07.000000000 +0000
@@ -30,7 +30,7 @@
RoomsListModel::RoomsListModel(QObject *parent) :
QAbstractTableModel(parent),
- c_nColumns(8)
+ c_nColumns(9)
{
m_headerData =
QStringList()
@@ -40,6 +40,7 @@
<< tr("T")
<< tr("Owner")
<< tr("Map")
+ << tr("Script")
<< tr("Rules")
<< tr("Weapons");
diff -Nru hedgewars-0.9.19.3/QTfrontend/net/newnetclient.cpp hedgewars-0.9.20.5/QTfrontend/net/newnetclient.cpp
--- hedgewars-0.9.19.3/QTfrontend/net/newnetclient.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/net/newnetclient.cpp 2014-01-08 16:25:16.000000000 +0000
@@ -94,7 +94,7 @@
NetSocket.disconnectFromHost();
}
-void HWNewNet::CreateRoom(const QString & room)
+void HWNewNet::CreateRoom(const QString & room, const QString & password)
{
if(netClientState != InLobby)
{
@@ -104,11 +104,15 @@
myroom = room;
- RawSendNet(QString("CREATE_ROOM%1%2").arg(delimeter).arg(room));
+ if(password.isEmpty())
+ RawSendNet(QString("CREATE_ROOM%1%2").arg(delimeter).arg(room));
+ else
+ RawSendNet(QString("CREATE_ROOM%1%2%1%3").arg(delimeter).arg(room).arg(password));
+
isChief = true;
}
-void HWNewNet::JoinRoom(const QString & room)
+void HWNewNet::JoinRoom(const QString & room, const QString &password)
{
if(netClientState != InLobby)
{
@@ -118,7 +122,11 @@
myroom = room;
- RawSendNet(QString("JOIN_ROOM%1%2").arg(delimeter).arg(room));
+ if(password.isEmpty())
+ RawSendNet(QString("JOIN_ROOM%1%2").arg(delimeter).arg(room));
+ else
+ RawSendNet(QString("JOIN_ROOM%1%2%1%3").arg(delimeter).arg(room).arg(password));
+
isChief = false;
}
@@ -303,14 +311,12 @@
if (lst[0] == "ROOMS")
{
- if(lst.size() % 8 != 1)
+ if(lst.size() % 9 != 1)
{
qWarning("Net: Malformed ROOMS message");
return;
}
- QStringList tmp = lst;
- tmp.removeFirst();
- m_roomsListModel->setRoomsList(tmp);
+ m_roomsListModel->setRoomsList(lst.mid(1));
if (m_private_game == false && m_nick_registered == false)
{
emit NickNotRegistered(mynick);
@@ -398,7 +404,7 @@
return;
}
- if (lst[0] == "CLIENT_FLAGS")
+ if (lst[0] == "CLIENT_FLAGS" || lst[0] == "CF")
{
if(lst.size() < 3 || lst[1].size() < 2)
{
@@ -436,6 +442,16 @@
foreach(const QString & nick, nicks)
m_playersModel->setFlag(nick, PlayersListModel::Registered, setFlag);
break;
+ // flag indicating if a player is in room
+ case 'i':
+ foreach(const QString & nick, nicks)
+ m_playersModel->setFlag(nick, PlayersListModel::InRoom, setFlag);
+ break;
+ // flag indicating if a player is contributor
+ case 'c':
+ foreach(const QString & nick, nicks)
+ m_playersModel->setFlag(nick, PlayersListModel::InRoom, setFlag);
+ break;
// flag indicating if a player has engine running
case 'g':
if(inRoom)
@@ -509,7 +525,7 @@
return;
}
- if(lst[0] == "ROOM" && lst.size() == 10 && lst[1] == "ADD")
+ if(lst[0] == "ROOM" && lst.size() == 11 && lst[1] == "ADD")
{
QStringList tmp = lst;
tmp.removeFirst();
@@ -519,7 +535,7 @@
return;
}
- if(lst[0] == "ROOM" && lst.size() == 11 && lst[1] == "UPD")
+ if(lst[0] == "ROOM" && lst.size() == 12 && lst[1] == "UPD")
{
QStringList tmp = lst;
tmp.removeFirst();
@@ -609,15 +625,9 @@
return;
}
- if (lst[0] == "ADMIN_ACCESS")
- {
- // obsolete, see +a client flag
- return;
- }
-
if(lst[0] == "JOINING")
{
- if(lst.size() < 2)
+ if(lst.size() != 2)
{
qWarning("Net: Bad JOINING message");
return;
@@ -625,6 +635,7 @@
myroom = lst[1];
emit roomNameUpdated(myroom);
+ return;
}
if(netClientState == InLobby && lst[0] == "JOINED")
@@ -800,17 +811,6 @@
m_playersModel->playerLeftRoom(lst[1]);
return;
}
-
- // obsolete
- if (lst[0] == "ROOM_CONTROL_ACCESS")
- {
- if (lst.size() < 2)
- {
- qWarning("Net: Bad ROOM_CONTROL_ACCESS message");
- return;
- }
- return;
- }
}
qWarning() << "Net: Unknown message or wrong state:" << lst;
@@ -1055,10 +1055,11 @@
switch(n)
{
case 0:
- {
emit NickTaken(mynick);
break;
- }
+ case 2:
+ emit askForRoomPassword();
+ break;
}
}
@@ -1076,3 +1077,9 @@
{
return m_roomPlayersModel;
}
+
+void HWNewNet::roomPasswordEntered(const QString &password)
+{
+ if(!myroom.isEmpty())
+ JoinRoom(myroom, password);
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/net/newnetclient.h hedgewars-0.9.20.5/QTfrontend/net/newnetclient.h
--- hedgewars-0.9.19.3/QTfrontend/net/newnetclient.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/net/newnetclient.h 2014-01-08 16:25:16.000000000 +0000
@@ -76,6 +76,7 @@
PlayersListModel * m_playersModel;
QSortFilterProxyModel * m_lobbyPlayersModel;
QSortFilterProxyModel * m_roomPlayersModel;
+ QString m_lastRoom;
QStringList cmdbuf;
@@ -103,6 +104,7 @@
void adminAccess(bool);
void roomMaster(bool);
void roomNameUpdated(const QString & name);
+ void askForRoomPassword();
void netSchemeConfig(QStringList &);
void paramChanged(const QString & param, const QStringList & value);
@@ -153,8 +155,8 @@
void setLatestProtocolVar(int proto);
void askServerVars();
- void JoinRoom(const QString & room);
- void CreateRoom(const QString & room);
+ void JoinRoom(const QString & room, const QString & password);
+ void CreateRoom(const QString & room, const QString &password);
void updateRoomName(const QString &);
void askRoomsList();
void gameFinished(bool correcly);
@@ -173,6 +175,7 @@
void removeBan(const QString &);
void banIP(const QString & ip, const QString & reason, int seconds);
void banNick(const QString & nick, const QString & reason, int seconds);
+ void roomPasswordEntered(const QString & password);
private slots:
void ClientRead();
diff -Nru hedgewars-0.9.19.3/QTfrontend/net/recorder.cpp hedgewars-0.9.20.5/QTfrontend/net/recorder.cpp
--- hedgewars-0.9.19.3/QTfrontend/net/recorder.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/net/recorder.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -143,3 +143,8 @@
return arguments;
}
+
+bool HWRecorder::simultaneousRun()
+{
+ return true;
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/net/recorder.h hedgewars-0.9.20.5/QTfrontend/net/recorder.h
--- hedgewars-0.9.19.3/QTfrontend/net/recorder.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/net/recorder.h 2013-12-25 05:19:22.000000000 +0000
@@ -35,6 +35,7 @@
virtual ~HWRecorder();
void EncodeVideo(const QByteArray & record);
+ bool simultaneousRun();
VideoItem * item; // used by pagevideos
QString name;
diff -Nru hedgewars-0.9.19.3/QTfrontend/net/tcpBase.cpp hedgewars-0.9.20.5/QTfrontend/net/tcpBase.cpp
--- hedgewars-0.9.19.3/QTfrontend/net/tcpBase.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/net/tcpBase.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -80,6 +80,7 @@
QObject(parent),
m_hasStarted(false),
m_isDemoMode(demoMode),
+ m_connected(false),
IPCSocket(0)
{
if(!IPCServer)
@@ -103,12 +104,23 @@
// connection should be already finished
return;
}
+
disconnect(IPCServer, SIGNAL(newConnection()), this, SLOT(NewConnection()));
IPCSocket = IPCServer->nextPendingConnection();
+
if(!IPCSocket) return;
+
+ m_connected = true;
+
connect(IPCSocket, SIGNAL(disconnected()), this, SLOT(ClientDisconnect()));
connect(IPCSocket, SIGNAL(readyRead()), this, SLOT(ClientRead()));
SendToClientFirst();
+
+ if(simultaneousRun())
+ {
+ srvsList.removeOne(this);
+ emit isReadyNow();
+ }
}
void TCPBase::RealStart()
@@ -134,7 +146,7 @@
connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(StartProcessError(QProcess::ProcessError)));
QStringList arguments=getArguments();
-#ifdef DEBUG
+#ifdef QT_DEBUG
// redirect everything written on stdout/stderr
process->setProcessChannelMode(QProcess::ForwardedChannels);
#endif
@@ -149,7 +161,8 @@
disconnect(IPCSocket, SIGNAL(readyRead()), this, SLOT(ClientRead()));
onClientDisconnect();
- emit isReadyNow();
+ if(!simultaneousRun())
+ emit isReadyNow();
IPCSocket->deleteLater();
deleteLater();
@@ -188,6 +201,7 @@
TCPBase * last = srvsList.last();
if(couldCancelPreviousRequest
&& last->couldBeRemoved()
+ && (last->isConnected() || !last->hasStarted())
&& (last->parent() == parent()))
{
srvsList.removeLast();
@@ -195,7 +209,7 @@
Start(couldCancelPreviousRequest);
} else
{
- connect(srvsList.last(), SIGNAL(isReadyNow()), this, SLOT(tcpServerReady()));
+ connect(last, SIGNAL(isReadyNow()), this, SLOT(tcpServerReady()));
srvsList.push_back(this);
}
}
@@ -246,3 +260,18 @@
{
return false;
}
+
+bool TCPBase::isConnected()
+{
+ return m_connected;
+}
+
+bool TCPBase::simultaneousRun()
+{
+ return false;
+}
+
+bool TCPBase::hasStarted()
+{
+ return m_hasStarted;
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/net/tcpBase.h hedgewars-0.9.20.5/QTfrontend/net/tcpBase.h
--- hedgewars-0.9.19.3/QTfrontend/net/tcpBase.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/net/tcpBase.h 2013-12-25 05:19:22.000000000 +0000
@@ -42,6 +42,9 @@
virtual ~TCPBase();
virtual bool couldBeRemoved();
+ virtual bool simultaneousRun();
+ bool isConnected();
+ bool hasStarted();
signals:
void isReadyNow();
@@ -69,6 +72,7 @@
static QPointer IPCServer;
bool m_isDemoMode;
+ bool m_connected;
void RealStart();
QPointer IPCSocket;
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/CampaignDefault.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/CampaignDefault.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/Hedgehog.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/Hedgehog.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/StatsCustomAchievement.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/StatsCustomAchievement.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Classic_Fairytale/backstab.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Classic_Fairytale/backstab.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Classic_Fairytale/dragon.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Classic_Fairytale/dragon.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Classic_Fairytale/enemy.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Classic_Fairytale/enemy.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Classic_Fairytale/epil.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Classic_Fairytale/epil.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Classic_Fairytale/family.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Classic_Fairytale/family.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Classic_Fairytale/first_blood.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Classic_Fairytale/first_blood.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Classic_Fairytale/journey.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Classic_Fairytale/journey.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Classic_Fairytale/queen.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Classic_Fairytale/queen.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Classic_Fairytale/shadow.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Classic_Fairytale/shadow.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Classic_Fairytale/united.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Classic_Fairytale/united.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/cosmos.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/cosmos.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/death01.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/death01.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/death02.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/death02.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/desert01.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/desert01.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/desert02.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/desert02.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/desert03.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/desert03.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/final.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/final.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/fruit01.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/fruit01.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/fruit02.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/fruit02.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/fruit03.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/fruit03.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/ice01.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/ice01.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/ice02.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/ice02.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/moon01.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/moon01.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/campaign/A_Space_Adventure/moon02.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/campaign/A_Space_Adventure/moon02.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/chat/hedgehogcontributor.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/chat/hedgehogcontributor.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/chat/hedgehogcontributor_gray.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/chat/hedgehogcontributor_gray.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/chat/roomadmincontributor.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/chat/roomadmincontributor.png differ
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/chat/roomadmincontributor_gray.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/chat/roomadmincontributor_gray.png differ
diff -Nru hedgewars-0.9.19.3/QTfrontend/res/css/birthday.css hedgewars-0.9.20.5/QTfrontend/res/css/birthday.css
--- hedgewars-0.9.19.3/QTfrontend/res/css/birthday.css 2012-12-19 16:09:05.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/res/css/birthday.css 2013-11-18 07:03:07.000000000 +0000
@@ -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(20, 20, 20, 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;
}
-QLineEdit, QListWidget, QListView,QTableView, QTextBrowser,
-QSpinBox, QToolBox, QPlainTextEdit {
+QToolButton {
+background-color: #11084A;
+}
+
+QToolButton:hover {
+background-color: #150A61;
+}
+
+QToolButton:pressed {
+background-color: #100744;
+}
+
+QLineEdit, QListWidget, QListView, QTableView, QTextBrowser,
+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;
@@ -116,17 +143,18 @@
alternate-background-color: #2f213a;
gridline-color: transparent;
}
-
+QTabWidget::pane { top: -2px; }
QTabBar::tab {
-border-bottom-width: 0;
border-radius: 0;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
padding: 3px;
+background-color: #00351d;
+color: #ffcc00;
}
-QTabBar::tab:!selected {
-color: #0d0544;
-background-color: #ffcc00;
+QTabBar::tab:selected {
+border-bottom-color: #0d0544;
+border-bottom-width: 0;
}
QSpinBox::up-button{
background: transparent;
@@ -151,6 +179,7 @@
QComboBox {
border-radius: 10px;
padding: 3px;
+height: 18px;
}
QComboBox:pressed{
border-color: white;
@@ -240,9 +269,66 @@
QSlider::handle::horizontal {
border: 0px;
-margin: -2px 0px;
-border-radius: 3px;
+margin: -8px 0px;
background-color: #ffcc00;
-width: 8px;
+width: 12px;
+height: 6px;
+border-radius: 3px;
}
+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;
+}
+
+PageMultiplayer TeamSelWidget {
+min-height: 500px;
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/res/css/chat.css hedgewars-0.9.20.5/QTfrontend/res/css/chat.css
--- hedgewars-0.9.19.3/QTfrontend/res/css/chat.css 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/res/css/chat.css 2013-12-30 18:42:23.000000000 +0000
@@ -9,7 +9,7 @@
*
* In the QTfrontend of hedgewars also display:none; will work for class names
* that start with msg_ and .timestamp - as long as they are referenced
- * directly and not within any class hierachy.
+ * directly and not within any class hierarchy.
* Note: Will only effect new lines!
*
******************************************************************************
diff -Nru hedgewars-0.9.19.3/QTfrontend/res/css/christmas.css hedgewars-0.9.20.5/QTfrontend/res/css/christmas.css
--- hedgewars-0.9.19.3/QTfrontend/res/css/christmas.css 2013-06-03 08:01:41.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/res/css/christmas.css 2013-11-18 07:03:07.000000000 +0000
@@ -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;
}
-QLineEdit, QListWidget, QListView,QTableView, QTextBrowser,
-QSpinBox, QToolBox, QPlainTextEdit {
+QToolButton {
+background-color: #11084A;
+}
+
+QToolButton:hover {
+background-color: #150A61;
+}
+
+QToolButton:pressed {
+background-color: #100744;
+}
+
+QLineEdit, QListWidget, QListView, QTableView, QTextBrowser,
+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;
@@ -116,17 +143,18 @@
alternate-background-color: #2f213a;
gridline-color: transparent;
}
-
+QTabWidget::pane { top: -2px; }
QTabBar::tab {
-border-bottom-width: 0;
border-radius: 0;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
padding: 3px;
+background-color: #00351d;
+color: #ffcc00;
}
-QTabBar::tab:!selected {
-color: #0d0544;
-background-color: #ffcc00;
+QTabBar::tab:selected {
+border-bottom-color: #0d0544;
+border-bottom-width: 0;
}
QSpinBox::up-button{
background: transparent;
@@ -151,6 +179,7 @@
QComboBox {
border-radius: 10px;
padding: 3px;
+height: 18px;
}
QComboBox:pressed{
border-color: white;
@@ -240,9 +269,66 @@
QSlider::handle::horizontal {
border: 0px;
-margin: -2px 0px;
-border-radius: 3px;
+margin: -8px 0px;
background-color: #ffcc00;
-width: 8px;
+width: 12px;
+height: 6px;
+border-radius: 3px;
}
+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;
+}
+
+PageMultiplayer TeamSelWidget {
+min-height: 500px;
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/res/html/about.html hedgewars-0.9.20.5/QTfrontend/res/html/about.html
--- hedgewars-0.9.19.3/QTfrontend/res/html/about.html 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/res/html/about.html 2013-10-31 20:21:56.000000000 +0000
@@ -77,12 +77,12 @@
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 <m.bresciani@email.it >
- Japanese: ADAM Etienne <etienne.adam@gmail.com >, Marco Bresciani <m.bresciani@email.it >, 梅津洋恵
+ Japanese: ADAM Etienne <etienne.adam@gmail.com >, Marco Bresciani <m.bresciani@email.it >
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 >
+ Russian: Andrey Korotaev <unC0Rr@gmail.com >, Vitaly Novichkov <admin@wohlnet.ru >
Slovak: Jose Riha
Spanish: Carlos Vives <mail@carlosvives.es >
Swedish: Niklas Grahn <raewolusjoon@yaoo.com >, Henrik Rostedt <henrik.rostedt@gmail.com >
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/QTfrontend/res/iconEarth.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/QTfrontend/res/iconEarth.png differ
diff -Nru hedgewars-0.9.19.3/QTfrontend/res/xml/tips.xml hedgewars-0.9.20.5/QTfrontend/res/xml/tips.xml
--- hedgewars-0.9.19.3/QTfrontend/res/xml/tips.xml 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/res/xml/tips.xml 1970-01-01 00:00:00.000000000 +0000
@@ -1,62 +0,0 @@
-# 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.
- Heads or tails? Type '/rnd' in lobby and you'll find out. Also '/rnd rock paper scissors' works!
- 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 -Nru hedgewars-0.9.19.3/QTfrontend/servermessages.h hedgewars-0.9.20.5/QTfrontend/servermessages.h
--- hedgewars-0.9.19.3/QTfrontend/servermessages.h 2013-06-11 08:24:00.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/servermessages.h 1970-01-01 00:00:00.000000000 +0000
@@ -1,30 +0,0 @@
-const char * serverMessages[] = {
-QT_TRANSLATE_NOOP("server", "No checker rights"),
-QT_TRANSLATE_NOOP("server", "Authentication failed"),
-QT_TRANSLATE_NOOP("server", "60 seconds cooldown after kick"),
-QT_TRANSLATE_NOOP("server", "kicked"),
-QT_TRANSLATE_NOOP("server", "Ping timeout"),
-QT_TRANSLATE_NOOP("server", "bye"),
-QT_TRANSLATE_NOOP("server", "Empty config entry"),
-QT_TRANSLATE_NOOP("server", "Not room master"),
-QT_TRANSLATE_NOOP("server", "Corrupted hedgehogs info"),
-QT_TRANSLATE_NOOP("server", "too many teams"),
-QT_TRANSLATE_NOOP("server", "too many hedgehogs"),
-QT_TRANSLATE_NOOP("server", "There's already a team with same name in the list"),
-QT_TRANSLATE_NOOP("server", "round in progress"),
-QT_TRANSLATE_NOOP("server", "restricted"),
-QT_TRANSLATE_NOOP("server", "REMOVE_TEAM: no such team"),
-QT_TRANSLATE_NOOP("server", "Not team owner!"),
-QT_TRANSLATE_NOOP("server", "Less than two clans!"),
-QT_TRANSLATE_NOOP("server", "Room with such name already exists"),
-QT_TRANSLATE_NOOP("server", "Illegal room name"),
-QT_TRANSLATE_NOOP("server", "No such room"),
-QT_TRANSLATE_NOOP("server", "Joining restricted"),
-QT_TRANSLATE_NOOP("server", "Registered users only"),
-QT_TRANSLATE_NOOP("server", "You are banned in this room"),
-QT_TRANSLATE_NOOP("server", "Nickname already chosen"),
-QT_TRANSLATE_NOOP("server", "Illegal nickname"),
-QT_TRANSLATE_NOOP("server", "Protocol already known"),
-QT_TRANSLATE_NOOP("server", "Bad number"),
-QT_TRANSLATE_NOOP("server", "Nickname is already in use")
-};
diff -Nru hedgewars-0.9.19.3/QTfrontend/team.cpp hedgewars-0.9.20.5/QTfrontend/team.cpp
--- hedgewars-0.9.19.3/QTfrontend/team.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/team.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -171,7 +171,7 @@
bool HWTeam::loadFromFile()
{
- QSettings teamfile(QString("physfs://Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
+ QSettings teamfile(QString("physfs://Teams/%1.hwt").arg(DataManager::safeFileName(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();
@@ -204,7 +204,7 @@
bool HWTeam::fileExists()
{
- QFile f(QString("physfs://Teams/%1.hwt").arg(m_name));
+ QFile f(QString("physfs://Teams/%1.hwt").arg(DataManager::safeFileName(m_name)));
return f.exists();
}
@@ -212,7 +212,7 @@
{
if(m_isNetTeam)
return false;
- QFile cfgfile(QString("physfs://Teams/%1.hwt").arg(m_name));
+ QFile cfgfile(QString("physfs://Teams/%1.hwt").arg(DataManager::safeFileName(m_name)));
cfgfile.remove();
return true;
}
@@ -221,12 +221,12 @@
{
if (OldTeamName != m_name)
{
- QFile cfgfile(QString("physfs://Teams/%1.hwt").arg(OldTeamName));
+ QFile cfgfile(QString("physfs://Teams/%1.hwt").arg(DataManager::safeFileName(OldTeamName)));
cfgfile.remove();
OldTeamName = m_name;
}
- QString fileName = QString("physfs://Teams/%1.hwt").arg(m_name);
+ QString fileName = QString("physfs://Teams/%1.hwt").arg(DataManager::safeFileName(m_name));
DataManager::ensureFileExists(fileName);
QSettings teamfile(fileName, QSettings::IniFormat, 0);
teamfile.setIniCodec("UTF-8");
@@ -261,7 +261,7 @@
return true;
}
-QStringList HWTeam::teamGameConfig(quint32 InitHealth, GameUIConfig * config) const
+QStringList HWTeam::teamGameConfig(quint32 InitHealth) const
{
QStringList sl;
if (m_isNetTeam)
@@ -276,16 +276,8 @@
sl.push_back(QString("evoicepack " + m_voicepack));
sl.push_back(QString("eflag " + m_flag));
- if (!m_isNetTeam)
- {
- for(int i = 0; i < BINDS_NUMBER; i++)
- {
- 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));
- }
- }
+ if(!m_owner.isEmpty())
+ sl.push_back(QString("eowner ") + m_owner);
for (int t = 0; t < m_numHedgehogs; t++)
{
diff -Nru hedgewars-0.9.19.3/QTfrontend/team.h hedgewars-0.9.20.5/QTfrontend/team.h
--- hedgewars-0.9.19.3/QTfrontend/team.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/team.h 2013-10-31 20:21:56.000000000 +0000
@@ -93,7 +93,7 @@
void incWins();
// convert team info into strings for further computation
- QStringList teamGameConfig(quint32 InitHealth, GameUIConfig * config) const;
+ QStringList teamGameConfig(quint32 InitHealth) const;
// comparison operators
bool operator == (const HWTeam& t1) const;
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/dialog/upload_video.cpp hedgewars-0.9.20.5/QTfrontend/ui/dialog/upload_video.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/dialog/upload_video.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/dialog/upload_video.cpp 2013-10-31 20:21:56.000000000 +0000
@@ -291,7 +291,7 @@
QNetworkReply *reply = (QNetworkReply*)sender();
reply->deleteLater();
- location = QString::fromAscii(reply->rawHeader("Location"));
+ location = QString::fromLatin1(reply->rawHeader("Location"));
if (location.isEmpty())
{
QString errorStr = QMessageBox::tr("Error while sending metadata to youtube.com:\n");
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/mouseoverfilter.cpp hedgewars-0.9.20.5/QTfrontend/ui/mouseoverfilter.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/mouseoverfilter.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/mouseoverfilter.cpp 2013-10-31 20:21:56.000000000 +0000
@@ -49,8 +49,6 @@
{
SDLInteraction::instance().playSoundFile("/Sounds/steps.ogg");
}
-
- return true;
}
else if (event->type() == QEvent::Leave)
{
@@ -63,7 +61,6 @@
else
abstractpage->setButtonDescription("");
}
-
return false;
}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/AbstractPage.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/AbstractPage.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/AbstractPage.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/AbstractPage.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -67,7 +67,7 @@
descLabel->setAlignment(Qt::AlignCenter);
descLabel->setWordWrap(true);
descLabel->setOpenExternalLinks(true);
- descLabel->setFixedHeight(50);
+ descLabel->setFixedHeight(60);
descLabel->setStyleSheet("font-size: 16px");
bottomLeftLayout->addWidget(descLabel);
pageLayout->addWidget(descLabel, 1, 1);
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagecampaign.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pagecampaign.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagecampaign.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagecampaign.cpp 2013-10-31 20:21:56.000000000 +0000
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include "pagecampaign.h"
@@ -31,18 +32,43 @@
pageLayout->setRowStretch(0, 1);
pageLayout->setRowStretch(3, 1);
+ QGridLayout * infoLayout = new QGridLayout();
+ infoLayout->setColumnStretch(0, 1);
+ infoLayout->setColumnStretch(1, 1);
+ infoLayout->setColumnStretch(2, 1);
+ infoLayout->setColumnStretch(3, 1);
+ infoLayout->setColumnStretch(4, 1);
+ infoLayout->setRowStretch(0, 1);
+ infoLayout->setRowStretch(1, 1);
+
+ // set this as default image first time page is created, this will change in hwform.cpp
+ btnPreview = formattedButton(":/res/campaign/A_Classic_Fairytale/first_blood.png", true);
+ infoLayout->setAlignment(btnPreview, Qt::AlignHCenter | Qt::AlignVCenter);
+
+ lbldescription = new QLabel();
+ lbldescription->setAlignment(Qt::AlignHCenter| Qt::AlignTop);
+ lbldescription->setWordWrap(true);
+
+ lbltitle = new QLabel();
+ lbltitle->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
+
CBTeam = new QComboBox(this);
CBMission = new QComboBox(this);
CBCampaign = new QComboBox(this);
- pageLayout->addWidget(CBTeam, 1, 1);
- pageLayout->addWidget(CBCampaign, 2, 1);
- pageLayout->addWidget(CBMission, 3, 1);
+ infoLayout->addWidget(btnPreview,0,1,2,1);
+ infoLayout->addWidget(lbltitle,0,2,1,2);
+ infoLayout->addWidget(lbldescription,1,2,1,2);
+
+ pageLayout->addLayout(infoLayout, 0, 0, 2, 3);
+ pageLayout->addWidget(CBTeam, 2, 1);
+ pageLayout->addWidget(CBCampaign, 3, 1);
+ pageLayout->addWidget(CBMission, 4, 1);
BtnStartCampaign = new QPushButton(this);
BtnStartCampaign->setFont(*font14);
BtnStartCampaign->setText(QPushButton::tr("Go!"));
- pageLayout->addWidget(BtnStartCampaign, 2, 2);
+ pageLayout->addWidget(BtnStartCampaign, 3, 2);
return pageLayout;
}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagecampaign.h hedgewars-0.9.20.5/QTfrontend/ui/page/pagecampaign.h
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagecampaign.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagecampaign.h 2013-10-31 20:21:56.000000000 +0000
@@ -28,7 +28,10 @@
public:
PageCampaign(QWidget* parent = 0);
+ QPushButton *btnPreview;
QPushButton *BtnStartCampaign;
+ QLabel *lbldescription;
+ QLabel *lbltitle;
QComboBox *CBMission;
QComboBox *CBCampaign;
QComboBox *CBTeam;
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagedata.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pagedata.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagedata.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagedata.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#include "pagedata.h"
#include "databrowser.h"
@@ -48,10 +49,23 @@
return pageLayout;
}
+QLayout * PageDataDownload::footerLayoutDefinition()
+{
+ QHBoxLayout * bottomLayout = new QHBoxLayout();
+ bottomLayout->setStretch(0, 1);
+
+ pbOpenDir = addButton(tr("Open packages directory"), bottomLayout, 1, false);
+
+ bottomLayout->setStretch(2, 1);
+
+ return bottomLayout;
+}
+
void PageDataDownload::connectSignals()
{
connect(web, SIGNAL(anchorClicked(QUrl)), this, SLOT(request(const QUrl&)));
connect(this, SIGNAL(goBack()), this, SLOT(onPageLeave()));
+ connect(pbOpenDir, SIGNAL(clicked()), this, SLOT(openPackagesDir()));
}
PageDataDownload::PageDataDownload(QWidget* parent) : AbstractPage(parent)
@@ -193,3 +207,9 @@
//DataManager::instance().reload();
}
}
+
+void PageDataDownload::openPackagesDir()
+{
+ QString path = QDir::toNativeSeparators(cfgdir->absolutePath() + "/Data");
+ QDesktopServices::openUrl(QUrl("file:///" + path));
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagedata.h hedgewars-0.9.20.5/QTfrontend/ui/page/pagedata.h
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagedata.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagedata.h 2013-12-25 05:19:22.000000000 +0000
@@ -27,6 +27,7 @@
class QNetworkReply;
class QVBoxLayout;
+
class PageDataDownload : public AbstractPage
{
Q_OBJECT
@@ -39,12 +40,14 @@
protected:
QLayout * bodyLayoutDefinition();
+ QLayout * footerLayoutDefinition();
void connectSignals();
private:
DataBrowser *web;
QHash progressBars;
QVBoxLayout *progressBarsLayout;
+ QPushButtonWithSound * pbOpenDir;
bool m_contentDownloaded; ///< true if something was downloaded since last page leave
@@ -54,6 +57,7 @@
void pageDownloaded();
void fileDownloaded();
void downloadProgress(qint64, qint64);
+ void openPackagesDir();
void onPageLeave();
};
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagedrawmap.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pagedrawmap.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagedrawmap.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagedrawmap.cpp 2013-10-31 20:21:56.000000000 +0000
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include "pagedrawmap.h"
#include "drawmapwidget.h"
@@ -32,12 +33,22 @@
cbEraser = new QCheckBox(tr("Eraser"), this);
pageLayout->addWidget(cbEraser, 0, 0);
pbUndo = addButton(tr("Undo"), pageLayout, 1, 0);
- pbClear = addButton(tr("Clear"), pageLayout, 2, 0);
- pbLoad = addButton(tr("Load"), pageLayout, 3, 0);
- pbSave = addButton(tr("Save"), pageLayout, 4, 0);
+
+ rbPolyline = new QRadioButton(tr("Polyline"), this);
+ pageLayout->addWidget(rbPolyline, 2, 0);
+ rbRectangle = new QRadioButton(tr("Rectangle"), this);
+ pageLayout->addWidget(rbRectangle, 3, 0);
+ rbEllipse = new QRadioButton(tr("Ellipse"), this);
+ pageLayout->addWidget(rbEllipse, 4, 0);
+
+ rbPolyline->setChecked(true);
+
+ pbClear = addButton(tr("Clear"), pageLayout, 5, 0);
+ pbLoad = addButton(tr("Load"), pageLayout, 6, 0);
+ pbSave = addButton(tr("Save"), pageLayout, 7, 0);
drawMapWidget = new DrawMapWidget(this);
- pageLayout->addWidget(drawMapWidget, 0, 1, 6, 1);
+ pageLayout->addWidget(drawMapWidget, 0, 1, 9, 1);
return pageLayout;
}
@@ -49,6 +60,10 @@
connect(pbClear, SIGNAL(clicked()), drawMapWidget, SLOT(clear()));
connect(pbLoad, SIGNAL(clicked()), this, SLOT(load()));
connect(pbSave, SIGNAL(clicked()), this, SLOT(save()));
+
+ connect(rbPolyline, SIGNAL(toggled(bool)), this, SLOT(pathTypeSwitched(bool)));
+ connect(rbRectangle, SIGNAL(toggled(bool)), this, SLOT(pathTypeSwitched(bool)));
+ connect(rbEllipse, SIGNAL(toggled(bool)), this, SLOT(pathTypeSwitched(bool)));
}
PageDrawMap::PageDrawMap(QWidget* parent) : AbstractPage(parent)
@@ -71,3 +86,13 @@
if(!fileName.isEmpty())
drawMapWidget->save(fileName);
}
+
+void PageDrawMap::pathTypeSwitched(bool b)
+{
+ if(b)
+ {
+ if(rbPolyline->isChecked()) drawMapWidget->setPathType(DrawMapScene::Polyline);
+ else if(rbRectangle->isChecked()) drawMapWidget->setPathType(DrawMapScene::Rectangle);
+ else if(rbEllipse->isChecked()) drawMapWidget->setPathType(DrawMapScene::Ellipse);
+ }
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagedrawmap.h hedgewars-0.9.20.5/QTfrontend/ui/page/pagedrawmap.h
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagedrawmap.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagedrawmap.h 2013-10-31 20:21:56.000000000 +0000
@@ -22,6 +22,7 @@
#include "AbstractPage.h"
class DrawMapWidget;
+class QRadioButton;
class PageDrawMap : public AbstractPage
{
@@ -42,10 +43,14 @@
QPushButton * pbLoad;
QPushButton * pbSave;
QCheckBox * cbEraser;
+ QRadioButton * rbPolyline;
+ QRadioButton * rbRectangle;
+ QRadioButton * rbEllipse;
private slots:
void load();
void save();
+ void pathTypeSwitched(bool b);
};
#endif
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pageeditteam.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pageeditteam.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pageeditteam.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pageeditteam.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -203,12 +203,23 @@
{
initPage();
- QRegExp pngSuffix("\\.png$");
-
m_playerHash = "0000000000000000000000000000000000000000";
+ m_loaded = false;
+}
+
+void PageEditTeam::lazyLoad()
+{
+ if(m_loaded) return;
+ m_loaded = true;
+ qDebug("[LAZINESS] PageEditTeam::lazyLoad()");
+
+ HatModel * hatsModel = DataManager::instance().hatModel();
+ for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
+ HHHats[i]->setModel(hatsModel);
- DataManager & dataMgr = DataManager::instance();
+ QRegExp pngSuffix("\\.png$");
+ DataManager & dataMgr = DataManager::instance();
QStringList list;
@@ -236,7 +247,7 @@
pix = pix.copy(0, 0, 32, 32);
QIcon icon(pix);
- QString grave = QString(file).remove(pngSuffix);
+ QString grave = file.remove(pngSuffix);
CBGrave->addItem(icon, grave);
}
@@ -327,6 +338,8 @@
void PageEditTeam::createTeam(const QString & name, const QString & playerHash)
{
m_playerHash = playerHash;
+ lazyLoad();
+
HWTeam newTeam(name);
loadTeam(newTeam);
}
@@ -334,6 +347,8 @@
void PageEditTeam::editTeam(const QString & name, const QString & playerHash)
{
m_playerHash = playerHash;
+ lazyLoad();
+
HWTeam team(name);
team.loadFromFile();
loadTeam(team);
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pageeditteam.h hedgewars-0.9.20.5/QTfrontend/ui/page/pageeditteam.h
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pageeditteam.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pageeditteam.h 2013-10-31 20:21:56.000000000 +0000
@@ -66,6 +66,7 @@
HWTeam data();
QString m_playerHash;
KeyBinder * binder;
+ bool m_loaded;
QLayout * bodyLayoutDefinition();
QLayout * footerLayoutDefinition();
@@ -78,6 +79,8 @@
QPushButton * btnRandomTeam;
QPushButton * btnTestSound;
+ void lazyLoad();
+
private slots:
void saveTeam();
void setRandomNames();
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagegamestats.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pagegamestats.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagegamestats.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagegamestats.cpp 2013-10-31 20:21:56.000000000 +0000
@@ -40,10 +40,15 @@
QLayout * PageGameStats::bodyLayoutDefinition()
{
+ kindOfPoints = QString("");
+ defaultGraphTitle = true;
QGridLayout * pageLayout = new QGridLayout();
pageLayout->setSpacing(20);
pageLayout->setColumnStretch(0, 1);
pageLayout->setColumnStretch(1, 1);
+ pageLayout->setRowStretch(0, 1);
+ pageLayout->setRowStretch(1, 20);
+ //pageLayout->setRowStretch(1, -1); this should work but there is unnecessary empty space betwin lines if used
pageLayout->setContentsMargins(7, 7, 7, 0);
QGroupBox * gb = new QGroupBox(this);
@@ -61,15 +66,15 @@
gbl->addWidget(l);
gbl->addWidget(labelGameStats);
gb->setLayout(gbl);
- pageLayout->addWidget(gb, 1, 1, 1, 2);
+ pageLayout->addWidget(gb, 1, 1);
// graph
graphic = new FitGraphicsView(gb);
- l = new QLabel(this);
- l->setTextFormat(Qt::RichText);
- l->setText(" " + PageGameStats::tr("Health graph") + " ");
- l->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
- gbl->addWidget(l);
+ labelGraphTitle = new QLabel(this);
+ labelGraphTitle->setTextFormat(Qt::RichText);
+ labelGraphTitle->setText(" " + PageGameStats::tr("Health graph") + " ");
+ labelGraphTitle->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ gbl->addWidget(labelGraphTitle);
gbl->addWidget(graphic);
graphic->scale(1.0, -1.0);
graphic->setBackgroundBrush(QBrush(Qt::black));
@@ -154,28 +159,41 @@
void PageGameStats::renderStats()
{
- QGraphicsScene * scene = new QGraphicsScene();
-
- QMap >::const_iterator i = healthPoints.constBegin();
- while (i != healthPoints.constEnd())
- {
- quint32 c = i.key();
- //QColor clanColor = QColor(qRgb((c >> 16) & 255, (c >> 8) & 255, c & 255));
- QVector hps = i.value();
-
- QPainterPath path;
- if (hps.size())
- path.moveTo(0, hps[0]);
-
- for(int t = 1; t < hps.size(); ++t)
- path.lineTo(t, hps[t]);
-
- scene->addPath(path, QPen(c));
- ++i;
- }
-
- graphic->setScene(scene);
- graphic->fitInView(graphic->sceneRect());
+ graphic->show();
+ labelGraphTitle-> show();
+ if(defaultGraphTitle) {
+ labelGraphTitle->setText(" " + PageGameStats::tr("Health graph") + " ");
+ } else {
+ defaultGraphTitle = true;
+ }
+ // if not health data sent
+ if(healthPoints.size() == 0) {
+ labelGraphTitle->hide();
+ graphic->hide();
+ } else {
+ QGraphicsScene * scene = new QGraphicsScene();
+
+ QMap >::const_iterator i = healthPoints.constBegin();
+ while (i != healthPoints.constEnd())
+ {
+ quint32 c = i.key();
+ //QColor clanColor = QColor(qRgb((c >> 16) & 255, (c >> 8) & 255, c & 255));
+ QVector hps = i.value();
+
+ QPainterPath path;
+ if (hps.size())
+ path.moveTo(0, hps[0]);
+
+ for(int t = 1; t < hps.size(); ++t)
+ path.lineTo(t, hps[t]);
+
+ scene->addPath(path, QPen(c));
+ ++i;
+ }
+
+ graphic->setScene(scene);
+ graphic->fitInView(graphic->sceneRect());
+ }
}
void PageGameStats::GameStats(char type, const QString & info)
@@ -217,6 +235,13 @@
healthPoints[clan].append(hp);
break;
}
+ case 'g' :
+ {
+ // TODO: change default picture or add change pic capability
+ defaultGraphTitle = false;
+ labelGraphTitle->setText(" " + info + " ");
+ break;
+ }
case 'T': // local team stats
{
//AddStatText("local team: " + info + "
");
@@ -232,7 +257,11 @@
}
break;
}
-
+ case 'p' :
+ {
+ kindOfPoints = info;
+ break;
+ }
case 'P' :
{
int i = info.indexOf(' ');
@@ -269,7 +298,13 @@
}
QString message;
- QString killstring = PageGameStats::tr("(%1 kill)", "", kills).arg(kills);
+ QString killstring;
+ if(kindOfPoints.compare("") == 0) {
+ killstring = PageGameStats::tr("(%1 kill)", "", kills).arg(kills);
+ } else {
+ killstring = PageGameStats::tr("(%1 %2)", "", kills).arg(kills).arg(kindOfPoints);
+ kindOfPoints = QString("");
+ }
message = QString("
%1 %2. %3 ").arg(image, QString::number(playerPosition), playername, clanColor.name()) + killstring + "
";
@@ -300,6 +335,12 @@
AddStatText(message);
break;
}
+ case 'c' :
+ {
+ QString message = " "+info+"
";
+ AddStatText(message);
+ break;
+ }
}
}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagegamestats.h hedgewars-0.9.20.5/QTfrontend/ui/page/pagegamestats.h
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagegamestats.h 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagegamestats.h 2013-10-31 20:21:56.000000000 +0000
@@ -49,6 +49,8 @@
QLabel *labelGameStats;
QLabel *labelGameWin;
QLabel *labelGameRank;
+ QLabel *labelGraphTitle;
+ QString kindOfPoints;
FitGraphicsView * graphic;
public slots:
@@ -67,6 +69,7 @@
QMap > healthPoints;
unsigned int playerPosition;
quint32 lastColor;
+ bool defaultGraphTitle;
protected:
QLayout * bodyLayoutDefinition();
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagemain.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pagemain.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagemain.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagemain.cpp 2014-01-08 16:25:17.000000000 +0000
@@ -21,10 +21,12 @@
#include
#include
#include
+#include
#include "pagemain.h"
#include "hwconsts.h"
#include "hwform.h"
+#include "DataManager.h"
QLayout * PageMain::bodyLayoutDefinition()
{
@@ -119,6 +121,9 @@
void PageMain::connectSignals()
{
+#ifndef QT_DEBUG
+ connect(this, SIGNAL(pageEnter()), this, SLOT(updateTip()));
+#endif
connect(BtnNet, SIGNAL(clicked()), this, SLOT(toggleNetworkChoice()));
//connect(BtnNetLocal, SIGNAL(clicked()), this, SLOT(toggleNetworkChoice()));
//connect(BtnNetOfficial, SIGNAL(clicked()), this, SLOT(toggleNetworkChoice()));
@@ -132,16 +137,19 @@
if(frontendEffects)
setAttribute(Qt::WA_NoSystemBackground, true);
mainNote->setOpenExternalLinks(true);
-
-#ifdef DEBUG
+#ifdef QT_DEBUG
setDefaultDescription(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!"));
#else
- setDefaultDescription(QLabel::tr("Tip: ") + randomTip());
+ setDefaultDescription(QLabel::tr("Tip: %1").arg(randomTip()));
#endif
+}
+void PageMain::updateTip()
+{
+ setDefaultDescription(QLabel::tr("Tip: %1").arg(randomTip()));
}
-QString PageMain::randomTip() const
+QString PageMain::randomTip()
{
#ifdef _WIN32
int platform = 1;
@@ -150,35 +158,62 @@
#else
int platform = 3;
#endif
- QStringList 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;
+ if(!Tips.length())
+ {
+ DataManager & dataMgr = DataManager::instance();
+
+ // get locale
+ QSettings settings(dataMgr.settingsFileName(),
+ QSettings::IniFormat);
+
+ QString loc = settings.value("misc/locale", "").toString();
+ if (loc.isEmpty())
+ loc = QLocale::system().name();
+
+ QString tipFile = QString("physfs://Locale/tips_" + loc + ".xml");
+
+ // if file is non-existant try with language only
+ if (!QFile::exists(tipFile))
+ tipFile = QString("physfs://Locale/tips_" + loc.remove(QRegExp("_.*$")) + ".xml");
+
+ // fallback if file for current locale is non-existant
+ if (!QFile::exists(tipFile))
+ tipFile = QString("physfs://Locale/tips_en.xml");
+
+ QFile file(tipFile);
+ file.open(QIODevice::ReadOnly);
+ QTextStream in(&file);
+ in.setCodec("UTF-8");
+ 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 << split_string[1];
+ line = in.readLine();
}
- 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
+ // 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
- file.close();
- return Tips[QTime(0, 0, 0).secsTo(QTime::currentTime()) % Tips.length()];
+ file.close();
+ }
+
+ if(Tips.length())
+ return Tips[QTime(0, 0, 0).secsTo(QTime::currentTime()) % Tips.length()];
+ else
+ return QString();
}
void PageMain::toggleNetworkChoice()
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagemain.h hedgewars-0.9.20.5/QTfrontend/ui/page/pagemain.h
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagemain.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagemain.h 2013-12-25 05:19:22.000000000 +0000
@@ -48,10 +48,12 @@
void connectSignals();
QIcon originalNetworkIcon, disabledNetworkIcon;
- QString randomTip() const;
+ QString randomTip();
+ QStringList Tips;
private slots:
void toggleNetworkChoice();
+ void updateTip();
};
#endif
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagenet.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pagenet.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagenet.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagenet.cpp 2013-10-31 20:21:57.000000000 +0000
@@ -73,7 +73,7 @@
BtnNetSvrStart = formattedButton(QPushButton::tr("Start server"));
BtnNetSvrStart->setMinimumWidth(180);
QString serverPath = bindir->absolutePath() + "/hedgewars-server";
-#ifdef Q_WS_WIN
+#ifdef Q_OS_WIN
serverPath += + ".exe";
#endif
QFile server(serverPath);
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagenetserver.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pagenetserver.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagenetserver.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagenetserver.cpp 2013-10-31 20:21:57.000000000 +0000
@@ -76,7 +76,7 @@
BtnShare = new QPushButton(gb);
BtnShare->setText(QPushButton::tr("Invite your friends to your server in just 1 click!"));
- BtnShare->setWhatsThis(QPushButton::tr("Click to copy your unique server URL in your clipboard. Send this link to your friends ands and they will be able to join you."));
+ BtnShare->setWhatsThis(QPushButton::tr("Click to copy your unique server URL to your clipboard. Send this link to your friends and they will be able to join you."));
gbLayout->addWidget(BtnShare, 2, 1);
labelURL = new QLabel(gb);
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pageoptions.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pageoptions.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pageoptions.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pageoptions.cpp 2013-10-31 20:21:57.000000000 +0000
@@ -279,10 +279,10 @@
// make some min/max-consts, shared with engine?
windowWidthEdit = new QSpinBox(groupGame);
windowWidthEdit->setRange(640, 102400);
- windowWidthEdit->setFixedSize(55, CBResolution->height());
+ windowWidthEdit->setFixedSize(60, CBResolution->height());
windowHeightEdit = new QSpinBox(groupGame);
windowHeightEdit->setRange(480, 102400);
- windowHeightEdit->setFixedSize(55, CBResolution->height());
+ windowHeightEdit->setFixedSize(60, CBResolution->height());
winResLayout->addWidget(windowWidthEdit, 0);
winResLayout->addWidget(winLabelX, 0);
@@ -365,6 +365,39 @@
WeaponTooltip = new QCheckBox(groupGame);
WeaponTooltip->setText(QCheckBox::tr("Show ammo menu tooltips"));
groupGame->layout()->addWidget(WeaponTooltip, 9, 0, 1, 2);
+
+ groupGame->addDivider();
+
+ lblTags = new QLabel(groupGame);
+ lblTags->setText(QLabel::tr("Displayed tags above hogs and translucent tags"));
+ groupGame->layout()->addWidget(lblTags, 11, 0, 1, 2);
+
+ tagsContainer = new QWidget();
+ QHBoxLayout * tagsLayout = new QHBoxLayout(tagsContainer);
+ tagsLayout->setSpacing(0);
+ groupGame->layout()->addWidget(tagsContainer, 12, 0, 1, 2);
+
+ CBTeamTag = new QCheckBox(groupGame);
+ CBTeamTag->setText(QCheckBox::tr("Team"));
+ CBTeamTag->setWhatsThis(QCheckBox::tr("Enable team tags by default"));
+
+ CBHogTag = new QCheckBox(groupGame);
+ CBHogTag->setText(QCheckBox::tr("Hog"));
+ CBHogTag->setWhatsThis(QCheckBox::tr("Enable hedgehog tags by default"));
+
+ CBHealthTag = new QCheckBox(groupGame);
+ CBHealthTag->setText(QCheckBox::tr("Health"));
+ CBHealthTag->setWhatsThis(QCheckBox::tr("Enable health tags by default"));
+
+ CBTagOpacity = new QCheckBox(groupGame);
+ CBTagOpacity->setText(QCheckBox::tr("Translucent"));
+ CBTagOpacity->setWhatsThis(QCheckBox::tr("Enable translucent tags by default"));
+
+ tagsLayout->addWidget(CBTeamTag, 0);
+ tagsLayout->addWidget(CBHogTag, 0);
+ tagsLayout->addWidget(CBHealthTag, 0);
+ tagsLayout->addWidget(CBTagOpacity, 0);
+ tagsLayout->addStretch(1);
}
{ // group: frontend
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pageoptions.h hedgewars-0.9.20.5/QTfrontend/ui/page/pageoptions.h
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pageoptions.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pageoptions.h 2013-10-31 20:21:57.000000000 +0000
@@ -90,6 +90,13 @@
QCheckBox *CBSavePassword;
QCheckBox *CBAltDamage;
QCheckBox *CBNameWithDate;
+
+
+ QCheckBox *CBTeamTag;
+ QCheckBox *CBHogTag;
+ QCheckBox *CBHealthTag;
+ QCheckBox *CBTagOpacity;
+
#ifdef __APPLE__
QCheckBox *CBAutoUpdate;
QPushButton *BtnUpdateNow;
@@ -165,7 +172,9 @@
QLabel * lblFullScreenRes;
QLabel * lblWinScreenRes;
+ QLabel * lblTags;
QWidget * winResContainer;
+ QWidget * tagsContainer;
private slots:
void forceFullscreen(int index);
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pageroomslist.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pageroomslist.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pageroomslist.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pageroomslist.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -169,47 +169,11 @@
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->addSpacing(filterSpacing);
-
- // Weapons dropdown
-
- 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->addSpacing(filterSpacing);
-
- // Clear filters button
-
- BtnClear = addButton(tr("Clear filters"), filterLayout, 0);
- weaponLabel->setFixedHeight(CBWeapons->height());
- BtnClear->setStyleSheet("padding: 4px;");
-
// Lobby chat
chatWidget = new HWChatWidget(this, false);
m_splitter->addWidget(chatWidget);
- CBRules->addItem(QComboBox::tr("Any"));
-
return pageLayout;
}
@@ -230,7 +194,6 @@
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()));
@@ -238,8 +201,6 @@
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);
@@ -273,22 +234,8 @@
{
roomsModel = NULL;
stateFilteredModel = NULL;
- schemeFilteredModel = NULL;
- weaponsFilteredModel = NULL;
initPage();
-
- // not the most elegant solution but it works
- ammoSchemeModel = new AmmoSchemeModel(this, NULL);
- for (int i = 0; i < ammoSchemeModel->predefSchemesNames.count(); i++)
- CBRules->addItem(ammoSchemeModel->predefSchemesNames.at(i).toAscii().constData());
-
- CBWeapons->addItem(QComboBox::tr("Any"));
- for (int i = 0; i < cDefaultAmmos.count(); i++)
- {
- QPair ammo = cDefaultAmmos.at(i);
- CBWeapons->addItem(ammo.first.toAscii().constData());
- }
}
@@ -531,17 +478,17 @@
void PageRoomsList::onCreateClick()
{
- RoomNamePrompt prompt(parentWidget()->parentWidget(), m_gameSettings->value("frontend/lastroomname", QString()).toString());
- connect(&prompt, SIGNAL(roomNameChosen(const QString &)), this, SLOT(onRoomNameChosen(const QString &)));
- prompt.exec();
+ RoomNamePrompt prompt(this, m_gameSettings->value("frontend/lastroomname", QString()).toString());
+ if(prompt.exec())
+ onRoomNameChosen(prompt.getRoomName(), prompt.getPassword());
}
-void PageRoomsList::onRoomNameChosen(const QString & roomName)
+void PageRoomsList::onRoomNameChosen(const QString & roomName, const QString & password)
{
if (!roomName.trimmed().isEmpty())
{
m_gameSettings->setValue("frontend/lastroomname", roomName);
- emit askForCreateRoom(roomName);
+ emit askForCreateRoom(roomName, password);
}
else
{
@@ -570,7 +517,7 @@
if (!gameInLobby)
emit askJoinConfirmation(roomName);
else
- emit askForJoinRoom(roomName);
+ emit askForJoinRoom(roomName, QString());
}
void PageRoomsList::onRefreshClick()
@@ -578,16 +525,6 @@
emit askForRoomList();
}
-void PageRoomsList::onClearClick()
-{
- showGamesInLobby->setChecked(true);
- showGamesInProgress->setChecked(true);
- CBRules->setCurrentIndex(0);
- CBWeapons->setCurrentIndex(0);
- searchText->clear();
- searchText->setFocus();
-}
-
void PageRoomsList::onJoinConfirmation(const QString & room)
{
@@ -600,7 +537,7 @@
if (reallyJoinMsg.exec() == QMessageBox::Ok)
{
- emit askForJoinRoom(room);
+ emit askForJoinRoom(room, QString());
}
}
@@ -628,25 +565,15 @@
roomsModel->sort(RoomsListModel::StateColumn, Qt::AscendingOrder);
stateFilteredModel = new QSortFilterProxyModel(this);
- schemeFilteredModel = new QSortFilterProxyModel(this);
- weaponsFilteredModel = new QSortFilterProxyModel(this);
stateFilteredModel->setDynamicSortFilter(true);
- schemeFilteredModel->setDynamicSortFilter(true);
- weaponsFilteredModel->setDynamicSortFilter(true);
roomsModel->setFilterKeyColumn(-1); // search in all columns
stateFilteredModel->setFilterKeyColumn(RoomsListModel::StateColumn);
- schemeFilteredModel->setFilterKeyColumn(RoomsListModel::SchemeColumn);
- weaponsFilteredModel->setFilterKeyColumn(RoomsListModel::WeaponsColumn);
roomsModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- schemeFilteredModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- weaponsFilteredModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- schemeFilteredModel->setSourceModel(stateFilteredModel);
- weaponsFilteredModel->setSourceModel(schemeFilteredModel);
- roomsModel->setSourceModel(weaponsFilteredModel);
+ roomsModel->setSourceModel(stateFilteredModel);
// let the table view display the last model in the filter chain
roomsList->setModel(roomsModel);
@@ -660,8 +587,6 @@
stateFilteredModel->setSourceModel(model);
- roomsList->hideColumn(RoomsListModel::StateColumn);
-
QHeaderView * h = roomsList->horizontalHeader();
h->setSortIndicatorShown(true);
@@ -678,6 +603,8 @@
h->resizeSection(RoomsListModel::WeaponsColumn, 100);
}
+ // hide column used for filtering
+ roomsList->hideColumn(RoomsListModel::StateColumn);
// save header state on change
connect(roomsList->horizontalHeader(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)),
@@ -714,29 +641,17 @@
if (roomsModel == NULL)
return;
- roomsModel->setFilterWildcard(QString("*%1*").arg(searchText->text()));
+ roomsModel->setFilterFixedString(searchText->text());
bool stateLobby = showGamesInLobby->isChecked();
bool stateProgress = showGamesInProgress->isChecked();
if (stateLobby && stateProgress)
- stateFilteredModel->setFilterWildcard("*"); // "any"
+ stateFilteredModel->setFilterFixedString(QString()); // "any"
else if (stateLobby != stateProgress)
stateFilteredModel->setFilterFixedString(QString(stateProgress));
else
stateFilteredModel->setFilterFixedString(QString("none")); // Basically, none.
-
- if (CBRules->currentIndex() == 0)
- schemeFilteredModel->setFilterWildcard("*"); // "any"
- else
- schemeFilteredModel->setFilterWildcard(
- QString("*%1*").arg(CBRules->currentText()));
-
- if (CBWeapons->currentIndex() == 0)
- weaponsFilteredModel->setFilterWildcard("*"); // "any"
- else
- weaponsFilteredModel->setFilterWildcard(
- QString("*%1*").arg(CBWeapons->currentText()));
}
void PageRoomsList::setSettings(QSettings *settings)
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pageroomslist.h hedgewars-0.9.20.5/QTfrontend/ui/page/pageroomslist.h
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pageroomslist.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pageroomslist.h 2013-12-25 05:19:22.000000000 +0000
@@ -55,10 +55,7 @@
QPushButton * BtnCreate;
QPushButton * BtnJoin;
QPushButton * BtnAdmin;
- QPushButton * BtnClear;
QComboBox * CBState;
- QComboBox * CBRules;
- QComboBox * CBWeapons;
HWChatWidget * chatWidget;
QLabel * lblCount;
@@ -70,8 +67,8 @@
void updateNickCounter(int cnt);
signals:
- void askForCreateRoom(const QString &);
- void askForJoinRoom(const QString &);
+ void askForCreateRoom(const QString &, const QString &);
+ void askForJoinRoom(const QString &, const QString &);
void askForRoomList();
void askJoinConfirmation(const QString &);
@@ -84,12 +81,11 @@
void onCreateClick();
void onJoinClick();
void onRefreshClick();
- void onClearClick();
void onJoinConfirmation(const QString &);
void onSortIndicatorChanged(int logicalIndex, Qt::SortOrder order);
void onFilterChanged();
void saveHeaderState();
- void onRoomNameChosen(const QString &);
+ void onRoomNameChosen(const QString &, const QString &password);
void roomSelectionChanged(const QModelIndex &, const QModelIndex &);
void moveSelectionUp();
void moveSelectionDown();
@@ -98,8 +94,6 @@
QSettings * m_gameSettings;
QSortFilterProxyModel * roomsModel;
QSortFilterProxyModel * stateFilteredModel;
- QSortFilterProxyModel * schemeFilteredModel;
- QSortFilterProxyModel * weaponsFilteredModel;
QAction * showGamesInLobby;
QAction * showGamesInProgress;
QSplitter * m_splitter;
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagescheme.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pagescheme.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagescheme.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagescheme.cpp 2014-01-08 16:25:17.000000000 +0000
@@ -383,6 +383,23 @@
glBSLayout->addWidget(SB_GetAwayTime,14,2,1,1);
l = new QLabel(gbBasicSettings);
+ l->setText(QLabel::tr("World Edge"));
+ l->setWordWrap(true);
+ glBSLayout->addWidget(l,15,0,1,1);
+ l = new QLabel(gbBasicSettings);
+ l->setFixedSize(32,32);
+ l->setPixmap(QPixmap(":/res/iconEarth.png"));
+ glBSLayout->addWidget(l,15,1,1,1);
+ CB_WorldEdge = new QComboBox(gbBasicSettings);
+ CB_WorldEdge->insertItem(0, tr("None (Default)"));
+ CB_WorldEdge->insertItem(1, tr("Wrap (World wraps)"));
+ CB_WorldEdge->insertItem(2, tr("Bounce (Edges reflect)"));
+ CB_WorldEdge->insertItem(3, tr("Sea (Edges connect to sea)"));
+ /* CB_WorldEdge->insertItem(4, tr("Skybox")); */
+ glBSLayout->addWidget(CB_WorldEdge,15,2,1,1);
+
+
+ l = new QLabel(gbBasicSettings);
l->setText(QLabel::tr("Scheme Name:"));
LE_name = new QLineEdit(this);
@@ -471,6 +488,7 @@
mapper->addMapping(SB_HealthDecrease, 38);
mapper->addMapping(SB_RopeModifier, 39);
mapper->addMapping(SB_GetAwayTime, 40);
+ mapper->addMapping(CB_WorldEdge, 41, "currentIndex");
mapper->toFirst();
}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagescheme.h hedgewars-0.9.20.5/QTfrontend/ui/page/pagescheme.h
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagescheme.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagescheme.h 2014-01-08 16:25:17.000000000 +0000
@@ -91,6 +91,7 @@
QSpinBox * SB_Explosives;
QSpinBox * SB_RopeModifier;
QSpinBox * SB_GetAwayTime;
+ QComboBox * CB_WorldEdge;
QLineEdit * LE_name;
QGroupBox * gbGameModes;
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/page/pagevideos.cpp hedgewars-0.9.20.5/QTfrontend/ui/page/pagevideos.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/page/pagevideos.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/page/pagevideos.cpp 2014-01-08 16:25:17.000000000 +0000
@@ -414,7 +414,7 @@
setName(item, newName);
}
}
-#ifdef Q_WS_WIN
+#ifdef Q_OS_WIN
// there is a bug in qt, QDir::rename() doesn't fail on such names but damages files
if (newName.contains(QRegExp("[\"*:<>?\\/|]")))
{
@@ -508,8 +508,8 @@
else
{
QString path = item->path();
- desc += tr("Date: %1\n").arg(QFileInfo(path).created().toString(Qt::DefaultLocaleLongDate));
- desc += tr("Size: %1\n").arg(FileSizeStr(path));
+ desc += tr("Date: %1").arg(QFileInfo(path).created().toString(Qt::DefaultLocaleLongDate)) + "\n";
+ desc += tr("Size: %1").arg(FileSizeStr(path)) + "\n";
if (item->desc.isEmpty())
{
// Extract description from file;
@@ -845,7 +845,7 @@
for (int i = 0; i < array.size(); i++)
array[i] = array[i] ^ 0xC4 ^ i;
array = array.toBase64();
- return QString::fromAscii(array.data());
+ return QString::fromLatin1(array.data());
}
static QString unprotectPass(QString str)
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/qaspectratiolayout.cpp hedgewars-0.9.20.5/QTfrontend/ui/qaspectratiolayout.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/qaspectratiolayout.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/qaspectratiolayout.cpp 1970-01-01 00:00:00.000000000 +0000
@@ -1,244 +0,0 @@
-/*
- * Copyright (c) 2009 Nokia Corporation.
- */
-
-#include "qaspectratiolayout.h"
-
-QAspectRatioLayout::QAspectRatioLayout(QWidget* parent, int spacing) : QLayout(parent)
-{
- init(spacing);
-}
-
-QAspectRatioLayout::QAspectRatioLayout(int spacing)
-{
- init(spacing);
-}
-
-QAspectRatioLayout::~QAspectRatioLayout()
-{
- delete item;
- delete lastReceivedRect;
- delete _geometry;
-}
-
-void QAspectRatioLayout::init(int spacing)
-{
- item = 0;
- lastReceivedRect = new QRect(0, 0, 0, 0);
- _geometry = new QRect(0, 0, 0, 0);
- setSpacing(spacing);
-}
-
-
-/* Adds item if place isn't already taken. */
-void QAspectRatioLayout::add(QLayoutItem* item)
-{
- if(!hasItem())
- {
- replaceItem(item);
- }
-}
-
-/* Adds item if place isn't already taken. */
-void QAspectRatioLayout::addItem(QLayoutItem* item)
-{
- if(!hasItem())
- {
- replaceItem(item);
- }
-}
-
-/* Adds widget if place isn't already taken. */
-void QAspectRatioLayout::addWidget(QWidget* widget)
-{
- if(!hasItem())
- {
- replaceItem(new QWidgetItem(widget));
- }
-}
-
-/* Returns the item pointer and dereferences it here. */
-QLayoutItem* QAspectRatioLayout::take()
-{
- QLayoutItem* item = 0;
- if(this->hasItem())
- {
- item = this->item;
- this->item = 0;
- }
- return item;
-}
-
-/* Returns the item pointer and dereferences it here. */
-QLayoutItem* QAspectRatioLayout::takeAt(int index)
-{
- if(index != 0)
- {
- return 0;
- }
- return this->take();
-}
-
-/* Returns the item pointer. */
-QLayoutItem* QAspectRatioLayout::itemAt(int index) const
-{
- if(index != 0)
- {
- return 0;
- }
- if(hasItem())
- {
- return this->item;
- }
- return 0;
-}
-
-/* Checks if we have an item. */
-bool QAspectRatioLayout::hasItem() const
-{
- return this->item != 0;
-}
-
-/* Returns the count of items which can be either 0 or 1. */
-int QAspectRatioLayout::count() const
-{
- int returnValue = 0;
- if(hasItem())
- {
- returnValue = 1;
- }
- return returnValue;
-}
-
-/* Replaces the item with the new and returns the old. */
-QLayoutItem* QAspectRatioLayout::replaceItem(QLayoutItem* item)
-{
- QLayoutItem* old = 0;
- if(this->hasItem())
- {
- old = this->item;
- }
- this->item = item;
- setGeometry(*this->_geometry);
- return old;
-}
-
-/* Tells which way layout expands. */
-Qt::Orientations QAspectRatioLayout::expandingDirections() const
-{
- return Qt::Horizontal | Qt::Vertical;
-}
-
-/* Tells which size is preferred. */
-QSize QAspectRatioLayout::sizeHint() const
-{
- return this->item->minimumSize();
-}
-
-/* Tells minimum size. */
-QSize QAspectRatioLayout::minimumSize() const
-{
- return this->item->minimumSize();
-}
-
-/*
- * Tells if heightForWidth calculations is handled.
- * It isn't since width isn't enough to calculate
- * proper size.
- */
-bool QAspectRatioLayout::hasHeightForWidth() const
-{
- return false;
-}
-
-/* Replaces lastReceivedRect. */
-void QAspectRatioLayout::setLastReceivedRect(const QRect& rect)
-{
- QRect* oldRect = this->lastReceivedRect;
- this->lastReceivedRect = new QRect(rect.topLeft(), rect.size());
- delete oldRect;
-}
-
-/* Returns geometry */
-QRect QAspectRatioLayout::geometry()
-{
- return QRect(*this->_geometry);
-}
-
-/* Sets geometry to given size. */
-void QAspectRatioLayout::setGeometry(const QRect& rect)
-{
- /*
- * We check if the item is set and
- * if size is the same previously received.
- * If either is false nothing is done.
- */
- if(!this->hasItem() ||
- areRectsEqual(*this->lastReceivedRect, rect))
- {
- return;
- }
- /* Replace the last received rectangle. */
- setLastReceivedRect(rect);
- /* Calculate proper size for the item relative to the received size. */
- QSize properSize = calculateProperSize(rect.size());
- /* Calculate center location in the rect and with item size. */
- QPoint properLocation = calculateCenterLocation(rect.size(), properSize);
- /* Set items geometry */
- this->item->setGeometry(QRect(properLocation, properSize));
- QRect* oldRect = this->_geometry;
- /* Cache the calculated geometry. */
- this->_geometry = new QRect(properLocation, properSize);
- delete oldRect;
- /* Super classes setGeometry */
- QLayout::setGeometry(*this->_geometry);
-}
-
-/* Takes the shortest side and creates QSize
- * with the shortest side as width and height. */
-QSize QAspectRatioLayout::calculateProperSize(QSize from) const
-{
- QSize properSize;
- if(from.height() * 2 < from.width())
- {
- properSize.setHeight(from.height() - this->margin());
- properSize.setWidth(from.height() * 2 - this->margin());
- }
- else
- {
- properSize.setWidth(from.width() - this->margin());
- properSize.setHeight(from.width() / 2 - this->margin());
- }
- return properSize;
-}
-
-/* Calculates center location from the given height and width for item size. */
-QPoint QAspectRatioLayout::calculateCenterLocation(QSize from,
- QSize itemSize) const
-{
- QPoint centerLocation;
- if((from.width() - itemSize.width()) > 0)
- {
- centerLocation.setX((from.width() - itemSize.width())/2);
- }
- if((from.height() - itemSize.height()) > 0)
- {
- centerLocation.setY((from.height() - itemSize.height())/2);
- }
- return centerLocation;
-}
-
-/* Compares if two QRects are equal. */
-bool QAspectRatioLayout::areRectsEqual(const QRect& a,
- const QRect& b) const
-{
- bool result = false;
- if(a.x() == b.x() &&
- a.y() == b.y() &&
- a.height() == b.height() &&
- a.width() == b.width())
- {
- result = true;
- }
- return result;
-}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/qaspectratiolayout.h hedgewars-0.9.20.5/QTfrontend/ui/qaspectratiolayout.h
--- hedgewars-0.9.19.3/QTfrontend/ui/qaspectratiolayout.h 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/qaspectratiolayout.h 1970-01-01 00:00:00.000000000 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2009 Nokia Corporation.
- */
-
-#ifndef QASPECTRATIOLAYOUT_H_
-#define QASPECTRATIOLAYOUT_H_
-
-#include
-#include
-#include
-#include
-#include
-
-
-class QAspectRatioLayout : public QLayout
-{
- Q_OBJECT
-
- public:
- QAspectRatioLayout(QWidget* parent, int spacing =-1);
- QAspectRatioLayout(int spacing = -1);
- ~QAspectRatioLayout();
-
- /* Convenience method */
- virtual void add(QLayoutItem* item);
-
- /* http://doc.trolltech.com/qlayout.html#addItem */
- virtual void addItem(QLayoutItem* item);
- /* http://doc.trolltech.com/qlayout.html#addWidget */
- virtual void addWidget(QWidget* widget);
- /* http://doc.trolltech.com/qlayout.html#takeAt */
- virtual QLayoutItem* takeAt(int index);
- /* http://doc.trolltech.com/qlayout.html#itemAt */
- virtual QLayoutItem* itemAt(int index) const;
- /* http://doc.trolltech.com/qlayout.html#count */
- virtual int count() const;
-
- /*
- * These are ours since we do have only one item.
- */
- virtual QLayoutItem* replaceItem(QLayoutItem* item);
- virtual QLayoutItem* take();
- virtual bool hasItem() const;
-
- /* http://doc.trolltech.com/qlayout.html#expandingDirections */
- virtual Qt::Orientations expandingDirections() const;
-
- /*
- * This method contains most of the juice of this article.
- * http://doc.trolltech.com/qlayoutitem.html#setGeometry
- */
- virtual void setGeometry(const QRect& rect);
- /* http://doc.trolltech.com/qlayoutitem.html#geometry */
- virtual QRect geometry();
-
- /* http://doc.trolltech.com/qlayoutitem.html#sizeHint */
- virtual QSize sizeHint() const;
- /* http://doc.trolltech.com/qlayout.html#minimumSize */
- virtual QSize minimumSize() const;
- /* http://doc.trolltech.com/qlayoutitem.html#hasHeightForWidth */
- virtual bool hasHeightForWidth() const;
-
- private:
- /* Saves the last received rect. */
- void setLastReceivedRect(const QRect& rect);
- /* Used to initialize the object. */
- void init(int spacing);
- /* Calculates the maximum size for the item from the assigned size. */
- QSize calculateProperSize(QSize from) const;
- /* Calculates the center location from the assigned size and
- * the items size. */
- QPoint calculateCenterLocation(QSize from, QSize itemSize) const;
- /* Check if two QRects are equal */
- bool areRectsEqual(const QRect& a, const QRect& b) const;
- /* Contains item reference */
- QLayoutItem* item;
- /*
- * Used for caching so we won't do calculations every time
- * setGeometry is called.
- */
- QRect* lastReceivedRect;
- /* Contains geometry */
- QRect* _geometry;
-
-};
-
-#endif /* QASPECTRATIOLAYOUT_H_ */
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/about.cpp hedgewars-0.9.20.5/QTfrontend/ui/widget/about.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/about.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/about.cpp 2014-01-08 16:25:17.000000000 +0000
@@ -39,6 +39,15 @@
}
#endif
+
+#if defined(Q_OS_WINDOWS)
+#define sopath(x) x ".dll"
+#elif defined(Q_OS_MAC)
+#define sopath(x) "@executable_path/../Frameworks/" x ".framework/" x
+#else
+#define sopath(x) "lib" x ".so"
+#endif
+
#include "about.h"
About::About(QWidget * parent) :
@@ -52,11 +61,8 @@
QLabel *imageLabel = new QLabel;
QImage image(":/res/Hedgehog.png");
imageLabel->setPixmap(QPixmap::fromImage(image));
- imageLabel->setScaledContents(true);
- imageLabel->setMinimumWidth(2.8);
- imageLabel->setMaximumWidth(280);
- imageLabel->setMinimumHeight(30);
- imageLabel->setMaximumHeight(300);
+ imageLabel->setFixedWidth(273);
+ imageLabel->setFixedHeight(300);
leftLayout->addWidget(imageLabel, 0, Qt::AlignHCenter);
@@ -93,10 +99,62 @@
libinfo.append(QString(tr("Unknown Compiler")).arg(__VERSION__) + QString(" "));
#endif
+ const SDL_version *sdl_ver = SDL_Linked_Version();
libinfo.append(QString("SDL version: %1.%2.%3 ")
- .arg(SDL_MAJOR_VERSION)
- .arg(SDL_MINOR_VERSION)
- .arg(SDL_PATCHLEVEL));
+ .arg(sdl_ver->major)
+ .arg(sdl_ver->minor)
+ .arg(sdl_ver->patch));
+
+ const SDL_version *sdlmixer_ver = Mix_Linked_Version();
+ libinfo.append(QString("SDL_mixer version: %1.%2.%3 ")
+ .arg(sdlmixer_ver->major)
+ .arg(sdlmixer_ver->minor)
+ .arg(sdlmixer_ver->patch));
+
+ // the remaining sdl modules used only in engine, so instead of needlessly linking them here
+ // we dynamically call the function returning the linked version
+ void *sdlnet_handle = SDL_LoadObject(sopath("SDL_net"));
+ if (sdlnet_handle != NULL) {
+ SDL_version *(*sdlnet_ver_get)(void) = NULL;
+ sdlnet_ver_get = (SDL_version *(*)(void)) SDL_LoadFunction(sdlnet_handle, "SDLNet_Linked_Version");
+ if (sdlnet_ver_get != NULL) {
+ SDL_version *sdlnet_ver = sdlnet_ver_get();
+ libinfo.append(QString("SDL_net version: %1.%2.%3 ")
+ .arg(sdlnet_ver->major)
+ .arg(sdlnet_ver->minor)
+ .arg(sdlnet_ver->patch));
+ }
+ SDL_UnloadObject(sdlnet_handle);
+ }
+
+ void *sdlimage_handle = SDL_LoadObject(sopath("SDL_image"));
+ if (sdlimage_handle != NULL) {
+ SDL_version *(*sdlimage_ver_get)(void) = NULL;
+ sdlimage_ver_get = (SDL_version *(*)(void)) SDL_LoadFunction(sdlimage_handle, "IMG_Linked_Version");
+ if (sdlimage_ver_get != NULL) {
+ SDL_version *sdlimage_ver = sdlimage_ver_get();
+ libinfo.append(QString("SDL_image version: %1.%2.%3 ")
+ .arg(sdlimage_ver->major)
+ .arg(sdlimage_ver->minor)
+ .arg(sdlimage_ver->patch));
+ }
+ SDL_UnloadObject(sdlnet_handle);
+ }
+
+ void *sdlttf_handle = SDL_LoadObject(sopath("SDL_ttf"));
+ if (sdlttf_handle != NULL) {
+ SDL_version *(*sdlttf_ver_get)(void) = NULL;
+ sdlttf_ver_get = (SDL_version *(*)(void)) SDL_LoadFunction(sdlttf_handle, "TTF_Linked_Version");
+ if (sdlttf_ver_get != NULL) {
+ SDL_version *sdlttf_ver = sdlttf_ver_get();
+ libinfo.append(QString("SDL_ttf version: %1.%2.%3 ")
+ .arg(sdlttf_ver->major)
+ .arg(sdlttf_ver->minor)
+ .arg(sdlttf_ver->patch));
+ }
+ SDL_UnloadObject(sdlnet_handle);
+ }
+
libinfo.append(QString("Qt version: %1 ").arg(QT_VERSION_STR));
@@ -112,6 +170,8 @@
.arg(PHYSFS_VER_MINOR)
.arg(PHYSFS_VER_PATCH));
+ // TODO: how to add Lua information?
+
QLabel * lblLibInfo = new QLabel();
lblLibInfo->setOpenExternalLinks(true);
lblLibInfo->setText(libinfo);
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/chatwidget.cpp hedgewars-0.9.20.5/QTfrontend/ui/widget/chatwidget.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/chatwidget.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/chatwidget.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -176,7 +176,7 @@
QWidget(parent),
mainLayout(this)
{
- this->gameSettings = gameSettings;
+ this->gameSettings = NULL;
this->notify = notify;
m_isAdmin = false;
@@ -861,6 +861,8 @@
else
nick = m_clickedNick;
+ bool isOnline = (mil.size() > 0);
+
QSortFilterProxyModel * playersSortFilterModel = qobject_cast(chatNicks->model());
if(!playersSortFilterModel)
return;
@@ -871,8 +873,11 @@
return;
bool isSelf = (nick == m_userNick);
+ bool isInRoom = players->isFlagSet(nick, PlayersListModel::InRoom);
+
+ acFollow->setVisible(!isSelf && isInRoom);
- acFollow->setVisible(!isSelf);
+ acInfo->setVisible(isOnline);
// update context menu labels according to possible action
if(players->isFlagSet(nick, PlayersListModel::Ignore))
@@ -901,7 +906,7 @@
if (m_isAdmin)
{
- acKick->setVisible(!isSelf);
+ acKick->setVisible(!isSelf && isOnline);
acBan->setVisible(!isSelf);
}
@@ -930,3 +935,17 @@
chatText->verticalScrollBar()->setValue(m_scrollBarPos);
}
}
+
+void HWChatWidget::resizeEvent(QResizeEvent * event)
+{
+ Q_UNUSED(event);
+
+ afterContentAdd();
+}
+
+void HWChatWidget::showEvent(QShowEvent * event)
+{
+ Q_UNUSED(event);
+
+ afterContentAdd();
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/chatwidget.h hedgewars-0.9.20.5/QTfrontend/ui/widget/chatwidget.h
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/chatwidget.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/chatwidget.h 2013-10-31 20:21:57.000000000 +0000
@@ -68,6 +68,8 @@
protected:
virtual void dragEnterEvent(QDragEnterEvent * event);
virtual void dropEvent(QDropEvent * event);
+ virtual void resizeEvent(QResizeEvent * event);
+ virtual void showEvent(QShowEvent * event);
private:
static QString * s_styleSheet;
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/drawmapwidget.cpp hedgewars-0.9.20.5/QTfrontend/ui/widget/drawmapwidget.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/drawmapwidget.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/drawmapwidget.cpp 2013-10-31 20:21:57.000000000 +0000
@@ -62,8 +62,43 @@
{
Q_UNUSED(event);
+ int height = this->height();
+ int width = this->width();
+
+ if ((m_scene->height() > 0) && (m_scene->width() > 0) && (height > 0))
+ {
+ qreal saspect = m_scene->width() / m_scene->height();
+
+ qreal h = height;
+ qreal w = width;
+ qreal waspect = w / h;
+
+ if (waspect < saspect)
+ {
+ h = w / saspect;
+ }
+ else if (waspect > saspect)
+ {
+ w = saspect * h;
+ }
+
+ int fixedh = (int)h;
+ int fixedw = (int)w;
+
+ if (ui->graphicsView->width() != fixedw)
+ {
+ ui->graphicsView->setFixedWidth(fixedw);
+ }
+
+ if (ui->graphicsView->height() != fixedh)
+ {
+ ui->graphicsView->setFixedHeight(fixedh);
+ }
+
+ }
+
if(ui->graphicsView && ui->graphicsView->scene())
- ui->graphicsView->fitInView(ui->graphicsView->scene()->sceneRect(), Qt::KeepAspectRatio);
+ ui->graphicsView->fitInView(m_scene->sceneRect(), Qt::KeepAspectRatio);
}
void DrawMapWidget::showEvent(QShowEvent * event)
@@ -88,6 +123,11 @@
if(m_scene) m_scene->setErasing(erasing);
}
+void DrawMapWidget::setPathType(DrawMapScene::PathType pathType)
+{
+ if(m_scene) m_scene->setPathType(pathType);
+}
+
void DrawMapWidget::save(const QString & fileName)
{
if(m_scene)
@@ -125,6 +165,7 @@
}
else
m_scene->decode(qUncompress(QByteArray::fromBase64(f.readAll())));
+ //m_scene->decode(f.readAll());
}
}
@@ -156,7 +197,7 @@
QGraphicsView::setScene(scene);
}
-// Why don't I ever recieve this event?
+// Why don't I ever receive this event?
void DrawMapView::enterEvent(QEvent *event)
{
if(m_scene)
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/drawmapwidget.h hedgewars-0.9.20.5/QTfrontend/ui/widget/drawmapwidget.h
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/drawmapwidget.h 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/drawmapwidget.h 2013-10-31 20:21:57.000000000 +0000
@@ -25,7 +25,6 @@
#include
#include
-#include "qaspectratiolayout.h"
#include "drawmapscene.h"
@@ -61,12 +60,13 @@
QVBoxLayout * vbox = new QVBoxLayout(drawMapWidget);
vbox->setMargin(0);
lblPoints = new QLabel("0", drawMapWidget);
- vbox->addWidget(lblPoints);
- QAspectRatioLayout * arLayout = new QAspectRatioLayout();
- arLayout->setMargin(0);
+ QLayout * arLayout = new QVBoxLayout();
+ arLayout->setAlignment(Qt::AlignCenter);
vbox->addLayout(arLayout);
graphicsView = new DrawMapView(drawMapWidget);
+ graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
arLayout->addWidget(graphicsView);
retranslateUi(drawMapWidget);
@@ -100,6 +100,7 @@
void setErasing(bool erasing);
void save(const QString & fileName);
void load(const QString & fileName);
+ void setPathType(DrawMapScene::PathType pathType);
protected:
void changeEvent(QEvent *e);
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/feedbackdialog.cpp hedgewars-0.9.20.5/QTfrontend/ui/widget/feedbackdialog.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/feedbackdialog.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/feedbackdialog.cpp 2013-10-31 20:21:57.000000000 +0000
@@ -34,7 +34,7 @@
#include
-#ifdef Q_WS_WIN
+#ifdef Q_OS_WIN
#define WINVER 0x0500
#include
#else
@@ -42,7 +42,7 @@
#include
#endif
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
#include
#ifndef _SC_NPROCESSORS_ONLN
#define _SC_NPROCESSORS_ONLN 58
@@ -207,7 +207,7 @@
QString processor_name = "Processor: ";
// platform specific code
-#ifdef Q_WS_MACX
+#ifdef Q_OS_MACX
number_of_cores += QString::number(sysconf(_SC_NPROCESSORS_ONLN)) + "\n";
uint64_t memsize;
@@ -240,7 +240,7 @@
default: os_version += "\"Unknown version\"\n"; break;
}
#endif
-#ifdef Q_WS_WIN
+#ifdef Q_OS_WIN
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
number_of_cores += QString::number(sysinfo.dwNumberOfProcessors) + "\n";
@@ -257,27 +257,24 @@
case QSysInfo::WV_2003: os_version += "Windows Server 2003\n"; break;
case QSysInfo::WV_VISTA: os_version += "Windows Vista\n"; break;
case QSysInfo::WV_WINDOWS7: os_version += "Windows 7\n"; break;
- //case QSysInfo::WV_WINDOWS8: os_version += "Windows 8\n"; break; //QT 5+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ case QSysInfo::WV_WINDOWS8: os_version += "Windows 8\n"; break;
+#endif
default: os_version += "Windows (Unknown version)\n"; break;
}
kernel_line += "Windows kernel\n";
#endif
-#ifdef Q_WS_X11
+#ifdef Q_OS_LINUX
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/1024/1024) + " MB\n";
+ quint32 pages = sysconf(_SC_PHYS_PAGES);
+ quint32 page_size = sysconf(_SC_PAGE_SIZE);
+ quint32 total = pages * page_size / 1024 / 1024;
+ total_ram += QString::number(total) + " MB\n";
os_version += "GNU/Linux or BSD\n";
#endif
// uname -a
-#if defined(Q_WS_X11) || defined(Q_WS_MACX)
+#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
QProcess *process = new QProcess();
QStringList arguments = QStringList("-a");
process->start("uname", arguments);
@@ -286,7 +283,7 @@
delete process;
#endif
-#if (!defined(Q_WS_MACX) && defined(__i386__)) || defined(__x86_64__)
+#if (defined(Q_OS_WIN) && defined(__i386__)) || defined(__x86_64__)
// cpu info
quint32 registers[4];
quint32 i;
@@ -432,7 +429,7 @@
void FeedbackDialog::finishedSlot(QNetworkReply* reply)
{
- if (reply && reply->error() == QNetworkReply::NoError)
+ if (reply->error() == QNetworkReply::NoError)
{
QMessageBox infoMsg(this);
infoMsg.setIcon(QMessageBox::Information);
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/gamecfgwidget.cpp hedgewars-0.9.20.5/QTfrontend/ui/widget/gamecfgwidget.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/gamecfgwidget.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/gamecfgwidget.cpp 2014-01-08 16:25:17.000000000 +0000
@@ -321,6 +321,7 @@
bcfg << QString("e$healthdec %1").arg(schemeData(38).toInt()).toUtf8();
bcfg << QString("e$ropepct %1").arg(schemeData(39).toInt()).toUtf8();
bcfg << QString("e$getawaytime %1").arg(schemeData(40).toInt()).toUtf8();
+ bcfg << QString("e$worldedge %1").arg(schemeData(41).toInt()).toUtf8();
bcfg << QString("e$template_filter %1").arg(pMapContainer->getTemplateFilter()).toUtf8();
bcfg << QString("e$mapgen %1").arg(mapgen).toUtf8();
@@ -389,7 +390,10 @@
seedChanged(pMapContainer->getCurrentSeed());
templateFilterChanged(pMapContainer->getTemplateFilter());
- themeChanged(pMapContainer->getCurrentTheme());
+
+ QString t = pMapContainer->getCurrentTheme();
+ if(!t.isEmpty())
+ themeChanged(t);
schemeChanged(GameSchemes->currentIndex());
scriptChanged(Scripts->currentIndex());
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/hatbutton.cpp hedgewars-0.9.20.5/QTfrontend/ui/widget/hatbutton.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/hatbutton.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/hatbutton.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -19,7 +19,6 @@
#include
#include "hatprompt.h"
-#include "DataManager.h"
#include "HatModel.h"
#include "hatbutton.h"
@@ -28,8 +27,13 @@
setIconSize(QSize(32, 37));
setFixedSize(44, 44);
- m_hatModel = DataManager::instance().hatModel();
+ m_hatModel = 0;
connect(this, SIGNAL(clicked()), this, SLOT(showPrompt()));
+}
+
+void HatButton::setModel(HatModel *model)
+{
+ m_hatModel = model;
setCurrentIndex(0);
}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/hatbutton.h hedgewars-0.9.20.5/QTfrontend/ui/widget/hatbutton.h
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/hatbutton.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/hatbutton.h 2013-12-25 05:19:22.000000000 +0000
@@ -35,6 +35,7 @@
HatButton(QWidget* parent);
int currentIndex();
QString currentHat() const;
+ void setModel(HatModel * model);
private:
QModelIndex m_hat;
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/mapContainer.cpp hedgewars-0.9.20.5/QTfrontend/ui/widget/mapContainer.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/mapContainer.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/mapContainer.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -55,6 +55,11 @@
mapgen(MAPGEN_REGULAR),
m_previewSize(256, 128)
{
+ // don't show preview anything until first show event
+ m_previewEnabled = false;
+ m_missionsViewSetup = false;
+ m_staticViewSetup = false;
+
hhSmall.load(":/res/hh_small.png");
hhLimit = 18;
templateFilter = 0;
@@ -158,28 +163,14 @@
/* Static maps list */
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 */
- missionMapList = new QListView;
- missionMapList->setModel(m_missionMapModel);
- missionMapList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ missionMapList = new QListView(this);
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 */
@@ -261,7 +252,6 @@
staticMapChanged(m_staticMapModel->index(0, 0));
missionMapChanged(m_missionMapModel->index(0, 0));
changeMapType(MapModel::GeneratedMap);
- setRandomTheme();
}
void HWMapContainer::setImage(const QImage newImage)
@@ -347,15 +337,16 @@
void HWMapContainer::previewClicked()
{
- switch (m_mapInfo.type)
- {
- case MapModel::HandDrawnMap:
- emit drawMapRequested();
- break;
- default:
- setRandomMap();
- break;
- }
+ if (isMaster()) // should only perform these if master, but disabling the button when not, causes an unattractive preview.
+ switch (m_mapInfo.type)
+ {
+ case MapModel::HandDrawnMap:
+ emit drawMapRequested();
+ break;
+ default:
+ setRandomMap();
+ break;
+ }
}
QString HWMapContainer::getCurrentSeed() const
@@ -607,8 +598,22 @@
updatePreview();
}
+void HWMapContainer::showEvent(QShowEvent * event)
+{
+ if (!m_previewEnabled) {
+ m_previewEnabled = true;
+ setRandomTheme();
+ updatePreview();
+ }
+ QWidget::showEvent(event);
+}
+
void HWMapContainer::updatePreview()
{
+ // abort if the widget isn't supposed to show anything yet
+ if (!m_previewEnabled)
+ return;
+
if (pMap)
{
disconnect(pMap, 0, this, SLOT(setImage(const QImage)));
@@ -725,6 +730,7 @@
btnEditMap->show();
break;
case MapModel::MissionMap:
+ setupMissionMapsView();
mapgen = MAPGEN_MAP;
missionMapChanged(newMap.isValid() ? newMap : missionMapList->currentIndex());
lblMapList->setText(tr("Mission:"));
@@ -735,6 +741,7 @@
emit mapChanged(m_curMap);
break;
case MapModel::StaticMap:
+ setupStaticMapsView();
mapgen = MAPGEN_MAP;
staticMapChanged(newMap.isValid() ? newMap : staticMapList->currentIndex());
lblMapList->setText(tr("Map:"));
@@ -934,3 +941,35 @@
btnTheme->setIcon(QIcon());
btnTheme->setText(tr("Theme: %1").arg(name));
}
+
+void HWMapContainer::setupMissionMapsView()
+{
+ if(m_missionsViewSetup) return;
+ m_missionsViewSetup = true;
+
+ m_missionMapModel->loadMaps();
+ missionMapList->setModel(m_missionMapModel);
+ missionMapList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ QItemSelectionModel * missionSelectionModel = missionMapList->selectionModel();
+ connect(missionSelectionModel,
+ SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)),
+ this,
+ SLOT(missionMapChanged(const QModelIndex &, const QModelIndex &)));
+ missionSelectionModel->setCurrentIndex(m_missionMapModel->index(0, 0), QItemSelectionModel::Clear | QItemSelectionModel::SelectCurrent);
+}
+
+void HWMapContainer::setupStaticMapsView()
+{
+ if(m_staticViewSetup) return;
+ m_staticViewSetup = true;
+
+ m_staticMapModel->loadMaps();
+ staticMapList->setModel(m_staticMapModel);
+ staticMapList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ QItemSelectionModel * staticSelectionModel = staticMapList->selectionModel();
+ connect(staticSelectionModel,
+ SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)),
+ this,
+ SLOT(staticMapChanged(const QModelIndex &, const QModelIndex &)));
+ staticSelectionModel->setCurrentIndex(m_staticMapModel->index(0, 0), QItemSelectionModel::Clear | QItemSelectionModel::SelectCurrent);
+}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/mapContainer.h hedgewars-0.9.20.5/QTfrontend/ui/widget/mapContainer.h
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/mapContainer.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/mapContainer.h 2013-12-25 05:19:22.000000000 +0000
@@ -111,6 +111,7 @@
protected:
virtual void resizeEvent ( QResizeEvent * event );
+ virtual void showEvent ( QShowEvent * event );
private:
QVBoxLayout mainLayout;
@@ -149,6 +150,9 @@
QPushButton * btnSeed;
bool m_master;
QList m_childWidgets;
+ bool m_previewEnabled;
+ bool m_missionsViewSetup;
+ bool m_staticViewSetup;
void intSetSeed(const QString & seed);
void intSetMap(const QString & map);
@@ -161,6 +165,8 @@
void changeMapType(MapModel::MapType type, const QModelIndex & newMap = QModelIndex());
void updatePreview();
void updateThemeButtonSize();
+ void setupMissionMapsView();
+ void setupStaticMapsView();
MapModel::MapInfo m_mapInfo;
int m_themeID;
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/roomnameprompt.cpp hedgewars-0.9.20.5/QTfrontend/ui/widget/roomnameprompt.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/roomnameprompt.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/roomnameprompt.cpp 2013-10-31 20:21:49.000000000 +0000
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include "roomnameprompt.h"
@@ -32,24 +33,34 @@
setWindowFlags(Qt::Sheet);
setWindowModality(Qt::WindowModal);
setMinimumSize(360, 130);
- resize(360, 130);
+ resize(360, 180);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
// Layout
QVBoxLayout * dialogLayout = new QVBoxLayout(this);
// Label
- label = new QLabel(tr("Enter a name for your room."));
+ label = new QLabel(tr("Enter a name for your room."), this);
label->setWordWrap(true);
- dialogLayout->addWidget(label, 0);
+ dialogLayout->addWidget(label);
// 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);
+ leRoomName = new QLineEdit(this);
+ leRoomName->setText(roomName);
+ leRoomName->setMaxLength(59); // It didn't like 60 :(
+ leRoomName->setStyleSheet("QLineEdit { padding: 3px; }");
+ leRoomName->selectAll();
+ dialogLayout->addWidget(leRoomName);
+
+ cbSetPassword = new QCheckBox(this);
+ cbSetPassword->setText(tr("set password"));
+ dialogLayout->addWidget(cbSetPassword);
+
+ lePassword = new QLineEdit(this);
+ lePassword->setMaxLength(30);
+ lePassword->setStyleSheet("QLineEdit { padding: 3px; }");
+ lePassword->setEnabled(false);
+ dialogLayout->addWidget(lePassword);
dialogLayout->addStretch(1);
@@ -62,7 +73,7 @@
QPushButton * btnOkay = new QPushButton(tr("Create room"));
connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
connect(btnOkay, SIGNAL(clicked()), this, SLOT(accept()));
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
buttonLayout->addWidget(btnCancel);
buttonLayout->addWidget(btnOkay);
#else
@@ -73,10 +84,20 @@
setStyleSheet("QPushButton { padding: 5px; }");
- connect(btnOkay, SIGNAL(clicked()), this, SLOT(setRoomName()));
+ connect(cbSetPassword, SIGNAL(toggled(bool)), this, SLOT(checkBoxToggled()));
}
-void RoomNamePrompt::setRoomName()
+QString RoomNamePrompt::getRoomName()
{
- emit roomNameChosen(editBox->text());
+ return leRoomName->text();
+}
+
+QString RoomNamePrompt::getPassword()
+{
+ return lePassword->text();
+}
+
+void RoomNamePrompt::checkBoxToggled()
+{
+ lePassword->setEnabled(cbSetPassword->isChecked());
}
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/roomnameprompt.h hedgewars-0.9.20.5/QTfrontend/ui/widget/roomnameprompt.h
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/roomnameprompt.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/roomnameprompt.h 2013-10-31 20:21:49.000000000 +0000
@@ -23,6 +23,7 @@
class QLineEdit;
class QLabel;
+class QCheckBox;
class RoomNamePrompt : public QDialog
{
@@ -30,16 +31,17 @@
public:
RoomNamePrompt(QWidget* parent, const QString & roomName);
-
- signals:
- void roomNameChosen(const QString & roomName);
-
- private slots:
- void setRoomName();
+ QString getRoomName();
+ QString getPassword();
private:
- QLineEdit * editBox;
+ QLineEdit * leRoomName;
QLabel * label;
+ QCheckBox * cbSetPassword;
+ QLineEdit * lePassword;
+
+ private slots:
+ void checkBoxToggled();
};
#endif // ROOMNAMEPROMPT_H
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/seedprompt.cpp hedgewars-0.9.20.5/QTfrontend/ui/widget/seedprompt.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/seedprompt.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/seedprompt.cpp 2013-10-31 20:21:49.000000000 +0000
@@ -62,7 +62,7 @@
QPushButton * btnOkay = new QPushButton(tr("Set seed"));
connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
connect(btnOkay, SIGNAL(clicked()), this, SLOT(accept()));
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
buttonLayout->addWidget(btnCancel);
buttonLayout->addWidget(btnOkay);
#else
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui/widget/teamselhelper.cpp hedgewars-0.9.20.5/QTfrontend/ui/widget/teamselhelper.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui/widget/teamselhelper.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui/widget/teamselhelper.cpp 2013-10-31 20:21:49.000000000 +0000
@@ -55,7 +55,7 @@
butt = new QPushButton(difficultyIcon, team.name().replace("&","&&"), this);
butt->setFlat(true);
- butt->setWhatsThis(tr("%1's team").arg(team.owner()));
+ butt->setToolTip(team.owner());
mainLayout.addWidget(butt);
butt->setStyleSheet("QPushButton{"
"icon-size: 48px;"
diff -Nru hedgewars-0.9.19.3/QTfrontend/ui_hwform.cpp hedgewars-0.9.20.5/QTfrontend/ui_hwform.cpp
--- hedgewars-0.9.19.3/QTfrontend/ui_hwform.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/ui_hwform.cpp 2013-10-31 20:21:49.000000000 +0000
@@ -55,8 +55,8 @@
HWForm->resize(QSize(640, 480).expandedTo(HWForm->minimumSizeHint()));
HWForm->setMinimumSize(QSize(720, 450));
QString title = QMainWindow::tr("Hedgewars %1").arg(*cVersionString);
-#ifdef DEBUG
- title += QMainWindow::tr("-r%1 (%2)").arg(*cRevisionString, *cHashString);
+#ifdef QT_DEBUG
+ title += QString("-r%1 (%2)").arg(*cRevisionString, *cHashString);
#endif
HWForm->setWindowTitle(title);
centralWidget = new QWidget(HWForm);
diff -Nru hedgewars-0.9.19.3/QTfrontend/util/DataManager.cpp hedgewars-0.9.20.5/QTfrontend/util/DataManager.cpp
--- hedgewars-0.9.19.3/QTfrontend/util/DataManager.cpp 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/util/DataManager.cpp 2013-12-25 05:19:22.000000000 +0000
@@ -98,8 +98,7 @@
MapModel * DataManager::staticMapModel()
{
if (m_staticMapModel == NULL) {
- m_staticMapModel = new MapModel();
- m_staticMapModel->loadMaps(MapModel::StaticMap);
+ m_staticMapModel = new MapModel(MapModel::StaticMap, this);
}
return m_staticMapModel;
}
@@ -107,8 +106,7 @@
MapModel * DataManager::missionMapModel()
{
if (m_missionMapModel == NULL) {
- m_missionMapModel = new MapModel();
- m_missionMapModel->loadMaps(MapModel::MissionMap);
+ m_missionMapModel = new MapModel(MapModel::MissionMap, this);
}
return m_missionMapModel;
}
@@ -117,7 +115,6 @@
{
if (m_themeModel == NULL) {
m_themeModel = new ThemeModel();
- m_themeModel->loadThemes();
}
return m_themeModel;
}
@@ -199,6 +196,15 @@
return m_settingsFileName;
}
+QString DataManager::safeFileName(QString fileName)
+{
+ fileName.replace('\\', '_');
+ fileName.replace('/', '_');
+ fileName.replace(':', '_');
+
+ return fileName;
+}
+
void DataManager::reload()
{
// removed for now (also code was a bit unclean, could lead to segfault if
diff -Nru hedgewars-0.9.19.3/QTfrontend/util/DataManager.h hedgewars-0.9.20.5/QTfrontend/util/DataManager.h
--- hedgewars-0.9.19.3/QTfrontend/util/DataManager.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/util/DataManager.h 2013-10-31 20:21:49.000000000 +0000
@@ -119,6 +119,8 @@
QString settingsFileName();
+ static QString safeFileName(QString fileName);
+
static bool ensureFileExists(const QString & fileName);
public slots:
diff -Nru hedgewars-0.9.19.3/QTfrontend/util/FileEngine.cpp hedgewars-0.9.20.5/QTfrontend/util/FileEngine.cpp
--- hedgewars-0.9.19.3/QTfrontend/util/FileEngine.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/util/FileEngine.cpp 2013-10-31 20:21:49.000000000 +0000
@@ -54,7 +54,7 @@
}
if (!m_handle) {
- qWarning("[PHYSFS] Failed to open %s, reason: %s", m_fileName.toUtf8().constData(), PHYSFS_getLastError());
+ qWarning("%s", QString("[PHYSFS] Failed to open %1, reason: %2").arg(m_fileName).arg(FileEngineHandler::errorStr()).toLocal8Bit().constData());
return false;
}
@@ -310,6 +310,8 @@
FileEngineHandler::FileEngineHandler(char *argv0)
{
PHYSFS_init(argv0);
+
+ qDebug("%s", QString("[PHYSFS] Init: %1").arg(errorStr()).toLocal8Bit().constData());
}
FileEngineHandler::~FileEngineHandler()
@@ -328,16 +330,19 @@
void FileEngineHandler::mount(const QString &path)
{
PHYSFS_mount(path.toUtf8().constData(), NULL, 0);
+ qDebug("%s", QString("[PHYSFS] Mounting '%1' to '/': %2").arg(path).arg(errorStr()).toLocal8Bit().constData());
}
void FileEngineHandler::mount(const QString & path, const QString & mountPoint)
{
PHYSFS_mount(path.toUtf8().constData(), mountPoint.toUtf8().constData(), 0);
+ qDebug("%s", QString("[PHYSFS] Mounting '%1' to '%2': %3").arg(path).arg(mountPoint).arg(errorStr()).toLocal8Bit().data());
}
void FileEngineHandler::setWriteDir(const QString &path)
{
PHYSFS_setWriteDir(path.toUtf8().constData());
+ qDebug("%s", QString("[PHYSFS] Setting write dir to '%1': %2").arg(path).arg(errorStr()).toLocal8Bit().data());
}
void FileEngineHandler::mountPacks()
@@ -345,6 +350,12 @@
hedgewarsMountPackages();
}
+QString FileEngineHandler::errorStr()
+{
+ QString s = QString::fromUtf8(PHYSFS_getLastError());
+ return s.isEmpty() ? "ok" : s;
+}
+
FileEngineIterator::FileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, const QStringList &entries)
: QAbstractFileEngineIterator(filters, nameFilters)
diff -Nru hedgewars-0.9.19.3/QTfrontend/util/FileEngine.h hedgewars-0.9.20.5/QTfrontend/util/FileEngine.h
--- hedgewars-0.9.19.3/QTfrontend/util/FileEngine.h 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/util/FileEngine.h 2013-10-31 20:21:49.000000000 +0000
@@ -71,6 +71,7 @@
static void mount(const QString & path, const QString & mountPoint);
static void setWriteDir(const QString & path);
static void mountPacks();
+ static QString errorStr();
// private:
static const QString scheme;
diff -Nru hedgewars-0.9.19.3/QTfrontend/util/LibavInteraction.cpp hedgewars-0.9.20.5/QTfrontend/util/LibavInteraction.cpp
--- hedgewars-0.9.19.3/QTfrontend/util/LibavInteraction.cpp 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/util/LibavInteraction.cpp 2013-10-31 20:21:49.000000000 +0000
@@ -30,6 +30,10 @@
#include "HWApplication.h"
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 25, 0)
+#define CodecID AVCodecID
+#endif
+
struct Codec
{
CodecID id;
@@ -278,7 +282,7 @@
return "";
int s = float(pContext->duration)/AV_TIME_BASE;
- QString desc = QString(tr("Duration: %1m %2s\n")).arg(s/60).arg(s%60);
+ QString desc = tr("Duration: %1m %2s").arg(s/60).arg(s%60) + "\n";
for (int i = 0; i < (int)pContext->nb_streams; i++)
{
AVStream* pStream = pContext->streams[i];
@@ -290,11 +294,11 @@
if (pCodec->codec_type == AVMEDIA_TYPE_VIDEO)
{
- desc += QString(tr("Video: %1x%2, ")).arg(pCodec->width).arg(pCodec->height);
+ desc += QString(tr("Video: %1x%2")).arg(pCodec->width).arg(pCodec->height) + ", ";
if (pStream->avg_frame_rate.den)
{
float fps = float(pStream->avg_frame_rate.num)/pStream->avg_frame_rate.den;
- desc += QString(tr("%1 fps, ")).arg(fps, 0, 'f', 2);
+ desc += QString(tr("%1 fps")).arg(fps, 0, 'f', 2) + ", ";
}
}
else if (pCodec->codec_type == AVMEDIA_TYPE_AUDIO)
diff -Nru hedgewars-0.9.19.3/QTfrontend/util/LibavInteraction.h hedgewars-0.9.20.5/QTfrontend/util/LibavInteraction.h
--- hedgewars-0.9.19.3/QTfrontend/util/LibavInteraction.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/util/LibavInteraction.h 2013-10-31 20:21:49.000000000 +0000
@@ -16,8 +16,8 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef LIBAV_ITERACTION
-#define LIBAV_ITERACTION
+#ifndef LIBAV_INTERACTION
+#define LIBAV_INTERACTION
#include
@@ -48,4 +48,4 @@
QString getFileInfo(const QString & filepath);
};
-#endif // LIBAV_ITERACTION
+#endif // LIBAV_INTERACTION
diff -Nru hedgewars-0.9.19.3/QTfrontend/weapons.h hedgewars-0.9.20.5/QTfrontend/weapons.h
--- hedgewars-0.9.19.3/QTfrontend/weapons.h 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/QTfrontend/weapons.h 2013-12-25 05:19:22.000000000 +0000
@@ -21,45 +21,46 @@
//skip---------------------------------|
//structure------------------------------------------------------------------|
-#define AMMOLINE_DEFAULT_QT "9391929422199121032235111001201000000211110101011111121"
-#define AMMOLINE_DEFAULT_PROB "0405040541600655546554464776576666666155510101115411121"
-#define AMMOLINE_DEFAULT_DELAY "0000000000000205500000040007004000000000220000000600020"
-#define AMMOLINE_DEFAULT_CRATE "1311110312111111123114111111111111111211111101111111121"
-
-#define AMMOLINE_CRAZY_QT "9999999999999999992999999999999999299999999909999992999"
-#define AMMOLINE_CRAZY_PROB "1111110111111111111111111111111111111111111101111111111"
-#define AMMOLINE_CRAZY_DELAY "0000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CRAZY_CRATE "1311110312111111123114111111111111111211110101111111121"
-
-#define AMMOLINE_PROMODE_QT "9090009000000000000009000000000000000000000000000000000"
-#define AMMOLINE_PROMODE_PROB "0000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_PROMODE_DELAY "0000000000000205500000040007004000000000200000000000020"
-#define AMMOLINE_PROMODE_CRATE "1111110111111111111111111111111111111111100101111111121"
-
-#define AMMOLINE_SHOPPA_QT "0000009900000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_PROB "4444410044244402210112121222422000000002000400010011001"
-#define AMMOLINE_SHOPPA_DELAY "0000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_CRATE "1111110111111111111111111111111111111111101101111111121"
-
-#define AMMOLINE_CLEAN_QT "1010009000010000011000000000000000000000000000001000000"
-#define AMMOLINE_CLEAN_PROB "0405040541600655546554464776576666666155510101115411121"
-#define AMMOLINE_CLEAN_DELAY "0000000000000000000000000000000000000000000000000000020"
-#define AMMOLINE_CLEAN_CRATE "1311110312111111123114111111111111111211111101111111121"
-
-#define AMMOLINE_MINES_QT "0000009900090000000300000000000000000000000000000000000"
-#define AMMOLINE_MINES_PROB "0000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_MINES_DELAY "0000000000000205500000040007004000000000200000000600020"
-#define AMMOLINE_MINES_CRATE "1111110111111111111111111111111111111111111101111111121"
-
-#define AMMOLINE_PORTALS_QT "9000009002000000002100000000000000110000090000000000000"
-#define AMMOLINE_PORTALS_PROB "0405040541600655546554464776576666666155510101115411121"
-#define AMMOLINE_PORTALS_DELAY "0000000000000205500000040007004000000000200000000600020"
-#define AMMOLINE_PORTALS_CRATE "1311110312111111123114111111111111111211111101111111121"
-
-#define AMMOLINE_ONEEVERY_QT "1111119111111111111111111111111111111111111111111111111"
-#define AMMOLINE_ONEEVERY_PROB "1111110111111111111111111111111111111111111111111111111"
-#define AMMOLINE_ONEEVERY_DELAY "0000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_ONEEVERY_CRATE "1111110111111111111111111111111111111111111111111111111"
+
+#define AMMOLINE_DEFAULT_QT "93919294221991210322351110012000000002111001010111110001"
+#define AMMOLINE_DEFAULT_PROB "04050405416006555465544647765766666661555101011154111111"
+#define AMMOLINE_DEFAULT_DELAY "00000000000002055000000400070040000000002200000006000200"
+#define AMMOLINE_DEFAULT_CRATE "13111103121111111231141111111111111112111111011111111111"
+
+#define AMMOLINE_CRAZY_QT "99999999999999999929999999999999992999999999099999929991"
+#define AMMOLINE_CRAZY_PROB "11111101111111111111111111111111111111111111011111111111"
+#define AMMOLINE_CRAZY_DELAY "00000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_CRAZY_CRATE "13111103121111111231141111111111111112111101011111111111"
+
+#define AMMOLINE_PROMODE_QT "90900090000000000000090000000000000000000000000000000000"
+#define AMMOLINE_PROMODE_PROB "00000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_PROMODE_DELAY "00000000000002055000000400070040000000002000000000000200"
+#define AMMOLINE_PROMODE_CRATE "11111101111111111111111111111111111111111001011111111111"
+
+#define AMMOLINE_SHOPPA_QT "00000099000000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPA_PROB "44444100442444022101121212224220000000020004000100110010"
+#define AMMOLINE_SHOPPA_DELAY "00000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPA_CRATE "11111101111111111111111111111111111111111011011111111110"
+
+#define AMMOLINE_CLEAN_QT "10100090000100000110000000000000000000000000000010000000"
+#define AMMOLINE_CLEAN_PROB "04050405416006555465544647765766666661555101011154111211"
+#define AMMOLINE_CLEAN_DELAY "00000000000000000000000000000000000000000000000000000200"
+#define AMMOLINE_CLEAN_CRATE "13111103121111111231141111111111111112111111011111111111"
+
+#define AMMOLINE_MINES_QT "00000099000900000003000000000000000000000000000000000000"
+#define AMMOLINE_MINES_PROB "00000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_MINES_DELAY "00000000000002055000000400070040000000002000000006000200"
+#define AMMOLINE_MINES_CRATE "11111101111111111111111111111111111111111111011111111111"
+
+#define AMMOLINE_PORTALS_QT "90000090020000000021000000000000001100000900000000000000"
+#define AMMOLINE_PORTALS_PROB "04050405416006555465544647765766666661555101011154111211"
+#define AMMOLINE_PORTALS_DELAY "00000000000002055000000400070040000000002000000006000200"
+#define AMMOLINE_PORTALS_CRATE "13111103121111111231141111111111111112111111011111111111"
+
+#define AMMOLINE_ONEEVERY_QT "11111191111111111111111111111111111111111111111111111111"
+#define AMMOLINE_ONEEVERY_PROB "11111101111111111111111111111111111111111111111111111111"
+#define AMMOLINE_ONEEVERY_DELAY "00000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_ONEEVERY_CRATE "11111101111111111111111111111111111111111111111111111111"
//When adding new weapons also insert one element in cDefaultAmmos list (hwconsts.cpp.in)
diff -Nru hedgewars-0.9.19.3/README hedgewars-0.9.20.5/README
--- hedgewars-0.9.19.3/README 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/README 2013-10-31 20:21:50.000000000 +0000
@@ -1,17 +1,46 @@
Hedgewars - a turn based strategy game.
-Distributed under the terms of the GNU GPL licence.
-Images and sounds are distributed under the terms of the GNU FDL licence.
+=======================================
-Source:
-Copyright 2004-2013 Andrey Korotaev
-Portions copyright 2006-2008 Igor Ulyanov aka Displacer
+Copyright 2004-2013 Andrey Korotaev and others.
+See QTfrontend/res/html/about.html and CREDITS for a complete list of authors.
+
+Licence:
+--------
+Source code is distributed under the terms of the GNU General Public Licence
+version 2; images and sounds are distributed under the terms of the GNU Free
+Documentation Licence version 1.2. See the COPYING file for the full text of
+the licenses.
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
+-------------
+See our wiki at: https://code.google.com/p/hedgewars/wiki/BuildingHedgewars
+
+You can find an outline of the necessary dependencies in the INSTALL file.
+
+Source code:
+------------
+Our main repository is located at http://hedgewars.googlecode.com using
+Mercurial as DVCS. A Git repository is also available (mirrored daily)
+at https://github.com/hedgewars/hw
+
+Contribute:
+-----------
+If you see a bug or have any suggestion please use the official bug tracker at
+http://code.google.com/p/hedgewars/issues/list or the integrated feedback
+button.
+
+If you want to help or get to know the sources better you can do that with some
+easy tasks from http://code.google.com/p/hedgewars/wiki/TODO. We also have an
+extended API in LUA to customize your adventures in our wiki at
+http://code.google.com/p/hedgewars/wiki/LuaAPI.
+
+If you know your way through the code feel free to send a patch or open a pull
+request. The best LUA scripts get released in the official DLC page and later
+integrated in the next version.
-Dependencies:
-you can find an outline of the necessary dependencies in the INSTALL file.
+Contact:
+--------
+* IRC channel - irc://irc.freenode.net/hedgewars
+* community forum - http://www.hedgewars.org/forum
+* mailing list - https://mail.gna.org/listinfo/hedgewars-dev
diff -Nru hedgewars-0.9.19.3/cmake_modules/CMakeDeterminePascalCompiler.cmake hedgewars-0.9.20.5/cmake_modules/CMakeDeterminePascalCompiler.cmake
--- hedgewars-0.9.19.3/cmake_modules/CMakeDeterminePascalCompiler.cmake 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/CMakeDeterminePascalCompiler.cmake 2013-10-31 20:21:50.000000000 +0000
@@ -0,0 +1,69 @@
+# Determine the compiler to use for Pascal programs
+# NOTE, a generator may set CMAKE_Pascal_COMPILER before
+# loading this file to force a compiler.
+# use environment variable Pascal first if defined by user, next use
+# the cmake variable CMAKE_GENERATOR_PASCAL which can be defined by a generator
+# as a default compiler
+
+# NOTE: on Darwin cmake >= 2.8.11 until cmake <= 2.8.12.1 will add an incompatible
+# -F flag to so you won't be able to use those versions with this script
+
+if(NOT CMAKE_Pascal_COMPILER)
+ # prefer the environment variable FPC
+ if($ENV{FPC} MATCHES ".+")
+ get_filename_component(CMAKE_Pascal_COMPILER_INIT $ENV{FPC} PROGRAM PROGRAM_ARGS CMAKE_Pascal_FLAGS_ENV_INIT)
+ if(CMAKE_Pascal_FLAGS_ENV_INIT)
+ set(CMAKE_Pascal_COMPILER_ARG1 "${CMAKE_Pascal_FLAGS_ENV_INIT}" CACHE STRING "First argument to Pascal compiler")
+ endif(CMAKE_Pascal_FLAGS_ENV_INIT)
+ if(EXISTS ${CMAKE_Pascal_COMPILER_INIT})
+ else(EXISTS ${CMAKE_Pascal_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable FPC:\n$ENV{FPC}.")
+ endif(EXISTS ${CMAKE_Pascal_COMPILER_INIT})
+ endif($ENV{FPC} MATCHES ".+")
+
+ # next try prefer the compiler specified by the generator
+ if(CMAKE_GENERATOR_PASCAL)
+ if(NOT CMAKE_Pascal_COMPILER_INIT)
+ set(CMAKE_Pascal_COMPILER_INIT ${CMAKE_GENERATOR_PASCAL})
+ endif(NOT CMAKE_Pascal_COMPILER_INIT)
+ endif(CMAKE_GENERATOR_PASCAL)
+
+ # finally list compilers to try
+ if(CMAKE_Pascal_COMPILER_INIT)
+ set(CMAKE_Pascal_COMPILER_LIST ${CMAKE_Pascal_COMPILER_INIT})
+ else(CMAKE_Pascal_COMPILER_INIT)
+ set(CMAKE_Pascal_COMPILER_LIST fpc)
+ endif(CMAKE_Pascal_COMPILER_INIT)
+
+ # Find the compiler.
+ find_program(CMAKE_Pascal_COMPILER NAMES ${CMAKE_Pascal_COMPILER_LIST} DOC "Pascal compiler")
+ if(CMAKE_Pascal_COMPILER_INIT AND NOT CMAKE_Pascal_COMPILER)
+ set(CMAKE_Pascal_COMPILER "${CMAKE_Pascal_COMPILER_INIT}" CACHE FILEPATH "Pascal compiler" FORCE)
+ endif(CMAKE_Pascal_COMPILER_INIT AND NOT CMAKE_Pascal_COMPILER)
+endif(NOT CMAKE_Pascal_COMPILER)
+mark_as_advanced(CMAKE_Pascal_COMPILER)
+
+if(NOT CMAKE_Pascal_COMPILER_VERSION)
+ execute_process(COMMAND ${CMAKE_Pascal_COMPILER} -iV
+ OUTPUT_VARIABLE CMAKE_Pascal_COMPILER_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ) # we assume no error for something so simple
+ set(CMAKE_Pascal_COMPILER_ARG1 "-l- -v0ewn")
+endif(NOT CMAKE_Pascal_COMPILER_VERSION)
+mark_as_advanced(CMAKE_Pascal_COMPILER_VERSION)
+
+get_filename_component(COMPILER_LOCATION "${CMAKE_Pascal_COMPILER}" PATH)
+
+# configure variables set in this file for fast reload later on
+if(${CMAKE_VERSION} VERSION_LESS 2.8.10)
+ configure_file(${CMAKE_MODULE_PATH}/CMakePascalCompiler.cmake.in
+ "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakePascalCompiler.cmake"
+ IMMEDIATE )
+else(${CMAKE_VERSION} VERSION_LESS 2.8.10)
+ configure_file(${CMAKE_MODULE_PATH}/CMakePascalCompiler.cmake.in
+ "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${CMAKE_VERSION}/CMakePascalCompiler.cmake"
+ IMMEDIATE )
+endif(${CMAKE_VERSION} VERSION_LESS 2.8.10)
+
+set(CMAKE_Pascal_COMPILER_ENV_VAR "FPC")
+
diff -Nru hedgewars-0.9.19.3/cmake_modules/CMakePascalCompiler.cmake.in hedgewars-0.9.20.5/cmake_modules/CMakePascalCompiler.cmake.in
--- hedgewars-0.9.19.3/cmake_modules/CMakePascalCompiler.cmake.in 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/CMakePascalCompiler.cmake.in 2013-10-31 20:21:50.000000000 +0000
@@ -0,0 +1,12 @@
+set(CMAKE_Pascal_COMPILER "@CMAKE_Pascal_COMPILER@")
+set(CMAKE_Pascal_COMPILER_ARG1 "@CMAKE_Pascal_COMPILER_ARG1@")
+set(CMAKE_Pascal_COMPILER_LOADED 1)
+set(CMAKE_Pascal_COMPILER_VERSION "@CMAKE_Pascal_COMPILER_VERSION@")
+
+set(CMAKE_Pascal_COMPILER_ENV_VAR "FPC")
+
+set(CMAKE_Pascal_SOURCE_FILE_EXTENSIONS "pas" "pp")
+set(CMAKE_Pascal_IGNORE_EXTENSIONS ppu;PPU;h;H;o;O;obj;OBJ;def;DEF;rc;RC)
+set(CMAKE_Pascal_LINKER_PREFERENCE Prefered)
+set(CMAKE_Pascal_OUTPUT_EXTENSION_REPLACE 1)
+set(CMAKE_Pascal_OUTPUT_EXTENSION ".o")
diff -Nru hedgewars-0.9.19.3/cmake_modules/CMakePascalInformation.cmake hedgewars-0.9.20.5/cmake_modules/CMakePascalInformation.cmake
--- hedgewars-0.9.19.3/cmake_modules/CMakePascalInformation.cmake 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/CMakePascalInformation.cmake 2014-01-08 16:25:17.000000000 +0000
@@ -0,0 +1,228 @@
+# This file sets the basic flags for the Pascal language in CMake.
+# It also loads the available platform file for the system-compiler
+# if it exists.
+
+# in case fpc ever becomes included in cmake
+get_filename_component(CMAKE_BASE_NAME ${CMAKE_Pascal_COMPILER} NAME_WE)
+set(CMAKE_SYSTEM_AND_Pascal_COMPILER_INFO_FILE
+ ${CMAKE_ROOT}/Modules/Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME}.cmake)
+include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME} OPTIONAL)
+
+# This section should actually be in Platform/${CMAKE_SYSTME_NAME}-fpc.cmake
+set(CMAKE_Pascal_FLAGS_DEBUG_INIT "-O- -g -gl -gp -gh")
+set(CMAKE_Pascal_FLAGS_MINSIZEREL_INIT "-Os -dNDEBUG")
+set(CMAKE_Pascal_FLAGS_RELEASE_INIT "-O2 -dNDEBUG")
+set(CMAKE_Pascal_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -gl -gp")
+
+# This should be included before the _INIT variables are
+# used to initialize the cache. Since the rule variables
+# have if blocks on them, users can still define them here.
+# But, it should still be after the platform file so changes can
+# be made to those values.
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE)
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE})
+endif(CMAKE_USER_MAKE_RULES_OVERRIDE)
+
+if(CMAKE_USER_MAKE_RULES_OVERRIDE_Pascal)
+ include(${CMAKE_USER_MAKE_RULES_OVERRIDE_Pascal})
+endif(CMAKE_USER_MAKE_RULES_OVERRIDE_Pascal)
+
+# Create a set of shared library variable specific to Pascal
+# For 90% of the systems, these are the same flags as the C versions
+# so if these are not set just copy the flags from the c version
+
+# No flags supported during linking as a shell script takes care of it
+# however to avoid interferences we escape -Wl flags to the Pascal -k
+#if(NOT CMAKE_SHARED_LIBRARY_CREATE_Pascal_FLAGS)
+#-shared (linux) / -dynamiclib -Wl,-headerpad_max_install_names (darwin)
+# string(REGEX REPLACE "-Wl," "-k" CMAKE_SHARED_LIBRARY_CREATE_Pascal_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
+#endif(NOT CMAKE_SHARED_LIBRARY_CREATE_Pascal_FLAGS)
+
+if(NOT CMAKE_SHARED_LIBRARY_Pascal_FLAGS AND CMAKE_SHARED_LIBRARY_C_FLAGS)
+#-fPIC
+ string(REGEX REPLACE "-Wl," "-k" CMAKE_SHARED_LIBRARY_Pascal_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_LINK_Pascal_FLAGS AND CMAKE_SHARED_LIBRARY_LINK_C_FLAGS)
+#-rdynamic (linux) / (empty on darwin)
+ string(REGEX REPLACE "-Wl," "-k" CMAKE_SHARED_LIBRARY_LINK_Pascal_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS})
+endif()
+
+if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_Pascal_FLAG)
+#-Wl,-rpath,
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_Pascal_FLAG "-k-rpath")
+endif(NOT CMAKE_SHARED_LIBRARY_RUNTIME_Pascal_FLAG)
+
+if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_Pascal_FLAG_SEP)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_Pascal_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
+endif(NOT CMAKE_SHARED_LIBRARY_RUNTIME_Pascal_FLAG_SEP)
+
+if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_Pascal_FLAG)
+#-Wl,-rpath-link,
+ set(CMAKE_SHARED_LIBRARY_RPATH_LINK_Pascal_FLAG "-k-rpath-link")
+endif(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_Pascal_FLAG)
+
+# for most systems a module is the same as a shared library
+# so unless the variable CMAKE_MODULE_EXISTS is set just
+# copy the values from the LIBRARY variables
+if(NOT CMAKE_MODULE_EXISTS)
+ set(CMAKE_SHARED_MODULE_Pascal_FLAGS ${CMAKE_SHARED_LIBRARY_Pascal_FLAGS})
+ set(CMAKE_SHARED_MODULE_CREATE_Pascal_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_Pascal_FLAGS})
+endif(NOT CMAKE_MODULE_EXISTS)
+
+# repeat for modules
+if(NOT CMAKE_SHARED_MODULE_CREATE_Pascal_FLAGS AND CMAKE_SHARED_MODULE_CREATE_C_FLAGS)
+# ? (linux) / -bundle -Wl,-headerpad_max_install_names (darwin)
+ string(REGEX REPLACE "-Wl," "-k" CMAKE_SHARED_MODULE_CREATE_Pascal_FLAGS ${CMAKE_SHARED_MODULE_CREATE_C_FLAGS})
+endif()
+
+if(NOT CMAKE_SHARED_MODULE_Pascal_FLAGS AND CMAKE_SHARED_MODULE_C_FLAGS)
+ string(REGEX REPLACE "-Wl," "-k" CMAKE_SHARED_MODULE_Pascal_FLAGS ${CMAKE_SHARED_MODULE_C_FLAGS})
+endif()
+
+if(NOT CMAKE_SHARED_MODULE_RUNTIME_Pascal_FLAG)
+ set(CMAKE_SHARED_MODULE_RUNTIME_Pascal_FLAG ${CMAKE_SHARED_MODULE_RUNTIME_C_FLAG})
+endif(NOT CMAKE_SHARED_MODULE_RUNTIME_Pascal_FLAG)
+
+if(NOT CMAKE_SHARED_MODULE_RUNTIME_Pascal_FLAG_SEP)
+ set(CMAKE_SHARED_MODULE_RUNTIME_Pascal_FLAG_SEP ${CMAKE_SHARED_MODULE_RUNTIME_C_FLAG_SEP})
+endif(NOT CMAKE_SHARED_MODULE_RUNTIME_Pascal_FLAG_SEP)
+
+# now other system things
+if(NOT CMAKE_INCLUDE_FLAG_Pascal)
+ #amazing, fpc: -I Add to include path
+ set(CMAKE_INCLUDE_FLAG_Pascal ${CMAKE_INCLUDE_FLAG_C})
+endif(NOT CMAKE_INCLUDE_FLAG_Pascal)
+
+if(NOT CMAKE_INCLUDE_FLAG_SEP_Pascal)
+ set(CMAKE_INCLUDE_FLAG_SEP_Pascal ${CMAKE_INCLUDE_FLAG_SEP_C})
+endif(NOT CMAKE_INCLUDE_FLAG_SEP_Pascal)
+
+if(NOT CMAKE_Pascal_FRAMEWORK_SEARCH_FLAG)
+ #however -F won't work, -Ff is Pascal equivalent
+ set(CMAKE_Pascal_FRAMEWORK_SEARCH_FLAG "-Ff")
+endif(NOT CMAKE_Pascal_FRAMEWORK_SEARCH_FLAG)
+
+# Copy C version of this flag which is normally determined in platform file.
+if(NOT CMAKE_SHARED_LIBRARY_SONAME_Pascal_FLAG)
+#-soname (linux) / -install-name (dawin)
+ set(CMAKE_SHARED_LIBRARY_SONAME_Pascal_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_C_FLAG})
+endif(NOT CMAKE_SHARED_LIBRARY_SONAME_Pascal_FLAG)
+
+set(CMAKE_VERBOSE_MAKEFILE FALSE CACHE BOOL "If this value is on, makefiles will be generated without the .SILENT directive, and all commands will be echoed to the console during the make. This is useful for debugging only. With Visual Studio IDE projects all commands are done without /nologo.")
+
+#set(CMAKE_Pascal_FLAGS "$ENV{FPFLAGS} ${CMAKE_Pascal_FLAGS_INIT} ${CMAKE_Pascal_FLAGS}" CACHE STRING "Flags for Pascal compiler." FORCE)
+
+include(CMakeCommonLanguageInclude)
+
+# now define the following rule variables
+
+# CMAKE_Pascal_CREATE_SHARED_LIBRARY
+# CMAKE_Pascal_CREATE_SHARED_MODULE
+# CMAKE_Pascal_CREATE_STATIC_LIBRARY
+# CMAKE_Pascal_COMPILE_OBJECT
+# CMAKE_Pascal_LINK_EXECUTABLE
+
+# variables supplied by the generator at use time
+#
+# the target without the suffix
+#
+#
+#
+#
+#
+
+# Pascal compiler information
+#
+#
+#
+#
+
+# Static library tools
+# NONE!
+
+if(NOT EXECUTABLE_OUTPUT_PATH)
+ set (EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR})
+endif(NOT EXECUTABLE_OUTPUT_PATH)
+
+# create a Pascal shared library
+if(NOT CMAKE_Pascal_CREATE_SHARED_LIBRARY)
+ if(WIN32)
+ set(CMAKE_Pascal_CREATE_SHARED_LIBRARY "${EXECUTABLE_OUTPUT_PATH}/ppas.bat")
+ else(WIN32)
+ set(CMAKE_Pascal_CREATE_SHARED_LIBRARY "${EXECUTABLE_OUTPUT_PATH}/ppas.sh")
+ endif(WIN32)
+# other expandable variables here are
+endif(NOT CMAKE_Pascal_CREATE_SHARED_LIBRARY)
+
+# create an Pascal shared module just copy the shared library rule
+if(NOT CMAKE_Pascal_CREATE_SHARED_MODULE)
+ set(CMAKE_Pascal_CREATE_SHARED_MODULE ${CMAKE_Pascal_CREATE_SHARED_LIBRARY})
+endif(NOT CMAKE_Pascal_CREATE_SHARED_MODULE)
+
+# create an Pascal static library (unsupported)
+if(NOT CMAKE_Pascal_CREATE_STATIC_LIBRARY)
+ set(CMAKE_Pascal_CREATE_STATIC_LIBRARY
+ "echo STATIC LIBRARIES ARE NOT SUPPORTED" "exit")
+endif(NOT CMAKE_Pascal_CREATE_STATIC_LIBRARY)
+
+# compile a Pascal file into an object file
+if(NOT CMAKE_Pascal_COMPILE_OBJECT)
+ if(UNIX)
+ #when you have multiple ld installation make sure you get the one bundled with the system C compiler
+ include(Platform/${CMAKE_SYSTEM_NAME}-GNU-C.cmake OPTIONAL)
+ if(CMAKE_COMPILER_IS_GNUCC)
+ get_filename_component(CMAKE_C_COMPILER_DIR ${CMAKE_C_COMPILER} PATH)
+ set(CMAKE_Pascal_UNIX_FLAGS "-FD${CMAKE_C_COMPILER_DIR}")
+ endif(CMAKE_COMPILER_IS_GNUCC)
+ if(APPLE)
+ #TODO: take care of CMAKE_INSTALL_NAME_DIR for shared targets
+ else(APPLE)
+ if(CMAKE_INSTALL_RPATH)
+ #need to escape twice because we use a script to link
+ #\\\\ is just \\ which escapes '\' in the final script
+ #same for $$ which escapes '$' in cmake
+ string(REGEX REPLACE "\\$" "\\\\$$" CMAKE_INSTALL_RPATH_ESCAPED ${CMAKE_INSTALL_RPATH})
+ #normally this flag is found in but that's not active here
+ set(CMAKE_Pascal_UNIX_FLAGS "${CMAKE_SHARED_LIBRARY_RUNTIME_Pascal_FLAG} -k'${CMAKE_INSTALL_RPATH_ESCAPED}' ${CMAKE_Pascal_UNIX_FLAGS}")
+ endif()
+ endif(APPLE)
+ endif(UNIX)
+
+ #-Cn is mandatory as it's what creates the ppas.* script
+ set(CMAKE_Pascal_COMPILE_OBJECT
+ " -Cn -FE${EXECUTABLE_OUTPUT_PATH} -FU${CMAKE_CURRENT_BINARY_DIR}/ ${CMAKE_Pascal_UNIX_FLAGS} ")
+endif(NOT CMAKE_Pascal_COMPILE_OBJECT)
+
+# link Pascal objects in a single executable
+if(NOT CMAKE_Pascal_LINK_EXECUTABLE)
+ if(WIN32)
+ set(CMAKE_Pascal_LINK_EXECUTABLE "${EXECUTABLE_OUTPUT_PATH}/ppas.bat")
+ else(WIN32)
+ set(CMAKE_Pascal_LINK_EXECUTABLE "${EXECUTABLE_OUTPUT_PATH}/ppas.sh")
+ endif(WIN32)
+# other expandable variables here are
+endif(NOT CMAKE_Pascal_LINK_EXECUTABLE)
+
+if(CMAKE_Pascal_STANDARD_LIBRARIES_INIT)
+ set(CMAKE_Pascal_STANDARD_LIBRARIES "${CMAKE_Pascal_STANDARD_LIBRARIES_INIT}"
+ CACHE STRING "Libraries linked by default (usually handled internally).")
+ mark_as_advanced(CMAKE_Pascal_STANDARD_LIBRARIES)
+endif(CMAKE_Pascal_STANDARD_LIBRARIES_INIT)
+
+if(NOT CMAKE_NOT_USING_CONFIG_FLAGS)
+ set(CMAKE_Pascal_FLAGS_DEBUG "${CMAKE_Pascal_FLAGS_DEBUG_INIT}" CACHE STRING
+ "Flags used by the compiler during debug builds.")
+ set(CMAKE_Pascal_FLAGS_MINSIZEREL "${CMAKE_Pascal_FLAGS_MINSIZEREL_INIT}" CACHE STRING
+ "Flags used by the compiler during release minsize builds.")
+ set(CMAKE_Pascal_FLAGS_RELEASE "${CMAKE_Pascal_FLAGS_RELEASE_INIT}" CACHE STRING
+ "Flags used by the compiler during release builds (/MD /Ob1 /Oi /Ot /Oy /Gs will produce slightly less optimized but smaller files).")
+ set(CMAKE_Pascal_FLAGS_RELWITHDEBINFO "${CMAKE_Pascal_FLAGS_RELWITHDEBINFO_INIT}" CACHE STRING
+ "Flags used by the compiler during Release with Debug Info builds.")
+endif(NOT CMAKE_NOT_USING_CONFIG_FLAGS)
+
+mark_as_advanced(CMAKE_Pascal_FLAGS CMAKE_Pascal_FLAGS_DEBUG CMAKE_Pascal_FLAGS_MINSIZEREL
+ CMAKE_Pascal_FLAGS_RELEASE CMAKE_Pascal_FLAGS_RELWITHDEBINFO)
+set(CMAKE_Pascal_INFORMATION_LOADED 1)
+
diff -Nru hedgewars-0.9.19.3/cmake_modules/CMakeTestPascalCompiler.cmake hedgewars-0.9.20.5/cmake_modules/CMakeTestPascalCompiler.cmake
--- hedgewars-0.9.19.3/cmake_modules/CMakeTestPascalCompiler.cmake 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/CMakeTestPascalCompiler.cmake 2013-10-31 20:21:51.000000000 +0000
@@ -0,0 +1,53 @@
+# This file is used by EnableLanguage in cmGlobalGenerator to determine that
+# the FreePascal can actually compile and link the most basic of programs.
+# If not, a fatal error is set, cmake stops processing commands and will not
+# generate any makefiles or projects.
+
+if(NOT CMAKE_Pascal_COMPILER_WORKS)
+ message(STATUS "Check for working Pascal compiler: ${CMAKE_Pascal_COMPILER}")
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeTmp/testpascalcompiler.pas
+ "program testPascalCompiler;
+ begin
+ end.
+ ")
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeTmp/CMakeLists.txt
+ "set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake_modules)
+ set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL \"\" FORCE)
+ project(test Pascal)
+ add_executable(testpascalcompiler testpascalcompiler.pas)
+ ")
+
+# To avoid try_compile recurse error, use any binary directory other
+# than ${CMAKE_BINARY_DIR}. The choice of
+# bindir = ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp is
+# especially advantageous since it makes an in-source build which
+# means that no special variables need to be set to find files.
+ try_compile(CMAKE_Pascal_COMPILER_WORKS
+ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeTmp
+ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeTmp
+ test
+ OUTPUT_VARIABLE RESULT_OUTPUT
+ )
+ set(PASCAL_TEST_WAS_RUN 1)
+endif(NOT CMAKE_Pascal_COMPILER_WORKS)
+
+if(NOT CMAKE_Pascal_COMPILER_WORKS)
+ message(STATUS "Check for working Pascal compiler: ${CMAKE_Pascal_COMPILER} -- broken")
+ file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the Pascal compiler works failed with "
+ "the following output:\n${RESULT_OUTPUT}\n\n")
+ message(FATAL_ERROR "The Pascal builder \"${CMAKE_Pascal_COMPILER}\" "
+ "is not able to compile and link a simple test program.\nIt fails "
+ "with the following output:\n ${RESULT_OUTPUT}\n\n"
+ "CMake will not be able to correctly generate this project.")
+else(NOT CMAKE_Pascal_COMPILER_WORKS)
+ if(PASCAL_TEST_WAS_RUN)
+ message(STATUS "Check for working Pascal compiler: ${CMAKE_Pascal_COMPILER} -- works")
+ file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the Pascal compiler works passed with "
+ "the following output:\n${RESULT_OUTPUT}\n\n")
+ endif(PASCAL_TEST_WAS_RUN)
+ set(CMAKE_Pascal_COMPILER_WORKS 1 CACHE INTERNAL "")
+endif(NOT CMAKE_Pascal_COMPILER_WORKS)
+
diff -Nru hedgewars-0.9.19.3/cmake_modules/FindFFMPEG.cmake hedgewars-0.9.20.5/cmake_modules/FindFFMPEG.cmake
--- hedgewars-0.9.19.3/cmake_modules/FindFFMPEG.cmake 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/FindFFMPEG.cmake 2013-10-31 20:21:51.000000000 +0000
@@ -25,18 +25,23 @@
# 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 ${VERBOSITY})
- pkg_check_modules(_FFMPEG_AVFORMAT libavformat ${VERBOSITY})
- pkg_check_modules(_FFMPEG_AVUTIL libavutil ${VERBOSITY})
-endif (PKG_CONFIG_FOUND)
+if(PKG_CONFIG_FOUND)
+ if(NOT LIBAVCODEC_INCLUDE_DIR OR NOT LIBAVCODEC_LIBRARY)
+ pkg_check_modules(_FFMPEG_AVCODEC libavcodec)
+ endif()
+ if(NOT LIBAVFORMAT_LIBRARY)
+ pkg_check_modules(_FFMPEG_AVFORMAT libavformat)
+ endif()
+ if(NOT LIBAVUTIL_LIBRARY)
+ pkg_check_modules(_FFMPEG_AVUTIL libavutil)
+ endif()
+endif(PKG_CONFIG_FOUND)
find_path(LIBAVCODEC_INCLUDE_DIR
NAMES libavcodec/avcodec.h
- PATHS ${_AVCODEC_INCLUDE_DIRS}
- /usr/include /usr/local/include #system level
- /opt/local/include #macports
- /sw/include #fink
+ PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS} #pkg-config
+ /usr/include /usr/local/include #system level
+ /opt/local/include /sw/include #macports & fink
PATH_SUFFIXES libav ffmpeg
)
@@ -44,26 +49,23 @@
find_library(LIBAVCODEC_LIBRARY
NAMES avcodec
- PATHS ${_AVCODEC_LIBRARY_DIRS}
- /usr/lib /usr/local/lib #system level
- /opt/local/lib #macports
- /sw/lib #fink
+ PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS} #pkg-config
+ /usr/lib /usr/local/lib #system level
+ /opt/local/lib /sw/lib #macports & fink
)
find_library(LIBAVFORMAT_LIBRARY
NAMES avformat
- PATHS ${_AVFORMAT_LIBRARY_DIRS}
- /usr/lib /usr/local/lib #system level
- /opt/local/lib #macports
- /sw/lib #fink
+ PATHS ${_FFMPEG_AVFORMAT_LIBRARY_DIRS} #pkg-config
+ /usr/lib /usr/local/lib #system level
+ /opt/local/lib /sw/lib #macports & fink
)
find_library(LIBAVUTIL_LIBRARY
NAMES avutil
- PATHS ${_AVUTIL_LIBRARY_DIRS}
- /usr/lib /usr/local/lib #system level
- /opt/local/lib #macports
- /sw/lib #fink
+ PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS} #pkg-config
+ /usr/lib /usr/local/lib #system level
+ /opt/local/lib /sw/lib #macports & fink
)
find_package_handle_standard_args(FFMPEG DEFAULT_MSG LIBAVCODEC_LIBRARY LIBAVCODEC_INCLUDE_DIR
diff -Nru hedgewars-0.9.19.3/cmake_modules/FindFreePascal.cmake hedgewars-0.9.20.5/cmake_modules/FindFreePascal.cmake
--- hedgewars-0.9.19.3/cmake_modules/FindFreePascal.cmake 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/FindFreePascal.cmake 1970-01-01 00:00:00.000000000 +0000
@@ -1,37 +0,0 @@
-# - Try to find the FreePascal executable
-# Once done this will define
-#
-# FREEPASCAL_FOUND - system has Freepascal
-# FREEPASCAL_VERSION - Freepascal version
-# FREEPASCAL_EXECUTABLE - Freepascal executable
-#
-# Copyright (c) 2012, Bryan Dunsmore
-# Copyright (c) 2013, Vittorio Giovara
-#
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-
-
-find_program(FREEPASCAL_EXECUTABLE
- NAMES fpc
- PATHS /opt/local/bin /usr/local/bin /usr/bin
- )
-
-if (FREEPASCAL_EXECUTABLE)
- # check Freepascal version
- execute_process(COMMAND ${FREEPASCAL_EXECUTABLE} -iV
- OUTPUT_VARIABLE FREEPASCAL_VERSION
- ERROR_VARIABLE FREEPASCAL_VERSION_ERROR
- RESULT_VARIABLE FREEPASCAL_VERSION_RESULT
- OUTPUT_STRIP_TRAILING_WHITESPACE
- )
-
- if(NOT ${FREEPASCAL_VERSION_RESULT} EQUAL 0)
- message(SEND_ERROR "Command \"${FREEPASCAL_EXECUTABLE} -iV\" failed with output: ${FREEPASCAL_VERSION_ERROR}")
- endif()
-endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(FreePascal DEFAULT_MSG FREEPASCAL_EXECUTABLE FREEPASCAL_VERSION)
-mark_as_advanced(FREEPASCAL_VERSION)
-
diff -Nru hedgewars-0.9.19.3/cmake_modules/FindGMP.cmake hedgewars-0.9.20.5/cmake_modules/FindGMP.cmake
--- hedgewars-0.9.19.3/cmake_modules/FindGMP.cmake 2013-01-18 08:12:34.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/FindGMP.cmake 1970-01-01 00:00:00.000000000 +0000
@@ -1,17 +0,0 @@
-FIND_PATH(GMP_INCLUDE_DIR gmp.h)
-
-FIND_LIBRARY(GMP_LIBRARY NAMES GMP gmp)
-
-IF (GMP_INCLUDE_DIR AND GMP_LIBRARY)
- SET(GMP_FOUND TRUE)
- ENDIF (GMP_INCLUDE_DIR AND GMP_LIBRARY)
-
- IF (GMP_FOUND)
- IF (NOT GMP_FIND_QUIETLY)
- MESSAGE(STATUS "Found GMP: ${GMP_LIBRARY}")
- ENDIF (NOT GMP_FIND_QUIETLY)
- ELSE (GMP_FOUND)
- IF (GMP_FIND_REQUIRED)
- MESSAGE(FATAL_ERROR "Could not find GMP")
- ENDIF (GMP_FIND_REQUIRED)
-ENDIF (GMP_FOUND)
diff -Nru hedgewars-0.9.19.3/cmake_modules/FindLibraryWithDebug.cmake hedgewars-0.9.20.5/cmake_modules/FindLibraryWithDebug.cmake
--- hedgewars-0.9.19.3/cmake_modules/FindLibraryWithDebug.cmake 2013-06-03 08:01:41.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/FindLibraryWithDebug.cmake 1970-01-01 00:00:00.000000000 +0000
@@ -1,113 +0,0 @@
-#
-# FIND_LIBRARY_WITH_DEBUG
-# -> enhanced FIND_LIBRARY to allow the search for an
-# optional debug library with a WIN32_DEBUG_POSTFIX similar
-# to CMAKE_DEBUG_POSTFIX when creating a shared lib
-# it has to be the second and third argument
-
-# Copyright (c) 2007, Christian Ehrlicher,
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-
-MACRO(FIND_LIBRARY_WITH_DEBUG var_name win32_dbg_postfix_name dgb_postfix libname)
-
- IF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX")
-
- # no WIN32_DEBUG_POSTFIX -> simply pass all arguments to FIND_LIBRARY
- FIND_LIBRARY(${var_name}
- ${win32_dbg_postfix_name}
- ${dgb_postfix}
- ${libname}
- ${ARGN}
- )
-
- ELSE(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX")
-
- IF(NOT WIN32)
- # on non-win32 we don't need to take care about WIN32_DEBUG_POSTFIX
-
- FIND_LIBRARY(${var_name} ${libname} ${ARGN})
-
- ELSE(NOT WIN32)
-
- # 1. get all possible libnames
- SET(args ${ARGN})
- SET(newargs "")
- SET(libnames_release "")
- SET(libnames_debug "")
-
- LIST(LENGTH args listCount)
-
- IF("${libname}" STREQUAL "NAMES")
- SET(append_rest 0)
- LIST(APPEND args " ")
-
- FOREACH(i RANGE ${listCount})
- LIST(GET args ${i} val)
-
- IF(append_rest)
- LIST(APPEND newargs ${val})
- ELSE(append_rest)
- IF("${val}" STREQUAL "PATHS")
- LIST(APPEND newargs ${val})
- SET(append_rest 1)
- ELSE("${val}" STREQUAL "PATHS")
- LIST(APPEND libnames_release "${val}")
- LIST(APPEND libnames_debug "${val}${dgb_postfix}")
- ENDIF("${val}" STREQUAL "PATHS")
- ENDIF(append_rest)
-
- ENDFOREACH(i)
-
- ELSE("${libname}" STREQUAL "NAMES")
-
- # just one name
- LIST(APPEND libnames_release "${libname}")
- LIST(APPEND libnames_debug "${libname}${dgb_postfix}")
-
- SET(newargs ${args})
-
- ENDIF("${libname}" STREQUAL "NAMES")
-
- # search the release lib
- FIND_LIBRARY(${var_name}_RELEASE
- NAMES ${libnames_release}
- ${newargs}
- )
-
- # search the debug lib
- FIND_LIBRARY(${var_name}_DEBUG
- NAMES ${libnames_debug}
- ${newargs}
- )
-
- IF(${var_name}_RELEASE AND ${var_name}_DEBUG)
-
- # both libs found
- SET(${var_name} optimized ${${var_name}_RELEASE}
- debug ${${var_name}_DEBUG})
-
- ELSE(${var_name}_RELEASE AND ${var_name}_DEBUG)
-
- IF(${var_name}_RELEASE)
-
- # only release found
- SET(${var_name} ${${var_name}_RELEASE})
-
- ELSE(${var_name}_RELEASE)
-
- # only debug (or nothing) found
- SET(${var_name} ${${var_name}_DEBUG})
-
- ENDIF(${var_name}_RELEASE)
-
- ENDIF(${var_name}_RELEASE AND ${var_name}_DEBUG)
-
- MARK_AS_ADVANCED(${var_name}_RELEASE)
- MARK_AS_ADVANCED(${var_name}_DEBUG)
-
- ENDIF(NOT WIN32)
-
- ENDIF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX")
-
-ENDMACRO(FIND_LIBRARY_WITH_DEBUG)
diff -Nru hedgewars-0.9.19.3/cmake_modules/FindLua.cmake hedgewars-0.9.20.5/cmake_modules/FindLua.cmake
--- hedgewars-0.9.19.3/cmake_modules/FindLua.cmake 2013-06-03 08:01:41.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/FindLua.cmake 2013-10-31 20:21:51.000000000 +0000
@@ -1,37 +1,26 @@
-# Find the Lua library
-# --------------------
-# On Android/Windows/OSX this just defines the name of the library that
-# will be compiled from our bundled sources
-# On Linux it will try to load the system library and fallback to compiling
-# the bundled one when nothing is found
+# Find liblua
+#
+# Once done this will define
+# LUA_FOUND - system has Lua
+# LUA_INCLUDE_DIR - the Lua include directory
+# LUA_LIBRARY - The library needed to use Lua
+# Copyright (c) 2013, Vittorio Giovara
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
-set(LUA_FOUND false)
-set(LUA_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/misc/liblua)
+include(FindPackageHandleStandardArgs)
-if (ANDROID)
- SET(LUA_DEFAULT "liblua5.1.so")
-else (ANDROID)
- IF(WIN32)
- SET(LUA_DEFAULT lua.dll)
- ELSE(WIN32)
- IF(APPLE)
- SET(LUA_DEFAULT lua)
- ELSE(APPLE)
- #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)
- 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()
- ENDIF(APPLE)
- ENDIF(WIN32)
-ENDIF(ANDROID)
-
-SET(LUA_LIBRARY ${LUA_DEFAULT} CACHE STRING "Lua library to link to; file name without path only!")
+find_path(LUA_INCLUDE_DIR lua.h
+ PATHS /usr/include /usr/local/include /usr/pkg/include
+ PATH_SUFFIXES lua5.1 lua51)
+find_library(LUA_LIBRARY NAMES lua51 lua5.1 lua-5.1 lua
+ PATHS /lib /usr/lib /usr/local/lib /usr/pkg/lib)
+find_package_handle_standard_args(Lua DEFAULT_MSG LUA_LIBRARY LUA_INCLUDE_DIR)
+mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARY)
diff -Nru hedgewars-0.9.19.3/cmake_modules/FindSDL1or2.cmake hedgewars-0.9.20.5/cmake_modules/FindSDL1or2.cmake
--- hedgewars-0.9.19.3/cmake_modules/FindSDL1or2.cmake 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/FindSDL1or2.cmake 2013-10-31 20:21:51.000000000 +0000
@@ -0,0 +1,24 @@
+find_package(SDL QUIET)
+
+if(NOT SDL_FOUND)
+ find_package(SDL2 REQUIRED)
+ set(SDL_INCLUDE_DIR ${SDL2_INCLUDE_DIR})
+ set(SDL_LIBRARY ${SDL2_LIBRARY})
+endif()
+
+if(NOT SDL_VERSION)
+ #find which version of SDL we have
+ find_file(sdlversion_h SDL_version.h ${SDL_INCLUDE_DIR})
+ if(sdlversion_h)
+ file(STRINGS ${sdlversion_h} sdl_majorversion_tmp REGEX "SDL_MAJOR_VERSION[\t' ']+[0-9]+")
+ file(STRINGS ${sdlversion_h} sdl_minorversion_tmp REGEX "SDL_MINOR_VERSION[\t' ']+[0-9]+")
+ file(STRINGS ${sdlversion_h} sdl_patchversion_tmp REGEX "SDL_PATCHLEVEL[\t' ']+[0-9]+")
+ string(REGEX MATCH "([0-9]+)" sdl_majorversion "${sdl_majorversion_tmp}")
+ string(REGEX MATCH "([0-9]+)" sdl_minorversion "${sdl_minorversion_tmp}")
+ string(REGEX MATCH "([0-9]+)" sdl_patchversion "${sdl_patchversion_tmp}")
+ set(SDL_VERSION "${sdl_majorversion}.${sdl_minorversion}.${sdl_patchversion}")
+ endif()
+endif()
+
+mark_as_advanced(sdlversion_h sdl_majorversion sdl_minorversion sdl_patchversion)
+
diff -Nru hedgewars-0.9.19.3/cmake_modules/FindSDL2.cmake hedgewars-0.9.20.5/cmake_modules/FindSDL2.cmake
--- hedgewars-0.9.19.3/cmake_modules/FindSDL2.cmake 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/FindSDL2.cmake 2013-10-31 20:21:51.000000000 +0000
@@ -0,0 +1,164 @@
+# Locate SDL2 library
+# This module defines
+# SDL2_LIBRARY, the name of the library to link against
+# SDL2_FOUND, if false, do not try to link to SDL2
+# SDL2_INCLUDE_DIR, where to find SDL.h
+#
+# This module responds to the the flag:
+# SDL2_BUILDING_LIBRARY
+# If this is defined, then no SDL2main will be linked in because
+# only applications need main().
+# Otherwise, it is assumed you are building an application and this
+# module will attempt to locate and set the the proper link flags
+# as part of the returned SDL2_LIBRARY variable.
+#
+# Don't forget to include SDLmain.h and SDLmain.m your project for the
+# OS X framework based version. (Other versions link to -lSDL2main which
+# this module will try to find on your behalf.) Also for OS X, this
+# module will automatically add the -framework Cocoa on your behalf.
+#
+#
+# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
+# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
+# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
+# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
+# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
+# as appropriate. These values are used to generate the final SDL2_LIBRARY
+# variable, but when these values are unset, SDL2_LIBRARY does not get created.
+#
+#
+# $SDL2DIR is an environment variable that would
+# correspond to the ./configure --prefix=$SDL2DIR
+# used in building SDL2.
+# l.e.galup 9-20-02
+#
+# Modified by Eric Wing.
+# Added code to assist with automated building by using environmental variables
+# and providing a more controlled/consistent search behavior.
+# Added new modifications to recognize OS X frameworks and
+# additional Unix paths (FreeBSD, etc).
+# Also corrected the header search path to follow "proper" SDL guidelines.
+# Added a search for SDL2main which is needed by some platforms.
+# Added a search for threads which is needed by some platforms.
+# Added needed compile switches for MinGW.
+#
+# On OSX, this will prefer the Framework version (if found) over others.
+# People will have to manually change the cache values of
+# SDL2_LIBRARY to override this selection or set the CMake environment
+# CMAKE_INCLUDE_PATH to modify the search paths.
+#
+# Note that the header path has changed from SDL2/SDL.h to just SDL.h
+# This needed to change because "proper" SDL convention
+# is #include "SDL.h", not . This is done for portability
+# reasons because not all systems place things in SDL2/ (see FreeBSD).
+
+#=============================================================================
+# Copyright 2003-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+SET(SDL2_SEARCH_PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+)
+
+FIND_PATH(SDL2_INCLUDE_DIR SDL.h
+ HINTS
+ $ENV{SDL2DIR}
+ PATH_SUFFIXES include/SDL2 include
+ PATHS ${SDL2_SEARCH_PATHS}
+)
+
+FIND_LIBRARY(SDL2_LIBRARY_TEMP
+ NAMES SDL2
+ HINTS
+ $ENV{SDL2DIR}
+ PATH_SUFFIXES lib64 lib
+ PATHS ${SDL2_SEARCH_PATHS}
+)
+
+IF(NOT SDL2_BUILDING_LIBRARY)
+ IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
+ # Non-OS X framework versions expect you to also dynamically link to
+ # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
+ # seem to provide SDL2main for compatibility even though they don't
+ # necessarily need it.
+ FIND_LIBRARY(SDL2MAIN_LIBRARY
+ NAMES SDL2main
+ HINTS
+ $ENV{SDL2DIR}
+ PATH_SUFFIXES lib64 lib
+ PATHS ${SDL2_SEARCH_PATHS}
+ )
+ ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
+ENDIF(NOT SDL2_BUILDING_LIBRARY)
+
+# SDL2 may require threads on your system.
+# The Apple build may not need an explicit flag because one of the
+# frameworks may already provide it.
+# But for non-OSX systems, I will use the CMake Threads package.
+IF(NOT APPLE)
+ FIND_PACKAGE(Threads)
+ENDIF(NOT APPLE)
+
+# MinGW needs an additional library, mwindows
+# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
+# (Actually on second look, I think it only needs one of the m* libraries.)
+IF(MINGW)
+ SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
+ENDIF(MINGW)
+
+IF(SDL2_LIBRARY_TEMP)
+ # For SDL2main
+ IF(NOT SDL2_BUILDING_LIBRARY)
+ IF(SDL2MAIN_LIBRARY)
+ SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
+ ENDIF(SDL2MAIN_LIBRARY)
+ ENDIF(NOT SDL2_BUILDING_LIBRARY)
+
+ # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
+ # CMake doesn't display the -framework Cocoa string in the UI even
+ # though it actually is there if I modify a pre-used variable.
+ # I think it has something to do with the CACHE STRING.
+ # So I use a temporary variable until the end so I can set the
+ # "real" variable in one-shot.
+ IF(APPLE)
+ SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
+ ENDIF(APPLE)
+
+ # For threads, as mentioned Apple doesn't need this.
+ # In fact, there seems to be a problem if I used the Threads package
+ # and try using this line, so I'm just skipping it entirely for OS X.
+ IF(NOT APPLE)
+ SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
+ ENDIF(NOT APPLE)
+
+ # For MinGW library
+ IF(MINGW)
+ SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
+ ENDIF(MINGW)
+
+ # Set the final string here so the GUI reflects the final state.
+ SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
+ # Set the temp variable to INTERNAL so it is not seen in the CMake GUI
+ SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
+ENDIF(SDL2_LIBRARY_TEMP)
+
+INCLUDE(FindPackageHandleStandardArgs)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
+
diff -Nru hedgewars-0.9.19.3/cmake_modules/TargetArch.cmake hedgewars-0.9.20.5/cmake_modules/TargetArch.cmake
--- hedgewars-0.9.19.3/cmake_modules/TargetArch.cmake 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/TargetArch.cmake 2014-01-04 19:46:00.000000000 +0000
@@ -0,0 +1,142 @@
+# Original file location https://github.com/petroules/solar-cmake/blob/master/TargetArch.cmake
+#Copyright (c) 2012 Petroules Corporation. All rights reserved.
+#Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+#
+# 1 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+# 2 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# Based on the Qt 5 processor detection code, so should be very accurate
+# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
+# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
+
+# Regarding POWER/PowerPC, just as is noted in the Qt source,
+# "There are many more known variants/revisions that we do not handle/detect."
+
+set(archdetect_c_code "
+#if defined(__arm__) || defined(__TARGET_ARCH_ARM)
+ #if defined(__ARM_ARCH_7__) \\
+ || defined(__ARM_ARCH_7A__) \\
+ || defined(__ARM_ARCH_7R__) \\
+ || defined(__ARM_ARCH_7M__) \\
+ || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
+ #error cmake_ARCH armv7
+ #elif defined(__ARM_ARCH_6__) \\
+ || defined(__ARM_ARCH_6J__) \\
+ || defined(__ARM_ARCH_6T2__) \\
+ || defined(__ARM_ARCH_6Z__) \\
+ || defined(__ARM_ARCH_6K__) \\
+ || defined(__ARM_ARCH_6ZK__) \\
+ || defined(__ARM_ARCH_6M__) \\
+ || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
+ #error cmake_ARCH armv6
+ #elif defined(__ARM_ARCH_5TEJ__) \\
+ || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
+ #error cmake_ARCH armv5
+ #else
+ #error cmake_ARCH arm
+ #endif
+#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
+ #error cmake_ARCH i386
+#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
+ #error cmake_ARCH x86_64
+#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
+ #error cmake_ARCH ia64
+#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
+ || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
+ || defined(_M_MPPC) || defined(_M_PPC)
+ #if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
+ #error cmake_ARCH ppc64
+ #else
+ #error cmake_ARCH ppc
+ #endif
+#endif
+
+#error cmake_ARCH unknown
+")
+
+# Set ppc_support to TRUE before including this file or ppc and ppc64
+# will be treated as invalid architectures since they are no longer supported by Apple
+
+function(target_architecture output_var)
+ if(APPLE AND CMAKE_OSX_ARCHITECTURES)
+ # On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set
+ # First let's normalize the order of the values
+
+ # Note that it's not possible to compile PowerPC applications if you are using
+ # the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
+ # disable it by default
+ # See this page for more information:
+ # http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
+
+ # Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
+ # On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
+
+ foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
+ if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
+ set(osx_arch_ppc TRUE)
+ elseif("${osx_arch}" STREQUAL "i386")
+ set(osx_arch_i386 TRUE)
+ elseif("${osx_arch}" STREQUAL "x86_64")
+ set(osx_arch_x86_64 TRUE)
+ elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
+ set(osx_arch_ppc64 TRUE)
+ else()
+ message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
+ endif()
+ endforeach()
+
+ # Now add all the architectures in our normalized order
+ if(osx_arch_ppc)
+ list(APPEND ARCH ppc)
+ endif()
+
+ if(osx_arch_i386)
+ list(APPEND ARCH i386)
+ endif()
+
+ if(osx_arch_x86_64)
+ list(APPEND ARCH x86_64)
+ endif()
+
+ if(osx_arch_ppc64)
+ list(APPEND ARCH ppc64)
+ endif()
+ else()
+ file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
+
+ enable_language(C)
+
+ # Detect the architecture in a rather creative way...
+ # This compiles a small C program which is a series of ifdefs that selects a
+ # particular #error preprocessor directive whose message string contains the
+ # target architecture. The program will always fail to compile (both because
+ # file is not a valid C program, and obviously because of the presence of the
+ # #error preprocessor directives... but by exploiting the preprocessor in this
+ # way, we can detect the correct target architecture even when cross-compiling,
+ # since the program itself never needs to be run (only the compiler/preprocessor)
+ try_run(
+ run_result_unused
+ compile_result_unused
+ "${CMAKE_BINARY_DIR}"
+ "${CMAKE_BINARY_DIR}/arch.c"
+ COMPILE_OUTPUT_VARIABLE ARCH
+ CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
+ )
+
+ # Parse the architecture name from the compiler output
+ string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
+
+ # Get rid of the value marker leaving just the architecture name
+ string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
+
+ # If we are compiling with an unknown architecture this variable should
+ # already be set to "unknown" but in the case that it's empty (i.e. due
+ # to a typo in the code), then set it to unknown
+ if (NOT ARCH)
+ set(ARCH unknown)
+ endif()
+ endif()
+
+ set(${output_var} "${ARCH}" PARENT_SCOPE)
+endfunction()
diff -Nru hedgewars-0.9.19.3/cmake_modules/compilerchecks.cmake hedgewars-0.9.20.5/cmake_modules/compilerchecks.cmake
--- hedgewars-0.9.19.3/cmake_modules/compilerchecks.cmake 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/compilerchecks.cmake 2013-10-31 20:21:51.000000000 +0000
@@ -0,0 +1,91 @@
+
+#TESTING TIME
+include(CheckCCompilerFlag)
+#when you need to check for a linker flag, just leave the argument of "check_c_compiler_flag" empty
+
+# CMAKE_C{XX}_FLAGS is for compiler flags (c and c++)
+# CMAKE_EXE_LINKER_FLAGS is for linker flags (also add them to pascal_flags and haskell_flags)
+# CMAKE_SHARED_LIBRARY__FLAGS same but for shared libraries
+
+#TODO: should there be two different checks for C and CXX?
+#TODO: can the various if(platform) be avoided in some way?
+
+
+if(NOT (WIN32 OR (CMAKE_SYSTEM_NAME MATCHES BSD.OS) OR (CMAKE_SYSTEM_NAME MATCHES FreeBSD)))
+ #stack protection, when found it needs to go in the linker flags too
+ #it is disabled on win32 because it adds a dll and messes with linker
+ #some bsd installations reported problems too
+ #(see 822312 654424 on bugzilla.redhat.com)
+ check_c_compiler_flag("-fstack-protector-all -fstack-protector" HAVE_STACKPROTECTOR)
+ if(HAVE_STACKPROTECTOR)
+ add_flag_append(CMAKE_C_FLAGS "-fstack-protector-all -fstack-protector")
+ add_flag_append(CMAKE_CXX_FLAGS "-fstack-protector-all -fstack-protector")
+ endif()
+endif()
+
+
+
+if(UNIX)
+ #symbol visibility
+ check_c_compiler_flag("-fvisibility=hidden" HAVE_VISIBILITY)
+ if(HAVE_VISIBILITY)
+ add_flag_append(CMAKE_C_FLAGS "-fvisibility=hidden")
+ add_flag_append(CMAKE_CXX_FLAGS "-fvisibility=hidden")
+ endif()
+
+ #check for noexecstack on ELF, Gentoo security
+ set(CMAKE_REQUIRED_FLAGS "-Wl,-znoexecstack")
+ check_c_compiler_flag("" HAVE_NOEXECSTACK)
+ if(HAVE_NOEXECSTACK)
+ add_linker_flag("-znoexecstack")
+ endif()
+
+ #check for origin on ELF, BSD $ORIGIN support
+ set(CMAKE_REQUIRED_FLAGS "-Wl,-zorigin")
+ check_c_compiler_flag("" HAVE_ORIGIN)
+ if(HAVE_ORIGIN)
+ add_linker_flag("-zorigin")
+ endif()
+
+ #check for full relro on ELF, Debian security
+ set(CMAKE_REQUIRED_FLAGS "-Wl,-zrelro,-znow")
+ check_c_compiler_flag("" HAVE_RELROFULL)
+ if(HAVE_RELROFULL)
+ add_linker_flag("-zrelro")
+ add_linker_flag("-znow")
+ else()
+ #if full relro is not available, try partial relro
+ set(CMAKE_REQUIRED_FLAGS "-Wl,-zrelro")
+ check_c_compiler_flag("" HAVE_RELROPARTIAL)
+ if(HAVE_RELROPARTIAL)
+ add_linker_flag("-zrelro")
+ endif()
+ endif()
+
+ if(CMAKE_BUILD_TYPE MATCHES "RELEASE")
+ set(CMAKE_REQUIRED_FLAGS "-Wl,--as-needed")
+ check_c_compiler_flag("" HAVE_ASNEEDED)
+ if(HAVE_ASNEEDED)
+ add_linker_flag("--as-needed")
+ endif()
+ endif()
+else(UNIX)
+ #check for ASLR on Windows Vista or later, requires binutils >= 2.20
+ set(CMAKE_REQUIRED_FLAGS "-Wl,--nxcompat")
+ check_c_compiler_flag("" HAVE_WINASLR)
+ if(HAVE_WINASLR)
+ add_linker_flag("--nxcompat")
+ endif()
+
+ #check for DEP on Windows XP SP2 or later, requires binutils >= 2.20
+ set(CMAKE_REQUIRED_FLAGS "-Wl,--dynamicbase")
+ check_c_compiler_flag("" HAVE_WINDEP)
+ if(HAVE_WINDEP)
+ add_linker_flag("--dynamicbase")
+ endif()
+endif(UNIX)
+
+
+#always unset or these flags will be spread everywhere
+unset(CMAKE_REQUIRED_FLAGS)
+
diff -Nru hedgewars-0.9.19.3/cmake_modules/cpackvars.cmake hedgewars-0.9.20.5/cmake_modules/cpackvars.cmake
--- hedgewars-0.9.19.3/cmake_modules/cpackvars.cmake 2013-06-11 08:23:53.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/cpackvars.cmake 2014-01-04 19:46:00.000000000 +0000
@@ -58,7 +58,7 @@
"\\\\.db$"
"\\\\.dof$"
"\\\\.or$"
- "\\\\.stackdump$"
+ "\\\\.stackdump$"
#archives
"\\\\.zip$"
"\\\\.gz$"
@@ -84,14 +84,13 @@
"cmake_uninstall\\\\.cmake$"
"CMakeCache\\\\.txt$"
"build_windows_.*\\\\.bat$"
-# "^${CMAKE_CURRENT_SOURCE_DIR}/misc/libtremor"
-# "^${CMAKE_CURRENT_SOURCE_DIR}/misc/libfreetype"
-# "^${CMAKE_CURRENT_SOURCE_DIR}/misc/liblua"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/misc/liblua"
# "^${CMAKE_CURRENT_SOURCE_DIR}/project_files/frontlib"
# "^${CMAKE_CURRENT_SOURCE_DIR}/project_files/cmdlineClient"
- "^${CMAKE_CURRENT_SOURCE_DIR}/misc/libopenalbridge"
"^${CMAKE_CURRENT_SOURCE_DIR}/misc/winutils/bin"
"^${CMAKE_CURRENT_SOURCE_DIR}/project_files/promotional_art"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/project_files/AudioMono"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/project_files/HedgewarsMobile"
"^${CMAKE_CURRENT_SOURCE_DIR}/tools/templates"
"^${CMAKE_CURRENT_SOURCE_DIR}/tools/drawMapTest"
"^${CMAKE_CURRENT_SOURCE_DIR}/doc"
diff -Nru hedgewars-0.9.19.3/cmake_modules/paths.cmake hedgewars-0.9.20.5/cmake_modules/paths.cmake
--- hedgewars-0.9.19.3/cmake_modules/paths.cmake 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/paths.cmake 2014-01-08 16:25:17.000000000 +0000
@@ -0,0 +1,70 @@
+#where to build libs and bins
+set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+#these variables are for non-makefile generators
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${EXECUTABLE_OUTPUT_PATH})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${EXECUTABLE_OUTPUT_PATH})
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH})
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${LIBRARY_OUTPUT_PATH})
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${LIBRARY_OUTPUT_PATH})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${LIBRARY_OUTPUT_PATH})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${LIBRARY_OUTPUT_PATH})
+
+#resource paths
+if(UNIX AND NOT APPLE)
+ set(target_binary_install_dir "bin" CACHE PATH "install dest for binaries")
+ set(target_library_install_dir "lib" CACHE PATH "install dest for libs")
+
+ string(SUBSTRING "${DATA_INSTALL_DIR}" 0 1 sharepath_start)
+ if (NOT (${sharepath_start} MATCHES "/"))
+ set(HEDGEWARS_DATADIR "${CMAKE_INSTALL_PREFIX}/${DATA_INSTALL_DIR}/")
+ else()
+ set(HEDGEWARS_DATADIR "${DATA_INSTALL_DIR}/")
+ endif()
+ set(HEDGEWARS_FULL_DATADIR "${HEDGEWARS_DATADIR}")
+else()
+ set(target_binary_install_dir "./")
+
+ if(APPLE)
+ set(target_library_install_dir "../Frameworks/")
+ set(CMAKE_INSTALL_PREFIX "Hedgewars.app/Contents/MacOS/")
+ set(HEDGEWARS_DATADIR "../Resources/")
+ set(HEDGEWARS_FULL_DATADIR "/Applications/${CMAKE_INSTALL_PREFIX}/${HEDGEWARS_DATADIR}")
+ elseif(WIN32)
+ set(target_library_install_dir "./")
+ set(HEDGEWARS_DATADIR "./")
+ set(HEDGEWARS_FULL_DATADIR "${CMAKE_INSTALL_PREFIX}/")
+ link_directories("${EXECUTABLE_OUTPUT_PATH}" "${CMAKE_SOURCE_DIR}/misc/winutils/bin")
+ endif()
+endif()
+
+
+#RPATH SETTINGS
+#necessary for dynamic libraries on UNIX, ignored elsewhere
+
+#use, i.e. don't skip the full RPATH for the build tree
+set(CMAKE_SKIP_BUILD_RPATH FALSE)
+set(CMAKE_SKIP_INSTALL_RPATH FALSE)
+
+#it's safe to use our RPATH because it is relative
+set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
+
+#add the automatically determined parts of the RPATH
+#which point to directories outside the build tree to the install RPATH
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
+
+if(APPLE)
+ #@rpath mangling
+ set(CMAKE_INSTALL_RPATH "@executable_path/../Frameworks")
+ #install_name_tool for libraries
+ set(CMAKE_INSTALL_NAME_DIR "@executable_path/../Frameworks")
+else(APPLE)
+ #paths where to find libraries (final slash not optional):
+ # - the first is relative to the executable
+ # - the second is the same directory of the executable (so it runs in bin/)
+ # - the third one is the full path of the system dir
+ #source http://www.cmake.org/pipermail/cmake/2008-January/019290.html
+ set(CMAKE_INSTALL_RPATH "$ORIGIN/../${target_library_install_dir}/:$ORIGIN/:${CMAKE_INSTALL_PREFIX}/${target_library_install_dir}/")
+endif(APPLE)
diff -Nru hedgewars-0.9.19.3/cmake_modules/platform.cmake hedgewars-0.9.20.5/cmake_modules/platform.cmake
--- hedgewars-0.9.19.3/cmake_modules/platform.cmake 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/platform.cmake 2014-01-04 19:46:00.000000000 +0000
@@ -0,0 +1,123 @@
+
+if(APPLE)
+ if(${CMAKE_VERSION} VERSION_GREATER "2.8.10.2" AND
+ ${CMAKE_VERSION} VERSION_LESS "2.8.12.1")
+ message(FATAL_ERROR "This version of CMake is known *not* to work, please update or use a lower version")
+ endif()
+
+ set(CMAKE_FIND_FRAMEWORK "FIRST")
+
+ #what system are we building for
+ set(minimum_macosx_version $ENV{MACOSX_DEPLOYMENT_TARGET})
+
+ #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)
+ 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()
+ if(NOT minimum_macosx_version)
+ message(FATAL_ERROR "sw_vers not found! Need explicit MACOSX_DEPLOYMENT_TARGET variable set")
+ else()
+ message("*** sw_vers not found! Fallback to MACOSX_DEPLOYMENT_TARGET variable ***")
+ set(current_macosx_version ${minimum_macosx_version})
+ endif()
+ endif()
+
+ #if nothing is set, we deploy only for the current system
+ if(NOT minimum_macosx_version)
+ set(minimum_macosx_version ${current_macosx_version})
+ endif()
+
+ #10.3 systems don't have enough processing power anyway
+ #10.4 does not have @rpath support (which SDL uses)
+ if(minimum_macosx_version VERSION_LESS "10.5")
+ message(FATAL_ERROR "Hedgewars is not supported on your version of Mac OS X")
+ endif()
+
+ if(NOT CMAKE_OSX_ARCHITECTURES)
+ if(current_macosx_version VERSION_LESS "10.6")
+ #SDL is only 32 bit on older OS version
+ if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "powerpc*")
+ set(CMAKE_OSX_ARCHITECTURES "ppc7400")
+ else()
+ set(CMAKE_OSX_ARCHITECTURES "i386")
+ endif()
+ endif()
+ endif()
+
+ #parse this system variable and adjust only the powerpc syntax to be compatible with -P
+ if(CMAKE_OSX_ARCHITECTURES)
+ string(REGEX MATCH "[pP][pP][cC]+" powerpc_build "${CMAKE_OSX_ARCHITECTURES}")
+ string(REGEX MATCH "[iI]386+" i386_build "${CMAKE_OSX_ARCHITECTURES}")
+ string(REGEX MATCH "[xX]86_64+" x86_64_build "${CMAKE_OSX_ARCHITECTURES}")
+ if(x86_64_build)
+ add_flag_prepend(CMAKE_Pascal_FLAGS -Px86_64)
+ elseif(i386_build)
+ add_flag_prepend(CMAKE_Pascal_FLAGS -Pi386)
+ elseif(powerpc_build)
+ add_flag_prepend(CMAKE_Pascal_FLAGS -Ppowerpc)
+ else()
+ message(FATAL_ERROR "Unknown architecture present in CMAKE_OSX_ARCHITECTURES (${CMAKE_OSX_ARCHITECTURES})")
+ endif()
+ list(LENGTH CMAKE_OSX_ARCHITECTURES num_of_archs)
+ if(num_of_archs GREATER 1)
+ message("*** Only one architecture in CMAKE_OSX_ARCHITECTURES is supported, picking the first one ***")
+ endif()
+ elseif(CMAKE_SIZEOF_VOID_P MATCHES "8")
+ #if that variable is not set check if we are on x86_64 and if so force it, else use default
+ add_flag_prepend(CMAKE_Pascal_FLAGS -Px86_64)
+ endif()
+
+ #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 CMAKE_OSX_SYSROOT AND
+ NOT ${minimum_macosx_version} VERSION_EQUAL ${current_macosx_version})
+ find_program(xcrun xcrun)
+ if(xcrun)
+ execute_process(COMMAND ${xcrun} "--show-sdk-path"
+ OUTPUT_VARIABLE current_sdk_path
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REPLACE "${current_macosx_version}"
+ "${minimum_macosx_version}"
+ CMAKE_OSX_SYSROOT
+ "${current_sdk_path}")
+ else()
+ message("*** xcrun not found! Build will work on ${current_macosx_version} only ***")
+ endif()
+ endif()
+ if(CMAKE_OSX_SYSROOT)
+ add_flag_append(CMAKE_Pascal_FLAGS "-XR${CMAKE_OSX_SYSROOT}")
+ add_flag_append(CMAKE_Pascal_FLAGS "-k-macosx_version_min -k${minimum_macosx_version}")
+ add_flag_append(CMAKE_Pascal_FLAGS "-k-L${LIBRARY_OUTPUT_PATH} -Fl${LIBRARY_OUTPUT_PATH}")
+ endif()
+
+ #add user framework directory
+ add_flag_append(CMAKE_Pascal_FLAGS "-Ff~/Library/Frameworks")
+
+ #workaround older cmake versions
+ if(${CMAKE_VERSION} VERSION_LESS "2.8.12")
+ add_flag_append(CMAKE_C_LINK_FLAGS "-Wl,-rpath -Wl,${CMAKE_INSTALL_RPATH}")
+ add_flag_append(CMAKE_CXX_LINK_FLAGS "-Wl,-rpath -Wl,${CMAKE_INSTALL_RPATH}")
+ add_flag_append(CMAKE_Pascal_LINK_FLAGS "-k-rpath -k${CMAKE_INSTALL_RPATH}")
+ endif()
+endif(APPLE)
+
+if(MINGW)
+ #this flags prevents a few dll hell problems
+ add_flag_append(CMAKE_C_FLAGS "-static-libgcc")
+ add_flag_append(CMAKE_CXX_FLAGS "-static-libgcc")
+endif(MINGW)
+
+if(WIN32)
+ if(NOT ${BUILD_SHARED_LIB})
+ message(FATAL_ERROR "Static linking is not supported on Windows")
+ endif()
+endif(WIN32)
+
+if(UNIX)
+ add_flag_append(CMAKE_C_FLAGS "-fPIC")
+ add_flag_append(CMAKE_CXX_FLAGS "-fPIC")
+endif(UNIX)
diff -Nru hedgewars-0.9.19.3/cmake_modules/revinfo.cmake hedgewars-0.9.20.5/cmake_modules/revinfo.cmake
--- hedgewars-0.9.19.3/cmake_modules/revinfo.cmake 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/revinfo.cmake 2014-01-04 19:46:00.000000000 +0000
@@ -0,0 +1,54 @@
+#detect Mercurial revision and init rev/hash information
+find_program(HGCOMMAND hg)
+find_program(GITCOMMAND git)
+if(EXISTS ${CMAKE_SOURCE_DIR}/.hg AND HGCOMMAND)
+ execute_process(COMMAND ${HGCOMMAND} identify -in
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE internal_version
+ ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ #check local repo status
+ string(REGEX REPLACE "[^+]" "" HGCHANGED ${internal_version})
+ string(REGEX REPLACE "[0-9a-zA-Z]+(.*) ([0-9]+)(.*)" "\\2" HEDGEWARS_REVISION ${internal_version})
+ string(REGEX REPLACE "([0-9a-zA-Z]+)(.*) [0-9]+(.*)" "\\1" HEDGEWARS_HASH ${internal_version})
+
+ if(HGCHANGED)
+ message("*** You have uncommitted changes in your repository ***")
+ endif()
+
+ #let's assume that if you have hg you might be interested in debugging
+ set(default_build_type "DEBUG")
+
+ #write down hash and rev for easy picking should hg be missing
+ file(WRITE "${CMAKE_SOURCE_DIR}/share/version_info.txt" "Hedgewars versioning information, do not modify\nrev ${HEDGEWARS_REVISION}\nhash ${HEDGEWARS_HASH}\n")
+elseif(EXISTS ${CMAKE_SOURCE_DIR}/.git AND GITCOMMAND)
+ execute_process(COMMAND ${GITCOMMAND} rev-parse --short HEAD
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE HEDGEWARS_HASH
+ ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ set(HEDGEWARS_REVISION "GIT")
+
+ #let's assume that if you have git you might be interested in debugging
+ set(default_build_type "DEBUG")
+
+ #write down hash and rev for easy picking should hg be missing
+ file(WRITE "${CMAKE_SOURCE_DIR}/share/version_info.txt" "Hedgewars versioning information, do not modify\nrev ${HEDGEWARS_REVISION}\nhash ${HEDGEWARS_HASH}\n")
+else()
+ set(default_build_type "RELEASE")
+ # when compiling outside rev control, fetch revision and hash information from version_info.txt
+ find_file(version_info version_info.txt PATH ${CMAKE_SOURCE_DIR}/share)
+ if(version_info)
+ file(STRINGS ${version_info} internal_version REGEX "rev")
+ string(REGEX REPLACE "rev ([GIT0-9]*)" "\\1" HEDGEWARS_REVISION ${internal_version})
+ file(STRINGS ${version_info} internal_version REGEX "hash")
+ string(REGEX REPLACE "hash ([a-zA-Z0-9]*)" "\\1" HEDGEWARS_HASH ${internal_version})
+ else()
+ message(WARNING "${CMAKE_SOURCE_DIR}/share/version_info.txt not found, revision information "
+ "will be incorrect!!! Contact your source provider to fix this!")
+ set(HEDGEWARS_REVISION "0000")
+ set(HEDGEWARS_HASH "unknown")
+ endif()
+endif()
+
+
diff -Nru hedgewars-0.9.19.3/cmake_modules/utils.cmake hedgewars-0.9.20.5/cmake_modules/utils.cmake
--- hedgewars-0.9.19.3/cmake_modules/utils.cmake 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/cmake_modules/utils.cmake 2013-10-31 20:21:51.000000000 +0000
@@ -1,4 +1,5 @@
+#find package helpers
macro(find_package_or_fail _PKG_NAME)
find_package(${_PKG_NAME})
string(TOUPPER ${_PKG_NAME} _PKG_NAME_UP)
@@ -11,7 +12,7 @@
find_package(${_PKG_NAME})
string(TOUPPER ${_PKG_NAME} _PKG_NAME_UP)
if(NOT ${_PKG_NAME_UP}_FOUND)
- message(SEND_ERROR "Missing ${_PKG_NAME}! Rerun cmake with -D${_VAR_NAME}=1 to build without it.")
+ message(SEND_ERROR "Missing ${_PKG_NAME}! Rerun cmake with -D${_VAR_NAME}=1 to skip this error.")
endif(NOT ${_PKG_NAME_UP}_FOUND)
endmacro(find_package_or_disable _PKG_NAME _VAR_NAME)
@@ -25,6 +26,28 @@
endif(NOT ${_VAR_NAME})
endmacro(find_package_or_disable_msg _PKG_NAME _VAR_NAME _MSG)
+#variable manipulation macros
+macro(add_flag_append _VAR_NAME _FLAG)
+ set(${_VAR_NAME} "${${_VAR_NAME}} ${_FLAG}")
+endmacro(add_flag_append _VAR_NAME _FLAG)
+
+macro(add_flag_prepend _VAR_NAME _FLAG)
+ set(${_VAR_NAME} "${_FLAG} ${${_VAR_NAME}}")
+endmacro(add_flag_prepend _VAR_NAME _FLAG)
+
+macro(add_linker_flag _FLAG)
+ list(APPEND haskell_flags "-optl" "-Wl,${_FLAG}")
+ #executables
+ add_flag_append(CMAKE_C_LINK_FLAGS "-Wl,${_FLAG}")
+ add_flag_append(CMAKE_CXX_LINK_FLAGS "-Wl,${_FLAG}")
+ add_flag_append(CMAKE_Pascal_LINK_FLAGS "-k${_FLAG}")
+ #libraries
+ add_flag_append(CMAKE_SHARED_LIBRARY_C_FLAGS "-Wl,${_FLAG}")
+ add_flag_append(CMAKE_SHARED_LIBRARY_CXX_FLAGS "-Wl,${_FLAG}")
+ #CMAKE_SHARED_LIBRARY_Pascal_FLAGS is already set by CMAKE_Pascal_LINK_FLAGS
+endmacro(add_linker_flag _FLAG)
#TODO: find_package_or_bundle
+
+
diff -Nru hedgewars-0.9.19.3/debian/changelog hedgewars-0.9.20.5/debian/changelog
--- hedgewars-0.9.19.3/debian/changelog 2013-06-21 15:56:13.000000000 +0000
+++ hedgewars-0.9.20.5/debian/changelog 2014-01-10 17:17:27.000000000 +0000
@@ -1,8 +1,74 @@
-hedgewars (0.9.19.3-1~ubuntu12.10.1) quantal-backports; urgency=low
+hedgewars (0.9.20.5-1~ubuntu12.10.1) quantal-backports; urgency=low
- * No-change backport to quantal (LP: #1191816)
+ * No-change backport to quantal (LP: #1267563)
- -- Felix Geyer Fri, 21 Jun 2013 17:56:13 +0200
+ -- Felix Geyer Fri, 10 Jan 2014 18:17:27 +0100
+
+hedgewars (0.9.20.5-1) unstable; urgency=low
+
+ * New upstream tarball, upload to unstable
+ * Simplified debian/rules, by removing override_dh_install
+ * debian/control, reorganized and dropped some useless build-deps
+ taken from upstream wiki build page
+
+ -- Gianfranco Costamagna Sat, 04 Jan 2014 17:53:27 +0100
+
+hedgewars (0.9.20.3-2) experimental; urgency=low
+
+ * Removed fPIC support on fpc, fixing build failures
+ in arm* and sparc platforms
+
+ -- Gianfranco Costamagna Fri, 03 Jan 2014 01:32:36 +0100
+
+hedgewars (0.9.20.3-1) unstable; urgency=low
+
+ * New upstream minor release, suitable for unstable
+
+ -- Gianfranco Costamagna Thu, 02 Jan 2014 12:37:23 +0100
+
+hedgewars (0.9.20-2) experimental; urgency=low
+
+ * Building without parallel support
+
+ -- Gianfranco Costamagna Sun, 29 Dec 2013 14:02:19 +0100
+
+hedgewars (0.9.20-1) experimental; urgency=low
+
+ * New upstream release (lp: #1264606)
+ - new Mission Campaign: A Space Adventure!
+ (thanks to Master_ex for working on it!)
+ - Shapes on drawn maps
+ - New rubber utility
+ - A polished Graphical user interface
+ - AFK mode. (Press p when not your turn online
+ to trigger autoskip of your turn.)
+ - Visual enhancements for whip and crosshair
+ - New hats
+ - New voice pack (Russian)
+ - Map edges can wrap or bounce.
+ - Password protected rooms
+ - Translation updates
+ - Many, many, many bugfixes.
+ - And much more (see ChangeLog.txt)
+ * Switch to debhelper
+
+ -- Gianfranco Costamagna Sat, 28 Dec 2013 09:10:41 +0100
+
+hedgewars (0.9.19.3-2) experimental; urgency=low
+
+ * Upload to experimental
+ * debian/rules
+ - no linking of libgcc_s.so.1 is needed anymore
+ - simplified some target
+ * debian/control
+ - Bumped standard version to 3.9.5, no changes required.
+ - moved libpng12-dev to libpng-dev.
+ - VCS-Git and VCS-Browser are now in a canonical form
+ - extended hedgewars-data description
+ * debian/copyright
+ - fixed copyright symbol usage
+
+ -- Gianfranco Costamagna Thu, 27 Jun 2013 15:59:59 +0200
hedgewars (0.9.19.3-1) unstable; urgency=low
diff -Nru hedgewars-0.9.19.3/debian/control hedgewars-0.9.20.5/debian/control
--- hedgewars-0.9.19.3/debian/control 2013-06-11 08:53:27.000000000 +0000
+++ hedgewars-0.9.20.5/debian/control 2014-01-09 10:47:47.000000000 +0000
@@ -4,40 +4,36 @@
Maintainer: Debian Games Team
Uploaders: Dmitry E. Oboukhov ,
Gianfranco Costamagna
-Build-Depends: debhelper (>= 9), cmake, cdbs, dpkg-dev (>= 1.16.1~),
- libqt4-dev (>= 4.2),
- fp-compiler,
+Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~),
+ cmake,
+ qt4-qmake,
+ libqt4-dev,
libsdl1.2-dev,
- libsdl-ttf2.0-dev,
+ libsdl-net1.2-dev,
libsdl-mixer1.2-dev,
libsdl-image1.2-dev,
- libsdl-net1.2-dev,
- bzip2,
- fp-units-gfx,
- ghc,
- libghc-stm-dev,
- libghc-network-dev,
- libghc-dataenc-dev,
- libghc-hslogger-dev,
- libghc-utf8-string-dev,
+ libsdl-ttf2.0-dev,
liblua5.1-dev,
- imagemagick,
- libghc-bytestring-show-dev,
fpc,
libpng12-dev,
libavcodec-dev,
libavformat-dev,
freeglut3-dev,
+ ghc,
+ libghc-bytestring-show-dev,
+ libghc-dataenc-dev,
+ libghc-hslogger-dev,
libghc-mtl-dev,
+ libghc-network-dev,
libghc-parsec3-dev,
+ libghc-utf8-string-dev,
libghc-vector-dev,
- qt4-qmake,
- fp-units-misc,
- libghc-random-dev
-Standards-Version: 3.9.4
+ libghc-random-dev,
+ imagemagick
+Standards-Version: 3.9.5
Homepage: http://hedgewars.org
-VCS-Browser: http://git.debian.org/?p=collab-maint/hedgewars.git;a=summary
-VCS-Git: git://git.debian.org/collab-maint/hedgewars.git
+VCS-Git: git://anonscm.debian.org/pkg-games/hedgewars.git
+VCS-Browser: http://anonscm.debian.org/gitweb/?p=pkg-games/hedgewars.git
Package: hedgewars
Architecture: any
@@ -73,11 +69,10 @@
shown only when all movement on the battlefield has ceased).
Package: hedgewars-data
-Conflicts: hedgewars (<= 0.8.1-10)
-Replaces: hedgewars (<= 0.8.1-10)
Architecture: all
Depends: ${misc:Depends}
Recommends: hedgewars
Description: Data files for hedgewars
- This package contains data files (images, sounds, levels data)
- for the hedgewars package.
+ This package contains data files for the hedgewars package.
+ Examples of files are: maps, scripts, themes, images, sounds,
+ level data and other miscellaneous files needed by hedgewars.
diff -Nru hedgewars-0.9.19.3/debian/copyright hedgewars-0.9.20.5/debian/copyright
--- hedgewars-0.9.19.3/debian/copyright 2013-06-11 08:53:27.000000000 +0000
+++ hedgewars-0.9.20.5/debian/copyright 2014-01-09 08:38:00.000000000 +0000
@@ -52,12 +52,12 @@
Public License can be found in `/usr/share/common-licenses/GPL-2'.
Data/Fonts/DroidSansFallback.ttf:
- Google Droid are (c) The Android Open Source Project under the
+ Google Droid are © The Android Open Source Project under the
terms of the Apache license (2.0). Google Droid changes are in
public domain.
On Debian systems, the complete text of the Apache License version 2.0
can be found in `/usr/share/common-licenses/Apache-2.0'.
-The Debian packaging is (C) 2006, Dmitry E. Oboukhov and
+The Debian packaging is © 2006, Dmitry E. Oboukhov and
is licensed under the GPL, see `/usr/share/common-licenses/GPL-2'.
diff -Nru hedgewars-0.9.19.3/debian/hedgewars-data.install hedgewars-0.9.20.5/debian/hedgewars-data.install
--- hedgewars-0.9.19.3/debian/hedgewars-data.install 2013-06-11 08:53:27.000000000 +0000
+++ hedgewars-0.9.20.5/debian/hedgewars-data.install 2014-01-09 08:38:00.000000000 +0000
@@ -1 +1 @@
-debian/tmp/usr/share/games/hedgewars /usr/share/games/
+usr/share/games/hedgewars /usr/share/games/
diff -Nru hedgewars-0.9.19.3/debian/hedgewars.install hedgewars-0.9.20.5/debian/hedgewars.install
--- hedgewars-0.9.19.3/debian/hedgewars.install 2013-06-11 08:53:27.000000000 +0000
+++ hedgewars-0.9.20.5/debian/hedgewars.install 2014-01-09 08:38:00.000000000 +0000
@@ -1,4 +1,4 @@
-debian/tmp/usr/lib/* /usr/lib/
-obj-*/share/hedgewars/Data/misc/hwengine.desktop /usr/share/games/hedgewars/Data/misc
-debian/tmp/usr/share/games/hedgewars/Data/misc/hedgewars.desktop /usr/share/applications/
-tmp-icon/* /usr/share/icons/hicolor/
+usr/lib
+obj-*/share/hedgewars/Data/misc/hwengine.desktop /usr/share/games/hedgewars/Data/misc
+share/hedgewars/Data/misc/hedgewars.desktop /usr/share/applications/
+tmp-icon/* /usr/share/icons/hicolor/
diff -Nru hedgewars-0.9.19.3/debian/rules hedgewars-0.9.20.5/debian/rules
--- hedgewars-0.9.19.3/debian/rules 2013-06-11 08:53:27.000000000 +0000
+++ hedgewars-0.9.20.5/debian/rules 2014-01-09 08:38:00.000000000 +0000
@@ -1,32 +1,9 @@
#!/usr/bin/make -f
-include /usr/share/cdbs/1/rules/debhelper.mk
-include /usr/share/cdbs/1/class/cmake.mk
-DPKG_EXPORT_BUILDFLAGS = 1
-include /usr/share/dpkg/buildflags.mk
-CFLAGS+=$(CPPFLAGS)
-CXXFLAGS+=$(CPPFLAGS)
+%:
+ dh $@
-DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
-#Helping libc >= 2.17, see launchpad bug #1179850
-TYPE_FLAGS = -DFPFLAGS="-k/lib/$(DEB_HOST_MULTIARCH)/libgcc_s.so.1"
-
-DEB_CMAKE_INSTALL_PREFIX := /usr/lib/hedgewars
-DEB_CMAKE_EXTRA_FLAGS := -DNOSERVER=0 \
- -DDATA_INSTALL_DIR=/usr/share/games/hedgewars $(TYPE_FLAGS)
-
-UPSTREAM_VERSION := $(shell dpkg-parsechangelog \
- |grep ^Version|awk '{print $$2}'|sed 's/-[[:digit:]]\+$$//' \
-)
-
-clean::
- rm -fr tmp-icon stamp-icon
-
-pre-build:: stamp-icon
-
-stamp-icon:
- rm -fr tmp-icon
- mkdir -p tmp-icon
+override_dh_auto_configure:
for icon in `find debian/hicolor-icons -type f`; do \
dirname=`dirname $$icon`; \
dirname=`basename $$dirname`; \
@@ -34,11 +11,10 @@
mkdir -p tmp-icon/$$dirname/apps; \
convert $$icon tmp-icon/$$dirname/apps/$$basename.png; \
done
-
-tarball:
- cd .. && \
- tar --exclude=debian \
- --exclude=.git \
- -czf hedgewars_$(UPSTREAM_VERSION).orig.tar.gz \
- hedgewars-$(UPSTREAM_VERSION)
-
+ dh_auto_configure -- -DCMAKE_INSTALL_PREFIX=/usr/lib/hedgewars \
+ -DDATA_INSTALL_DIR=/usr/share/games/hedgewars \
+ -DCMAKE_BUILD_TYPE=RELEASE
+
+override_dh_clean:
+ rm -rf tmp-icon
+ dh_clean
diff -Nru hedgewars-0.9.19.3/gameServer/Actions.hs hedgewars-0.9.20.5/gameServer/Actions.hs
--- hedgewars-0.9.19.3/gameServer/Actions.hs 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/Actions.hs 2014-01-08 16:25:17.000000000 +0000
@@ -17,10 +17,11 @@
import Control.DeepSeq
import Data.Unique
import Control.Arrow
-import Control.Exception
+import Control.Exception as E
import System.Process
import Network.Socket
import System.Random
+import qualified Data.Traversable as DT
-----------------------------
#if defined(OFFICIAL_SERVER)
import OfficialServer.GameReplayStore
@@ -162,14 +163,24 @@
rnc <- gets roomsClients
io $ do
- modifyClient rnc (\cl -> cl{teamsInGame = 0, isReady = False, isMaster = False, isInGame = False, clientClan = Nothing}) ci
+ modifyClient rnc (
+ \cl -> cl{teamsInGame = 0
+ , isReady = False
+ , isMaster = False
+ , isInGame = False
+ , isJoinedMidGame = False
+ , clientClan = Nothing}) ci
modifyRoom rnc (\r -> r{playersIn = playersIn r + 1}) ri
moveClientToRoom rnc ri ci
chans <- liftM (map sendChan) $ roomClientsS ri
clNick <- client's nick
+ allClientsChans <- liftM (Prelude.map sendChan . Prelude.filter isVisible) $! allClientsS
- processAction $ AnswerClients chans ["JOINED", clNick]
+ mapM_ processAction [
+ AnswerClients chans ["JOINED", clNick]
+ , AnswerClients allClientsChans ["CLIENT_FLAGS", "+i", clNick]
+ ]
processAction (MoveToLobby msg) = do
@@ -177,22 +188,26 @@
ri <- clientRoomA
rnc <- gets roomsClients
playersNum <- io $ room'sM rnc playersIn ri
+ specialRoom <- io $ room'sM rnc isSpecial ri
master <- client's isMaster
-- client <- client's id
clNick <- client's nick
chans <- othersChans
if master then
- if playersNum > 1 then
+ if (playersNum > 1) || specialRoom then
mapM_ processAction [ChangeMaster Nothing, NoticeMessage AdminLeft, RemoveClientTeams, AnswerClients chans ["LEFT", clNick, msg]]
else
processAction RemoveRoom
else
mapM_ processAction [RemoveClientTeams, AnswerClients chans ["LEFT", clNick, msg]]
+ allClientsChans <- liftM (Prelude.map sendChan . Prelude.filter isVisible) $! allClientsS
+ processAction $ AnswerClients allClientsChans ["CLIENT_FLAGS", "-i", clNick]
+
-- when not removing room
ready <- client's isReady
- when (not master || playersNum > 1) . io $ do
+ when (not master || playersNum > 1 || specialRoom) . io $ do
modifyRoom rnc (\r -> r{
playersIn = playersIn r - 1,
readyPlayers = if ready then readyPlayers r - 1 else readyPlayers r
@@ -205,31 +220,40 @@
proto <- client's clientProto
ri <- clientRoomA
rnc <- gets roomsClients
- newMasterId <- liftM (\ids -> fromMaybe (last . filter (/= ci) $ ids) delegateId) . io $ roomClientsIndicesM rnc ri
- newMaster <- io $ client'sM rnc id newMasterId
+ specialRoom <- io $ room'sM rnc isSpecial ri
+ newMasterId <- liftM (\ids -> fromMaybe (listToMaybe . reverse . filter (/= ci) $ ids) $ liftM Just delegateId) . io $ roomClientsIndicesM rnc ri
+ newMaster <- io $ client'sM rnc id `DT.mapM` newMasterId
oldMasterId <- io $ room'sM rnc masterID ri
- oldMaster <- io $ client'sM rnc id oldMasterId
oldRoomName <- io $ room'sM rnc name ri
kicked <- client's isKickedFromServer
thisRoomChans <- liftM (map sendChan) $ roomClientsS ri
- let newRoomName = if (proto < 42) || kicked then nick newMaster else oldRoomName
- mapM_ processAction [
+ let newRoomName = if ((proto < 42) || kicked) && (not specialRoom) then maybeNick newMaster else oldRoomName
+
+ when (isJust oldMasterId) $ do
+ oldMasterNick <- io $ client'sM rnc nick (fromJust oldMasterId)
+ mapM_ processAction [
+ ModifyClient2 (fromJust oldMasterId) (\c -> c{isMaster = False})
+ , AnswerClients thisRoomChans ["CLIENT_FLAGS", "-h", oldMasterNick]
+ ]
+
+ when (isJust newMasterId) $
+ mapM_ processAction [
+ ModifyClient2 (fromJust newMasterId) (\c -> c{isMaster = True})
+ , AnswerClients [sendChan $ fromJust newMaster] ["ROOM_CONTROL_ACCESS", "1"]
+ , AnswerClients thisRoomChans ["CLIENT_FLAGS", "+h", nick $ fromJust newMaster]
+ ]
+
+ processAction $
ModifyRoom (\r -> r{masterID = newMasterId
, name = newRoomName
, isRestrictedJoins = False
, isRestrictedTeams = False
- , isRegisteredOnly = False}
+ , isRegisteredOnly = isSpecial r}
)
- , ModifyClient2 newMasterId (\c -> c{isMaster = True})
- , ModifyClient2 oldMasterId (\c -> c{isMaster = False})
- , AnswerClients [sendChan newMaster] ["ROOM_CONTROL_ACCESS", "1"]
- , AnswerClients thisRoomChans ["CLIENT_FLAGS", "-h", nick oldMaster]
- , AnswerClients thisRoomChans ["CLIENT_FLAGS", "+h", nick newMaster]
- ]
newRoom' <- io $ room'sM rnc id ri
chans <- liftM (map sendChan) $! sameProtoClientsS proto
- processAction $ AnswerClients chans ("ROOM" : "UPD" : oldRoomName : roomInfo (nick newMaster) newRoom')
+ processAction $ AnswerClients chans ("ROOM" : "UPD" : oldRoomName : roomInfo proto (maybeNick newMaster) newRoom')
processAction (AddRoom roomName roomPassword) = do
@@ -239,7 +263,7 @@
n <- client's nick
let rm = newRoom{
- masterID = clId,
+ masterID = Just clId,
name = roomName,
password = roomPassword,
roomProto = proto
@@ -252,7 +276,7 @@
chans <- liftM (map sendChan) $! sameProtoClientsS proto
mapM_ processAction [
- AnswerClients chans ("ROOM" : "ADD" : roomInfo n rm{playersIn = 1})
+ AnswerClients chans ("ROOM" : "ADD" : roomInfo proto n rm{playersIn = 1})
]
@@ -279,9 +303,9 @@
rnc <- gets roomsClients
ri <- io $ clientRoomM rnc clId
rm <- io $ room'sM rnc id ri
- n <- io $ client'sM rnc nick (masterID rm)
+ masterCl <- io $ client'sM rnc id `DT.mapM` (masterID rm)
chans <- liftM (map sendChan) $! sameProtoClientsS proto
- processAction $ AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo n rm)
+ processAction $ AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo proto (maybeNick masterCl) rm)
processAction UnreadyRoomClients = do
@@ -290,7 +314,7 @@
pr <- client's clientProto
mapM_ processAction [
AnswerClients (map sendChan roomPlayers) $ notReadyMessage pr . map nick . filter (not . isMaster) $ roomPlayers
- , ModifyRoomClients (\cl -> cl{isReady = isMaster cl})
+ , ModifyRoomClients (\cl -> cl{isReady = isMaster cl, isJoinedMidGame = False})
, ModifyRoom (\r -> r{readyPlayers = 1})
]
where
@@ -301,10 +325,17 @@
rnc <- gets roomsClients
ri <- clientRoomA
thisRoomChans <- liftM (map sendChan) $ roomClientsS ri
+ joinedMidGame <- liftM (filter isJoinedMidGame) $ roomClientsS ri
answerRemovedTeams <- io $
- room'sM rnc (map (\t -> AnswerClients thisRoomChans ["REMOVE_TEAM", t]) . leftTeams . fromJust . gameInfo) ri
+ room'sM rnc (\r -> let gi = fromJust $ gameInfo r in
+ concatMap (\c ->
+ (answerFullConfigParams c (mapParams r) (params r))
+ ++
+ (map (\t -> AnswerClients [sendChan c] ["REMOVE_TEAM", t]) $ leftTeams gi)
+ ) joinedMidGame
+ ) ri
- mapM_ processAction $
+ mapM_ processAction $ (
SaveReplay
: ModifyRoom
(\r -> r{
@@ -312,10 +343,11 @@
readyPlayers = 0
}
)
- : UnreadyRoomClients
: SendUpdateOnThisRoom
: AnswerClients thisRoomChans ["ROUND_FINISHED"]
: answerRemovedTeams
+ )
+ ++ [UnreadyRoomClients]
processAction (SendTeamRemovalMessage teamName) = do
@@ -325,7 +357,8 @@
ModifyRoom (\r -> r{
gameInfo = liftM (\g -> g{
teamsInGameNumber = teamsInGameNumber g - 1
- , roundMsgs = rmTeamMsg : roundMsgs g
+ , roundMsgs = (if isJust $ lastFilteredTimedMsg g then (:) (fromJust $ lastFilteredTimedMsg g) else id)
+ $ rmTeamMsg : roundMsgs g
}) $ gameInfo r
})
]
@@ -399,50 +432,61 @@
processAction (ProcessAccountInfo info) = do
case info of
- HasAccount passwd isAdmin -> do
+ HasAccount passwd isAdmin isContr -> do
b <- isBanned
c <- client's isChecker
- when (not b) $ (if c then checkerLogin else playerLogin) passwd isAdmin
+ when (not b) $ (if c then checkerLogin else playerLogin) passwd isAdmin isContr
Guest -> do
b <- isBanned
c <- client's isChecker
when (not b) $
if c then
- checkerLogin "" False
+ checkerLogin "" False False
else
processAction JoinLobby
- Admin -> do
+ Admin ->
mapM_ processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby]
- chan <- client's sendChan
- processAction $ AnswerClients [chan] ["ADMIN_ACCESS"]
+ ReplayName fn -> processAction $ ShowReplay fn
where
isBanned = do
processAction $ CheckBanned False
liftM B.null $ client's nick
- checkerLogin _ False = processAction $ ByeClient $ loc "No checker rights"
- checkerLogin p True = do
+ 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
+ playerLogin p a contr = do
chan <- client's sendChan
- mapM_ processAction [AnswerClients [chan] ["ASKPASSWORD"], ModifyClient (\c -> c{webPassword = p, isAdministrator = a})]
+ mapM_ processAction [
+ AnswerClients [chan] ["ASKPASSWORD"]
+ , ModifyClient (\c -> c{webPassword = p, isAdministrator = a, isContributor = contr})
+ ]
processAction JoinLobby = do
chan <- client's sendChan
+ rnc <- gets roomsClients
clientNick <- client's nick
isAuthenticated <- liftM (not . B.null) $ client's webPassword
isAdmin <- client's isAdministrator
+ isContr <- client's isContributor
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
- let clFlags = B.concat . L.concat $ [["u" | isAuthenticated], ["a" | isAdmin]]
+ let contrNicks = L.map nick . L.filter isContributor $ loggedInClients
+ inRoomNicks <- io $
+ allClientsM rnc
+ >>= filterM (liftM ((/=) lobbyId) . clientRoomM rnc)
+ >>= mapM (client'sM rnc nick)
+ let clFlags = B.concat . L.concat $ [["u" | isAuthenticated], ["a" | isAdmin], ["c" | isContr]]
mapM_ processAction . concat $ [
[AnswerClients clientsChans ["LOBBY:JOINED", clientNick]]
, [AnswerClients [chan] ("LOBBY:JOINED" : clientNick : lobbyNicks)]
, [AnswerClients [chan] ("CLIENT_FLAGS" : "+u" : authenticatedNicks) | not $ null authenticatedNicks]
, [AnswerClients [chan] ("CLIENT_FLAGS" : "+a" : adminsNicks) | not $ null adminsNicks]
+ , [AnswerClients [chan] ("CLIENT_FLAGS" : "+c" : contrNicks) | not $ null contrNicks]
+ , [AnswerClients [chan] ("CLIENT_FLAGS" : "+i" : inRoomNicks) | not $ null inRoomNicks]
, [AnswerClients (chan : clientsChans) ["CLIENT_FLAGS", B.concat["+" , clFlags], clientNick] | not $ B.null clFlags]
, [ModifyClient (\cl -> cl{logonPassed = True, isVisible = True})]
, [SendServerMessage]
@@ -589,6 +633,7 @@
where
st irnc = (length $ allRooms irnc, length $ allClients irnc)
+
processAction RestartServer = do
sp <- gets (shutdownPending . serverInfo)
when (not sp) $ do
@@ -602,6 +647,7 @@
return ()
processAction $ ModifyServerInfo (\s -> s{shutdownPending = True})
+
processAction Stats = do
cls <- allClientsS
rms <- allRoomsS
@@ -629,32 +675,88 @@
ri <- clientRoomA
rnc <- gets roomsClients
- io $ do
+ readyCheckersIds <- io $ do
r <- room'sM rnc id ri
saveReplay r
+ allci <- allClientsM rnc
+ filterM (client'sM rnc isReadyChecker) allci
+
+ when (not $ null readyCheckersIds) $ do
+ oldci <- gets clientIndex
+ withStateT (\s -> s{clientIndex = Just $ head readyCheckersIds})
+ $ processAction CheckRecord
+ modify (\s -> s{clientIndex = oldci})
+ where
+ isReadyChecker cl = isChecker cl && isReady cl
processAction CheckRecord = do
p <- client's clientProto
c <- client's sendChan
- (cinfo, l) <- io $ loadReplay (fromIntegral p)
+ ri <- clientRoomA
+ rnc <- gets roomsClients
+
+ blackList <- liftM (map (recordFileName . fromJust . checkInfo) . filter (isJust . checkInfo)) allClientsS
+
+ readyCheckersIds <- io $ do
+ allci <- allClientsM rnc
+ filterM (client'sM rnc (isJust . checkInfo)) allci
+
+ (cinfo, l) <- io $ loadReplay (fromIntegral p) blackList
when (not . null $ l) $
mapM_ processAction [
AnswerClients [c] ("REPLAY" : l)
- , ModifyClient $ \c -> c{checkInfo = cinfo}
+ , ModifyClient $ \c -> c{checkInfo = cinfo, isReady = False}
]
+
processAction (CheckFailed msg) = do
Just (CheckInfo fileName _) <- client's checkInfo
io $ moveFailedRecord fileName
+
processAction (CheckSuccess info) = do
- Just (CheckInfo fileName _) <- client's checkInfo
+ Just (CheckInfo fileName teams) <- client's checkInfo
+ p <- client's clientProto
+ si <- gets serverInfo
+ io $ writeChan (dbQueries si) $ StoreAchievements p (B.pack fileName) (map toPair teams) info
io $ moveCheckedRecord fileName
+ where
+ toPair t = (teamname t, teamowner t)
+
+processAction (QueryReplay rname) = do
+ (Just ci) <- gets clientIndex
+ si <- gets serverInfo
+ uid <- client's clUID
+ io $ writeChan (dbQueries si) $ GetReplayName ci (hashUnique uid) rname
#else
processAction SaveReplay = return ()
processAction CheckRecord = return ()
processAction (CheckFailed _) = return ()
processAction (CheckSuccess _) = return ()
+processAction (QueryReplay _) = return ()
#endif
+
+processAction (ShowReplay rname) = do
+ c <- client's sendChan
+ cl <- client's id
+
+ let fileName = B.concat ["checked/", if B.isPrefixOf "replays/" rname then B.drop 8 rname else rname]
+
+ cInfo <- liftIO $ E.handle (\(e :: SomeException) ->
+ warningM "REPLAYS" (B.unpack $ B.concat ["Problems reading ", fileName, ": ", B.pack $ show e]) >> return Nothing) $ do
+ (t, p1, p2, msgs) <- liftM read $ readFile (B.unpack fileName)
+ return $ Just (t, Map.fromList p1, Map.fromList p2, reverse msgs)
+
+ let (teams', params1, params2, roundMsgs') = fromJust cInfo
+
+ when (isJust cInfo) $ do
+ mapM_ processAction $ concat [
+ [AnswerClients [c] ["JOINED", nick cl]]
+ , answerFullConfigParams cl params1 params2
+ , answerAllTeams cl teams'
+ , [AnswerClients [c] ["RUN_GAME"]]
+ , [AnswerClients [c] $ "EM" : roundMsgs']
+ , [AnswerClients [c] ["KICKED"]]
+ ]
diff -Nru hedgewars-0.9.19.3/gameServer/Consts.hs hedgewars-0.9.20.5/gameServer/Consts.hs
--- hedgewars-0.9.19.3/gameServer/Consts.hs 2012-12-19 16:09:06.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/Consts.hs 2013-11-18 07:03:07.000000000 +0000
@@ -4,4 +4,4 @@
import qualified Data.ByteString.Char8 as B
serverVersion :: B.ByteString
-serverVersion = "1"
+serverVersion = "2"
diff -Nru hedgewars-0.9.19.3/gameServer/CoreTypes.hs hedgewars-0.9.20.5/gameServer/CoreTypes.hs
--- hedgewars-0.9.19.3/gameServer/CoreTypes.hs 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/CoreTypes.hs 2014-01-04 19:46:00.000000000 +0000
@@ -76,6 +76,8 @@
| CheckFailed B.ByteString
| CheckSuccess [B.ByteString]
| Random [ClientChan] [B.ByteString]
+ | QueryReplay B.ByteString
+ | ShowReplay B.ByteString
type ClientChan = Chan [B.ByteString]
@@ -99,14 +101,15 @@
logonPassed :: Bool,
isVisible :: Bool,
clientProto :: !Word16,
- roomID :: RoomIndex,
pingsQueue :: !Word,
isMaster :: Bool,
isReady :: !Bool,
isInGame :: Bool,
isAdministrator :: Bool,
isChecker :: Bool,
+ isContributor :: Bool,
isKickedFromServer :: Bool,
+ isJoinedMidGame :: Bool,
clientClan :: !(Maybe B.ByteString),
checkInfo :: Maybe CheckInfo,
teamsInGame :: Word
@@ -143,6 +146,7 @@
GameInfo
{
roundMsgs :: [B.ByteString],
+ lastFilteredTimedMsg :: Maybe B.ByteString,
leftTeams :: [B.ByteString],
teamsAtStart :: [TeamInfo],
teamsInGameNumber :: Int,
@@ -160,12 +164,13 @@
newGameInfo =
GameInfo
[]
+ Nothing
[]
data RoomInfo =
RoomInfo
{
- masterID :: ClientIndex,
+ masterID :: Maybe ClientIndex,
name :: B.ByteString,
password :: B.ByteString,
roomProto :: Word16,
@@ -176,6 +181,8 @@
isRestrictedJoins :: Bool,
isRestrictedTeams :: Bool,
isRegisteredOnly :: Bool,
+ isSpecial :: Bool,
+ greeting :: B.ByteString,
roomBansList :: ![B.ByteString],
mapParams :: Map.Map B.ByteString B.ByteString,
params :: Map.Map B.ByteString [B.ByteString]
@@ -184,7 +191,7 @@
newRoom :: RoomInfo
newRoom =
RoomInfo
- (error "No room master defined")
+ Nothing
""
""
0
@@ -195,13 +202,20 @@
False
False
False
+ False
+ ""
[]
(
- Map.fromList $ Prelude.zipWith (,)
+ Map.fromList $ Prelude.zip
["MAP", "MAPGEN", "MAZE_SIZE", "SEED", "TEMPLATE"]
["+rnd+", "0", "0", "seed", "0"]
)
- (Map.singleton "SCHEME" ["Default"])
+ (
+ Map.fromList $ Prelude.zip
+ ["SCHEME", "SCRIPT"]
+ [["Default"], ["Normal"]]
+ )
+
data StatisticsInfo =
StatisticsInfo
@@ -239,7 +253,7 @@
True
"http://www.hedgewars.org/
"
"Hedgewars 0.9.19 is out! Please update. Download page here
"
- 45 -- latestReleaseVersion
+ 47 -- latestReleaseVersion
41 -- earliestCompatibleVersion
46631
""
@@ -251,15 +265,18 @@
[]
data AccountInfo =
- HasAccount B.ByteString Bool
+ HasAccount B.ByteString Bool Bool
| Guest
| Admin
+ | ReplayName B.ByteString
deriving (Show, Read)
data DBQuery =
CheckAccount ClientIndex Int B.ByteString B.ByteString
| ClearCache
| SendStats Int Int
+ | StoreAchievements Word16 B.ByteString [(B.ByteString, B.ByteString)] [B.ByteString]
+ | GetReplayName ClientIndex Int B.ByteString
deriving (Show, Read)
data CoreMessage =
diff -Nru hedgewars-0.9.19.3/gameServer/EngineInteraction.hs hedgewars-0.9.20.5/gameServer/EngineInteraction.hs
--- hedgewars-0.9.19.3/gameServer/EngineInteraction.hs 2013-06-03 08:01:41.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/EngineInteraction.hs 2013-11-18 07:03:07.000000000 +0000
@@ -12,6 +12,7 @@
import Data.Word
import Data.Bits
import Control.Arrow
+import Data.Maybe
-------------
import CoreTypes
import Utils
@@ -32,17 +33,22 @@
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 :: B.ByteString -> (B.ByteString, B.ByteString, Maybe (Maybe B.ByteString))
checkNetCmd msg = check decoded
where
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)
+ check Nothing = (B.empty, B.empty, Nothing)
+ check (Just msgs) = let (a, b) = (filter isLegal msgs, filter isNonEmpty a) in (encode a, encode b, lft a)
encode = B.pack . Base64.encode . BW.unpack . B.concat
isLegal m = (B.length m > 1) && (flip Set.member legalMessages . B.head . B.tail $ m)
+ lft = foldr l Nothing
+ l m n = let m' = B.head $ B.tail m; tst = flip Set.member in
+ if not $ tst timedMessages m' then n
+ else if '+' /= m' then Just Nothing else Just . Just . B.pack . Base64.encode . BW.unpack $ 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"
+ timedMessages = Set.fromList $ "+LlRrUuDdZzAaSjJ,NpPwtgc12345" ++ slotMessages
replayToDemo :: [TeamInfo]
@@ -50,18 +56,18 @@
-> Map.Map B.ByteString [B.ByteString]
-> [B.ByteString]
-> [B.ByteString]
-replayToDemo teams mapParams params msgs = concat [
+replayToDemo ti mParams prms msgs = concat [
[em "TD"]
, maybeScript
, maybeMap
- , [eml ["etheme ", head $ params Map.! "THEME"]]
- , [eml ["eseed ", mapParams Map.! "SEED"]]
+ , [eml ["etheme ", head $ prms Map.! "THEME"]]
+ , [eml ["eseed ", mParams Map.! "SEED"]]
, [eml ["e$gmflags ", showB gameFlags]]
, schemeFlags
- , [eml ["e$template_filter ", mapParams Map.! "TEMPLATE"]]
+ , [eml ["e$template_filter ", mParams Map.! "TEMPLATE"]]
, [eml ["e$mapgen ", mapgen]]
, mapgenSpecific
- , concatMap teamSetup teams
+ , concatMap teamSetup ti
, msgs
, [em "!"]
]
@@ -69,13 +75,13 @@
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"
+ maybeScript = let s = head . fromMaybe ["Normal"] $ Map.lookup "SCRIPT" prms in if s == "Normal" then [] else [eml ["escript Scripts/Multiplayer/", s, ".lua"]]
+ maybeMap = let m = mParams Map.! "MAP" in if m `elem` mapGenTypes then [] else [eml ["emap ", m]]
+ scheme = tail $ prms Map.! "SCHEME"
+ mapgen = mParams Map.! "MAPGEN"
mapgenSpecific = case mapgen of
- "+maze+" -> [eml ["e$maze_size ", head $ params Map.! "MAZE_SIZE"]]
- "+drawn" -> drawnMapData . head $ params Map.! "DRAWNMAP"
+ "+maze+" -> [eml ["e$maze_size ", head $ prms Map.! "MAZE_SIZE"]]
+ "+drawn" -> drawnMapData . head $ prms Map.! "DRAWNMAP"
_ -> []
gameFlags :: Word32
gameFlags = foldl (\r (b, f) -> if b == "false" then r else r .|. f) 0 $ zip scheme gameFlagConsts
@@ -83,7 +89,7 @@
$ filter (\(_, (n, _)) -> not $ B.null n)
$ zip (drop (length gameFlagConsts) scheme) schemeParams
ammoStr :: B.ByteString
- ammoStr = head . tail $ params Map.! "AMMO"
+ ammoStr = head . tail $ prms 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"]
diff -Nru hedgewars-0.9.19.3/gameServer/HWProtoChecker.hs hedgewars-0.9.20.5/gameServer/HWProtoChecker.hs
--- hedgewars-0.9.19.3/gameServer/HWProtoChecker.hs 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/HWProtoChecker.hs 2013-10-31 20:21:52.000000000 +0000
@@ -1,22 +1,17 @@
{-# 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 ["READY"] = return [ModifyClient $ \c -> c{isReady = True}, CheckRecord]
handleCmd_checker ["CHECKED", "FAIL", msg] = do
isChecking <- liftM (isJust . checkInfo) thisClient
diff -Nru hedgewars-0.9.19.3/gameServer/HWProtoCore.hs hedgewars-0.9.20.5/gameServer/HWProtoCore.hs
--- hedgewars-0.9.19.3/gameServer/HWProtoCore.hs 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/HWProtoCore.hs 2013-12-25 05:19:22.000000000 +0000
@@ -4,7 +4,6 @@
import Control.Monad.Reader
import Data.Maybe
import qualified Data.ByteString.Char8 as B
-import qualified Data.List as L
--------------------------------------
import CoreTypes
import Actions
@@ -34,24 +33,28 @@
else
return [ModifyClient (\c -> c{pingsQueue = pingsQueue c - 1})]
-handleCmd ("CMD" : parameters) =
- let c = concatMap B.words parameters in
- if not $ null c then
- h $ (upperCase . head $ c) : tail c
- else
- return []
+handleCmd ["CMD", parameters] = do
+ let (cmd, plist) = B.break (== ' ') parameters
+ let param = B.dropWhile (== ' ') plist
+ h (upperCase cmd) param
where
- h ["DELEGATE", n] = handleCmd ["DELEGATE", n]
- h ["STATS"] = handleCmd ["STATS"]
- h ("PART":m:ms) = handleCmd ["PART", B.unwords $ m:ms]
- h ("QUIT":m:ms) = handleCmd ["QUIT", B.unwords $ m:ms]
- h ("RND":rs) = handleCmd ("RND":rs)
- h ("GLOBAL":m:ms) = do
+ h "DELEGATE" n | not $ B.null n = handleCmd ["DELEGATE", n]
+ h "STATS" _ = handleCmd ["STATS"]
+ h "PART" m | not $ B.null m = handleCmd ["PART", m]
+ | otherwise = handleCmd ["PART"]
+ h "QUIT" m | not $ B.null m = handleCmd ["QUIT", m]
+ | otherwise = handleCmd ["QUIT"]
+ h "RND" p = handleCmd ("RND" : B.words p)
+ h "GLOBAL" p = do
cl <- thisClient
rnc <- liftM snd ask
let chans = map (sendChan . client rnc) $ allClients rnc
- return [AnswerClients chans ["CHAT", "[global notice]", B.unwords $ m:ms] | isAdministrator cl]
- h c = return [Warning . B.concat . L.intersperse " " $ "Unknown cmd" : c]
+ return [AnswerClients chans ["CHAT", "[global notice]", p] | isAdministrator cl]
+ h "WATCH" f = return [QueryReplay f]
+ h "FIX" _ = handleCmd ["FIX"]
+ h "UNFIX" _ = handleCmd ["UNFIX"]
+ h "GREETING" msg = handleCmd ["GREETING", msg]
+ h c p = return [Warning $ B.concat ["Unknown cmd: /", c, p]]
handleCmd cmd = do
(ci, irnc) <- ask
diff -Nru hedgewars-0.9.19.3/gameServer/HWProtoInRoomState.hs hedgewars-0.9.20.5/gameServer/HWProtoInRoomState.hs
--- hedgewars-0.9.19.3/gameServer/HWProtoInRoomState.hs 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/HWProtoInRoomState.hs 2014-01-08 16:25:17.000000000 +0000
@@ -31,7 +31,11 @@
| otherwise = do
chans <- roomOthersChans
cl <- thisClient
- if isMaster cl then
+ rm <- thisRoom
+
+ if isSpecial rm then
+ return [Warning $ loc "Restricted"]
+ else if isMaster cl then
return [
ModifyRoom f,
AnswerClients chans ("CFG" : paramName : paramStrs)]
@@ -43,6 +47,7 @@
else
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 $ loc "Corrupted hedgehogs info"]
| otherwise = do
@@ -217,11 +222,15 @@
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]
+ : [ModifyRoom (\r -> r{gameInfo = liftM
+ (\g -> g{
+ roundMsgs = if B.null nonEmptyMsgs then roundMsgs g else nonEmptyMsgs : roundMsgs g
+ , lastFilteredTimedMsg = fromMaybe (lastFilteredTimedMsg g) lastFTMsg})
+ $ gameInfo r})]
else
return []
where
- (legalMsgs, nonEmptyMsgs) = checkNetCmd msg
+ (legalMsgs, nonEmptyMsgs, lastFTMsg) = checkNetCmd msg
handleCmd_inRoom ["ROUNDFINISHED", _] = do
@@ -283,11 +292,17 @@
if not $ isMaster cl then
[ProtocolError $ loc "Not room master"]
else
+ if illegalName newName then
+ [Warning $ loc "Illegal room name"]
+ else
+ if isSpecial rm then
+ [Warning $ loc "Restricted"]
+ else
if isJust $ find (\r -> newName == name r) rs then
[Warning $ loc "Room with such name already exists"]
else
[ModifyRoom roomUpdate,
- AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo (nick cl) (roomUpdate rm))]
+ AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo (clientProto cl) (nick cl) (roomUpdate rm))]
where
roomUpdate r = r{name = newName}
@@ -316,6 +331,7 @@
maybeClientId <- clientByNick newAdmin
master <- liftM isMaster thisClient
serverAdmin <- liftM isAdministrator thisClient
+ thisRoomMasterId <- liftM masterID thisRoom
let newAdminId = fromJust maybeClientId
let sameRoom = clientRoom rnc thisClientId == clientRoom rnc newAdminId
return
@@ -323,6 +339,7 @@
(master || serverAdmin)
&& isJust maybeClientId
&& ((newAdminId /= thisClientId) || (serverAdmin && not master))
+ && (Just newAdminId /= thisRoomMasterId)
&& sameRoom]
@@ -353,6 +370,19 @@
s <- roomClientsChans
return [AnswerClients s ["CHAT", n, B.unwords $ "/rnd" : rs], Random s rs]
+handleCmd_inRoom ["FIX"] = do
+ cl <- thisClient
+ return [ModifyRoom (\r -> r{isSpecial = True}) | isAdministrator cl]
+
+handleCmd_inRoom ["UNFIX"] = do
+ cl <- thisClient
+ return [ModifyRoom (\r -> r{isSpecial = False}) | isAdministrator cl]
+
+handleCmd_inRoom ["GREETING", msg] = do
+ cl <- thisClient
+ rm <- thisRoom
+ return [ModifyRoom (\r -> r{greeting = msg}) | isAdministrator cl || (isMaster cl && (not $ isSpecial rm))]
+
handleCmd_inRoom ["LIST"] = return [] -- for old clients (<= 0.9.17)
handleCmd_inRoom (s:_) = return [ProtocolError $ "Incorrect command '" `B.append` s `B.append` "' (state: in room)"]
diff -Nru hedgewars-0.9.19.3/gameServer/HWProtoLobbyState.hs hedgewars-0.9.20.5/gameServer/HWProtoLobbyState.hs
--- hedgewars-0.9.19.3/gameServer/HWProtoLobbyState.hs 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/HWProtoLobbyState.hs 2013-12-25 05:19:22.000000000 +0000
@@ -1,10 +1,10 @@
{-# LANGUAGE OverloadedStrings #-}
module HWProtoLobbyState where
-import qualified Data.Map as Map
import Data.Maybe
import Data.List
import Control.Monad.Reader
+import qualified Data.ByteString.Char8 as B
--------------------------------------
import CoreTypes
import Actions
@@ -14,16 +14,6 @@
import EngineInteraction
-answerAllTeams :: ClientInfo -> [TeamInfo] -> [Action]
-answerAllTeams cl = concatMap toAnswer
- where
- clChan = sendChan cl
- toAnswer team =
- [AnswerClients [clChan] $ teamToNet team,
- AnswerClients [clChan] ["TEAM_COLOR", teamname team, teamcolor team],
- AnswerClients [clChan] ["HH_NUM", teamname team, showB $ hhnum team]]
-
-
handleCmd_lobby :: CmdHandler
@@ -31,10 +21,9 @@
(ci, irnc) <- ask
let cl = irnc `client` ci
rooms <- allRoomInfos
- let roomsInfoList = concatMap (\r -> roomInfo (nick $ irnc `client` masterID r) r) . filter (\r -> (roomProto r == clientProto cl))
+ let roomsInfoList = concatMap (\r -> roomInfo (clientProto cl) (maybeNick . liftM (client irnc) $ masterID r) r) . filter (\r -> (roomProto r == clientProto cl))
return [AnswerClients [sendChan cl] ("ROOMS" : roomsInfoList rooms)]
-
handleCmd_lobby ["CHAT", msg] = do
n <- clientNick
s <- roomOthersChans
@@ -51,7 +40,7 @@
[
AddRoom rName roomPassword
, AnswerClients [sendChan cl] ["CLIENT_FLAGS", "+hr", nick cl]
- , ModifyClient (\c -> c{isMaster = True, isReady = True})
+ , ModifyClient (\c -> c{isMaster = True, isReady = True, isJoinedMidGame = False})
, ModifyRoom (\r -> r{readyPlayers = 1})
]
@@ -70,34 +59,37 @@
let sameProto = clientProto cl == roomProto jRoom
let jRoomClients = map (client irnc) $ roomClients irnc jRI
let nicks = map nick jRoomClients
- let ownerNick = nick . fromJust $ find isMaster jRoomClients
+ let owner = find isMaster jRoomClients
let chans = map sendChan (cl : jRoomClients)
let isBanned = host cl `elem` roomBansList jRoom
return $
- if isNothing maybeRI || not sameProto then
+ if isNothing maybeRI then
[Warning $ loc "No such room"]
+ else if not sameProto then
+ [Warning $ loc "Room version incompatible to your hedgewars version"]
else if isRestrictedJoins jRoom then
[Warning $ loc "Joining restricted"]
- else if isRegisteredOnly jRoom then
+ else if isRegisteredOnly jRoom && (B.null . webPassword $ cl) && not (isAdministrator cl) then
[Warning $ loc "Registered users only"]
else if isBanned then
[Warning $ loc "You are banned in this room"]
else if roomPassword /= password jRoom then
[NoticeMessage WrongPassword]
else
- [
+ (
MoveToRoom jRI
- , AnswerClients [sendChan cl] $ "JOINED" : nicks
- , AnswerClients chans ["CLIENT_FLAGS", "-r", nick cl]
- , AnswerClients [sendChan cl] $ ["CLIENT_FLAGS", "+h", ownerNick]
- ]
- ++ (if clientProto cl < 38 then map (readynessMessage cl) jRoomClients else [sendStateFlags cl jRoomClients])
- ++ answerFullConfig cl (mapParams jRoom) (params jRoom)
+ : ModifyClient (\c -> c{isJoinedMidGame = isJust $ gameInfo jRoom})
+ : AnswerClients chans ["CLIENT_FLAGS", "-r", nick cl]
+ : [(AnswerClients [sendChan cl] $ "JOINED" : nicks) | not $ null nicks]
+ )
+ ++ [AnswerClients [sendChan cl] ["CLIENT_FLAGS", "+h", nick $ fromJust owner] | isJust owner]
+ ++ [sendStateFlags cl jRoomClients | not $ null jRoomClients]
+ ++ answerFullConfig cl jRoom
++ answerTeams cl jRoom
++ watchRound cl jRoom chans
+ ++ [AnswerClients [sendChan cl] ["CHAT", "[greeting]", greeting jRoom] | greeting jRoom /= ""]
where
- 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
@@ -105,28 +97,19 @@
(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
-
- answerFullConfig cl mpr pr
- | clientProto cl < 38 = map (toAnswer cl) $
- (reverse . map (\(a, b) -> (a, [b])) $ Map.toList mpr)
- ++ (("SCHEME", pr Map.! "SCHEME")
- : (filter (\(p, _) -> p /= "SCHEME") $ Map.toList pr))
-
- | otherwise = map (toAnswer cl) $
- ("FULLMAPCONFIG", Map.elems mpr)
- : ("SCHEME", pr Map.! "SCHEME")
- : (filter (\(p, _) -> p /= "SCHEME") $ Map.toList pr)
+ -- get config from gameInfo if possible, otherwise from room
+ answerFullConfig cl jRoom = let f r g = (if isJust $ gameInfo jRoom then g . fromJust . gameInfo else r) jRoom
+ in answerFullConfigParams cl (f mapParams giMapParams) (f params giParams)
answerTeams cl jRoom = let f = if isJust $ gameInfo jRoom then teamsAtStart . fromJust . gameInfo else teams in answerAllTeams cl $ f jRoom
watchRound cl jRoom chans = if isNothing $ gameInfo jRoom then
[]
else
- [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)]
+ 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] =
diff -Nru hedgewars-0.9.19.3/gameServer/HandlerUtils.hs hedgewars-0.9.20.5/gameServer/HandlerUtils.hs
--- hedgewars-0.9.19.3/gameServer/HandlerUtils.hs 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/HandlerUtils.hs 2013-10-31 20:21:52.000000000 +0000
@@ -6,7 +6,7 @@
import RoomsAndClients
import CoreTypes
-import Actions
+
thisClient :: Reader (ClientIndex, IRnC) ClientInfo
thisClient = do
@@ -64,5 +64,5 @@
clientByNick n = do
(_, rnc) <- ask
let allClientIDs = allClients rnc
- return $ find (\clId -> n == nick (client rnc clId)) allClientIDs
+ return $ find (\clId -> let cl = client rnc clId in n == nick cl && not (isChecker cl)) allClientIDs
diff -Nru hedgewars-0.9.19.3/gameServer/NetRoutines.hs hedgewars-0.9.20.5/gameServer/NetRoutines.hs
--- hedgewars-0.9.19.3/gameServer/NetRoutines.hs 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/NetRoutines.hs 2013-10-31 20:21:53.000000000 +0000
@@ -36,7 +36,6 @@
False
False
0
- lobbyId
0
False
False
@@ -44,6 +43,8 @@
False
False
False
+ False
+ False
Nothing
Nothing
0
diff -Nru hedgewars-0.9.19.3/gameServer/OfficialServer/DBInteraction.hs hedgewars-0.9.20.5/gameServer/OfficialServer/DBInteraction.hs
--- hedgewars-0.9.19.3/gameServer/OfficialServer/DBInteraction.hs 2012-12-19 16:09:06.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/OfficialServer/DBInteraction.hs 2013-10-31 20:21:53.000000000 +0000
@@ -49,6 +49,8 @@
writeChan (coreChan si) $ ClientAccountInfo clId clUid (if clHost `L.elem` localAddressList then Admin else Guest)
ClearCache -> return ()
SendStats {} -> return ()
+ GetReplayName {} -> return ()
+ StoreAchievements {} -> return ()
flushRequests si
pipeDbConnectionLoop :: Chan DBQuery -> Chan CoreMessage -> Handle -> Handle -> Map.Map ByteString (UTCTime, AccountInfo) -> Int -> IO (Map.Map ByteString (UTCTime, AccountInfo), Int)
@@ -77,7 +79,22 @@
writeChan cChan $ ClientAccountInfo clId clUid (snd $ fromJust cacheEntry)
return (accountsCache, req)
+ GetReplayName {} -> do
+ SIO.hPutStrLn hIn $ show q
+ hFlush hIn
+
+ (clId', clUid', accountInfo) <- SIO.hGetLine hOut >>= (maybeException . maybeRead)
+
+ writeChan cChan $ ClientAccountInfo clId' clUid' accountInfo
+ return (accountsCache, req)
+
ClearCache -> return (Map.empty, req)
+ StoreAchievements {} -> (
+ (SIO.hPutStrLn hIn $ show q) >>
+ hFlush hIn >>
+ return (accountsCache, req))
+ `Exception.onException`
+ (unGetChan queries q)
SendStats {} -> (
(SIO.hPutStrLn hIn $ show q) >>
hFlush hIn >>
diff -Nru hedgewars-0.9.19.3/gameServer/OfficialServer/GameReplayStore.hs hedgewars-0.9.20.5/gameServer/OfficialServer/GameReplayStore.hs
--- hedgewars-0.9.19.3/gameServer/OfficialServer/GameReplayStore.hs 2013-06-03 08:01:41.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/OfficialServer/GameReplayStore.hs 2013-10-31 20:21:53.000000000 +0000
@@ -17,13 +17,16 @@
import EngineInteraction
-pickReplayFile :: Int -> IO String
-pickReplayFile p = do
- files <- liftM (filter (isSuffixOf ('.' : show p))) $ getDirectoryContents "replays"
+pickReplayFile :: Int -> [String] -> IO String
+pickReplayFile p blackList = do
+ files <- liftM (filter (\f -> sameProto f && notBlacklisted f)) $ getDirectoryContents "replays"
if (not $ null files) then
return $ "replays/" ++ head files
else
return ""
+ where
+ sameProto = (isSuffixOf ('.' : show p))
+ notBlacklisted = flip notElem blackList
saveReplay :: RoomInfo -> IO ()
saveReplay r = do
@@ -38,9 +41,9 @@
(\(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
+loadReplay :: Int -> [String] -> IO (Maybe CheckInfo, [B.ByteString])
+loadReplay p blackList = E.handle (\(e :: SomeException) -> warningM "REPLAYS" "Problems reading replay" >> return (Nothing, [])) $ do
+ fileName <- pickReplayFile p blackList
if (not $ null fileName) then
loadFile fileName
else
diff -Nru hedgewars-0.9.19.3/gameServer/OfficialServer/checker.hs hedgewars-0.9.20.5/gameServer/OfficialServer/checker.hs
--- hedgewars-0.9.19.3/gameServer/OfficialServer/checker.hs 2013-06-03 08:01:41.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/OfficialServer/checker.hs 2013-12-30 19:57:36.000000000 +0000
@@ -24,19 +24,25 @@
import System.Posix
#endif
+readInt_ :: (Num a) => B.ByteString -> a
+readInt_ str =
+ case B.readInt str of
+ Just (i, t) | B.null t -> fromIntegral i
+ _ -> 0
+
data Message = Packet [B.ByteString]
| CheckFailed B.ByteString
| CheckSuccess [B.ByteString]
deriving Show
serverAddress = "netserver.hedgewars.org"
-protocolNumber = "43"
+protocolNumber = "47"
-getLines :: Handle -> IO [String]
+getLines :: Handle -> IO [B.ByteString]
getLines h = g
where
g = do
- l <- liftM Just (hGetLine h) `Exception.catch` (\(_ :: Exception.IOException) -> return Nothing)
+ l <- liftM Just (B.hGetLine h) `Exception.catch` (\(_ :: Exception.IOException) -> return Nothing)
if isNothing l then
return []
else
@@ -45,38 +51,43 @@
return $ fromJust l : lst
-engineListener :: Chan Message -> Handle -> IO ()
-engineListener coreChan h = do
- output <- getLines h
- debugM "Engine" $ show output
- if isNothing $ L.find start output then
+engineListener :: Chan Message -> Handle -> String -> IO ()
+engineListener coreChan h fileName = do
+ stats <- liftM (ps . L.dropWhile (not . start)) $ getLines h
+ debugM "Engine" $ show stats
+ if null stats then
writeChan coreChan $ CheckFailed "No stats msg"
else
- writeChan coreChan $ CheckSuccess []
+ writeChan coreChan $ CheckSuccess stats
+
+ removeFile fileName
where
start = flip L.elem ["WINNERS", "DRAW"]
-
+ ps ("DRAW" : bs) = "DRAW" : ps bs
+ ps ("WINNERS" : n : bs) = let c = readInt_ n in "WINNERS" : n : take c bs ++ (ps $ drop c bs)
+ ps ("ACHIEVEMENT" : typ : teamname : location : value : bs) =
+ "ACHIEVEMENT" : typ : teamname : location : value : ps bs
+ ps _ = []
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
+ B.hPut h . BW.pack . concat . map (fromMaybe [] . 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"
+ (_, _, Just hOut, _) <- createProcess (proc "/usr/home/unC0Rr/Sources/Hedgewars/Releases/0.9.20/bin/hwengine"
+ [fileName
+ , "--user-prefix", "/usr/home/unC0Rr/.hedgewars"
+ , "--prefix", "/usr/home/unC0Rr/Sources/Hedgewars/Releases/0.9.20/share/hedgewars/Data"
+ , "--nomusic"
+ , "--nosound"
+ , "--stats-only"
])
- {std_out = CreatePipe}
+ {std_err = CreatePipe}
hSetBuffering hOut LineBuffering
- void $ forkIO $ engineListener coreChan hOut
+ void $ forkIO $ engineListener coreChan hOut fileName
takePacks :: State B.ByteString [[B.ByteString]]
@@ -154,13 +165,13 @@
#endif
updateGlobalLogger "Core" (setLevel DEBUG)
- updateGlobalLogger "Network" (setLevel DEBUG)
+ updateGlobalLogger "Network" (setLevel WARNING)
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"
+ conf <- join . liftIO . CF.readfile CF.emptyCP $ d ++ "/.hedgewars/settings.ini"
l <- CF.get conf "net" "nick"
p <- CF.get conf "net" "passwordhash"
return (B.pack l, B.pack p)
diff -Nru hedgewars-0.9.19.3/gameServer/OfficialServer/extdbinterface.hs hedgewars-0.9.20.5/gameServer/OfficialServer/extdbinterface.hs
--- hedgewars-0.9.19.3/gameServer/OfficialServer/extdbinterface.hs 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/OfficialServer/extdbinterface.hs 2014-01-04 19:46:00.000000000 +0000
@@ -9,16 +9,31 @@
import Data.Maybe
import Database.HDBC
import Database.HDBC.MySQL
+import Data.List (lookup)
+import qualified Data.ByteString.Char8 as B
+import Data.Word
--------------------------
import CoreTypes
+import Utils
dbQueryAccount =
- "SELECT users.pass, users_roles.rid FROM users LEFT JOIN users_roles ON (users.uid = users_roles.uid AND users_roles.rid = 3) WHERE users.name = ?"
+ "SELECT users.pass, \
+ \ (SELECT COUNT(users_roles.rid) FROM users_roles WHERE users.uid = users_roles.uid AND users_roles.rid = 3), \
+ \ (SELECT COUNT(users_roles.rid) FROM users_roles WHERE users.uid = users_roles.uid AND users_roles.rid = 13) \
+ \ FROM users WHERE users.name = ?"
dbQueryStats =
"INSERT INTO gameserver_stats (players, rooms, last_update) VALUES (?, ?, UNIX_TIMESTAMP())"
+dbQueryAchievement =
+ "INSERT INTO achievements (time, typeid, userid, value, filename, location, protocol) \
+ \ VALUES (?, (SELECT id FROM achievement_types WHERE name = ?), (SELECT uid FROM users WHERE name = ?), \
+ \ ?, ?, ?, ?)"
+
+dbQueryReplayFilename = "SELECT filename FROM achievements WHERE id = ?"
+
+
dbInteractionLoop dbConn = forever $ do
q <- liftM read getLine
hPutStrLn stderr $ show q
@@ -27,24 +42,59 @@
CheckAccount clId clUid clNick _ -> do
statement <- prepare dbConn dbQueryAccount
execute statement [SqlByteString clNick]
- passAndRole <- fetchRow statement
+ result <- fetchRow statement
finish statement
let response =
- if isJust passAndRole then
+ if isJust result then let [pass, adm, contr] = fromJust result in
(
clId,
clUid,
HasAccount
- (fromSql . head . fromJust $ passAndRole)
- (fromSql (last . fromJust $ passAndRole) == Just (3 :: Int))
+ (fromSql pass)
+ (fromSql adm == Just (1 :: Int))
+ (fromSql contr == Just (1 :: Int))
)
else
(clId, clUid, Guest)
print response
hFlush stdout
+ GetReplayName clId clUid fileId -> do
+ statement <- prepare dbConn dbQueryReplayFilename
+ execute statement [SqlByteString fileId]
+ result <- fetchRow statement
+ finish statement
+ let fn = if (isJust result) then fromJust . fromSql . head . fromJust $ result else ""
+ print (clId, clUid, ReplayName fn)
+ hFlush stdout
+
SendStats clients rooms ->
run dbConn dbQueryStats [SqlInt32 $ fromIntegral clients, SqlInt32 $ fromIntegral rooms] >> return ()
+--StoreAchievements (B.pack fileName) (map toPair teams) info
+ StoreAchievements p fileName teams info ->
+ mapM_ (run dbConn dbQueryAchievement) $ (parseStats p fileName teams) info
+
+
+readTime = read . B.unpack . B.take 19 . B.drop 8
+
+
+parseStats :: Word16 -> B.ByteString -> [(B.ByteString, B.ByteString)] -> [B.ByteString] -> [[SqlValue]]
+parseStats p fileName teams = ps
+ where
+ time = readTime fileName
+ ps [] = []
+ ps ("DRAW" : bs) = ps bs
+ ps ("WINNERS" : n : bs) = ps $ drop (readInt_ n) bs
+ ps ("ACHIEVEMENT" : typ : teamname : location : value : bs) =
+ [ SqlUTCTime time
+ , SqlByteString typ
+ , SqlByteString $ fromMaybe "" (lookup teamname teams)
+ , SqlInt32 (readInt_ value)
+ , SqlByteString fileName
+ , SqlByteString location
+ , SqlInt32 $ fromIntegral p
+ ] : ps bs
+ ps (b:bs) = ps bs
dbConnectionLoop mySQLConnectionInfo =
diff -Nru hedgewars-0.9.19.3/gameServer/Utils.hs hedgewars-0.9.20.5/gameServer/Utils.hs
--- hedgewars-0.9.19.3/gameServer/Utils.hs 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/gameServer/Utils.hs 2013-12-25 05:19:22.000000000 +0000
@@ -92,6 +92,8 @@
, (44, "0.9.19-dev")
, (45, "0.9.19")
, (46, "0.9.20-dev")
+ , (47, "0.9.20")
+ , (48, "0.9.21-dev")
]
askFromConsole :: B.ByteString -> IO B.ByteString
@@ -125,8 +127,9 @@
upperCase :: B.ByteString -> B.ByteString
upperCase = UTF8.fromString . map Char.toUpper . UTF8.toString
-roomInfo :: B.ByteString -> RoomInfo -> [B.ByteString]
-roomInfo n r = [
+roomInfo :: Word16 -> B.ByteString -> RoomInfo -> [B.ByteString]
+roomInfo p n r
+ | p < 46 = [
showB $ isJust $ gameInfo r,
name r,
showB $ playersIn r,
@@ -136,6 +139,49 @@
head (Map.findWithDefault ["Default"] "SCHEME" (params r)),
head (Map.findWithDefault ["Default"] "AMMO" (params r))
]
+ | otherwise = [
+ showB $ isJust $ gameInfo r,
+ name r,
+ showB $ playersIn r,
+ showB $ length $ teams r,
+ n,
+ Map.findWithDefault "+rnd+" "MAP" (mapParams r),
+ head (Map.findWithDefault ["Normal"] "SCRIPT" (params r)),
+ head (Map.findWithDefault ["Default"] "SCHEME" (params r)),
+ head (Map.findWithDefault ["Default"] "AMMO" (params r))
+ ]
+
+answerFullConfigParams ::
+ ClientInfo
+ -> Map.Map B.ByteString B.ByteString
+ -> Map.Map B.ByteString [B.ByteString]
+ -> [Action]
+answerFullConfigParams cl mpr pr
+ | clientProto cl < 38 = map (toAnswer cl) $
+ (reverse . map (\(a, b) -> (a, [b])) $ Map.toList mpr)
+ ++ (("SCHEME", pr Map.! "SCHEME")
+ : (filter (\(p, _) -> p /= "SCHEME") $ Map.toList pr))
+
+ | otherwise = map (toAnswer cl) $
+ ("FULLMAPCONFIG", Map.elems mpr)
+ : ("SCHEME", pr Map.! "SCHEME")
+ : (filter (\(p, _) -> p /= "SCHEME") $ Map.toList pr)
+ where
+ toAnswer cl (paramName, paramStrs) = AnswerClients [sendChan cl] $ "CFG" : paramName : paramStrs
+
+
+answerAllTeams :: ClientInfo -> [TeamInfo] -> [Action]
+answerAllTeams cl = concatMap toAnswer
+ where
+ clChan = sendChan cl
+ toAnswer team =
+ [AnswerClients [clChan] $ teamToNet team,
+ AnswerClients [clChan] ["TEAM_COLOR", teamname team, teamcolor team],
+ AnswerClients [clChan] ["HH_NUM", teamname team, showB $ hhnum team]]
+
loc :: B.ByteString -> B.ByteString
loc = id
+
+maybeNick :: Maybe ClientInfo -> B.ByteString
+maybeNick = fromMaybe "[empty]" . liftM nick
diff -Nru hedgewars-0.9.19.3/hedgewars/ArgParsers.inc hedgewars-0.9.20.5/hedgewars/ArgParsers.inc
--- hedgewars-0.9.19.3/hedgewars/ArgParsers.inc 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/ArgParsers.inc 1970-01-01 00:00:00.000000000 +0000
@@ -1,348 +0,0 @@
-(*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2013 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
- *)
-
-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 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
- 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;
-{$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-6)))
- end
- else if tmp <= 6 then
- // set the fullcolor anaglyph
- cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp)))
- else
- // any other mode
- cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp-6)));
-{$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;
-
-
-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 := max(getLongIntParameter(arg, paramIndex, parseParameter), cMinScreenWidth);
- {--fullscreen-height} 4 : cFullscreenHeight := max(getLongIntParameter(arg, paramIndex, parseParameter), cMinScreenHeight);
- {--width} 5 : cWindowedWidth := max(2 * (getLongIntParameter(arg, paramIndex, parseParameter) div 2), cMinScreenWidth);
- {--height} 6 : cWindowedHeight := max(2 * (getLongIntParameter(arg, paramIndex, parseParameter) div 2), cMinScreenHeight);
- {--frame-interval} 7 : cTimerInterval := getLongIntParameter(arg, paramIndex, parseParameter);
- {--volume} 8 : SetVolume ( max(getLongIntParameter(arg, paramIndex, parseParameter), 0) );
- {--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
- 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}
-
diff -Nru hedgewars-0.9.19.3/hedgewars/ArgParsers.pas hedgewars-0.9.20.5/hedgewars/ArgParsers.pas
--- hedgewars-0.9.19.3/hedgewars/ArgParsers.pas 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/ArgParsers.pas 2014-01-08 16:25:17.000000000 +0000
@@ -0,0 +1,373 @@
+(*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2013 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"}
+
+unit ArgParsers;
+interface
+
+{$IFNDEF HWLIBRARY}
+procedure GetParams;
+{$ELSE}
+procedure parseCommandLine(argc: LongInt; argv: PPChar);
+{$ENDIF}
+
+implementation
+uses uVariables, uTypes, uUtils, uSound, uConsts;
+var isInternal: Boolean {$IFDEF HWLIBRARY} = true{$ENDIF};
+
+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 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, ' --no-teamtag');
+ WriteLn(stdout, ' --no-hogtag');
+ WriteLn(stdout, ' --no-healthtag');
+ WriteLn(stdout, ' --translucent-tags');
+ 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
+ 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;
+{$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-6)))
+ end
+ else if tmp <= 6 then
+ // set the fullcolor anaglyph
+ cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp)))
+ else
+ // any other mode
+ cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp-6)));
+{$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;
+
+
+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..18] of String = ('--fullscreen-width','--fullscreen-height', '--width', '--height', '--depth','--volume','--nomusic','--nosound','--locale','--fullscreen','--showfps','--altdmg','--frame-interval','--low-quality','--no-teamtag','--no-hogtag','--no-healthtag','--translucent-tags');
+ reallyAll: array[0..34] 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','--no-teamtag','--no-hogtag','--no-healthtag','--translucent-tags');
+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 := max(getLongIntParameter(arg, paramIndex, parseParameter), cMinScreenWidth);
+ {--fullscreen-height} 4 : cFullscreenHeight := max(getLongIntParameter(arg, paramIndex, parseParameter), cMinScreenHeight);
+ {--width} 5 : cWindowedWidth := max(2 * (getLongIntParameter(arg, paramIndex, parseParameter) div 2), cMinScreenWidth);
+ {--height} 6 : cWindowedHeight := max(2 * (getLongIntParameter(arg, paramIndex, parseParameter) div 2), cMinScreenHeight);
+ {--frame-interval} 7 : cTimerInterval := getLongIntParameter(arg, paramIndex, parseParameter);
+ {--volume} 8 : SetVolume ( max(getLongIntParameter(arg, paramIndex, parseParameter), 0) );
+ {--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();
+ {--no-teamtag} 31 : cTagsMask := cTagsMask and not htTeamName;
+ {--no-hogtag} 32 : cTagsMask := cTagsMask and not htName;
+ {--no-healthtag} 33 : cTagsMask := cTagsMask and not htHealth;
+ {--translucent-tags} 34 : cTagsMask := cTagsMask or htTransparent
+ 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
+ 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') or (cmd = '--no-teamtag') or (cmd = '--no-hogtag') or (cmd = '--no-healthtag') or (cmd = '--translucent-tags');
+ 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}
+
+end.
+
diff -Nru hedgewars-0.9.19.3/hedgewars/CMakeLists.txt hedgewars-0.9.20.5/hedgewars/CMakeLists.txt
--- hedgewars-0.9.19.3/hedgewars/CMakeLists.txt 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/CMakeLists.txt 2014-01-08 16:25:17.000000000 +0000
@@ -1,268 +1,213 @@
-find_package(SDL)
+find_package(SDL1or2)
find_package(SDL_image)
find_package(SDL_net)
find_package(SDL_ttf)
find_package(SDL_mixer)
-include (CheckLibraryExists)
-#Mix_Init/Mix_Quit from SDL_mixer 1.2.10
-check_library_exists(${SDLMIXER_LIBRARY} Mix_Init "" HAVE_MIXINIT)
-if(HAVE_MIXINIT)
- list(APPEND pascal_flags "-dSDL_MIXER_NEWER")
-endif()
-#IMG_Init/IMG_Quit from SDL_image 1.2.8
-check_library_exists(${SDLIMAGE_LIBRARY} IMG_Init "" HAVE_IMGINIT)
-if(HAVE_IMGINIT)
- list(APPEND pascal_flags "-dSDL_IMAGE_NEWER")
-endif()
+include(CheckLibraryExists)
+include(${CMAKE_MODULE_PATH}/utils.cmake)
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.inc.in ${CMAKE_CURRENT_BINARY_DIR}/config.inc)
+enable_language(Pascal)
+add_flag_append(CMAKE_Pascal_FLAGS "-Cs2000000")
+add_flag_append(CMAKE_Pascal_FLAGS_DEBUG "-gv")
+add_flag_append(CMAKE_Pascal_FLAGS_RELEASE "-Xs")
+if(UNIX)
+ include(TargetArch)
+ target_architecture(CMAKE_TARGET_ARCHITECTURES)
+ if(${CMAKE_Pascal_COMPILER_VERSION} VERSION_GREATER 2.7 OR ${CMAKE_TARGET_ARCHITECTURES} MATCHES "x86_64" OR ${CMAKE_TARGET_ARCHITECTURES} MATCHES "i386")
+ add_flag_append(CMAKE_Pascal_FLAGS "-fPIC")
+ endif()
+endif(UNIX)
-#SOURCE AND PROGRAMS SECTION
-if(${BUILD_ENGINE_LIBRARY})
- set(engine_output_name "${CMAKE_SHARED_LIBRARY_PREFIX}hwengine${CMAKE_SHARED_LIBRARY_SUFFIX}")
- set(hwengine_project hwLibrary.pas)
-else()
- set(engine_output_name "hwengine${CMAKE_EXECUTABLE_SUFFIX}")
- set(hwengine_project hwengine.pas)
-endif()
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.inc.in ${CMAKE_CURRENT_BINARY_DIR}/config.inc)
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
-if (APPLE)
- set(required_fpc_version 2.6)
-else()
- set(required_fpc_version 2.2)
-endif()
+#set the sources with the correct order of dependencies so that cmake won't be confused
set(engine_sources
- ${hwengine_project}
- LuaPas.pas
- PNGh.pas
SDLh.pas
- uAI.pas
- uAIActions.pas
- uAILandMarks.pas
- uAIAmmoTests.pas
- uAIMisc.pas
- uAmmos.pas
- uCaptions.pas
- uChat.pas
- uCollisions.pas
- uCommands.pas
- uCommandHandlers.pas
- uConsole.pas
+ uSinTable.pas
+ uFloat.pas
uConsts.pas
- uCursor.pas
+ LuaPas.pas
+ uTypes.pas
+ uVariables.pas
+ uUtils.pas
+ uMisc.pas
+ uConsole.pas
+ uCommands.pas
uDebug.pas
- uFloat.pas
- uGame.pas
- uGears.pas
- uGearsHandlers.pas
- uGearsHandlersRope.pas
- uGearsHedgehog.pas
- uGearsList.pas
- uGearsRender.pas
- uGearsUtils.pas
- uIO.pas
uInputHandler.pas
- uLand.pas
- uLandGenMaze.pas
- uLandGraphics.pas
- uLandObjects.pas
- uLandOutline.pas
- uLandPainted.pas
- uLandTemplates.pas
- uLandTexture.pas
- uLocale.pas
- uMisc.pas
- uPhysFSLayer.pas
- uRandom.pas
- uRender.pas
+ uTextures.pas
uRenderUtils.pas
- uScript.pas
- uSinTable.pas
+ uRender.pas
+ uCaptions.pas
+ uIO.pas
+ uChat.pas
+ uPhysFSLayer.pas
uSound.pas
+ ArgParsers.pas
+ uRandom.pas
+ uLocale.pas
uStats.pas
- uStore.pas
- uTeams.pas
- uTextures.pas
- uTouch.pas
- uTypes.pas
- uUtils.pas
- uVariables.pas
+ uCursor.pas
uVideoRec.pas
- uVisualGears.pas
- uWorld.pas
- GSHandlers.inc
- VGSHandlers.inc
- ArgParsers.inc
- options.inc
+ uAILandMarks.pas
adler32.pas
- ${CMAKE_CURRENT_BINARY_DIR}/config.inc
- )
-
-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")
- list(APPEND pascal_flags "-Cg")
- endif(CMAKE_SIZEOF_VOID_P MATCHES "8")
+ uLandTemplates.pas
+ uLandTexture.pas
+ uLandGraphics.pas
+ uLandPainted.pas
+ uLandOutline.pas
+ uLandGenMaze.pas
- # 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 VERSION_GREATER "10.5")
- list(APPEND pascal_flags "-k-no_order_inits")
- endif()
- set(destination_dir ${target_library_install_dir})
-else(${BUILD_ENGINE_LIBRARY})
- set(destination_dir ${target_binary_install_dir})
-endif(${BUILD_ENGINE_LIBRARY})
+ #this is where dependency tracking becomes hard
+ uStore.pas
+ uAmmos.pas
+ uLandObjects.pas
+ uLand.pas
+ uGearsList.pas
+ uCollisions.pas
+ uAIMisc.pas
+ uAIActions.pas
+ uAIAmmoTests.pas
+ uAI.pas
+ uWorld.pas
+ uVisualGearsList.pas
+ uVisualGearsHandlers.pas
+ uVisualGears.pas
+ uGears.pas
+ uGame.pas
+ uCommandHandlers.pas
+ uGearsRender.pas
+ uGearsHedgehog.pas
+ uGearsHandlers.pas
+ uGearsHandlersRope.pas
+ uGearsHandlersMess.pas
+ uGearsUtils.pas
+ uTeams.pas
-include(${CMAKE_MODULE_PATH}/utils.cmake)
+ #these interact with everything, so compile last
+ uScript.pas
+ )
-find_package_or_fail(FreePascal)
-#when cmake-2.6 support is dropped, this ought to be inside FindFreePascal.cmake
-if (FREEPASCAL_VERSION VERSION_LESS required_fpc_version)
- message(FATAL_ERROR "Freepascal ${FREEPASCAL_VERSION} is too old, minimum version required is ${required_fpc_version}")
+if (${CMAKE_Pascal_COMPILER_VERSION} VERSION_LESS 2.2 OR # older versions are just ancient
+ (${CMAKE_Pascal_COMPILER_VERSION} VERSION_LESS 2.6 AND APPLE)) # because of 64bit and opengl bindings
+ message(FATAL_ERROR "Your FreePascal installation is too old (fpc ${CMAKE_Pascal_COMPILER_VERSION})!")
+elseif(CMAKE_Pascal_COMPILER_VERSION VERSION_GREATER 2.4)
+ #enable INLINE only with a recent version of fpc
+ add_flag_prepend(CMAKE_Pascal_FLAGS_RELEASE -Si)
endif()
+#generic folder where our libraries reside
+add_flag_append(CMAKE_Pascal_FLAGS "-Fl${LIBRARY_OUTPUT_PATH}")
#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}")
- string(REGEX MATCH "[xX]86_64+" x86_64_build "${CMAKE_OSX_ARCHITECTURES}")
-
- if(powerpc_build)
- set(powerpc_build "powerpc")
- endif()
-
+if(NOT ${BUILD_ENGINE_LIBRARY} AND APPLE)
#on OSX we need to provide the SDL_main() function when building as executable
- 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_library_only "${SDL_LIBRARY}")
- #find libsdmain.a
- 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
- list(APPEND engine_sources SDLmain)
- set(SDLMAIN_LIB "${LIBRARY_OUTPUT_PATH}/libSDLmain.a")
- endif()
-
- list(APPEND pascal_flags "-k${SDLMAIN_LIB}")
- endif()
+ add_subdirectory(sdlmain)
+ list(APPEND HW_LINK_LIBS SDLmain)
+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)
+if(FFMPEG_FOUND)
+ add_subdirectory(avwrapper)
+ list(APPEND HW_LINK_LIBS avwrapper)
+ add_definitions(-dUSE_VIDEO_RECORDING)
+ #only for SDL < 2, linking carried out by fpc
+ find_package_or_disable_msg(GLUT NOVIDEOREC "Video recording will not be built")
+endif()
find_package_or_disable_msg(PNG NOPNG "Screenshots will be saved in BMP")
if(PNG_FOUND)
+ list(INSERT engine_sources 0 PNGh.pas)
list(REMOVE_AT PNG_LIBRARIES 1) #removing the zlib library path
get_filename_component(PNG_LIBRARY_DIR ${PNG_LIBRARIES} PATH)
- list(APPEND pascal_flags "-dPNG_SCREENSHOTS" "-Fl${PNG_LIBRARY_DIR}" "-k-L${PNG_LIBRARY_DIR}")
+ add_flag_append(CMAKE_Pascal_FLAGS "-k-L${PNG_LIBRARY_DIR} -Fl${PNG_LIBRARY_DIR}")
+ add_definitions(-dPNG_SCREENSHOTS)
endif()
-
-#this command is a workaround to some inlining issues present in older FreePascal versions and fixed in 2.6
-if(FREEPASCAL_VERSION VERSION_LESS "2.6")
- #under some configurations CMAKE_BUILD_TOOL fails to pass on the jobserver, breaking parallel compilation
- if(UNIX)
- set(SAFE_BUILD_TOOL $(MAKE))
- else()
- set(SAFE_BUILD_TOOL ${CMAKE_BUILD_TOOL})
- endif()
- add_custom_target(ENGINECLEAN COMMAND ${SAFE_BUILD_TOOL} "clean" "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
+if(LUA_FOUND AND LUA_SYSTEM)
+ get_filename_component(LUA_LIBRARY_DIR ${LUA_LIBRARY} PATH)
+ get_filename_component(LUA_LIBRARY_NAME ${LUA_LIBRARY} NAME)
+ #NAME_WE would strip the .1 (or .2) next to the ".so"
+ string(REGEX REPLACE "${CMAKE_SHARED_LIBRARY_PREFIX}(.*)${CMAKE_SHARED_LIBRARY_SUFFIX}" "\\1" LUA_LIBRARY_NAME "${LUA_LIBRARY_NAME}")
+ add_flag_append(CMAKE_Pascal_FLAGS "-Fl${LUA_LIBRARY_DIR} -XLAlua=${LUA_LIBRARY_NAME}")
+else()
+ add_definitions(-dLUA_INTERNAL)
+ list(APPEND HW_LINK_LIBS lua)
+ add_flag_append(CMAKE_Pascal_FLAGS "-XLAlua=${lua_output_name}")
endif()
-
-if(${FFMPEG_FOUND})
- # TODO: this check is only for SDL < 2
- # fpc will take care of linking but we need to have this library installed
- find_package(GLUT REQUIRED)
-
- #TODO: convert avwrapper to .pas unit so we can skip this step
- include_directories(${FFMPEG_INCLUDE_DIR})
- 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_library_install_dir})
- else()
- add_library(avwrapper STATIC avwrapper.c)
- endif()
+if(PHYSFS_FOUND)
+ get_filename_component(PHYSFS_LIBRARY_DIR ${PHYSFS_LIBRARY} PATH)
+ add_flag_append(CMAKE_Pascal_FLAGS "-Fl${PHYSFS_LIBRARY}")
+else()
+ add_definitions(-dPHYSFS_INTERNAL)
+ list(APPEND HW_LINK_LIBS physfs)
+ #-XLA is a beta fpc flag that renames libraries before passing them to the linker
+ #we also have to pass PHYSFS_INTERNAL to satisfy windows runtime requirements
+ #(should be harmless on other platforms)
+ add_flag_append(CMAKE_Pascal_FLAGS "-XLAphysfs=${physfs_output_name}")
endif()
+list(APPEND HW_LINK_LIBS physlayer)
+
+#Mix_Init/Mix_Quit from SDL_mixer 1.2.10
+check_library_exists(${SDLMIXER_LIBRARY} Mix_Init "" HAVE_MIXINIT)
+if(HAVE_MIXINIT)
+ add_definitions(-dSDL_MIXER_NEWER)
+endif(HAVE_MIXINIT)
-set(fpc_flags ${pascal_flags} ${hwengine_project})
+#IMG_Init/IMG_Quit from SDL_image 1.2.8
+check_library_exists(${SDLIMAGE_LIBRARY} IMG_Init "" HAVE_IMGINIT)
+if(HAVE_IMGINIT)
+ add_definitions(-dSDL_IMAGE_NEWER)
+endif(HAVE_IMGINIT)
-if(NOT APPLE)
- #here is the command for standard executables or for shared library
- add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}"
- COMMAND "${FREEPASCAL_EXECUTABLE}"
- ARGS ${fpc_flags} -o${engine_output_name}
- DEPENDS ${engine_sources}
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- )
-else()
- #these are the dependencies for building a universal binary on Mac OS X
- foreach (build_arch ${powerpc_build} ${i386_build} ${x86_64_build})
- list(APPEND lipo_args_list "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}")
- add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}"
- COMMAND "${FREEPASCAL_EXECUTABLE}"
- ARGS ${fpc_flags} -ohwengine.${build_arch} -P${build_arch}
- DEPENDS ${engine_sources}
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- )
- 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}"
- COMMAND "lipo"
- ARGS ${lipo_args_list} -create -output ${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}
- DEPENDS ${lipo_args_list}
- )
+if(NOT (SDL_VERSION VERSION_LESS 2.0))
+ add_definitions(-dSDL2)
endif()
+#needs to be last
+add_definitions(-dDEBUGFILE)
-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(hwengine lua)
-endif()
+# source files are with full path after this
+set(sourcefiles_sofar "${CMAKE_CURRENT_SOURCE_DIR}/options.inc" "${CMAKE_CURRENT_BINARY_DIR}/config.inc")
+foreach(loop_var ${engine_sources})
+ list(APPEND sourcefiles_sofar "${CMAKE_CURRENT_SOURCE_DIR}/${loop_var}")
+endforeach(loop_var)
-# same for physfs
-if(NOT PHYSFS_FOUND)
- add_dependencies(hwengine physfs)
-endif()
-add_dependencies(hwengine physlayer)
+#SOURCE AND PROGRAMS SECTION
+if(BUILD_ENGINE_LIBRARY)
+ message("***Engine will be built as library (experimental)***")
+ if(APPLE AND current_macosx_version VERSION_GREATER "10.5")
+ # due to compiler/linker issues on Max OS X 10.6 -k-no_order_inits is needed to avoid linking fail
+ add_flag_prepend(CMAKE_Pascal_FLAGS "-k-no_order_inits")
+ endif()
-#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(hwengine avwrapper)
-endif()
+ #workaround for missing support during object generation
+ set(engine_output_name "${CMAKE_SHARED_LIBRARY_PREFIX}hwengine${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ set(destination_dir ${target_library_install_dir})
+ add_flag_prepend(CMAKE_Pascal_FLAGS "-o${LIBRARY_OUTPUT_PATH}/${engine_output_name}")
-#this command is a workaround to some inlining issues present in older FreePascal versions and fixed in 2.6
-if((FREEPASCAL_VERSION VERSION_LESS "2.6") AND (NOT ${FFMPEG_FOUND}))
- add_dependencies(hwengine ENGINECLEAN)
+ add_definitions(-dHWLIBRARY)
+ set_source_files_properties(hwLibrary.pas PROPERTIES OBJECT_DEPENDS "${sourcefiles_sofar}")
+ set_source_files_properties(hwLibrary.pas PROPERTIES OBJECT_DEPENDS hwengine.pas)
+ add_library(hwengine SHARED hwLibrary.pas)
+else()
+ # no need to change name here because target has same name
+ set(engine_output_name "hwengine${CMAKE_EXECUTABLE_SUFFIX}")
+ set(destination_dir ${target_binary_install_dir})
+ set_source_files_properties(hwengine.pas PROPERTIES OBJECT_DEPENDS "${sourcefiles_sofar}")
+ add_executable(hwengine hwengine.pas)
endif()
+#even though not actually used, this will trigger relink if any lib changes
+target_link_libraries(hwengine ${HW_LINK_LIBS})
+
install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}" DESTINATION ${destination_dir})
diff -Nru hedgewars-0.9.19.3/hedgewars/GSHandlers.inc hedgewars-0.9.20.5/hedgewars/GSHandlers.inc
--- hedgewars-0.9.19.3/hedgewars/GSHandlers.inc 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/GSHandlers.inc 1970-01-01 00:00:00.000000000 +0000
@@ -1,5645 +0,0 @@
-(*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2013 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
- *)
-
-(*
- * This file contains the step handlers for gears.
- *
- * Important: Since gears change the course of the game, calculations that
- * lead to different results for different clients/players/machines
- * should NOT occur!
- * Use safe functions and data types! (e.g. GetRandom() and hwFloat)
- *)
-
-procedure doStepPerPixel(Gear: PGear; step: TGearStepProcedure; onlyCheckIfChanged: boolean);
-var
- dX, dY, sX, sY: hwFloat;
- i, steps: LongWord;
- caller: TGearStepProcedure;
-begin
- dX:= Gear^.dX;
- dY:= Gear^.dY;
- steps:= max(abs(hwRound(Gear^.X+dX)-hwRound(Gear^.X)), abs(hwRound(Gear^.Y+dY)-hwRound(Gear^.Y)));
-
- // Gear is still on the same Pixel it was before
- if steps < 1 then
- begin
- if onlyCheckIfChanged then
- begin
- Gear^.X := Gear^.X + dX;
- Gear^.Y := Gear^.Y + dY;
- EXIT;
- end
- else
- steps := 1;
- end;
-
- if steps > 1 then
- begin
- sX:= dX / steps;
- sY:= dY / steps;
- end
-
- else
- begin
- sX:= dX;
- sY:= dY;
- end;
-
- caller:= Gear^.doStep;
-
- for i:= 1 to steps do
- begin
- Gear^.X := Gear^.X + sX;
- Gear^.Y := Gear^.Y + sY;
- step(Gear);
- if (Gear^.doStep <> caller)
- or ((Gear^.State and gstCollision) <> 0)
- or ((Gear^.State and gstMoving) = 0) then
- break;
- end;
-end;
-
-procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
-var
- gi: PGear;
- d: LongInt;
-begin
- gi := GearsList;
- while gi <> nil do
- begin
- if (gi^.Kind = gtHedgehog) then
- begin
- d := r - hwRound(Distance(gi^.X - x, gi^.Y - y));
- if (d > 1) and (not gi^.Invulnerable) and (GetRandom(2) = 0) then
- begin
- if (CurrentHedgehog^.Gear = gi) then
- PlaySoundV(sndOops, gi^.Hedgehog^.Team^.voicepack)
-
- else
- begin
- if ((gi^.State and gstMoving) = 0) and (gi^.Hedgehog^.Effects[heFrozen] = 0) then
- begin
- gi^.dX.isNegative:= X r div 2 then
- PlaySoundV(sndNooo, gi^.Hedgehog^.Team^.voicepack)
- else
- PlaySoundV(sndUhOh, gi^.Hedgehog^.Team^.voicepack);
- end;
- end;
- end;
-
- gi := gi^.NextGear
- end;
-end;
-
-procedure HideHog(HH: PHedgehog);
-begin
- ScriptCall('onHogHide', HH^.Gear^.Uid);
- DeleteCI(HH^.Gear);
- if FollowGear = HH^.Gear then
- FollowGear:= nil;
-
- if lastGearByUID = HH^.Gear then
- lastGearByUID := nil;
-
- HH^.Gear^.Message:= HH^.Gear^.Message or gmRemoveFromList;
- with HH^.Gear^ do
- begin
- Z := cHHZ;
- HH^.Gear^.Active:= false;
- State:= State and (not (gstHHDriven or gstAttacking or gstAttacked));
- Message := Message and (not gmAttack);
- end;
- HH^.GearHidden:= HH^.Gear;
- HH^.Gear:= nil
-end;
-
-procedure RestoreHog(HH: PHedgehog);
-begin
- HH^.Gear:=HH^.GearHidden;
- HH^.GearHidden:= nil;
- InsertGearToList(HH^.Gear);
- HH^.Gear^.State:= (HH^.Gear^.State and (not (gstHHDriven or gstInvisible or gstAttacking))) or gstAttacked;
- AddGearCI(HH^.Gear);
- HH^.Gear^.Active:= true;
- ScriptCall('onHogRestore', HH^.Gear^.Uid)
-end;
-
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepDrowningGear(Gear: PGear);
- begin
- AllInactive := false;
- Gear^.Y := Gear^.Y + cDrownSpeed;
- Gear^.X := Gear^.X + Gear^.dX * cDrownSpeed;
- // Create some bubbles (0.5% might be better but causes too few bubbles sometimes)
- if ((not SuddenDeathDmg and (WaterOpacity < $FF))
- or (SuddenDeathDmg and (SDWaterOpacity < $FF))) and ((GameTicks and $1F) = 0) then
- if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then
- AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble)
- else if Random(12) = 0 then
- AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble);
- if (not SuddenDeathDmg and (WaterOpacity > $FE))
- or (SuddenDeathDmg and (SDWaterOpacity > $FE))
- or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then
- DeleteGear(Gear);
- end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepFallingGear(Gear: PGear);
-var
- isFalling: boolean;
- //tmp: QWord;
- tdX, tdY: hwFloat;
- collV, collH: LongInt;
- land: word;
-begin
- // clip velocity at 2 - over 1 per pixel, but really shouldn't cause many actual problems.
- if Gear^.dX.Round > 2 then
- Gear^.dX.QWordValue:= 8589934592;
- if Gear^.dY.Round > 2 then
- Gear^.dY.QWordValue:= 8589934592;
-
- if (Gear^.State and gstSubmersible <> 0) and (hwRound(Gear^.Y) > cWaterLine) then
- begin
- Gear^.dX:= Gear^.dX * _0_999;
- Gear^.dY:= Gear^.dY * _0_999
- end;
-
- Gear^.State := Gear^.State and (not gstCollision);
- collV := 0;
- collH := 0;
- tdX := Gear^.dX;
- tdY := Gear^.dY;
-
-
-
-// might need some testing/adjustments - just to avoid projectiles to fly forever (accelerated by wind/skips)
- if (hwRound(Gear^.X) < min(LAND_WIDTH div -2, -2048))
- or (hwRound(Gear^.X) > max(LAND_WIDTH * 3 div 2, 6144)) then
- Gear^.State := Gear^.State or gstCollision;
-
- if Gear^.dY.isNegative then
- begin
- isFalling := true;
- land:= TestCollisionYwithGear(Gear, -1);
- if land <> 0 then
- begin
- collV := -1;
- if land and lfIce <> 0 then
- Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
- else
- Gear^.dX := Gear^.dX * Gear^.Friction;
-
- Gear^.dY := - Gear^.dY * Gear^.Elasticity;
- Gear^.State := Gear^.State or gstCollision
- end
- else if (Gear^.AdvBounce=1) and (TestCollisionYwithGear(Gear, 1) <> 0) then
- collV := 1;
- end
- else
- begin // Gear^.dY.isNegative is false
- land:= TestCollisionYwithGear(Gear, 1);
- if land <> 0 then
- begin
- collV := 1;
- isFalling := false;
- if land and lfIce <> 0 then
- Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
- else
- Gear^.dX := Gear^.dX * Gear^.Friction;
-
- Gear^.dY := - Gear^.dY * Gear^.Elasticity;
- Gear^.State := Gear^.State or gstCollision
- end
- else
- begin
- isFalling := true;
- if (Gear^.AdvBounce=1) and (TestCollisionYwithGear(Gear, -1) <> 0) then
- collV := -1
- end
- end;
-
-
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
- begin
- collH := hwSign(Gear^.dX);
- Gear^.dX := - Gear^.dX * Gear^.Elasticity;
- Gear^.dY := Gear^.dY * Gear^.Elasticity;
- Gear^.State := Gear^.State or gstCollision
- end
- else if (Gear^.AdvBounce=1) and TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)) then
- collH := -hwSign(Gear^.dX);
- //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then
- if (Gear^.AdvBounce=1) and (collV <>0) and (collH <> 0) and ((collV=-1)
- or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)) then
- begin
- Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction;
- Gear^.dY := tdX*Gear^.Elasticity;
- //*Gear^.Friction;
- Gear^.dY.isNegative := not tdY.isNegative;
- isFalling := false;
- Gear^.AdvBounce := 10;
- end;
-
- if Gear^.AdvBounce > 1 then
- dec(Gear^.AdvBounce);
-
- if isFalling then
- begin
- Gear^.dY := Gear^.dY + cGravity;
- if (GameFlags and gfMoreWind) <> 0 then
- Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
- end;
-
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
- if Gear^.Kind <> gtBee then
- CheckGearDrowning(Gear);
- //if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) < _0_0002) and
- if (not isFalling) and ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_02.QWordValue) then
- Gear^.State := Gear^.State and (not gstMoving)
- else
- Gear^.State := Gear^.State or gstMoving;
-
- if (Gear^.nImpactSounds > 0) and
- (Gear^.State and gstCollision <> 0) and
- (((Gear^.Kind <> gtMine) and (Gear^.Damage <> 0)) or (Gear^.State and gstMoving <> 0)) and
- (((Gear^.Radius < 3) and (Gear^.dY < -_0_1)) or
- ((Gear^.Radius >= 3) and
- ((Gear^.dX.QWordValue > _0_1.QWordValue) or (Gear^.dY.QWordValue > _0_1.QWordValue)))) then
- PlaySound(TSound(ord(Gear^.ImpactSound) + LongInt(GetRandom(Gear^.nImpactSounds))), true);
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepBomb(Gear: PGear);
-var
- i, x, y: LongInt;
- dX, dY, gdX: hwFloat;
- vg: PVisualGear;
-begin
- AllInactive := false;
-
- doStepFallingGear(Gear);
-
- dec(Gear^.Timer);
- if Gear^.Timer = 1000 then // might need adjustments
- case Gear^.Kind of
- gtGrenade: makeHogsWorry(Gear^.X, Gear^.Y, 50);
- gtClusterBomb: makeHogsWorry(Gear^.X, Gear^.Y, 20);
- gtWatermelon: makeHogsWorry(Gear^.X, Gear^.Y, 75);
- gtHellishBomb: makeHogsWorry(Gear^.X, Gear^.Y, 90);
- gtGasBomb: makeHogsWorry(Gear^.X, Gear^.Y, 50);
- end;
-
- if (Gear^.Kind = gtBall) and ((Gear^.State and gstTmpFlag) <> 0) then
- begin
- CheckCollision(Gear);
- if (Gear^.State and gstCollision) <> 0 then
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLDontDraw or EXPLNoGfx);
- end;
-
- if (Gear^.Kind = gtGasBomb) and ((GameTicks mod 200) = 0) then
- begin
- vg:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeWhite);
- if vg <> nil then
- vg^.Tint:= $FFC0C000;
- end;
-
- if Gear^.Timer = 0 then
- begin
- case Gear^.Kind of
- gtGrenade: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
- gtBall: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 40, Gear^.Hedgehog, EXPLAutoSound);
- gtClusterBomb:
- 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) + gdX / 5;
- dY := (GetRandomf - _3) * _0_08;
- FollowGear := AddGear(x, y, gtCluster, 0, dX, dY, 25)
- end
- end;
- gtWatermelon:
- 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) + gdX / 5;
- dY := (GetRandomf - _1_5) * _0_3;
- FollowGear:= AddGear(x, y, gtMelonPiece, 0, dX, dY, 75);
- FollowGear^.DirAngle := i * 60
- end
- end;
- gtHellishBomb:
- begin
- x := hwRound(Gear^.X);
- y := hwRound(Gear^.Y);
- doMakeExplosion(x, y, 90, Gear^.Hedgehog, EXPLAutoSound);
-
- for i:= 0 to 127 do
- begin
- dX := AngleCos(i * 16) * _0_5 * (GetRandomf + _1);
- dY := AngleSin(i * 16) * _0_5 * (GetRandomf + _1);
- if i mod 2 = 0 then
- begin
- AddGear(x, y, gtFlame, gstTmpFlag, dX, dY, 0);
- AddGear(x, y, gtFlame, 0, dX, -dY, 0)
- end
- else
- begin
- AddGear(x, y, gtFlame, 0, dX, dY, 0);
- AddGear(x, y, gtFlame, gstTmpFlag, dX, -dY, 0)
- end;
- end
- end;
- gtGasBomb:
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLAutoSound);
- for i:= 0 to 2 do
- begin
- x:= GetRandom(60);
- y:= GetRandom(40);
- FollowGear:= AddGear(hwRound(Gear^.X) - 30 + x, hwRound(Gear^.Y) - 20 + y, gtPoisonCloud, 0, _0, _0, 0);
- end
- end;
- end;
- DeleteGear(Gear);
- exit
- end;
-
- CalcRotationDirAngle(Gear);
-
- if Gear^.Kind = gtHellishBomb then
- begin
-
- if Gear^.Timer = 3000 then
- begin
- Gear^.nImpactSounds := 0;
- PlaySound(sndHellish);
- end;
-
- if (GameTicks and $3F) = 0 then
- if (Gear^.State and gstCollision) = 0 then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace);
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepMolotov(Gear: PGear);
-var
- s: Longword;
- i, gX, gY: LongInt;
- dX, dY: hwFloat;
- smoke, glass: PVisualGear;
-begin
- AllInactive := false;
-
- doStepFallingGear(Gear);
- CalcRotationDirAngle(Gear);
-
- // let's add some smoke depending on speed
- s:= max(32,152 - round((abs(hwFloat2FLoat(Gear^.dX))+abs(hwFloat2Float(Gear^.dY)))*120))+random(10);
- if (GameTicks mod s) = 0 then
- begin
- // adjust angle to match the texture
- if Gear^.dX.isNegative then
- i:= 130
- else i:= 50;
-
- smoke:= AddVisualGear(hwRound(Gear^.X)-round(cos((Gear^.DirAngle+i) * pi / 180)*20), hwRound(Gear^.Y)-round(sin((Gear^.DirAngle+i) * pi / 180)*20), vgtSmoke);
- if smoke <> nil then
- smoke^.Scale:= 0.75;
- end;
-
- if (Gear^.State and gstCollision) <> 0 then
- begin
- PlaySound(sndMolotov);
- gX := hwRound(Gear^.X);
- gY := hwRound(Gear^.Y);
- for i:= 0 to 4 do
- begin
- (*glass:= AddVisualGear(gx+random(7)-3, gy+random(5)-2, vgtEgg);
- if glass <> nil then
- begin
- glass^.Frame:= 2;
- glass^.Tint:= $41B83ED0 - i * $10081000;
- glass^.dX:= 1/(10*(random(11)-5));
- glass^.dY:= -1/(random(4)+5);
- end;*)
- glass:= AddVisualGear(gx+random(7)-3, gy+random(7)-3, vgtStraightShot);
- if glass <> nil then
- with glass^ do
- begin
- Frame:= 2;
- Tint:= $41B83ED0 - i * $10081000;
- Angle:= random(360);
- dx:= 0.0000001;
- dy:= 0;
- if random(2) = 0 then
- dx := -dx;
- FrameTicks:= 750;
- State:= ord(sprEgg)
- end;
- end;
- for i:= 0 to 24 do
- begin
- dX := AngleCos(i * 2) * ((_0_15*(i div 5))) * (GetRandomf + _1);
- dY := AngleSin(i * 8) * _0_5 * (GetRandomf + _1);
- AddGear(gX, gY, gtFlame, gstTmpFlag, dX, dY, 0);
- AddGear(gX, gY, gtFlame, gstTmpFlag, dX,-dY, 0);
- AddGear(gX, gY, gtFlame, gstTmpFlag,-dX, dY, 0);
- AddGear(gX, gY, gtFlame, gstTmpFlag,-dX,-dY, 0);
- end;
- DeleteGear(Gear);
- exit
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-
-procedure doStepCluster(Gear: PGear);
-begin
- AllInactive := false;
- doStepFallingGear(Gear);
- if (Gear^.State and gstCollision) <> 0 then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Timer, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear);
- exit
- end;
-
- if (Gear^.Kind = gtMelonPiece)
- or (Gear^.Kind = gtBall) then
- CalcRotationDirAngle(Gear)
- else if (GameTicks and $1F) = 0 then
- begin
- if hwRound(Gear^.Y) > cWaterLine then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble)
- else AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepShell(Gear: PGear);
-begin
- AllInactive := false;
- if (GameFlags and gfMoreWind) = 0 then
- Gear^.dX := Gear^.dX + cWindSpeed;
- doStepFallingGear(Gear);
- if (Gear^.State and gstCollision) <> 0 then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear);
- exit
- end;
- if (GameTicks and $3F) = 0 then
- begin
- if hwRound(Gear^.Y) > cWaterLine then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble)
- else AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSnowball(Gear: PGear);
-var kick, i: LongInt;
- particle: PVisualGear;
- gdX, gdY: hwFloat;
-begin
- AllInactive := false;
- if (GameFlags and gfMoreWind) = 0 then
- Gear^.dX := Gear^.dX + cWindSpeed;
- gdX := Gear^.dX;
- gdY := Gear^.dY;
- doStepFallingGear(Gear);
- CalcRotationDirAngle(Gear);
- if (Gear^.State and gstCollision) <> 0 then
- begin
- kick:= hwRound((hwAbs(gdX)+hwAbs(gdY)) * _20);
- Gear^.dX:= gdX;
- Gear^.dY:= gdY;
- AmmoShove(Gear, 0, kick);
- for i:= 15 + kick div 10 downto 0 do
- begin
- particle := AddVisualGear(hwRound(Gear^.X) + Random(25), hwRound(Gear^.Y) + Random(25), vgtDust);
- if particle <> nil then
- particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480)
- end;
- DeleteGear(Gear);
- exit
- end;
- if ((GameTicks and $1F) = 0) and (Random(3) = 0) then
- begin
- particle:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtDust);
- if particle <> nil then
- particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480)
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSnowflake(Gear: PGear);
-var xx, yy, px, py, rx, ry, lx, ly: LongInt;
- move, draw, allpx, gun: Boolean;
- s: PSDL_Surface;
- p: PLongwordArray;
- lf: LongWord;
-begin
-inc(Gear^.Pos);
-gun:= (Gear^.State and gstTmpFlag) <> 0;
-move:= false;
-draw:= false;
-if gun then
- begin
- Gear^.State:= Gear^.State and (not gstInvisible);
- doStepFallingGear(Gear);
- CheckCollision(Gear);
- if ((Gear^.State and gstCollision) <> 0) or ((Gear^.State and gstMoving) = 0) then
- draw:= true;
- xx:= hwRound(Gear^.X);
- yy:= hwRound(Gear^.Y);
- end
-else if GameTicks and $7 = 0 then
- begin
- with Gear^ do
- begin
- State:= State and (not gstInvisible);
- X:= X + cWindSpeed * 3200 + dX;
- Y:= Y + dY + cGravity * vobFallSpeed * 8; // using same value as flakes to try and get similar results
- xx:= hwRound(X);
- yy:= hwRound(Y);
- if vobVelocity <> 0 then
- begin
- DirAngle := DirAngle + (Damage / 1000);
- if DirAngle < 0 then
- DirAngle := DirAngle + 360
- else if 360 < DirAngle then
- DirAngle := DirAngle - 360;
- end;
-(*
-We aren't using frametick right now, so just a waste of cycles.
- inc(Health, 8);
- if longword(Health) > vobFrameTicks then
- begin
- dec(Health, vobFrameTicks);
- inc(Timer);
- if Timer = vobFramesCount then
- Timer:= 0
- end;
-*)
- // move back to cloud layer
- if yy > cWaterLine then
- move:= true
- else if (xx > snowRight) or (xx < snowLeft) then
- move:=true
- // Solid pixel encountered
- else if ((yy and LAND_HEIGHT_MASK) = 0) and ((xx and LAND_WIDTH_MASK) = 0) and (Land[yy, xx] <> 0) then
- begin
- lf:= Land[yy, xx] and (lfObject or lfBasic or lfIndestructible);
- if lf = 0 then lf:= lfObject;
- // If there's room below keep falling
- if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (Land[yy-1, xx] = 0) then
- begin
- X:= X - cWindSpeed * 1600 - dX;
- end
- // If there's room below, on the sides, fill the gaps
- else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx-(1*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx-(1*hwSign(cWindSpeed)))] = 0) then
- begin
- X:= X - _0_8 * hwSign(cWindSpeed);
- Y:= Y - dY - cGravity * vobFallSpeed * 8;
- end
- else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx-(2*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx-(2*hwSign(cWindSpeed)))] = 0) then
- begin
- X:= X - _0_8 * 2 * hwSign(cWindSpeed);
- Y:= Y - dY - cGravity * vobFallSpeed * 8;
- end
- else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx+(1*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx+(1*hwSign(cWindSpeed)))] = 0) then
- begin
- X:= X + _0_8 * hwSign(cWindSpeed);
- Y:= Y - dY - cGravity * vobFallSpeed * 8;
- end
- else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx+(2*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx+(2*hwSign(cWindSpeed)))] = 0) then
- begin
- X:= X + _0_8 * 2 * hwSign(cWindSpeed);
- Y:= Y - dY - cGravity * vobFallSpeed * 8;
- end
- // if there's an hog/object below do nothing
- else if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((Land[yy+1, xx] and $FF) <> 0))
- then move:=true
- else draw:= true
- end
- end
- end;
-if draw then
- with Gear^ do
- begin
- // we've collided with land. draw some stuff and get back into the clouds
- move:= true;
- if (Pos > 20) and ((CurAmmoGear = nil)
- or (CurAmmoGear^.Kind <> gtRope)) then
- begin
-////////////////////////////////// TODO - ASK UNC0RR FOR A GOOD HOME FOR THIS ////////////////////////////////////
- if not gun then
- begin
- dec(yy,3);
- dec(xx,1)
- end;
- s:= SpritesData[sprSnow].Surface;
- p:= s^.pixels;
- allpx:= true;
- for py:= 0 to Pred(s^.h) do
- begin
- for px:= 0 to Pred(s^.w) do
- begin
- lx:=xx + px; ly:=yy + py;
- if (ly and LAND_HEIGHT_MASK = 0) and (lx and LAND_WIDTH_MASK = 0) and (Land[ly, lx] and $FF = 0) then
- begin
- rx:= lx;
- ry:= ly;
- if cReducedQuality and rqBlurryLand <> 0 then
- begin
- rx:= rx div 2;ry:= ry div 2;
- end;
- if Land[yy + py, xx + px] <= lfAllObjMask then
- if gun then
- begin
- LandDirty[yy div 32, xx div 32]:= 1;
- if LandPixels[ry, rx] = 0 then
- Land[ly, lx]:= lfDamaged or lfObject
- else Land[ly, lx]:= lfDamaged or lfBasic
- end
- else Land[ly, lx]:= lf;
- if gun then
- LandPixels[ry, rx]:= (ExplosionBorderColor and (not AMask)) or (p^[px] and AMask)
- else LandPixels[ry, rx]:= addBgColor(LandPixels[ry, rx], p^[px]);
- end
- else allpx:= false
- end;
- p:= @(p^[s^.pitch shr 2])
- end;
-
- // Why is this here. For one thing, there's no test on +1 being safe.
- //Land[py, px+1]:= lfBasic;
-
- if allpx then
- UpdateLandTexture(xx, Pred(s^.h), yy, Pred(s^.w), true)
- else
- begin
- UpdateLandTexture(
- max(0, min(LAND_WIDTH, xx)),
- min(LAND_WIDTH - xx, Pred(s^.w)),
- max(0, min(LAND_WIDTH, yy)),
- min(LAND_HEIGHT - yy, Pred(s^.h)), false // could this be true without unnecessarily creating blanks?
- );
- end;
-////////////////////////////////// TODO - ASK UNC0RR FOR A GOOD HOME FOR THIS ////////////////////////////////////
- end
- end;
-
-if move then
- begin
- if gun then
- begin
- DeleteGear(Gear);
- exit
- end;
- Gear^.Pos:= 0;
- Gear^.X:= int2hwFloat(LongInt(GetRandom(snowRight - snowLeft)) + snowLeft);
- Gear^.Y:= int2hwFloat(LAND_HEIGHT + LongInt(GetRandom(50)) - 1325);
- Gear^.State:= Gear^.State or gstInvisible;
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepGrave(Gear: PGear);
-begin
- if (Gear^.Message and gmDestroy) <> 0 then
- begin
- DeleteGear(Gear);
- exit
- end;
-
- AllInactive := false;
-
- if Gear^.dY.isNegative then
- if TestCollisionY(Gear, -1) then
- Gear^.dY := _0;
-
- if not Gear^.dY.isNegative then
- if TestCollisionY(Gear, 1) then
- begin
- Gear^.dY := - Gear^.dY * Gear^.Elasticity;
- if Gear^.dY > - _1div1024 then
- begin
- Gear^.Active := false;
- exit
- end
- else if Gear^.dY < - _0_03 then
- PlaySound(Gear^.ImpactSound)
- end;
-
- Gear^.Y := Gear^.Y + Gear^.dY;
- CheckGearDrowning(Gear);
- Gear^.dY := Gear^.dY + cGravity
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepBeeWork(Gear: PGear);
-var
- t: hwFloat;
- gX,gY,i: LongInt;
- uw, nuw: boolean;
- flower: PVisualGear;
-
-begin
- AllInactive := false;
- gX := hwRound(Gear^.X);
- gY := hwRound(Gear^.Y);
- uw := (Gear^.Tag <> 0); // was bee underwater last tick?
- nuw := (cWaterLine < gy + Gear^.Radius); // is bee underwater now?
-
- // if water entered or left
- if nuw <> uw then
- begin
- AddVisualGear(gX, cWaterLine, vgtSplash);
- AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
- AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
- AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
- AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
- StopSoundChan(Gear^.SoundChannel);
- if nuw then
- begin
- Gear^.SoundChannel := LoopSound(sndBeeWater);
- Gear^.Tag := 1;
- end
- else
- begin
- Gear^.SoundChannel := LoopSound(sndBee);
- Gear^.Tag := 0;
- end;
- end;
-
-
- if Gear^.Timer = 0 then
- Gear^.RenderTimer:= false
- else
- begin
- if (GameTicks and $F) = 0 then
- begin
- if (GameTicks and $30) = 0 then
- AddVisualGear(gX, gY, vgtBeeTrace);
- Gear^.dX := Gear^.Elasticity * (Gear^.dX + _0_000064 * (Gear^.Target.X - gX));
- Gear^.dY := Gear^.Elasticity * (Gear^.dY + _0_000064 * (Gear^.Target.Y - gY));
- // make sure new speed isn't higher than original one (which we stored in Friction variable)
- t := Gear^.Friction / Distance(Gear^.dX, Gear^.dY);
- Gear^.dX := Gear^.dX * t;
- Gear^.dY := Gear^.dY * t;
- end;
-
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
-
- end;
-
-
- CheckCollision(Gear);
- if ((Gear^.State and gstCollision) <> 0) then
- begin
- StopSoundChan(Gear^.SoundChannel);
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
- for i:= 0 to 31 do
- begin
- flower:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot);
- if flower <> nil then
- with flower^ do
- begin
- Scale:= 0.75;
- dx:= 0.001 * (random(200));
- dy:= 0.001 * (random(200));
- if random(2) = 0 then
- dx := -dx;
- if random(2) = 0 then
- dy := -dy;
- FrameTicks:= random(250) + 250;
- State:= ord(sprTargetBee);
- end;
- end;
- DeleteGear(Gear);
- end;
-
- if (Gear^.Timer > 0) then
- dec(Gear^.Timer)
- else
- begin
- if nuw then
- begin
- StopSoundChan(Gear^.SoundChannel);
- CheckGearDrowning(Gear);
- end
- else
- doStepFallingGear(Gear);
- end;
-end;
-
-procedure doStepBee(Gear: PGear);
-begin
- AllInactive := false;
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
- Gear^.dY := Gear^.dY + cGravity;
- CheckCollision(Gear);
- if (Gear^.State and gstCollision) <> 0 then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear);
- exit
- end;
- dec(Gear^.Timer);
- if Gear^.Timer = 0 then
- begin
- Gear^.Hedgehog^.Gear^.Message:= Gear^.Hedgehog^.Gear^.Message and (not gmAttack);
- Gear^.Hedgehog^.Gear^.State:= Gear^.Hedgehog^.Gear^.State and (not gstAttacking);
- AttackBar:= 0;
-
- Gear^.SoundChannel := LoopSound(sndBee);
- Gear^.Timer := 5000;
- // save initial speed in otherwise unused Friction variable
- Gear^.Friction := Distance(Gear^.dX, Gear^.dY);
- Gear^.doStep := @doStepBeeWork
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepShotIdle(Gear: PGear);
-begin
- AllInactive := false;
- inc(Gear^.Timer);
- if Gear^.Timer > 75 then
- begin
- DeleteGear(Gear);
- AfterAttack
- end
-end;
-
-procedure doStepShotgunShot(Gear: PGear);
-var
- i: LongWord;
- shell: PVisualGear;
-begin
- AllInactive := false;
-
- if ((Gear^.State and gstAnimation) = 0) then
- begin
- dec(Gear^.Timer);
- if Gear^.Timer = 0 then
- begin
- PlaySound(sndShotgunFire);
- shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
- if shell <> nil then
- begin
- shell^.dX := gear^.dX.QWordValue / -17179869184;
- shell^.dY := gear^.dY.QWordValue / -17179869184;
- shell^.Frame := 0
- end;
- Gear^.State := Gear^.State or gstAnimation
- end;
- exit
- end else
- if(Gear^.Hedgehog^.Gear = nil) or ((Gear^.Hedgehog^.Gear^.State and gstMoving) <> 0) then
- begin
- DeleteGear(Gear);
- AfterAttack;
- exit
- end
- else
- inc(Gear^.Timer);
-
- i := 200;
- repeat
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
- CheckCollision(Gear);
- if (Gear^.State and gstCollision) <> 0 then
- begin
- Gear^.X := Gear^.X + Gear^.dX * 8;
- Gear^.Y := Gear^.Y + Gear^.dY * 8;
- ShotgunShot(Gear);
- Gear^.doStep := @doStepShotIdle;
- exit
- end;
-
- CheckGearDrowning(Gear);
- if (Gear^.State and gstDrowning) <> 0 then
- begin
- Gear^.doStep := @doStepShotIdle;
- exit
- end;
- dec(i)
- until i = 0;
- if (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0) or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
- Gear^.doStep := @doStepShotIdle
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure spawnBulletTrail(Bullet: PGear);
-var oX, oY: hwFloat;
- VGear: PVisualGear;
-begin
- if Bullet^.PortalCounter = 0 then
- begin
- ox:= CurrentHedgehog^.Gear^.X + Int2hwFloat(GetLaunchX(CurrentHedgehog^.CurAmmoType, hwSign(CurrentHedgehog^.Gear^.dX), CurrentHedgehog^.Gear^.Angle));
- oy:= CurrentHedgehog^.Gear^.Y + Int2hwFloat(GetLaunchY(CurrentHedgehog^.CurAmmoType, CurrentHedgehog^.Gear^.Angle));
- end
- else
- begin
- ox:= Bullet^.Elasticity;
- oy:= Bullet^.Friction;
- end;
-
- // Bullet trail
- VGear := AddVisualGear(hwRound(ox), hwRound(oy), vgtLineTrail);
-
- if VGear <> nil then
- begin
- VGear^.X:= hwFloat2Float(ox);
- VGear^.Y:= hwFloat2Float(oy);
- VGear^.dX:= hwFloat2Float(Bullet^.X);
- VGear^.dY:= hwFloat2Float(Bullet^.Y);
-
- // reached edge of land. assume infinite beam. Extend it way out past camera
- if (hwRound(Bullet^.X) and LAND_WIDTH_MASK <> 0)
- or (hwRound(Bullet^.Y) and LAND_HEIGHT_MASK <> 0) then
- // only extend if not under water
- if hwRound(Bullet^.Y) < cWaterLine then
- begin
- VGear^.dX := VGear^.dX + max(LAND_WIDTH,4096) * (VGear^.dX - VGear^.X);
- VGear^.dY := VGear^.dY + max(LAND_WIDTH,4096) * (VGear^.dY - VGear^.Y);
- end;
-
- VGear^.Timer := 200;
- end;
-end;
-
-procedure doStepBulletWork(Gear: PGear);
-var
- i, x, y: LongWord;
- oX, oY: hwFloat;
- VGear: PVisualGear;
-begin
- AllInactive := false;
- inc(Gear^.Timer);
- i := 80;
- oX := Gear^.X;
- oY := Gear^.Y;
- repeat
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
- x := hwRound(Gear^.X);
- y := hwRound(Gear^.Y);
-
- if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then
- inc(Gear^.Damage);
- // let's interrupt before a collision to give portals a chance to catch the bullet
- if (Gear^.Damage = 1) and (Gear^.Tag = 0) and not(CheckLandValue(x, y, lfLandMask)) then
- begin
- Gear^.Tag := 1;
- Gear^.Damage := 0;
- Gear^.X := Gear^.X - Gear^.dX;
- Gear^.Y := Gear^.Y - Gear^.dY;
- CheckGearDrowning(Gear);
- break;
- end
- else
- Gear^.Tag := 0;
-
- if Gear^.Damage > 5 then
- if Gear^.AmmoType = amDEagle then
- AmmoShove(Gear, 7, 20)
- else
- AmmoShove(Gear, Gear^.Timer, 20);
- CheckGearDrowning(Gear);
- dec(i)
- until (i = 0) or (Gear^.Damage > Gear^.Health) or ((Gear^.State and gstDrowning) <> 0);
-
- if Gear^.Damage > 0 then
- begin
- DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 82 - i, 1);
- dec(Gear^.Health, Gear^.Damage);
- Gear^.Damage := 0
- end;
- if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and ((not SuddenDeathDmg and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF))) then
- begin
- for i:=(Gear^.Health - Gear^.Damage) * 4 downto 0 do
- begin
- if Random(6) = 0 then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble);
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
- end;
- end;
-
- if (Gear^.Health <= 0)
- or (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0)
- or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
- begin
- if (Gear^.Kind = gtSniperRifleShot) and ((GameFlags and gfLaserSight) = 0) then
- cLaserSighting := false;
- if (Ammoz[Gear^.AmmoType].Ammo.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and ((GameFlags and gfArtillery) = 0) then
- cArtillery := false;
-
- // Bullet Hit
- if (hwRound(Gear^.X) and LAND_WIDTH_MASK = 0) and (hwRound(Gear^.Y) and LAND_HEIGHT_MASK = 0) then
- begin
- VGear := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBulletHit);
- if VGear <> nil then
- begin
- VGear^.Angle := DxDy2Angle(-Gear^.dX, Gear^.dY);
- end;
- end;
-
- spawnBulletTrail(Gear);
- Gear^.doStep := @doStepShotIdle
- end;
-end;
-
-procedure doStepDEagleShot(Gear: PGear);
-begin
- PlaySound(sndGun);
- // add 3 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just plain old weird angles
- Gear^.X := Gear^.X + Gear^.dX * 3;
- Gear^.Y := Gear^.Y + Gear^.dY * 3;
- Gear^.doStep := @doStepBulletWork
-end;
-
-procedure doStepSniperRifleShot(Gear: PGear);
-var
- HHGear: PGear;
- shell: PVisualGear;
-begin
- cArtillery := true;
- HHGear := Gear^.Hedgehog^.Gear;
- HHGear^.State := HHGear^.State or gstNotKickable;
- HedgehogChAngle(HHGear);
- if not cLaserSighting then
- // game does not have default laser sight. turn it on and give them a chance to aim
- begin
- cLaserSighting := true;
- HHGear^.Message := 0;
- if (HHGear^.Angle >= 32) then
- dec(HHGear^.Angle,32)
- end;
-
- if (HHGear^.Message and gmAttack) <> 0 then
- begin
- shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
- if shell <> nil then
- begin
- shell^.dX := gear^.dX.QWordValue / -8589934592;
- shell^.dY := gear^.dY.QWordValue / -8589934592;
- shell^.Frame := 1
- end;
- Gear^.State := Gear^.State or gstAnimation;
- Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5;
- Gear^.dY := -AngleCos(HHGear^.Angle) * _0_5;
- PlaySound(sndGun);
- // add 3 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just weird angles
- Gear^.X := Gear^.X + Gear^.dX * 3;
- Gear^.Y := Gear^.Y + Gear^.dY * 3;
- Gear^.doStep := @doStepBulletWork;
- end
- else
- if (GameTicks mod 32) = 0 then
- if (GameTicks mod 4096) < 2048 then
- begin
- if (HHGear^.Angle + 1 <= cMaxAngle) then
- inc(HHGear^.Angle)
- end
- else
- if (HHGear^.Angle >= 1) then
- dec(HHGear^.Angle);
-
- if (TurnTimeLeft > 0) then
- dec(TurnTimeLeft)
- else
- begin
- DeleteGear(Gear);
- AfterAttack
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepActionTimer(Gear: PGear);
-begin
-dec(Gear^.Timer);
-case Gear^.Kind of
- gtATStartGame:
- begin
- AllInactive := false;
- if Gear^.Timer = 0 then
- begin
- AddCaption(trmsg[sidStartFight], cWhiteColor, capgrpGameState);
- end
- end;
- gtATFinishGame:
- begin
- AllInactive := false;
- if Gear^.Timer = 1000 then
- begin
- ScreenFade := sfToBlack;
- ScreenFadeValue := 0;
- ScreenFadeSpeed := 1;
- end;
- if Gear^.Timer = 0 then
- begin
- SendIPC(_S'N');
- SendIPC(_S'q');
- GameState := gsExit
- end
- end;
- end;
-if Gear^.Timer = 0 then
- DeleteGear(Gear)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepPickHammerWork(Gear: PGear);
-var
- i, ei, x, y: LongInt;
- HHGear: PGear;
-begin
- AllInactive := false;
- HHGear := Gear^.Hedgehog^.Gear;
- dec(Gear^.Timer);
- if ((GameFlags and gfInfAttack) <> 0) and (TurnTimeLeft > 0) then
- dec(TurnTimeLeft);
- if (TurnTimeLeft = 0) or (Gear^.Timer = 0)
- or((Gear^.Message and gmDestroy) <> 0)
- or((HHGear^.State and gstHHDriven) =0) then
- begin
- StopSoundChan(Gear^.SoundChannel);
- DeleteGear(Gear);
- AfterAttack;
- doStepHedgehogMoving(HHGear); // for gfInfAttack
- exit
- end;
-
- x:= hwRound(Gear^.X);
- y:= hwRound(Gear^.Y);
- if (Gear^.Timer mod 33) = 0 then
- begin
- HHGear^.State := HHGear^.State or gstNoDamage;
- doMakeExplosion(x, y + 7, 6, Gear^.Hedgehog, EXPLDontDraw);
- HHGear^.State := HHGear^.State and (not gstNoDamage)
- end;
-
- if (Gear^.Timer mod 47) = 0 then
- begin
- // ok. this was an attempt to turn off dust if not actually drilling land. I have no idea why it isn't working as expected
- if (( (y + 12) and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y + 12, x] > 255) then
- for i:= 0 to 1 do
- AddVisualGear(x - 5 + Random(10), y + 12, vgtDust);
-
- i := x - Gear^.Radius - LongInt(GetRandom(2));
- ei := x + Gear^.Radius + LongInt(GetRandom(2));
- while i <= ei do
- begin
- DrawExplosion(i, y + 3, 3);
- inc(i, 1)
- end;
-
- if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9), lfIndestructible) then
- begin
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + _1_9;
- end;
- SetAllHHToActive;
- end;
- if TestCollisionYwithGear(Gear, 1) <> 0 then
- begin
- Gear^.dY := _0;
- SetLittle(HHGear^.dX);
- HHGear^.dY := _0;
- end
- else
- begin
- if CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y + Gear^.dY + cGravity), lfLandMask) then
- begin
- Gear^.dY := Gear^.dY + cGravity;
- Gear^.Y := Gear^.Y + Gear^.dY
- end;
- if hwRound(Gear^.Y) > cWaterLine then
- Gear^.Timer := 1
- end;
-
- Gear^.X := Gear^.X + HHGear^.dX;
- if CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y)-cHHRadius, lfLandMask) then
- begin
- HHGear^.X := Gear^.X;
- HHGear^.Y := Gear^.Y - int2hwFloat(cHHRadius)
- end;
-
- if (Gear^.Message and gmAttack) <> 0 then
- if (Gear^.State and gsttmpFlag) <> 0 then
- Gear^.Timer := 1
- else //there would be a mistake.
- else
- if (Gear^.State and gsttmpFlag) = 0 then
- Gear^.State := Gear^.State or gsttmpFlag;
- if ((Gear^.Message and gmLeft) <> 0) then
- Gear^.dX := - _0_3
- else
- if ((Gear^.Message and gmRight) <> 0) then
- Gear^.dX := _0_3
- else Gear^.dX := _0;
-end;
-
-procedure doStepPickHammer(Gear: PGear);
-var
- i, y: LongInt;
- ar: TRangeArray;
- HHGear: PGear;
-begin
- i := 0;
- HHGear := Gear^.Hedgehog^.Gear;
-
- y := hwRound(Gear^.Y) - cHHRadius * 2;
- while y < hwRound(Gear^.Y) do
- begin
- ar[i].Left := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
- ar[i].Right := hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
- inc(y, 2);
- inc(i)
- end;
-
- DrawHLinesExplosions(@ar, 3, hwRound(Gear^.Y) - cHHRadius * 2, 2, Pred(i));
- Gear^.dY := HHGear^.dY;
- DeleteCI(HHGear);
-
- Gear^.SoundChannel := LoopSound(sndPickhammer);
- doStepPickHammerWork(Gear);
- Gear^.doStep := @doStepPickHammerWork
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-var
- BTPrevAngle, BTSteps: LongInt;
-
-procedure doStepBlowTorchWork(Gear: PGear);
-var
- HHGear: PGear;
- b: boolean;
- prevX: LongInt;
-begin
- AllInactive := false;
- dec(Gear^.Timer);
- if ((GameFlags and gfInfAttack) <> 0) and (TurnTimeLeft > 0) then
- dec(TurnTimeLeft);
-
- HHGear := Gear^.Hedgehog^.Gear;
-
- HedgehogChAngle(HHGear);
-
- b := false;
-
- if abs(LongInt(HHGear^.Angle) - BTPrevAngle) > 7 then
- begin
- Gear^.dX := SignAs(AngleSin(HHGear^.Angle) * _0_5, Gear^.dX);
- Gear^.dY := AngleCos(HHGear^.Angle) * ( - _0_5);
- BTPrevAngle := HHGear^.Angle;
- b := true
- end;
-
- if ((HHGear^.State and gstMoving) <> 0) then
- begin
- doStepHedgehogMoving(HHGear);
- if (HHGear^.State and gstHHDriven) = 0 then
- Gear^.Timer := 0
- end;
-
- if Gear^.Timer mod cHHStepTicks = 0 then
- begin
- b := true;
- if Gear^.dX.isNegative then
- HHGear^.Message := (HHGear^.Message and (gmAttack or gmUp or gmDown)) or gmLeft
- else
- HHGear^.Message := (HHGear^.Message and (gmAttack or gmUp or gmDown)) or gmRight;
-
- if ((HHGear^.State and gstMoving) = 0) then
- begin
- HHGear^.State := HHGear^.State and (not gstAttacking);
- prevX := hwRound(HHGear^.X);
-
- // why the call to HedgehogStep then a further increment of X?
- if (prevX = hwRound(HHGear^.X)) and
- CheckLandValue(hwRound(HHGear^.X + SignAs(_6, HHGear^.dX)), hwRound(HHGear^.Y),
- lfIndestructible) then HedgehogStep(HHGear);
-
- if (prevX = hwRound(HHGear^.X)) and
- CheckLandValue(hwRound(HHGear^.X + SignAs(_6, HHGear^.dX)), hwRound(HHGear^.Y),
- lfIndestructible) then HHGear^.X := HHGear^.X + SignAs(_1, HHGear^.dX);
- HHGear^.State := HHGear^.State or gstAttacking
- end;
-
- inc(BTSteps);
- if BTSteps = 7 then
- begin
- BTSteps := 0;
- if CheckLandValue(hwRound(HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC) + SignAs(_6,Gear^.dX)), hwRound(HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC)),lfIndestructible) then
- begin
- Gear^.X := HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC);
- Gear^.Y := HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC);
- end;
- HHGear^.State := HHGear^.State or gstNoDamage;
- AmmoShove(Gear, 2, 15);
- HHGear^.State := HHGear^.State and (not gstNoDamage)
- end;
- end;
-
- if b then
- begin
- DrawTunnel(HHGear^.X + Gear^.dX * cHHRadius,
- HHGear^.Y + Gear^.dY * cHHRadius - _1 -
- ((hwAbs(Gear^.dX) / (hwAbs(Gear^.dX) + hwAbs(Gear^.dY))) * _0_5 * 7),
- Gear^.dX, Gear^.dY,
- cHHStepTicks, cHHRadius * 2 + 7);
- end;
-
- if (TurnTimeLeft = 0) or (Gear^.Timer = 0)
- or ((HHGear^.Message and gmAttack) <> 0) then
- begin
- HHGear^.Message := 0;
- HHGear^.State := HHGear^.State and (not gstNotKickable);
- DeleteGear(Gear);
- AfterAttack
- end
-end;
-
-procedure doStepBlowTorch(Gear: PGear);
-var
- HHGear: PGear;
-begin
- BTPrevAngle := High(LongInt);
- BTSteps := 0;
- HHGear := Gear^.Hedgehog^.Gear;
- HedgehogChAngle(HHGear);
- Gear^.dX := SignAs(AngleSin(HHGear^.Angle) * _0_5, Gear^.dX);
- Gear^.dY := AngleCos(HHGear^.Angle) * ( - _0_5);
- DrawTunnel(HHGear^.X,
- HHGear^.Y + Gear^.dY * cHHRadius - _1 -
- ((hwAbs(Gear^.dX) / (hwAbs(Gear^.dX) + hwAbs(Gear^.dY))) * _0_5 * 7),
- Gear^.dX, Gear^.dY,
- cHHStepTicks, cHHRadius * 2 + 7);
- HHGear^.Message := 0;
- HHGear^.State := HHGear^.State or gstNotKickable;
- Gear^.doStep := @doStepBlowTorchWork
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepMine(Gear: PGear);
-var vg: PVisualGear;
- dxdy: hwFloat;
-begin
- if Gear^.Health = 0 then dxdy:= hwAbs(Gear^.dX)+hwAbs(Gear^.dY);
- if (Gear^.State and gstMoving) <> 0 then
- begin
- DeleteCI(Gear);
- doStepFallingGear(Gear);
- if (Gear^.State and gstMoving) = 0 then
- begin
- AddGearCI(Gear);
- Gear^.dX := _0;
- Gear^.dY := _0
- end;
- CalcRotationDirAngle(Gear);
- AllInactive := false
- end
- else if (GameTicks and $3F) = 25 then
- doStepFallingGear(Gear);
- if (Gear^.Health = 0) then
- begin
- if (dxdy > _0_4) and (Gear^.State and gstCollision <> 0) then
- inc(Gear^.Damage, hwRound(dxdy * _50));
-
- if ((GameTicks and $FF) = 0) and (Gear^.Damage > random(30)) then
- begin
- vg:= AddVisualGear(hwRound(Gear^.X) - 4 + Random(8), hwRound(Gear^.Y) - 4 - Random(4), vgtSmoke);
- if vg <> nil then
- vg^.Scale:= 0.5
- end;
-
- if (Gear^.Damage > 35) then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear);
- exit
- end
- end;
-
- if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
- if ((Gear^.State and gstAttacking) = 0) then
- begin
- if ((GameTicks and $1F) = 0) then
- if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then
- Gear^.State := Gear^.State or gstAttacking
- end
- else // gstAttacking <> 0
- begin
- AllInactive := false;
- if (Gear^.Timer and $FF) = 0 then
- PlaySound(sndMineTick);
- if Gear^.Timer = 0 then
- begin
- if ((Gear^.State and gstWait) <> 0)
- or (cMineDudPercent = 0)
- or (getRandom(100) > cMineDudPercent) then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear)
- end
- else
- begin
- vg:= AddVisualGear(hwRound(Gear^.X) - 4 + Random(8), hwRound(Gear^.Y) - 4 - Random(4), vgtSmoke);
- if vg <> nil then
- vg^.Scale:= 0.5;
- PlaySound(sndVaporize);
- Gear^.Health := 0;
- Gear^.Damage := 0;
- Gear^.State := Gear^.State and (not gstAttacking)
- end;
- exit
- end;
- dec(Gear^.Timer);
- end
- else // gsttmpFlag = 0
- if (TurnTimeLeft = 0)
- or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime))
- or (Gear^.Hedgehog^.Gear = nil) then
- Gear^.State := Gear^.State or gsttmpFlag;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSMine(Gear: PGear);
-begin
- // TODO: do real calculation?
- if TestCollisionXwithGear(Gear, 2)
- or (TestCollisionYwithGear(Gear, -2) <> 0)
- or TestCollisionXwithGear(Gear, -2)
- or (TestCollisionYwithGear(Gear, 2) <> 0) then
- begin
- if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
- begin
- PlaySound(sndRopeAttach);
- Gear^.dX:= _0;
- Gear^.dY:= _0;
- AddGearCI(Gear);
- end;
- end
- else
- begin
- DeleteCI(Gear);
- doStepFallingGear(Gear);
- AllInactive := false;
- CalcRotationDirAngle(Gear);
- end;
-
- if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
- begin
- if ((Gear^.State and gstAttacking) = 0) then
- begin
- if ((GameTicks and $1F) = 0) then
- if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then
- Gear^.State := Gear^.State or gstAttacking
- end
- else // gstAttacking <> 0
- begin
- AllInactive := false;
- if Gear^.Timer = 0 then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear);
- exit
- end else
- if (Gear^.Timer and $FF) = 0 then
- PlaySound(sndMineTick);
-
- dec(Gear^.Timer);
- end
- end
- else // gsttmpFlag = 0
- if (TurnTimeLeft = 0)
- or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime))
- or (Gear^.Hedgehog^.Gear = nil) then
- Gear^.State := Gear^.State or gsttmpFlag;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepDynamite(Gear: PGear);
-begin
- doStepFallingGear(Gear);
- AllInactive := false;
- if Gear^.Timer mod 166 = 0 then
- inc(Gear^.Tag);
- if Gear^.Timer = 1000 then // might need better timing
- makeHogsWorry(Gear^.X, Gear^.Y, 75);
- if Gear^.Timer = 0 then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 75, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear);
- exit
- end;
- dec(Gear^.Timer);
-end;
-
-///////////////////////////////////////////////////////////////////////////////
-
-procedure doStepRollingBarrel(Gear: PGear);
-var
- i: LongInt;
- particle: PVisualGear;
- dxdy: hwFloat;
-begin
- if (Gear^.dY.QWordValue = 0) and (Gear^.dY.QWordValue = 0) and (TestCollisionYwithGear(Gear, 1) = 0) then
- SetLittle(Gear^.dY);
- Gear^.State := Gear^.State or gstAnimation;
- if Gear^.Health < cBarrelHealth then Gear^.State:= Gear^.State and not gstFrozen;
-
- if ((Gear^.dX.QWordValue <> 0)
- or (Gear^.dY.QWordValue <> 0)) then
- begin
- DeleteCI(Gear);
- AllInactive := false;
- dxdy:= hwAbs(Gear^.dX)+hwAbs(Gear^.dY);
- doStepFallingGear(Gear);
- if (Gear^.State and gstCollision <> 0) and(dxdy > _0_4) then
- begin
- if (TestCollisionYwithGear(Gear, 1) <> 0) then
- begin
- Gear^.State := Gear^.State or gsttmpFlag;
- for i:= min(12, hwRound(dxdy*_10)) downto 0 do
- begin
- particle := AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12,vgtDust);
- if particle <> nil then
- particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480)
- end
- end;
- inc(Gear^.Damage, hwRound(dxdy * _50))
- end;
- CalcRotationDirAngle(Gear);
- //CheckGearDrowning(Gear)
- end
- else
- begin
- Gear^.State := Gear^.State or gsttmpFlag;
- AddGearCI(Gear)
- end;
-
-(*
-Attempt to make a barrel knock itself over an edge. Would need more checks to avoid issues like burn damage
- begin
- x:= hwRound(Gear^.X);
- y:= hwRound(Gear^.Y);
- if (((y+1) and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
- if (Land[y+1, x] = 0) then
- begin
- if (((y+1) and LAND_HEIGHT_MASK) = 0) and (((x+Gear^.Radius-2) and LAND_WIDTH_MASK) = 0) and (Land[y+1, x+Gear^.Radius-2] = 0) then
- Gear^.dX:= -_0_08
- else if (((y+1 and LAND_HEIGHT_MASK)) = 0) and (((x-(Gear^.Radius-2)) and LAND_WIDTH_MASK) = 0) and (Land[y+1, x-(Gear^.Radius-2)] = 0) then
- Gear^.dX:= _0_08;
- end;
- if Gear^.dX.QWordValue = 0 then AddGearCI(Gear)
- end; *)
-
- if not Gear^.dY.isNegative and (Gear^.dY < _0_001) and (TestCollisionYwithGear(Gear, 1) <> 0) then
- Gear^.dY := _0;
- if hwAbs(Gear^.dX) < _0_001 then
- Gear^.dX := _0;
-
- if (Gear^.Health > 0) and ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
- if (cBarrelHealth div Gear^.Health) > 2 then
- AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
- else
- AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
- dec(Gear^.Health, Gear^.Damage);
- Gear^.Damage := 0;
- if Gear^.Health <= 0 then
- doStepCase(Gear);
-end;
-
-procedure doStepCase(Gear: PGear);
-var
- i, x, y: LongInt;
- k: TGearType;
- dX, dY: HWFloat;
- hog: PHedgehog;
- sparkles: PVisualGear;
- gi: PGear;
-begin
- k := Gear^.Kind;
-
- if (Gear^.Message and gmDestroy) > 0 then
- begin
- DeleteGear(Gear);
- FreeActionsList;
- SetAllToActive;
- // something (hh, mine, etc...) could be on top of the case
- with CurrentHedgehog^ do
- if Gear <> nil then
- Gear^.Message := Gear^.Message and (not (gmLJump or gmHJump));
- exit
- end;
- if (k = gtExplosives) and (Gear^.Health < cBarrelHealth) then Gear^.State:= Gear^.State and not gstFrozen;
-
- if ((k <> gtExplosives) and (Gear^.Damage > 0)) or ((k = gtExplosives) and (Gear^.Health<=0)) then
- begin
- x := hwRound(Gear^.X);
- y := hwRound(Gear^.Y);
- hog:= Gear^.Hedgehog;
-
- DeleteGear(Gear);
- // <-- delete gear!
-
- if k = gtCase then
- begin
- doMakeExplosion(x, y, 25, hog, EXPLAutoSound);
- for i:= 0 to 63 do
- AddGear(x, y, gtFlame, 0, _0, _0, 0);
- end
- else if k = gtExplosives then
- begin
- doMakeExplosion(x, y, 75, hog, EXPLAutoSound);
- for i:= 0 to 31 do
- begin
- dX := AngleCos(i * 64) * _0_5 * (getrandomf + _1);
- dY := AngleSin(i * 64) * _0_5 * (getrandomf + _1);
- AddGear(x, y, gtFlame, 0, dX, dY, 0);
- AddGear(x, y, gtFlame, gstTmpFlag, -dX, -dY, 0);
- end
- end;
- exit
- end;
-
- if k = gtExplosives then
- begin
- //if V > _0_03 then Gear^.State:= Gear^.State or gstAnimation;
- if (hwAbs(Gear^.dX) > _0_15) or ((hwAbs(Gear^.dY) > _0_15) and (hwAbs(Gear^.dX) > _0_02)) then
- begin
- Gear^.doStep := @doStepRollingBarrel;
- exit;
- end
- else Gear^.dX:= _0;
-
- if ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
- if (cBarrelHealth div Gear^.Health) > 2 then
- AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
- else
- AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
- dec(Gear^.Health, Gear^.Damage);
- Gear^.Damage := 0;
- end
- else
- begin
- if (Gear^.Pos <> posCaseHealth) and (GameTicks and $1FFF = 0) then // stir 'em up periodically
- begin
- gi := GearsList;
- while gi <> nil do
- begin
- if gi^.Kind = gtGenericFaller then
- begin
- gi^.Active:= true;
- gi^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
- gi^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
- gi^.dX:= _90-(GetRandomf*_360);
- gi^.dY:= _90-(GetRandomf*_360)
- end;
- gi := gi^.NextGear
- end
- end;
-
- if Gear^.Timer = 500 then
- begin
-(* Can't make sparkles team coloured without working out what the next team is going to be. This should be solved, really, since it also screws up
- voices. Reinforcements voices is heard for active team, not team-to-be. Either that or change crate spawn from end of turn to start, although that
- has its own complexities. *)
- // Abuse a couple of gear values to track origin
- Gear^.Angle:= hwRound(Gear^.Y);
- Gear^.Tag:= random(2);
- inc(Gear^.Timer)
- end;
- if Gear^.Timer < 1833 then inc(Gear^.Timer);
- if Gear^.Timer = 1000 then
- begin
- sparkles:= AddVisualGear(hwRound(Gear^.X), Gear^.Angle, vgtDust, 1);
- if sparkles <> nil then
- begin
- sparkles^.dX:= 0;
- sparkles^.dY:= 0;
- sparkles^.Angle:= 270;
- if Gear^.Tag = 1 then
- sparkles^.Tint:= $3744D7FF
- else sparkles^.Tint:= $FAB22CFF
- end;
- end;
- if Gear^.Timer < 1000 then
- begin
- AllInactive:= false;
- exit
- end
- end;
-
-
- if (Gear^.dY.QWordValue <> 0)
- or (TestCollisionYwithGear(Gear, 1) = 0) then
- begin
- AllInactive := false;
-
- Gear^.dY := Gear^.dY + cGravity;
-
- if (Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, -1) <> 0) then
- Gear^.dY := _0;
-
- Gear^.Y := Gear^.Y + Gear^.dY;
-
- if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then
- SetAllHHToActive(false);
-
- if (not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0) then
- begin
- if (Gear^.dY > _0_2) and (k = gtExplosives) then
- inc(Gear^.Damage, hwRound(Gear^.dY * _70));
-
- if Gear^.dY > _0_2 then
- for i:= min(12, hwRound(Gear^.dY*_10)) downto 0 do
- AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
-
- Gear^.dY := - Gear^.dY * Gear^.Elasticity;
- if Gear^.dY > - _0_001 then
- Gear^.dY := _0
- else if Gear^.dY < - _0_03 then
- PlaySound(Gear^.ImpactSound);
- end;
- //if Gear^.dY > - _0_001 then Gear^.dY:= _0
- CheckGearDrowning(Gear);
- end;
-
- if (Gear^.dY.QWordValue = 0) then
- AddGearCI(Gear)
- else if (Gear^.dY.QWordValue <> 0) then
- DeleteCI(Gear)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-
-procedure doStepTarget(Gear: PGear);
-begin
- if (Gear^.Timer = 0) and (Gear^.Tag = 0) then
- PlaySound(sndWarp);
-
- if (Gear^.Tag = 0) and (Gear^.Timer < 1000) then
- inc(Gear^.Timer)
- else if Gear^.Tag = 1 then
- Gear^.Tag := 2
- else if Gear^.Tag = 2 then
- if Gear^.Timer > 0 then
- dec(Gear^.Timer)
- else
- begin
- DeleteGear(Gear);
- exit;
- end;
-
- doStepCase(Gear)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepIdle(Gear: PGear);
-begin
- AllInactive := false;
- dec(Gear^.Timer);
- if Gear^.Timer = 0 then
- begin
- DeleteGear(Gear);
- AfterAttack
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepShover(Gear: PGear);
-var
- HHGear: PGear;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
- HHGear^.State := HHGear^.State or gstNoDamage;
- DeleteCI(HHGear);
-
- AmmoShove(Gear, 30, 115);
-
- HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
- Gear^.Timer := 250;
- Gear^.doStep := @doStepIdle
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepWhip(Gear: PGear);
-var
- HHGear: PGear;
- i: LongInt;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
- HHGear^.State := HHGear^.State or gstNoDamage;
- DeleteCI(HHGear);
-
- for i:= 0 to 3 do
- begin
- AmmoShove(Gear, 30, 25);
- Gear^.X := Gear^.X + Gear^.dX * 5
- end;
-
- HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
-
- Gear^.Timer := 250;
- Gear^.doStep := @doStepIdle
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepFlame(Gear: PGear);
-var
- gX,gY,i: LongInt;
- sticky: Boolean;
- vgt: PVisualGear;
- tdX,tdY: HWFloat;
-begin
- sticky:= (Gear^.State and gsttmpFlag) <> 0;
- if not sticky then AllInactive := false;
-
- if TestCollisionYwithGear(Gear, 1) = 0 then
- begin
- AllInactive := false;
-
- if ((GameTicks mod 100) = 0) then
- begin
- vgt:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFire, gstTmpFlag);
- if vgt <> nil then
- begin
- vgt^.dx:= 0;
- vgt^.dy:= 0;
- vgt^.FrameTicks:= 1800 div (Gear^.Tag mod 3 + 2);
- end;
- end;
-
-
- if Gear^.dX.QWordValue > _0_01.QWordValue then
- Gear^.dX := Gear^.dX * _0_995;
-
- Gear^.dY := Gear^.dY + cGravity;
- // if sticky then Gear^.dY := Gear^.dY + cGravity;
-
- if Gear^.dY.QWordValue > _0_2.QWordValue then
- Gear^.dY := Gear^.dY * _0_995;
-
- //if sticky then Gear^.X := Gear^.X + Gear^.dX else
- Gear^.X := Gear^.X + Gear^.dX + cWindSpeed * 640;
- Gear^.Y := Gear^.Y + Gear^.dY;
-
- if (hwRound(Gear^.Y) > cWaterLine) then
- begin
- gX := hwRound(Gear^.X);
- for i:= 0 to 3 do
- AddVisualGear(gX - 16 + Random(32), cWaterLine - 16 + Random(16), vgtSteam);
- PlaySound(sndVaporize);
- DeleteGear(Gear);
- exit
- end
- end
- else
- begin
- if sticky then
- begin
- Gear^.Radius := 7;
- tdX:= Gear^.dX;
- tdY:= Gear^.dY;
- Gear^.dX.QWordValue:= 214748365;
- Gear^.dY.QWordValue:= 429496730;
- Gear^.dX.isNegative:= getrandom(2)<>1;
- Gear^.dY.isNegative:= true;
- AmmoShove(Gear, 2, 125);
- Gear^.dX:= tdX;
- Gear^.dY:= tdY;
- Gear^.Radius := 1
- end;
- if Gear^.Timer > 0 then
- begin
- dec(Gear^.Timer);
- inc(Gear^.Damage)
- end
- else
- begin
- gX := hwRound(Gear^.X);
- gY := hwRound(Gear^.Y);
- // Standard fire
- if not sticky then
- begin
- if ((GameTicks and $1) = 0) then
- begin
- Gear^.Radius := 7;
- tdX:= Gear^.dX;
- tdY:= Gear^.dY;
- Gear^.dX.QWordValue:= 214748365;
- Gear^.dY.QWordValue:= 429496730;
- Gear^.dX.isNegative:= getrandom(2)<>1;
- Gear^.dY.isNegative:= true;
- AmmoShove(Gear, 6, 100);
- Gear^.dX:= tdX;
- Gear^.dY:= tdY;
- Gear^.Radius := 1;
- end
- else if ((GameTicks and $3) = 3) then
- doMakeExplosion(gX, gY, 8, Gear^.Hedgehog, 0);//, EXPLNoDamage);
- //DrawExplosion(gX, gY, 4);
-
- if ((GameTicks and $7) = 0) and (Random(2) = 0) then
- for i:= Random(2) downto 0 do
- AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
-
- if Gear^.Health > 0 then
- dec(Gear^.Health);
- Gear^.Timer := 450 - Gear^.Tag * 8
- end
- else
- begin
- // Modified fire
- if ((GameTicks and $7FF) = 0) and ((GameFlags and gfSolidLand) = 0) then
- begin
- DrawExplosion(gX, gY, 4);
-
- for i:= Random(3) downto 0 do
- AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
- end;
-
-// This one is interesting. I think I understand the purpose, but I wonder if a bit more fuzzy of kicking could be done with getrandom.
- Gear^.Timer := 100 - Gear^.Tag * 3;
- if (Gear^.Damage > 3000+Gear^.Tag*1500) then
- Gear^.Health := 0
- end
- end
- end;
- if Gear^.Health = 0 then
- begin
- gX := hwRound(Gear^.X);
- gY := hwRound(Gear^.Y);
- if not sticky then
- begin
- if ((GameTicks and $3) = 0) and (Random(1) = 0) then
- for i:= Random(2) downto 0 do
- AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
- end
- else
- for i:= Random(3) downto 0 do
- AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
-
- DeleteGear(Gear)
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepFirePunchWork(Gear: PGear);
-var
- HHGear: PGear;
-begin
- AllInactive := false;
- if ((Gear^.Message and gmDestroy) <> 0) then
- begin
- DeleteGear(Gear);
- AfterAttack;
- exit
- end;
-
- HHGear := Gear^.Hedgehog^.Gear;
- if hwRound(HHGear^.Y) <= Gear^.Tag - 2 then
- begin
- Gear^.Tag := hwRound(HHGear^.Y);
- DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y - _1, _0_5, _0, cHHRadius * 4, 2);
- HHGear^.State := HHGear^.State or gstNoDamage;
- Gear^.Y := HHGear^.Y;
- AmmoShove(Gear, 30, 40);
- HHGear^.State := HHGear^.State and (not gstNoDamage)
- end;
-
- HHGear^.dY := HHGear^.dY + cGravity;
- if not (HHGear^.dY.isNegative) then
- begin
- HHGear^.State := HHGear^.State or gstMoving;
- DeleteGear(Gear);
- AfterAttack;
- exit
- end;
-
- if CheckLandValue(hwRound(HHGear^.X), hwRound(HHGear^.Y + HHGear^.dY + SignAs(_6,Gear^.dY)),
- lfIndestructible) then
- HHGear^.Y := HHGear^.Y + HHGear^.dY
-end;
-
-procedure doStepFirePunch(Gear: PGear);
-var
- HHGear: PGear;
-begin
- AllInactive := false;
- HHGear := Gear^.Hedgehog^.Gear;
- DeleteCI(HHGear);
- //HHGear^.X := int2hwFloat(hwRound(HHGear^.X)) - _0_5; WTF?
- HHGear^.dX := SignAs(cLittle, Gear^.dX);
-
- HHGear^.dY := - _0_3;
-
- Gear^.X := HHGear^.X;
- Gear^.dX := SignAs(_0_45, Gear^.dX);
- Gear^.dY := - _0_9;
- Gear^.doStep := @doStepFirePunchWork;
- DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y + _1, _0_5, _0, cHHRadius * 4, 5);
-
- PlaySoundV(TSound(ord(sndFirePunch1) + GetRandom(6)), HHGear^.Hedgehog^.Team^.voicepack)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-
-procedure doStepParachuteWork(Gear: PGear);
-var
- HHGear: PGear;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
-
- inc(Gear^.Timer);
-
- if (TestCollisionYwithGear(HHGear, 1) <> 0)
- or ((HHGear^.State and gstHHDriven) = 0)
- or CheckGearDrowning(HHGear)
- or ((Gear^.Message and gmAttack) <> 0) then
- begin
- with HHGear^ do
- begin
- Message := 0;
- SetLittle(dX);
- dY := _0;
- State := State or gstMoving;
- end;
- DeleteGear(Gear);
- isCursorVisible := false;
- ApplyAmmoChanges(HHGear^.Hedgehog^);
- exit
- end;
-
- HHGear^.X := HHGear^.X + cWindSpeed * 200;
-
- if (Gear^.Message and gmLeft) <> 0 then
- HHGear^.X := HHGear^.X - cMaxWindSpeed * 80
-
- else if (Gear^.Message and gmRight) <> 0 then
- HHGear^.X := HHGear^.X + cMaxWindSpeed * 80;
-
- if (Gear^.Message and gmUp) <> 0 then
- HHGear^.Y := HHGear^.Y - cGravity * 40
-
- else if (Gear^.Message and gmDown) <> 0 then
- HHGear^.Y := HHGear^.Y + cGravity * 40;
-
- // don't drift into obstacles
- if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
- HHGear^.X := HHGear^.X - int2hwFloat(hwSign(HHGear^.dX));
- HHGear^.Y := HHGear^.Y + cGravity * 100;
- Gear^.X := HHGear^.X;
- Gear^.Y := HHGear^.Y
-end;
-
-procedure doStepParachute(Gear: PGear);
-var
- HHGear: PGear;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
-
- DeleteCI(HHGear);
-
- AfterAttack;
-
- HHGear^.State := HHGear^.State and (not (gstAttacking or gstAttacked or gstMoving));
- HHGear^.Message := HHGear^.Message and (not gmAttack);
-
- Gear^.doStep := @doStepParachuteWork;
-
- Gear^.Message := HHGear^.Message;
- doStepParachuteWork(Gear)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepAirAttackWork(Gear: PGear);
-begin
- AllInactive := false;
- Gear^.X := Gear^.X + cAirPlaneSpeed * Gear^.Tag;
-
- if (Gear^.Health > 0)and(not (Gear^.X < Gear^.dX))and(Gear^.X < Gear^.dX + cAirPlaneSpeed) then
- begin
- dec(Gear^.Health);
- case Gear^.State of
- 0: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
- 1: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMine, 0, cBombsSpeed * Gear^.Tag, _0, 0);
- 2: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtNapalmBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
- 3: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtDrill, gsttmpFlag, cBombsSpeed * Gear^.Tag, _0, Gear^.Timer + 1);
- //4: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtWaterMelon, 0, cBombsSpeed *
- // Gear^.Tag, _0, 5000);
- end;
- Gear^.dX := Gear^.dX + int2hwFloat(30 * Gear^.Tag);
- StopSoundChan(Gear^.SoundChannel, 4000);
- end;
-
- if (GameTicks and $3F) = 0 then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
-
- if (hwRound(Gear^.X) > (max(LAND_WIDTH,4096)+2048)) or (hwRound(Gear^.X) < -2048) then
- begin
- // avoid to play forever (is this necessary?)
- StopSoundChan(Gear^.SoundChannel);
- DeleteGear(Gear)
- end;
-end;
-
-procedure doStepAirAttack(Gear: PGear);
-begin
- AllInactive := false;
-
- if Gear^.X.QWordValue = 0 then
- begin
- Gear^.Tag := 1;
- Gear^.X := -_2048;
- end
- else
- begin
- Gear^.Tag := -1;
- Gear^.X := int2hwFloat(max(LAND_WIDTH,4096) + 2048);
- end;
-
- Gear^.Y := int2hwFloat(topY-300);
- Gear^.dX := int2hwFloat(Gear^.Target.X - 5 * Gear^.Tag * 15);
-
- // calcs for Napalm Strike, so that it will hit the target (without wind at least :P)
- if (Gear^.State = 2) then
- Gear^.dX := Gear^.dX - cBombsSpeed * Gear^.Tag * 900
- // calcs for regular falling gears
- else if (int2hwFloat(Gear^.Target.Y) - Gear^.Y > _0) then
- Gear^.dX := Gear^.dX - cBombsSpeed * hwSqrt((int2hwFloat(Gear^.Target.Y) - Gear^.Y) * 2 /
- cGravity) * Gear^.Tag;
-
- Gear^.Health := 6;
- Gear^.doStep := @doStepAirAttackWork;
- Gear^.SoundChannel := LoopSound(sndPlane, 4000);
-
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-
-procedure doStepAirBomb(Gear: PGear);
-begin
- AllInactive := false;
- doStepFallingGear(Gear);
- if (Gear^.State and gstCollision) <> 0 then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear);
- with mobileRecord do
- if (performRumble <> nil) and (not fastUntilLag) then
- performRumble(kSystemSoundID_Vibrate);
- exit
- end;
- if (GameTicks and $3F) = 0 then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-
-procedure doStepGirder(Gear: PGear);
-var
- HHGear: PGear;
- x, y, tx, ty: hwFloat;
-begin
- AllInactive := false;
-
- HHGear := Gear^.Hedgehog^.Gear;
- tx := int2hwFloat(Gear^.Target.X);
- ty := int2hwFloat(Gear^.Target.Y);
- x := HHGear^.X;
- y := HHGear^.Y;
-
- if (Distance(tx - x, ty - y) > _256)
- or (not TryPlaceOnLand(Gear^.Target.X - SpritesData[sprAmGirder].Width div 2, Gear^.Target.Y - SpritesData[sprAmGirder].Height div 2, sprAmGirder, Gear^.State, true, false)) then
- begin
- PlaySound(sndDenied);
- HHGear^.Message := HHGear^.Message and (not gmAttack);
- HHGear^.State := HHGear^.State and (not gstAttacking);
- HHGear^.State := HHGear^.State or gstHHChooseTarget;
- isCursorVisible := true;
- DeleteGear(Gear)
- end
- else
- begin
- PlaySound(sndPlaced);
- DeleteGear(Gear);
- AfterAttack;
- end;
-
- HHGear^.State := HHGear^.State and (not (gstAttacking or gstAttacked));
- HHGear^.Message := HHGear^.Message and (not gmAttack);
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepTeleportAfter(Gear: PGear);
-var
- HHGear: PGear;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
- doStepHedgehogMoving(HHGear);
- // if not infattack mode wait for hedgehog finish falling to collect cases
- if ((GameFlags and gfInfAttack) <> 0)
- or ((HHGear^.State and gstMoving) = 0)
- or (Gear^.Hedgehog^.Gear^.Damage > 0)
- or ((HHGear^.State and gstDrowning) = 1) then
- begin
- DeleteGear(Gear);
- AfterAttack
- end
-end;
-
-procedure doStepTeleportAnim(Gear: PGear);
-begin
- if (Gear^.Hedgehog^.Gear^.Damage > 0) then
- begin
- DeleteGear(Gear);
- AfterAttack;
- end;
- inc(Gear^.Timer);
- if Gear^.Timer = 65 then
- begin
- Gear^.Timer := 0;
- inc(Gear^.Pos);
- if Gear^.Pos = 11 then
- Gear^.doStep := @doStepTeleportAfter
- end;
-end;
-
-procedure doStepTeleport(Gear: PGear);
-var
- HHGear: PGear;
-begin
- AllInactive := false;
-
- HHGear := Gear^.Hedgehog^.Gear;
- if not TryPlaceOnLand(Gear^.Target.X - SpritesData[sprHHTelepMask].Width div 2,
- Gear^.Target.Y - SpritesData[sprHHTelepMask].Height div 2,
- sprHHTelepMask, 0, false, false) then
- begin
- HHGear^.Message := HHGear^.Message and (not gmAttack);
- HHGear^.State := HHGear^.State and (not gstAttacking);
- HHGear^.State := HHGear^.State or gstHHChooseTarget;
- DeleteGear(Gear);
- isCursorVisible := true;
- PlaySound(sndDenied)
- end
- else
- begin
- DeleteCI(HHGear);
- SetAllHHToActive;
- Gear^.doStep := @doStepTeleportAnim;
-
- // copy old HH position and direction to Gear (because we need them for drawing the vanishing hog)
- Gear^.dX := HHGear^.dX;
- // retrieve the cursor direction (it was previously copied to X so it doesn't get lost)
- HHGear^.dX.isNegative := (Gear^.X.QWordValue <> 0);
- Gear^.X := HHGear^.X;
- Gear^.Y := HHGear^.Y;
- HHGear^.X := int2hwFloat(Gear^.Target.X);
- HHGear^.Y := int2hwFloat(Gear^.Target.Y);
- HHGear^.State := HHGear^.State or gstMoving;
- Gear^.Hedgehog^.Unplaced := false;
- isCursorVisible := false;
- playSound(sndWarp)
- end;
- Gear^.Target.X:= NoPointX
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSwitcherWork(Gear: PGear);
-var
- HHGear: PGear;
- hedgehog: PHedgehog;
- State: Longword;
-begin
- AllInactive := false;
-
- if ((Gear^.Message and (not gmSwitch)) <> 0) or (TurnTimeLeft = 0) then
- begin
- hedgehog := Gear^.Hedgehog;
- //Msg := Gear^.Message and (not gmSwitch);
- DeleteGear(Gear);
- ApplyAmmoChanges(hedgehog^);
-
- HHGear := CurrentHedgehog^.Gear;
- ApplyAmmoChanges(HHGear^.Hedgehog^);
- //HHGear^.Message := Msg;
- exit
- end;
-
- if (Gear^.Message and gmSwitch) <> 0 then
- begin
- HHGear := CurrentHedgehog^.Gear;
- HHGear^.Message := HHGear^.Message and (not gmSwitch);
- Gear^.Message := Gear^.Message and (not gmSwitch);
- State := HHGear^.State;
- HHGear^.State := 0;
- HHGear^.Z := cHHZ;
- HHGear^.Active := false;
- HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList;
-
- PlaySound(sndSwitchHog);
-
- repeat
- CurrentTeam^.CurrHedgehog := Succ(CurrentTeam^.CurrHedgehog) mod (CurrentTeam^.HedgehogsNumber);
- until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) and
- (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear^.Damage = 0) and
- (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Effects[heFrozen]=0);
-
- SwitchCurrentHedgehog(@CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog]);
- AmmoMenuInvalidated:= true;
-
- HHGear := CurrentHedgehog^.Gear;
- HHGear^.State := State;
- HHGear^.Active := true;
- FollowGear := HHGear;
- HHGear^.Z := cCurrHHZ;
- HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList;
- Gear^.X := HHGear^.X;
- Gear^.Y := HHGear^.Y
- end;
-end;
-
-procedure doStepSwitcher(Gear: PGear);
-var
- HHGear: PGear;
-begin
- Gear^.doStep := @doStepSwitcherWork;
-
- HHGear := Gear^.Hedgehog^.Gear;
- OnUsedAmmo(HHGear^.Hedgehog^);
- with HHGear^ do
- begin
- State := State and (not gstAttacking);
- Message := Message and (not gmAttack)
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepMortar(Gear: PGear);
-var
- dX, dY, gdX, gdY: hwFloat;
- i: LongInt;
-begin
- AllInactive := false;
- gdX := Gear^.dX;
- gdY := Gear^.dY;
-
- doStepFallingGear(Gear);
- if (Gear^.State and gstCollision) <> 0 then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLAutoSound);
- gdX.isNegative := not gdX.isNegative;
- gdY.isNegative := not gdY.isNegative;
- gdX:= gdX*_0_2;
- gdY:= gdY*_0_2;
-
- for i:= 0 to 4 do
- begin
- dX := gdX + rndSign(GetRandomf) * _0_03;
- dY := gdY + rndSign(GetRandomf) * _0_03;
- AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtCluster, 0, dX, dY, 25);
- end;
-
- DeleteGear(Gear);
- exit
- end;
-
- if (GameTicks and $3F) = 0 then
- begin
- if hwRound(Gear^.Y) > cWaterLine then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble)
- else AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepKamikazeWork(Gear: PGear);
-var
- i: LongWord;
- HHGear: PGear;
- sparkles: PVisualGear;
- hasWishes: boolean;
-begin
- AllInactive := false;
- hasWishes:= ((Gear^.Message and (gmPrecise or gmSwitch)) = (gmPrecise or gmSwitch));
- if hasWishes then
- Gear^.AdvBounce:= 1;
-
- HHGear := Gear^.Hedgehog^.Gear;
- if HHGear = nil then
- begin
- DeleteGear(Gear);
- exit
- end;
-
- HHGear^.State := HHGear^.State or gstNoDamage;
- DeleteCI(HHGear);
-
- Gear^.X := HHGear^.X;
- Gear^.Y := HHGear^.Y;
- if (GameTicks mod 2 = 0) and hasWishes then
- begin
- sparkles:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtDust, 1);
- if sparkles <> nil then
- begin
- sparkles^.Tint:= ((random(210)+45) shl 24) or ((random(210)+45) shl 16) or ((random(210)+45) shl 8) or $FF;
- sparkles^.Angle:= random(360);
- end
- end;
-
- i := 2;
- repeat
-
- Gear^.X := Gear^.X + HHGear^.dX;
- Gear^.Y := Gear^.Y + HHGear^.dY;
- HHGear^.X := Gear^.X;
- HHGear^.Y := Gear^.Y;
-
- inc(Gear^.Damage, 2);
-
- // if TestCollisionXwithGear(HHGear, hwSign(Gear^.dX))
- // or TestCollisionYwithGear(HHGear, hwSign(Gear^.dY)) then inc(Gear^.Damage, 3);
-
- dec(i)
- until (i = 0)
- or (Gear^.Damage > Gear^.Health);
-
- inc(upd);
- if upd > 3 then
- begin
- if Gear^.Health < 1500 then
- begin
- if Gear^.AdvBounce <> 0 then
- Gear^.Pos := 3
- else
- Gear^.Pos := 2;
- end;
-
- AmmoShove(Gear, 30, 40);
-
- DrawTunnel(HHGear^.X - HHGear^.dX * 10,
- HHGear^.Y - _2 - HHGear^.dY * 10 + hwAbs(HHGear^.dY) * 2,
- HHGear^.dX,
- HHGear^.dY,
- 20 + cHHRadius * 2,
- cHHRadius * 2 + 7);
-
- upd := 0
- end;
-
- if Gear^.Health < Gear^.Damage then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
- if hasWishes then
- for i:= 0 to 31 do
- begin
- sparkles:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot);
- if sparkles <> nil then
- with sparkles^ do
- begin
- Tint:= ((random(210)+45) shl 24) or ((random(210)+45) shl 16) or ((random(210)+45) shl 8) or $FF;
- Angle:= random(360);
- dx:= 0.001 * (random(200));
- dy:= 0.001 * (random(200));
- if random(2) = 0 then
- dx := -dx;
- if random(2) = 0 then
- dy := -dy;
- FrameTicks:= random(400) + 250
- end
- end;
- AfterAttack;
- HHGear^.Message:= HHGear^.Message or gmDestroy;
- DeleteGear(Gear);
- end
- else
- begin
- dec(Gear^.Health, Gear^.Damage);
- Gear^.Damage := 0
- end
-end;
-
-procedure doStepKamikazeIdle(Gear: PGear);
-begin
- AllInactive := false;
- dec(Gear^.Timer);
- if Gear^.Timer = 0 then
- begin
- Gear^.Pos := 1;
- PlaySoundV(sndKamikaze, Gear^.Hedgehog^.Team^.voicepack);
- Gear^.doStep := @doStepKamikazeWork
- end
-end;
-
-procedure doStepKamikaze(Gear: PGear);
-var
- HHGear: PGear;
-begin
- AllInactive := false;
-
- HHGear := Gear^.Hedgehog^.Gear;
-
- HHGear^.dX := Gear^.dX;
- HHGear^.dY := Gear^.dY;
-
- Gear^.dX := SignAs(_0_45, Gear^.dX);
- Gear^.dY := - _0_9;
-
- Gear^.Timer := 550;
-
- Gear^.doStep := @doStepKamikazeIdle
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-
-const cakeh = 27;
-var
- CakePoints: array[0..Pred(cakeh)] of record
- x, y: hwFloat;
- end;
- CakeI: Longword;
-
-procedure doStepCakeExpl(Gear: PGear);
-begin
- AllInactive := false;
-
- inc(Gear^.Tag);
- if Gear^.Tag < 2250 then
- exit;
-
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg, Gear^.Hedgehog, EXPLAutoSound);
- AfterAttack;
- DeleteGear(Gear)
-end;
-
-procedure doStepCakeDown(Gear: PGear);
-var
- gi: PGear;
- dmg, dmgBase: LongInt;
- fX, fY, tdX, tdY: hwFloat;
-begin
- AllInactive := false;
-
- inc(Gear^.Tag);
- if Gear^.Tag < 100 then
- exit;
- Gear^.Tag := 0;
-
- if Gear^.Pos = 0 then
- begin
-///////////// adapted from doMakeExplosion ///////////////////////////
- //fX:= Gear^.X;
- //fY:= Gear^.Y;
- //fX.QWordValue:= fX.QWordValue and $FFFFFFFF00000000;
- //fY.QWordValue:= fY.QWordValue and $FFFFFFFF00000000;
- fX:= int2hwFloat(hwRound(Gear^.X));
- fY:= int2hwFloat(hwRound(Gear^.Y));
- dmgBase:= cakeDmg shl 1 + cHHRadius div 2;
- gi := GearsList;
- while gi <> nil do
- begin
- if gi^.Kind = gtHedgehog then
- begin
- dmg:= 0;
- tdX:= gi^.X-fX;
- tdY:= gi^.Y-fY;
- if hwRound(hwAbs(tdX)+hwAbs(tdY)) < dmgBase then
- dmg:= dmgBase - max(hwRound(Distance(tdX, tdY)),gi^.Radius);
- if (dmg > 1) then dmg:= ModifyDamage(min(dmg div 2, cakeDmg), gi);
- if (dmg > 1) then
- if (CurrentHedgehog^.Gear = gi) and (not gi^.Invulnerable) then
- gi^.State := gi^.State or gstLoser
- else
- gi^.State := gi^.State or gstWinner;
- end;
- gi := gi^.NextGear
- end;
-//////////////////////////////////////////////////////////////////////
- Gear^.doStep := @doStepCakeExpl;
- PlaySound(sndCake)
- end
- else dec(Gear^.Pos)
-end;
-
-
-procedure doStepCakeWork(Gear: PGear);
-var
- tdx, tdy: hwFloat;
-begin
- AllInactive := false;
-
- inc(Gear^.Tag);
- if Gear^.Tag < 7 then
- exit;
-
- dec(Gear^.Health);
- Gear^.Timer := Gear^.Health*10;
- if Gear^.Health mod 100 = 0 then
- Gear^.PortalCounter:= 0;
- // This is not seconds, but at least it is *some* feedback
- if (Gear^.Health = 0) or ((Gear^.Message and gmAttack) <> 0) then
- begin
- FollowGear := Gear;
- Gear^.RenderTimer := false;
- Gear^.doStep := @doStepCakeDown;
- exit
- end;
-
- cakeStep(Gear);
-
- if Gear^.Tag = 0 then
- begin
- CakeI := (CakeI + 1) mod cakeh;
- tdx := CakePoints[CakeI].x - Gear^.X;
- tdy := - CakePoints[CakeI].y + Gear^.Y;
- CakePoints[CakeI].x := Gear^.X;
- CakePoints[CakeI].y := Gear^.Y;
- Gear^.DirAngle := DxDy2Angle(tdx, tdy);
- end;
-end;
-
-procedure doStepCakeUp(Gear: PGear);
-var
- i: Longword;
-begin
- AllInactive := false;
-
- inc(Gear^.Tag);
- if Gear^.Tag < 100 then
- exit;
- Gear^.Tag := 0;
-
- if Gear^.Pos = 6 then
- begin
- for i:= 0 to Pred(cakeh) do
- begin
- CakePoints[i].x := Gear^.X;
- CakePoints[i].y := Gear^.Y
- end;
- CakeI := 0;
- Gear^.doStep := @doStepCakeWork
- end
- else
- inc(Gear^.Pos)
-end;
-
-procedure doStepCakeFall(Gear: PGear);
-begin
- AllInactive := false;
-
- Gear^.dY := Gear^.dY + cGravity;
- if TestCollisionYwithGear(Gear, 1) <> 0 then
- Gear^.doStep := @doStepCakeUp
- else
- begin
- Gear^.Y := Gear^.Y + Gear^.dY;
- if CheckGearDrowning(Gear) then
- AfterAttack
- end
-end;
-
-procedure doStepCake(Gear: PGear);
-var
- HHGear: PGear;
-begin
- AllInactive := false;
-
- HHGear := Gear^.Hedgehog^.Gear;
- HHGear^.Message := HHGear^.Message and (not gmAttack);
- Gear^.CollisionMask:= lfNotCurrentMask;
-
- FollowGear := Gear;
-
- Gear^.doStep := @doStepCakeFall
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSeductionWork(Gear: PGear);
-var i: LongInt;
- hogs: PGearArrayS;
-begin
- AllInactive := false;
- hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Radius);
- if hogs.size > 0 then
- begin
- for i:= 0 to hogs.size - 1 do
- with hogs.ar^[i]^ do
- begin
- if hogs.ar^[i] <> CurrentHedgehog^.Gear then
- begin
- dX:= _50 * cGravity * (Gear^.X - X) / _25;
- dY:= -_450 * cGravity;
- Active:= true;
- end
- end;
- end ;
- AfterAttack;
- DeleteGear(Gear);
-(*
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
- x := hwRound(Gear^.X);
- y := hwRound(Gear^.Y);
-
- if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
- if (Land[y, x] <> 0) then
- begin
- Gear^.dX.isNegative := not Gear^.dX.isNegative;
- Gear^.dY.isNegative := not Gear^.dY.isNegative;
- Gear^.dX := Gear^.dX * _1_5;
- Gear^.dY := Gear^.dY * _1_5 - _0_3;
- AmmoShove(Gear, 0, 40);
- AfterAttack;
- DeleteGear(Gear)
- end
- else
- else
- begin
- AfterAttack;
- DeleteGear(Gear)
- end*)
-end;
-
-procedure doStepSeductionWear(Gear: PGear);
-var heart: PVisualGear;
-begin
- AllInactive := false;
- inc(Gear^.Timer);
- if Gear^.Timer > 250 then
- begin
- Gear^.Timer := 0;
- inc(Gear^.Pos);
- if Gear^.Pos = 5 then
- PlaySoundV(sndYoohoo, Gear^.Hedgehog^.Team^.voicepack)
- end;
-
- if (Gear^.Pos = 14) and (RealTicks and $3 = 0) then
- begin
- heart:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot);
- if heart <> nil then
- with heart^ do
- begin
- dx:= 0.001 * (random(200));
- dy:= 0.001 * (random(200));
- if random(2) = 0 then
- dx := -dx;
- if random(2) = 0 then
- dy := -dy;
- FrameTicks:= random(750) + 1000;
- State:= ord(sprSeduction)
- end;
- end;
-
- if Gear^.Pos = 15 then
- Gear^.doStep := @doStepSeductionWork
-end;
-
-procedure doStepSeduction(Gear: PGear);
-begin
- AllInactive := false;
- //DeleteCI(Gear^.Hedgehog^.Gear);
- Gear^.doStep := @doStepSeductionWear
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepWaterUp(Gear: PGear);
-var
- i: LongWord;
-begin
- if (Gear^.Tag = 0)
- or (cWaterLine = 0) then
- begin
- DeleteGear(Gear);
- exit
- end;
-
- AllInactive := false;
-
- inc(Gear^.Timer);
- if Gear^.Timer = 17 then
- Gear^.Timer := 0
- else
- exit;
-
- if cWaterLine > 0 then
- begin
- dec(cWaterLine);
- for i:= 0 to LAND_WIDTH - 1 do
- Land[cWaterLine, i] := 0;
- SetAllToActive
- end;
-
- dec(Gear^.Tag);
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepDrill(Gear: PGear);
-forward;
-
-procedure doStepDrillDrilling(Gear: PGear);
-var
- t: PGearArray;
- tempColl: Word;
-begin
- AllInactive := false;
- if (Gear^.Timer > 0) and (Gear^.Timer mod 10 <> 0) then
- begin
- dec(Gear^.Timer);
- exit;
- end;
-
- DrawTunnel(Gear^.X, Gear^.Y, Gear^.dX, Gear^.dY, 2, 6);
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
- if (Gear^.Timer mod 30) = 0 then
- AddVisualGear(hwRound(Gear^.X + _20 * Gear^.dX), hwRound(Gear^.Y + _20 * Gear^.dY), vgtDust);
- if (CheckGearDrowning(Gear)) then
- begin
- StopSoundChan(Gear^.SoundChannel);
- exit
- end;
-
- tempColl:= Gear^.CollisionMask;
- Gear^.CollisionMask:= $007F;
- if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) or (GameTicks > Gear^.FlightTime) then
- t := CheckGearsCollision(Gear)
- else t := nil;
- Gear^.CollisionMask:= tempColl;
- //fixes drill not exploding when touching HH bug
-
- if (Gear^.Timer = 0) or ((t <> nil) and (t^.Count <> 0))
- or ( ((Gear^.State and gsttmpFlag) = 0) and (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (not TestCollisionXWithGear(Gear, hwSign(Gear^.dX))))
-// CheckLandValue returns true if the type isn't matched
- or (not CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y), lfIndestructible)) then
- begin
- //out of time or exited ground
- StopSoundChan(Gear^.SoundChannel);
- if (Gear^.State and gsttmpFlag) <> 0 then
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound)
- else
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear);
- exit
- end
-
- else if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (not TestCollisionXWithGear(Gear, hwSign(Gear^.dX))) then
- begin
- StopSoundChan(Gear^.SoundChannel);
- Gear^.Tag := 1;
- Gear^.doStep := @doStepDrill
- end;
-
- dec(Gear^.Timer);
-end;
-
-procedure doStepDrill(Gear: PGear);
-var
- t: PGearArray;
- oldDx, oldDy: hwFloat;
- t2: hwFloat;
-begin
- AllInactive := false;
-
- if (Gear^.State and gsttmpFlag) = 0 then
- Gear^.dX := Gear^.dX + cWindSpeed;
-
- oldDx := Gear^.dX;
- oldDy := Gear^.dY;
-
- doStepFallingGear(Gear);
-
- if (GameTicks and $3F) = 0 then
- begin
- if hwRound(Gear^.Y) > cWaterLine then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble)
- else AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
- end;
-
- if ((Gear^.State and gstCollision) <> 0) then
- begin
- //hit
- Gear^.dX := oldDx;
- Gear^.dY := oldDy;
-
- if GameTicks > Gear^.FlightTime then
- t := CheckGearsCollision(Gear)
- else
- t := nil;
- if (t = nil) or (t^.Count = 0) then
- begin
- //hit the ground not the HH
- t2 := _0_5 / Distance(Gear^.dX, Gear^.dY);
- Gear^.dX := Gear^.dX * t2;
- Gear^.dY := Gear^.dY * t2;
- end
-
- else if (t <> nil) then
- begin
- //explode right on contact with HH
- if (Gear^.State and gsttmpFlag) <> 0 then
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound)
- else
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear);
- exit;
- end;
-
- Gear^.SoundChannel := LoopSound(sndDrillRocket);
- Gear^.doStep := @doStepDrillDrilling;
-
- if (Gear^.State and gsttmpFlag) <> 0 then
- gear^.RenderTimer:= true;
- if Gear^.Timer > 0 then dec(Gear^.Timer)
- end
- else if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Tag <> 0) then
- begin
- if Gear^.Timer > 0 then
- dec(Gear^.Timer)
- else
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
- DeleteGear(Gear);
- end
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepBallgunWork(Gear: PGear);
-var
- HHGear, ball: PGear;
- rx, ry: hwFloat;
- gX, gY: LongInt;
-begin
- AllInactive := false;
- dec(Gear^.Timer);
- HHGear := Gear^.Hedgehog^.Gear;
- HedgehogChAngle(HHGear);
- gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
- gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
- if (Gear^.Timer mod 100) = 0 then
- begin
- rx := rndSign(getRandomf * _0_1);
- ry := rndSign(getRandomf * _0_1);
-
- ball:= AddGear(gx, gy, gtBall, 0, SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx, AngleCos(HHGear^.Angle) * ( - _0_8) + ry, 0);
- ball^.CollisionMask:= lfNotCurrentMask;
-
- PlaySound(sndGun);
- end;
-
- if (Gear^.Timer = 0) or ((HHGear^.State and gstHHDriven) = 0) then
- begin
- DeleteGear(Gear);
- AfterAttack
- end
-end;
-
-procedure doStepBallgun(Gear: PGear);
-var
- HHGear: PGear;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
- HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown));
- HHGear^.State := HHGear^.State or gstNotKickable;
- Gear^.doStep := @doStepBallgunWork
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepRCPlaneWork(Gear: PGear);
-
-const cAngleSpeed = 3;
-var
- HHGear: PGear;
- i: LongInt;
- dX, dY: hwFloat;
- fChanged: boolean;
- trueAngle: Longword;
- t: PGear;
-begin
- AllInactive := false;
-
- HHGear := Gear^.Hedgehog^.Gear;
- FollowGear := Gear;
-
- if Gear^.Timer > 0 then
- dec(Gear^.Timer);
-
- fChanged := false;
- if ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then
- begin
- fChanged := true;
- if Gear^.Angle > 2048 then
- dec(Gear^.Angle)
- else if Gear^.Angle < 2048 then
- inc(Gear^.Angle)
- else fChanged := false
- end
- else
- begin
- if ((Gear^.Message and gmLeft) <> 0) then
- begin
- fChanged := true;
- Gear^.Angle := (Gear^.Angle + (4096 - cAngleSpeed)) mod 4096
- end;
-
- if ((Gear^.Message and gmRight) <> 0) then
- begin
- fChanged := true;
- Gear^.Angle := (Gear^.Angle + cAngleSpeed) mod 4096
- end
- end;
-
- if fChanged then
- begin
- Gear^.dX.isNegative := (Gear^.Angle > 2048);
- if Gear^.dX.isNegative then
- trueAngle := 4096 - Gear^.Angle
- else
- trueAngle := Gear^.Angle;
-
- Gear^.dX := SignAs(AngleSin(trueAngle), Gear^.dX) * _0_25;
- Gear^.dY := AngleCos(trueAngle) * -_0_25;
- end;
-
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
-
- if (GameTicks and $FF) = 0 then
- if Gear^.Timer < 3500 then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace)
- else
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
-
- if ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then
- begin
- HHGear^.Message := HHGear^.Message and (not gmAttack);
- AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
- _0_5, 0);
- dec(Gear^.Health)
- end;
-
- if ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then
- begin
- Gear^.State := Gear^.State or gsttmpFlag;
- PauseMusic;
- playSound(sndRideOfTheValkyries);
- end;
-
- // pickup bonuses
- t := CheckGearNear(Gear, gtCase, 36, 36);
- if t <> nil then
- PickUp(HHGear, t);
-
- CheckCollision(Gear);
-
- if ((Gear^.State and gstCollision) <> 0) or CheckGearDrowning(Gear) then
- begin
- StopSoundChan(Gear^.SoundChannel);
- StopSound(sndRideOfTheValkyries);
- ResumeMusic;
-
- if ((Gear^.State and gstCollision) <> 0) then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, Gear^.Hedgehog, EXPLAutoSound);
- for i:= 0 to 15 do
- begin
- dX := AngleCos(i * 64) * _0_5 * (GetRandomf + _1);
- dY := AngleSin(i * 64) * _0_5 * (GetRandomf + _1);
- AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtFlame, 0, dX, dY, 0);
- AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtFlame, 0, dX, -dY, 0);
- end;
- DeleteGear(Gear)
- end;
-
- AfterAttack;
- CurAmmoGear := nil;
- if (GameFlags and gfInfAttack) = 0 then
- begin
- if TagTurnTimeLeft = 0 then
- TagTurnTimeLeft:= TurnTimeLeft;
-
- TurnTimeLeft:= 14 * 125;
- end;
-
- HHGear^.Message := 0;
- ParseCommand('/taunt ' + #1, true)
- end
-end;
-
-procedure doStepRCPlane(Gear: PGear);
-var
- HHGear: PGear;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
- HHGear^.Message := 0;
- HHGear^.State := HHGear^.State or gstNotKickable;
- Gear^.Angle := HHGear^.Angle;
- Gear^.Tag := hwSign(HHGear^.dX);
-
- if HHGear^.dX.isNegative then
- Gear^.Angle := 4096 - Gear^.Angle;
- Gear^.doStep := @doStepRCPlaneWork
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepJetpackWork(Gear: PGear);
-var
- HHGear: PGear;
- fuel, i: LongInt;
- move: hwFloat;
- isUnderwater: Boolean;
- bubble: PVisualGear;
-begin
- isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius;
- if Gear^.Pos > 0 then
- dec(Gear^.Pos);
- AllInactive := false;
- HHGear := Gear^.Hedgehog^.Gear;
- //dec(Gear^.Timer);
- move := _0_2;
- fuel := 50;
-(*if (HHGear^.Message and gmPrecise) <> 0 then
- begin
- move:= _0_02;
- fuel:= 5;
- end;*)
- if HHGear^.Message and gmPrecise <> 0 then
- HedgehogChAngle(HHGear)
- else if Gear^.Health > 0 then
- begin
- if HHGear^.Message and gmUp <> 0 then
- begin
- if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
- begin
- if isUnderwater then
- begin
- HHGear^.dY := HHGear^.dY - (move * _0_7);
- for i:= random(10)+10 downto 0 do
- begin
- bubble := AddVisualGear(hwRound(HHGear^.X) - 8 + random(16), hwRound(HHGear^.Y) + 16 + random(8), vgtBubble);
- if bubble <> nil then
- bubble^.dY:= random(20)/10+0.1;
- end
- end
- else HHGear^.dY := HHGear^.dY - move;
- end;
- dec(Gear^.Health, fuel);
- Gear^.MsgParam := Gear^.MsgParam or gmUp;
- Gear^.Timer := GameTicks
- end;
- move.isNegative := (HHGear^.Message and gmLeft) <> 0;
- if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
- begin
- HHGear^.dX := HHGear^.dX + (move * _0_1);
- if isUnderwater then
- begin
- for i:= random(5)+5 downto 0 do
- begin
- bubble := AddVisualGear(hwRound(HHGear^.X)+random(8), hwRound(HHGear^.Y) - 8 + random(16), vgtBubble);
- if bubble <> nil then
- begin
- bubble^.dX:= (random(10)/10 + 0.02) * -1;
- if (move.isNegative) then
- begin
- bubble^.X := bubble^.X + 28;
- bubble^.dX:= bubble^.dX * (-1)
- end
- else bubble^.X := bubble^.X - 28;
- end;
- end
- end;
- dec(Gear^.Health, fuel div 5);
- Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gmLeft or gmRight));
- Gear^.Timer := GameTicks
- end
- end;
-
- // erases them all at once :-/
- if (Gear^.Timer <> 0) and (GameTicks - Gear^.Timer > 250) then
- begin
- Gear^.Timer := 0;
- Gear^.MsgParam := 0
- end;
-
- if Gear^.Health < 0 then
- Gear^.Health := 0;
-
- i:= Gear^.Health div 20;
-
- if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
- begin
- Gear^.Damage:= i;
- //AddCaption('Fuel: '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
- FreeTexture(Gear^.Tex);
- Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(i) + '%', cWhiteColor, fntSmall)
- end;
-
- if (HHGear^.Message and (gmAttack or gmUp or gmLeft or gmRight) <> 0) and
- (HHGear^.Message and gmPrecise = 0) then
- Gear^.State := Gear^.State and (not gsttmpFlag);
-
- if HHGear^.Message and gmPrecise = 0 then
- HHGear^.Message := HHGear^.Message and (not (gmUp or gmLeft or gmRight));
- HHGear^.State := HHGear^.State or gstMoving;
-
- Gear^.X := HHGear^.X;
- Gear^.Y := HHGear^.Y;
-
- if not isUnderWater and hasBorder and ((HHGear^.X < _0)
- or (hwRound(HHGear^.X) > LAND_WIDTH)) then
- HHGear^.dY.isNegative:= false;
-
- if ((Gear^.State and gsttmpFlag) = 0)
- or (HHGear^.dY < _0) then
- doStepHedgehogMoving(HHGear);
-
- if // (Gear^.Health = 0)
- (HHGear^.Damage <> 0)
- //or CheckGearDrowning(HHGear)
- or (cWaterLine + cVisibleWater * 4 < hwRound(HHGear^.Y))
- or (TurnTimeLeft = 0)
- // allow brief ground touches - to be fair on this, might need another counter
- or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and (TestCollisionYwithGear(HHGear, 1) <> 0))
- or ((Gear^.Message and gmAttack) <> 0) then
- begin
- with HHGear^ do
- begin
- Message := 0;
- Active := true;
- State := State or gstMoving
- end;
- DeleteGear(Gear);
- isCursorVisible := false;
- ApplyAmmoChanges(HHGear^.Hedgehog^);
- // if Gear^.Tex <> nil then FreeTexture(Gear^.Tex);
-
-// Gear^.Tex:= RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(round(Gear^.Health / 20)) + '%', cWhiteColor, fntSmall)
-
-//AddCaption(trmsg[sidFuel]+': '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
- end
-end;
-
-procedure doStepJetpack(Gear: PGear);
-var
- HHGear: PGear;
-begin
- Gear^.Pos:= 0;
- Gear^.doStep := @doStepJetpackWork;
-
- HHGear := Gear^.Hedgehog^.Gear;
- FollowGear := HHGear;
- AfterAttack;
- with HHGear^ do
- begin
- State := State and (not gstAttacking);
- Message := Message and (not (gmAttack or gmUp or gmPrecise or gmLeft or gmRight));
-
- if (dY < _0_1) and (dY > -_0_1) then
- begin
- Gear^.State := Gear^.State or gsttmpFlag;
- dY := dY - _0_2
- end
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepBirdyDisappear(Gear: PGear);
-begin
- AllInactive := false;
- Gear^.Pos := 0;
- if Gear^.Timer < 2000 then
- inc(Gear^.Timer, 1)
- else
- begin
- DeleteGear(Gear);
- end;
-end;
-
-procedure doStepBirdyFly(Gear: PGear);
-var
- HHGear: PGear;
- fuel, i: LongInt;
- move: hwFloat;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
- if HHGear = nil then
- begin
- DeleteGear(Gear);
- exit
- end;
-
- move := _0_2;
- fuel := 50;
-
- if Gear^.Pos > 0 then
- dec(Gear^.Pos, 1)
- else if (HHGear^.Message and (gmLeft or gmRight or gmUp)) <> 0 then
- Gear^.Pos := 500;
-
- if HHGear^.dX.isNegative then
- Gear^.Tag := -1
- else
- Gear^.Tag := 1;
-
- if (HHGear^.Message and gmUp) <> 0 then
- begin
- if (not HHGear^.dY.isNegative)
- or (HHGear^.Y > -_256) then
- HHGear^.dY := HHGear^.dY - move;
-
- dec(Gear^.Health, fuel);
- Gear^.MsgParam := Gear^.MsgParam or gmUp;
- end;
-
- if (HHGear^.Message and gmLeft) <> 0 then move.isNegative := true;
- if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
- begin
- HHGear^.dX := HHGear^.dX + (move * _0_1);
- dec(Gear^.Health, fuel div 5);
- Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gmLeft or gmRight));
- end;
-
- if Gear^.Health < 0 then
- Gear^.Health := 0;
-
- if ((GameTicks and $FF) = 0) and (Gear^.Health < 500) then
- for i:= ((500-Gear^.Health) div 250) downto 0 do
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFeather);
-
- if (HHGear^.Message and gmAttack <> 0) then
- begin
- HHGear^.Message := HHGear^.Message and (not gmAttack);
- if Gear^.FlightTime > 0 then
- begin
- AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + 32, gtEgg, 0, Gear^.dX * _0_5, Gear^.dY, 0);
- PlaySound(sndBirdyLay);
- dec(Gear^.FlightTime)
- end;
- end;
-
- if HHGear^.Message and (gmUp or gmPrecise or gmLeft or gmRight) <> 0 then
- Gear^.State := Gear^.State and (not gsttmpFlag);
-
- HHGear^.Message := HHGear^.Message and (not (gmUp or gmPrecise or gmLeft or gmRight));
- HHGear^.State := HHGear^.State or gstMoving;
-
- Gear^.X := HHGear^.X;
- Gear^.Y := HHGear^.Y - int2hwFloat(32);
- // For some reason I need to reapply followgear here, something else grabs it otherwise.
- // this is probably not needed anymore
- if not CurrentTeam^.ExtDriven then FollowGear := HHGear;
-
- if ((Gear^.State and gsttmpFlag) = 0)
- or (HHGear^.dY < _0) then
- doStepHedgehogMoving(HHGear);
-
- if (Gear^.Health = 0)
- or (HHGear^.Damage <> 0)
- or CheckGearDrowning(HHGear)
- or (TurnTimeLeft = 0)
- // allow brief ground touches - to be fair on this, might need another counter
- or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and (TestCollisionYwithGear(HHGear, 1) <> 0))
- or ((Gear^.Message and gmAttack) <> 0) then
- begin
- with HHGear^ do
- begin
- Message := 0;
- Active := true;
- State := State or gstMoving
- end;
- Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
- if HHGear^.dY < _0 then
- begin
- Gear^.dX := HHGear^.dX;
- Gear^.dY := HHGear^.dY;
- end;
- Gear^.Timer := 0;
- Gear^.doStep := @doStepBirdyDisappear;
- CurAmmoGear := nil;
- isCursorVisible := false;
- AfterAttack;
- end
-end;
-
-procedure doStepBirdyDescend(Gear: PGear);
-var
- HHGear: PGear;
-begin
- if Gear^.Timer > 0 then
- dec(Gear^.Timer, 1)
- else if Gear^.Hedgehog^.Gear = nil then
- begin
- DeleteGear(Gear);
- AfterAttack;
- exit
- end;
- HHGear := Gear^.Hedgehog^.Gear;
- HHGear^.Message := HHGear^.Message and (not (gmUp or gmPrecise or gmLeft or gmRight));
- if abs(hwRound(HHGear^.Y - Gear^.Y)) > 32 then
- begin
- if Gear^.Timer = 0 then
- Gear^.Y := Gear^.Y + _0_1
- end
- else if Gear^.Timer = 0 then
- begin
- Gear^.doStep := @doStepBirdyFly;
- HHGear^.dY := -_0_2
- end
-end;
-
-procedure doStepBirdyAppear(Gear: PGear);
-begin
- Gear^.Pos := 0;
- if Gear^.Timer < 2000 then
- inc(Gear^.Timer, 1)
- else
- begin
- Gear^.Timer := 500;
- Gear^.dX := _0;
- Gear^.dY := _0;
- Gear^.State := Gear^.State and (not gstAnimation);
- Gear^.doStep := @doStepBirdyDescend;
- end
-end;
-
-procedure doStepBirdy(Gear: PGear);
-var
- HHGear: PGear;
-begin
- gear^.State := gear^.State or gstAnimation and (not gstTmpFlag);
- Gear^.doStep := @doStepBirdyAppear;
-
- if CurrentHedgehog = nil then
- begin
- DeleteGear(Gear);
- exit
- end;
-
- HHGear := CurrentHedgehog^.Gear;
-
- if HHGear^.dX.isNegative then
- Gear^.Tag := -1
- else
- Gear^.Tag := 1;
- Gear^.Pos := 0;
- AllInactive := false;
- FollowGear := HHGear;
- with HHGear^ do
- begin
- State := State and (not gstAttacking);
- Message := Message and (not (gmAttack or gmUp or gmPrecise or gmLeft or gmRight))
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepEggWork(Gear: PGear);
-var
- vg: PVisualGear;
- i: LongInt;
-begin
- AllInactive := false;
- Gear^.dX := Gear^.dX;
- doStepFallingGear(Gear);
- // CheckGearDrowning(Gear); // already checked for in doStepFallingGear
- CalcRotationDirAngle(Gear);
-
- if (Gear^.State and gstCollision) <> 0 then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, Gear^.Hedgehog, EXPLPoisoned, $C0E0FFE0);
- PlaySound(sndEggBreak);
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
- vg := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
- if vg <> nil then
- vg^.Frame := 2;
-
- for i:= 10 downto 0 do
- begin
- vg := AddVisualGear(hwRound(Gear^.X) - 3 + Random(6), hwRound(Gear^.Y) - 3 + Random(6),
- vgtDust);
- if vg <> nil then
- vg^.dX := vg^.dX + (Gear^.dX.QWordValue / 21474836480);
- end;
-
- DeleteGear(Gear);
- exit
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doPortalColorSwitch();
-var CurWeapon: PAmmo;
-begin
- if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and ((CurrentHedgehog^.Gear^.Message and gmSwitch) <> 0) then
- with CurrentHedgehog^ do
- if (CurAmmoType = amPortalGun) then
- begin
- CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and (not gmSwitch);
-
- CurWeapon:= GetCurAmmoEntry(CurrentHedgehog^);
- if CurWeapon^.Pos <> 0 then
- CurWeapon^.Pos := 0
-
- else
- CurWeapon^.Pos := 1;
- end;
-end;
-
-procedure doStepPortal(Gear: PGear);
-var
- iterator, conPortal: PGear;
- s, r, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed,
- resetx, resety, resetdx, resetdy: hwFloat;
- sx, sy, rh, resetr: LongInt;
- hasdxy, isbullet, iscake, isCollision: Boolean;
-begin
- doPortalColorSwitch();
-
- // destroy portal if ground it was attached too is gone
- if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] <= lfAllObjMask)
- or (Gear^.Timer < 1)
- or (Gear^.Hedgehog^.Team <> CurrentHedgehog^.Team)
- or (hwRound(Gear^.Y) > cWaterLine) then
- begin
- deleteGear(Gear);
- EXIT;
- end;
-
- if (TurnTimeLeft < 1)
- or (Gear^.Health < 1) then
- dec(Gear^.Timer);
-
- if Gear^.Timer < 10000 then
- gear^.RenderTimer := true;
-
- // abort if there is no other portal connected to this one
- if (Gear^.LinkedGear = nil) then
- exit;
- if ((Gear^.LinkedGear^.Tag and 1) = 0) then // or if it's still moving;
- exit;
-
- conPortal := Gear^.LinkedGear;
-
- // check all gears for stuff to port through
- iterator := nil;
- while true do
- begin
-
- // iterate through GearsList
- if iterator = nil then
- iterator := GearsList
- else
- iterator := iterator^.NextGear;
-
- // end of list?
- if iterator = nil then
- break;
-
- // don't port portals or other gear that wouldn't make sense
- if (iterator^.Kind in [gtPortal, gtRope, gtAirAttack, gtIceGun])
- or (iterator^.PortalCounter > 32) then
- continue;
-
- // don't port hogs on rope
- // TODO: this will also prevent hogs while falling after rope use from
- // falling through portals... fix that!
-
- // check if gear fits through portal
- if (iterator^.Radius > Gear^.Radius) then
- continue;
-
- // this is the max range we accept incoming gears in
- r := Int2hwFloat(iterator^.Radius+Gear^.Radius);
-
- // too far away?
- if (iterator^.X < Gear^.X - r)
- or (iterator^.X > Gear^.X + r)
- or (iterator^.Y < Gear^.Y - r)
- or (iterator^.Y > Gear^.Y + r) then
- continue;
-
- hasdxy := (((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0)) or ((iterator^.State or gstMoving) = 0));
-
- // in case the object is not moving, let's asume it's falling towards the portal
- if not hasdxy then
- begin
- if Gear^.Y < iterator^.Y then
- continue;
- ox:= Gear^.X - iterator^.X;
- oy:= Gear^.Y - iterator^.Y;
- end
- else
- begin
- ox:= iterator^.dX;
- oy:= iterator^.dY;
- end;
-
- // cake will need extra treatment... it's so delicious and moist!
- iscake:= (iterator^.Kind = gtCake);
-
- // won't port stuff that does not move towards the front/portal entrance
- if iscake then
- begin
- if not (((iterator^.X - Gear^.X)*ox + (iterator^.Y - Gear^.Y)*oy).isNegative) then
- continue;
- end
- else
- if not ((Gear^.dX*ox + Gear^.dY*oy).isNegative) then
- continue;
-
- isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]);
-
- r:= int2hwFloat(iterator^.Radius);
-
- if not (isbullet or iscake) then
- begin
- // wow! good candidate there, let's see if the distance and direction is okay!
- if hasdxy then
- begin
- s := Distance(iterator^.dX, iterator^.dY);
- // if the resulting distance is 0 skip this gear
- if s.QWordValue = 0 then
- continue;
- s := r / s;
- ox:= iterator^.X + s * iterator^.dX;
- oy:= iterator^.Y + s * iterator^.dY;
- end
- else
- begin
- ox:= iterator^.X;
- oy:= iterator^.Y + r;
- end;
-
- if (hwRound(Distance(Gear^.X-ox,Gear^.Y-oy)) > Gear^.Radius + 1 ) then
- continue;
- end;
-
- // draw bullet trail
- if isbullet then
- spawnBulletTrail(iterator);
-
- // calc gear offset in portal vector direction
- ox := (iterator^.X - Gear^.X);
- oy := (iterator^.Y - Gear^.Y);
- poffs:= (Gear^.dX * ox + Gear^.dY * oy);
-
- if not isBullet and poffs.isNegative then
- continue;
-
- // only port bullets close to the portal
- if isBullet and (not (hwAbs(poffs) < _3)) then
- continue;
-
- //
- // gears that make it till here will definately be ported
- //
- // (but old position/movement vector might be restored in case there's
- // not enough space on the other side)
- //
-
- resetr := iterator^.Radius;
- resetx := iterator^.X;
- resety := iterator^.Y;
- resetdx := iterator^.dX;
- resetdy := iterator^.dY;
-
- // create a normal of the portal vector, but ...
- nx := Gear^.dY;
- ny := Gear^.dX;
- // ... decide where the top is based on the hog's direction when firing the portal
- if Gear^.Elasticity.isNegative then
- nx.isNegative := (not nx.isNegative)
- else
- ny.isNegative := not ny.isNegative;
-
- // calc gear offset in portal normal vector direction
- noffs:= (nx * ox + ny * oy);
-
- if isBullet and (noffs.Round >= Longword(Gear^.Radius)) then
- continue;
-
- // avoid gravity related loops of not really moving gear
- if not (iscake or isbullet)
- and (Gear^.dY.isNegative)
- and (conPortal^.dY.isNegative)
- and ((iterator^.dX.QWordValue + iterator^.dY.QWordValue) < _0_08.QWordValue)
- and (iterator^.PortalCounter > 0) then
- continue;
-
- // calc gear speed along to the vector and the normal vector of the portal
- if hasdxy then
- begin
- pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY);
- nspeed:= (nx * iterator^.dX + ny * iterator^.dY);
- end
- else
- begin
- pspeed:= hwAbs(cGravity * oy);
- nspeed:= _0;
- end;
-
- // creating normal vector of connected (exit) portal
- nx := conPortal^.dY;
- ny := conPortal^.dX;
- if conPortal^.Elasticity.isNegative then
- nx.isNegative := (not nx.isNegative)
- else
- ny.isNegative := not ny.isNegative;
-
- // inverse cake's normal movement direction,
- // as if it just walked through a hole
- //if iscake then nspeed.isNegative:= not nspeed.isNegative;
-
-//AddFileLog('poffs:'+cstr(poffs)+' noffs:'+cstr(noffs)+' pspeed:'+cstr(pspeed)+' nspeed:'+cstr(nspeed));
- iterator^.dX := -pspeed * conPortal^.dX + nspeed * nx;
- iterator^.dY := -pspeed * conPortal^.dY + nspeed * ny;
-
- // make the gear's exit position close to the portal while
- // still respecting the movement direction
-
- // determine the distance (in exit vector direction)
- // that we want the gear at
- if iscake then
- ox:= (r - _0_7)
- else
- ox:= (r * _1_5);
- s:= ox / poffs;
- poffs:= ox;
- if (nspeed.QWordValue <> 0)
- and (pspeed > _0) then
- noffs:= noffs * s * (nspeed / pspeed);
-
- // move stuff with high normal offset closer to the portal's center
- if not isbullet then
- begin
- s := hwAbs(noffs) + r - int2hwFloat(Gear^.Radius);
- if s > _0 then
- noffs:= noffs - SignAs(s,noffs)
- end;
-
- iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx;
- iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny;
-
- if not hasdxy and (not (conPortal^.dY.isNegative)) then
- begin
- iterator^.dY:= iterator^.dY + hwAbs(cGravity * (iterator^.Y - conPortal^.Y))
- end;
-
- // see if the space on the exit side actually is enough
-
- if not (isBullet or isCake) then
- begin
- // TestCollisionXwithXYShift requires a hwFloat for xShift
- ox.QWordValue := _1.QWordValue;
- ox.isNegative := not iterator^.dX.isNegative;
-
- sx := hwSign(iterator^.dX);
- sy := hwSign(iterator^.dY);
-
- if iterator^.Radius > 1 then
- iterator^.Radius := iterator^.Radius - 1;
-
- // check front
- isCollision := TestCollisionY(iterator, sy)
- or TestCollisionX(iterator, sx);
-
- if not isCollision then
- begin
- // check center area (with half the radius so that the
- // the square check won't check more pixels than we want to)
- iterator^.Radius := 1 + resetr div 2;
- rh := resetr div 4;
- isCollision := TestCollisionYwithXYShift(iterator, 0, -sy * rh, sy, false)
- or TestCollisionXwithXYShift(iterator, ox * rh, 0, sx, false);
- end;
-
- iterator^.Radius := resetr;
-
- if isCollision then
- begin
- // collision! oh crap! go back!
- iterator^.X := resetx;
- iterator^.Y := resety;
- iterator^.dX := resetdx;
- iterator^.dY := resetdy;
- continue;
- end;
- end;
-
- //
- // You're now officially portaled!
- //
-
- // Until loops are reliably broken
- if iscake then
- iterator^.PortalCounter:= 33
- else
- begin
- inc(iterator^.PortalCounter);
- iterator^.Active:= true;
- iterator^.State:= iterator^.State and (not gstHHHJump) or gstMoving;
- end;
-
- // is it worth adding an arcsin table? Just how often would we end up doing something like this?
- // SYNCED ANGLE UPDATE
- if iterator^.Kind = gtRCPlane then
- begin
- // recycling as temp vars
- resety.isNegative:= false;
- resety.QWordValue:= 4294967296 * 112;
- resetx.isNegative:= false;
- resetx.QWordValue:= 4294967296 * 35;
- resetdx.isNegative:= false;
- resetdx.QWordValue:= 4294967296 * 1152;
-
- resetdy:=hwAbs(iterator^.dX*4);
- resetdy:= resetdy + hwPow(resetdy,3)/_6 + _3 * hwPow(resetdy,5) / _40 + _5 * hwPow(resetdy,7) / resety + resetx * hwPow(resetdy,9) / resetdx;
- iterator^.Angle:= hwRound(resetdy*_2048 / _PI);
- if not iterator^.dY.isNegative then iterator^.Angle:= 2048-iterator^.Angle;
- if iterator^.dX.isNegative then iterator^.Angle:= 4096-iterator^.Angle;
- end
- // VISUAL USE OF ANGLE ONLY
- else if (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtKamikaze) and (CurAmmoGear^.Hedgehog = iterator^.Hedgehog) then
- begin
- iterator^.Angle:= DxDy2AttackAngle(iterator^.dX, iterator^.dY);
- iterator^.Angle:= 2048-iterator^.Angle;
- if iterator^.dX.isNegative then iterator^.Angle:= 4096-iterator^.Angle;
- end;
-
- if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
- and (iterator = CurrentHedgehog^.Gear)
- and (CurAmmoGear <> nil)
- and (CurAmmoGear^.Kind =gtRope) then
- CurAmmoGear^.PortalCounter:= 1;
-
- if not isbullet and (iterator^.State and gstInvisible = 0)
- and (iterator^.Kind <> gtFlake) then
- FollowGear := iterator;
-
- // store X/Y values of exit for net bullet trail
- if isbullet then
- begin
- iterator^.Elasticity:= iterator^.X;
- iterator^.Friction := iterator^.Y;
- end;
-
- if Gear^.Health > 1 then
- dec(Gear^.Health);
- end;
-end;
-
-
-
-procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
-var
- CurWeapon: PAmmo;
-begin
- if CurrentHedgehog <> nil then
- with CurrentHedgehog^ do
- begin
- CurWeapon:= GetCurAmmoEntry(CurrentHedgehog^);
- if (CurAmmoType = amPortalGun) then
- begin
- if not destroyGear then
- begin
- // switch color of ball to opposite of oldPortal
- if (oldPortal^.Tag and 2) = 0 then
- CurWeapon^.Pos:= 1
- else
- CurWeapon^.Pos:= 0;
- end;
-
- // make the ball visible
- CurWeapon^.Timer := 0;
- end
- end;
- if destroyGear then
- oldPortal^.Timer:= 0;
-end;
-
-procedure doStepMovingPortal_real(Gear: PGear);
-var
- x, y, tx, ty: LongInt;
- s: hwFloat;
-begin
- x := hwRound(Gear^.X);
- y := hwRound(Gear^.Y);
- tx := 0;
- ty := 0;
- // avoid compiler hints
-
- if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then
- begin
- Gear^.State := Gear^.State or gstCollision;
- Gear^.State := Gear^.State and (not gstMoving);
-
- if (Land[y, x] and lfBouncy <> 0)
- or (not CalcSlopeTangent(Gear, x, y, tx, ty, 255))
- or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
- begin
- loadNewPortalBall(Gear, true);
- EXIT;
- end;
-
- // making a normalized normal vector
- s := _1/DistanceI(tx,ty);
- Gear^.dX := s * ty;
- Gear^.dY := -s * tx;
-
- Gear^.DirAngle := DxDy2Angle(-Gear^.dY,Gear^.dX);
- if not Gear^.dX.isNegative then
- Gear^.DirAngle := 180-Gear^.DirAngle;
-
- if ((Gear^.LinkedGear = nil)
- or (hwRound(Distance(Gear^.X - Gear^.LinkedGear^.X,Gear^.Y-Gear^.LinkedGear^.Y)) >=Gear^.Radius*2)) then
- begin
- loadNewPortalBall(Gear, false);
- inc(Gear^.Tag);
- Gear^.doStep := @doStepPortal;
- end
- else
- loadNewPortalBall(Gear, true);
- end
-
- else if (y > cWaterLine)
- or (y < -max(LAND_WIDTH,4096))
- or (x > 2*max(LAND_WIDTH,4096))
- or (x < -max(LAND_WIDTH,4096)) then
- loadNewPortalBall(Gear, true);
-end;
-
-procedure doStepMovingPortal(Gear: PGear);
-begin
- doPortalColorSwitch();
- doStepPerPixel(Gear, @doStepMovingPortal_real, true);
- if (Gear^.Timer < 1)
- or (Gear^.Hedgehog^.Team <> CurrentHedgehog^.Team) then
- deleteGear(Gear);
-end;
-
-procedure doStepPortalShot(newPortal: PGear);
-var
- iterator: PGear;
- s: hwFloat;
- CurWeapon: PAmmo;
-begin
- s:= Distance (newPortal^.dX, newPortal^.dY);
-
- // Adds the hog speed (only that part in/directly against shot direction)
- // to the shot speed (which we triple previously btw)
- // (This is done my projecting the hog movement vector onto the shot movement vector and then adding the resulting length
- // to the scaler)
- s := (_2 * s + (newPortal^.dX * CurrentHedgehog^.Gear^.dX + newPortal^.dY * CurrentHedgehog^.Gear^.dY ) / s) / s;
- newPortal^.dX := newPortal^.dX * s;
- newPortal^.dY := newPortal^.dY * s;
-
- newPortal^.LinkedGear := nil;
-
- if CurrentHedgehog <> nil then
- with CurrentHedgehog^ do
- begin
- CurWeapon:= GetCurAmmoEntry(CurrentHedgehog^);
- // let's save the HH's dX's direction so we can decide where the "top" of the portal hole
- newPortal^.Elasticity.isNegative := CurrentHedgehog^.Gear^.dX.isNegative;
- // when doing a backjump the dx is the opposite of the facing direction
- if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then
- newPortal^.Elasticity.isNegative := not newPortal^.Elasticity.isNegative;
-
- // make portal gun look unloaded
- if (CurWeapon <> nil) and (CurAmmoType = amPortalGun) then
- CurWeapon^.Timer := CurWeapon^.Timer or 2;
-
- iterator := GearsList;
- while iterator <> nil do
- begin
- if (iterator^.Kind = gtPortal) then
- if (iterator <> newPortal) and (iterator^.Timer > 0) and (iterator^.Hedgehog = CurrentHedgehog) then
- begin
- if ((iterator^.Tag and 2) = (newPortal^.Tag and 2)) then
- begin
- iterator^.Timer:= 0;
- end
- else
- begin
- // link portals with each other
- newPortal^.LinkedGear := iterator;
- iterator^.LinkedGear := newPortal;
- iterator^.Health := newPortal^.Health;
- end;
- end;
- iterator^.PortalCounter:= 0;
- iterator := iterator^.NextGear
- end;
-
- if newPortal^.LinkedGear <> nil then
- begin
- // This jiggles gears, to ensure a portal connection just placed under a gear takes effect.
- iterator:= GearsList;
- while iterator <> nil do
- begin
- if not (iterator^.Kind in [gtPortal, gtAirAttack, gtKnife]) and ((iterator^.Hedgehog <> CurrentHedgehog)
- or ((iterator^.Message and gmAllStoppable) = 0)) then
- begin
- iterator^.Active:= true;
- if iterator^.dY.QWordValue = 0 then
- iterator^.dY.isNegative:= false;
- iterator^.State:= iterator^.State or gstMoving;
- DeleteCI(iterator);
- //inc(iterator^.dY.QWordValue,10);
- end;
- iterator:= iterator^.NextGear
- end
- end
- end;
- newPortal^.State := newPortal^.State and (not gstCollision);
- newPortal^.State := newPortal^.State or gstMoving;
- newPortal^.doStep := @doStepMovingPortal;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepPiano(Gear: PGear);
-var
- r0, r1: LongInt;
- odY: hwFloat;
-begin
- AllInactive := false;
- if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and
- ((CurrentHedgehog^.Gear^.Message and gmSlot) <> 0) then
- begin
- case CurrentHedgehog^.Gear^.MsgParam of
- 0: PlaySound(sndPiano0);
- 1: PlaySound(sndPiano1);
- 2: PlaySound(sndPiano2);
- 3: PlaySound(sndPiano3);
- 4: PlaySound(sndPiano4);
- 5: PlaySound(sndPiano5);
- 6: PlaySound(sndPiano6);
- 7: PlaySound(sndPiano7);
- else PlaySound(sndPiano8);
- end;
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtNote);
- CurrentHedgehog^.Gear^.MsgParam := 0;
- CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and (not gmSlot);
- end;
-
- if (*((Gear^.Pos = 3) and ((GameFlags and gfSolidLand) <> 0)) or*) (Gear^.Pos = 5) then
- begin
- Gear^.dY := Gear^.dY + cGravity * 2;
- Gear^.Y := Gear^.Y + Gear^.dY;
- if CheckGearDrowning(Gear) then
- begin
- Gear^.Y:= Gear^.Y + _50;
- OnUsedAmmo(CurrentHedgehog^);
- if CurrentHedgehog^.Gear <> nil then
- begin
- // Drown the hedgehog. Could also just delete it, but hey, this gets a caption
- CurrentHedgehog^.Gear^.Active := true;
- CurrentHedgehog^.Gear^.X := Gear^.X;
- CurrentHedgehog^.Gear^.Y := int2hwFloat(cWaterLine+cVisibleWater)+_128;
- CurrentHedgehog^.Unplaced := false;
- if TagTurnTimeLeft = 0 then
- TagTurnTimeLeft:= TurnTimeLeft;
- TurnTimeLeft:= 0
- end;
- ResumeMusic
- end;
- exit
- end;
-
- odY:= Gear^.dY;
- doStepFallingGear(Gear);
-
- if (Gear^.State and gstDrowning) <> 0 then
- begin
- Gear^.Y:= Gear^.Y + _50;
- OnUsedAmmo(CurrentHedgehog^);
- if CurrentHedgehog^.Gear <> nil then
- begin
- // Drown the hedgehog. Could also just delete it, but hey, this gets a caption
- CurrentHedgehog^.Gear^.Active := true;
- CurrentHedgehog^.Gear^.X := Gear^.X;
- CurrentHedgehog^.Gear^.Y := int2hwFloat(cWaterLine+cVisibleWater)+_128;
- CurrentHedgehog^.Unplaced := false;
- if TagTurnTimeLeft = 0 then
- TagTurnTimeLeft:= TurnTimeLeft;
- TurnTimeLeft:= 0
- end;
- ResumeMusic
- end
- else if (Gear^.State and gstCollision) <> 0 then
- begin
- r0 := GetRandom(21);
- r1 := GetRandom(21);
- doMakeExplosion(hwRound(Gear^.X) - 30 - r0, hwRound(Gear^.Y) + 40, 40 + r1, Gear^.Hedgehog, 0);
- doMakeExplosion(hwRound(Gear^.X) + 30 + r1, hwRound(Gear^.Y) + 40, 40 + r0, Gear^.Hedgehog, 0);
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 80 + r0, Gear^.Hedgehog, EXPLAutoSound);
- for r0:= 0 to 4 do
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtNote);
- Gear^.dY := cGravity * 2 - odY;
- Gear^.Pos := Gear^.Pos + 1;
- end
- else
- Gear^.dY := Gear^.dY + cGravity * 2;
- // let it fall faster so itdoesn't take too long for the whole attack
-end;
-
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSineGunShotWork(Gear: PGear);
-var
- x, y, rX, rY, t, tmp, initHealth: LongInt;
- oX, oY, ldX, ldY, sdX, sdY, sine, lx, ly, amp: hwFloat;
- justCollided: boolean;
-begin
- AllInactive := false;
- initHealth := Gear^.Health;
- lX := Gear^.X;
- lY := Gear^.Y;
- ldX := Gear^.dX;
- ldY := Gear^.dY;
- sdy := _0_5/Distance(Gear^.dX,Gear^.dY);
- ldX := ldX * sdy;
- ldY := ldY * sdy;
- sdY := hwAbs(ldX) + hwAbs(ldY);
- sdX := _1 - hwAbs(ldX/sdY);
- sdY := _1 - hwAbs(ldY/sdY);
- if (ldX.isNegative = ldY.isNegative) then
- sdY := -sdY;
-
- // initial angle depends on current GameTicks
- t := getRandom(4096);
-
-
- // used for a work-around detection of area that is within land array, but outside borders
- justCollided := false;
-
- repeat
- lX := lX + ldX;
- lY := lY + ldY;
- oX := Gear^.X;
- oY := Gear^.Y;
- rX := hwRound(oX);
- rY := hwRound(oY);
- tmp := t mod 4096;
- amp := _128 * (_1 - hwSqr(int2hwFloat(Gear^.Health)/initHealth));
- sine := amp * AngleSin(tmp mod 2048);
- sine.isNegative := (tmp < 2048);
- inc(t,Gear^.Health div 313);
- Gear^.X := lX + (sine * sdX);
- Gear^.Y := ly + (sine * sdY);
- Gear^.dX := Gear^.X - oX;
- Gear^.dY := Gear^.Y - oY;
-
- x := hwRound(Gear^.X);
- y := hwRound(Gear^.Y);
-
- // if borders are on, stop outside land array
- if hasBorder and (((x and LAND_WIDTH_MASK) <> 0) or ((y and LAND_HEIGHT_MASK) <> 0)) then
- begin
- Gear^.Damage := 0;
- Gear^.Health := 0;
- end
- else
- begin
- if (rY <= cWaterLine) or (y <= cWaterLine) then
- begin
- if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0)
- and (Land[y, x] <> 0) then
- begin
- if justCollided then
- begin
- Gear^.Damage := 0;
- Gear^.Health := 0;
- end
- else
- begin
- inc(Gear^.Damage,3);
- justCollided := true;
- end;
- end
- else
- justCollided := false;
-
- // kick nearby hogs, dig tunnel and add some fire
- // if at least 5 collisions occured
- if Gear^.Damage > 0 then
- begin
- DrawExplosion(rX,rY,Gear^.Radius);
-
- // kick nearby hogs
- AmmoShove(Gear, 35, 50);
-
- dec(Gear^.Health, Gear^.Damage);
- Gear^.Damage := 0;
-
- // add some fire to the tunnel
- if getRandom(6) = 0 then
- begin
- tmp:= GetRandom(2 * Gear^.Radius);
- AddGear(x - Gear^.Radius + tmp, y - GetRandom(Gear^.Radius + 1), gtFlame, gsttmpFlag, _0, _0, 0)
- end
- end;
-
- if random(100) = 0 then
- AddVisualGear(x, y, vgtSmokeTrace);
- end
- else dec(Gear^.Health, 5); // if underwater get additional damage
- end;
-
- dec(Gear^.Health);
-
- // decrease bullet size towards the end
- if (Gear^.Radius > 4) then
- begin
- if (Gear^.Health <= (initHealth div 3)) then
- dec(Gear^.Radius)
- end
- else if (Gear^.Radius > 3) then
- begin
- if (Gear^.Health <= (initHealth div 4)) then
- dec(Gear^.Radius)
- end
- else if (Gear^.Radius > 2) then begin
- if (Gear^.Health <= (initHealth div 5)) then
- dec(Gear^.Radius)
- end
- else if (Gear^.Radius > 1) then
- begin
- if (Gear^.Health <= (initHealth div 6)) then
- dec(Gear^.Radius)
- end;
-
- until (Gear^.Health <= 0);
-
- DeleteGear(Gear);
- AfterAttack;
-end;
-
-procedure doStepSineGunShot(Gear: PGear);
-var
- HHGear: PGear;
-begin
- PlaySound(sndSineGun);
-
- // push the shooting Hedgehog back
- HHGear := CurrentHedgehog^.Gear;
- Gear^.dX.isNegative := not Gear^.dX.isNegative;
- Gear^.dY.isNegative := not Gear^.dY.isNegative;
- HHGear^.dX := Gear^.dX;
- HHGear^.dY := Gear^.dY;
- AmmoShove(Gear, 0, 80);
- Gear^.dX.isNegative := not Gear^.dX.isNegative;
- Gear^.dY.isNegative := not Gear^.dY.isNegative;
-
- Gear^.doStep := @doStepSineGunShotWork;
- with mobileRecord do
- if (performRumble <> nil) and (not fastUntilLag) then
- performRumble(kSystemSoundID_Vibrate);
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepFlamethrowerWork(Gear: PGear);
-var
- HHGear, flame: PGear;
- rx, ry, speed: hwFloat;
- i, gX, gY: LongInt;
-begin
- AllInactive := false;
- HHGear := Gear^.Hedgehog^.Gear;
- HedgehogChAngle(HHGear);
- gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
- gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
-
- if (GameTicks and $FF) = 0 then
- begin
- if (HHGear^.Message and gmRight) <> 0 then
- begin
- if HHGear^.dX.isNegative and (Gear^.Tag < 20) then
- inc(Gear^.Tag)
- else if Gear^.Tag > 5 then
- dec(Gear^.Tag);
- end
- else if (HHGear^.Message and gmLeft) <> 0 then
- begin
- if HHGear^.dX.isNegative and (Gear^.Tag > 5) then
- dec(Gear^.Tag)
- else if Gear^.Tag < 20 then
- inc(Gear^.Tag);
- end
- end;
-
- dec(Gear^.Timer);
- if Gear^.Timer = 0 then
- begin
- dec(Gear^.Health);
- if (Gear^.Health mod 5) = 0 then
- begin
- rx := rndSign(getRandomf * _0_1);
- ry := rndSign(getRandomf * _0_1);
- speed := _0_5 * (_10 / Gear^.Tag);
-
- flame:= AddGear(gx, gy, gtFlame, gstTmpFlag,
- SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
- AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
- flame^.CollisionMask:= lfNotCurrentMask;
-
- if (Gear^.Health mod 30) = 0 then
- begin
- flame:= AddGear(gx, gy, gtFlame, 0,
- SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
- AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
- flame^.CollisionMask:= lfNotCurrentMask;
- end
- end;
- Gear^.Timer:= Gear^.Tag
- end;
-
- if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) then
- begin
- DeleteGear(Gear);
- AfterAttack
- end
- else
- begin
- i:= Gear^.Health div 5;
- if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
- begin
- Gear^.Damage:= i;
- FreeTexture(Gear^.Tex);
- Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(i) +
- '%', cWhiteColor, fntSmall)
- end
- end
-end;
-
-procedure doStepFlamethrower(Gear: PGear);
-var
- HHGear: PGear;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
- HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown or gmLeft or gmRight));
- HHGear^.State := HHGear^.State or gstNotKickable;
- Gear^.doStep := @doStepFlamethrowerWork
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepLandGunWork(Gear: PGear);
-var
- HHGear, land: PGear;
- rx, ry, speed: hwFloat;
- i, gX, gY: LongInt;
-begin
- AllInactive := false;
- HHGear := Gear^.Hedgehog^.Gear;
- HedgehogChAngle(HHGear);
- gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
- gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
-
- if (GameTicks and $FF) = 0 then
- begin
- if (HHGear^.Message and gmRight) <> 0 then
- begin
- if HHGear^.dX.isNegative and (Gear^.Tag < 20) then
- inc(Gear^.Tag)
- else if Gear^.Tag > 5 then
- dec(Gear^.Tag);
- end
- else if (HHGear^.Message and gmLeft) <> 0 then
- begin
- if HHGear^.dX.isNegative and (Gear^.Tag > 5) then
- dec(Gear^.Tag)
- else if Gear^.Tag < 20 then
- inc(Gear^.Tag);
- end
- end;
-
- dec(Gear^.Timer);
- if Gear^.Timer = 0 then
- begin
- dec(Gear^.Health);
-
- rx := rndSign(getRandomf * _0_1);
- ry := rndSign(getRandomf * _0_1);
- speed := (_3 / Gear^.Tag);
-
- land:= AddGear(gx, gy, gtFlake, gstTmpFlag,
- SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
- AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
- land^.CollisionMask:= lfNotCurrentMask;
-
- Gear^.Timer:= Gear^.Tag
- end;
-
- if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) or ((HHGear^.Message and gmAttack) <> 0) then
- begin
- HHGear^.Message:= HHGear^.Message and (not gmAttack);
- DeleteGear(Gear);
- AfterAttack
- end
- else
- begin
- i:= Gear^.Health div 10;
- if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
- begin
- Gear^.Damage:= i;
- FreeTexture(Gear^.Tex);
- Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(i) +
- '%', cWhiteColor, fntSmall)
- end
- end
-end;
-
-procedure doStepLandGun(Gear: PGear);
-var
- HHGear: PGear;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
- HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown or gmLeft or gmRight or gmAttack));
- HHGear^.State := HHGear^.State or gstNotKickable;
- Gear^.doStep := @doStepLandGunWork
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepPoisonCloud(Gear: PGear);
-begin
- if Gear^.Timer = 0 then
- begin
- DeleteGear(Gear);
- exit
- end;
- dec(Gear^.Timer);
- Gear^.X:= Gear^.X + Gear^.dX;
- Gear^.Y:= Gear^.Y + Gear^.dY;
- Gear^.dX := Gear^.dX + cWindSpeed / 4;
- Gear^.dY := Gear^.dY + cGravity / 100;
- if (GameTicks and $FF) = 0 then
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLDontDraw or EXPLNoGfx or EXPLNoDamage or EXPLDoNotTouchAny or EXPLPoisoned);
- AllInactive:= false;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepHammer(Gear: PGear);
-var HHGear, tmp, tmp2: PGear;
- t: PGearArray;
- i: LongInt;
-begin
-HHGear:= Gear^.Hedgehog^.Gear;
-HHGear^.State:= HHGear^.State or gstNoDamage;
-DeleteCI(HHGear);
-
-t:= CheckGearsCollision(Gear);
-
-for i:= 5 downto 0 do
- AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
-
-i:= t^.Count;
-while i > 0 do
- begin
- dec(i);
- tmp:= t^.ar[i];
- if (tmp^.State and gstNoDamage) = 0 then
- if (tmp^.Kind = gtHedgehog) or (tmp^.Kind = gtMine) or (tmp^.Kind = gtExplosives) then
- begin
- //tmp^.State:= tmp^.State or gstFlatened;
- if not tmp^.Invulnerable then
- ApplyDamage(tmp, CurrentHedgehog, tmp^.Health div 3, dsUnknown);
- //DrawTunnel(tmp^.X, tmp^.Y - _1, _0, _0_5, cHHRadius * 6, cHHRadius * 3);
- tmp2:= AddGear(hwRound(tmp^.X), hwRound(tmp^.Y), gtHammerHit, 0, _0, _0, 0);
- tmp2^.LinkedGear:= tmp;
- SetAllToActive
- end
- else
- begin
- end
- end;
-
-HHGear^.State:= HHGear^.State and (not gstNoDamage);
-Gear^.Timer:= 250;
-Gear^.doStep:= @doStepIdle
-end;
-
-procedure doStepHammerHitWork(Gear: PGear);
-var
- i, j, ei: LongInt;
- HitGear: PGear;
-begin
- AllInactive := false;
- HitGear := Gear^.LinkedGear;
- dec(Gear^.Timer);
- if (HitGear = nil) or (Gear^.Timer = 0) or ((Gear^.Message and gmDestroy) <> 0) then
- begin
- DeleteGear(Gear);
- exit
- end;
-
- if (Gear^.Timer mod 5) = 0 then
- begin
- AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
-
- i := hwRound(Gear^.X) - HitGear^.Radius + 2;
- ei := hwRound(Gear^.X) + HitGear^.Radius - 2;
- for j := 1 to 4 do DrawExplosion(i - GetRandom(5), hwRound(Gear^.Y) + 6*j, 3);
- for j := 1 to 4 do DrawExplosion(ei + LongInt(GetRandom(5)), hwRound(Gear^.Y) + 6*j, 3);
- while i <= ei do
- begin
- for j := 1 to 11 do DrawExplosion(i, hwRound(Gear^.Y) + 3*j, 3);
- inc(i, 1)
- end;
-
- if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9)
- , lfIndestructible) then
- begin
- //Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + _1_9
- end;
- end;
- if TestCollisionYwithGear(Gear, 1) <> 0 then
- begin
- Gear^.dY := _0;
- SetLittle(HitGear^.dX);
- HitGear^.dY := _0;
- end
- else
- begin
- //Gear^.dY := Gear^.dY + cGravity;
- //Gear^.Y := Gear^.Y + Gear^.dY;
- if hwRound(Gear^.Y) > cWaterLine then
- Gear^.Timer := 1
- end;
-
- //Gear^.X := Gear^.X + HitGear^.dX;
- HitGear^.X := Gear^.X;
- HitGear^.Y := Gear^.Y;
- SetLittle(HitGear^.dY);
- HitGear^.Active:= true;
-end;
-
-procedure doStepHammerHit(Gear: PGear);
-var
- i, y: LongInt;
- ar: TRangeArray;
- HHGear: PGear;
-begin
- i := 0;
- HHGear := Gear^.Hedgehog^.Gear;
-
- y := hwRound(Gear^.Y) - cHHRadius * 2;
- while y < hwRound(Gear^.Y) do
- begin
- ar[i].Left := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
- ar[i].Right := hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
- inc(y, 2);
- inc(i)
- end;
-
- DrawHLinesExplosions(@ar, 3, hwRound(Gear^.Y) - cHHRadius * 2, 2, Pred(i));
- Gear^.dY := HHGear^.dY;
- DeleteCI(HHGear);
-
- doStepHammerHitWork(Gear);
- Gear^.doStep := @doStepHammerHitWork
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepResurrectorWork(Gear: PGear);
-var
- graves: PGearArrayS;
- resgear: PGear;
- hh: PHedgehog;
- i: LongInt;
-begin
- if (TurnTimeLeft > 0) then
- dec(TurnTimeLeft);
-
- AllInactive := false;
- hh := Gear^.Hedgehog;
-
- // no, you can't do that here
- {DrawCentered(hwRound(hh^.Gear^.X) + WorldDx, hwRound(hh^.Gear^.Y) + WorldDy -
- cHHRadius - 14 - hh^.HealthTagTex^.h, hh^.HealthTagTex);
- }
- (*DrawCircle(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, 1.5, 0, 0, $FF,
- $FF);*)
-
- if ((Gear^.Message and gmUp) <> 0) then
- begin
- if (GameTicks and $F) <> 0 then
- exit;
- end
- else if (GameTicks and $1FF) <> 0 then
- exit;
-
- if Gear^.Power < 45 then
- begin
- inc(Gear^.Power);
- if TestCollisionYwithGear(hh^.Gear, -1) = 0 then
- hh^.Gear^.Y := hh^.Gear^.Y - _1;
- end;
-
- graves := GearsNear(Gear^.X, Gear^.Y, gtGrave, Gear^.Radius);
-
- if graves.size = 0 then
- begin
- StopSoundChan(Gear^.SoundChannel);
- Gear^.Timer := 250;
- Gear^.doStep := @doStepIdle;
- exit;
- end;
-
- if ((Gear^.Message and gmAttack) <> 0) and (hh^.Gear^.Health > 0) and (TurnTimeLeft > 0) then
- begin
- if LongInt(graves.size) <= Gear^.Tag then Gear^.Tag:= 0;
- dec(hh^.Gear^.Health);
- if (hh^.Gear^.Health = 0) and (hh^.Gear^.Damage = 0) then
- hh^.Gear^.Damage:= 1;
- RenderHealth(hh^);
- RecountTeamHealth(hh^.Team);
- inc(graves.ar^[Gear^.Tag]^.Health);
- inc(Gear^.Tag)
-{-for i:= 0 to High(graves) do begin
- if hh^.Gear^.Health > 0 then begin
- dec(hh^.Gear^.Health);
- inc(graves[i]^.Health);
- end;
- end; -}
- end
- else
- begin
- // now really resurrect the hogs with the hp saved in the graves
- for i:= 0 to graves.size - 1 do
- if graves.ar^[i]^.Health > 0 then
- begin
- resgear := AddGear(hwRound(graves.ar^[i]^.X), hwRound(graves.ar^[i]^.Y), gtHedgehog, gstWait, _0, _0, 0);
- resgear^.Hedgehog := graves.ar^[i]^.Hedgehog;
- resgear^.Health := graves.ar^[i]^.Health;
- PHedgehog(graves.ar^[i]^.Hedgehog)^.Gear := resgear;
- graves.ar^[i]^.Message:= graves.ar^[i]^.Message or gmDestroy;
- graves.ar^[i]^.Active:= true;
- RenderHealth(resgear^.Hedgehog^);
- RecountTeamHealth(resgear^.Hedgehog^.Team);
- resgear^.Hedgehog^.Effects[heResurrected]:= 1;
- // only make hat-less hedgehogs look like zombies, preserve existing hats
-
- if resgear^.Hedgehog^.Hat = 'NoHat' then
- LoadHedgehogHat(resgear^.Hedgehog^, 'Reserved/Zombie');
- end;
-
- hh^.Gear^.dY := _0;
- hh^.Gear^.dX := _0;
- doStepHedgehogMoving(hh^.Gear);
- StopSoundChan(Gear^.SoundChannel);
- Gear^.Timer := 250;
- Gear^.doStep := @doStepIdle;
- end
- //if hh^.Gear^.Health = 0 then doStepHedgehogFree(hh^.Gear);
-end;
-
-procedure doStepResurrector(Gear: PGear);
-var
- graves: PGearArrayS;
- hh: PHedgehog;
- i: LongInt;
-begin
- AllInactive := false;
- graves := GearsNear(Gear^.X, Gear^.Y, gtGrave, Gear^.Radius);
-
- if graves.size > 0 then
- begin
- hh := Gear^.Hedgehog;
- for i:= 0 to graves.size - 1 do
- begin
- PHedgehog(graves.ar^[i]^.Hedgehog)^.Gear := nil;
- graves.ar^[i]^.Health := 0;
- end;
- Gear^.doStep := @doStepResurrectorWork;
- if ((Gear^.Message and gmAttack) <> 0) and (hh^.Gear^.Health > 0) and (TurnTimeLeft > 0) then
- begin
- if LongInt(graves.size) <= Gear^.Tag then Gear^.Tag:= 0;
- dec(hh^.Gear^.Health);
- if (hh^.Gear^.Health = 0) and (hh^.Gear^.Damage = 0) then
- hh^.Gear^.Damage:= 1;
- RenderHealth(hh^);
- RecountTeamHealth(hh^.Team);
- inc(graves.ar^[Gear^.Tag]^.Health);
- inc(Gear^.Tag)
- end
- end
- else
- begin
- StopSoundChan(Gear^.SoundChannel);
- Gear^.Timer := 250;
- Gear^.doStep := @doStepIdle;
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepNapalmBomb(Gear: PGear);
-var
- i, gX, gY: LongInt;
- dX, dY: hwFloat;
-begin
- AllInactive := false;
- doStepFallingGear(Gear);
- if (Gear^.Timer > 0) and ((Gear^.State and gstCollision) <> 0) then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, Gear^.Hedgehog, EXPLAutoSound);
- gX := hwRound(Gear^.X);
- gY := hwRound(Gear^.Y);
- for i:= 0 to 10 do
- begin
- dX := AngleCos(i * 2) * ((_0_1*(i div 5))) * (GetRandomf + _1);
- dY := AngleSin(i * 8) * _0_5 * (GetRandomf + _1);
- AddGear(gX, gY, gtFlame, 0, dX, dY, 0);
- AddGear(gX, gY, gtFlame, 0, dX, -dY, 0);
- AddGear(gX, gY, gtFlame, 0, -dX, dY, 0);
- AddGear(gX, gY, gtFlame, 0, -dX, -dY, 0);
- end;
- DeleteGear(Gear);
- exit
- end;
- if (Gear^.Timer = 0) then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, Gear^.Hedgehog, EXPLAutoSound);
- for i:= -19 to 19 do
- FollowGear := AddGear(hwRound(Gear^.X) + i div 3, hwRound(Gear^.Y), gtFlame, 0, _0_001 * i, _0, 0);
- DeleteGear(Gear);
- exit
- end;
- if (GameTicks and $3F) = 0 then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
- dec(Gear^.Timer)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepStructure(Gear: PGear);
-var
- x, y: LongInt;
- HH: PHedgehog;
- t: PGear;
-begin
- HH:= Gear^.Hedgehog;
-
- if (Gear^.State and gstMoving) <> 0 then
- begin
- AddGearCI(Gear);
- Gear^.dX:= _0;
- Gear^.dY:= _0;
- Gear^.State:= Gear^.State and (not gstMoving);
- end;
-
- dec(Gear^.Health, Gear^.Damage);
- Gear^.Damage:= 0;
-
- if Gear^.Pos = 1 then
- begin
- AddGearCI(Gear);
- AfterAttack;
- if Gear = CurAmmoGear then
- CurAmmoGear:= nil;
- if HH^.Gear <> nil then
- HideHog(HH);
- Gear^.Pos:= 2
- end;
-
- if Gear^.Pos = 2 then
- begin
- if ((GameTicks mod 100) = 0) and (Gear^.Timer < 1000) then
- begin
- if (Gear^.Timer mod 10) = 0 then
- begin
- DeleteCI(Gear);
- Gear^.Y:= Gear^.Y - _0_5;
- AddGearCI(Gear);
- end;
- inc(Gear^.Timer);
- end;
- if Gear^.Tag <= TotalRounds then
- Gear^.Pos:= 3;
- end;
-
- if Gear^.Pos = 3 then
- if Gear^.Timer < 1000 then
- begin
- if (Gear^.Timer mod 10) = 0 then
- begin
- DeleteCI(Gear);
- Gear^.Y:= Gear^.Y - _0_5;
- AddGearCI(Gear);
- end;
- inc(Gear^.Timer);
- end
- else
- begin
- if HH^.GearHidden <> nil then
- RestoreHog(HH);
- Gear^.Pos:= 4;
- end;
-
- if Gear^.Pos = 4 then
- if ((GameTicks mod 1000) = 0) and ((GameFlags and gfInvulnerable) = 0) then
- begin
- t:= GearsList;
- while t <> nil do
- begin
- if (t^.Kind = gtHedgehog) and (t^.Hedgehog^.Team^.Clan = HH^.Team^.Clan) then
- t^.Invulnerable:= true;
- t:= t^.NextGear;
- end;
- end;
-
- if Gear^.Health <= 0 then
- begin
- if HH^.GearHidden <> nil then
- RestoreHog(HH);
-
- x := hwRound(Gear^.X);
- y := hwRound(Gear^.Y);
-
- DeleteCI(Gear);
- DeleteGear(Gear);
-
- doMakeExplosion(x, y, 50, CurrentHedgehog, EXPLAutoSound);
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-(*
- TARDIS needs
- Warp in. Pos = 1
- Pause. Pos = 2
- Hide gear (TARDIS hedgehog was nil)
- Warp out. Pos = 3
- ... idle active for some time period ... Pos = 4
- Warp in. Pos = 1
- Pause. Pos = 2
- Restore gear (TARDIS hedgehog was not nil)
- Warp out. Pos = 3
-*)
-
-procedure doStepTardisWarp(Gear: PGear);
-var HH: PHedgehog;
- i,j,cnt: LongWord;
-begin
-HH:= Gear^.Hedgehog;
-if Gear^.Pos = 2 then
- begin
- StopSoundChan(Gear^.SoundChannel);
- if (Gear^.Timer = 0) then
- begin
- if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible = 0) then
- begin
- AfterAttack;
- if Gear = CurAmmoGear then CurAmmoGear := nil;
- if (HH^.Gear^.Damage = 0) and (HH^.Gear^.Health > 0) and
- ((Gear^.State and (gstMoving or gstHHDeath or gstHHGone)) = 0) then
- HideHog(HH)
- end
- //else if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible <> 0) then
- else if (HH^.GearHidden <> nil) then// and (HH^.Gear^.State and gstInvisible <> 0) then
- RestoreHog(HH)
- end;
-
- inc(Gear^.Timer);
- if (Gear^.Timer > 2000) and ((GameTicks mod 2000) = 1000) then
- begin
- Gear^.SoundChannel := LoopSound(sndTardis);
- Gear^.Pos:= 3
- end
- end;
-
-if (Gear^.Pos = 1) and (GameTicks and $1F = 0) and (Gear^.Power < 255) then
- begin
- inc(Gear^.Power);
- if (Gear^.Power = 172) and (HH^.Gear <> nil) and
- (HH^.Gear^.Damage = 0) and (HH^.Gear^.Health > 0) and
- ((HH^.Gear^.State and (gstMoving or gstHHDeath or gstHHGone)) = 0) then
- with HH^.Gear^ do
- begin
- State:= State or gstAnimation;
- Tag:= 2;
- Timer:= 0;
- Pos:= 0
- end
- end;
-if (Gear^.Pos = 3) and (GameTicks and $1F = 0) and (Gear^.Power > 0) then
- dec(Gear^.Power);
-if (Gear^.Pos = 1) and (Gear^.Power = 255) and ((GameTicks mod 2000) = 1000) then
- Gear^.Pos:= 2;
-if (Gear^.Pos = 3) and (Gear^.Power = 0) then
- begin
- StopSoundChan(Gear^.SoundChannel);
- if HH^.GearHidden = nil then
- begin
- DeleteGear(Gear);
- exit
- end;
- Gear^.Pos:= 4;
- // This condition might need tweaking
- Gear^.Timer:= GetRandom(cHedgehogTurnTime*TeamsCount)+cHedgehogTurnTime
- end;
-
-if (Gear^.Pos = 4) then
- begin
- cnt:= 0;
- for j:= 0 to Pred(HH^.Team^.Clan^.TeamsNumber) do
- for i:= 0 to Pred(HH^.Team^.Clan^.Teams[j]^.HedgehogsNumber) do
- if (HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear <> nil)
- and ((HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.State and gstDrowning) = 0)
- and (HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.Health > HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.Damage) then
- inc(cnt);
- if (cnt = 0) or SuddenDeathDmg or (Gear^.Timer = 0) then
- begin
- if HH^.GearHidden <> nil then
- FindPlace(HH^.GearHidden, false, 0, LAND_WIDTH,true);
-
- if HH^.GearHidden <> nil then
- begin
- Gear^.X:= HH^.GearHidden^.X;
- Gear^.Y:= HH^.GearHidden^.Y;
- end;
- Gear^.Timer:= 0;
-
- if (HH^.GearHidden <> nil) and (cnt = 0) then // do an emergency jump back in this case. the team needs you!
- begin
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtExplosion);
- Gear^.Pos:= 2;
- Gear^.Power:= 255;
- end
- else begin
- Gear^.SoundChannel := LoopSound(sndTardis);
- Gear^.Pos:= 1;
- Gear^.Power:= 0;
- end
- end
- else if (CurrentHedgehog^.Team^.Clan = Gear^.Hedgehog^.Team^.Clan) then dec(Gear^.Timer)
- end;
-
-end;
-
-procedure doStepTardis(Gear: PGear);
-var i,j,cnt: LongWord;
- HH: PHedgehog;
-begin
-(*
- Conditions for not activating.
- 1. Hog is last of his clan
- 2. Sudden Death is in play
- 3. Hog is a king
-*)
- HH:= Gear^.Hedgehog;
- if HH^.Gear <> nil then
- if (HH^.Gear = nil) or (HH^.King) or (SuddenDeathDmg) then
- begin
- if HH^.Gear <> nil then
- begin
- HH^.Gear^.Message := HH^.Gear^.Message and (not gmAttack);
- HH^.Gear^.State:= HH^.Gear^.State and (not gstAttacking);
- end;
- PlaySound(sndDenied);
- DeleteGear(gear);
- exit
- end;
- cnt:= 0;
- for j:= 0 to Pred(HH^.Team^.Clan^.TeamsNumber) do
- for i:= 0 to Pred(HH^.Team^.Clan^.Teams[j]^.HedgehogsNumber) do
- if (HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear <> nil)
- and ((HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.State and gstDrowning) = 0)
- and (HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.Health > HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.Damage) then
- inc(cnt);
- if cnt < 2 then
- begin
- if HH^.Gear <> nil then
- begin
- HH^.Gear^.Message := HH^.Gear^.Message and (not gmAttack);
- HH^.Gear^.State:= HH^.Gear^.State and (not gstAttacking);
- end;
- PlaySound(sndDenied);
- DeleteGear(gear);
- exit
- end;
- Gear^.SoundChannel := LoopSound(sndTardis);
- Gear^.doStep:= @doStepTardisWarp
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-
-(*
-WIP. The ice gun will have the following effects. It has been proposed by sheepluva that it take the appearance of a large freezer
-spewing ice cubes. The cubes will be visual gears only. The scatter from them and the impact snow dust should help hide imprecisions in things like the GearsNear effect.
-For now we assume a "ray" like a deagle projected out from the gun.
-All these effects assume the ray's angle is not changed and that the target type was unchanged over a number of ticks. This is a simplifying assumption for "gun was applying freezing effect to the same target".
- * When fired at water a layer of ice textured land is added above the water.
- * When fired at non-ice land (land and lfLandMask and not lfIce) the land is overlaid with a thin layer of ice textured land around that point (say, 1 or 2px into land, 1px above). For attractiveness, a slope would probably be needed.
- * When fired at a hog (land and $00FF <> 0), while the hog is targetted, the hog's state is set to frozen. As long as the gun is on the hog, a frozen hog sprite creeps up from the feet to the head. If the effect is interrupted before reaching the top, the freezing state is cleared.
-A frozen hog will animate differently. To be decided, but possibly in a similar fashion to a grave when it comes to explosions. The hog might (possibly) not be damaged by explosions. This might make freezing potentially useful for friendlies in a bad position. It might be better to allow damage though.
-A frozen hog stays frozen for a certain number of turns. Each turn the frozen overlay becomes fainter, until it fades and the hog animates normally again.
-*)
-
-
-procedure updateFuel(Gear: PGear);
-var
- t:LongInt;
-begin
- t:= Gear^.Health div 10;
- if (t <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
- begin
- Gear^.Damage:= t;
- FreeTexture(Gear^.Tex);
- Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(t) +
- '%', cWhiteColor, fntSmall)
- end;
- if Gear^.Message and (gmUp or gmDown) <> 0 then
- begin
- StopSoundChan(Gear^.SoundChannel);
- Gear^.SoundChannel:= -1;
- if GameTicks mod 40 = 0 then dec(Gear^.Health)
- end
- else
- begin
- if Gear^.SoundChannel = -1 then
- Gear^.SoundChannel := LoopSound(sndIceBeam);
- if GameTicks mod 10 = 0 then dec(Gear^.Health)
- end
-end;
-
-
-procedure updateTarget(Gear:PGear; newX, newY:HWFloat);
-// var
-// iter:PGear;
-begin
- with Gear^ do
- begin
- dX:= newX;
- dY:= newY;
- Pos:= 0;
- Target.X:= NoPointX;
- LastDamage:= nil;
- X:= Hedgehog^.Gear^.X;
- Y:= Hedgehog^.Gear^.Y;
- end;
-end;
-
-procedure doStepIceGun(Gear: PGear);
-const iceWaitCollision:Longint = 0;
-const iceCollideWithGround:Longint = 1;
-//const iceWaitNextTarget:Longint = 2;
-//const iceCollideWithHog:Longint = 4;
-const iceCollideWithWater:Longint = 5;
-//const waterFreezingTime:Longint = 500;
-const groundFreezingTime:Longint = 1000;
-const iceRadius = 32;
-const iceHeight = 40;
-var
- HHGear, iter: PGear;
- landRect: TSDL_Rect;
- ndX, ndY: hwFloat;
- i, j, t, gX, gY: LongInt;
- hogs: PGearArrayS;
- vg: PVisualGear;
-begin
- HHGear := Gear^.Hedgehog^.Gear;
- if (Gear^.Message and gmAttack <> 0) or (Gear^.Health = 0) or (HHGear = nil) or (HHGear^.Damage <> 0) or (HHGear^.dX.QWordValue > 4294967) then
- begin
- StopSoundChan(Gear^.SoundChannel);
- DeleteGear(Gear);
- AfterAttack;
- exit
- end;
- updateFuel(Gear);
-
- with Gear^ do
- begin
- HedgehogChAngle(HHGear);
- ndX:= SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _4;
- ndY:= -AngleCos(HHGear^.Angle) * _4;
- if (ndX <> dX) or (ndY <> dY) or
- ((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and
- (Target.Y and LAND_HEIGHT_MASK = 0) and ((Land[Target.Y, Target.X] = 0))) then
- begin
- updateTarget(Gear, ndX, ndY);
- Timer := iceWaitCollision;
- end
- else
- begin
- X:= X + dX;
- Y:= Y + dY;
- gX:= hwRound(X);
- gY:= hwRound(Y);
- if Target.X = NoPointX then t:= hwRound(hwSqr(X-HHGear^.X)+hwSqr(Y-HHGear^.Y));
-
- if Target.X <> NoPointX then
- begin
- CheckCollision(Gear);
- if (State and gstCollision) <> 0 then
- begin
- if Timer = iceWaitCollision then
- begin
- Timer := iceCollideWithGround;
- Power := GameTicks;
- end
- end
- else if (target.y >= cWaterLine) then
- begin
- if Timer = iceWaitCollision then
- begin
- Timer := iceCollideWithWater;
- Power := GameTicks;
- end;
- end;
-
- if (abs(gX-Target.X) < 2) and (abs(gY-Target.Y) < 2) then
- begin
- X:= HHGear^.X;
- Y:= HHGear^.Y
- end;
-
- if (Timer = iceCollideWithGround) and ((GameTicks - Power) > groundFreezingTime) then
- begin
- FillRoundInLand(target.x, target.y, iceRadius, icePixel);
- landRect.x := min(max(target.x - iceRadius, 0), LAND_WIDTH - 1);
- landRect.y := min(max(target.y - iceRadius, 0), LAND_HEIGHT - 1);
- landRect.w := min(2*iceRadius, LAND_WIDTH - landRect.x - 1);
- landRect.h := min(2*iceRadius, LAND_HEIGHT - landRect.y - 1);
- UpdateLandTexture(landRect.x, landRect.w, landRect.y, landRect.h, true);
-
- // Freeze nearby mines/explosives/cases too
- iter := GearsList;
- while iter <> nil do
- begin
- if (iter^.State and gstFrozen = 0) and
- ((iter^.Kind = gtExplosives) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine)) and
- (abs(iter^.X.Round-target.x)+abs(iter^.Y.Round-target.y)+2<2*iceRadius) and (Distance(iter^.X-int2hwFloat(target.x),iter^.Y-int2hwFloat(target.y)) nil then
- begin
- i:= random(100) + 155;
- vg^.Tint:= i shl 24 or i shl 16 or $FF shl 8 or Longword(random(200) + 55);
- vg^.Angle:= random(360);
- vg^.dx:= 0.001 * random(80);
- vg^.dy:= 0.001 * random(80)
- end
- end;
- PlaySound(sndHogFreeze);
- iter^.State:= iter^.State or gstFrozen;
- if iter^.Kind = gtMine then // dud mine block
- begin
- vg:= AddVisualGear(hwRound(iter^.X) - 4 + Random(8), hwRound(iter^.Y) - 4 - Random(4), vgtSmoke);
- if vg <> nil then
- vg^.Scale:= 0.5;
- PlaySound(sndVaporize);
- iter^.Health := 0;
- iter^.Damage := 0;
- iter^.State := iter^.State and (not gstAttacking)
- end
- else if iter^.Kind = gtCase then
- begin
- DeleteCI(iter);
- AddGearCI(iter)
- end
- else // gtExplosives
- iter^.Health:= iter^.Health + cBarrelHealth
- end;
- iter:= iter^.NextGear
- end;
-
- // FillRoundInLandWithIce(Target.X, Target.Y, iceRadius);
- SetAllHHToActive;
- Timer := iceWaitCollision;
- end;
-
- if (Timer = iceCollideWithWater) and ((GameTicks - Power) > groundFreezingTime) then
- begin
- PlaySound(sndHogFreeze);
- DrawIceBreak(Target.X, cWaterLine - iceHeight, iceRadius, iceHeight);
- SetAllHHToActive;
- Timer := iceWaitCollision;
- end;
-(*
- Any ideas for something that would look good here?
- if (Target.X <> NoPointX) and ((Timer = iceCollideWithGround) or (Timer = iceCollideWithWater)) and (GameTicks mod max((groundFreezingTime-((GameTicks - Power)*2)),2) = 0) then //and CheckLandValue(Target.X, Target.Y, lfIce) then
- begin
- vg:= AddVisualGear(Target.X+random(20)-10, Target.Y+random(40)-10, vgtDust, 1);
- if vg <> nil then
- begin
- i:= random(100) + 155;
- vg^.Tint:= IceColor or $FF;
- vg^.Angle:= random(360);
- vg^.dx:= 0.001 * random(80);
- vg^.dy:= 0.001 * random(80)
- end
- end;
-*)
-
-// freeze nearby hogs
- hogs := GearsNear(int2hwFloat(Target.X), int2hwFloat(Target.Y), gtHedgehog, Gear^.Radius*2);
- if hogs.size > 0 then
- for i:= 0 to hogs.size - 1 do
- if hogs.ar^[i] <> HHGear then
- if GameTicks mod 5 = 0 then
- begin
- hogs.ar^[i]^.Active:= true;
- if hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] < 256 then
- hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] := hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] + 1
- else if hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] = 256 then
- begin
- hogs.ar^[i]^.Hedgehog^.Effects[heFrozen]:= 200000-1;//cHedgehogTurnTime + cReadyDelay
- PlaySound(sndHogFreeze);
- end;
- end;
- inc(Pos)
- end
- else if (t > 400) and ((gY > cWaterLine) or
- (((gX and LAND_WIDTH_MASK = 0) and (gY and LAND_HEIGHT_MASK = 0))
- and (Land[gY, gX] <> 0))) then
- begin
- Target.X:= gX;
- Target.Y:= gY;
- X:= HHGear^.X;
- Y:= HHGear^.Y
- end;
- if (gX > max(LAND_WIDTH,4096)*2) or
- (gX < -max(LAND_WIDTH,4096)) or
- (gY < -max(LAND_HEIGHT,4096)) or
- (gY > max(LAND_HEIGHT,4096)+512) then
- begin
- //X:= HHGear^.X;
- //Y:= HHGear^.Y
- Target.X:= gX;
- Target.Y:= gY;
- end
- end
- end;
-end;
-
-procedure doStepAddAmmo(Gear: PGear);
-var a: TAmmoType;
- gi: PGear;
-begin
-if Gear^.Timer > 0 then dec(Gear^.Timer)
-else
- begin
- if Gear^.Pos = posCaseUtility then
- a:= GetUtility(Gear^.Hedgehog)
- else
- a:= GetAmmo(Gear^.Hedgehog);
- CheckSum:= CheckSum xor GameTicks;
- gi := GearsList;
- while gi <> nil do
- 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));
- DeleteGear(Gear)
- end;
-end;
-
-procedure doStepGenericFaller(Gear: PGear);
-begin
-if Gear^.Timer < $FFFFFFFF then
- if Gear^.Timer > 0 then
- dec(Gear^.Timer)
- else
- begin
- DeleteGear(Gear);
- exit
- end;
-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);
-var hogs: PGearArrayS;
- HHGear: PGear;
- tdX: hwFloat;
- dir: LongInt;
-begin
-doStepFallingGear(Gear);
-if Gear^.Timer > 0 then dec(Gear^.Timer);
-// creeper sleep phase
-if (Gear^.Hedgehog = nil) and (Gear^.Timer > 0) then exit;
-
-if Gear^.Hedgehog <> nil then HHGear:= Gear^.Hedgehog^.Gear
-else HHGear:= nil;
-
-// creeper boom phase
-if (Gear^.State and gstTmpFlag <> 0) then
- begin
- if (Gear^.Timer = 0) then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 300, CurrentHedgehog, EXPLAutoSound);
- DeleteGear(Gear)
- end;
- // ssssss he essssscaped
- if (Gear^.Timer > 250) and ((HHGear = nil) or
- (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) > 180) and
- (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > _180))) then
- begin
- Gear^.State:= Gear^.State and (not gstTmpFlag);
- Gear^.Timer:= 0
- end;
- exit
- end;
-
-// Search out a new target, as target seek time has expired, target is dead, target is out of range, or we did not have a target
-if (HHGear = nil) or (Gear^.Timer = 0) or
- (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) > Gear^.Angle) and
- (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > int2hwFloat(Gear^.Angle)))
- then
- begin
- hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Angle);
- if hogs.size > 1 then
- Gear^.Hedgehog:= hogs.ar^[GetRandom(hogs.size)]^.Hedgehog
- else if hogs.size = 1 then Gear^.Hedgehog:= hogs.ar^[0]^.Hedgehog
- else Gear^.Hedgehog:= nil;
- if Gear^.Hedgehog <> nil then Gear^.Timer:= 5000;
- exit
- end;
-
-// we have a target. move the creeper.
-if HHGear <> nil then
- begin
- // GOTCHA
- if ((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) < 50) and
- (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) < _50) then
- begin
- // hisssssssssss
- Gear^.State:= Gear^.State or gstTmpFlag;
- Gear^.Timer:= 1500;
- exit
- end;
- if (Gear^.State and gstMoving <> 0) then
- begin
- Gear^.dY:= _0;
- Gear^.dX:= _0;
- end
- else if (GameTicks and $FF = 0) then
- begin
- tdX:= HHGear^.X-Gear^.X;
- dir:= hwSign(tdX);
- if not TestCollisionX(Gear, dir) then
- Gear^.X:= Gear^.X + signAs(_1,tdX);
- if TestCollisionXwithXYShift(Gear, signAs(_10,tdX), 0, dir) then
- begin
- Gear^.dX:= SignAs(_0_15, tdX);
- Gear^.dY:= -_0_3;
- Gear^.State:= Gear^.State or gstMoving
- end
- end;
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepKnife(Gear: PGear);
-//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 = 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;
- Gear^.Damage:= 0;
- if Gear^.Timer > 0 then dec(Gear^.Timer);
- 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);
- AllInactive := false;
- a:= Gear^.DirAngle;
- CalcRotationDirAngle(Gear);
- Gear^.DirAngle:= a+(Gear^.DirAngle-a)*2*hwSign(Gear^.dX) // double rotation
- end
- else if (Gear^.CollisionIndex = -1) and (Gear^.Timer = 0) then
- begin
- (*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);
- if la = _10000 then
- begin
- // debug for when we couldn't get an angle
- //AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeWhite);
-*)
- Gear^.DirAngle:= DxDy2Angle(Gear^.dX, Gear^.dY) + (random(30)-15);
- if (Gear^.dX.isNegative and Gear^.dY.isNegative) or
- ((not Gear^.dX.isNegative) and (not Gear^.dY.isNegative)) then Gear^.DirAngle:= Gear^.DirAngle-90;
- // end
- // else Gear^.DirAngle:= hwFloat2Float(la)*90; // sheepluva's comment claims 45deg = 0.5 - yet orientation doesn't seem consistent?
- // AddFileLog('la: '+floattostr(la)+' DirAngle: '+inttostr(round(Gear^.DirAngle)));
- Gear^.dX:= _0;
- Gear^.dY:= _0;
- Gear^.State:= Gear^.State and (not gstMoving) or gstCollision;
- Gear^.Radius:= 16;
- if Gear^.Health > 0 then AmmoShove(Gear, Gear^.Health, 0);
- Gear^.Health:= 0;
- Gear^.Timer:= 500;
- AddGearCI(Gear)
- end
- else if GameTicks and $3F = 0 then
- begin
- if (TestCollisionYwithGear(Gear, -1) = 0)
- and (not TestCollisionXwithGear(Gear, 1))
- and (not TestCollisionXwithGear(Gear, -1))
- and (TestCollisionYwithGear(Gear, 1) = 0) then Gear^.State:= Gear^.State and (not gstCollision) or gstMoving;
- end
-end;
-(*
- This didn't end up getting used, but, who knows, might be reasonable for javellin or something
-// Make the knife initial angle based on the hog attack angle, or is that too hard?
-procedure doStepKnife(Gear: PGear);
-var t,
- gx, gy, ga, // gear x,y,angle
- lx, ly, la, // land x,y,angle
- ox, oy, // x,y offset
- w, h, // wXh of clip area
- tx, ty // tip position in sprite
- : LongInt;
- surf: PSDL_Surface;
- s: hwFloat;
-
-begin
- Gear^.dY := Gear^.dY + cGravity;
- if (GameFlags and gfMoreWind) <> 0 then
- Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density;
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
- CheckGearDrowning(Gear);
- gx:= hwRound(Gear^.X);
- gy:= hwRound(Gear^.Y);
- if Gear^.State and gstDrowning <> 0 then exit;
- with Gear^ do
- begin
- if CheckLandValue(gx, gy, lfLandMask) then
- begin
- t:= Angle + hwRound((hwAbs(dX)+hwAbs(dY)) * _10);
-
- if t < 0 then inc(t, 4096)
- else if 4095 < t then dec(t, 4096);
- Angle:= t;
-
- DirAngle:= Angle / 4096 * 360
- end
- else
- begin
-//This is the set of postions for the knife.
-//Using FlipSurface and copyToXY the knife can be written to the LandPixels at 32 positions, and an appropriate line drawn in Land.
- t:= Angle mod 1024;
- case t div 128 of
- 0: begin
- ox:= 2; oy:= 5;
- w := 25; h:= 5;
- tx:= 0; ty:= 2
- end;
- 1: begin
- ox:= 2; oy:= 15;
- w:= 24; h:= 8;
- tx:= 0; ty:= 7
- end;
- 2: begin
- ox:= 2; oy:= 27;
- w:= 23; h:= 12;
- tx:= -12; ty:= -5
- end;
- 3: begin
- ox:= 2; oy:= 43;
- w:= 21; h:= 15;
- tx:= 0; ty:= 14
- end;
- 4: begin
- ox:= 29; oy:= 8;
- w:= 19; h:= 19;
- tx:= 0; ty:= 17
- end;
- 5: begin
- ox:= 29; oy:= 32;
- w:= 15; h:= 21;
- tx:= 0; ty:= 20
- end;
- 6: begin
- ox:= 51; oy:= 3;
- w:= 11; h:= 23;
- tx:= 0; ty:= 22
- end;
- 7: begin
- ox:= 51; oy:= 34;
- w:= 7; h:= 24;
- tx:= 0; ty:= 23
- end
- end;
-
- surf:= SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, RMask, GMask, BMask, AMask);
- copyToXYFromRect(SpritesData[sprKnife].Surface, surf, ox, oy, w, h, 0, 0);
- // try to make the knife hit point first
- lx := 0;
- ly := 0;
- if CalcSlopeTangent(Gear, gx, gy, lx, ly, 255) then
- begin
- la:= vector2Angle(int2hwFloat(lx), int2hwFloat(ly));
- ga:= vector2Angle(dX, dY);
- AddFileLog('la: '+inttostr(la)+' ga: '+inttostr(ga)+' Angle: '+inttostr(Angle));
- // change to 0 to 4096 forced by LongWord in Gear
- if la < 0 then la:= 4096+la;
- if ga < 0 then ga:= 4096+ga;
- if ((Angle > ga) and (Angle < la)) or ((Angle < ga) and (Angle > la)) then
- begin
- if Angle >= 2048 then dec(Angle, 2048)
- else if Angle < 2048 then inc(Angle, 2048)
- end;
- AddFileLog('la: '+inttostr(la)+' ga: '+inttostr(ga)+' Angle: '+inttostr(Angle))
- end;
- case Angle div 1024 of
- 0: begin
- flipSurface(surf, true);
- flipSurface(surf, true);
- BlitImageAndGenerateCollisionInfo(gx-(w-tx), gy-(h-ty), w, surf)
- end;
- 1: begin
- flipSurface(surf, false);
- BlitImageAndGenerateCollisionInfo(gx-(w-tx), gy-ty, w, surf)
- end;
- 2: begin // knife was actually drawn facing this way...
- BlitImageAndGenerateCollisionInfo(gx-tx, gy-ty, w, surf)
- end;
- 3: begin
- flipSurface(surf, true);
- BlitImageAndGenerateCollisionInfo(gx-tx, gy-(h-ty), w, surf)
- end
- end;
- SDL_FreeSurface(surf);
- // this needs to calculate actual width/height + land clipping since update texture doesn't.
- // i.e. this will crash if you fire near sides of map, but until I get the blit right, not going to put real values
- UpdateLandTexture(hwRound(X)-32, 64, hwRound(Y)-32, 64, true);
- DeleteGear(Gear);
- exit
- end
- end;
-end;
-*)
diff -Nru hedgewars-0.9.19.3/hedgewars/LuaPas.pas hedgewars-0.9.20.5/hedgewars/LuaPas.pas
--- hedgewars-0.9.19.3/hedgewars/LuaPas.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/LuaPas.pas 2014-01-08 16:25:17.000000000 +0000
@@ -14,6 +14,12 @@
uses uConsts;
{.$DEFINE LUA_GETHOOK}
+const LuaLibName = {$IFDEF LUA_INTERNAL}'libhwlua'{$ELSE}'liblua'{$ENDIF};
+
+{$IFNDEF WIN32}
+ {$linklib lua}
+{$ENDIF}
+
type
size_t = Cardinal;
Psize_t = ^size_t;
@@ -22,9 +28,6 @@
lua_State = record end;
Plua_State = ^lua_State;
-{$DEFINE LuaLibName:= cLuaLibrary}
-
-
(*****************************************************************************)
(* luaconfig.h *)
(*****************************************************************************)
diff -Nru hedgewars-0.9.19.3/hedgewars/SDLMain.h hedgewars-0.9.20.5/hedgewars/SDLMain.h
--- hedgewars-0.9.19.3/hedgewars/SDLMain.h 2013-06-03 14:14:48.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/SDLMain.h 1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-/* SDLMain.m - main entry point for our Cocoa-ized SDL app
- Initial Version: Darrell Walisser
- Non-NIB-Code & other changes: Max Horn
-
- Feel free to customize this file to suit your needs
-*/
-
-#ifndef _SDLMain_h_
-#define _SDLMain_h_
-
-#import
-
-@interface SDLMain : NSObject
-@end
-
-#endif /* _SDLMain_h_ */
diff -Nru hedgewars-0.9.19.3/hedgewars/SDLMain.m hedgewars-0.9.20.5/hedgewars/SDLMain.m
--- hedgewars-0.9.19.3/hedgewars/SDLMain.m 2013-03-22 11:37:13.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/SDLMain.m 1970-01-01 00:00:00.000000000 +0000
@@ -1,385 +0,0 @@
-/* SDLMain.m - main entry point for our Cocoa-ized SDL app
- Initial Version: Darrell Walisser
- Non-NIB-Code & other changes: Max Horn
-
- Feel free to customize this file to suit your needs
-*/
-
-#include "SDL.h"
-#include "SDLMain.h"
-#include /* for MAXPATHLEN */
-#include
-
-/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
- but the method still is there and works. To avoid warnings, we declare
- it ourselves here. */
-@interface NSApplication(SDL_Missing_Methods)
-- (void)setAppleMenu:(NSMenu *)menu;
-@end
-
-/* Use this flag to determine whether we use SDLMain.nib or not */
-#define SDL_USE_NIB_FILE 0
-
-/* Use this flag to determine whether we use CPS (docking) or not */
-#define SDL_USE_CPS 1
-#ifdef SDL_USE_CPS
-/* Portions of CPS.h */
-typedef struct CPSProcessSerNum
-{
- UInt32 lo;
- UInt32 hi;
-} CPSProcessSerNum;
-
-extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
-extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
-extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
-
-#endif /* SDL_USE_CPS */
-
-static int gArgc;
-static char **gArgv;
-static BOOL gFinderLaunch;
-static BOOL gCalledAppMainline = FALSE;
-
-static NSString *getApplicationName(void)
-{
- const NSDictionary *dict;
- NSString *appName = 0;
-
- /* Determine the application name */
- dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
- if (dict)
- appName = [dict objectForKey: @"CFBundleName"];
-
- if (![appName length])
- appName = [[NSProcessInfo processInfo] processName];
-
- return appName;
-}
-
-#if SDL_USE_NIB_FILE
-/* A helper category for NSString */
-@interface NSString (ReplaceSubString)
-- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
-@end
-#endif
-
-@interface SDLApplication : NSApplication
-@end
-
-@implementation SDLApplication
-/* Invoked from the Quit menu item */
-- (void)terminate:(id)sender
-{
- /* Post a SDL_QUIT event */
- SDL_Event event;
- event.type = SDL_QUIT;
- SDL_PushEvent(&event);
-}
-@end
-
-/* The main class of the application, the application's delegate */
-@implementation SDLMain
-
-/* Set the working directory to the .app's parent directory */
-- (void) setupWorkingDirectory:(BOOL)shouldChdir
-{
- if (shouldChdir)
- {
- char parentdir[MAXPATHLEN];
- CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
- CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
- if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) {
- chdir(parentdir); /* chdir to the binary app's parent */
- }
- CFRelease(url);
- CFRelease(url2);
- }
-}
-
-#if SDL_USE_NIB_FILE
-
-/* Fix menu to contain the real app name instead of "SDL App" */
-- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
-{
- NSRange aRange;
- NSEnumerator *enumerator;
- NSMenuItem *menuItem;
-
- aRange = [[aMenu title] rangeOfString:@"SDL App"];
- if (aRange.length != 0)
- [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
-
- enumerator = [[aMenu itemArray] objectEnumerator];
- while ((menuItem = [enumerator nextObject]))
- {
- aRange = [[menuItem title] rangeOfString:@"SDL App"];
- if (aRange.length != 0)
- [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
- if ([menuItem hasSubmenu])
- [self fixMenu:[menuItem submenu] withAppName:appName];
- }
- [ aMenu sizeToFit ];
-}
-
-#else
-
-static void setApplicationMenu(void)
-{
- /* warning: this code is very odd */
- NSMenu *appleMenu;
- NSMenuItem *menuItem;
- NSString *title;
- NSString *appName;
-
- appName = getApplicationName();
- appleMenu = [[NSMenu alloc] initWithTitle:@""];
-
- /* Add menu items */
- title = [@"About " stringByAppendingString:appName];
- [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
-
- [appleMenu addItem:[NSMenuItem separatorItem]];
-
- title = [@"Hide " stringByAppendingString:appName];
- [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
-
- menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
- [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
-
- [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
-
- [appleMenu addItem:[NSMenuItem separatorItem]];
-
- title = [@"Quit " stringByAppendingString:appName];
- [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
-
-
- /* Put menu into the menubar */
- menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
- [menuItem setSubmenu:appleMenu];
- [[NSApp mainMenu] addItem:menuItem];
-
- /* Tell the application object that this is now the application menu */
- [NSApp setAppleMenu:appleMenu];
-
- /* Finally give up our references to the objects */
- [appleMenu release];
- [menuItem release];
-}
-
-/* Create a window menu */
-static void setupWindowMenu(void)
-{
- NSMenu *windowMenu;
- NSMenuItem *windowMenuItem;
- NSMenuItem *menuItem;
-
- windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
-
- /* "Minimize" item */
- menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
- [windowMenu addItem:menuItem];
- [menuItem release];
-
- /* Put menu into the menubar */
- windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
- [windowMenuItem setSubmenu:windowMenu];
- [[NSApp mainMenu] addItem:windowMenuItem];
-
- /* Tell the application object that this is now the window menu */
- [NSApp setWindowsMenu:windowMenu];
-
- /* Finally give up our references to the objects */
- [windowMenu release];
- [windowMenuItem release];
-}
-
-/* Replacement for NSApplicationMain */
-static void CustomApplicationMain (int argc, char **argv)
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- SDLMain *sdlMain;
-
- /* Ensure the application object is initialised */
- [SDLApplication sharedApplication];
-
-#ifdef SDL_USE_CPS
- {
- CPSProcessSerNum PSN;
- /* Tell the dock about us */
- if (!CPSGetCurrentProcess(&PSN))
- if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
- if (!CPSSetFrontProcess(&PSN))
- [SDLApplication sharedApplication];
- }
-#endif /* SDL_USE_CPS */
-
- /* Set up the menubar */
- NSMenu *menu = [[NSMenu alloc] init];
- [NSApp setMainMenu:menu];
- setApplicationMenu();
- setupWindowMenu();
- [menu release];
-
- /* Create SDLMain and make it the app delegate */
- sdlMain = [[SDLMain alloc] init];
- [NSApp setDelegate:sdlMain];
-
- /* Start the main event loop */
- [NSApp run];
-
- [sdlMain release];
- [pool release];
-}
-
-#endif
-
-
-/*
- * Catch document open requests...this lets us notice files when the app
- * was launched by double-clicking a document, or when a document was
- * dragged/dropped on the app's icon. You need to have a
- * CFBundleDocumentsType section in your Info.plist to get this message,
- * apparently.
- *
- * Files are added to gArgv, so to the app, they'll look like command line
- * arguments. Previously, apps launched from the finder had nothing but
- * an argv[0].
- *
- * This message may be received multiple times to open several docs on launch.
- *
- * This message is ignored once the app's mainline has been called.
- */
-- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
-{
- const char *temparg;
- size_t arglen;
- char *arg;
- char **newargv;
-
- if (!gFinderLaunch) /* MacOS is passing command line args. */
- return FALSE;
-
- if (gCalledAppMainline) /* app has started, ignore this document. */
- return FALSE;
-
- temparg = [filename UTF8String];
- arglen = SDL_strlen(temparg) + 1;
- arg = (char *) SDL_malloc(arglen);
- if (arg == NULL)
- return FALSE;
-
- newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
- if (newargv == NULL)
- {
- SDL_free(arg);
- return FALSE;
- }
- gArgv = newargv;
-
- SDL_strlcpy(arg, temparg, arglen);
- gArgv[gArgc++] = arg;
- gArgv[gArgc] = NULL;
- return TRUE;
-}
-
-
-/* Called when the internal event loop has just started running */
-- (void) applicationDidFinishLaunching: (NSNotification *) note
-{
- int status;
-
- /* Set the working directory to the .app's parent directory */
- [self setupWorkingDirectory:gFinderLaunch];
-
-#if SDL_USE_NIB_FILE
- /* Set the main menu to contain the real app name instead of "SDL App" */
- [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
-#endif
-
- /* Hand off to main application code */
- gCalledAppMainline = TRUE;
- status = SDL_main (gArgc, gArgv);
-
- /* We're done, thank you for playing */
- exit(status);
-}
-@end
-
-
-@implementation NSString (ReplaceSubString)
-
-- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
-{
- unsigned int bufferSize;
- unsigned int selfLen = [self length];
- unsigned int aStringLen = [aString length];
- unichar *buffer;
- NSRange localRange;
- NSString *result;
-
- bufferSize = selfLen + aStringLen - aRange.length;
- buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
-
- /* Get first part into buffer */
- localRange.location = 0;
- localRange.length = aRange.location;
- [self getCharacters:buffer range:localRange];
-
- /* Get middle part into buffer */
- localRange.location = 0;
- localRange.length = aStringLen;
- [aString getCharacters:(buffer+aRange.location) range:localRange];
-
- /* Get last part into buffer */
- localRange.location = aRange.location + aRange.length;
- localRange.length = selfLen - localRange.location;
- [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
-
- /* Build output string */
- result = [NSString stringWithCharacters:buffer length:bufferSize];
-
- NSDeallocateMemoryPages(buffer, bufferSize);
-
- return result;
-}
-
-@end
-
-
-
-#ifdef main
-# undef main
-#endif
-
-
-/* Main entry point to executable - should *not* be SDL_main! */
-int main (int argc, char **argv)
-{
- /* Copy the arguments into a global variable */
- /* This is passed if we are launched by double-clicking */
- if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
- gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
- gArgv[0] = argv[0];
- gArgv[1] = NULL;
- gArgc = 1;
- gFinderLaunch = YES;
- } else {
- int i;
- gArgc = argc;
- gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
- for (i = 0; i <= argc; i++)
- gArgv[i] = argv[i];
- gFinderLaunch = NO;
- }
-
-#if SDL_USE_NIB_FILE
- [SDLApplication poseAsClass:[NSApplication class]];
- NSApplicationMain (argc, argv);
-#else
- CustomApplicationMain (argc, argv);
-#endif
- return 0;
-}
-
diff -Nru hedgewars-0.9.19.3/hedgewars/SDLh.pas hedgewars-0.9.20.5/hedgewars/SDLh.pas
--- hedgewars-0.9.19.3/hedgewars/SDLh.pas 2013-06-04 14:22:41.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/SDLh.pas 2014-01-08 16:25:17.000000000 +0000
@@ -54,7 +54,8 @@
{$ENDIF}
{$IFDEF DARWIN}
- {$IFNDEF IPHONEOS}
+ {$IFNDEF HWLIBRARY}
+ {$linklib SDLmain}
{$PASCALMAINNAME SDL_main}
{$linkframework Cocoa}
{$linkframework SDL}
@@ -76,19 +77,11 @@
SDL_ImageLibName = 'SDL_image.dll';
SDL_NetLibName = 'SDL_net.dll';
{$ELSE}
- {$IFDEF DARWIN}
- SDLLibName = 'SDL';
- SDL_TTFLibName = 'SDL_ttf';
- SDL_MixerLibName = 'SDL_mixer';
- SDL_ImageLibName = 'SDL_image';
- SDL_NetLibName = 'SDL_net';
- {$ELSE}
- SDLLibName = 'libSDL.so';
- SDL_TTFLibName = 'libSDL_ttf.so';
- SDL_MixerLibName = 'libSDL_mixer.so';
- SDL_ImageLibName = 'libSDL_image.so';
- SDL_NetLibName = 'libSDL_net.so';
- {$ENDIF}
+ SDLLibName = 'libSDL';
+ SDL_TTFLibName = 'libSDL_ttf';
+ SDL_MixerLibName = 'libSDL_mixer';
+ SDL_ImageLibName = 'libSDL_image';
+ SDL_NetLibName = 'libSDL_net';
{$ENDIF}
/////////////////////////////////////////////////////////////////
@@ -96,20 +89,22 @@
/////////////////////////////////////////////////////////////////
// SDL_Init() flags
- SDL_INIT_TIMER = $00000001;
- SDL_INIT_AUDIO = $00000010;
- SDL_INIT_VIDEO = $00000020;
- SDL_INIT_JOYSTICK = $00000200;
-{$IFDEF SDL13}
- SDL_INIT_HAPTIC = $00001000;
+ SDL_INIT_TIMER = $00000001;
+ SDL_INIT_AUDIO = $00000010;
+ SDL_INIT_VIDEO = $00000020; // implies SDL_INIT_EVENTS (sdl2)
+ SDL_INIT_JOYSTICK = $00000200; // implies SDL_INIT_EVENTS (sdl2)
+{$IFDEF SDL2}
+ SDL_INIT_HAPTIC = $00001000;
+ SDL_INIT_GAMECONTROLLER = $00002000; // implies SDL_INIT_JOYSTICK
+ SDL_INIT_EVENTS = $00004000;
{$ELSE}
- SDL_INIT_CDROM = $00000100;
- SDL_INIT_EVENTTHREAD = $01000000;
+ SDL_INIT_CDROM = $00000100;
+ SDL_INIT_EVENTTHREAD = $01000000;
{$ENDIF}
- SDL_INIT_NOPARACHUTE = $00100000;
- SDL_INIT_EVERYTHING = $0000FFFF;
+ SDL_INIT_NOPARACHUTE = $00100000;
+ //SDL_INIT_EVERYTHING // unsafe, init subsystems one at a time
- SDL_ALLEVENTS = $FFFFFFFF;
+ SDL_ALLEVENTS = $FFFFFFFF; // dummy event type to prevent stack corruption
SDL_APPINPUTFOCUS = $02;
SDL_BUTTON_LEFT = 1;
@@ -118,10 +113,20 @@
SDL_BUTTON_WHEELUP = 4;
SDL_BUTTON_WHEELDOWN = 5;
-{$IFDEF SDL13}
+
+{$IFDEF SDL2}
// SDL_Event types
- SDL_FIRSTEVENT = 0;
+ // pascal does not support unions as is, so we list here every possible event
+ // and later associate a struct type each
+ SDL_FIRSTEVENT = 0; // type
+ SDL_COMMONDEVENT = 1; // type and timestamp
SDL_QUITEV = $100;
+ SDL_APP_TERMINATING = $101;
+ SDL_APP_LOWMEMORY = $102;
+ SDL_APP_WILLENTERBACKGROUND = $103;
+ SDL_APP_DIDENTERBACKGROUND = $104;
+ SDL_APP_WILLENTERFOREGROUND = $105;
+ SDL_APP_DIDENTERFOREGROUND = $106;
SDL_WINDOWEVENT = $200;
SDL_SYSWMEVENT = $201;
SDL_KEYDOWN = $300;
@@ -132,22 +137,22 @@
SDL_MOUSEBUTTONDOWN = $401;
SDL_MOUSEBUTTONUP = $402;
SDL_MOUSEWHEEL = $403;
- SDL_INPUTMOTION = $500;
- SDL_INPUTBUTTONDOWN = $501;
- SDL_INPUTBUTTONUP = $502;
- SDL_INPUTWHEEL = $503;
- SDL_INPUTPROXIMITYIN = $504;
- SDL_INPUTPROXIMITYOUT = $505;
SDL_JOYAXISMOTION = $600;
SDL_JOYBALLMOTION = $601;
SDL_JOYHATMOTION = $602;
SDL_JOYBUTTONDOWN = $603;
SDL_JOYBUTTONUP = $604;
+ SDL_JOYDEVICEADDED = $605;
+ SDL_JOYDEVICEREMOVED = $606;
+ SDL_CONTROLLERAXISMOTION = $650;
+ SDL_CONTROLLERBUTTONDOWN = $651;
+ SDL_CONTROLLERBUTTONUP = $652;
+ SDL_CONTROLLERDEVICEADDED = $653;
+ SDL_CONTROLLERDEVICEREMOVED = $654;
+ SDL_CONTROLLERDEVICEREMAPPED = $655;
SDL_FINGERDOWN = $700;
SDL_FINGERUP = $701;
SDL_FINGERMOTION = $702;
- SDL_TOUCHBUTTONDOWN = $703;
- SDL_TOUCHBUTTONUP = $704;
SDL_DOLLARGESTURE = $800;
SDL_DOLLARRECORD = $801;
SDL_MULTIGESTURE = $802;
@@ -155,33 +160,21 @@
SDL_DROPFILE = $1000;
SDL_USEREVENT = $8000;
SDL_LASTEVENT = $FFFF;
- // no compatibility events $7000
// SDL_Surface flags
SDL_SWSURFACE = $00000000; //*< Not used */
SDL_PREALLOC = $00000001; //*< Surface uses preallocated memory */
SDL_RLEACCEL = $00000002; //*< Surface is RLE encoded */
SDL_DONTFREE = $00000004; //*< Surface is referenced internally */
- SDL_SRCALPHA = $00010000;
- SDL_SRCCOLORKEY = $00020000;
- SDL_ANYFORMAT = $00100000;
- SDL_HWPALETTE = $00200000;
- SDL_DOUBLEBUF = $00400000;
- SDL_FULLSCREEN = $00800000;
- SDL_RESIZABLE = $01000000;
- SDL_NOFRAME = $02000000;
- SDL_OPENGL = $04000000;
- SDL_HWSURFACE = $08000001; //*< Not used */
- SDL_ASYNCBLIT = $08000000; //*< Not used */
- SDL_RLEACCELOK = $08000000; //*< Not used */
- SDL_HWACCEL = $08000000; //*< Not used */
+ SDL_SRCCOLORKEY = $00020000; // compatibility only
- // SDL_Renderer flags
+ // SDL_RendererFlags
SDL_RENDERER_SOFTWARE = $00000001; //*< The renderer is a software fallback */
SDL_RENDERER_ACCELERATED = $00000002; //*< The renderer uses hardware acceleration */
- SDL_RENDERER_PRESENTVSYNC = $00000004;
+ SDL_RENDERER_PRESENTVSYNC = $00000004; //*< Present is synchronized with the refresh rate */
+ SDL_RENDERER_TARGETTEXTURE = $00000008; //*< The renderer supports rendering to texture */
- // SDL_WindowFlags (enum)
+ // SDL_WindowFlags
SDL_WINDOW_FULLSCREEN = $00000001; //*< fullscreen window, implies borderless */
SDL_WINDOW_OPENGL = $00000002; //*< window usable with OpenGL context */
SDL_WINDOW_SHOWN = $00000004; //*< window is visible */
@@ -193,11 +186,12 @@
SDL_WINDOW_INPUT_GRABBED = $00000100; //*< window has grabbed input focus */
SDL_WINDOW_INPUT_FOCUS = $00000200; //*< window has input focus */
SDL_WINDOW_MOUSE_FOCUS = $00000400; //*< window has mouse focus */
+ SDL_WINDOW_FULLSCREEN_DESKTOP = $00001001; //*< fullscreen as maximed window */
SDL_WINDOW_FOREIGN = $00000800; //*< window not created by SDL */
SDL_WINDOWPOS_CENTERED_MASK = $2FFF0000;
- // SDL_WindowEventID (enum)
+ // SDL_WindowEventID
SDL_WINDOWEVENT_NONE = 0; //*< Never used
SDL_WINDOWEVENT_SHOWN = 1; //*< Window has been shown
SDL_WINDOWEVENT_HIDDEN = 2; //*< Window has been hidden
@@ -315,6 +309,7 @@
SDLK_q = 113;
SDLK_w = 119;
SDLK_DELETE = 127;
+ SDLK_KP_ENTER = 271;
SDLK_UP = 273;
SDLK_DOWN = 274;
SDLK_RIGHT = 275;
@@ -334,18 +329,20 @@
// http://www.freepascal.org/docs-html/prog/progsu144.html
type
-{$IFDEF SDL13}
+{$IFDEF SDL2}
PSDL_Window = Pointer;
PSDL_Renderer = Pointer;
PSDL_Texture = Pointer;
PSDL_GLContext= Pointer;
- TSDL_FingerId = Int64;
TSDL_TouchId = Int64;
{$ENDIF}
+ TSDL_FingerId = Int64;
+
+ TSDL_eventaction = (SDL_ADDEVENT, SDL_PEEPEVENT, SDL_GETEVENT);
PSDL_Rect = ^TSDL_Rect;
TSDL_Rect = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
x, y, w, h: LongInt;
{$ELSE}
x, y: SmallInt;
@@ -354,12 +351,12 @@
end;
TPoint = record
- X, Y: LongInt;
+ x, y: LongInt;
end;
PSDL_PixelFormat = ^TSDL_PixelFormat;
TSDL_PixelFormat = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
format: LongWord;
palette: Pointer;
BitsPerPixel : Byte;
@@ -400,23 +397,22 @@
{$ENDIF}
end;
- TSDL_eventaction = (SDL_ADDEVENT, SDL_PEEPEVENT, SDL_GETEVENT);
-
PSDL_Surface = ^TSDL_Surface;
TSDL_Surface = record
flags : LongWord;
format: PSDL_PixelFormat;
w, h : LongInt;
- pitch : {$IFDEF SDL13}LongInt{$ELSE}Word{$ENDIF};
+ pitch : {$IFDEF SDL2}LongInt{$ELSE}Word{$ENDIF};
pixels: Pointer;
- offset: LongInt;
-{$IFDEF SDL13}
+{$IFDEF SDL2}
userdata: Pointer;
locked: LongInt;
lock_data: Pointer;
clip_rect: TSDL_Rect;
map: Pointer;
refcount: LongInt;
+{$ELSE}
+ offset: LongInt;
{$ENDIF}
end;
@@ -426,18 +422,24 @@
r: Byte;
g: Byte;
b: Byte;
- unused: Byte;
+ a: Byte; //sdl12 name is 'unused' but as long as size matches...
end;
+ (* SDL_RWops and friends *)
PSDL_RWops = ^TSDL_RWops;
+{$IFDEF SDL2}
+ TSize = function( context: PSDL_RWops): Int64; cdecl;
+ TSeek = function( context: PSDL_RWops; offset: Int64; whence: LongInt ): Int64; cdecl;
+{$ELSE}
TSeek = function( context: PSDL_RWops; offset: LongInt; whence: LongInt ): LongInt; cdecl;
+{$ENDIF}
TRead = function( context: PSDL_RWops; Ptr: Pointer; size: LongInt; maxnum : LongInt ): LongInt; cdecl;
TWrite = function( context: PSDL_RWops; Ptr: Pointer; size: LongInt; num: LongInt ): LongInt; cdecl;
TClose = function( context: PSDL_RWops ): LongInt; cdecl;
TStdio = record
- autoclose: {$IFDEF SDL13}Boolean{$ELSE}LongInt{$ENDIF};
+ autoclose: {$IFDEF SDL2}Boolean{$ELSE}LongInt{$ENDIF};
fp: Pointer;
end;
@@ -449,29 +451,63 @@
TUnknown = record
data1: Pointer;
+{$IFDEF SDL2}
+ data2: Pointer;
+{$ENDIF}
end;
+{$IFDEF ANDROID}
+ TAndroidio = record
+ fileName, inputStream, readableByteChannel: Pointer;
+ readMethod, assetFileDescriptor: Pointer;
+ position, size, offset: Int64;
+ fd: LongInt;
+ end;
+{$ELSE}
+{$IFDEF WIN32}
+ TWinbuffer = record
+ data: Pointer;
+ size, left: LongInt;
+ end;
+ TWindowsio = record
+ append : {$IFDEF SDL2}Boolean{$ELSE}LongInt{$ENDIF};
+ h : Pointer;
+ buffer : TWinbuffer;
+ end;
+{$ENDIF}
+{$ENDIF}
+
TSDL_RWops = record
+{$IFDEF SDL2}
+ size: TSize;
+{$ENDIF}
seek: TSeek;
read: TRead;
write: TWrite;
close: TClose;
type_: LongWord;
case Byte of
- 0: (stdio: TStdio);
- 1: (mem: TMem);
- 2: (unknown: TUnknown);
+{$IFDEF ANDROID}
+ 0: (androidio: TAndroidio);
+{$ELSE}
+{$IFDEF WIN32}
+ 0: (windowsio: TWindowsio);
+{$ENDIF}
+{$ENDIF}
+ 1: (stdio: TStdio); // assumes HAVE_STDIO_H
+ 2: (mem: TMem);
+ 3: (unknown: TUnknown);
end;
{* SDL_Event type definition *}
-{$IFDEF SDL13}
- TSDL_KeySym = record
+{$IFDEF SDL2}
+ TSDL_Keysym = record
scancode: LongInt;
- sym: LongWord;
+ sym: LongInt;
modifier: Word;
- unicode: LongWord;
+ unused: LongWord;
end;
TSDL_WindowEvent = record
@@ -503,27 +539,15 @@
TSDL_TouchFingerEvent = record
type_: LongWord;
timestamp: LongWord;
- windowId: LongWord;
touchId: TSDL_TouchId;
fingerId: TSDL_FingerId;
- state, padding1, padding2, padding3: Byte;
- x, y: Word;
- dx, dy: SmallInt;
- pressure: Word;
- end;
-
- TSDL_TouchButtonEvent = record
- type_: LongWord;
- timestamp: LongWord;
- windowId: LongWord;
- touchId: TSDL_TouchId;
- state, button, padding1, padding2: Byte;
+ x, y, dx, dy: Single;
+ pressure: Single;
end;
TSDL_MultiGestureEvent = record
type_: LongWord;
timestamp: LongWord;
- windowId: LongWord;
touchId: TSDL_TouchId;
dTheta, dDist, x, y: Single;
numFingers, padding: Word;
@@ -532,11 +556,10 @@
TSDL_DollarGestureEvent = record
type_: LongWord;
timestamp: LongWord;
- windowId: LongWord;
touchId: Int64;
gesturedId: Int64;
numFingers: LongWord;
- error: Single;
+ error, x, y: Single;
end;
TSDL_DropEvent = record
@@ -550,6 +573,37 @@
timestamp: LongWord;
msg: Pointer;
end;
+
+ TSDL_ControllerAxisEvent = record
+ type_: LongWord;
+ timestamp: LongWord;
+ which: LongInt;
+ axis, padding1, padding2, padding3: Byte;
+ value: SmallInt;
+ padding4: Word;
+ end;
+
+ TSDL_ControllerButtonEvent = record
+ type_: LongWord;
+ timestamp: LongWord;
+ which: LongInt;
+ button, states, padding1, padding2: Byte;
+ end;
+
+ TSDL_ControllerDeviceEvent = record
+ type_: LongWord;
+ timestamp: LongWord;
+ which: SmallInt;
+ end;
+
+ TSDL_JoyDeviceEvent = TSDL_ControllerDeviceEvent;
+
+ TSDL_CommonEvent = record
+ type_: LongWord;
+ timestamp: LongWord;
+ end;
+
+ TSDL_OSEvent = TSDL_CommonEvent;
{$ELSE}
TSDL_KeySym = record
scancode: Byte;
@@ -571,35 +625,36 @@
{$ENDIF}
TSDL_KeyboardEvent = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
type_: LongWord;
-// timestamp: LongWord;
+ timestamp: LongWord;
windowID: LongWord;
- state, repeat_ {*,padding2, padding3*}: Byte;
+ state, repeat_, padding2, padding3: Byte;
{$ELSE}
type_, which, state: Byte;
{$ENDIF}
- keysym: TSDL_KeySym;
+ keysym: TSDL_Keysym;
end;
TSDL_MouseMotionEvent = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
type_: LongWord;
timestamp: LongWord;
windowID: LongWord;
- state, padding1, padding2, padding3: Byte;
- x, y, z, xrel, yrel : LongInt;
+ which, state: LongWord;
+ x, y, xrel, yrel: LongInt;
{$ELSE}
type_, which, state: Byte;
- x, y, xrel, yrel : Word;
+ x, y, xrel, yrel: Word;
{$ENDIF}
end;
TSDL_MouseButtonEvent = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
type_: LongWord;
timestamp: LongWord;
windowID: LongWord;
+ which: LongWord;
button, state, padding1, padding2: Byte;
x, y: LongInt;
{$ELSE}
@@ -610,9 +665,10 @@
TSDL_MouseWheelEvent = record
type_: LongWord;
-{$IFDEF SDL13}
+{$IFDEF SDL2}
timestamp: LongWord;
windowID: LongWord;
+ which: LongWord;
{$ELSE}
which: Byte;
{$ENDIF}
@@ -620,56 +676,58 @@
end;
TSDL_JoyAxisEvent = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
type_: LongWord;
timestamp: LongWord;
+ which: LongWord;
{$ELSE}
type_: Byte;
-{$ENDIF}
which: Byte;
+{$ENDIF}
axis: Byte;
-{$IFDEF SDL13}
- padding1, padding2: Byte;
+{$IFDEF SDL2}
+ padding1, padding2, padding3: Byte;
value: LongInt;
+ padding4: Word;
{$ELSE}
value: SmallInt;
{$ENDIF}
end;
TSDL_JoyBallEvent = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
type_: LongWord;
timestamp: LongWord;
+ which: LongWord;
{$ELSE}
type_: Byte;
-{$ENDIF}
which: Byte;
+{$ENDIF}
ball: Byte;
-{$IFDEF SDL13}
- padding1, padding2: Byte;
- xrel, yrel: LongInt;
-{$ELSE}
- xrel, yrel: SmallInt;
+{$IFDEF SDL2}
+ padding1, padding2, padding3: Byte;
{$ENDIF}
+ xrel, yrel: SmallInt;
end;
TSDL_JoyHatEvent = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
type_: LongWord;
timestamp: LongWord;
+ which: LongWord;
{$ELSE}
type_: Byte;
-{$ENDIF}
which: Byte;
+{$ENDIF}
hat: Byte;
value: Byte;
-{$IFDEF SDL13}
- padding1: Byte;
+{$IFDEF SDL2}
+ padding1, padding2: Byte;
{$ENDIF}
end;
TSDL_JoyButtonEvent = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
type_: LongWord;
timestamp: LongWord;
{$ELSE}
@@ -678,13 +736,13 @@
which: Byte;
button: Byte;
state: Byte;
-{$IFDEF SDL13}
+{$IFDEF SDL2}
padding1: Byte;
{$ENDIF}
end;
TSDL_QuitEvent = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
type_: LongWord;
timestamp: LongWord;
{$ELSE}
@@ -693,7 +751,7 @@
end;
TSDL_UserEvent = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
type_: LongWord;
timestamp: LongWord;
windowID: LongWord;
@@ -706,9 +764,10 @@
PSDL_Event = ^TSDL_Event;
TSDL_Event = record
-{$IFDEF SDL13}
+{$IFDEF SDL2}
case LongInt of
- SDL_FIRSTEVENT: (type_: LongInt);
+ SDL_FIRSTEVENT: (type_: LongWord);
+ SDL_COMMONDEVENT: (common: TSDL_CommonEvent);
SDL_WINDOWEVENT: (window: TSDL_WindowEvent);
SDL_KEYDOWN,
SDL_KEYUP: (key: TSDL_KeyboardEvent);
@@ -723,14 +782,20 @@
SDL_JOYHATMOTION: (jhat: TSDL_JoyHatEvent);
SDL_JOYBUTTONDOWN,
SDL_JOYBUTTONUP: (jbutton: TSDL_JoyButtonEvent);
+ SDL_JOYDEVICEADDED,
+ SDL_JOYDEVICEREMOVED: (jdevice: TSDL_JoyDeviceEvent);
+ SDL_CONTROLLERAXISMOTION: (caxis: TSDL_ControllerAxisEvent);
+ SDL_CONTROLLERBUTTONUP,
+ SDL_CONTROLLERBUTTONDOWN: (cbutton: TSDL_ControllerButtonEvent);
+ SDL_CONTROLLERDEVICEADDED,
+ SDL_CONTROLLERDEVICEREMAPPED,
+ SDL_CONTROLLERDEVICEREMOVED: (cdevice: TSDL_ControllerDeviceEvent);
SDL_QUITEV: (quit: TSDL_QuitEvent);
SDL_USEREVENT: (user: TSDL_UserEvent);
SDL_SYSWMEVENT: (syswm: TSDL_SysWMEvent);
SDL_FINGERDOWN,
SDL_FINGERUP,
SDL_FINGERMOTION: (tfinger: TSDL_TouchFingerEvent);
- SDL_TOUCHBUTTONUP,
- SDL_TOUCHBUTTONDOWN: (tbutton: TSDL_TouchButtonEvent);
SDL_MULTIGESTURE: (mgesture: TSDL_MultiGestureEvent);
SDL_DOLLARGESTURE: (dgesture: TSDL_DollarGestureEvent);
SDL_DROPFILE: (drop: TSDL_DropEvent);
@@ -783,16 +848,20 @@
SDL_GL_MULTISAMPLEBUFFERS,
SDL_GL_MULTISAMPLESAMPLES,
SDL_GL_ACCELERATED_VISUAL,
-{$IFDEF SDL13}
+{$IFDEF SDL2}
SDL_GL_RETAINED_BACKING,
SDL_GL_CONTEXT_MAJOR_VERSION,
- SDL_GL_CONTEXT_MINOR_VERSION
+ SDL_GL_CONTEXT_MINOR_VERSION,
+ SDL_GL_CONTEXT_EGL,
+ SDL_GL_CONTEXT_FLAGS,
+ SDL_GL_CONTEXT_PROFILE_MASK,
+ SDL_GL_SHARE_WITH_CURRENT_CONTEXT
{$ELSE}
SDL_GL_SWAP_CONTROL
{$ENDIF}
);
-{$IFDEF SDL13}
+{$IFDEF SDL2}
TSDL_ArrayByteOrder = ( // array component order, low Byte -> high Byte
SDL_ARRAYORDER_NONE,
SDL_ARRAYORDER_RGB,
@@ -804,7 +873,7 @@
);
{$ENDIF}
-// Joystick/Controller support
+ // Joystick/Controller support
PSDL_Joystick = ^TSDL_Joystick;
TSDL_Joystick = record
end;
@@ -840,7 +909,7 @@
TMixMusic = record
end;
- TPostMix = procedure(udata: pointer; stream: PByte; len: LongInt); cdecl;
+ TPostMix = procedure(udata: Pointer; stream: PByte; len: LongInt); cdecl;
{* SDL_net *}
TIPAddress = record
@@ -907,7 +976,7 @@
function SDL_RWFromFile(filename, mode: PChar): PSDL_RWops; cdecl; external SDLLibName;
function SDL_SaveBMP_RW(surface: PSDL_Surface; dst: PSDL_RWops; freedst: LongInt): LongInt; cdecl; external SDLLibName;
-{$IFDEF SDL13}
+{$IFDEF SDL2}
function SDL_CreateWindow(title: PChar; x,y,w,h: LongInt; flags: LongWord): PSDL_Window; cdecl; external SDLLibName;
function SDL_CreateRenderer(window: PSDL_Window; index: LongInt; flags: LongWord): PSDL_Renderer; cdecl; external SDLLibName;
function SDL_DestroyWindow(window: PSDL_Window): LongInt; cdecl; external SDLLibName;
@@ -940,8 +1009,15 @@
procedure SDL_StartTextInput; cdecl; external SDLLibName;
function SDL_PeepEvents(event: PSDL_Event; numevents: LongInt; action: TSDL_eventaction; minType, maxType: LongWord): LongInt; cdecl; external SDLLibName;
+
+function SDL_AllocFormat(format: LongWord): PSDL_PixelFormat; cdecl; external SDLLibName;
+procedure SDL_FreeFormat(pixelformat: PSDL_PixelFormat); cdecl; external SDLLibName;
{$ELSE}
function SDL_PeepEvents(event: PSDL_Event; numevents: LongInt; action: TSDL_eventaction; mask: LongWord): LongInt; cdecl; external SDLLibName;
+
+function SDL_EnableUNICODE(enable: LongInt): LongInt; cdecl; external SDLLibName;
+function SDL_EnableKeyRepeat(timedelay, interval: LongInt): LongInt; cdecl; external SDLLibName;
+function SDL_VideoDriverName(namebuf: PChar; maxlen: LongInt): PChar; cdecl; external SDLLibName;
{$ENDIF}
@@ -957,22 +1033,24 @@
procedure SDL_SetEventFilter(filter: TSDL_EventFilter); cdecl; external SDLLibName;
function SDL_ShowCursor(toggle: LongInt): LongInt; cdecl; external SDLLibName;
+procedure SDL_WarpMouse(x, y: Word); {$IFDEF SDL2}inline{$ELSE}cdecl; external SDLLibName{$ENDIF};
+function SDL_GetKeyState(numkeys: PLongInt): PByteArray; cdecl; external SDLLibName {$IFDEF SDL2} name 'SDL_GetKeyboardState'{$ENDIF};
procedure SDL_WM_SetIcon(icon: PSDL_Surface; mask : Byte); cdecl; external SDLLibName;
procedure SDL_WM_SetCaption(title: PChar; icon: PChar); cdecl; external SDLLibName;
function SDL_WM_ToggleFullScreen(surface: PSDL_Surface): LongInt; cdecl; external SDLLibName;
-// remember to mark the threaded functions as 'cdecl; export;'
-// (or have fun debugging nil arguments)
-function SDL_CreateThread(fn: Pointer; {$IFDEF SDL13}name: PChar;{$ENDIF} data: Pointer): PSDL_Thread; cdecl; external SDLLibName;
+(* remember to mark the threaded functions as 'cdecl; export;'
+ (or have fun debugging nil arguments) *)
+function SDL_CreateThread(fn: Pointer; {$IFDEF SDL2}name: PChar;{$ENDIF} data: Pointer): PSDL_Thread; cdecl; external SDLLibName;
procedure SDL_WaitThread(thread: PSDL_Thread; status: PLongInt); cdecl; external SDLLibName;
procedure SDL_KillThread(thread: PSDL_Thread); cdecl; external SDLLibName;
function SDL_CreateMutex: PSDL_mutex; cdecl; external SDLLibName;
procedure SDL_DestroyMutex(mutex: PSDL_mutex); cdecl; external SDLLibName;
-function SDL_LockMutex(mutex: PSDL_mutex): LongInt; cdecl; external SDLLibName name 'SDL_mutexP';
-function SDL_UnlockMutex(mutex: PSDL_mutex): LongInt; cdecl; external SDLLibName name 'SDL_mutexV';
+function SDL_LockMutex(mutex: PSDL_mutex): LongInt; cdecl; external SDLLibName {$IFNDEF SDL2}name 'SDL_mutexP'{$ENDIF};
+function SDL_UnlockMutex(mutex: PSDL_mutex): LongInt; cdecl; external SDLLibName {$IFNDEF SDL2}name 'SDL_mutexV'{$ENDIF};
function SDL_GL_SetAttribute(attr: TSDL_GLattr; value: LongInt): LongInt; cdecl; external SDLLibName;
procedure SDL_GL_SwapBuffers; cdecl; external SDLLibName;
@@ -1003,15 +1081,6 @@
{$ENDIF}
-{* Compatibility between SDL-1.2 and SDL-1.3 *}
-procedure SDL_WarpMouse(x, y: Word); {$IFDEF SDL13}inline{$ELSE}cdecl; external SDLLibName{$ENDIF};
-function SDL_GetKeyState(numkeys: PLongInt): PByteArray; cdecl; external SDLLibName {$IFDEF SDL13} name 'SDL_GetKeyboardState'{$ENDIF};
-function SDL_AllocFormat(format: LongWord): PSDL_PixelFormat; {$IFDEF SDL13}cdecl; external SDLLibName;{$ENDIF}
-procedure SDL_FreeFormat(pixelformat: PSDL_PixelFormat); {$IFDEF SDL13}cdecl; external SDLLibName;{$ENDIF}
-function SDL_VideoDriverName(namebuf: PChar; maxlen: LongInt): PChar; {$IFNDEF SDL13}cdecl; external SDLLibName;{$ENDIF}
-function SDL_EnableUNICODE(enable: LongInt): LongInt; {$IFNDEF SDL13}cdecl; external SDLLibName;{$ENDIF}
-function SDL_EnableKeyRepeat(timedelay, interval: LongInt): LongInt; {$IFNDEF SDL13}cdecl; external SDLLibName;{$ENDIF}
-
(* SDL_ttf *)
function TTF_Init: LongInt; cdecl; external SDL_TTFLibName;
procedure TTF_Quit; cdecl; external SDL_TTFLibName;
@@ -1026,8 +1095,8 @@
procedure TTF_SetFontStyle(font: PTTF_Font; style: LongInt); cdecl; external SDL_TTFLibName;
(* SDL_mixer *)
-function Mix_Init(flags: LongInt): LongInt; {$IFDEF SDL_MIXER_NEWER}cdecl; external SDL_MixerLibName;{$ENDIF}
-procedure Mix_Quit; {$IFDEF SDL_MIXER_NEWER}cdecl; external SDL_MixerLibName;{$ENDIF}
+function Mix_Init(flags: LongInt): LongInt; {$IFDEF SDL_MIXER_NEWER}cdecl; external SDL_MixerLibName{$ELSE}inline{$ENDIF};
+procedure Mix_Quit; {$IFDEF SDL_MIXER_NEWER}cdecl; external SDL_MixerLibName{$ELSE}inline{$ENDIF};
function Mix_OpenAudio(frequency: LongInt; format: Word; channels: LongInt; chunksize: LongInt): LongInt; cdecl; external SDL_MixerLibName;
procedure Mix_CloseAudio; cdecl; external SDL_MixerLibName;
@@ -1059,11 +1128,11 @@
function Mix_FadeInChannelTimed(channel: LongInt; chunk: PMixChunk; loops: LongInt; fadems: LongInt; ticks: LongInt): LongInt; cdecl; external SDL_MixerLibName;
function Mix_FadeOutChannel(channel: LongInt; fadems: LongInt): LongInt; cdecl; external SDL_MixerLibName;
-procedure Mix_SetPostMix( mix_func: TPostMix; arg: pointer); cdecl; external SDL_MixerLibName;
+procedure Mix_SetPostMix( mix_func: TPostMix; arg: Pointer); cdecl; external SDL_MixerLibName;
(* SDL_image *)
-function IMG_Init(flags: LongInt): LongInt; {$IFDEF SDL_IMAGE_NEWER}cdecl; external SDL_ImageLibName;{$ENDIF}
-procedure IMG_Quit; {$IFDEF SDL_IMAGE_NEWER}cdecl; external SDL_ImageLibName;{$ENDIF}
+function IMG_Init(flags: LongInt): LongInt; {$IFDEF SDL_IMAGE_NEWER}cdecl; external SDL_ImageLibName{$ELSE}inline{$ENDIF};
+procedure IMG_Quit; {$IFDEF SDL_IMAGE_NEWER}cdecl; external SDL_ImageLibName{$ELSE}inline{$ENDIF};
function IMG_Load(const _file: PChar): PSDL_Surface; cdecl; external SDL_ImageLibName;
function IMG_Load_RW(rwop: PSDL_RWops; freesrc: LongBool): PSDL_Surface; cdecl; external SDL_ImageLibName;
@@ -1092,64 +1161,23 @@
function SDLNet_Read32(buf: Pointer): LongWord;
implementation
-{$IFDEF SDL13}
-uses strings, uVariables, uStore;
+{$IFDEF SDL2}
+uses uStore;
-// compatible functions
+// for sdl1.2 we directly call SDL_WarpMouse()
+// for sdl2 we provide a SDL_WarpMouse() which calls the right SDL_WarpMouseInWindow() function
+// this has the advantage of reducing 'uses' and 'ifdef' statements
+// (SDLwindow is a private member of uStore module)
procedure SDL_WarpMouse(x, y: Word); inline;
begin
WarpMouse(x, y);
end;
-
-function SDL_VideoDriverName(namebuf: PChar; maxlen: LongInt): PChar;
-var name : PChar = nil;
-begin
- name:= SDL_GetCurrentVideoDriver();
- if (name <> nil) and (namebuf <> nil) then
- begin
- strlcopy(namebuf, name, maxlen);
- SDL_VideoDriverName:= namebuf
- end;
- SDL_VideoDriverName:= name;
-end;
-
-function SDL_EnableUNICODE(enable: LongInt): LongInt;
-begin
- enable:= enable; // avoid hint
- SDL_StartTextInput();
- SDL_EnableUNICODE:= 0;
-end;
-
-function SDL_EnableKeyRepeat(timedelay, interval: LongInt): LongInt;
-begin
- timedelay:= timedelay; // avoid hint
- interval:= interval; // avoid hint
- SDL_EnableKeyRepeat:= 0;
-end;
-{$ELSE}
-const conversionFormat: TSDL_PixelFormat = (
- palette: nil; BitsPerPixel: 32; BytesPerPixel: 4;
- Rloss: 0; Gloss: 0; Bloss: 0; Aloss: 0;
- Rshift: RShift; Gshift: GShift; Bshift: BShift; Ashift: AShift;
- RMask: RMask; GMask: GMask; BMask: BMask; AMask: AMask;
- colorkey: 0; alpha: 255);
-
-function SDL_AllocFormat(format: LongWord): PSDL_PixelFormat;
-begin
- format:= format;
- SDL_AllocFormat:= @conversionFormat;
-end;
-
-procedure SDL_FreeFormat(pixelformat: PSDL_PixelFormat);
-begin
- pixelformat:= pixelformat; // avoid hint
-end;
{$ENDIF}
function SDL_MustLock(Surface: PSDL_Surface): Boolean;
begin
SDL_MustLock:=
-{$IFDEF SDL13}
+{$IFDEF SDL2}
((surface^.flags and SDL_RLEACCEL) <> 0)
{$ELSE}
( surface^.offset <> 0 ) or (( surface^.flags and (SDL_HWSURFACE or SDL_ASYNCBLIT or SDL_RLEACCEL)) <> 0)
@@ -1157,23 +1185,23 @@
end;
{$IFNDEF SDL_MIXER_NEWER}
-function Mix_Init(flags: LongInt): LongInt;
+function Mix_Init(flags: LongInt): LongInt; inline;
begin
Mix_Init:= flags;
end;
-procedure Mix_Quit;
+procedure Mix_Quit; inline;
begin
end;
{$ENDIF}
{$IFNDEF SDL_IMAGE_NEWER}
-function IMG_Init(flags: LongInt): LongInt;
+function IMG_Init(flags: LongInt): LongInt; inline;
begin
IMG_Init:= flags;
end;
-procedure IMG_Quit;
+procedure IMG_Quit; inline;
begin
end;
{$ENDIF}
diff -Nru hedgewars-0.9.19.3/hedgewars/VGSHandlers.inc hedgewars-0.9.20.5/hedgewars/VGSHandlers.inc
--- hedgewars-0.9.19.3/hedgewars/VGSHandlers.inc 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/VGSHandlers.inc 1970-01-01 00:00:00.000000000 +0000
@@ -1,802 +0,0 @@
-(*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2013 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
- *)
-
-(*
- * This file contains the step handlers for visual gears.
- *
- * Since the effects of visual gears do not affect the course of the game,
- * no "synchronization" between players is required.
- * => The usage of safe functions or data types (e.g. GetRandom() or hwFloat)
- * is usually not necessary and therefore undesirable.
- *)
-
-procedure doStepFlake(Gear: PVisualGear; Steps: Longword);
-var sign: real;
- moved: boolean;
-begin
-if vobCount = 0 then exit;
-
-sign:= 1;
-with Gear^ do
- begin
- inc(FrameTicks, Steps);
- if not SuddenDeathDmg and (FrameTicks > vobFrameTicks) then
- begin
- dec(FrameTicks, vobFrameTicks);
- inc(Frame);
- if Frame = vobFramesCount then
- Frame:= 0
- end
- else if SuddenDeathDmg and (FrameTicks > vobSDFrameTicks) then
- begin
- dec(FrameTicks, vobSDFrameTicks);
- inc(Frame);
- if Frame = vobSDFramesCount then
- Frame:= 0
- end;
- X:= X + (cWindSpeedf * 400 + dX + tdX) * Steps * Gear^.Scale;
- if SuddenDeathDmg then
- Y:= Y + (dY + tdY + cGravityf * vobSDFallSpeed) * Steps * Gear^.Scale
- else
- Y:= Y + (dY + tdY + cGravityf * vobFallSpeed) * Steps * Gear^.Scale;
- Angle:= Angle + dAngle * Steps;
- if Angle > 360 then
- Angle:= Angle - 360
- else
- if Angle < - 360 then
- Angle:= Angle + 360;
-
-
- if (round(X) >= cLeftScreenBorder)
- and (round(X) <= cRightScreenBorder)
- and (round(Y) - 75 <= LAND_HEIGHT)
- and (Timer > 0) and (Timer-Steps > 0) then
- begin
- if tdX > 0 then
- sign := 1
- else
- sign:= -1;
- tdX:= tdX - 0.005*Steps*sign;
- if ((sign < 0) and (tdX > 0)) or ((sign > 0) and (tdX < 0)) then
- tdX:= 0;
- if tdX > 0 then
- sign := 1
- else
- sign:= -1;
- tdY:= tdY - 0.005*Steps*sign;
- if ((sign < 0) and (tdY > 0)) or ((sign > 0) and (tdY < 0)) then
- tdY:= 0;
- dec(Timer, Steps)
- end
- else
- begin
- moved:= false;
- if round(X) < cLeftScreenBorder then
- begin
- X:= X + cScreenSpace;
- moved:= true
- end
- else
- if round(X) > cRightScreenBorder then
- begin
- X:= X - cScreenSpace;
- moved:= true
- end;
- // if round(Y) < (LAND_HEIGHT - 1024 - 75) then Y:= Y + 25.0; // For if flag is set for flakes rising upwards?
- if (Gear^.Layer = 2) and (round(Y) - 225 > LAND_HEIGHT) then
- begin
- X:= cLeftScreenBorder + random(cScreenSpace);
- Y:= Y - (1024 + 250 + random(50)); // TODO - configure in theme (jellies for example could use limited range)
- moved:= true
- end
- else if (Gear^.Layer <> 2) and (round(Y) + 50 > LAND_HEIGHT) then
- begin
- X:= cLeftScreenBorder + random(cScreenSpace);
- Y:= Y - (1024 + random(25));
- moved:= true
- end;
- if moved then
- begin
- Angle:= random(360);
- dx:= 0.0000038654705 * random(10000);
- dy:= 0.000003506096 * random(7000);
- if random(2) = 0 then dx := -dx
- end;
- Timer:= 0;
- tdX:= 0;
- tdY:= 0
- end;
- end;
-
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepBeeTrace(Gear: PVisualGear; Steps: Longword);
-begin
-if Gear^.FrameTicks > Steps then
- dec(Gear^.FrameTicks, Steps)
-else
- DeleteVisualGear(Gear);
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepCloud(Gear: PVisualGear; Steps: Longword);
-var s: Longword;
- t: real;
-begin
-Gear^.X:= Gear^.X + (cWindSpeedf * 750 * Gear^.dX * Gear^.Scale) * Steps;
-
-// up-and-down-bounce magic
-s := (GameTicks + Gear^.Timer) mod 4096;
-t := 8 * Gear^.Scale * hwFloat2Float(AngleSin(s mod 2048));
-if (s < 2048) then t := -t;
-
-Gear^.Y := LAND_HEIGHT - 1184 + LongInt(Gear^.Timer mod 8) + t;
-
-if round(Gear^.X) < cLeftScreenBorder then
- Gear^.X:= Gear^.X + cScreenSpace
-else
- if round(Gear^.X) > cRightScreenBorder then
- Gear^.X:= Gear^.X - cScreenSpace
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepExpl(Gear: PVisualGear; Steps: Longword);
-var s: LongInt;
-begin
-s:= min(Steps, cExplFrameTicks);
-
-Gear^.X:= Gear^.X + Gear^.dX * s;
-Gear^.Y:= Gear^.Y + Gear^.dY * s;
-//Gear^.dY:= Gear^.dY + cGravityf;
-
-if Gear^.FrameTicks <= Steps then
- if Gear^.Frame = 0 then
- DeleteVisualGear(Gear)
- else
- begin
- dec(Gear^.Frame);
- Gear^.FrameTicks:= cExplFrameTicks
- end
- else dec(Gear^.FrameTicks, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepNote(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + Gear^.dX * Steps;
-
-Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
-Gear^.dY:= Gear^.dY + cGravityf * Steps / 2;
-
-Gear^.Angle:= Gear^.Angle + (Gear^.Frame + 1) * Steps / 10;
-while Gear^.Angle > cMaxAngle do
- Gear^.Angle:= Gear^.Angle - cMaxAngle;
-
-if Gear^.FrameTicks <= Steps then
- DeleteVisualGear(Gear)
-else
- dec(Gear^.FrameTicks, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepLineTrail(Gear: PVisualGear; Steps: Longword);
-begin
-Steps := Steps;
-if Gear^.Timer <= Steps then
- DeleteVisualGear(Gear)
-else
- dec(Gear^.Timer, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepEgg(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + Gear^.dX * Steps;
-
-Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
-Gear^.dY:= Gear^.dY + cGravityf * Steps;
-
-Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
-
-if Gear^.FrameTicks <= Steps then
- begin
- DeleteVisualGear(Gear);
- exit
- end
-else
- dec(Gear^.FrameTicks, Steps);
-
-if Gear^.FrameTicks < $FF then
- Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or Gear^.FrameTicks
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepFire(Gear: PVisualGear; Steps: Longword);
-var vgt: PVisualGear;
-begin
-Gear^.X:= Gear^.X + Gear^.dX * Steps;
-
-Gear^.Y:= Gear^.Y + Gear^.dY * Steps;// + cGravityf * (Steps * Steps);
-if (Gear^.State and gstTmpFlag) = 0 then
- begin
- Gear^.dY:= Gear^.dY + cGravityf * Steps;
- if ((GameTicks mod 200) < Steps + 1) then
- begin
- vgt:= AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtFire);
- if vgt <> nil then
- begin
- vgt^.dx:= 0;
- vgt^.dy:= 0;
- vgt^.State:= gstTmpFlag;
- end;
- end
- end
-else
- inc(Steps, Steps);
-
-if Gear^.FrameTicks <= Steps then
- DeleteVisualGear(Gear)
-else
- dec(Gear^.FrameTicks, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepShell(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + Gear^.dX * Steps;
-
-Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
-Gear^.dY:= Gear^.dY + cGravityf * Steps;
-
-Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
-
-if Gear^.FrameTicks <= Steps then
- DeleteVisualGear(Gear)
-else
- dec(Gear^.FrameTicks, Steps)
-end;
-
-procedure doStepSmallDamage(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.Y:= Gear^.Y - 0.02 * Steps;
-
-if Gear^.FrameTicks <= Steps then
- DeleteVisualGear(Gear)
-else
- dec(Gear^.FrameTicks, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepBubble(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + Gear^.dX * Steps;
-Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
-Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
-Gear^.dX := Gear^.dX / (1.001 * Steps);
-Gear^.dY := Gear^.dY / (1.001 * Steps);
-
-if (Gear^.FrameTicks <= Steps) or (round(Gear^.Y) < cWaterLine) then
- DeleteVisualGear(Gear)
-else
- dec(Gear^.FrameTicks, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSteam(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + (cWindSpeedf * 100 + Gear^.dX) * Steps;
-Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
-
-if Gear^.FrameTicks <= Steps then
- if Gear^.Frame = 0 then
- DeleteVisualGear(Gear)
- else
- begin
- if Random(2) = 0 then
- dec(Gear^.Frame);
- Gear^.FrameTicks:= cExplFrameTicks
- end
-else dec(Gear^.FrameTicks, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepAmmo(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
-
-Gear^.scale:= Gear^.scale + 0.0025 * Steps;
-Gear^.alpha:= Gear^.alpha - 0.0015 * Steps;
-
-if Gear^.alpha < 0 then
- DeleteVisualGear(Gear)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSmoke(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + (cWindSpeedf + Gear^.dX) * Steps;
-Gear^.Y:= Gear^.Y - (cDrownSpeedf + Gear^.dY) * Steps;
-
-Gear^.dX := Gear^.dX + (cWindSpeedf * 0.3 * Steps);
-//Gear^.dY := Gear^.dY - (cDrownSpeedf * 0.995);
-
-if Gear^.FrameTicks <= Steps then
- if Gear^.Frame = 0 then
- DeleteVisualGear(Gear)
- else
- begin
- if Random(2) = 0 then
- dec(Gear^.Frame);
- Gear^.FrameTicks:= cExplFrameTicks
- end
- else dec(Gear^.FrameTicks, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepDust(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + (cWindSpeedf + (cWindSpeedf * 0.03 * Steps) + Gear^.dX) * Steps;
-Gear^.Y:= Gear^.Y - (Gear^.dY) * Steps;
-
-Gear^.dX := Gear^.dX - (Gear^.dX * 0.005 * Steps);
-Gear^.dY := Gear^.dY - (cDrownSpeedf * 0.001 * Steps);
-
-if Gear^.FrameTicks <= Steps then
- if Gear^.Frame = 0 then
- DeleteVisualGear(Gear)
- else
- begin
- dec(Gear^.Frame);
- Gear^.FrameTicks:= cExplFrameTicks
- end
- else dec(Gear^.FrameTicks, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSplash(Gear: PVisualGear; Steps: Longword);
-begin
-if Gear^.FrameTicks <= Steps then
- DeleteVisualGear(Gear)
-else
- dec(Gear^.FrameTicks, Steps);
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepDroplet(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + Gear^.dX * Steps;
-
-Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
-Gear^.dY:= Gear^.dY + cGravityf * Steps;
-
-if round(Gear^.Y) > cWaterLine then
- begin
- DeleteVisualGear(Gear);
- PlaySound(TSound(ord(sndDroplet1) + Random(3)));
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSmokeRing(Gear: PVisualGear; Steps: Longword);
-begin
-inc(Gear^.Timer, Steps);
-if Gear^.Timer >= Gear^.FrameTicks then
- DeleteVisualGear(Gear)
-else
- begin
- Gear^.scale := 1.25 * (-power(2, -10 * Int(Gear^.Timer)/Gear^.FrameTicks) + 1) + 0.4;
- Gear^.alpha := 1 - power(Gear^.Timer / 350, 4);
- if Gear^.alpha < 0 then
- Gear^.alpha:= 0;
- end;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepFeather(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + Gear^.dX * Steps;
-
-Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
-Gear^.dY:= Gear^.dY + cGravityf * Steps;
-
-Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
-
-if Gear^.FrameTicks <= Steps then
- DeleteVisualGear(Gear)
-else
- dec(Gear^.FrameTicks, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-const cSorterWorkTime = 640;
-var thexchar: array[0..cMaxTeams] of
- record
- dy, ny, dw: LongInt;
- team: PTeam;
- SortFactor: QWord;
- end;
- currsorter: PVisualGear = nil;
-
-procedure doStepTeamHealthSorterWork(Gear: PVisualGear; Steps: Longword);
-var i, t: LongInt;
-begin
-for t:= 1 to min(Steps, Gear^.Timer) do
- begin
- dec(Gear^.Timer);
- if (Gear^.Timer and 15) = 0 then
- for i:= 0 to Pred(TeamsCount) do
- with thexchar[i] do
- begin
- {$WARNINGS OFF}
- team^.DrawHealthY:= ny + dy * LongInt(Gear^.Timer) div cSorterWorkTime;
- team^.TeamHealthBarWidth:= team^.NewTeamHealthBarWidth + dw * LongInt(Gear^.Timer) div cSorterWorkTime;
- {$WARNINGS ON}
- end;
- end;
-
-if (Gear^.Timer = 0) or (currsorter <> Gear) then
- begin
- if currsorter = Gear then
- currsorter:= nil;
- DeleteVisualGear(Gear);
- exit
- end
-end;
-
-procedure doStepTeamHealthSorter(Gear: PVisualGear; Steps: Longword);
-var i: Longword;
- b: boolean;
- t: LongInt;
-begin
-Steps:= Steps; // avoid compiler hint
-
-for t:= 0 to Pred(TeamsCount) do
- with thexchar[t] do
- begin
- team:= TeamsArray[t];
- dy:= team^.DrawHealthY;
- dw:= team^.TeamHealthBarWidth - team^.NewTeamHealthBarWidth;
- if team^.TeamHealth > 0 then
- begin
- SortFactor:= team^.Clan^.ClanHealth;
- SortFactor:= (SortFactor shl 3) + team^.Clan^.ClanIndex;
- SortFactor:= (SortFactor shl 30) + team^.TeamHealth;
- end
- else
- SortFactor:= 0;
- end;
-
-if TeamsCount > 1 then
- repeat
- b:= true;
- for t:= 0 to TeamsCount - 2 do
- if (thexchar[t].SortFactor > thexchar[Succ(t)].SortFactor) then
- begin
- thexchar[cMaxTeams]:= thexchar[t];
- thexchar[t]:= thexchar[Succ(t)];
- thexchar[Succ(t)]:= thexchar[cMaxTeams];
- b:= false
- end
- until b;
-
-t:= - 4;
-for i:= 0 to Pred(TeamsCount) do
- with thexchar[i] do
- if team^.TeamHealth > 0 then
- begin
- dec(t, team^.HealthTex^.h + 2);
- ny:= t;
- dy:= dy - ny
- end;
-
-Gear^.Timer:= cSorterWorkTime;
-Gear^.doStep:= @doStepTeamHealthSorterWork;
-currsorter:= Gear;
-//doStepTeamHealthSorterWork(Gear, Steps)
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSpeechBubbleWork(Gear: PVisualGear; Steps: Longword);
-begin
-if Gear^.Timer > Steps then dec(Gear^.Timer, Steps) else Gear^.Timer:= 0;
-
-if (Gear^.Hedgehog^.Gear <> nil) then
- begin
- Gear^.X:= hwFloat2Float(Gear^.Hedgehog^.Gear^.X) + (Gear^.Tex^.w div 2 - Gear^.FrameTicks);
- Gear^.Y:= hwFloat2Float(Gear^.Hedgehog^.Gear^.Y) - (16 + Gear^.Tex^.h);
- end;
-
-if Gear^.Timer = 0 then
- begin
- if Gear^.Hedgehog^.SpeechGear = Gear then
- Gear^.Hedgehog^.SpeechGear:= nil;
- DeleteVisualGear(Gear)
- end;
-end;
-
-procedure doStepSpeechBubble(Gear: PVisualGear; Steps: Longword);
-begin
-Steps:= Steps; // avoid compiler hint
-
-with Gear^.Hedgehog^ do
- if SpeechGear <> nil then
- SpeechGear^.Timer:= 0;
-
-Gear^.Hedgehog^.SpeechGear:= Gear;
-
-Gear^.Timer:= max(LongInt(Length(Gear^.Text)) * 150, 3000);
-
-Gear^.Tex:= RenderSpeechBubbleTex(Gear^.Text, Gear^.FrameTicks, fnt16);
-
-case Gear^.FrameTicks of
- 1: Gear^.FrameTicks:= SpritesData[sprSpeechTail].Width-28;
- 2: Gear^.FrameTicks:= SpritesData[sprThoughtTail].Width-20;
- 3: Gear^.FrameTicks:= SpritesData[sprShoutTail].Width-10;
- end;
-
-Gear^.doStep:= @doStepSpeechBubbleWork;
-
-Gear^.Y:= Gear^.Y - Gear^.Tex^.h
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepHealthTagWork(Gear: PVisualGear; Steps: Longword);
-begin
-if Steps > Gear^.Timer then
- DeleteVisualGear(Gear)
-else
- begin
- dec(Gear^.Timer, Steps);
- Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
- Gear^.X:= Gear^.X + Gear^.dX * Steps
- end;
-end;
-
-procedure doStepHealthTagWorkUnderWater(Gear: PVisualGear; Steps: Longword);
-begin
-if round(Gear^.Y) - 10 < cWaterLine then
- DeleteVisualGear(Gear)
-else
- Gear^.Y:= Gear^.Y - 0.08 * Steps;
-
-end;
-
-procedure doStepHealthTag(Gear: PVisualGear; Steps: Longword);
-var s: shortstring;
-begin
-s:= '';
-
-str(Gear^.State, s);
-if Gear^.Hedgehog <> nil then
- Gear^.Tex:= RenderStringTex(s, Gear^.Hedgehog^.Team^.Clan^.Color, fnt16)
-else
- Gear^.Tex:= RenderStringTex(s, cWhiteColor, fnt16);
-
-Gear^.doStep:= @doStepHealthTagWork;
-
-if (round(Gear^.Y) > cWaterLine) and (Gear^.Frame = 0) then
- Gear^.doStep:= @doStepHealthTagWorkUnderWater;
-
-Gear^.Y:= Gear^.Y - Gear^.Tex^.h;
-
-if Steps > 1 then
- Gear^.doStep(Gear, Steps-1);
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSmokeTrace(Gear: PVisualGear; Steps: Longword);
-begin
-inc(Gear^.Timer, Steps );
-if Gear^.Timer > 64 then
- begin
- if Gear^.State = 0 then
- begin
- DeleteVisualGear(Gear);
- exit;
- end;
- dec(Gear^.State, Gear^.Timer div 65);
- Gear^.Timer:= Gear^.Timer mod 65;
- end;
-Gear^.dX:= Gear^.dX + cWindSpeedf * Steps;
-Gear^.X:= Gear^.X + Gear^.dX;
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepExplosionWork(Gear: PVisualGear; Steps: Longword);
-begin
-inc(Gear^.Timer, Steps);
-if Gear^.Timer > 75 then
- begin
- inc(Gear^.State, Gear^.Timer div 76);
- Gear^.Timer:= Gear^.Timer mod 76;
- if Gear^.State > 5 then
- DeleteVisualGear(Gear);
- end;
-end;
-
-procedure doStepExplosion(Gear: PVisualGear; Steps: Longword);
-var i: LongWord;
- gX,gY: LongInt;
- vg: PVisualGear;
-begin
-gX:= round(Gear^.X);
-gY:= round(Gear^.Y);
-for i:= 0 to 31 do
- begin
- vg:= AddVisualGear(gX, gY, vgtFire);
- if vg <> nil then
- begin
- vg^.State:= gstTmpFlag;
- inc(vg^.FrameTicks, vg^.FrameTicks)
- end
- end;
-for i:= 0 to 8 do AddVisualGear(gX, gY, vgtExplPart);
-for i:= 0 to 8 do AddVisualGear(gX, gY, vgtExplPart2);
-Gear^.doStep:= @doStepExplosionWork;
-if Steps > 1 then
- Gear^.doStep(Gear, Steps-1);
-end;
-
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepBigExplosionWork(Gear: PVisualGear; Steps: Longword);
-var maxMovement: LongInt;
-begin
-
-inc(Gear^.Timer, Steps);
-if (Gear^.Timer and 5) = 0 then
- begin
- maxMovement := max(1, 13 - ((Gear^.Timer * 15) div 250));
- ShakeCamera(maxMovement);
- end;
-
-if Gear^.Timer > 250 then
- DeleteVisualGear(Gear);
-end;
-
-procedure doStepBigExplosion(Gear: PVisualGear; Steps: Longword);
-var i: LongWord;
- gX,gY: LongInt;
- vg: PVisualGear;
-begin
-//ScreenFade:= sfFromWhite;
-//ScreenFadeValue:= round(60 * zoom * zoom);
-//ScreenFadeSpeed:= 5;
-gX:= round(Gear^.X);
-gY:= round(Gear^.Y);
-AddVisualGear(gX, gY, vgtSmokeRing);
-for i:= 0 to 46 do
- begin
- vg:= AddVisualGear(gX, gY, vgtFire);
- if vg <> nil then
- begin
- vg^.State:= gstTmpFlag;
- inc(vg^.FrameTicks, vg^.FrameTicks)
- end
- end;
-for i:= 0 to 15 do
- AddVisualGear(gX, gY, vgtExplPart);
-for i:= 0 to 15 do
- AddVisualGear(gX, gY, vgtExplPart2);
-Gear^.doStep:= @doStepBigExplosionWork;
-if Steps > 1 then
- Gear^.doStep(Gear, Steps-1);
-with mobileRecord do
- if (performRumble <> nil) and (not fastUntilLag) then
- performRumble(kSystemSoundID_Vibrate);
-end;
-
-procedure doStepChunk(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + Gear^.dX * Steps;
-
-Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
-Gear^.dY:= Gear^.dY + cGravityf * Steps;
-
-Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
-
-if (round(Gear^.Y) > cWaterLine) and ((cReducedQuality and rqPlainSplash) = 0) then
- begin
- AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtDroplet);
- DeleteVisualGear(Gear);
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepBulletHit(Gear: PVisualGear; Steps: Longword);
-begin
-if Gear^.FrameTicks <= Steps then
- DeleteVisualGear(Gear)
-else
- dec(Gear^.FrameTicks, Steps);
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepCircle(Gear: PVisualGear; Steps: Longword);
-var tmp: LongInt;
- i: LongWord;
-begin
-with Gear^ do
- if Frame <> 0 then
- for i:= 1 to Steps do
- begin
- inc(FrameTicks);
- if (FrameTicks mod Frame) = 0 then
- begin
- tmp:= Gear^.Tint and $FF;
- if tdY >= 0 then
- inc(tmp)
- else
- dec(tmp);
- if tmp < round(dX) then
- tdY:= 1;
- if tmp > round(dY) then
- tdY:= -1;
- if tmp > 255 then
- tmp := 255;
- if tmp < 0 then
- tmp := 0;
- Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or Longword(tmp)
- end
- end
-end;
-
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepSmoothWindBar(Gear: PVisualGear; Steps: Longword);
-begin
-inc(Gear^.Timer, Steps);
-
-while Gear^.Timer >= 10 do
- begin
- dec(Gear^.Timer, 10);
- if WindBarWidth < Gear^.Tag then
- inc(WindBarWidth)
- else if WindBarWidth > Gear^.Tag then
- dec(WindBarWidth);
- end;
-if cWindspeedf > Gear^.dAngle then
- begin
- cWindspeedf := cWindspeedf - Gear^.Angle*Steps;
- if cWindspeedf < Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
- end
-else if cWindspeedf < Gear^.dAngle then
- begin
- cWindspeedf := cWindspeedf + Gear^.Angle*Steps;
- if cWindspeedf > Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
- end;
-
-if (WindBarWidth = Gear^.Tag) and (cWindspeedf = Gear^.dAngle) then
- DeleteVisualGear(Gear)
-end;
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepStraightShot(Gear: PVisualGear; Steps: Longword);
-begin
-Gear^.X:= Gear^.X + Gear^.dX * Steps;
-Gear^.Y:= Gear^.Y - Gear^.dY * Steps;
-
-if Gear^.FrameTicks <= Steps then
- DeleteVisualGear(Gear)
-else
- begin
- dec(Gear^.FrameTicks, Steps);
- if (Gear^.FrameTicks < 501) and (Gear^.FrameTicks mod 5 = 0) then
- Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or (((Gear^.Tint and $000000FF) * Gear^.FrameTicks) div 500)
- end
-end;
-
diff -Nru hedgewars-0.9.19.3/hedgewars/avwrapper/CMakeLists.txt hedgewars-0.9.20.5/hedgewars/avwrapper/CMakeLists.txt
--- hedgewars-0.9.19.3/hedgewars/avwrapper/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/avwrapper/CMakeLists.txt 2013-10-31 20:21:54.000000000 +0000
@@ -0,0 +1,15 @@
+#FFMPEG/Libav libraries have been searched already in main CMakeLists.txt
+
+# TODO: this check is only for SDL < 2
+# fpc will take care of linking but we need to have this library installed
+find_package(GLUT REQUIRED)
+
+include_directories(${FFMPEG_INCLUDE_DIR})
+
+add_library(avwrapper avwrapper.c)
+#TODO: find good VERSION and SOVERSION values
+target_link_libraries(avwrapper ${FFMPEG_LIBRARIES})
+install(TARGETS avwrapper RUNTIME DESTINATION ${target_binary_install_dir}
+ LIBRARY DESTINATION ${target_library_install_dir}
+ ARCHIVE DESTINATION ${target_library_install_dir})
+
diff -Nru hedgewars-0.9.19.3/hedgewars/avwrapper/avwrapper.c hedgewars-0.9.20.5/hedgewars/avwrapper/avwrapper.c
--- hedgewars-0.9.19.3/hedgewars/avwrapper/avwrapper.c 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/avwrapper/avwrapper.c 2014-01-04 19:46:00.000000000 +0000
@@ -0,0 +1,543 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2013 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 "libavformat/avformat.h"
+#include "libavutil/mathematics.h"
+
+#ifndef AVIO_FLAG_WRITE
+#define AVIO_FLAG_WRITE AVIO_WRONLY
+#endif
+
+#if (defined _MSC_VER)
+#define AVWRAP_DECL __declspec(dllexport)
+#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun))
+#define AVWRAP_DECL __attribute__((visibility("default")))
+#else
+#define AVWRAP_DECL
+#endif
+
+static AVFormatContext* g_pContainer;
+static AVOutputFormat* g_pFormat;
+static AVStream* g_pAStream;
+static AVStream* g_pVStream;
+static AVFrame* g_pAFrame;
+static AVFrame* g_pVFrame;
+static AVCodec* g_pACodec;
+static AVCodec* g_pVCodec;
+static AVCodecContext* g_pAudio;
+static AVCodecContext* g_pVideo;
+
+static int g_Width, g_Height;
+static uint32_t g_Frequency, g_Channels;
+static int g_VQuality;
+static AVRational g_Framerate;
+
+static FILE* g_pSoundFile;
+static int16_t* g_pSamples;
+static int g_NumSamples;
+
+
+#if LIBAVCODEC_VERSION_MAJOR < 54
+#define OUTBUFFER_SIZE 200000
+static uint8_t g_OutBuffer[OUTBUFFER_SIZE];
+#endif
+
+// pointer to function from hwengine (uUtils.pas)
+static void (*AddFileLogRaw)(const char* pString);
+
+static int FatalError(const char* pFmt, ...)
+{
+ char Buffer[1024];
+ va_list VaArgs;
+
+ va_start(VaArgs, pFmt);
+ vsnprintf(Buffer, 1024, pFmt, VaArgs);
+ va_end(VaArgs);
+
+ AddFileLogRaw("Error in av-wrapper: ");
+ AddFileLogRaw(Buffer);
+ AddFileLogRaw("\n");
+ return(-1);
+}
+
+// Function to be called from libav for logging.
+// Note: libav can call LogCallback from different threads
+// (there is mutex in AddFileLogRaw).
+static void LogCallback(void* p, int Level, const char* pFmt, va_list VaArgs)
+{
+ char Buffer[1024];
+
+ vsnprintf(Buffer, 1024, pFmt, VaArgs);
+ AddFileLogRaw(Buffer);
+}
+
+static void Log(const char* pFmt, ...)
+{
+ char Buffer[1024];
+ va_list VaArgs;
+
+ va_start(VaArgs, pFmt);
+ vsnprintf(Buffer, 1024, pFmt, VaArgs);
+ va_end(VaArgs);
+
+ AddFileLogRaw(Buffer);
+}
+
+static void AddAudioStream()
+{
+#if LIBAVFORMAT_VERSION_MAJOR >= 53
+ g_pAStream = avformat_new_stream(g_pContainer, g_pACodec);
+#else
+ g_pAStream = av_new_stream(g_pContainer, 1);
+#endif
+ if(!g_pAStream)
+ {
+ Log("Could not allocate audio stream\n");
+ return;
+ }
+ g_pAStream->id = 1;
+
+ g_pAudio = g_pAStream->codec;
+
+ avcodec_get_context_defaults3(g_pAudio, g_pACodec);
+ g_pAudio->codec_id = g_pACodec->id;
+
+ // put parameters
+ g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16;
+ g_pAudio->sample_rate = g_Frequency;
+ g_pAudio->channels = g_Channels;
+
+ // set quality
+ g_pAudio->bit_rate = 160000;
+
+ // for codecs that support variable bitrate use it, it should be better
+ g_pAudio->flags |= CODEC_FLAG_QSCALE;
+ g_pAudio->global_quality = 1*FF_QP2LAMBDA;
+
+ // some formats want stream headers to be separate
+ if (g_pFormat->flags & AVFMT_GLOBALHEADER)
+ g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+ // open it
+#if LIBAVCODEC_VERSION_MAJOR >= 53
+ if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0)
+#else
+ if (avcodec_open(g_pAudio, g_pACodec) < 0)
+#endif
+ {
+ Log("Could not open audio codec %s\n", g_pACodec->long_name);
+ return;
+ }
+
+#if LIBAVCODEC_VERSION_MAJOR >= 54
+ if (g_pACodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
+#else
+ if (g_pAudio->frame_size == 0)
+#endif
+ g_NumSamples = 4096;
+ else
+ g_NumSamples = g_pAudio->frame_size;
+ g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t));
+ g_pAFrame = avcodec_alloc_frame();
+ if (!g_pAFrame)
+ {
+ Log("Could not allocate frame\n");
+ return;
+ }
+}
+
+// returns non-zero if there is more sound, -1 in case of error
+static int WriteAudioFrame()
+{
+ if (!g_pAStream)
+ return 0;
+
+ AVPacket Packet = { 0 };
+ av_init_packet(&Packet);
+
+ int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile);
+
+#if LIBAVCODEC_VERSION_MAJOR >= 53
+ AVFrame* pFrame = NULL;
+ if (NumSamples > 0)
+ {
+ g_pAFrame->nb_samples = NumSamples;
+ avcodec_fill_audio_frame(g_pAFrame, g_Channels, AV_SAMPLE_FMT_S16,
+ (uint8_t*)g_pSamples, NumSamples*2*g_Channels, 1);
+ pFrame = g_pAFrame;
+ }
+ // when NumSamples == 0 we still need to call encode_audio2 to flush
+ int got_packet;
+ if (avcodec_encode_audio2(g_pAudio, &Packet, pFrame, &got_packet) != 0)
+ return FatalError("avcodec_encode_audio2 failed");
+ if (!got_packet)
+ return 0;
+#else
+ if (NumSamples == 0)
+ return 0;
+ int BufferSize = OUTBUFFER_SIZE;
+ if (g_pAudio->frame_size == 0)
+ BufferSize = NumSamples*g_Channels*2;
+ Packet.size = avcodec_encode_audio(g_pAudio, g_OutBuffer, BufferSize, g_pSamples);
+ if (Packet.size == 0)
+ return 1;
+ if (g_pAudio->coded_frame && g_pAudio->coded_frame->pts != AV_NOPTS_VALUE)
+ Packet.pts = av_rescale_q(g_pAudio->coded_frame->pts, g_pAudio->time_base, g_pAStream->time_base);
+ Packet.flags |= AV_PKT_FLAG_KEY;
+ Packet.data = g_OutBuffer;
+#endif
+
+ // Write the compressed frame to the media file.
+ Packet.stream_index = g_pAStream->index;
+ if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
+ return FatalError("Error while writing audio frame");
+ return 1;
+}
+
+// add a video output stream
+static int AddVideoStream()
+{
+#if LIBAVFORMAT_VERSION_MAJOR >= 53
+ g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
+#else
+ g_pVStream = av_new_stream(g_pContainer, 0);
+#endif
+ if (!g_pVStream)
+ return FatalError("Could not allocate video stream");
+
+ g_pVideo = g_pVStream->codec;
+
+ avcodec_get_context_defaults3(g_pVideo, g_pVCodec);
+ g_pVideo->codec_id = g_pVCodec->id;
+
+ // put parameters
+ // resolution must be a multiple of two
+ g_pVideo->width = g_Width & ~1; // make even (dimensions should be even)
+ g_pVideo->height = g_Height & ~1; // make even
+ /* time base: this is the fundamental unit of time (in seconds) in terms
+ of which frame timestamps are represented. for fixed-fps content,
+ timebase should be 1/framerate and timestamp increments should be
+ identically 1. */
+ g_pVideo->time_base.den = g_Framerate.num;
+ g_pVideo->time_base.num = g_Framerate.den;
+ //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */
+ g_pVideo->pix_fmt = PIX_FMT_YUV420P;
+
+ // set quality
+ if (g_VQuality > 100)
+ g_pVideo->bit_rate = g_VQuality;
+ else
+ {
+ g_pVideo->flags |= CODEC_FLAG_QSCALE;
+ g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA;
+ }
+
+ // some formats want stream headers to be separate
+ if (g_pFormat->flags & AVFMT_GLOBALHEADER)
+ g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+#if LIBAVCODEC_VERSION_MAJOR < 53
+ // for some versions of ffmpeg x264 options must be set explicitly
+ if (strcmp(g_pVCodec->name, "libx264") == 0)
+ {
+ g_pVideo->coder_type = FF_CODER_TYPE_AC;
+ g_pVideo->flags |= CODEC_FLAG_LOOP_FILTER;
+ g_pVideo->crf = 23;
+ g_pVideo->thread_count = 3;
+ g_pVideo->me_cmp = FF_CMP_CHROMA;
+ g_pVideo->partitions = X264_PART_I8X8 | X264_PART_I4X4 | X264_PART_P8X8 | X264_PART_B8X8;
+ g_pVideo->me_method = ME_HEX;
+ g_pVideo->me_subpel_quality = 7;
+ g_pVideo->me_range = 16;
+ g_pVideo->gop_size = 250;
+ g_pVideo->keyint_min = 25;
+ g_pVideo->scenechange_threshold = 40;
+ g_pVideo->i_quant_factor = 0.71;
+ g_pVideo->b_frame_strategy = 1;
+ g_pVideo->qcompress = 0.6;
+ g_pVideo->qmin = 10;
+ g_pVideo->qmax = 51;
+ g_pVideo->max_qdiff = 4;
+ g_pVideo->max_b_frames = 3;
+ g_pVideo->refs = 3;
+ g_pVideo->directpred = 1;
+ g_pVideo->trellis = 1;
+ g_pVideo->flags2 = CODEC_FLAG2_BPYRAMID | CODEC_FLAG2_MIXED_REFS | CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT | CODEC_FLAG2_FASTPSKIP;
+ g_pVideo->weighted_p_pred = 2;
+ }
+#endif
+
+ // open the codec
+#if LIBAVCODEC_VERSION_MAJOR >= 53
+ AVDictionary* pDict = NULL;
+ if (strcmp(g_pVCodec->name, "libx264") == 0)
+ av_dict_set(&pDict, "preset", "medium", 0);
+
+ if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0)
+#else
+ if (avcodec_open(g_pVideo, g_pVCodec) < 0)
+#endif
+ return FatalError("Could not open video codec %s", g_pVCodec->long_name);
+
+ g_pVFrame = avcodec_alloc_frame();
+ if (!g_pVFrame)
+ return FatalError("Could not allocate frame");
+
+ g_pVFrame->linesize[0] = g_Width;
+ g_pVFrame->linesize[1] = g_Width/2;
+ g_pVFrame->linesize[2] = g_Width/2;
+ g_pVFrame->linesize[3] = 0;
+ return 0;
+}
+
+static int WriteFrame(AVFrame* pFrame)
+{
+ double AudioTime, VideoTime;
+ int ret;
+ // write interleaved audio frame
+ if (g_pAStream)
+ {
+ VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den;
+ do
+ {
+ AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den;
+ ret = WriteAudioFrame();
+ }
+ while (AudioTime < VideoTime && ret);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (!g_pVStream)
+ return 0;
+
+ AVPacket Packet;
+ av_init_packet(&Packet);
+ Packet.data = NULL;
+ Packet.size = 0;
+
+ g_pVFrame->pts++;
+ if (g_pFormat->flags & AVFMT_RAWPICTURE)
+ {
+ /* raw video case. The API will change slightly in the near
+ future for that. */
+ Packet.flags |= AV_PKT_FLAG_KEY;
+ Packet.stream_index = g_pVStream->index;
+ Packet.data = (uint8_t*)pFrame;
+ Packet.size = sizeof(AVPicture);
+
+ if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
+ return FatalError("Error while writing video frame");
+ return 0;
+ }
+ else
+ {
+#if LIBAVCODEC_VERSION_MAJOR >= 54
+ int got_packet;
+ if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0)
+ return FatalError("avcodec_encode_video2 failed");
+ if (!got_packet)
+ return 0;
+
+ if (Packet.pts != AV_NOPTS_VALUE)
+ Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base);
+ if (Packet.dts != AV_NOPTS_VALUE)
+ Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base);
+#else
+ Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame);
+ if (Packet.size < 0)
+ return FatalError("avcodec_encode_video failed");
+ if (Packet.size == 0)
+ return 0;
+
+ if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE)
+ Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base);
+ if( g_pVideo->coded_frame->key_frame )
+ Packet.flags |= AV_PKT_FLAG_KEY;
+ Packet.data = g_OutBuffer;
+#endif
+ // write the compressed frame in the media file
+ Packet.stream_index = g_pVStream->index;
+ if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
+ return FatalError("Error while writing video frame");
+
+ return 1;
+ }
+}
+
+AVWRAP_DECL int AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr)
+{
+ g_pVFrame->data[0] = pY;
+ g_pVFrame->data[1] = pCb;
+ g_pVFrame->data[2] = pCr;
+ return WriteFrame(g_pVFrame);
+}
+
+AVWRAP_DECL int AVWrapper_Init(
+ void (*pAddFileLogRaw)(const char*),
+ const char* pFilename,
+ const char* pDesc,
+ const char* pSoundFile,
+ const char* pFormatName,
+ const char* pVCodecName,
+ const char* pACodecName,
+ int Width, int Height,
+ int FramerateNum, int FramerateDen,
+ int VQuality)
+{
+ int ret;
+ AddFileLogRaw = pAddFileLogRaw;
+ av_log_set_callback( &LogCallback );
+
+ g_Width = Width;
+ g_Height = Height;
+ g_Framerate.num = FramerateNum;
+ g_Framerate.den = FramerateDen;
+ g_VQuality = VQuality;
+
+ // initialize libav and register all codecs and formats
+ av_register_all();
+
+ // find format
+ g_pFormat = av_guess_format(pFormatName, NULL, NULL);
+ if (!g_pFormat)
+ return FatalError("Format \"%s\" was not found", pFormatName);
+
+ // allocate the output media context
+ g_pContainer = avformat_alloc_context();
+ if (!g_pContainer)
+ return FatalError("Could not allocate output context");
+
+ g_pContainer->oformat = g_pFormat;
+
+ // store description of file
+ av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0);
+
+ // append extesnion to filename
+ char ext[16];
+ strncpy(ext, g_pFormat->extensions, 16);
+ ext[15] = 0;
+ ext[strcspn(ext,",")] = 0;
+ snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s.%s", pFilename, ext);
+
+ // find codecs
+ g_pVCodec = avcodec_find_encoder_by_name(pVCodecName);
+ g_pACodec = avcodec_find_encoder_by_name(pACodecName);
+
+ // add audio and video stream to container
+ g_pVStream = NULL;
+ g_pAStream = NULL;
+
+ if (g_pVCodec)
+ {
+ ret = AddVideoStream();
+ if (ret < 0)
+ return ret;
+ }
+ else
+ Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName);
+
+ if (g_pACodec)
+ {
+ g_pSoundFile = fopen(pSoundFile, "rb");
+ if (g_pSoundFile)
+ {
+ fread(&g_Frequency, 4, 1, g_pSoundFile);
+ fread(&g_Channels, 4, 1, g_pSoundFile);
+ AddAudioStream();
+ }
+ else
+ Log("Could not open %s\n", pSoundFile);
+ }
+ else
+ Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName);
+
+ if (!g_pAStream && !g_pVStream)
+ return FatalError("No video, no audio, aborting...");
+
+ // write format info to log
+ av_dump_format(g_pContainer, 0, g_pContainer->filename, 1);
+
+ // open the output file, if needed
+ if (!(g_pFormat->flags & AVFMT_NOFILE))
+ {
+ if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0)
+ return FatalError("Could not open output file (%s)", g_pContainer->filename);
+ }
+
+ // write the stream header, if any
+ avformat_write_header(g_pContainer, NULL);
+
+ g_pVFrame->pts = -1;
+ return 0;
+}
+
+AVWRAP_DECL int AVWrapper_Close()
+{
+ int ret;
+ // output buffered frames
+ if (g_pVCodec->capabilities & CODEC_CAP_DELAY)
+ {
+ do
+ ret = WriteFrame(NULL);
+ while (ret >= 0);
+ if (ret < 0)
+ return ret;
+ }
+ // output any remaining audio
+ do
+ {
+ ret = WriteAudioFrame();
+ }
+ while(ret >= 0);
+ if (ret < 0)
+ return ret;
+
+ // write the trailer, if any.
+ av_write_trailer(g_pContainer);
+
+ // close the output file
+ if (!(g_pFormat->flags & AVFMT_NOFILE))
+ avio_close(g_pContainer->pb);
+
+ // free everything
+ if (g_pVStream)
+ {
+ avcodec_close(g_pVideo);
+ av_free(g_pVideo);
+ av_free(g_pVStream);
+ av_free(g_pVFrame);
+ }
+ if (g_pAStream)
+ {
+ avcodec_close(g_pAudio);
+ av_free(g_pAudio);
+ av_free(g_pAStream);
+ av_free(g_pAFrame);
+ av_free(g_pSamples);
+ fclose(g_pSoundFile);
+ }
+
+ av_free(g_pContainer);
+ return 0;
+}
diff -Nru hedgewars-0.9.19.3/hedgewars/avwrapper.c hedgewars-0.9.20.5/hedgewars/avwrapper.c
--- hedgewars-0.9.19.3/hedgewars/avwrapper.c 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/avwrapper.c 1970-01-01 00:00:00.000000000 +0000
@@ -1,509 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2013 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 "libavformat/avformat.h"
-#include "libavutil/mathematics.h"
-
-#ifndef AVIO_FLAG_WRITE
-#define AVIO_FLAG_WRITE AVIO_WRONLY
-#endif
-
-static AVFormatContext* g_pContainer;
-static AVOutputFormat* g_pFormat;
-static AVStream* g_pAStream;
-static AVStream* g_pVStream;
-static AVFrame* g_pAFrame;
-static AVFrame* g_pVFrame;
-static AVCodec* g_pACodec;
-static AVCodec* g_pVCodec;
-static AVCodecContext* g_pAudio;
-static AVCodecContext* g_pVideo;
-
-static int g_Width, g_Height;
-static uint32_t g_Frequency, g_Channels;
-static int g_VQuality;
-static AVRational g_Framerate;
-
-static FILE* g_pSoundFile;
-static int16_t* g_pSamples;
-static int g_NumSamples;
-
-
-#if LIBAVCODEC_VERSION_MAJOR < 54
-#define OUTBUFFER_SIZE 200000
-static uint8_t g_OutBuffer[OUTBUFFER_SIZE];
-#endif
-
-// pointer to function from hwengine (uUtils.pas)
-static void (*AddFileLogRaw)(const char* pString);
-
-static void FatalError(const char* pFmt, ...)
-{
- char Buffer[1024];
- va_list VaArgs;
-
- va_start(VaArgs, pFmt);
- vsnprintf(Buffer, 1024, pFmt, VaArgs);
- va_end(VaArgs);
-
- AddFileLogRaw("Error in av-wrapper: ");
- AddFileLogRaw(Buffer);
- AddFileLogRaw("\n");
- exit(1);
-}
-
-// Function to be called from libav for logging.
-// Note: libav can call LogCallback from different threads
-// (there is mutex in AddFileLogRaw).
-static void LogCallback(void* p, int Level, const char* pFmt, va_list VaArgs)
-{
- char Buffer[1024];
-
- vsnprintf(Buffer, 1024, pFmt, VaArgs);
- AddFileLogRaw(Buffer);
-}
-
-static void Log(const char* pFmt, ...)
-{
- char Buffer[1024];
- va_list VaArgs;
-
- va_start(VaArgs, pFmt);
- vsnprintf(Buffer, 1024, pFmt, VaArgs);
- va_end(VaArgs);
-
- AddFileLogRaw(Buffer);
-}
-
-static void AddAudioStream()
-{
-#if LIBAVFORMAT_VERSION_MAJOR >= 53
- g_pAStream = avformat_new_stream(g_pContainer, g_pACodec);
-#else
- g_pAStream = av_new_stream(g_pContainer, 1);
-#endif
- if(!g_pAStream)
- {
- Log("Could not allocate audio stream\n");
- return;
- }
- g_pAStream->id = 1;
-
- g_pAudio = g_pAStream->codec;
-
- avcodec_get_context_defaults3(g_pAudio, g_pACodec);
- g_pAudio->codec_id = g_pACodec->id;
-
- // put parameters
- g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16;
- g_pAudio->sample_rate = g_Frequency;
- g_pAudio->channels = g_Channels;
-
- // set quality
- g_pAudio->bit_rate = 160000;
-
- // for codecs that support variable bitrate use it, it should be better
- g_pAudio->flags |= CODEC_FLAG_QSCALE;
- g_pAudio->global_quality = 1*FF_QP2LAMBDA;
-
- // some formats want stream headers to be separate
- if (g_pFormat->flags & AVFMT_GLOBALHEADER)
- g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
- // open it
-#if LIBAVCODEC_VERSION_MAJOR >= 53
- if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0)
-#else
- if (avcodec_open(g_pAudio, g_pACodec) < 0)
-#endif
- {
- Log("Could not open audio codec %s\n", g_pACodec->long_name);
- return;
- }
-
-#if LIBAVCODEC_VERSION_MAJOR >= 54
- if (g_pACodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
-#else
- if (g_pAudio->frame_size == 0)
-#endif
- g_NumSamples = 4096;
- else
- g_NumSamples = g_pAudio->frame_size;
- g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t));
- g_pAFrame = avcodec_alloc_frame();
- if (!g_pAFrame)
- {
- Log("Could not allocate frame\n");
- return;
- }
-}
-
-// returns non-zero if there is more sound
-static int WriteAudioFrame()
-{
- if (!g_pAStream)
- return 0;
-
- AVPacket Packet = { 0 };
- av_init_packet(&Packet);
-
- int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile);
-
-#if LIBAVCODEC_VERSION_MAJOR >= 53
- AVFrame* pFrame = NULL;
- if (NumSamples > 0)
- {
- g_pAFrame->nb_samples = NumSamples;
- avcodec_fill_audio_frame(g_pAFrame, g_Channels, AV_SAMPLE_FMT_S16,
- (uint8_t*)g_pSamples, NumSamples*2*g_Channels, 1);
- pFrame = g_pAFrame;
- }
- // when NumSamples == 0 we still need to call encode_audio2 to flush
- int got_packet;
- if (avcodec_encode_audio2(g_pAudio, &Packet, pFrame, &got_packet) != 0)
- FatalError("avcodec_encode_audio2 failed");
- if (!got_packet)
- return 0;
-#else
- if (NumSamples == 0)
- return 0;
- int BufferSize = OUTBUFFER_SIZE;
- if (g_pAudio->frame_size == 0)
- BufferSize = NumSamples*g_Channels*2;
- Packet.size = avcodec_encode_audio(g_pAudio, g_OutBuffer, BufferSize, g_pSamples);
- if (Packet.size == 0)
- return 1;
- if (g_pAudio->coded_frame && g_pAudio->coded_frame->pts != AV_NOPTS_VALUE)
- Packet.pts = av_rescale_q(g_pAudio->coded_frame->pts, g_pAudio->time_base, g_pAStream->time_base);
- Packet.flags |= AV_PKT_FLAG_KEY;
- Packet.data = g_OutBuffer;
-#endif
-
- // Write the compressed frame to the media file.
- Packet.stream_index = g_pAStream->index;
- if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
- FatalError("Error while writing audio frame");
- return 1;
-}
-
-// add a video output stream
-static void AddVideoStream()
-{
-#if LIBAVFORMAT_VERSION_MAJOR >= 53
- g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
-#else
- g_pVStream = av_new_stream(g_pContainer, 0);
-#endif
- if (!g_pVStream)
- FatalError("Could not allocate video stream");
-
- g_pVideo = g_pVStream->codec;
-
- avcodec_get_context_defaults3(g_pVideo, g_pVCodec);
- g_pVideo->codec_id = g_pVCodec->id;
-
- // put parameters
- // resolution must be a multiple of two
- g_pVideo->width = g_Width & ~1; // make even (dimensions should be even)
- g_pVideo->height = g_Height & ~1; // make even
- /* time base: this is the fundamental unit of time (in seconds) in terms
- of which frame timestamps are represented. for fixed-fps content,
- timebase should be 1/framerate and timestamp increments should be
- identically 1. */
- g_pVideo->time_base.den = g_Framerate.num;
- g_pVideo->time_base.num = g_Framerate.den;
- //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */
- g_pVideo->pix_fmt = PIX_FMT_YUV420P;
-
- // set quality
- if (g_VQuality > 100)
- g_pVideo->bit_rate = g_VQuality;
- else
- {
- g_pVideo->flags |= CODEC_FLAG_QSCALE;
- g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA;
- }
-
- // some formats want stream headers to be separate
- if (g_pFormat->flags & AVFMT_GLOBALHEADER)
- g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
-#if LIBAVCODEC_VERSION_MAJOR < 53
- // for some versions of ffmpeg x264 options must be set explicitly
- if (strcmp(g_pVCodec->name, "libx264") == 0)
- {
- g_pVideo->coder_type = FF_CODER_TYPE_AC;
- g_pVideo->flags |= CODEC_FLAG_LOOP_FILTER;
- g_pVideo->crf = 23;
- g_pVideo->thread_count = 3;
- g_pVideo->me_cmp = FF_CMP_CHROMA;
- g_pVideo->partitions = X264_PART_I8X8 | X264_PART_I4X4 | X264_PART_P8X8 | X264_PART_B8X8;
- g_pVideo->me_method = ME_HEX;
- g_pVideo->me_subpel_quality = 7;
- g_pVideo->me_range = 16;
- g_pVideo->gop_size = 250;
- g_pVideo->keyint_min = 25;
- g_pVideo->scenechange_threshold = 40;
- g_pVideo->i_quant_factor = 0.71;
- g_pVideo->b_frame_strategy = 1;
- g_pVideo->qcompress = 0.6;
- g_pVideo->qmin = 10;
- g_pVideo->qmax = 51;
- g_pVideo->max_qdiff = 4;
- g_pVideo->max_b_frames = 3;
- g_pVideo->refs = 3;
- g_pVideo->directpred = 1;
- g_pVideo->trellis = 1;
- g_pVideo->flags2 = CODEC_FLAG2_BPYRAMID | CODEC_FLAG2_MIXED_REFS | CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT | CODEC_FLAG2_FASTPSKIP;
- g_pVideo->weighted_p_pred = 2;
- }
-#endif
-
- // open the codec
-#if LIBAVCODEC_VERSION_MAJOR >= 53
- AVDictionary* pDict = NULL;
- if (strcmp(g_pVCodec->name, "libx264") == 0)
- av_dict_set(&pDict, "preset", "medium", 0);
-
- if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0)
-#else
- if (avcodec_open(g_pVideo, g_pVCodec) < 0)
-#endif
- FatalError("Could not open video codec %s", g_pVCodec->long_name);
-
- g_pVFrame = avcodec_alloc_frame();
- if (!g_pVFrame)
- FatalError("Could not allocate frame");
-
- g_pVFrame->linesize[0] = g_Width;
- g_pVFrame->linesize[1] = g_Width/2;
- g_pVFrame->linesize[2] = g_Width/2;
- g_pVFrame->linesize[3] = 0;
-}
-
-static int WriteFrame(AVFrame* pFrame)
-{
- double AudioTime, VideoTime;
-
- // write interleaved audio frame
- if (g_pAStream)
- {
- VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den;
- do
- AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den;
- while (AudioTime < VideoTime && WriteAudioFrame());
- }
-
- if (!g_pVStream)
- return 0;
-
- AVPacket Packet;
- av_init_packet(&Packet);
- Packet.data = NULL;
- Packet.size = 0;
-
- g_pVFrame->pts++;
- if (g_pFormat->flags & AVFMT_RAWPICTURE)
- {
- /* raw video case. The API will change slightly in the near
- future for that. */
- Packet.flags |= AV_PKT_FLAG_KEY;
- Packet.stream_index = g_pVStream->index;
- Packet.data = (uint8_t*)pFrame;
- Packet.size = sizeof(AVPicture);
-
- if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
- FatalError("Error while writing video frame");
- return 0;
- }
- else
- {
-#if LIBAVCODEC_VERSION_MAJOR >= 54
- int got_packet;
- if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0)
- FatalError("avcodec_encode_video2 failed");
- if (!got_packet)
- return 0;
-
- if (Packet.pts != AV_NOPTS_VALUE)
- Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base);
- if (Packet.dts != AV_NOPTS_VALUE)
- Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base);
-#else
- Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame);
- if (Packet.size < 0)
- FatalError("avcodec_encode_video failed");
- if (Packet.size == 0)
- return 0;
-
- if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE)
- Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base);
- if( g_pVideo->coded_frame->key_frame )
- Packet.flags |= AV_PKT_FLAG_KEY;
- Packet.data = g_OutBuffer;
-#endif
- // write the compressed frame in the media file
- Packet.stream_index = g_pVStream->index;
- if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
- FatalError("Error while writing video frame");
-
- return 1;
- }
-}
-
-void AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr)
-{
- g_pVFrame->data[0] = pY;
- g_pVFrame->data[1] = pCb;
- g_pVFrame->data[2] = pCr;
- WriteFrame(g_pVFrame);
-}
-
-void AVWrapper_Init(
- void (*pAddFileLogRaw)(const char*),
- const char* pFilename,
- const char* pDesc,
- const char* pSoundFile,
- const char* pFormatName,
- const char* pVCodecName,
- const char* pACodecName,
- int Width, int Height,
- int FramerateNum, int FramerateDen,
- int VQuality)
-{
- AddFileLogRaw = pAddFileLogRaw;
- av_log_set_callback( &LogCallback );
-
- g_Width = Width;
- g_Height = Height;
- g_Framerate.num = FramerateNum;
- g_Framerate.den = FramerateDen;
- g_VQuality = VQuality;
-
- // initialize libav and register all codecs and formats
- av_register_all();
-
- // find format
- g_pFormat = av_guess_format(pFormatName, NULL, NULL);
- if (!g_pFormat)
- FatalError("Format \"%s\" was not found", pFormatName);
-
- // allocate the output media context
- g_pContainer = avformat_alloc_context();
- if (!g_pContainer)
- FatalError("Could not allocate output context");
-
- g_pContainer->oformat = g_pFormat;
-
- // store description of file
- av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0);
-
- // append extesnion to filename
- char ext[16];
- strncpy(ext, g_pFormat->extensions, 16);
- ext[15] = 0;
- ext[strcspn(ext,",")] = 0;
- snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s.%s", pFilename, ext);
-
- // find codecs
- g_pVCodec = avcodec_find_encoder_by_name(pVCodecName);
- g_pACodec = avcodec_find_encoder_by_name(pACodecName);
-
- // add audio and video stream to container
- g_pVStream = NULL;
- g_pAStream = NULL;
-
- if (g_pVCodec)
- AddVideoStream();
- else
- Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName);
-
- if (g_pACodec)
- {
- g_pSoundFile = fopen(pSoundFile, "rb");
- if (g_pSoundFile)
- {
- fread(&g_Frequency, 4, 1, g_pSoundFile);
- fread(&g_Channels, 4, 1, g_pSoundFile);
- AddAudioStream();
- }
- else
- Log("Could not open %s\n", pSoundFile);
- }
- else
- Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName);
-
- if (!g_pAStream && !g_pVStream)
- FatalError("No video, no audio, aborting...");
-
- // write format info to log
- av_dump_format(g_pContainer, 0, g_pContainer->filename, 1);
-
- // open the output file, if needed
- if (!(g_pFormat->flags & AVFMT_NOFILE))
- {
- if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0)
- FatalError("Could not open output file (%s)", g_pContainer->filename);
- }
-
- // write the stream header, if any
- avformat_write_header(g_pContainer, NULL);
-
- g_pVFrame->pts = -1;
-}
-
-void AVWrapper_Close()
-{
- // output buffered frames
- if (g_pVCodec->capabilities & CODEC_CAP_DELAY)
- while( WriteFrame(NULL) );
- // output any remaining audio
- while( WriteAudioFrame() );
-
- // write the trailer, if any.
- av_write_trailer(g_pContainer);
-
- // close the output file
- if (!(g_pFormat->flags & AVFMT_NOFILE))
- avio_close(g_pContainer->pb);
-
- // free everything
- if (g_pVStream)
- {
- avcodec_close(g_pVideo);
- av_free(g_pVideo);
- av_free(g_pVStream);
- av_free(g_pVFrame);
- }
- if (g_pAStream)
- {
- avcodec_close(g_pAudio);
- av_free(g_pAudio);
- av_free(g_pAStream);
- av_free(g_pAFrame);
- av_free(g_pSamples);
- fclose(g_pSoundFile);
- }
-
- av_free(g_pContainer);
-}
diff -Nru hedgewars-0.9.19.3/hedgewars/config.inc.in hedgewars-0.9.20.5/hedgewars/config.inc.in
--- hedgewars-0.9.19.3/hedgewars/config.inc.in 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/config.inc.in 2013-10-31 20:21:54.000000000 +0000
@@ -25,5 +25,4 @@
cVersionString = '${HEDGEWARS_VERSION}';
cRevisionString = '${HEDGEWARS_REVISION}';
cHashString = '${HEDGEWARS_HASH}';
- cLuaLibrary = '${LUA_LIBRARY}';
cDefaultPathPrefix = '${HEDGEWARS_FULL_DATADIR}/Data';
diff -Nru hedgewars-0.9.19.3/hedgewars/hwLibrary.pas hedgewars-0.9.20.5/hedgewars/hwLibrary.pas
--- hedgewars-0.9.19.3/hedgewars/hwLibrary.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/hwLibrary.pas 2013-10-31 20:21:54.000000000 +0000
@@ -41,6 +41,11 @@
versionStr^:= cVersionString;
end;
+function HW_versionString: PChar; cdecl; export;
+begin
+ exit(cVersionString + '-r' + cRevisionString + ' (' + cHashString + ')');
+end;
+
// equivalent to esc+y; when closeFrontend = true the game exits after memory cleanup
procedure HW_terminate(closeFrontend: boolean); cdecl; export;
begin
@@ -118,6 +123,7 @@
GenLandPreview,
LoadLocaleWrapper,
HW_versionInfo,
+ HW_versionString,
HW_terminate,
HW_getNumberOfWeapons,
HW_getMaxNumberOfHogs,
diff -Nru hedgewars-0.9.19.3/hedgewars/hwengine.pas hedgewars-0.9.20.5/hedgewars/hwengine.pas
--- hedgewars-0.9.19.3/hedgewars/hwengine.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/hwengine.pas 2014-01-08 16:25:17.000000000 +0000
@@ -32,14 +32,12 @@
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, uCursor, uRandom
+ , uPhysFSLayer, uCursor, uRandom, ArgParsers, uVisualGearsHandlers, uTextures
{$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);
@@ -54,8 +52,6 @@
procedure freeEverything(complete:boolean); forward;
{$ENDIF}
-{$INCLUDE "ArgParsers.inc"}
-
///////////////////////////////////////////////////////////////////////////////
function DoTimer(Lag: LongInt): boolean;
var s: shortstring;
@@ -75,6 +71,7 @@
end;
gsStart:
begin
+ SetDefaultBinds;
if HasBorder then
DisableSomeWeapons;
AddClouds;
@@ -140,7 +137,7 @@
var event: TSDL_Event;
PrevTime, CurrTime: Longword;
isTerminated: boolean;
-{$IFDEF SDL13}
+{$IFDEF SDL2}
previousGameState: TGameState;
{$ELSE}
prevFocusState: boolean;
@@ -152,17 +149,17 @@
begin
SDL_PumpEvents();
- while SDL_PeepEvents(@event, 1, SDL_GETEVENT, {$IFDEF SDL13}SDL_FIRSTEVENT, SDL_LASTEVENT{$ELSE}SDL_ALLEVENTS{$ENDIF}) > 0 do
+ while SDL_PeepEvents(@event, 1, SDL_GETEVENT, {$IFDEF SDL2}SDL_FIRSTEVENT, SDL_LASTEVENT{$ELSE}SDL_ALLEVENTS{$ENDIF}) > 0 do
begin
case event.type_ of
-{$IFDEF SDL13}
+{$IFDEF SDL2}
SDL_KEYDOWN:
if GameState = gsChat then
begin
// sdl on iphone supports only ashii keyboards and the unicode field is deprecated in sdl 1.3
KeyPressChat(SDL_GetKeyFromScancode(event.key.keysym.sym), event.key.keysym.sym); //TODO correct for keymodifiers
end
- else
+ else
if GameState >= gsGame then ProcessKey(event.key);
SDL_KEYUP:
if (GameState <> gsChat) and (GameState >= gsGame) then
@@ -193,15 +190,16 @@
cNewScreenHeight:= max(2 * (event.window.data2 div 2), cMinScreenHeight);
cScreenResizeDelay:= RealTicks + 500{$IFDEF IPHONEOS}div 2{$ENDIF};
end;
-
+{$IFDEF USE_TOUCH_INTERFACE}
SDL_FINGERMOTION:
- onTouchMotion(event.tfinger.x, event.tfinger.y,event.tfinger.dx, event.tfinger.dy, event.tfinger.fingerId);
+ onTouchMotion(event.tfinger.x, event.tfinger.y, event.tfinger.dx, event.tfinger.dy, event.tfinger.fingerId);
SDL_FINGERDOWN:
onTouchDown(event.tfinger.x, event.tfinger.y, event.tfinger.fingerId);
SDL_FINGERUP:
onTouchUp(event.tfinger.x, event.tfinger.y, event.tfinger.fingerId);
+{$ENDIF}
{$ELSE}
SDL_KEYDOWN:
if GameState = gsChat then
@@ -341,7 +339,11 @@
if not cOnlyStats then SDLTry(SDL_Init(SDL_INIT_VIDEO or SDL_INIT_NOPARACHUTE) >= 0, true);
WriteLnToConsole(msgOK);
+{$IFDEF SDL2}
+ SDL_StartTextInput();
+{$ELSE}
SDL_EnableUNICODE(1);
+{$ENDIF}
SDL_ShowCursor(0);
WriteToConsole('Init SDL_ttf... ');
@@ -401,7 +403,7 @@
isDeveloperMode:= false;
TryDo(InitStepsFlags = cifAllInited, 'Some parameters not set (flags = ' + inttostr(InitStepsFlags) + ')', true);
- ParseCommand('rotmask', true);
+ //ParseCommand('rotmask', true);
{$IFDEF USE_VIDEO_RECORDING}
if GameType = gmtRecord then
@@ -440,9 +442,10 @@
if complete then
begin
uPhysFSLayer.initModule;
+ uTextures.initModule;
{$IFDEF ANDROID}GLUnit.initModule;{$ENDIF}
{$IFDEF USE_TOUCH_INTERFACE}uTouch.initModule;{$ENDIF}
-{$IFDEF USE_VIDEO_RECORDING}uVideoRec.initModule;{$ENDIF} //stub
+{$IFDEF USE_VIDEO_RECORDING}uVideoRec.initModule;{$ENDIF}
uAI.initModule;
uAIMisc.initModule;
uAILandMarks.initModule; //stub
@@ -452,7 +455,7 @@
uChat.initModule;
uCollisions.initModule;
uGears.initModule;
- uInputHandler.initModule; //stub
+ uInputHandler.initModule;
uMisc.initModule;
uLandTexture.initModule; //stub
uScript.initModule;
@@ -461,6 +464,7 @@
uStore.initModule;
uTeams.initModule;
uVisualGears.initModule;
+ uVisualGearsHandlers.initModule;
uWorld.initModule;
end;
end;
@@ -491,6 +495,7 @@
{$IFDEF USE_VIDEO_RECORDING}uVideoRec.freeModule;{$ENDIF}
{$IFDEF USE_TOUCH_INTERFACE}uTouch.freeModule;{$ENDIF} //stub
{$IFDEF ANDROID}GLUnit.freeModule;{$ENDIF}
+ uTextures.freeModule;
uPhysFSLayer.freeModule;
end;
@@ -533,6 +538,7 @@
///////////////////////////////////////////////////////////////////////////////
begin
preInitEverything();
+ cTagsMask:= htTeamName or htName or htHealth; // this one doesn't fit nicely w/ reset of other variables. suggestions welcome
GetParams();
if GameType = gmtLandPreview then
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/hedgewars/hwengine.res and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/hedgewars/hwengine.res differ
diff -Nru hedgewars-0.9.19.3/hedgewars/options.inc hedgewars-0.9.20.5/hedgewars/options.inc
--- hedgewars-0.9.19.3/hedgewars/options.inc 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/options.inc 2014-01-08 16:25:17.000000000 +0000
@@ -61,7 +61,7 @@
{$ENDIF}
{$IFDEF USE_TOUCH_INTERFACE}
- {$DEFINE SDL13}
+ {$DEFINE SDL2}
{$ENDIF}
diff -Nru hedgewars-0.9.19.3/hedgewars/sdlmain/CMakeLists.txt hedgewars-0.9.20.5/hedgewars/sdlmain/CMakeLists.txt
--- hedgewars-0.9.19.3/hedgewars/sdlmain/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/sdlmain/CMakeLists.txt 2013-10-31 20:21:54.000000000 +0000
@@ -0,0 +1,7 @@
+find_package(SDL REQUIRED)
+
+include_directories(${SDL_INCLUDE_DIR})
+
+add_library (SDLmain STATIC SDLMain.m)
+
+
diff -Nru hedgewars-0.9.19.3/hedgewars/sdlmain/SDLMain.h hedgewars-0.9.20.5/hedgewars/sdlmain/SDLMain.h
--- hedgewars-0.9.19.3/hedgewars/sdlmain/SDLMain.h 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/sdlmain/SDLMain.h 2013-10-31 20:21:54.000000000 +0000
@@ -0,0 +1,16 @@
+/* SDLMain.m - main entry point for our Cocoa-ized SDL app
+ Initial Version: Darrell Walisser
+ Non-NIB-Code & other changes: Max Horn
+
+ Feel free to customize this file to suit your needs
+*/
+
+#ifndef _SDLMain_h_
+#define _SDLMain_h_
+
+#import
+
+@interface SDLMain : NSObject
+@end
+
+#endif /* _SDLMain_h_ */
diff -Nru hedgewars-0.9.19.3/hedgewars/sdlmain/SDLMain.m hedgewars-0.9.20.5/hedgewars/sdlmain/SDLMain.m
--- hedgewars-0.9.19.3/hedgewars/sdlmain/SDLMain.m 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/sdlmain/SDLMain.m 2013-10-31 20:21:54.000000000 +0000
@@ -0,0 +1,385 @@
+/* SDLMain.m - main entry point for our Cocoa-ized SDL app
+ Initial Version: Darrell Walisser
+ Non-NIB-Code & other changes: Max Horn
+
+ Feel free to customize this file to suit your needs
+*/
+
+#include "SDL.h"
+#include "SDLMain.h"
+#include /* for MAXPATHLEN */
+#include
+
+/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
+ but the method still is there and works. To avoid warnings, we declare
+ it ourselves here. */
+@interface NSApplication(SDL_Missing_Methods)
+- (void)setAppleMenu:(NSMenu *)menu;
+@end
+
+/* Use this flag to determine whether we use SDLMain.nib or not */
+#define SDL_USE_NIB_FILE 0
+
+/* Use this flag to determine whether we use CPS (docking) or not */
+#define SDL_USE_CPS 1
+#ifdef SDL_USE_CPS
+/* Portions of CPS.h */
+typedef struct CPSProcessSerNum
+{
+ UInt32 lo;
+ UInt32 hi;
+} CPSProcessSerNum;
+
+extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
+extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
+extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
+
+#endif /* SDL_USE_CPS */
+
+static int gArgc;
+static char **gArgv;
+static BOOL gFinderLaunch;
+static BOOL gCalledAppMainline = FALSE;
+
+static NSString *getApplicationName(void)
+{
+ const NSDictionary *dict;
+ NSString *appName = 0;
+
+ /* Determine the application name */
+ dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
+ if (dict)
+ appName = [dict objectForKey: @"CFBundleName"];
+
+ if (![appName length])
+ appName = [[NSProcessInfo processInfo] processName];
+
+ return appName;
+}
+
+#if SDL_USE_NIB_FILE
+/* A helper category for NSString */
+@interface NSString (ReplaceSubString)
+- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
+@end
+#endif
+
+@interface SDLApplication : NSApplication
+@end
+
+@implementation SDLApplication
+/* Invoked from the Quit menu item */
+- (void)terminate:(id)sender
+{
+ /* Post a SDL_QUIT event */
+ SDL_Event event;
+ event.type = SDL_QUIT;
+ SDL_PushEvent(&event);
+}
+@end
+
+/* The main class of the application, the application's delegate */
+@implementation SDLMain
+
+/* Set the working directory to the .app's parent directory */
+- (void) setupWorkingDirectory:(BOOL)shouldChdir
+{
+ if (shouldChdir)
+ {
+ char parentdir[MAXPATHLEN];
+ CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+ CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
+ if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) {
+ chdir(parentdir); /* chdir to the binary app's parent */
+ }
+ CFRelease(url);
+ CFRelease(url2);
+ }
+}
+
+#if SDL_USE_NIB_FILE
+
+/* Fix menu to contain the real app name instead of "SDL App" */
+- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
+{
+ NSRange aRange;
+ NSEnumerator *enumerator;
+ NSMenuItem *menuItem;
+
+ aRange = [[aMenu title] rangeOfString:@"SDL App"];
+ if (aRange.length != 0)
+ [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
+
+ enumerator = [[aMenu itemArray] objectEnumerator];
+ while ((menuItem = [enumerator nextObject]))
+ {
+ aRange = [[menuItem title] rangeOfString:@"SDL App"];
+ if (aRange.length != 0)
+ [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
+ if ([menuItem hasSubmenu])
+ [self fixMenu:[menuItem submenu] withAppName:appName];
+ }
+ [ aMenu sizeToFit ];
+}
+
+#else
+
+static void setApplicationMenu(void)
+{
+ /* warning: this code is very odd */
+ NSMenu *appleMenu;
+ NSMenuItem *menuItem;
+ NSString *title;
+ NSString *appName;
+
+ appName = getApplicationName();
+ appleMenu = [[NSMenu alloc] initWithTitle:@""];
+
+ /* Add menu items */
+ title = [@"About " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ title = [@"Hide " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+
+ menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
+
+ [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ title = [@"Quit " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+
+
+ /* Put menu into the menubar */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+ [menuItem setSubmenu:appleMenu];
+ [[NSApp mainMenu] addItem:menuItem];
+
+ /* Tell the application object that this is now the application menu */
+ [NSApp setAppleMenu:appleMenu];
+
+ /* Finally give up our references to the objects */
+ [appleMenu release];
+ [menuItem release];
+}
+
+/* Create a window menu */
+static void setupWindowMenu(void)
+{
+ NSMenu *windowMenu;
+ NSMenuItem *windowMenuItem;
+ NSMenuItem *menuItem;
+
+ windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+
+ /* "Minimize" item */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
+ [windowMenu addItem:menuItem];
+ [menuItem release];
+
+ /* Put menu into the menubar */
+ windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
+ [windowMenuItem setSubmenu:windowMenu];
+ [[NSApp mainMenu] addItem:windowMenuItem];
+
+ /* Tell the application object that this is now the window menu */
+ [NSApp setWindowsMenu:windowMenu];
+
+ /* Finally give up our references to the objects */
+ [windowMenu release];
+ [windowMenuItem release];
+}
+
+/* Replacement for NSApplicationMain */
+static void CustomApplicationMain (int argc, char **argv)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ SDLMain *sdlMain;
+
+ /* Ensure the application object is initialised */
+ [SDLApplication sharedApplication];
+
+#ifdef SDL_USE_CPS
+ {
+ CPSProcessSerNum PSN;
+ /* Tell the dock about us */
+ if (!CPSGetCurrentProcess(&PSN))
+ if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
+ if (!CPSSetFrontProcess(&PSN))
+ [SDLApplication sharedApplication];
+ }
+#endif /* SDL_USE_CPS */
+
+ /* Set up the menubar */
+ NSMenu *menu = [[NSMenu alloc] init];
+ [NSApp setMainMenu:menu];
+ setApplicationMenu();
+ setupWindowMenu();
+ [menu release];
+
+ /* Create SDLMain and make it the app delegate */
+ sdlMain = [[SDLMain alloc] init];
+ [NSApp setDelegate:sdlMain];
+
+ /* Start the main event loop */
+ [NSApp run];
+
+ [sdlMain release];
+ [pool release];
+}
+
+#endif
+
+
+/*
+ * Catch document open requests...this lets us notice files when the app
+ * was launched by double-clicking a document, or when a document was
+ * dragged/dropped on the app's icon. You need to have a
+ * CFBundleDocumentsType section in your Info.plist to get this message,
+ * apparently.
+ *
+ * Files are added to gArgv, so to the app, they'll look like command line
+ * arguments. Previously, apps launched from the finder had nothing but
+ * an argv[0].
+ *
+ * This message may be received multiple times to open several docs on launch.
+ *
+ * This message is ignored once the app's mainline has been called.
+ */
+- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
+{
+ const char *temparg;
+ size_t arglen;
+ char *arg;
+ char **newargv;
+
+ if (!gFinderLaunch) /* MacOS is passing command line args. */
+ return FALSE;
+
+ if (gCalledAppMainline) /* app has started, ignore this document. */
+ return FALSE;
+
+ temparg = [filename UTF8String];
+ arglen = SDL_strlen(temparg) + 1;
+ arg = (char *) SDL_malloc(arglen);
+ if (arg == NULL)
+ return FALSE;
+
+ newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
+ if (newargv == NULL)
+ {
+ SDL_free(arg);
+ return FALSE;
+ }
+ gArgv = newargv;
+
+ SDL_strlcpy(arg, temparg, arglen);
+ gArgv[gArgc++] = arg;
+ gArgv[gArgc] = NULL;
+ return TRUE;
+}
+
+
+/* Called when the internal event loop has just started running */
+- (void) applicationDidFinishLaunching: (NSNotification *) note
+{
+ int status;
+
+ /* Set the working directory to the .app's parent directory */
+ [self setupWorkingDirectory:gFinderLaunch];
+
+#if SDL_USE_NIB_FILE
+ /* Set the main menu to contain the real app name instead of "SDL App" */
+ [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
+#endif
+
+ /* Hand off to main application code */
+ gCalledAppMainline = TRUE;
+ status = SDL_main (gArgc, gArgv);
+
+ /* We're done, thank you for playing */
+ exit(status);
+}
+@end
+
+
+@implementation NSString (ReplaceSubString)
+
+- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
+{
+ unsigned int bufferSize;
+ unsigned int selfLen = [self length];
+ unsigned int aStringLen = [aString length];
+ unichar *buffer;
+ NSRange localRange;
+ NSString *result;
+
+ bufferSize = selfLen + aStringLen - aRange.length;
+ buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
+
+ /* Get first part into buffer */
+ localRange.location = 0;
+ localRange.length = aRange.location;
+ [self getCharacters:buffer range:localRange];
+
+ /* Get middle part into buffer */
+ localRange.location = 0;
+ localRange.length = aStringLen;
+ [aString getCharacters:(buffer+aRange.location) range:localRange];
+
+ /* Get last part into buffer */
+ localRange.location = aRange.location + aRange.length;
+ localRange.length = selfLen - localRange.location;
+ [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
+
+ /* Build output string */
+ result = [NSString stringWithCharacters:buffer length:bufferSize];
+
+ NSDeallocateMemoryPages(buffer, bufferSize);
+
+ return result;
+}
+
+@end
+
+
+
+#ifdef main
+# undef main
+#endif
+
+
+/* Main entry point to executable - should *not* be SDL_main! */
+int main (int argc, char **argv)
+{
+ /* Copy the arguments into a global variable */
+ /* This is passed if we are launched by double-clicking */
+ if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
+ gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
+ gArgv[0] = argv[0];
+ gArgv[1] = NULL;
+ gArgc = 1;
+ gFinderLaunch = YES;
+ } else {
+ int i;
+ gArgc = argc;
+ gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
+ for (i = 0; i <= argc; i++)
+ gArgv[i] = argv[i];
+ gFinderLaunch = NO;
+ }
+
+#if SDL_USE_NIB_FILE
+ [SDLApplication poseAsClass:[NSApplication class]];
+ NSApplicationMain (argc, argv);
+#else
+ CustomApplicationMain (argc, argv);
+#endif
+ return 0;
+}
+
diff -Nru hedgewars-0.9.19.3/hedgewars/uAI.pas hedgewars-0.9.20.5/hedgewars/uAI.pas
--- hedgewars-0.9.19.3/hedgewars/uAI.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uAI.pas 2014-01-08 16:25:17.000000000 +0000
@@ -106,7 +106,7 @@
procedure TestAmmos(var Actions: TActions; Me: PGear; rareChecks: boolean);
var BotLevel: Byte;
ap: TAttackParams;
- Score, i, dAngle: LongInt;
+ Score, i, t, n, dAngle: LongInt;
a, aa: TAmmoType;
begin
BotLevel:= Me^.Hedgehog^.BotLevel;
@@ -182,7 +182,15 @@
end else
if (Ammoz[a].Ammo.Propz and ammoprop_AttackingPut) = 0 then
begin
+ if (AmmoTests[a].flags and amtest_MultipleAttacks) = 0 then
+ n:= 1 else n:= ap.AttacksNum;
+
AddAction(BestActions, aia_attack, aim_push, 650 + random(300), 0, 0);
+ for t:= 2 to n do
+ begin
+ AddAction(BestActions, aia_attack, aim_push, 150, 0, 0);
+ AddAction(BestActions, aia_attack, aim_release, ap.Power, 0, 0);
+ end;
AddAction(BestActions, aia_attack, aim_release, ap.Power, 0, 0);
end;
@@ -243,7 +251,7 @@
AddAction(Actions, aia_Weapon, Longword(amSkip), 100 + random(200), 0, 0);
if ((CurrentHedgehog^.MultiShootAttacks = 0) or ((Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoMoveAfter) = 0))
- and (GameFlags and gfArtillery = 0) then
+ and (GameFlags and gfArtillery = 0) and (cGravityf <> 0) then
begin
tmp:= random(2) + 1;
Push(0, Actions, Me^, tmp);
@@ -482,7 +490,7 @@
FillBonuses(((Me^.State and gstAttacked) <> 0) and (not isInMultiShoot));
SDL_LockMutex(ThreadLock);
-ThinkThread:= SDL_CreateThread(@Think{$IFDEF SDL13}, 'think'{$ENDIF}, Me);
+ThinkThread:= SDL_CreateThread(@Think{$IFDEF SDL2}, 'think'{$ENDIF}, Me);
SDL_UnlockMutex(ThreadLock);
end;
diff -Nru hedgewars-0.9.19.3/hedgewars/uAIAmmoTests.pas hedgewars-0.9.20.5/hedgewars/uAIAmmoTests.pas
--- hedgewars-0.9.19.3/hedgewars/uAIAmmoTests.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uAIAmmoTests.pas 2014-01-08 16:25:17.000000000 +0000
@@ -20,15 +20,16 @@
unit uAIAmmoTests;
interface
-uses SDLh, uConsts, uFloat, uTypes, uAIMisc;
+uses uConsts, uFloat, uTypes, uAIMisc;
const
- amtest_Rare = $00000001; // check only several positions
- amtest_NoTarget = $00000002; // each pos, but no targetting
+ amtest_Rare = $00000001; // check only several positions
+ amtest_NoTarget = $00000002; // each pos, but no targetting
+ amtest_MultipleAttacks = $00000004; // test could result in multiple attacks, set AttacksNum
var windSpeed: real;
type TAttackParams = record
- Time: Longword;
+ Time, AttacksNum: Longword;
Angle, Power: LongInt;
ExplX, ExplY, ExplR: LongInt;
AttackPutX, AttackPutY: LongInt;
@@ -53,6 +54,7 @@
function TestTeleport(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
function TestHammer(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
function TestCake(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestDynamite(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
type TAmmoTestProc = function (Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
TAmmoTest = record
@@ -72,8 +74,8 @@
(proc: nil; flags: 0), // amSkip
(proc: nil; flags: 0), // amRope
(proc: nil; flags: 0), // amMine
- (proc: @TestDesertEagle; flags: 0), // amDEagle
- (proc: nil; flags: 0), // amDynamite
+ (proc: @TestDesertEagle; flags: amtest_MultipleAttacks), // amDEagle
+ (proc: @TestDynamite; flags: amtest_NoTarget), // amDynamite
(proc: @TestFirePunch; flags: amtest_NoTarget), // amFirePunch
(proc: @TestWhip; flags: amtest_NoTarget), // amWhip
(proc: @TestBaseballBat; flags: amtest_NoTarget), // amBaseballBat
@@ -119,7 +121,8 @@
//(proc: nil; flags: 0), // amStructure
(proc: nil; flags: 0), // amLandGun
(proc: nil; flags: 0), // amIceGun
- (proc: nil; flags: 0) // amKnife
+ (proc: nil; flags: 0), // amKnife
+ (proc: nil; flags: 0) // amGirder
);
implementation
@@ -330,7 +333,7 @@
function TestMolotov(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
var Vx, Vy, r: real;
Score, EX, EY, valueResult: LongInt;
- TestTime: Longword;
+ TestTime: LongInt;
x, y, dY, meX, meY: real;
t: LongInt;
begin
@@ -382,7 +385,7 @@
const tDelta = 24;
var Vx, Vy, r: real;
Score, EX, EY, valueResult: LongInt;
- TestTime: Longword;
+ TestTime: LongInt;
x, y, meX, meY, dY: real;
t: LongInt;
begin
@@ -681,7 +684,7 @@
function TestDesertEagle(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
var Vx, Vy, x, y, t: real;
d: Longword;
- fallDmg, valueResult: LongInt;
+ {fallDmg, }valueResult: LongInt;
begin
if (Level > 4) or (Targ.Score < 0) or (Targ.Kind <> gtHedgehog) then exit(BadTurn);
Level:= Level; // avoid compiler hint
@@ -715,8 +718,13 @@
or (d > 48);
if Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) < 5 then
- valueResult:= RateShove(Me, Targ.Point.X, Targ.Point.Y, 1, 7, 20, vX*0.125, vY*0.125, afTrackFall)
-else valueResult:= BadTurn;
+ begin
+ ap.AttacksNum:= 1 + (d + 8) div 12;
+ valueResult:= RateShove(Me, Targ.Point.X, Targ.Point.Y, 1, 7, 20, vX*0.125, vY*0.125, afTrackFall) - ap.AttacksNum
+ end
+else
+ valueResult:= BadTurn;
+
TestDesertEagle:= valueResult
end;
@@ -724,7 +732,7 @@
function TestSniperRifle(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
var Vx, Vy, x, y, t, dmg: real;
d: Longword;
- fallDmg: LongInt;
+ //fallDmg: LongInt;
begin
if (Level > 3) or (Targ.Score < 0) or (Targ.Kind <> gtHedgehog) then exit(BadTurn);
Level:= Level; // avoid compiler hint
@@ -1039,7 +1047,7 @@
begin
ap.ExplR:= 0;
ap.Time:= 0;
-if (Level > 3) then
+if (Level > 3) or (cGravityf = 0) then
exit(BadTurn);
ap.Angle:= 0;
@@ -1216,4 +1224,48 @@
TestCake:= valueResult;
end;
+function TestDynamite(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+var valueResult: LongInt;
+ x, y, dx, dy: real;
+ EX, EY, t: LongInt;
+begin
+Targ:= Targ; // avoid compiler hint
+
+x:= hwFloat2Float(Me^.X) + hwSign(Me^.dX) * 7;
+y:= hwFloat2Float(Me^.Y);
+dx:= hwSign(Me^.dX) * 0.03;
+dy:= 0;
+t:= 5000;
+repeat
+ dec(t);
+ x:= x + dx;
+ dy:= dy + cGravityf;
+ y:= y + dy;
+
+ if TestColl(trunc(x), trunc(y), 3) then
+ t:= 0;
+until t = 0;
+
+EX:= trunc(x);
+EY:= trunc(y);
+
+if Level = 1 then
+ valueResult:= RateExplosion(Me, EX, EY, 76, afTrackFall or afErasesLand)
+else
+ valueResult:= RateExplosion(Me, EX, EY, 76);
+
+if (valueResult > 0) then
+ begin
+ ap.Angle:= 0;
+ ap.Power:= 1;
+ ap.Time:= 0;
+ ap.ExplR:= 150;
+ ap.ExplX:= EX;
+ ap.ExplY:= EY
+ end else
+ valueResult:= BadTurn;
+
+TestDynamite:= valueResult
+end;
+
end.
diff -Nru hedgewars-0.9.19.3/hedgewars/uAIMisc.pas hedgewars-0.9.20.5/hedgewars/uAIMisc.pas
--- hedgewars-0.9.19.3/hedgewars/uAIMisc.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uAIMisc.pas 2014-01-08 16:25:17.000000000 +0000
@@ -113,7 +113,7 @@
Targets.reset:= false;
end;
procedure FillTargets;
-var i, t: Longword;
+var //i, t: Longword;
f, e: LongInt;
Gear: PGear;
begin
@@ -812,13 +812,13 @@
jmpLJump:
begin
if TestCollisionYwithGear(Gear, -1) <> 0 then
- if not TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) then
+ if TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) = 0 then
Gear^.Y:= Gear^.Y - int2hwFloat(2)
else
- if not TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) then
+ if TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) = 0 then
Gear^.Y:= Gear^.Y - _1;
- if not (TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) or
- (TestCollisionYwithGear(Gear, -1) <> 0)) then
+ if (TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) = 0) and
+ (TestCollisionYwithGear(Gear, -1) = 0) then
begin
Gear^.dY:= -_0_15;
Gear^.dX:= SignAs(_0_15, Gear^.dX);
@@ -846,7 +846,7 @@
Gear^.dY:= -_0_25;
Gear^.dX:= SignAs(_0_02, Gear^.dX)
end;
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then SetLittle(Gear^.dX);
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0 then SetLittle(Gear^.dX);
Gear^.X:= Gear^.X + Gear^.dX;
inc(GoInfo.Ticks);
Gear^.dY:= Gear^.dY + cGravity;
diff -Nru hedgewars-0.9.19.3/hedgewars/uAmmos.pas hedgewars-0.9.20.5/hedgewars/uAmmos.pas
--- hedgewars-0.9.19.3/hedgewars/uAmmos.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uAmmos.pas 2014-01-08 16:25:17.000000000 +0000
@@ -53,11 +53,12 @@
uses uLocale, uVariables, uCommands, uUtils, uCaptions, uDebug;
type TAmmoCounts = array[TAmmoType] of Longword;
+ TAmmoArray = array[TAmmoType] of TAmmo;
var StoresList: array[0..Pred(cMaxHHs)] of PHHAmmo;
ammoLoadout, ammoProbability, ammoDelay, ammoReinforcement: shortstring;
InitialCounts: array[0..Pred(cMaxHHs)] of TAmmoCounts;
-procedure FillAmmoStore(Ammo: PHHAmmo; var cnts: TAmmoCounts);
+procedure FillAmmoStore(Ammo: PHHAmmo; var newAmmo: TAmmoArray);
var mi: array[0..cMaxSlotIndex] of byte;
a: TAmmoType;
begin
@@ -67,12 +68,10 @@
FillChar(Ammo^, sizeof(Ammo^), 0);
for a:= Low(TAmmoType) to High(TAmmoType) do
begin
- if cnts[a] > 0 then
+ if newAmmo[a].Count > 0 then
begin
TryDo(mi[Ammoz[a].Slot] <= cMaxSlotAmmoIndex, 'Ammo slot overflow', true);
- Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]]:= Ammoz[a].Ammo;
- with Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]] do
- Count:= cnts[a];
+ Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]]:= newAmmo[a];
inc(mi[Ammoz[a].Slot])
end
end;
@@ -84,6 +83,7 @@
var cnt: Longword;
a: TAmmoType;
ammos: TAmmoCounts;
+ newAmmos: TAmmoArray;
begin
TryDo((byte(ammoLoadout[0]) = byte(ord(High(TAmmoType)))) and (byte(ammoProbability[0]) = byte(ord(High(TAmmoType)))) and (byte(ammoDelay[0]) = byte(ord(High(TAmmoType)))) and (byte(ammoReinforcement[0]) = byte(ord(High(TAmmoType)))), 'Incomplete or missing ammo scheme set (incompatible frontend or demo/save?)', true);
@@ -141,7 +141,14 @@
else
InitialCounts[Pred(StoreCnt)][a]:= ammos[a];
end;
-FillAmmoStore(StoresList[Pred(StoreCnt)], ammos)
+
+ for a:= Low(TAmmoType) to High(TAmmoType) do
+ begin
+ newAmmos[a]:= Ammoz[a].Ammo;
+ newAmmos[a].Count:= ammos[a]
+ end;
+
+FillAmmoStore(StoresList[Pred(StoreCnt)], newAmmos)
end;
function GetAmmoByNum(num: Longword): PHHAmmo;
@@ -211,23 +218,31 @@
end;
procedure SetAmmo(var Hedgehog: THedgehog; ammo: TAmmoType; cnt: LongWord);
-var ammos: TAmmoCounts;
+var ammos: TAmmoArray;
slot, ami: LongInt;
hhammo: PHHAmmo;
CurWeapon: PAmmo;
+ a: TAmmoType;
begin
+if ammo = amNothing then exit;
{$HINTS OFF}
FillChar(ammos, sizeof(ammos), 0);
{$HINTS ON}
hhammo:= Hedgehog.Ammo;
+for a:= Low(TAmmoType) to High(TAmmoType) do
+ begin
+ ammos[a]:= Ammoz[a].Ammo;
+ ammos[a].Count:= 0
+ end;
+
for slot:= 0 to cMaxSlotIndex do
for ami:= 0 to cMaxSlotAmmoIndex do
if hhammo^[slot, ami].Count > 0 then
- ammos[hhammo^[slot, ami].AmmoType]:= hhammo^[slot, ami].Count;
+ ammos[hhammo^[slot, ami].AmmoType]:= hhammo^[slot, ami];
-ammos[ammo]:= cnt;
-if ammos[ammo] > AMMO_INFINITE then ammos[ammo]:= AMMO_INFINITE;
+ammos[ammo].Count:= cnt;
+if ammos[ammo].Count > AMMO_INFINITE then ammos[ammo].Count:= AMMO_INFINITE;
FillAmmoStore(hhammo, ammos);
CurWeapon:= GetCurAmmoEntry(Hedgehog);
@@ -307,18 +322,21 @@
if Hedgehog.Gear <> nil then
with Hedgehog do
begin
- CurMinAngle:= Ammoz[AmmoType].minAngle;
- if Ammoz[AmmoType].maxAngle <> 0 then
- CurMaxAngle:= Ammoz[AmmoType].maxAngle
- else
- CurMaxAngle:= cMaxAngle;
-
- with Hedgehog.Gear^ do
+ if (AmmoType <> amNothing) then
begin
- if Angle < CurMinAngle then
- Angle:= CurMinAngle;
- if Angle > CurMaxAngle then
- Angle:= CurMaxAngle;
+ CurMinAngle:= Ammoz[AmmoType].minAngle;
+ if Ammoz[AmmoType].maxAngle <> 0 then
+ CurMaxAngle:= Ammoz[AmmoType].maxAngle
+ else
+ CurMaxAngle:= cMaxAngle;
+
+ with Hedgehog.Gear^ do
+ begin
+ if Angle < CurMinAngle then
+ Angle:= CurMinAngle;
+ if Angle > CurMaxAngle then
+ Angle:= CurMaxAngle;
+ end
end
end
end;
@@ -455,14 +473,22 @@
procedure ResetWeapons;
var i, t: Longword;
a: TAmmoType;
+ newAmmos: TAmmoArray;
begin
for t:= 0 to Pred(TeamsCount) do
with TeamsArray[t]^ do
for i:= 0 to cMaxHHIndex do
Hedgehogs[i].CurAmmoType:= amNothing;
+for a:= Low(TAmmoType) to High(TAmmoType) do
+ newAmmos[a]:= Ammoz[a].Ammo;
+
for i:= 0 to Pred(StoreCnt) do
- FillAmmoStore(StoresList[i], InitialCounts[i]);
+ begin
+ for a:= Low(TAmmoType) to High(TAmmoType) do
+ newAmmos[a].Count:= InitialCounts[i][a];
+ FillAmmoStore(StoresList[i], newAmmos);
+ end;
for a:= Low(TAmmoType) to High(TAmmoType) do
if Ammoz[a].SkipTurns >= 10000 then
@@ -486,6 +512,8 @@
RegisterVariable('ammreinf', @SetAmmoReinforcement, false);
RegisterVariable('ammstore', @chAddAmmoStore , false);
+ CurMinAngle:= 0;
+ CurMaxAngle:= cMaxAngle;
StoreCnt:= 0;
ammoLoadout:= '';
ammoProbability:= '';
diff -Nru hedgewars-0.9.19.3/hedgewars/uChat.pas hedgewars-0.9.20.5/hedgewars/uChat.pas
--- hedgewars-0.9.19.3/hedgewars/uChat.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uChat.pas 2014-01-08 16:25:17.000000000 +0000
@@ -29,6 +29,7 @@
procedure AddChatString(s: shortstring);
procedure DrawChat;
procedure KeyPressChat(Key, Sym: Longword);
+procedure SendHogSpeech(s: shortstring);
implementation
uses SDLh, uInputHandler, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO;
@@ -41,15 +42,15 @@
Width: LongInt;
s: shortstring;
end;
- TChatCmd = (quit, pause, finish, fullscreen);
+ TChatCmd = (quit, pause, finish, showhistory, fullscreen);
var Strs: array[0 .. MaxStrIndex] of TChatLine;
MStrs: array[0 .. MaxStrIndex] of shortstring;
LocalStrs: array[0 .. MaxStrIndex] of shortstring;
missedCount: LongWord;
lastStr: LongWord;
- localLastStr: LongWord;
- history: LongWord;
+ localLastStr: LongInt;
+ history: LongInt;
visibleCount: LongWord;
InputStr: TChatLine;
InputStrL: array[0..260] of char; // for full str + 4-byte utf-8 char
@@ -58,13 +59,13 @@
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]
+ (r:$FF; g:$FF; b:$FF; a:$FF), // unused, feel free to take it for anything
+ (r:$FF; g:$FF; b:$FF; a:$FF), // chat message [White]
+ (r:$FF; g:$00; b:$FF; a:$FF), // action message [Purple]
+ (r:$90; g:$FF; b:$90; a:$FF), // join/leave message [Lime]
+ (r:$FF; g:$FF; b:$A0; a:$FF), // team message [Light Yellow]
+ (r:$FF; g:$00; b:$00; a:$FF), // error messages [Red]
+ (r:$00; g:$FF; b:$FF; a:$FF) // input line [Light Blue]
);
ChatCommandz: array [TChatCmd] of record
ChatCmd: string[31];
@@ -73,6 +74,7 @@
(ChatCmd: '/quit'; ProcedureCallChatCmd: 'halt'),
(ChatCmd: '/pause'; ProcedureCallChatCmd: 'pause'),
(ChatCmd: '/finish'; ProcedureCallChatCmd: 'finish'),
+ (ChatCmd: '/history'; ProcedureCallChatCmd: 'history'),
(ChatCmd: '/fullscreen'; ProcedureCallChatCmd: 'fullscr')
);
@@ -174,7 +176,7 @@
DrawFillRect(r);
Tint($00, $00, $00, $80);
DrawTexture(9 - cScreenWidth div 2, visibleCount * 16 + 11, InputStr.Tex);
- Tint($FF, $FF, $FF, $FF);
+ untint;
DrawTexture(8 - cScreenWidth div 2, visibleCount * 16 + 10, InputStr.Tex);
end;
@@ -187,7 +189,7 @@
DrawFillRect(r);
Tint($00, $00, $00, $80);
DrawTexture(9 - cScreenWidth div 2, (visibleCount - t) * 16 - 5, Strs[i].Tex);
- Tint($FF, $FF, $FF, $FF);
+ untint;
DrawTexture(8 - cScreenWidth div 2, (visibleCount - t) * 16 - 6, Strs[i].Tex);
dec(r.y, 16);
@@ -240,55 +242,64 @@
exit
end;
-// These 3 are same as above, only are to make the hedgehog say it on next attack
-if (s[1] = '/') and (copy(s, 1, 5) = '/hsa ') then
- begin
- if CurrentTeam^.ExtDriven then
- ParseCommand('/say ' + copy(s, 6, Length(s)-5), true)
- else
- SendHogSpeech(#4 + copy(s, 6, Length(s)-5));
- exit
- end;
-if (s[1] = '/') and (copy(s, 1, 5) = '/hta ') then
+if (s[1] = '/') then
begin
- if CurrentTeam^.ExtDriven then
- ParseCommand('/say ' + copy(s, 6, Length(s)-5), true)
- else
- SendHogSpeech(#5 + copy(s, 6, Length(s)-5));
- exit
- end;
-if (s[1] = '/') and (copy(s, 1, 5) = '/hya ') then
- begin
- if CurrentTeam^.ExtDriven then
- ParseCommand('/say ' + copy(s, 6, Length(s)-5), true)
- else
- SendHogSpeech(#6 + copy(s, 6, Length(s)-5));
- exit
- end;
+ // These 3 are same as above, only are to make the hedgehog say it on next attack
+ if (copy(s, 1, 5) = '/hsa ') then
+ begin
+ if CurrentTeam^.ExtDriven then
+ ParseCommand('/say ' + copy(s, 6, Length(s)-5), true)
+ else
+ SendHogSpeech(#4 + copy(s, 6, Length(s)-5));
+ exit
+ end;
-if (copy(s, 1, 6) = '/team ') and (length(s) > 6) then
- begin
- ParseCommand(s, true);
- exit
- end;
-if (s[1] = '/') and (copy(s, 1, 4) <> '/me ') then
- begin
- if CurrentTeam^.ExtDriven or (CurrentTeam^.Hedgehogs[0].BotLevel <> 0) then
- exit;
+ if (copy(s, 1, 5) = '/hta ') then
+ begin
+ if CurrentTeam^.ExtDriven then
+ ParseCommand('/say ' + copy(s, 6, Length(s)-5), true)
+ else
+ SendHogSpeech(#5 + copy(s, 6, Length(s)-5));
+ exit
+ end;
- for i:= Low(TWave) to High(TWave) do
- if (s = Wavez[i].cmd) then
- begin
- ParseCommand('/taunt ' + char(i), true);
- exit
- end;
+ if (copy(s, 1, 5) = '/hya ') then
+ begin
+ if CurrentTeam^.ExtDriven then
+ ParseCommand('/say ' + copy(s, 6, Length(s)-5), true)
+ else
+ SendHogSpeech(#6 + copy(s, 6, Length(s)-5));
+ exit
+ end;
- for j:= Low(TChatCmd) to High(TChatCmd) do
- if (s = ChatCommandz[j].ChatCmd) then
- begin
- ParseCommand(ChatCommandz[j].ProcedureCallChatCmd, true);
- exit
- end;
+ if (copy(s, 1, 6) = '/team ') and (length(s) > 6) then
+ begin
+ ParseCommand(s, true);
+ exit
+ end;
+
+ if (copy(s, 1, 4) = '/me ') then
+ begin
+ ParseCommand('/say ' + s, true);
+ exit
+ end;
+
+ if (not CurrentTeam^.ExtDriven) and (CurrentTeam^.Hedgehogs[0].BotLevel = 0) then
+ begin
+ for i:= Low(TWave) to High(TWave) do
+ if (s = Wavez[i].cmd) then
+ begin
+ 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
end
else
ParseCommand('/say ' + s, true);
@@ -298,7 +309,9 @@
begin
FreezeEnterKey;
history:= 0;
+{$IFNDEF SDL2}
SDL_EnableKeyRepeat(0,0);
+{$ENDIF}
GameState:= gsGame;
ResetKbd;
end;
@@ -325,7 +338,7 @@
SetLine(InputStr, '', true)
else CleanupInput
end;
- SDLK_RETURN:
+ SDLK_RETURN, SDLK_KP_ENTER:
begin
if Length(InputStr.s) > 0 then
begin
@@ -421,7 +434,9 @@
begin
s:= s; // avoid compiler hint
GameState:= gsChat;
+{$IFNDEF SDL2}
SDL_EnableKeyRepeat(200,45);
+{$ENDIF}
if length(s) = 0 then
SetLine(InputStr, '', true)
else
diff -Nru hedgewars-0.9.19.3/hedgewars/uCollisions.pas hedgewars-0.9.20.5/hedgewars/uCollisions.pas
--- hedgewars-0.9.19.3/hedgewars/uCollisions.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uCollisions.pas 2014-01-08 16:25:17.000000000 +0000
@@ -33,34 +33,34 @@
procedure initModule;
procedure freeModule;
-procedure AddGearCI(Gear: PGear);
+procedure AddCI(Gear: PGear);
procedure DeleteCI(Gear: PGear);
function CheckGearsCollision(Gear: PGear): PGearArray;
-function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): boolean;
+function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word;
function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word;
-function TestCollisionXKick(Gear: PGear; Dir: LongInt): boolean;
-function TestCollisionYKick(Gear: PGear; Dir: LongInt): boolean;
+function TestCollisionXKick(Gear: PGear; Dir: LongInt): Word;
+function TestCollisionYKick(Gear: PGear; Dir: LongInt): Word;
-function TestCollisionX(Gear: PGear; Dir: LongInt): boolean;
-function TestCollisionY(Gear: PGear; Dir: LongInt): boolean;
+function TestCollisionX(Gear: PGear; Dir: LongInt): Word;
+function TestCollisionY(Gear: PGear; Dir: LongInt): Word;
-function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean; inline;
-function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): boolean;
-function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): boolean; inline;
-function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): boolean;
+function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word; inline;
+function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
+function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; inline;
+function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
function TestRectancleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean;
// returns: negative sign if going downhill to left, value is steepness (noslope/error = _0, 45° = _0_5)
function CalcSlopeBelowGear(Gear: PGear): hwFloat;
function CalcSlopeNearGear(Gear: PGear; dirX, dirY: LongInt): hwFloat;
-function CalcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): Boolean;
+function CalcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): boolean;
implementation
-uses uConsts, uLandGraphics, uVariables, uDebug, uGearsList;
+uses uConsts, uLandGraphics, uVariables, uDebug;
type TCollisionEntry = record
X, Y, Radius: LongInt;
@@ -72,7 +72,7 @@
cinfos: array[0..MAXRECTSINDEX] of TCollisionEntry;
ga: TGearArray;
-procedure AddGearCI(Gear: PGear);
+procedure AddCI(Gear: PGear);
var t: PGear;
begin
if Gear^.CollisionIndex >= 0 then
@@ -83,7 +83,7 @@
X:= hwRound(Gear^.X);
Y:= hwRound(Gear^.Y);
Radius:= Gear^.Radius;
- ChangeRoundInLand(X, Y, Radius - 1, true, (Gear = CurrentHedgehog^.Gear) or ((Gear^.Kind = gtCase) and (Gear^.State and gstFrozen <> 0)));
+ ChangeRoundInLand(X, Y, Radius - 1, true, (Gear = CurrentHedgehog^.Gear) or ((Gear^.Kind = gtCase) and (Gear^.State and gstFrozen = 0)));
cGear:= Gear
end;
Gear^.CollisionIndex:= Count;
@@ -95,7 +95,7 @@
while (t <> nil) and (t^.Kind <> gtMine) do
t:= t^.NextGear;
if (t <> nil) then
- DeleteGear(t)
+ t^.State:= t^.State or gmDelete
end;
end;
@@ -104,7 +104,7 @@
if Gear^.CollisionIndex >= 0 then
begin
with cinfos[Gear^.CollisionIndex] do
- ChangeRoundInLand(X, Y, Radius - 1, false, (Gear = CurrentHedgehog^.Gear) or ((Gear^.Kind = gtCase) and (Gear^.State and gstFrozen <> 0)));
+ ChangeRoundInLand(X, Y, Radius - 1, false, (Gear = CurrentHedgehog^.Gear) or ((Gear^.Kind = gtCase) and (Gear^.State and gstFrozen = 0)));
cinfos[Gear^.CollisionIndex]:= cinfos[Pred(Count)];
cinfos[Gear^.CollisionIndex].cGear^.CollisionIndex:= Gear^.CollisionIndex;
Gear^.CollisionIndex:= -1;
@@ -135,7 +135,7 @@
end
end;
-function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): boolean;
+function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word;
var x, y, i: LongInt;
begin
// Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap
@@ -150,7 +150,6 @@
else
x:= x + Gear^.Radius;
-TestCollisionXwithGear:= true;
if (x and LAND_WIDTH_MASK) = 0 then
begin
y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
@@ -158,11 +157,11 @@
repeat
if (y and LAND_HEIGHT_MASK) = 0 then
if Land[y, x] and Gear^.CollisionMask <> 0 then
- exit;
+ exit(Land[y, x] and Gear^.CollisionMask);
inc(y)
until (y > i);
end;
-TestCollisionXwithGear:= false
+TestCollisionXwithGear:= 0
end;
function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word;
@@ -188,8 +187,7 @@
if (x and LAND_WIDTH_MASK) = 0 then
if Land[y, x] and Gear^.CollisionMask <> 0 then
begin
- TestCollisionYwithGear:= Land[y, x];
- exit;
+ exit(Land[y, x] and Gear^.CollisionMask)
end;
inc(x)
until (x > i);
@@ -197,34 +195,33 @@
TestCollisionYwithGear:= 0
end;
-function TestCollisionXKick(Gear: PGear; Dir: LongInt): boolean;
+function TestCollisionXKick(Gear: PGear; Dir: LongInt): Word;
var x, y, mx, my, i: LongInt;
- flag: boolean;
+ pixel: Word;
begin
-flag:= false;
+pixel:= 0;
x:= hwRound(Gear^.X);
if Dir < 0 then
x:= x - Gear^.Radius
else
x:= x + Gear^.Radius;
-TestCollisionXKick:= true;
if (x and LAND_WIDTH_MASK) = 0 then
begin
y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
i:= y + Gear^.Radius * 2 - 2;
repeat
if (y and LAND_HEIGHT_MASK) = 0 then
- if Land[y, x] > 255 then
- exit
- else if Land[y, x] <> 0 then
- flag:= true;
+ if Land[y, x] and Gear^.CollisionMask > 255 then
+ exit(Land[y, x] and Gear^.CollisionMask)
+ else if Land[y, x] and Gear^.CollisionMask <> 0 then
+ pixel:= Land[y, x] and Gear^.CollisionMask;
inc(y)
until (y > i);
end;
-TestCollisionXKick:= flag;
+TestCollisionXKick:= pixel;
-if flag then
+if pixel <> 0 then
begin
if hwAbs(Gear^.dX) < cHHKick then
exit;
@@ -237,12 +234,14 @@
for i:= 0 to Pred(Count) do
with cinfos[i] do
- if (Gear <> cGear) and (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2))
- and ((mx > x) xor (Dir > 0)) and
+ if (Gear <> cGear) and
+ ((mx > x) xor (Dir > 0)) and
(
((cGear^.Kind in [gtHedgehog, gtMine, gtKnife]) and ((Gear^.State and gstNotKickable) = 0)) or
// only apply X kick if the barrel is knocked over
- ((cGear^.Kind = gtExplosives) and ((cGear^.State and gsttmpflag) <> 0))) then
+ ((cGear^.Kind = gtExplosives) and ((cGear^.State and gsttmpflag) <> 0))
+ ) and
+ (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2)) then
begin
with cGear^ do
begin
@@ -253,24 +252,22 @@
Active:= true
end;
DeleteCI(cGear);
- TestCollisionXKick:= false;
- exit;
+ exit(0);
end
end
end;
-function TestCollisionYKick(Gear: PGear; Dir: LongInt): boolean;
+function TestCollisionYKick(Gear: PGear; Dir: LongInt): Word;
var x, y, mx, my, myr, i: LongInt;
- flag: boolean;
+ pixel: Word;
begin
-flag:= false;
+pixel:= 0;
y:= hwRound(Gear^.Y);
if Dir < 0 then
y:= y - Gear^.Radius
else
y:= y + Gear^.Radius;
-TestCollisionYKick:= true;
if (y and LAND_HEIGHT_MASK) = 0 then
begin
x:= hwRound(Gear^.X) - Gear^.Radius + 1;
@@ -278,16 +275,16 @@
repeat
if (x and LAND_WIDTH_MASK) = 0 then
if Land[y, x] > 0 then
- if Land[y, x] > 255 then
- exit
+ if Land[y, x] and Gear^.CollisionMask > 255 then
+ exit(Land[y, x] and Gear^.CollisionMask)
else if Land[y, x] <> 0 then
- flag:= true;
+ pixel:= Land[y, x] and Gear^.CollisionMask;
inc(x)
until (x > i);
end;
-TestCollisionYKick:= flag;
+TestCollisionYKick:= pixel;
-if flag then
+if pixel <> 0 then
begin
if hwAbs(Gear^.dY) < cHHKick then
exit;
@@ -300,11 +297,11 @@
for i:= 0 to Pred(Count) do
with cinfos[i] do
- if (Gear <> cGear) and (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2))
- and ((myr > y) xor (Dir > 0)) and
- (
- (cGear^.Kind in [gtHedgehog, gtMine, gtKnife, gtExplosives]) and
- ((Gear^.State and gstNotKickable) = 0)) then
+ if (Gear <> cGear) and
+ ((myr > y) xor (Dir > 0)) and
+ (Gear^.State and gstNotKickable = 0) and
+ (cGear^.Kind in [gtHedgehog, gtMine, gtKnife, gtExplosives]) and
+ (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2)) then
begin
with cGear^ do
begin
@@ -316,18 +313,17 @@
Active:= true
end;
DeleteCI(cGear);
- TestCollisionYKick:= false;
- exit
+ exit(0)
end
end
end;
-function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean; inline;
+function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word; inline;
begin
TestCollisionXwithXYShift:= TestCollisionXwithXYShift(Gear, ShiftX, ShiftY, Dir, true);
end;
-function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): boolean;
+function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
begin
Gear^.X:= Gear^.X + ShiftX;
Gear^.Y:= Gear^.Y + int2hwFloat(ShiftY);
@@ -338,7 +334,7 @@
Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY)
end;
-function TestCollisionX(Gear: PGear; Dir: LongInt): boolean;
+function TestCollisionX(Gear: PGear; Dir: LongInt): Word;
var x, y, i: LongInt;
begin
x:= hwRound(Gear^.X);
@@ -347,22 +343,21 @@
else
x:= x + Gear^.Radius;
-TestCollisionX:= true;
if (x and LAND_WIDTH_MASK) = 0 then
begin
y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
i:= y + Gear^.Radius * 2 - 2;
repeat
if (y and LAND_HEIGHT_MASK) = 0 then
- if Land[y, x] > 255 then
- exit;
+ if Land[y, x] and Gear^.CollisionMask > 255 then
+ exit(Land[y, x] and Gear^.CollisionMask);
inc(y)
until (y > i);
end;
-TestCollisionX:= false
+TestCollisionX:= 0
end;
-function TestCollisionY(Gear: PGear; Dir: LongInt): boolean;
+function TestCollisionY(Gear: PGear; Dir: LongInt): Word;
var x, y, i: LongInt;
begin
y:= hwRound(Gear^.Y);
@@ -371,33 +366,32 @@
else
y:= y + Gear^.Radius;
-TestCollisionY:= true;
if (y and LAND_HEIGHT_MASK) = 0 then
begin
x:= hwRound(Gear^.X) - Gear^.Radius + 1;
i:= x + Gear^.Radius * 2 - 2;
repeat
if (x and LAND_WIDTH_MASK) = 0 then
- if Land[y, x] > 255 then
- exit;
+ if Land[y, x] and Gear^.CollisionMask > 255 then
+ exit(Land[y, x] and Gear^.CollisionMask);
inc(x)
until (x > i);
end;
-TestCollisionY:= false
+TestCollisionY:= 0
end;
-function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): boolean; inline;
+function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; inline;
begin
TestCollisionYwithXYShift:= TestCollisionYwithXYShift(Gear, ShiftX, ShiftY, Dir, true);
end;
-function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): boolean;
+function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
begin
Gear^.X:= Gear^.X + int2hwFloat(ShiftX);
Gear^.Y:= Gear^.Y + int2hwFloat(ShiftY);
if withGear then
- TestCollisionYwithXYShift:= TestCollisionYwithGear(Gear, Dir) <> 0
+ TestCollisionYwithXYShift:= TestCollisionYwithGear(Gear, Dir)
else
TestCollisionYwithXYShift:= TestCollisionY(Gear, Dir);
diff -Nru hedgewars-0.9.19.3/hedgewars/uCommandHandlers.pas hedgewars-0.9.20.5/hedgewars/uCommandHandlers.pas
--- hedgewars-0.9.19.3/hedgewars/uCommandHandlers.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uCommandHandlers.pas 2014-01-08 16:25:17.000000000 +0000
@@ -109,39 +109,6 @@
CurrentTeam^.ExtDriven:= true
end;
-procedure chGrave(var s: shortstring);
-begin
-if CurrentTeam = nil then
- OutError(errmsgIncorrectUse + ' "/grave"', true);
-if s[1]='"' then
- Delete(s, 1, 1);
-if s[byte(s[0])]='"' then
- Delete(s, byte(s[0]), 1);
-CurrentTeam^.GraveName:= s
-end;
-
-procedure chFort(var s: shortstring);
-begin
-if CurrentTeam = nil then
- OutError(errmsgIncorrectUse + ' "/fort"', true);
-if s[1]='"' then
- Delete(s, 1, 1);
-if s[byte(s[0])]='"' then
- Delete(s, byte(s[0]), 1);
-CurrentTeam^.FortName:= s
-end;
-
-procedure chFlag(var s: shortstring);
-begin
-if CurrentTeam = nil then
- OutError(errmsgIncorrectUse + ' "/flag"', true);
-if s[1]='"' then
- Delete(s, 1, 1);
-if s[byte(s[0])]='"' then
- Delete(s, byte(s[0]), 1);
-CurrentTeam^.flag:= s
-end;
-
procedure chScript(var s: shortstring);
begin
if s[1]='"' then
@@ -152,21 +119,6 @@
ScriptLoad(s)
end;
-procedure chSetHat(var s: shortstring);
-begin
-if (not isDeveloperMode) or (CurrentTeam = nil) then exit;
-with CurrentTeam^ do
- begin
- if not CurrentHedgehog^.King then
- if (s = '')
- or (((GameFlags and gfKing) <> 0) and (s = 'crown'))
- or ((Length(s) > 39) and (Copy(s,1,8) = 'Reserved') and (Copy(s,9,32) <> PlayerHash)) then
- CurrentHedgehog^.Hat:= 'NoHat'
- else
- CurrentHedgehog^.Hat:= s
- end;
-end;
-
procedure chCurU_p(var s: shortstring);
begin
s:= s; // avoid compiler hint
@@ -641,9 +593,14 @@
begin
s:= s; // avoid compiler hint
if gameType <> gmtNet then
- isPaused:= not isPaused;
+ isPaused:= not isPaused
+ else
+ if (CurrentTeam^.ExtDriven) or (CurrentHedgehog^.BotLevel > 0) then
+ isAFK:= not isAFK
+ else
+ isAFK:= false; // for real ninjas
-if isPaused then
+if isPaused or isAFK then
SDL_ShowCursor(1)
else
SDL_ShowCursor(ord(GameState = gsConfirm))
@@ -652,10 +609,26 @@
procedure chRotateMask(var s: shortstring);
begin
s:= s; // avoid compiler hint
-if ((GameFlags and gfInvulnerable) = 0) then
- cTagsMask:= cTagsMasks[cTagsMask]
+// this is just for me, 'cause I thought it'd be fun. using the old precise + switch to keep it out of people's way
+if LocalMessage and (gmPrecise or gmSwitch) = (gmPrecise or gmSwitch) then
+ begin
+ if UIDisplay <> uiNone then
+ UIDisplay:= uiNone
+ else UIDisplay:= uiAll
+ end
+else if LocalMessage and gmPrecise = gmPrecise then
+ begin
+ if ((GameFlags and gfInvulnerable) = 0) then
+ cTagsMask:= cTagsMasks[cTagsMask]
+ else
+ cTagsMask:= cTagsMasksNoHealth[cTagsMask]
+ end
else
- cTagsMask:= cTagsMasksNoHealth[cTagsMask];
+ begin
+ if UIDisplay <> uiNoTeams then
+ UIDisplay:= uiNoTeams
+ else UIDisplay:= uiAll
+ end
end;
procedure chSpeedup_p(var s: shortstring);
@@ -797,6 +770,11 @@
CampaignVariable := s;
end;
+procedure chWorldEdge(var s: shortstring);
+begin
+WorldEdge:= TWorldEdge(StrToInt(s))
+end;
+
procedure initModule;
begin
//////// Begin top sorted by freq analysis not including chatmsg
@@ -817,7 +795,6 @@
RegisterVariable('setweap' , @chSetWeapon , false, true);
//////// End top by freq analysis
RegisterVariable('gencmd' , @chGenCmd , false);
- RegisterVariable('flag' , @chFlag , false);
RegisterVariable('script' , @chScript , false);
RegisterVariable('proto' , @chCheckProto , true );
RegisterVariable('spectate', @chFastUntilLag , false);
@@ -847,9 +824,6 @@
RegisterVariable('gmflags' , @chGameFlags , false);
RegisterVariable('turntime', @chHedgehogTurnTime, false);
RegisterVariable('minestime',@chMinesTime , false);
- RegisterVariable('fort' , @chFort , false);
- RegisterVariable('grave' , @chGrave , false);
- RegisterVariable('hat' , @chSetHat , false);
RegisterVariable('quit' , @chQuit , true );
RegisterVariable('forcequit', @chForceQuit , true );
RegisterVariable('confirm' , @chConfirm , true );
@@ -882,6 +856,7 @@
RegisterVariable('-cur_r' , @chCurR_m , true );
RegisterVariable('campvar' , @chCampVar , true );
RegisterVariable('record' , @chRecord , true );
+ RegisterVariable('worldedge',@chWorldEdge , false);
end;
procedure freeModule;
diff -Nru hedgewars-0.9.19.3/hedgewars/uCommands.pas hedgewars-0.9.20.5/hedgewars/uCommands.pas
--- hedgewars-0.9.19.3/hedgewars/uCommands.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uCommands.pas 2013-10-31 20:21:54.000000000 +0000
@@ -36,7 +36,7 @@
procedure StopMessages(Message: Longword);
implementation
-uses uConsts, uVariables, uConsole, uUtils, uDebug, SDLh;
+uses uConsts, uVariables, uConsole, uUtils, SDLh;
type PVariable = ^TVariable;
TVariable = record
@@ -52,12 +52,14 @@
begin
RegisterVariable(Name, p, Trusted, false);
end;
+
procedure RegisterVariable(Name: shortstring; p: TCommandHandler; Trusted: boolean; Rand: boolean);
-var
- value: PVariable;
+var value: PVariable;
begin
New(value);
-TryDo(value <> nil, 'RegisterVariable: value = nil', true);
+if value = nil then
+ ParseCommand('fatal RegisterVariable: value = nil', true);
+
FillChar(value^, sizeof(TVariable), 0);
value^.Name:= Name;
value^.Handler:= p;
diff -Nru hedgewars-0.9.19.3/hedgewars/uConsts.pas hedgewars-0.9.20.5/hedgewars/uConsts.pas
--- hedgewars-0.9.19.3/hedgewars/uConsts.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uConsts.pas 2014-01-08 16:25:17.000000000 +0000
@@ -47,8 +47,8 @@
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);
+ cWhiteColorChannels : TSDL_Color = (r:$FF; g:$FF; b:$FF; a:$FF);
+ cNearBlackColorChannels : TSDL_Color = (r:$00; g:$00; b:$10; a:$FF);
cWhiteColor : Longword = $FFFFFFFF;
cYellowColor : Longword = $FFFFFF00;
@@ -187,6 +187,7 @@
gfMoreWind = $01000000;
gfTagTeam = $02000000;
gfBottomBorder = $04000000;
+ gfShoppaBorder = $08000000;
// NOTE: When adding new game flags, ask yourself
// if a "game start notice" would be useful. If so,
// add one in uWorld.pas - look for "AddGoal".
@@ -249,6 +250,8 @@
ammoprop_NeedTarget = $00000004;
ammoprop_ForwMsgs = $00000008;
ammoprop_AttackInMove = $00000010;
+ ammoprop_DoesntStopTimerWhileAttacking
+ = $00000020;
ammoprop_NoCrosshair = $00000040;
ammoprop_AttackingPut = $00000080;
ammoprop_DontHold = $00000100;
@@ -262,6 +265,8 @@
ammoprop_OscAim = $00010000;
ammoprop_NoMoveAfter = $00020000;
ammoprop_Track = $00040000;
+ ammoprop_DoesntStopTimerInMultiShoot
+ = $00080000;
ammoprop_NoRoundEnd = $10000000;
AMMO_INFINITE = 100;
@@ -283,6 +288,13 @@
posCaseExplode = $00000010;
posCasePoison = $00000020;
+ // hog tag mask
+ //htNone = $00;
+ htTeamName = $01;
+ htName = $02;
+ htHealth = $04;
+ htTransparent = $08;
+
NoPointX = Low(LongInt);
cTargetPointRef : TPoint = (X: NoPointX; Y: 0);
diff -Nru hedgewars-0.9.19.3/hedgewars/uDebug.pas hedgewars-0.9.20.5/hedgewars/uDebug.pas
--- hedgewars-0.9.19.3/hedgewars/uDebug.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uDebug.pas 2013-10-31 20:21:55.000000000 +0000
@@ -33,11 +33,7 @@
begin
WriteLnToConsole(Msg);
if isFatalError then
- begin
ParseCommand('fatal ' + lastConsoleline, true);
- SDL_Quit;
- halt(1)
- end
end;
procedure TryDo(Assert: boolean; Msg: shortstring; isFatal: boolean);
diff -Nru hedgewars-0.9.19.3/hedgewars/uGame.pas hedgewars-0.9.20.5/hedgewars/uGame.pas
--- hedgewars-0.9.19.3/hedgewars/uGame.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uGame.pas 2014-01-08 16:25:17.000000000 +0000
@@ -27,8 +27,8 @@
implementation
////////////////////
uses uInputHandler, uTeams, uIO, uAI, uGears, uSound, uLocale, uCaptions,
- uVisualGears, uTypes, uVariables, uCommands, uConsts
- {$IFDEF USE_TOUCH_INTERFACE}, uTouch{$ENDIF};
+ uTypes, uVariables, uCommands, uConsts, uVisualGearsList
+ {$IFDEF USE_TOUCH_INTERFACE}, uTouch{$ENDIF};
procedure DoGameTick(Lag: LongInt);
var i,j : LongInt;
@@ -51,7 +51,7 @@
else if (GameType = gmtSave) or (fastUntilLag and (GameType = gmtNet)) then
Lag:= 2500;
- if (GameType = gmtDemo) then
+ if (GameType = gmtDemo) then
if isSpeed then
begin
i:= RealTicks-SpeedStart;
@@ -90,7 +90,7 @@
if CurrentHedgehog^.BotLevel <> 0 then
ProcessBot;
ProcessGears;
- {$IFDEF SDL13}ProcessTouch;{$ENDIF}
+ {$IFDEF USE_TOUCH_INTERFACE}ProcessTouch;{$ENDIF}
end
else
begin
diff -Nru hedgewars-0.9.19.3/hedgewars/uGears.pas hedgewars-0.9.20.5/hedgewars/uGears.pas
--- hedgewars-0.9.19.3/hedgewars/uGears.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uGears.pas 2014-01-08 16:25:17.000000000 +0000
@@ -33,61 +33,38 @@
* effects are called "Visual Gears" and defined in the respective unit!
*)
interface
-uses SDLh, uConsts, uFloat, uTypes;
+uses uConsts, uFloat, uTypes, uChat;
procedure initModule;
procedure freeModule;
function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content, cnt: Longword): PGear;
function SpawnFakeCrateAt(x, y: LongInt; crate: TCrateType; explode: boolean; poison: boolean ): PGear;
-function GetAmmo(Hedgehog: PHedgehog): TAmmoType;
-function GetUtility(Hedgehog: PHedgehog): TAmmoType;
-procedure HideHog(HH: PHedgehog);
-procedure RestoreHog(HH: PHedgehog);
procedure ProcessGears;
procedure EndTurnCleanup;
-procedure SetAllToActive;
-procedure SetAllHHToActive; inline;
-procedure SetAllHHToActive(Ice: boolean);
procedure DrawGears;
procedure FreeGearsList;
procedure AddMiscGears;
procedure AssignHHCoords;
function GearByUID(uid : Longword) : PGear;
-procedure doStepDrowningGear(Gear: PGear);
-
implementation
-uses uStore, uSound, uTeams, uRandom, uCollisions, uIO, uLandGraphics, {$IFDEF SDL13}uTouch,{$ENDIF}
- uLocale, uAI, uAmmos, uStats, uVisualGears, uScript, GLunit, uVariables,
+uses uStore, uSound, uTeams, uRandom, uIO, uLandGraphics,
+ {$IFDEF USE_TOUCH_INTERFACE}uTouch,{$ENDIF}
+ uLocale, uAmmos, uStats, uVisualGears, uScript, uVariables,
uCommands, uUtils, uTextures, uRenderUtils, uGearsRender, uCaptions, uDebug, uLandTexture,
- uGearsHedgehog, uGearsUtils, uGearsList, uGearsHandlers, uGearsHandlersRope;
+ uGearsHedgehog, uGearsUtils, uGearsList, uGearsHandlersRope
+ , uVisualGearsList, uGearsHandlersMess, uAI;
var skipFlag: boolean;
-procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); forward;
-//procedure AmmoFlameWork(Ammo: PGear); forward;
-function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS; forward;
-procedure SpawnBoxOfSmth; forward;
-procedure ShotgunShot(Gear: PGear); forward;
-procedure doStepCase(Gear: PGear); forward;
-
-
var delay: LongWord;
delay2: LongWord;
step: (stDelay, stChDmg, stSweep, stTurnReact,
stAfterDelay, stChWin, stWater, stChWin2, stHealth,
stSpawn, stNTurn);
- upd: Longword;
- snowLeft,snowRight: LongInt;
NewTurnTick: LongWord;
//SDMusic: shortstring;
-// For better maintainability the step handlers of gears are stored in
-// separate files.
-// Note: step handlers of gears that are hedgehogs are in a different file
-// than the handlers for all other gears.
-{$INCLUDE "GSHandlers.inc"}
-
function CheckNoDamage: boolean; // returns TRUE in case of no damaged hhs
var Gear: PGear;
dmg: LongInt;
@@ -101,7 +78,7 @@
begin
if (not isInMultiShoot) then
inc(Gear^.Damage, Gear^.Karma);
- if (Gear^.Damage <> 0) and (not Gear^.Invulnerable) then
+ if (Gear^.Damage <> 0) and ((Gear^.Hedgehog^.Effects[heInvulnerable] = 0)) then
begin
CheckNoDamage:= false;
@@ -175,7 +152,7 @@
dec(Gear^.Hedgehog^.InitialHealth, 5)
end
end;
- if tmp > 0 then
+ if tmp > 0 then
begin
inc(Gear^.Damage, min(tmp, max(0,Gear^.Health - 1 - Gear^.Damage)));
HHHurt(Gear^.Hedgehog, dsPoison);
@@ -190,13 +167,15 @@
var t: PGear;
i, AliveCount: LongInt;
s: shortstring;
+ prevtime: LongWord;
begin
+prevtime:= TurnTimeLeft;
ScriptCall('onGameTick');
if GameTicks mod 20 = 0 then ScriptCall('onGameTick20');
if GameTicks = NewTurnTick then
begin
ScriptCall('onNewTurn');
-{$IFDEF SDL13}
+{$IFDEF USE_TOUCH_INTERFACE}
uTouch.NewTurnBeginning();
{$ENDIF}
end;
@@ -225,7 +204,7 @@
DeleteGear(curHandledGear)
else
begin
- if curHandledGear^.Message and gmRemoveFromList <> 0 then
+ if curHandledGear^.Message and gmRemoveFromList <> 0 then
begin
RemoveGearFromList(curHandledGear);
// since I can't think of any good reason this would ever be separate from a remove from list, going to keep it inside this block
@@ -259,13 +238,13 @@
if delay = 0 then
inc(step)
end;
-
+
stChDmg:
if CheckNoDamage then
inc(step)
else
step:= stDelay;
-
+
stSweep:
if SweepDirty then
begin
@@ -274,7 +253,7 @@
end
else
inc(step);
-
+
stTurnReact:
begin
if (not bBetweenTurns) and (not isInMultiShoot) then
@@ -285,7 +264,7 @@
else
inc(step, 2);
end;
-
+
stAfterDelay:
begin
if delay = 0 then
@@ -328,15 +307,15 @@
if cHealthDecrease <> 0 then
begin
SuddenDeathDmg:= true;
-
+
// flash
ScreenFade:= sfFromWhite;
ScreenFadeValue:= sfMax;
ScreenFadeSpeed:= 1;
-
+
ChangeToSDClouds;
ChangeToSDFlakes;
- glClearColor(SDSkyColor.r * (SDTint/255) / 255, SDSkyColor.g * (SDTint/255) / 255, SDSkyColor.b * (SDTint/255) / 255, 0.99);
+ SetSkyColor(SDSkyColor.r * (SDTint/255) / 255, SDSkyColor.g * (SDTint/255) / 255, SDSkyColor.b * (SDTint/255) / 255);
Ammoz[amTardis].SkipTurns:= 9999;
Ammoz[amTardis].Probability:= 0;
end;
@@ -425,7 +404,8 @@
if (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.State and gstAttacked = 0)
and (CurAmmoGear = nil) then
SweepDirty;
- CheckNoDamage;
+ if (CurrentHedgehog^.Gear = nil) or (CurrentHedgehog^.Gear^.State and gstHHDriven = 0) or (CurrentHedgehog^.Gear^.Damage = 0) then
+ CheckNoDamage;
AliveCount:= 0; // shorter version of check for win to allow typical step activity to proceed
for i:= 0 to Pred(ClansCount) do
if ClansArray[i]^.ClanHealth > 0 then
@@ -443,8 +423,10 @@
if TurnTimeLeft > 0 then
if CurrentHedgehog^.Gear <> nil then
- if ((CurrentHedgehog^.Gear^.State and gstAttacking) = 0) and
- not(isInMultiShoot and (CurrentHedgehog^.CurAmmoType in [amShotgun, amDEagle, amSniperRifle])) then
+ if (((CurrentHedgehog^.Gear^.State and gstAttacking) = 0)
+ or (Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_DoesntStopTimerWhileAttacking <> 0))
+ and not(isInMultiShoot and ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_DoesntStopTimerInMultiShoot) <> 0)) then
+ //(CurrentHedgehog^.CurAmmoType in [amShotgun, amDEagle, amSniperRifle])
begin
if (TurnTimeLeft = 5000)
and (cHedgehogTurnTime >= 10000)
@@ -483,7 +465,7 @@
inc(hiTicks) // we do not recieve a message for this
end;
AddRandomness(CheckSum);
-
+TurnClockActive:= prevtime <> TurnTimeLeft;
inc(GameTicks)
end;
@@ -528,7 +510,7 @@
if (Gear <> nil) then
begin
if (GameFlags and gfInvulnerable) = 0 then
- Gear^.Invulnerable:= false;
+ Gear^.Hedgehog^.Effects[heInvulnerable]:= 0;
end;
end;
t:= GearsList;
@@ -542,7 +524,7 @@
end;
t:= t^.NextGear
end;
-
+
if ((GameFlags and gfResetWeps) <> 0) and (not PlacingHogs) then
ResetWeapons;
@@ -551,39 +533,6 @@
RecountTeamHealth(TeamsArray[i])
end;
-procedure SetAllToActive;
-var t: PGear;
-begin
-AllInactive:= false;
-t:= GearsList;
-while t <> nil do
- begin
- t^.Active:= true;
- t:= t^.NextGear
- end
-end;
-
-procedure SetAllHHToActive; inline;
-begin
-SetAllHHToActive(true)
-end;
-
-procedure SetAllHHToActive(Ice: boolean);
-var t: PGear;
-begin
-AllInactive:= false;
-t:= GearsList;
-while t <> nil do
- begin
- if (t^.Kind = gtHedgehog) or (t^.Kind = gtExplosives) then
- begin
- if (t^.Kind = gtHedgehog) and Ice then CheckIce(t);
- t^.Active:= true
- end;
- t:= t^.NextGear
- end
-end;
-
procedure DrawGears;
var Gear: PGear;
x, y: LongInt;
@@ -615,7 +564,7 @@
end;
procedure AddMiscGears;
-var i,rx, ry: Longword;
+var p,i,j,rx, ry: Longword;
rdx, rdy: hwFloat;
Gear: PGear;
begin
@@ -650,11 +599,13 @@
Gear:= GearsList;
if (GameFlags and gfInvulnerable) <> 0 then
- while Gear <> nil do
- begin
- Gear^.Invulnerable:= true; // this is only checked on hogs right now, so no need for gear type check
- Gear:= Gear^.NextGear
- end;
+ for p:= 0 to Pred(ClansCount) do
+ with ClansArray[p]^ do
+ for j:= 0 to Pred(TeamsNumber) do
+ with Teams[j]^ do
+ for i:= 0 to cMaxHHIndex do
+ with Hedgehogs[i] do
+ Effects[heInvulnerable]:= 1;
if (GameFlags and gfLaserSight) <> 0 then
cLaserSighting:= true;
@@ -673,214 +624,11 @@
snowRight:= max(LAND_WIDTH,4096)+512;
snowLeft:= -(snowRight-LAND_WIDTH);
-if (not hasBorder) and ((Theme = 'Snow') or (Theme = 'Christmas')) then
+if (not hasBorder) and cSnow then
for i:= vobCount * Longword(max(LAND_WIDTH,4096)) div 2048 downto 1 do
AddGear(LongInt(GetRandom(snowRight - snowLeft)) + snowLeft, LAND_HEIGHT + LongInt(GetRandom(750)) - 1300, gtFlake, 0, _0, _0, 0);
end;
-
-procedure ShotgunShot(Gear: PGear);
-var t: PGear;
- dmg, r, dist: LongInt;
- dx, dy: hwFloat;
-begin
-Gear^.Radius:= cShotgunRadius;
-t:= GearsList;
-while t <> nil do
- begin
- case t^.Kind of
- gtHedgehog,
- gtMine,
- gtSMine,
- gtKnife,
- gtCase,
- gtTarget,
- 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;
- dx:= Gear^.X-t^.X;
- dx.isNegative:= false;
- dy:= Gear^.Y-t^.Y;
- dy.isNegative:= false;
- if r-hwRound(dx+dy) > 0 then
- begin
- dist:= hwRound(Distance(dx, dy));
- dmg:= ModifyDamage(min(r - dist, 25), t);
- end;
- if dmg > 0 then
- begin
- if (not t^.Invulnerable) then
- ApplyDamage(t, Gear^.Hedgehog, dmg, dsBullet)
- else
- Gear^.State:= Gear^.State or gstWinner;
-
- DeleteCI(t);
- t^.dX:= t^.dX + Gear^.dX * dmg * _0_01 + SignAs(cHHKick, Gear^.dX);
- t^.dY:= t^.dY + Gear^.dY * dmg * _0_01;
- t^.State:= t^.State or gstMoving;
- if t^.Kind = gtKnife then t^.State:= t^.State and (not gstCollision);
- t^.Active:= true;
- FollowGear:= t
- end
- end;
- gtGrave: begin
- dmg:= 0;
- r:= Gear^.Radius + t^.Radius;
- dx:= Gear^.X-t^.X;
- dx.isNegative:= false;
- dy:= Gear^.Y-t^.Y;
- dy.isNegative:= false;
- if r-hwRound(dx+dy) > 0 then
- begin
- dist:= hwRound(Distance(dx, dy));
- dmg:= ModifyDamage(min(r - dist, 25), t);
- end;
- if dmg > 0 then
- begin
- t^.dY:= - _0_1;
- t^.Active:= true
- end
- end;
- end;
- t:= t^.NextGear
- end;
-if (GameFlags and gfSolidLand) = 0 then
- DrawExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cShotgunRadius)
-end;
-
-procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
-var t: PGearArray;
- Gear: PGear;
- i, j, tmpDmg: LongInt;
- VGear: PVisualGear;
-begin
-t:= CheckGearsCollision(Ammo);
-// Just to avoid hogs on rope dodging fire.
-if (CurAmmoGear <> nil) and ((CurAmmoGear^.Kind = gtRope) or (CurAmmoGear^.Kind = gtJetpack) or (CurAmmoGear^.Kind = gtBirdy))
-and (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.CollisionIndex = -1)
-and (sqr(hwRound(Ammo^.X) - hwRound(CurrentHedgehog^.Gear^.X)) + sqr(hwRound(Ammo^.Y) - hwRound(CurrentHedgehog^.Gear^.Y)) <= sqr(cHHRadius + Ammo^.Radius)) then
- begin
- t^.ar[t^.Count]:= CurrentHedgehog^.Gear;
- inc(t^.Count)
- end;
-
-i:= t^.Count;
-
-if (Ammo^.Kind = gtFlame) and (i > 0) then
- Ammo^.Health:= 0;
-while i > 0 do
- begin
- dec(i);
- Gear:= t^.ar[i];
- if (Ammo^.Kind = gtFlame) and (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then
- Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000);
- tmpDmg:= ModifyDamage(Damage, Gear);
- if (Gear^.State and gstNoDamage) = 0 then
- begin
-
- if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then
- begin
- VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit);
- if VGear <> nil then
- VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY);
- end;
-
- if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then
- Gear^.FlightTime:= 1;
-
-
- case Gear^.Kind of
- gtHedgehog,
- gtMine,
- gtSMine,
- gtKnife,
- gtTarget,
- gtCase,
- gtExplosives: //,
- //gtStructure:
- begin
- if (Ammo^.Kind = gtDrill) then
- begin
- Ammo^.Timer:= 0;
- exit;
- end;
- if (not Gear^.Invulnerable) then
- begin
- if (Ammo^.Kind = gtKnife) and (tmpDmg > 0) then
- for j:= 1 to max(1,min(3,tmpDmg div 5)) do
- begin
- VGear:= AddVisualGear(hwRound(Ammo^.X-((Ammo^.X-Gear^.X)/_2)), hwRound(Ammo^.Y-((Ammo^.Y-Gear^.Y)/_2)), vgtStraightShot);
- if VGear <> nil then
- with VGear^ do
- begin
- Tint:= $FFCC00FF;
- Angle:= random(360);
- dx:= 0.0005 * (random(100));
- dy:= 0.0005 * (random(100));
- if random(2) = 0 then
- dx := -dx;
- if random(2) = 0 then
- dy := -dy;
- FrameTicks:= 600+random(200);
- State:= ord(sprStar)
- end
- end;
- ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove)
- end
- else
- Gear^.State:= Gear^.State or gstWinner;
- if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then
- begin
- if (Ammo^.Hedgehog^.Gear <> nil) then
- Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable);
- ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
- end;
-
- if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then
- begin
- Gear^.dX:= Ammo^.dX * Power * _0_005;
- Gear^.dY:= Ammo^.dY * Power * _0_005
- end
- else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then
- begin
- Gear^.dX:= Ammo^.dX * Power * _0_01;
- Gear^.dY:= Ammo^.dY * Power * _0_01
- end;
-
- if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
- begin
- Gear^.Active:= true;
- DeleteCI(Gear);
- Gear^.State:= Gear^.State or gstMoving;
- if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and (not gstCollision);
- // move the gear upwards a bit to throw it over tiny obstacles at start
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
- begin
- if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then
- Gear^.Y:= Gear^.Y - _1;
- if not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then
- Gear^.Y:= Gear^.Y - _1;
- if not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then
- Gear^.Y:= Gear^.Y - _1;
- end
- end;
-
-
- if (Ammo^.Kind <> gtFlame) or ((Ammo^.State and gsttmpFlag) = 0) then
- FollowGear:= Gear
- end;
- end
- end;
- end;
-if i <> 0 then
- SetAllToActive
-end;
-
procedure AssignHHCoords;
var i, t, p, j: LongInt;
ar: array[0..Pred(cMaxHHs)] of PHedgehog;
@@ -945,31 +693,6 @@
end
end;
-var GearsNearArray : TPGearArray;
-function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS;
-var
- t: PGear;
- s: Longword;
-begin
- r:= r*r;
- s:= 0;
- SetLength(GearsNearArray, s);
- t := GearsList;
- while t <> nil do
- begin
- if (t^.Kind = Kind)
- and ((X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) < int2hwFloat(r)) then
- begin
- inc(s);
- SetLength(GearsNearArray, s);
- GearsNearArray[s - 1] := t;
- end;
- t := t^.NextGear;
- end;
-
- GearsNear.size:= s;
- GearsNear.ar:= @GearsNearArray
-end;
{procedure AmmoFlameWork(Ammo: PGear);
var t: PGear;
@@ -992,21 +715,6 @@
end;}
-function CountGears(Kind: TGearType): Longword;
-var t: PGear;
- count: Longword = 0;
-begin
-
-t:= GearsList;
-while t <> nil do
- begin
- if t^.Kind = Kind then
- inc(count);
- t:= t^.NextGear
- end;
-CountGears:= count;
-end;
-
function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content, cnt: Longword): PGear;
begin
FollowGear := AddGear(x, y, gtCase, 0, _0, _0, 0);
@@ -1049,7 +757,7 @@
FollowGear := AddGear(x, y, gtCase, 0, _0, _0, 0);
cCaseFactor := 0;
FollowGear^.Pos := posCaseDummy;
-
+
if explode then
FollowGear^.Pos := FollowGear^.Pos + posCaseExplode;
if poison then
@@ -1079,142 +787,6 @@
SpawnFakeCrateAt := FollowGear;
end;
-function GetAmmo(Hedgehog: PHedgehog): TAmmoType;
-var t, aTot: LongInt;
- i: TAmmoType;
-begin
-Hedgehog:= Hedgehog; // avoid hint
-
-aTot:= 0;
-for i:= Low(TAmmoType) to High(TAmmoType) do
- if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
- inc(aTot, Ammoz[i].Probability);
-
-t:= aTot;
-i:= Low(TAmmoType);
-if (t > 0) then
- begin
- t:= GetRandom(t);
- while t >= 0 do
- begin
- inc(i);
- if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
- dec(t, Ammoz[i].Probability)
- end
- end;
-GetAmmo:= i
-end;
-
-function GetUtility(Hedgehog: PHedgehog): TAmmoType;
-var t, uTot: LongInt;
- i: TAmmoType;
-begin
-
-uTot:= 0;
-for i:= Low(TAmmoType) to High(TAmmoType) do
- if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0)
- and ((Hedgehog^.Team^.HedgehogsNumber > 1) or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then
- inc(uTot, Ammoz[i].Probability);
-
-t:= uTot;
-i:= Low(TAmmoType);
-if (t > 0) then
- begin
- t:= GetRandom(t);
- while t >= 0 do
- begin
- inc(i);
- if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0) and ((Hedgehog^.Team^.HedgehogsNumber > 1)
- or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then
- dec(t, Ammoz[i].Probability)
- end
- end;
-GetUtility:= i
-end;
-
-
-
-procedure SpawnBoxOfSmth;
-var t, aTot, uTot, a, h: LongInt;
- i: TAmmoType;
-begin
-if (PlacingHogs) or
- (cCaseFactor = 0)
- or (CountGears(gtCase) >= 5)
- or (GetRandom(cCaseFactor) <> 0) then
- exit;
-
-FollowGear:= nil;
-aTot:= 0;
-uTot:= 0;
-for i:= Low(TAmmoType) to High(TAmmoType) do
- if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
- inc(aTot, Ammoz[i].Probability)
- else
- inc(uTot, Ammoz[i].Probability);
-
-t:=0;
-a:=aTot;
-h:= 1;
-
-if (aTot+uTot) <> 0 then
- if ((GameFlags and gfInvulnerable) = 0) then
- begin
- h:= cHealthCaseProb * 100;
- t:= GetRandom(10000);
- a:= (10000-h)*aTot div (aTot+uTot)
- end
- else
- begin
- t:= GetRandom(aTot+uTot);
- h:= 0
- end;
-
-
-if t 0) then
- begin
- FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
- t:= GetRandom(t);
- i:= Low(TAmmoType);
- FollowGear^.Pos:= posCaseAmmo;
- FollowGear^.AmmoType:= i;
- AddCaption(GetEventString(eidNewAmmoPack), cWhiteColor, capgrpAmmoInfo);
- end
- end
-else
- begin
- t:= uTot;
- if (t > 0) then
- begin
- FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
- t:= GetRandom(t);
- i:= Low(TAmmoType);
- FollowGear^.Pos:= posCaseUtility;
- FollowGear^.AmmoType:= i;
- AddCaption(GetEventString(eidNewUtilityPack), cWhiteColor, capgrpAmmoInfo);
- end
- end;
-
-// handles case of no ammo or utility crates - considered also placing booleans in uAmmos and altering probabilities
-if (FollowGear <> nil) then
- begin
- FindPlace(FollowGear, true, 0, LAND_WIDTH);
-
- if (FollowGear <> nil) then
- AddVoice(sndReinforce, CurrentTeam^.voicepack)
- end
-end;
-
function GearByUID(uid : Longword) : PGear;
var gear: PGear;
@@ -1275,6 +847,8 @@
text:= copy(s, 3, Length(s) - 1)
else text:= copy(s, 2, Length(s) - 1);
+ if text = '' then text:= '...';
+
(*
if CheckNoTeamOrHH then
begin
@@ -1288,7 +862,7 @@
// if team matches current hedgehog team, default to current hedgehog
if (i = 0) and (CurrentHedgehog <> nil) and (CurrentHedgehog^.Team = TeamsArray[t]) then
hh:= CurrentHedgehog
- else
+ else
begin
// otherwise use the first living hog or the hog amongs the remaining ones indicated by i
j:= 0;
@@ -1304,7 +878,7 @@
inc(j)
end
end;
- if hh <> nil then
+ if hh <> nil then
begin
Gear:= AddVisualGear(0, 0, vgtSpeechBubble);
if Gear <> nil then
@@ -1312,9 +886,10 @@
Gear^.Hedgehog:= hh;
Gear^.Text:= text;
Gear^.FrameTicks:= x
- end
+ end;
+ //ParseCommand('/say [' + hh^.Name + '] '+text, true)
+ AddChatString(#1+'[' + HH^.Name + '] '+text);
end
- //else ParseCommand('say ' + text, true)
end
else if (x >= 4) then
begin
diff -Nru hedgewars-0.9.19.3/hedgewars/uGearsHandlers.pas hedgewars-0.9.20.5/hedgewars/uGearsHandlers.pas
--- hedgewars-0.9.19.3/hedgewars/uGearsHandlers.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uGearsHandlers.pas 2014-01-08 16:25:17.000000000 +0000
@@ -61,7 +61,7 @@
begin
Gear^.Tag := 0;
Gear^.Y := Gear^.Y + int2hwFloat(yy);
- if not TestCollisionXwithGear(Gear, xxn) then
+ if TestCollisionXwithGear(Gear, xxn) = 0 then
begin
Gear^.X := Gear^.X + int2hwFloat(xxn);
NextAngle(Gear, dA)
@@ -69,7 +69,7 @@
end;
if (yy = 0) then
- if TestCollisionXwithGear(Gear, xx) then
+ if TestCollisionXwithGear(Gear, xx) <> 0 then
PrevAngle(Gear, dA)
else
begin
diff -Nru hedgewars-0.9.19.3/hedgewars/uGearsHandlersMess.pas hedgewars-0.9.20.5/hedgewars/uGearsHandlersMess.pas
--- hedgewars-0.9.19.3/hedgewars/uGearsHandlersMess.pas 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uGearsHandlersMess.pas 2014-01-08 16:25:17.000000000 +0000
@@ -0,0 +1,5935 @@
+(*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2013 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
+ *)
+
+(*
+ * This file contains the step handlers for gears.
+ *
+ * Important: Since gears change the course of the game, calculations that
+ * lead to different results for different clients/players/machines
+ * should NOT occur!
+ * Use safe functions and data types! (e.g. GetRandom() and hwFloat)
+ *)
+
+ {$INCLUDE "options.inc"}
+
+unit uGearsHandlersMess;
+interface
+uses uTypes, uFloat;
+
+procedure doStepPerPixel(Gear: PGear; step: TGearStepProcedure; onlyCheckIfChanged: boolean);
+procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
+procedure HideHog(HH: PHedgehog);
+procedure doStepDrowningGear(Gear: PGear);
+procedure doStepFallingGear(Gear: PGear);
+procedure doStepBomb(Gear: PGear);
+procedure doStepMolotov(Gear: PGear);
+procedure doStepCluster(Gear: PGear);
+procedure doStepShell(Gear: PGear);
+procedure doStepSnowball(Gear: PGear);
+procedure doStepSnowflake(Gear: PGear);
+procedure doStepGrave(Gear: PGear);
+procedure doStepBeeWork(Gear: PGear);
+procedure doStepBee(Gear: PGear);
+procedure doStepShotIdle(Gear: PGear);
+procedure doStepShotgunShot(Gear: PGear);
+procedure spawnBulletTrail(Bullet: PGear);
+procedure doStepBulletWork(Gear: PGear);
+procedure doStepDEagleShot(Gear: PGear);
+procedure doStepSniperRifleShot(Gear: PGear);
+procedure doStepActionTimer(Gear: PGear);
+procedure doStepPickHammerWork(Gear: PGear);
+procedure doStepPickHammer(Gear: PGear);
+procedure doStepBlowTorchWork(Gear: PGear);
+procedure doStepBlowTorch(Gear: PGear);
+procedure doStepMine(Gear: PGear);
+procedure doStepSMine(Gear: PGear);
+procedure doStepDynamite(Gear: PGear);
+procedure doStepRollingBarrel(Gear: PGear);
+procedure doStepCase(Gear: PGear);
+procedure doStepTarget(Gear: PGear);
+procedure doStepIdle(Gear: PGear);
+procedure doStepShover(Gear: PGear);
+procedure doStepWhip(Gear: PGear);
+procedure doStepFlame(Gear: PGear);
+procedure doStepFirePunchWork(Gear: PGear);
+procedure doStepFirePunch(Gear: PGear);
+procedure doStepParachuteWork(Gear: PGear);
+procedure doStepParachute(Gear: PGear);
+procedure doStepAirAttackWork(Gear: PGear);
+procedure doStepAirAttack(Gear: PGear);
+procedure doStepAirBomb(Gear: PGear);
+procedure doStepGirder(Gear: PGear);
+procedure doStepTeleportAfter(Gear: PGear);
+procedure doStepTeleportAnim(Gear: PGear);
+procedure doStepTeleport(Gear: PGear);
+procedure doStepSwitcherWork(Gear: PGear);
+procedure doStepSwitcher(Gear: PGear);
+procedure doStepMortar(Gear: PGear);
+procedure doStepKamikazeWork(Gear: PGear);
+procedure doStepKamikazeIdle(Gear: PGear);
+procedure doStepKamikaze(Gear: PGear);
+procedure doStepCakeExpl(Gear: PGear);
+procedure doStepCakeDown(Gear: PGear);
+procedure doStepCakeWork(Gear: PGear);
+procedure doStepCakeUp(Gear: PGear);
+procedure doStepCakeFall(Gear: PGear);
+procedure doStepCake(Gear: PGear);
+procedure doStepSeductionWork(Gear: PGear);
+procedure doStepSeductionWear(Gear: PGear);
+procedure doStepSeduction(Gear: PGear);
+procedure doStepWaterUp(Gear: PGear);
+procedure doStepDrillDrilling(Gear: PGear);
+procedure doStepDrill(Gear: PGear);
+procedure doStepBallgunWork(Gear: PGear);
+procedure doStepBallgun(Gear: PGear);
+procedure doStepRCPlaneWork(Gear: PGear);
+procedure doStepRCPlane(Gear: PGear);
+procedure doStepJetpackWork(Gear: PGear);
+procedure doStepJetpack(Gear: PGear);
+procedure doStepBirdyDisappear(Gear: PGear);
+procedure doStepBirdyFly(Gear: PGear);
+procedure doStepBirdyDescend(Gear: PGear);
+procedure doStepBirdyAppear(Gear: PGear);
+procedure doStepBirdy(Gear: PGear);
+procedure doStepEggWork(Gear: PGear);
+procedure doPortalColorSwitch();
+procedure doStepPortal(Gear: PGear);
+procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
+procedure doStepMovingPortal_real(Gear: PGear);
+procedure doStepMovingPortal(Gear: PGear);
+procedure doStepPortalShot(newPortal: PGear);
+procedure doStepPiano(Gear: PGear);
+procedure doStepSineGunShotWork(Gear: PGear);
+procedure doStepSineGunShot(Gear: PGear);
+procedure doStepFlamethrowerWork(Gear: PGear);
+procedure doStepFlamethrower(Gear: PGear);
+procedure doStepLandGunWork(Gear: PGear);
+procedure doStepLandGun(Gear: PGear);
+procedure doStepPoisonCloud(Gear: PGear);
+procedure doStepHammer(Gear: PGear);
+procedure doStepHammerHitWork(Gear: PGear);
+procedure doStepHammerHit(Gear: PGear);
+procedure doStepResurrectorWork(Gear: PGear);
+procedure doStepResurrector(Gear: PGear);
+procedure doStepNapalmBomb(Gear: PGear);
+procedure doStepStructure(Gear: PGear);
+procedure doStepTardisWarp(Gear: PGear);
+procedure doStepTardis(Gear: PGear);
+procedure updateFuel(Gear: PGear);
+procedure updateTarget(Gear:PGear; newX, newY:HWFloat);
+procedure doStepIceGun(Gear: PGear);
+procedure doStepAddAmmo(Gear: PGear);
+procedure doStepGenericFaller(Gear: PGear);
+procedure doStepCreeper(Gear: PGear);
+procedure doStepKnife(Gear: PGear);
+
+var
+ upd: Longword;
+ snowLeft,snowRight: LongInt;
+
+implementation
+uses uConsts, uVariables, uVisualGearsList, uRandom, uCollisions, uGearsList, uUtils, uSound
+ , SDLh, uScript, uGearsHedgehog, uGearsUtils, uIO, uCaptions, uLandGraphics
+ , uGearsHandlers, uTextures, uRenderUtils, uAmmos, uTeams, uLandTexture, uCommands
+ , uStore, uAI, uStats;
+
+procedure doStepPerPixel(Gear: PGear; step: TGearStepProcedure; onlyCheckIfChanged: boolean);
+var
+ dX, dY, sX, sY: hwFloat;
+ i, steps: LongWord;
+ caller: TGearStepProcedure;
+begin
+ dX:= Gear^.dX;
+ dY:= Gear^.dY;
+ steps:= max(abs(hwRound(Gear^.X+dX)-hwRound(Gear^.X)), abs(hwRound(Gear^.Y+dY)-hwRound(Gear^.Y)));
+
+ // Gear is still on the same Pixel it was before
+ if steps < 1 then
+ begin
+ if onlyCheckIfChanged then
+ begin
+ Gear^.X := Gear^.X + dX;
+ Gear^.Y := Gear^.Y + dY;
+ EXIT;
+ end
+ else
+ steps := 1;
+ end;
+
+ if steps > 1 then
+ begin
+ sX:= dX / steps;
+ sY:= dY / steps;
+ end
+
+ else
+ begin
+ sX:= dX;
+ sY:= dY;
+ end;
+
+ caller:= Gear^.doStep;
+
+ for i:= 1 to steps do
+ begin
+ Gear^.X := Gear^.X + sX;
+ Gear^.Y := Gear^.Y + sY;
+ step(Gear);
+ if (Gear^.doStep <> caller)
+ or ((Gear^.State and gstCollision) <> 0)
+ or ((Gear^.State and gstMoving) = 0) then
+ break;
+ end;
+end;
+
+procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
+var
+ gi: PGear;
+ d: LongInt;
+begin
+ gi := GearsList;
+ while gi <> nil do
+ begin
+ if (gi^.Kind = gtHedgehog) then
+ begin
+ d := r - hwRound(Distance(gi^.X - x, gi^.Y - y));
+ if (d > 1) and ((gi^.Hedgehog^.Effects[heInvulnerable] = 0)) and (GetRandom(2) = 0) then
+ begin
+ if (CurrentHedgehog^.Gear = gi) then
+ PlaySoundV(sndOops, gi^.Hedgehog^.Team^.voicepack)
+
+ else
+ begin
+ if ((gi^.State and gstMoving) = 0) and (gi^.Hedgehog^.Effects[heFrozen] = 0) then
+ begin
+ gi^.dX.isNegative:= X r div 2 then
+ PlaySoundV(sndNooo, gi^.Hedgehog^.Team^.voicepack)
+ else
+ PlaySoundV(sndUhOh, gi^.Hedgehog^.Team^.voicepack);
+ end;
+ end;
+ end;
+
+ gi := gi^.NextGear
+ end;
+end;
+
+procedure HideHog(HH: PHedgehog);
+begin
+ ScriptCall('onHogHide', HH^.Gear^.Uid);
+ DeleteCI(HH^.Gear);
+ if FollowGear = HH^.Gear then
+ FollowGear:= nil;
+
+ if lastGearByUID = HH^.Gear then
+ lastGearByUID := nil;
+
+ HH^.Gear^.Message:= HH^.Gear^.Message or gmRemoveFromList;
+ with HH^.Gear^ do
+ begin
+ Z := cHHZ;
+ HH^.Gear^.Active:= false;
+ State:= State and (not (gstHHDriven or gstAttacking or gstAttacked));
+ Message := Message and (not gmAttack);
+ end;
+ HH^.GearHidden:= HH^.Gear;
+ HH^.Gear:= nil
+end;
+
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepDrowningGear(Gear: PGear);
+ begin
+ AllInactive := false;
+ Gear^.Y := Gear^.Y + cDrownSpeed;
+ Gear^.X := Gear^.X + Gear^.dX * cDrownSpeed;
+ // Create some bubbles (0.5% might be better but causes too few bubbles sometimes)
+ if ((not SuddenDeathDmg and (WaterOpacity < $FF))
+ or (SuddenDeathDmg and (SDWaterOpacity < $FF))) and ((GameTicks and $1F) = 0) then
+ if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then
+ AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble)
+ else if Random(12) = 0 then
+ AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius, vgtBubble);
+ if (not SuddenDeathDmg and (WaterOpacity > $FE))
+ or (SuddenDeathDmg and (SDWaterOpacity > $FE))
+ or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then
+ DeleteGear(Gear);
+ end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepFallingGear(Gear: PGear);
+var
+ isFalling: boolean;
+ //tmp: QWord;
+ tX, tdX, tdY: hwFloat;
+ collV, collH, gX, gY: LongInt;
+ land, xland: word;
+ boing: PVisualGear;
+begin
+ tX:= Gear^.X;
+ gX:= hwRound(Gear^.X);
+ gY:= hwRound(Gear^.Y);
+ if (Gear^.Kind <> gtGenericFaller) and WorldWrap(Gear) and (WorldEdge = weWrap) and (Gear^.AdvBounce <> 0) and
+ ((TestCollisionXwithGear(Gear, 1) <> 0) or (TestCollisionXwithGear(Gear, -1) <> 0)) then
+ begin
+ Gear^.X:= tX;
+ Gear^.dX.isNegative:= (gX > LongInt(leftX) + Gear^.Radius*2)
+ end;
+
+ // clip velocity at 2 - over 1 per pixel, but really shouldn't cause many actual problems.
+ if Gear^.dX.Round > 2 then
+ Gear^.dX.QWordValue:= 8589934592;
+ if Gear^.dY.Round > 2 then
+ Gear^.dY.QWordValue:= 8589934592;
+
+ if (Gear^.State and gstSubmersible <> 0) and (gY > cWaterLine) then
+ begin
+ Gear^.dX:= Gear^.dX * _0_999;
+ Gear^.dY:= Gear^.dY * _0_999
+ end;
+
+ Gear^.State := Gear^.State and (not gstCollision);
+ collV := 0;
+ collH := 0;
+ tdX := Gear^.dX;
+ tdY := Gear^.dY;
+
+// might need some testing/adjustments - just to avoid projectiles to fly forever (accelerated by wind/skips)
+ if (gX < min(LAND_WIDTH div -2, -2048))
+ or (gX > max(LAND_WIDTH * 3 div 2, 6144)) then
+ Gear^.State := Gear^.State or gstCollision;
+
+ if Gear^.dY.isNegative then
+ begin
+ land:= TestCollisionYwithGear(Gear, -1);
+ isFalling := land = 0;
+ if land <> 0 then
+ begin
+ collV := -1;
+ if land and lfIce <> 0 then
+ Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
+ else Gear^.dX := Gear^.dX * Gear^.Friction;
+ if (Gear^.AdvBounce = 0) or (land and lfBouncy = 0) then
+ begin
+ Gear^.dY := - Gear^.dY * Gear^.Elasticity;
+ Gear^.State := Gear^.State or gstCollision
+ end
+ else Gear^.dY := - Gear^.dY * cElastic
+ end
+ else if Gear^.AdvBounce = 1 then
+ begin
+ land:= TestCollisionYwithGear(Gear, 1);
+ if land <> 0 then collV := 1
+ end
+ end
+ else
+ begin // Gear^.dY.isNegative is false
+ land:= TestCollisionYwithGear(Gear, 1);
+ if land <> 0 then
+ begin
+ collV := 1;
+ isFalling := false;
+ if land and lfIce <> 0 then
+ Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
+ else
+ Gear^.dX := Gear^.dX * Gear^.Friction;
+
+ if (Gear^.AdvBounce = 0) or (land and lfBouncy = 0) then
+ begin
+ Gear^.dY := - Gear^.dY * Gear^.Elasticity;
+ Gear^.State := Gear^.State or gstCollision
+ end
+ else Gear^.dY := - Gear^.dY * cElastic
+ end
+ else
+ begin
+ isFalling := true;
+ if Gear^.AdvBounce = 1 then
+ begin
+ land:= TestCollisionYwithGear(Gear, -1);
+ if land <> 0 then collV := -1
+ end
+ end
+ end;
+
+
+ xland:= TestCollisionXwithGear(Gear, hwSign(Gear^.dX));
+ if xland <> 0 then
+ begin
+ collH := hwSign(Gear^.dX);
+ if (Gear^.AdvBounce = 0) or (xland and lfBouncy = 0) then
+ begin
+ Gear^.dX := - Gear^.dX * Gear^.Elasticity;
+ Gear^.dY := Gear^.dY * Gear^.Elasticity;
+ Gear^.State := Gear^.State or gstCollision
+ end
+ else
+ begin
+ Gear^.dX := - Gear^.dX * cElastic;
+ Gear^.dY := Gear^.dY * cElastic
+ end
+ end
+ else if Gear^.AdvBounce = 1 then
+ begin
+ xland:= TestCollisionXwithGear(Gear, -hwSign(Gear^.dX));
+ if xland <> 0 then collH := -hwSign(Gear^.dX)
+ end;
+ //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then
+ if (collV <> 0) and (collH <> 0) and
+ (((Gear^.AdvBounce=1) and ((collV=-1) or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)))) then
+ //or ((xland or land) and lfBouncy <> 0)) then
+ begin
+ if (xland or land) and lfBouncy = 0 then
+ begin
+ Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction;
+ Gear^.dY := tdX*Gear^.Elasticity;
+ Gear^.State := Gear^.State or gstCollision
+ end
+ else
+ begin
+ Gear^.dX := tdY*cElastic*Gear^.Friction;
+ Gear^.dY := tdX*cElastic
+ end;
+
+ Gear^.dY.isNegative := not tdY.isNegative;
+ isFalling := false;
+ Gear^.AdvBounce := 10;
+ end;
+
+ if Gear^.AdvBounce > 1 then
+ dec(Gear^.AdvBounce);
+
+ if isFalling then
+ begin
+ Gear^.dY := Gear^.dY + cGravity;
+ if (GameFlags and gfMoreWind) <> 0 then
+ Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
+ end;
+
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ CheckGearDrowning(Gear);
+ //if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) < _0_0002) and
+ if (not isFalling) and ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_02.QWordValue) then
+ Gear^.State := Gear^.State and (not gstMoving)
+ else
+ Gear^.State := Gear^.State or gstMoving;
+
+ if ((xland or land) and lfBouncy <> 0) and (Gear^.dX.QWordValue < _0_15.QWordValue) and (Gear^.dY.QWordValue < _0_15.QWordValue) then
+ Gear^.State := Gear^.State or gstCollision;
+
+ if ((xland or land) and lfBouncy <> 0) and (Gear^.Radius >= 3) and
+ ((Gear^.dX.QWordValue > _0_15.QWordValue) or (Gear^.dY.QWordValue > _0_15.QWordValue)) then
+ begin
+ boing:= AddVisualGear(gX, gY, vgtStraightShot, 0, false, 1);
+ if boing <> nil then
+ with boing^ do
+ begin
+ Angle:= random(360);
+ dx:= 0;
+ dy:= 0;
+ FrameTicks:= 200;
+ tX:= _0;
+ tX.QWordValue:= Gear^.dY.QWordValue + Gear^.dX.QWordValue;
+ Scale:= hwFloat2Float(Gear^.Density * tX) / 1.5;
+ State:= ord(sprBoing)
+ end;
+ PlaySound(sndMelonImpact, true)
+ end
+ else if (Gear^.nImpactSounds > 0) and
+ (Gear^.State and gstCollision <> 0) and
+ (((Gear^.Kind <> gtMine) and (Gear^.Damage <> 0)) or (Gear^.State and gstMoving <> 0)) and
+ (((Gear^.Radius < 3) and (Gear^.dY < -_0_1)) or
+ ((Gear^.Radius >= 3) and
+ ((Gear^.dX.QWordValue > _0_1.QWordValue) or (Gear^.dY.QWordValue > _0_1.QWordValue)))) then
+ PlaySound(TSound(ord(Gear^.ImpactSound) + LongInt(GetRandom(Gear^.nImpactSounds))), true);
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepBomb(Gear: PGear);
+var
+ i, x, y: LongInt;
+ dX, dY, gdX: hwFloat;
+ vg: PVisualGear;
+begin
+ AllInactive := false;
+
+ doStepFallingGear(Gear);
+
+ dec(Gear^.Timer);
+ if Gear^.Timer = 1000 then // might need adjustments
+ case Gear^.Kind of
+ gtGrenade: makeHogsWorry(Gear^.X, Gear^.Y, 50);
+ gtClusterBomb: makeHogsWorry(Gear^.X, Gear^.Y, 20);
+ gtWatermelon: makeHogsWorry(Gear^.X, Gear^.Y, 75);
+ gtHellishBomb: makeHogsWorry(Gear^.X, Gear^.Y, 90);
+ gtGasBomb: makeHogsWorry(Gear^.X, Gear^.Y, 50);
+ end;
+
+ if (Gear^.Kind = gtBall) and ((Gear^.State and gstTmpFlag) <> 0) then
+ begin
+ CheckCollision(Gear);
+ if (Gear^.State and gstCollision) <> 0 then
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLDontDraw or EXPLNoGfx);
+ end;
+
+ if (Gear^.Kind = gtGasBomb) and ((GameTicks mod 200) = 0) then
+ begin
+ vg:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeWhite);
+ if vg <> nil then
+ vg^.Tint:= $FFC0C000;
+ end;
+
+ if Gear^.Timer = 0 then
+ begin
+ case Gear^.Kind of
+ gtGrenade: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+ gtBall: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 40, Gear^.Hedgehog, EXPLAutoSound);
+ gtClusterBomb:
+ 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) + gdX / 5;
+ dY := (GetRandomf - _3) * _0_08;
+ FollowGear := AddGear(x, y, gtCluster, 0, dX, dY, 25)
+ end
+ end;
+ gtWatermelon:
+ 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) + gdX / 5;
+ dY := (GetRandomf - _1_5) * _0_3;
+ FollowGear:= AddGear(x, y, gtMelonPiece, 0, dX, dY, 75);
+ FollowGear^.DirAngle := i * 60
+ end
+ end;
+ gtHellishBomb:
+ begin
+ x := hwRound(Gear^.X);
+ y := hwRound(Gear^.Y);
+ doMakeExplosion(x, y, 90, Gear^.Hedgehog, EXPLAutoSound);
+
+ for i:= 0 to 127 do
+ begin
+ dX := AngleCos(i * 16) * _0_5 * (GetRandomf + _1);
+ dY := AngleSin(i * 16) * _0_5 * (GetRandomf + _1);
+ if i mod 2 = 0 then
+ begin
+ AddGear(x, y, gtFlame, gstTmpFlag, dX, dY, 0);
+ AddGear(x, y, gtFlame, 0, dX, -dY, 0)
+ end
+ else
+ begin
+ AddGear(x, y, gtFlame, 0, dX, dY, 0);
+ AddGear(x, y, gtFlame, gstTmpFlag, dX, -dY, 0)
+ end;
+ end
+ end;
+ gtGasBomb:
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLAutoSound);
+ for i:= 0 to 2 do
+ begin
+ x:= GetRandom(60);
+ y:= GetRandom(40);
+ FollowGear:= AddGear(hwRound(Gear^.X) - 30 + x, hwRound(Gear^.Y) - 20 + y, gtPoisonCloud, 0, _0, _0, 0);
+ end
+ end;
+ end;
+ DeleteGear(Gear);
+ exit
+ end;
+
+ CalcRotationDirAngle(Gear);
+
+ if Gear^.Kind = gtHellishBomb then
+ begin
+
+ if Gear^.Timer = 3000 then
+ begin
+ Gear^.nImpactSounds := 0;
+ PlaySound(sndHellish);
+ end;
+
+ if (GameTicks and $3F) = 0 then
+ if (Gear^.State and gstCollision) = 0 then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace);
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepMolotov(Gear: PGear);
+var
+ s: Longword;
+ i, gX, gY: LongInt;
+ dX, dY: hwFloat;
+ smoke, glass: PVisualGear;
+begin
+ AllInactive := false;
+
+ doStepFallingGear(Gear);
+ CalcRotationDirAngle(Gear);
+
+ // let's add some smoke depending on speed
+ s:= max(32,152 - round((abs(hwFloat2FLoat(Gear^.dX))+abs(hwFloat2Float(Gear^.dY)))*120))+random(10);
+ if (GameTicks mod s) = 0 then
+ begin
+ // adjust angle to match the texture
+ if Gear^.dX.isNegative then
+ i:= 130
+ else i:= 50;
+
+ smoke:= AddVisualGear(hwRound(Gear^.X)-round(cos((Gear^.DirAngle+i) * pi / 180)*20), hwRound(Gear^.Y)-round(sin((Gear^.DirAngle+i) * pi / 180)*20), vgtSmoke);
+ if smoke <> nil then
+ smoke^.Scale:= 0.75;
+ end;
+
+ if (Gear^.State and gstCollision) <> 0 then
+ begin
+ PlaySound(sndMolotov);
+ gX := hwRound(Gear^.X);
+ gY := hwRound(Gear^.Y);
+ for i:= 0 to 4 do
+ begin
+ (*glass:= AddVisualGear(gx+random(7)-3, gy+random(5)-2, vgtEgg);
+ if glass <> nil then
+ begin
+ glass^.Frame:= 2;
+ glass^.Tint:= $41B83ED0 - i * $10081000;
+ glass^.dX:= 1/(10*(random(11)-5));
+ glass^.dY:= -1/(random(4)+5);
+ end;*)
+ glass:= AddVisualGear(gx+random(7)-3, gy+random(7)-3, vgtStraightShot);
+ if glass <> nil then
+ with glass^ do
+ begin
+ Frame:= 2;
+ Tint:= $41B83ED0 - i * $10081000;
+ Angle:= random(360);
+ dx:= 0.0000001;
+ dy:= 0;
+ if random(2) = 0 then
+ dx := -dx;
+ FrameTicks:= 750;
+ State:= ord(sprEgg)
+ end;
+ end;
+ for i:= 0 to 24 do
+ begin
+ dX := AngleCos(i * 2) * ((_0_15*(i div 5))) * (GetRandomf + _1);
+ dY := AngleSin(i * 8) * _0_5 * (GetRandomf + _1);
+ AddGear(gX, gY, gtFlame, gstTmpFlag, dX, dY, 0);
+ AddGear(gX, gY, gtFlame, gstTmpFlag, dX,-dY, 0);
+ AddGear(gX, gY, gtFlame, gstTmpFlag,-dX, dY, 0);
+ AddGear(gX, gY, gtFlame, gstTmpFlag,-dX,-dY, 0);
+ end;
+ DeleteGear(Gear);
+ exit
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+
+procedure doStepCluster(Gear: PGear);
+begin
+ AllInactive := false;
+ doStepFallingGear(Gear);
+ if (Gear^.State and gstCollision) <> 0 then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Timer, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ exit
+ end;
+
+ if (Gear^.Kind = gtMelonPiece)
+ or (Gear^.Kind = gtBall) then
+ CalcRotationDirAngle(Gear)
+ else if (GameTicks and $1F) = 0 then
+ begin
+ if hwRound(Gear^.Y) > cWaterLine then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble)
+ else AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepShell(Gear: PGear);
+begin
+ AllInactive := false;
+ if (GameFlags and gfMoreWind) = 0 then
+ Gear^.dX := Gear^.dX + cWindSpeed;
+ doStepFallingGear(Gear);
+ if (Gear^.State and gstCollision) <> 0 then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ exit
+ end;
+ if (GameTicks and $3F) = 0 then
+ begin
+ if hwRound(Gear^.Y) > cWaterLine then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble)
+ else AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSnowball(Gear: PGear);
+var kick, i: LongInt;
+ particle: PVisualGear;
+ gdX, gdY: hwFloat;
+begin
+ AllInactive := false;
+ if (GameFlags and gfMoreWind) = 0 then
+ Gear^.dX := Gear^.dX + cWindSpeed;
+ gdX := Gear^.dX;
+ gdY := Gear^.dY;
+ doStepFallingGear(Gear);
+ CalcRotationDirAngle(Gear);
+ if (Gear^.State and gstCollision) <> 0 then
+ begin
+ kick:= hwRound((hwAbs(gdX)+hwAbs(gdY)) * _20);
+ Gear^.dX:= gdX;
+ Gear^.dY:= gdY;
+ AmmoShove(Gear, 0, kick);
+ for i:= 15 + kick div 10 downto 0 do
+ begin
+ particle := AddVisualGear(hwRound(Gear^.X) + Random(25), hwRound(Gear^.Y) + Random(25), vgtDust);
+ if particle <> nil then
+ particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480)
+ end;
+ DeleteGear(Gear);
+ exit
+ end;
+ if ((GameTicks and $1F) = 0) and (Random(3) = 0) then
+ begin
+ particle:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtDust);
+ if particle <> nil then
+ particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480)
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSnowflake(Gear: PGear);
+var xx, yy, px, py, rx, ry, lx, ly: LongInt;
+ move, draw, allpx, gun: Boolean;
+ s: PSDL_Surface;
+ p: PLongwordArray;
+ lf: LongWord;
+begin
+inc(Gear^.Pos);
+gun:= (Gear^.State and gstTmpFlag) <> 0;
+move:= false;
+draw:= false;
+if gun then
+ begin
+ Gear^.State:= Gear^.State and (not gstInvisible);
+ doStepFallingGear(Gear);
+ CheckCollision(Gear);
+ if ((Gear^.State and gstCollision) <> 0) or ((Gear^.State and gstMoving) = 0) then
+ draw:= true;
+ xx:= hwRound(Gear^.X);
+ yy:= hwRound(Gear^.Y);
+ if draw and (WorldEdge = weWrap) and ((xx < LongInt(leftX) + 3) or (xx > LongInt(rightX) - 3)) then
+ begin
+ if xx < LongInt(leftX) + 3 then
+ xx:= rightX-3
+ else xx:= leftX+3;
+ Gear^.X:= int2hwFloat(xx)
+ end
+ end
+else if GameTicks and $7 = 0 then
+ begin
+ with Gear^ do
+ begin
+ State:= State and (not gstInvisible);
+ X:= X + cWindSpeed * 3200 + dX;
+ Y:= Y + dY + cGravity * vobFallSpeed * 8; // using same value as flakes to try and get similar results
+ xx:= hwRound(X);
+ yy:= hwRound(Y);
+ if vobVelocity <> 0 then
+ begin
+ DirAngle := DirAngle + (Damage / 1000);
+ if DirAngle < 0 then
+ DirAngle := DirAngle + 360
+ else if 360 < DirAngle then
+ DirAngle := DirAngle - 360;
+ end;
+(*
+We aren't using frametick right now, so just a waste of cycles.
+ inc(Health, 8);
+ if longword(Health) > vobFrameTicks then
+ begin
+ dec(Health, vobFrameTicks);
+ inc(Timer);
+ if Timer = vobFramesCount then
+ Timer:= 0
+ end;
+*)
+ // move back to cloud layer
+ if yy > cWaterLine then
+ move:= true
+ else if (xx > snowRight) or (xx < snowLeft) then
+ move:=true
+ // Solid pixel encountered
+ else if ((yy and LAND_HEIGHT_MASK) = 0) and ((xx and LAND_WIDTH_MASK) = 0) and (Land[yy, xx] <> 0) then
+ begin
+ lf:= Land[yy, xx] and (lfObject or lfBasic or lfIndestructible);
+ if lf = 0 then lf:= lfObject;
+ // If there's room below keep falling
+ if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (Land[yy-1, xx] = 0) then
+ begin
+ X:= X - cWindSpeed * 1600 - dX;
+ end
+ // If there's room below, on the sides, fill the gaps
+ else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx-(1*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx-(1*hwSign(cWindSpeed)))] = 0) then
+ begin
+ X:= X - _0_8 * hwSign(cWindSpeed);
+ Y:= Y - dY - cGravity * vobFallSpeed * 8;
+ end
+ else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx-(2*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx-(2*hwSign(cWindSpeed)))] = 0) then
+ begin
+ X:= X - _0_8 * 2 * hwSign(cWindSpeed);
+ Y:= Y - dY - cGravity * vobFallSpeed * 8;
+ end
+ else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx+(1*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx+(1*hwSign(cWindSpeed)))] = 0) then
+ begin
+ X:= X + _0_8 * hwSign(cWindSpeed);
+ Y:= Y - dY - cGravity * vobFallSpeed * 8;
+ end
+ else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx+(2*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx+(2*hwSign(cWindSpeed)))] = 0) then
+ begin
+ X:= X + _0_8 * 2 * hwSign(cWindSpeed);
+ Y:= Y - dY - cGravity * vobFallSpeed * 8;
+ end
+ // if there's an hog/object below do nothing
+ else if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((Land[yy+1, xx] and $FF) <> 0))
+ then move:=true
+ else draw:= true
+ end
+ end
+ end;
+if draw then
+ with Gear^ do
+ begin
+ // we've collided with land. draw some stuff and get back into the clouds
+ move:= true;
+ if (Pos > 20) and ((CurAmmoGear = nil)
+ or (CurAmmoGear^.Kind <> gtRope)) then
+ begin
+////////////////////////////////// TODO - ASK UNC0RR FOR A GOOD HOME FOR THIS ////////////////////////////////////
+ if not gun then
+ begin
+ dec(yy,3);
+ dec(xx,1)
+ end;
+ s:= SpritesData[sprSnow].Surface;
+ p:= s^.pixels;
+ allpx:= true;
+ for py:= 0 to Pred(s^.h) do
+ begin
+ for px:= 0 to Pred(s^.w) do
+ begin
+ lx:=xx + px; ly:=yy + py;
+ if (ly and LAND_HEIGHT_MASK = 0) and (lx and LAND_WIDTH_MASK = 0) and (Land[ly, lx] and $FF = 0) then
+ begin
+ rx:= lx;
+ ry:= ly;
+ if cReducedQuality and rqBlurryLand <> 0 then
+ begin
+ rx:= rx div 2;ry:= ry div 2;
+ end;
+ if Land[yy + py, xx + px] <= lfAllObjMask then
+ if gun then
+ begin
+ LandDirty[yy div 32, xx div 32]:= 1;
+ if LandPixels[ry, rx] = 0 then
+ Land[ly, lx]:= lfDamaged or lfObject
+ else Land[ly, lx]:= lfDamaged or lfBasic
+ end
+ else Land[ly, lx]:= lf;
+ if gun then
+ LandPixels[ry, rx]:= (ExplosionBorderColor and (not AMask)) or (p^[px] and AMask)
+ else LandPixels[ry, rx]:= addBgColor(LandPixels[ry, rx], p^[px]);
+ end
+ else allpx:= false
+ end;
+ p:= @(p^[s^.pitch shr 2])
+ end;
+
+ // Why is this here. For one thing, there's no test on +1 being safe.
+ //Land[py, px+1]:= lfBasic;
+
+ if allpx then
+ UpdateLandTexture(xx, Pred(s^.h), yy, Pred(s^.w), true)
+ else
+ begin
+ UpdateLandTexture(
+ max(0, min(LAND_WIDTH, xx)),
+ min(LAND_WIDTH - xx, Pred(s^.w)),
+ max(0, min(LAND_WIDTH, yy)),
+ min(LAND_HEIGHT - yy, Pred(s^.h)), false // could this be true without unnecessarily creating blanks?
+ );
+ end;
+////////////////////////////////// TODO - ASK UNC0RR FOR A GOOD HOME FOR THIS ////////////////////////////////////
+ end
+ end;
+
+if move then
+ begin
+ if gun then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+ Gear^.Pos:= 0;
+ Gear^.X:= int2hwFloat(LongInt(GetRandom(snowRight - snowLeft)) + snowLeft);
+ Gear^.Y:= int2hwFloat(LAND_HEIGHT + LongInt(GetRandom(50)) - 1325);
+ Gear^.State:= Gear^.State or gstInvisible;
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepGrave(Gear: PGear);
+begin
+ if (Gear^.Message and gmDestroy) <> 0 then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+
+ AllInactive := false;
+
+ if Gear^.dY.isNegative then
+ if TestCollisionY(Gear, -1) <> 0 then
+ Gear^.dY := _0;
+
+ if not Gear^.dY.isNegative then
+ if TestCollisionY(Gear, 1) <> 0 then
+ begin
+ Gear^.dY := - Gear^.dY * Gear^.Elasticity;
+ if Gear^.dY > - _1div1024 then
+ begin
+ Gear^.Active := false;
+ exit
+ end
+ else if Gear^.dY < - _0_03 then
+ PlaySound(Gear^.ImpactSound)
+ end;
+
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ CheckGearDrowning(Gear);
+ Gear^.dY := Gear^.dY + cGravity
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepBeeWork(Gear: PGear);
+var
+ t: hwFloat;
+ gX,gY,i: LongInt;
+ uw, nuw: boolean;
+ flower: PVisualGear;
+
+begin
+ WorldWrap(Gear);
+ AllInactive := false;
+ gX := hwRound(Gear^.X);
+ gY := hwRound(Gear^.Y);
+ uw := (Gear^.Tag <> 0); // was bee underwater last tick?
+ nuw := (cWaterLine < gy + Gear^.Radius); // is bee underwater now?
+
+ // if water entered or left
+ if nuw <> uw then
+ begin
+ AddVisualGear(gX, cWaterLine, vgtSplash);
+ AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
+ AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
+ AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
+ AddVisualGear(gX - 3 + Random(6), cWaterLine, vgtDroplet);
+ StopSoundChan(Gear^.SoundChannel);
+ if nuw then
+ begin
+ Gear^.SoundChannel := LoopSound(sndBeeWater);
+ Gear^.Tag := 1;
+ end
+ else
+ begin
+ Gear^.SoundChannel := LoopSound(sndBee);
+ Gear^.Tag := 0;
+ end;
+ end;
+
+
+ if Gear^.Timer = 0 then
+ begin
+ // no "fuel"? just fall
+ doStepFallingGear(Gear);
+ // if drowning, stop bee sound
+ if (Gear^.State and gstDrowning) <> 0 then
+ StopSoundChan(Gear^.SoundChannel);
+ end
+ else
+ begin
+ if (GameTicks and $F) = 0 then
+ begin
+ if (GameTicks and $30) = 0 then
+ begin
+ if nuw then
+ AddVisualGear(gX, gY, vgtBubble)
+ else
+ AddVisualGear(gX, gY, vgtBeeTrace);
+ end;
+ Gear^.dX := Gear^.Elasticity * (Gear^.dX + _0_000064 * (Gear^.Target.X - gX));
+ Gear^.dY := Gear^.Elasticity * (Gear^.dY + _0_000064 * (Gear^.Target.Y - gY));
+ // make sure new speed isn't higher than original one (which we stored in Friction variable)
+ t := Gear^.Friction / Distance(Gear^.dX, Gear^.dY);
+ Gear^.dX := Gear^.dX * t;
+ Gear^.dY := Gear^.dY * t;
+ end;
+
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+
+ end;
+
+
+ CheckCollision(Gear);
+ if ((Gear^.State and gstCollision) <> 0) then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+ for i:= 0 to 31 do
+ begin
+ flower:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot);
+ if flower <> nil then
+ with flower^ do
+ begin
+ Scale:= 0.75;
+ dx:= 0.001 * (random(200));
+ dy:= 0.001 * (random(200));
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ FrameTicks:= random(250) + 250;
+ State:= ord(sprTargetBee);
+ end;
+ end;
+ DeleteGear(Gear);
+ end;
+
+ if (Gear^.Timer > 0) then
+ begin
+ dec(Gear^.Timer);
+ if Gear^.Timer = 0 then
+ begin
+ // no need to display remaining time anymore
+ Gear^.RenderTimer:= false;
+ // bee can drown when timer reached 0
+ Gear^.State:= Gear^.State and not gstSubmersible;
+ end;
+ end;
+end;
+
+procedure doStepBee(Gear: PGear);
+begin
+ AllInactive := false;
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ Gear^.dY := Gear^.dY + cGravity;
+ CheckCollision(Gear);
+ if (Gear^.State and gstCollision) <> 0 then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ exit
+ end;
+ dec(Gear^.Timer);
+ if Gear^.Timer = 0 then
+ begin
+ Gear^.Hedgehog^.Gear^.Message:= Gear^.Hedgehog^.Gear^.Message and (not gmAttack);
+ Gear^.Hedgehog^.Gear^.State:= Gear^.Hedgehog^.Gear^.State and (not gstAttacking);
+ AttackBar:= 0;
+
+ Gear^.SoundChannel := LoopSound(sndBee);
+ Gear^.Timer := 5000;
+ // save initial speed in otherwise unused Friction variable
+ Gear^.Friction := Distance(Gear^.dX, Gear^.dY);
+ Gear^.doStep := @doStepBeeWork
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepShotIdle(Gear: PGear);
+begin
+ AllInactive := false;
+ inc(Gear^.Timer);
+ if Gear^.Timer > 75 then
+ begin
+ DeleteGear(Gear);
+ AfterAttack
+ end
+end;
+
+procedure doStepShotgunShot(Gear: PGear);
+var
+ i: LongWord;
+ shell: PVisualGear;
+begin
+ AllInactive := false;
+
+ if ((Gear^.State and gstAnimation) = 0) then
+ begin
+ dec(Gear^.Timer);
+ if Gear^.Timer = 0 then
+ begin
+ PlaySound(sndShotgunFire);
+ shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
+ if shell <> nil then
+ begin
+ shell^.dX := gear^.dX.QWordValue / -17179869184;
+ shell^.dY := gear^.dY.QWordValue / -17179869184;
+ shell^.Frame := 0
+ end;
+ Gear^.State := Gear^.State or gstAnimation
+ end;
+ exit
+ end else
+ if(Gear^.Hedgehog^.Gear = nil) or ((Gear^.Hedgehog^.Gear^.State and gstMoving) <> 0) then
+ begin
+ DeleteGear(Gear);
+ AfterAttack;
+ exit
+ end
+ else
+ inc(Gear^.Timer);
+
+ i := 200;
+ repeat
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ WorldWrap(Gear);
+ CheckCollision(Gear);
+ if (Gear^.State and gstCollision) <> 0 then
+ begin
+ Gear^.X := Gear^.X + Gear^.dX * 8;
+ Gear^.Y := Gear^.Y + Gear^.dY * 8;
+ ShotgunShot(Gear);
+ Gear^.doStep := @doStepShotIdle;
+ exit
+ end;
+
+ CheckGearDrowning(Gear);
+ if (Gear^.State and gstDrowning) <> 0 then
+ begin
+ Gear^.doStep := @doStepShotIdle;
+ exit
+ end;
+ dec(i)
+ until i = 0;
+ if (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0) or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
+ Gear^.doStep := @doStepShotIdle
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure spawnBulletTrail(Bullet: PGear);
+var oX, oY: hwFloat;
+ VGear: PVisualGear;
+begin
+ if Bullet^.PortalCounter = 0 then
+ begin
+ ox:= CurrentHedgehog^.Gear^.X + Int2hwFloat(GetLaunchX(CurrentHedgehog^.CurAmmoType, hwSign(CurrentHedgehog^.Gear^.dX), CurrentHedgehog^.Gear^.Angle));
+ oy:= CurrentHedgehog^.Gear^.Y + Int2hwFloat(GetLaunchY(CurrentHedgehog^.CurAmmoType, CurrentHedgehog^.Gear^.Angle));
+ end
+ else
+ begin
+ ox:= Bullet^.Elasticity;
+ oy:= Bullet^.Friction;
+ end;
+
+ // Bullet trail
+ VGear := AddVisualGear(hwRound(ox), hwRound(oy), vgtLineTrail);
+
+ if VGear <> nil then
+ begin
+ VGear^.X:= hwFloat2Float(ox);
+ VGear^.Y:= hwFloat2Float(oy);
+ VGear^.dX:= hwFloat2Float(Bullet^.X);
+ VGear^.dY:= hwFloat2Float(Bullet^.Y);
+
+ // reached edge of land. assume infinite beam. Extend it way out past camera
+ if (hwRound(Bullet^.X) and LAND_WIDTH_MASK <> 0)
+ or (hwRound(Bullet^.Y) and LAND_HEIGHT_MASK <> 0) then
+ // only extend if not under water
+ if hwRound(Bullet^.Y) < cWaterLine then
+ begin
+ VGear^.dX := VGear^.dX + max(LAND_WIDTH,4096) * (VGear^.dX - VGear^.X);
+ VGear^.dY := VGear^.dY + max(LAND_WIDTH,4096) * (VGear^.dY - VGear^.Y);
+ end;
+
+ VGear^.Timer := 200;
+ end;
+end;
+
+procedure doStepBulletWork(Gear: PGear);
+var
+ i, x, y: LongWord;
+ oX, oY, tX, tY, cX, cY: hwFloat;
+ VGear: PVisualGear;
+begin
+ AllInactive := false;
+ inc(Gear^.Timer);
+ i := 80;
+ oX := Gear^.X;
+ oY := Gear^.Y;
+ repeat
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ tX:= Gear^.X;
+ tY:= Gear^.Y;
+ if (Gear^.PortalCounter < 30) and WorldWrap(Gear) then
+ begin
+ cX:= Gear^.X;
+ cY:= Gear^.Y;
+ Gear^.X:= tX;
+ Gear^.Y:= tY;
+ SpawnBulletTrail(Gear);
+ Gear^.X:= cX;
+ Gear^.Y:= cY;
+ inc(Gear^.PortalCounter);
+ Gear^.Elasticity:= Gear^.X;
+ Gear^.Friction:= Gear^.Y;
+ SpawnBulletTrail(Gear);
+ end;
+ x := hwRound(Gear^.X);
+ y := hwRound(Gear^.Y);
+
+ if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then
+ inc(Gear^.Damage);
+ // let's interrupt before a collision to give portals a chance to catch the bullet
+ if (Gear^.Damage = 1) and (Gear^.Tag = 0) and not(CheckLandValue(x, y, lfLandMask)) then
+ begin
+ Gear^.Tag := 1;
+ Gear^.Damage := 0;
+ Gear^.X := Gear^.X - Gear^.dX;
+ Gear^.Y := Gear^.Y - Gear^.dY;
+ CheckGearDrowning(Gear);
+ break;
+ end
+ else
+ Gear^.Tag := 0;
+
+ if Gear^.Damage > 5 then
+ if Gear^.AmmoType = amDEagle then
+ AmmoShove(Gear, 7, 20)
+ else
+ AmmoShove(Gear, Gear^.Timer, 20);
+ CheckGearDrowning(Gear);
+ dec(i)
+ until (i = 0) or (Gear^.Damage > Gear^.Health) or ((Gear^.State and gstDrowning) <> 0);
+
+ if Gear^.Damage > 0 then
+ begin
+ DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 82 - i, 1);
+ dec(Gear^.Health, Gear^.Damage);
+ Gear^.Damage := 0
+ end;
+ if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and ((not SuddenDeathDmg and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF))) then
+ begin
+ for i:=(Gear^.Health - Gear^.Damage) * 4 downto 0 do
+ begin
+ if Random(6) = 0 then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble);
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ end;
+ end;
+
+ if (Gear^.Health <= 0)
+ or (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0)
+ or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
+ begin
+ if (Gear^.Kind = gtSniperRifleShot) and ((GameFlags and gfLaserSight) = 0) then
+ cLaserSighting := false;
+ if (Ammoz[Gear^.AmmoType].Ammo.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and ((GameFlags and gfArtillery) = 0) then
+ cArtillery := false;
+
+ // Bullet Hit
+ if (hwRound(Gear^.X) and LAND_WIDTH_MASK = 0) and (hwRound(Gear^.Y) and LAND_HEIGHT_MASK = 0) then
+ begin
+ VGear := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBulletHit);
+ if VGear <> nil then
+ begin
+ VGear^.Angle := DxDy2Angle(-Gear^.dX, Gear^.dY);
+ end;
+ end;
+
+ spawnBulletTrail(Gear);
+ Gear^.doStep := @doStepShotIdle
+ end;
+end;
+
+procedure doStepDEagleShot(Gear: PGear);
+begin
+ PlaySound(sndGun);
+ // add 3 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just plain old weird angles
+ Gear^.X := Gear^.X + Gear^.dX * 3;
+ Gear^.Y := Gear^.Y + Gear^.dY * 3;
+ Gear^.doStep := @doStepBulletWork
+end;
+
+procedure doStepSniperRifleShot(Gear: PGear);
+var
+ HHGear: PGear;
+ shell: PVisualGear;
+begin
+ cArtillery := true;
+ HHGear := Gear^.Hedgehog^.Gear;
+ HHGear^.State := HHGear^.State or gstNotKickable;
+ HedgehogChAngle(HHGear);
+ if not cLaserSighting then
+ // game does not have default laser sight. turn it on and give them a chance to aim
+ begin
+ cLaserSighting := true;
+ HHGear^.Message := 0;
+ if (HHGear^.Angle >= 32) then
+ dec(HHGear^.Angle,32)
+ end;
+
+ if (HHGear^.Message and gmAttack) <> 0 then
+ begin
+ shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
+ if shell <> nil then
+ begin
+ shell^.dX := gear^.dX.QWordValue / -8589934592;
+ shell^.dY := gear^.dY.QWordValue / -8589934592;
+ shell^.Frame := 1
+ end;
+ Gear^.State := Gear^.State or gstAnimation;
+ Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5;
+ Gear^.dY := -AngleCos(HHGear^.Angle) * _0_5;
+ PlaySound(sndGun);
+ // add 3 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just weird angles
+ Gear^.X := Gear^.X + Gear^.dX * 3;
+ Gear^.Y := Gear^.Y + Gear^.dY * 3;
+ Gear^.doStep := @doStepBulletWork;
+ end
+ else
+ if (GameTicks mod 32) = 0 then
+ if (GameTicks mod 4096) < 2048 then
+ begin
+ if (HHGear^.Angle + 1 <= cMaxAngle) then
+ inc(HHGear^.Angle)
+ end
+ else
+ if (HHGear^.Angle >= 1) then
+ dec(HHGear^.Angle);
+
+ if (TurnTimeLeft > 0) then
+ dec(TurnTimeLeft)
+ else
+ begin
+ DeleteGear(Gear);
+ AfterAttack
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepActionTimer(Gear: PGear);
+begin
+dec(Gear^.Timer);
+case Gear^.Kind of
+ gtATStartGame:
+ begin
+ AllInactive := false;
+ if Gear^.Timer = 0 then
+ begin
+ AddCaption(trmsg[sidStartFight], cWhiteColor, capgrpGameState);
+ end
+ end;
+ gtATFinishGame:
+ begin
+ AllInactive := false;
+ if Gear^.Timer = 1000 then
+ begin
+ ScreenFade := sfToBlack;
+ ScreenFadeValue := 0;
+ ScreenFadeSpeed := 1;
+ end;
+ if Gear^.Timer = 0 then
+ begin
+ SendIPC(_S'N');
+ SendIPC(_S'q');
+ GameState := gsExit
+ end
+ end;
+ end;
+if Gear^.Timer = 0 then
+ DeleteGear(Gear)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepPickHammerWork(Gear: PGear);
+var
+ i, ei, x, y: LongInt;
+ HHGear: PGear;
+begin
+ AllInactive := false;
+ WorldWrap(Gear);
+ HHGear := Gear^.Hedgehog^.Gear;
+ dec(Gear^.Timer);
+ if ((GameFlags and gfInfAttack) <> 0) and (TurnTimeLeft > 0) then
+ dec(TurnTimeLeft);
+ if (TurnTimeLeft = 0) or (Gear^.Timer = 0)
+ or((Gear^.Message and gmDestroy) <> 0)
+ or((HHGear^.State and gstHHDriven) =0) then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ DeleteGear(Gear);
+ AfterAttack;
+ doStepHedgehogMoving(HHGear); // for gfInfAttack
+ exit
+ end;
+
+ x:= hwRound(Gear^.X);
+ y:= hwRound(Gear^.Y);
+ if (Gear^.Timer mod 33) = 0 then
+ begin
+ HHGear^.State := HHGear^.State or gstNoDamage;
+ doMakeExplosion(x, y + 7, 6, Gear^.Hedgehog, EXPLDontDraw);
+ HHGear^.State := HHGear^.State and (not gstNoDamage)
+ end;
+
+ if (Gear^.Timer mod 47) = 0 then
+ begin
+ // ok. this was an attempt to turn off dust if not actually drilling land. I have no idea why it isn't working as expected
+ if (( (y + 12) and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y + 12, x] > 255) then
+ for i:= 0 to 1 do
+ AddVisualGear(x - 5 + Random(10), y + 12, vgtDust);
+
+ i := x - Gear^.Radius - LongInt(GetRandom(2));
+ ei := x + Gear^.Radius + LongInt(GetRandom(2));
+ while i <= ei do
+ begin
+ DrawExplosion(i, y + 3, 3);
+ inc(i, 1)
+ end;
+
+ if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9), lfIndestructible) then
+ begin
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + _1_9;
+ end;
+ SetAllHHToActive;
+ end;
+ if TestCollisionYwithGear(Gear, 1) <> 0 then
+ begin
+ Gear^.dY := _0;
+ SetLittle(HHGear^.dX);
+ HHGear^.dY := _0;
+ end
+ else
+ begin
+ if CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y + Gear^.dY + cGravity), lfLandMask) then
+ begin
+ Gear^.dY := Gear^.dY + cGravity;
+ Gear^.Y := Gear^.Y + Gear^.dY
+ end;
+ if hwRound(Gear^.Y) > cWaterLine then
+ Gear^.Timer := 1
+ end;
+
+ Gear^.X := Gear^.X + HHGear^.dX;
+ if CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y)-cHHRadius, lfLandMask) then
+ begin
+ HHGear^.X := Gear^.X;
+ HHGear^.Y := Gear^.Y - int2hwFloat(cHHRadius)
+ end;
+
+ if (Gear^.Message and gmAttack) <> 0 then
+ if (Gear^.State and gsttmpFlag) <> 0 then
+ Gear^.Timer := 1
+ else //there would be a mistake.
+ else
+ if (Gear^.State and gsttmpFlag) = 0 then
+ Gear^.State := Gear^.State or gsttmpFlag;
+ if ((Gear^.Message and gmLeft) <> 0) then
+ Gear^.dX := - _0_3
+ else
+ if ((Gear^.Message and gmRight) <> 0) then
+ Gear^.dX := _0_3
+ else Gear^.dX := _0;
+end;
+
+procedure doStepPickHammer(Gear: PGear);
+var
+ i, y: LongInt;
+ ar: TRangeArray;
+ HHGear: PGear;
+begin
+ i := 0;
+ HHGear := Gear^.Hedgehog^.Gear;
+
+ y := hwRound(Gear^.Y) - cHHRadius * 2;
+ while y < hwRound(Gear^.Y) do
+ begin
+ ar[i].Left := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
+ ar[i].Right := hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
+ inc(y, 2);
+ inc(i)
+ end;
+
+ DrawHLinesExplosions(@ar, 3, hwRound(Gear^.Y) - cHHRadius * 2, 2, Pred(i));
+ Gear^.dY := HHGear^.dY;
+ DeleteCI(HHGear);
+
+ Gear^.SoundChannel := LoopSound(sndPickhammer);
+ doStepPickHammerWork(Gear);
+ Gear^.doStep := @doStepPickHammerWork
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+var
+ BTPrevAngle, BTSteps: LongInt;
+
+procedure doStepBlowTorchWork(Gear: PGear);
+var
+ HHGear: PGear;
+ b: boolean;
+ prevX: LongInt;
+begin
+ AllInactive := false;
+ WorldWrap(Gear);
+ dec(Gear^.Timer);
+ if ((GameFlags and gfInfAttack) <> 0) and (TurnTimeLeft > 0) then
+ dec(TurnTimeLeft);
+
+ if Gear^.Hedgehog^.Gear = nil then
+ begin
+ DeleteGear(Gear);
+ AfterAttack;
+ exit
+ end;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+
+ HedgehogChAngle(HHGear);
+
+ b := false;
+
+ if abs(LongInt(HHGear^.Angle) - BTPrevAngle) > 7 then
+ begin
+ Gear^.dX := SignAs(AngleSin(HHGear^.Angle) * _0_5, Gear^.dX);
+ Gear^.dY := AngleCos(HHGear^.Angle) * ( - _0_5);
+ BTPrevAngle := HHGear^.Angle;
+ b := true
+ end;
+
+ if ((HHGear^.State and gstMoving) <> 0) then
+ begin
+ doStepHedgehogMoving(HHGear);
+ if (HHGear^.State and gstHHDriven) = 0 then
+ Gear^.Timer := 0
+ end;
+
+ if Gear^.Timer mod cHHStepTicks = 0 then
+ begin
+ b := true;
+ if Gear^.dX.isNegative then
+ HHGear^.Message := (HHGear^.Message and (gmAttack or gmUp or gmDown)) or gmLeft
+ else
+ HHGear^.Message := (HHGear^.Message and (gmAttack or gmUp or gmDown)) or gmRight;
+
+ if ((HHGear^.State and gstMoving) = 0) then
+ begin
+ HHGear^.State := HHGear^.State and (not gstAttacking);
+ prevX := hwRound(HHGear^.X);
+
+ // why the call to HedgehogStep then a further increment of X?
+ if (prevX = hwRound(HHGear^.X)) and
+ CheckLandValue(hwRound(HHGear^.X + SignAs(_6, HHGear^.dX)), hwRound(HHGear^.Y),
+ lfIndestructible) then HedgehogStep(HHGear);
+
+ if (prevX = hwRound(HHGear^.X)) and
+ CheckLandValue(hwRound(HHGear^.X + SignAs(_6, HHGear^.dX)), hwRound(HHGear^.Y),
+ lfIndestructible) then HHGear^.X := HHGear^.X + SignAs(_1, HHGear^.dX);
+ HHGear^.State := HHGear^.State or gstAttacking
+ end;
+
+ inc(BTSteps);
+ if BTSteps = 7 then
+ begin
+ BTSteps := 0;
+ if CheckLandValue(hwRound(HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC) + SignAs(_6,Gear^.dX)), hwRound(HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC)),lfIndestructible) then
+ begin
+ Gear^.X := HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC);
+ Gear^.Y := HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC);
+ end;
+ HHGear^.State := HHGear^.State or gstNoDamage;
+ AmmoShove(Gear, 2, 15);
+ HHGear^.State := HHGear^.State and (not gstNoDamage)
+ end;
+ end;
+
+ if b then
+ begin
+ DrawTunnel(HHGear^.X + Gear^.dX * cHHRadius,
+ HHGear^.Y + Gear^.dY * cHHRadius - _1 -
+ ((hwAbs(Gear^.dX) / (hwAbs(Gear^.dX) + hwAbs(Gear^.dY))) * _0_5 * 7),
+ Gear^.dX, Gear^.dY,
+ cHHStepTicks, cHHRadius * 2 + 7);
+ end;
+
+ if (TurnTimeLeft = 0) or (Gear^.Timer = 0)
+ or ((HHGear^.Message and gmAttack) <> 0) then
+ begin
+ HHGear^.Message := 0;
+ HHGear^.State := HHGear^.State and (not gstNotKickable);
+ DeleteGear(Gear);
+ AfterAttack
+ end
+end;
+
+procedure doStepBlowTorch(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ BTPrevAngle := High(LongInt);
+ BTSteps := 0;
+ HHGear := Gear^.Hedgehog^.Gear;
+ HedgehogChAngle(HHGear);
+ Gear^.dX := SignAs(AngleSin(HHGear^.Angle) * _0_5, Gear^.dX);
+ Gear^.dY := AngleCos(HHGear^.Angle) * ( - _0_5);
+ DrawTunnel(HHGear^.X,
+ HHGear^.Y + Gear^.dY * cHHRadius - _1 -
+ ((hwAbs(Gear^.dX) / (hwAbs(Gear^.dX) + hwAbs(Gear^.dY))) * _0_5 * 7),
+ Gear^.dX, Gear^.dY,
+ cHHStepTicks, cHHRadius * 2 + 7);
+ HHGear^.Message := 0;
+ HHGear^.State := HHGear^.State or gstNotKickable;
+ Gear^.doStep := @doStepBlowTorchWork
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepMine(Gear: PGear);
+var vg: PVisualGear;
+ dxdy: hwFloat;
+begin
+ if Gear^.Health = 0 then dxdy:= hwAbs(Gear^.dX)+hwAbs(Gear^.dY);
+ if (Gear^.State and gstMoving) <> 0 then
+ begin
+ DeleteCI(Gear);
+ doStepFallingGear(Gear);
+ if (Gear^.State and gstMoving) = 0 then
+ begin
+ AddCI(Gear);
+ Gear^.dX := _0;
+ Gear^.dY := _0
+ end;
+ CalcRotationDirAngle(Gear);
+ AllInactive := false
+ end
+ else if (GameTicks and $3F) = 25 then
+ doStepFallingGear(Gear);
+ if (Gear^.Health = 0) then
+ begin
+ if (dxdy > _0_4) and (Gear^.State and gstCollision <> 0) then
+ inc(Gear^.Damage, hwRound(dxdy * _50));
+
+ if ((GameTicks and $FF) = 0) and (Gear^.Damage > random(30)) then
+ begin
+ vg:= AddVisualGear(hwRound(Gear^.X) - 4 + Random(8), hwRound(Gear^.Y) - 4 - Random(4), vgtSmoke);
+ if vg <> nil then
+ vg^.Scale:= 0.5
+ end;
+
+ if (Gear^.Damage > 35) then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ exit
+ end
+ end;
+
+ if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
+ if ((Gear^.State and gstAttacking) = 0) then
+ begin
+ if ((GameTicks and $1F) = 0) then
+ if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then
+ Gear^.State := Gear^.State or gstAttacking
+ end
+ else // gstAttacking <> 0
+ begin
+ AllInactive := false;
+ if (Gear^.Timer and $FF) = 0 then
+ PlaySound(sndMineTick);
+ if Gear^.Timer = 0 then
+ begin
+ if ((Gear^.State and gstWait) <> 0)
+ or (cMineDudPercent = 0)
+ or (getRandom(100) > cMineDudPercent) then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear)
+ end
+ else
+ begin
+ vg:= AddVisualGear(hwRound(Gear^.X) - 4 + Random(8), hwRound(Gear^.Y) - 4 - Random(4), vgtSmoke);
+ if vg <> nil then
+ vg^.Scale:= 0.5;
+ PlaySound(sndVaporize);
+ Gear^.Health := 0;
+ Gear^.Damage := 0;
+ Gear^.State := Gear^.State and (not gstAttacking)
+ end;
+ exit
+ end;
+ dec(Gear^.Timer);
+ end
+ else // gsttmpFlag = 0
+ if (TurnTimeLeft = 0)
+ or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime))
+ or (Gear^.Hedgehog^.Gear = nil) then
+ Gear^.State := Gear^.State or gsttmpFlag;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSMine(Gear: PGear);
+ var land: Word;
+begin
+ // TODO: do real calculation?
+ land:= TestCollisionXwithGear(Gear, 2);
+ if land = 0 then land:= TestCollisionYwithGear(Gear,-2);
+ if land = 0 then land:= TestCollisionXwithGear(Gear,-2);
+ if land = 0 then land:= TestCollisionYwithGear(Gear, 2);
+ if (land <> 0) and (land and lfBouncy = 0) then
+ begin
+ if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
+ begin
+ PlaySound(sndRopeAttach);
+ Gear^.dX:= _0;
+ Gear^.dY:= _0;
+ AddCI(Gear);
+ end;
+ end
+ else
+ begin
+ DeleteCI(Gear);
+ doStepFallingGear(Gear);
+ AllInactive := false;
+ CalcRotationDirAngle(Gear);
+ end;
+
+ if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
+ begin
+ if ((Gear^.State and gstAttacking) = 0) then
+ begin
+ if ((GameTicks and $1F) = 0) then
+ if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then
+ Gear^.State := Gear^.State or gstAttacking
+ end
+ else // gstAttacking <> 0
+ begin
+ AllInactive := false;
+ if Gear^.Timer = 0 then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ exit
+ end
+ else
+ if (Gear^.Timer and $FF) = 0 then
+ PlaySound(sndMineTick);
+ dec(Gear^.Timer);
+ end
+ end
+ else // gsttmpFlag = 0
+ if ((GameFlags and gfInfAttack = 0) and ((TurnTimeLeft = 0) or (Gear^.Hedgehog^.Gear = nil)))
+ or ((GameFlags and gfInfAttack <> 0) and (GameTicks > Gear^.FlightTime)) then
+ Gear^.State := Gear^.State or gsttmpFlag;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepDynamite(Gear: PGear);
+begin
+ doStepFallingGear(Gear);
+ AllInactive := false;
+ if Gear^.Timer mod 166 = 0 then
+ inc(Gear^.Tag);
+ if Gear^.Timer = 1000 then // might need better timing
+ makeHogsWorry(Gear^.X, Gear^.Y, 75);
+ if Gear^.Timer = 0 then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 75, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ exit
+ end;
+ dec(Gear^.Timer);
+end;
+
+///////////////////////////////////////////////////////////////////////////////
+
+procedure doStepRollingBarrel(Gear: PGear);
+var
+ i: LongInt;
+ particle: PVisualGear;
+ dxdy: hwFloat;
+begin
+ if (Gear^.dY.QWordValue = 0) and (Gear^.dY.QWordValue = 0) and (TestCollisionYwithGear(Gear, 1) = 0) then
+ SetLittle(Gear^.dY);
+ Gear^.State := Gear^.State or gstAnimation;
+ if Gear^.Health < cBarrelHealth then Gear^.State:= Gear^.State and not gstFrozen;
+
+ if ((Gear^.dX.QWordValue <> 0)
+ or (Gear^.dY.QWordValue <> 0)) then
+ begin
+ DeleteCI(Gear);
+ AllInactive := false;
+ dxdy:= hwAbs(Gear^.dX)+hwAbs(Gear^.dY);
+ doStepFallingGear(Gear);
+ if (Gear^.State and gstCollision <> 0) and(dxdy > _0_4) then
+ begin
+ if (TestCollisionYwithGear(Gear, 1) <> 0) then
+ begin
+ Gear^.State := Gear^.State or gsttmpFlag;
+ for i:= min(12, hwRound(dxdy*_10)) downto 0 do
+ begin
+ particle := AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12,vgtDust);
+ if particle <> nil then
+ particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480)
+ end
+ end;
+ inc(Gear^.Damage, hwRound(dxdy * _50))
+ end;
+ CalcRotationDirAngle(Gear);
+ //CheckGearDrowning(Gear)
+ end
+ else
+ begin
+ Gear^.State := Gear^.State or gsttmpFlag;
+ AddCI(Gear)
+ end;
+
+(*
+Attempt to make a barrel knock itself over an edge. Would need more checks to avoid issues like burn damage
+ begin
+ x:= hwRound(Gear^.X);
+ y:= hwRound(Gear^.Y);
+ if (((y+1) and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
+ if (Land[y+1, x] = 0) then
+ begin
+ if (((y+1) and LAND_HEIGHT_MASK) = 0) and (((x+Gear^.Radius-2) and LAND_WIDTH_MASK) = 0) and (Land[y+1, x+Gear^.Radius-2] = 0) then
+ Gear^.dX:= -_0_08
+ else if (((y+1 and LAND_HEIGHT_MASK)) = 0) and (((x-(Gear^.Radius-2)) and LAND_WIDTH_MASK) = 0) and (Land[y+1, x-(Gear^.Radius-2)] = 0) then
+ Gear^.dX:= _0_08;
+ end;
+ if Gear^.dX.QWordValue = 0 then AddCI(Gear)
+ end; *)
+
+ if not Gear^.dY.isNegative and (Gear^.dY < _0_001) and (TestCollisionYwithGear(Gear, 1) <> 0) then
+ Gear^.dY := _0;
+ if hwAbs(Gear^.dX) < _0_001 then
+ Gear^.dX := _0;
+
+ if (Gear^.Health > 0) and ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
+ if (cBarrelHealth div Gear^.Health) > 2 then
+ AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
+ else
+ AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
+ dec(Gear^.Health, Gear^.Damage);
+ Gear^.Damage := 0;
+ if Gear^.Health <= 0 then
+ doStepCase(Gear);
+end;
+
+procedure doStepCase(Gear: PGear);
+var
+ i, x, y: LongInt;
+ k: TGearType;
+ dX, dY: HWFloat;
+ hog: PHedgehog;
+ sparkles: PVisualGear;
+ gi: PGear;
+begin
+ k := Gear^.Kind;
+
+ if (Gear^.Message and gmDestroy) > 0 then
+ begin
+ DeleteGear(Gear);
+ FreeActionsList;
+ SetAllToActive;
+ // something (hh, mine, etc...) could be on top of the case
+ with CurrentHedgehog^ do
+ if Gear <> nil then
+ Gear^.Message := Gear^.Message and (not (gmLJump or gmHJump));
+ exit
+ end;
+ if (k = gtExplosives) and (Gear^.Health < cBarrelHealth) then Gear^.State:= Gear^.State and not gstFrozen;
+
+ if ((k <> gtExplosives) and (Gear^.Damage > 0)) or ((k = gtExplosives) and (Gear^.Health<=0)) then
+ begin
+ x := hwRound(Gear^.X);
+ y := hwRound(Gear^.Y);
+ hog:= Gear^.Hedgehog;
+
+ DeleteGear(Gear);
+ // <-- delete gear!
+
+ if k = gtCase then
+ begin
+ doMakeExplosion(x, y, 25, hog, EXPLAutoSound);
+ for i:= 0 to 63 do
+ AddGear(x, y, gtFlame, 0, _0, _0, 0);
+ end
+ else if k = gtExplosives then
+ begin
+ doMakeExplosion(x, y, 75, hog, EXPLAutoSound);
+ for i:= 0 to 31 do
+ begin
+ dX := AngleCos(i * 64) * _0_5 * (getrandomf + _1);
+ dY := AngleSin(i * 64) * _0_5 * (getrandomf + _1);
+ AddGear(x, y, gtFlame, 0, dX, dY, 0);
+ AddGear(x, y, gtFlame, gstTmpFlag, -dX, -dY, 0);
+ end
+ end;
+ exit
+ end;
+
+ if k = gtExplosives then
+ begin
+ //if V > _0_03 then Gear^.State:= Gear^.State or gstAnimation;
+ if (hwAbs(Gear^.dX) > _0_15) or ((hwAbs(Gear^.dY) > _0_15) and (hwAbs(Gear^.dX) > _0_02)) then
+ begin
+ Gear^.doStep := @doStepRollingBarrel;
+ exit;
+ end
+ else Gear^.dX:= _0;
+
+ if ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
+ if (cBarrelHealth div Gear^.Health) > 2 then
+ AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
+ else
+ AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmokeWhite);
+ dec(Gear^.Health, Gear^.Damage);
+ Gear^.Damage := 0;
+ end
+ else
+ begin
+ if (Gear^.Pos <> posCaseHealth) and (GameTicks and $1FFF = 0) then // stir 'em up periodically
+ begin
+ gi := GearsList;
+ while gi <> nil do
+ begin
+ if gi^.Kind = gtGenericFaller then
+ begin
+ gi^.Active:= true;
+ gi^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
+ gi^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
+ gi^.dX:= _90-(GetRandomf*_360);
+ gi^.dY:= _90-(GetRandomf*_360)
+ end;
+ gi := gi^.NextGear
+ end
+ end;
+
+ if Gear^.Timer = 500 then
+ begin
+(* Can't make sparkles team coloured without working out what the next team is going to be. This should be solved, really, since it also screws up
+ voices. Reinforcements voices is heard for active team, not team-to-be. Either that or change crate spawn from end of turn to start, although that
+ has its own complexities. *)
+ // Abuse a couple of gear values to track origin
+ Gear^.Angle:= hwRound(Gear^.Y);
+ Gear^.Tag:= random(2);
+ inc(Gear^.Timer)
+ end;
+ if Gear^.Timer < 1833 then inc(Gear^.Timer);
+ if Gear^.Timer = 1000 then
+ begin
+ sparkles:= AddVisualGear(hwRound(Gear^.X), Gear^.Angle, vgtDust, 1);
+ if sparkles <> nil then
+ begin
+ sparkles^.dX:= 0;
+ sparkles^.dY:= 0;
+ sparkles^.Angle:= 270;
+ if Gear^.Tag = 1 then
+ sparkles^.Tint:= $3744D7FF
+ else sparkles^.Tint:= $FAB22CFF
+ end;
+ end;
+ if Gear^.Timer < 1000 then
+ begin
+ AllInactive:= false;
+ exit
+ end
+ end;
+
+
+ if (Gear^.dY.QWordValue <> 0)
+ or (TestCollisionYwithGear(Gear, 1) = 0) then
+ begin
+ AllInactive := false;
+
+ Gear^.dY := Gear^.dY + cGravity;
+
+ if ((not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0)) or
+ (Gear^.dY.isNegative and (TestCollisionYwithGear(Gear, -1) <> 0)) then
+ Gear^.dY := _0
+ else Gear^.Y := Gear^.Y + Gear^.dY;
+
+ if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then
+ SetAllHHToActive(false);
+
+ if (not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0) then
+ begin
+ if (Gear^.dY > _0_2) and (k = gtExplosives) then
+ inc(Gear^.Damage, hwRound(Gear^.dY * _70));
+
+ if Gear^.dY > _0_2 then
+ for i:= min(12, hwRound(Gear^.dY*_10)) downto 0 do
+ AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
+
+ Gear^.dY := - Gear^.dY * Gear^.Elasticity;
+ if Gear^.dY > - _0_001 then
+ Gear^.dY := _0
+ else if Gear^.dY < - _0_03 then
+ PlaySound(Gear^.ImpactSound);
+ end;
+ //if Gear^.dY > - _0_001 then Gear^.dY:= _0
+ CheckGearDrowning(Gear);
+ end;
+
+ if (Gear^.dY.QWordValue = 0) then
+ AddCI(Gear)
+ else if (Gear^.dY.QWordValue <> 0) then
+ DeleteCI(Gear)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+
+procedure doStepTarget(Gear: PGear);
+begin
+ if (Gear^.Timer = 0) and (Gear^.Tag = 0) then
+ begin
+ PlaySound(sndWarp);
+ // workaround: save spawn Y for doStepCase (which is a mess atm)
+ Gear^.Angle:= hwRound(Gear^.Y);
+ end;
+
+ if (Gear^.Tag = 0) and (Gear^.Timer < 1000) then
+ inc(Gear^.Timer)
+ else if Gear^.Tag = 1 then
+ Gear^.Tag := 2
+ else if Gear^.Tag = 2 then
+ if Gear^.Timer > 0 then
+ dec(Gear^.Timer)
+ else
+ begin
+ DeleteGear(Gear);
+ exit;
+ end;
+
+ doStepCase(Gear)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepIdle(Gear: PGear);
+begin
+ AllInactive := false;
+ dec(Gear^.Timer);
+ if Gear^.Timer = 0 then
+ begin
+ DeleteGear(Gear);
+ AfterAttack
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepShover(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+ HHGear^.State := HHGear^.State or gstNoDamage;
+ DeleteCI(HHGear);
+
+ AmmoShove(Gear, 30, 115);
+
+ HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
+ Gear^.Timer := 250;
+ Gear^.doStep := @doStepIdle
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepWhip(Gear: PGear);
+var
+ HHGear: PGear;
+ i: LongInt;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+ HHGear^.State := HHGear^.State or gstNoDamage;
+ DeleteCI(HHGear);
+
+ for i:= 0 to 3 do
+ begin
+ AddVisualGear(hwRound(Gear^.X) + hwSign(Gear^.dX) * (10 + 6 * i), hwRound(Gear^.Y) + 12 + Random(6), vgtDust);
+ AmmoShove(Gear, 30, 25);
+ Gear^.X := Gear^.X + Gear^.dX * 5
+ end;
+
+ HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
+
+ Gear^.Timer := 250;
+ Gear^.doStep := @doStepIdle
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepFlame(Gear: PGear);
+var
+ gX,gY,i: LongInt;
+ sticky: Boolean;
+ vgt: PVisualGear;
+ tdX,tdY: HWFloat;
+ landPixel: Word;
+begin
+ WorldWrap(Gear);
+ sticky:= (Gear^.State and gsttmpFlag) <> 0;
+ if not sticky then AllInactive := false;
+
+ landPixel:= TestCollisionYwithGear(Gear, 1);
+ if landPixel = 0 then
+ begin
+ AllInactive := false;
+
+ if ((GameTicks mod 100) = 0) then
+ begin
+ vgt:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFire, gstTmpFlag);
+ if vgt <> nil then
+ begin
+ vgt^.dx:= 0;
+ vgt^.dy:= 0;
+ vgt^.FrameTicks:= 1800 div (Gear^.Tag mod 3 + 2);
+ end;
+ end;
+
+
+ if Gear^.dX.QWordValue > _0_01.QWordValue then
+ Gear^.dX := Gear^.dX * _0_995;
+
+ Gear^.dY := Gear^.dY + cGravity;
+ // if sticky then Gear^.dY := Gear^.dY + cGravity;
+
+ if Gear^.dY.QWordValue > _0_2.QWordValue then
+ Gear^.dY := Gear^.dY * _0_995;
+
+ //if sticky then Gear^.X := Gear^.X + Gear^.dX else
+ Gear^.X := Gear^.X + Gear^.dX + cWindSpeed * 640;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+
+ if (hwRound(Gear^.Y) > cWaterLine) then
+ begin
+ gX := hwRound(Gear^.X);
+ for i:= 0 to 3 do
+ AddVisualGear(gX - 16 + Random(32), cWaterLine - 16 + Random(16), vgtSteam);
+ PlaySound(sndVaporize);
+ DeleteGear(Gear);
+ exit
+ end
+ end
+ else
+ begin
+ if (Gear^.Timer = 1) and (GameTicks and $3 = 0) then
+ begin
+ Gear^.Y:= Gear^.Y+_6;
+ if (landPixel and lfIce <> 0) or (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
+ begin
+ gX := hwRound(Gear^.X);
+ gY := hwRound(Gear^.Y)-6;
+ DrawExplosion(gX, gY, 4);
+ PlaySound(sndVaporize);
+ AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSteam);
+ DeleteGear(Gear);
+ exit
+ end;
+ Gear^.Y:= Gear^.Y-_6
+ end;
+ if sticky and (GameTicks and $F = 0) then
+ begin
+ Gear^.Radius := 7;
+ tdX:= Gear^.dX;
+ tdY:= Gear^.dY;
+ Gear^.dX.QWordValue:= 120000000;
+ Gear^.dY.QWordValue:= 429496730;
+ Gear^.dX.isNegative:= getrandom(2)<>1;
+ Gear^.dY.isNegative:= true;
+ AmmoShove(Gear, 2, 125);
+ Gear^.dX:= tdX;
+ Gear^.dY:= tdY;
+ Gear^.Radius := 1
+ end;
+ if Gear^.Timer > 0 then
+ begin
+ dec(Gear^.Timer);
+ inc(Gear^.Damage)
+ end
+ else
+ begin
+ gX := hwRound(Gear^.X);
+ gY := hwRound(Gear^.Y);
+ // Standard fire
+ if not sticky then
+ begin
+ if ((GameTicks and $1) = 0) then
+ begin
+ Gear^.Radius := 7;
+ tdX:= Gear^.dX;
+ tdY:= Gear^.dY;
+ Gear^.dX.QWordValue:= 214748365;
+ Gear^.dY.QWordValue:= 429496730;
+ Gear^.dX.isNegative:= getrandom(2)<>1;
+ Gear^.dY.isNegative:= true;
+ AmmoShove(Gear, 6, 100);
+ Gear^.dX:= tdX;
+ Gear^.dY:= tdY;
+ Gear^.Radius := 1;
+ end
+ else if ((GameTicks and $3) = 3) then
+ doMakeExplosion(gX, gY, 8, Gear^.Hedgehog, 0);//, EXPLNoDamage);
+ //DrawExplosion(gX, gY, 4);
+
+ if ((GameTicks and $7) = 0) and (Random(2) = 0) then
+ for i:= Random(2) downto 0 do
+ AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
+
+ if Gear^.Health > 0 then
+ dec(Gear^.Health);
+ Gear^.Timer := 450 - Gear^.Tag * 8 + LongInt(GetRandom(2))
+ end
+ else
+ begin
+ // Modified fire
+ if ((GameTicks and $7FF) = 0) and ((GameFlags and gfSolidLand) = 0) then
+ begin
+ DrawExplosion(gX, gY, 4);
+
+ for i:= Random(3) downto 0 do
+ AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
+ end;
+
+// This one is interesting. I think I understand the purpose, but I wonder if a bit more fuzzy of kicking could be done with getrandom.
+ Gear^.Timer := 100 - Gear^.Tag * 3 + LongInt(GetRandom(2));
+ if (Gear^.Damage > 3000+Gear^.Tag*1500) then
+ Gear^.Health := 0
+ end
+ end
+ end;
+ if Gear^.Health = 0 then
+ begin
+ gX := hwRound(Gear^.X);
+ gY := hwRound(Gear^.Y);
+ if not sticky then
+ begin
+ if ((GameTicks and $3) = 0) and (Random(1) = 0) then
+ for i:= Random(2) downto 0 do
+ AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
+ end
+ else
+ for i:= Random(3) downto 0 do
+ AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
+
+ DeleteGear(Gear)
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepFirePunchWork(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ AllInactive := false;
+ if ((Gear^.Message and gmDestroy) <> 0) then
+ begin
+ DeleteGear(Gear);
+ AfterAttack;
+ exit
+ end;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+ if hwRound(HHGear^.Y) <= Gear^.Tag - 2 then
+ begin
+ Gear^.Tag := hwRound(HHGear^.Y);
+ DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y - _1, _0_5, _0, cHHRadius * 4, 2);
+ HHGear^.State := HHGear^.State or gstNoDamage;
+ Gear^.Y := HHGear^.Y;
+ AmmoShove(Gear, 30, 40);
+ HHGear^.State := HHGear^.State and (not gstNoDamage)
+ end;
+
+ HHGear^.dY := HHGear^.dY + cGravity;
+ if Gear^.Timer > 0 then dec(Gear^.Timer);
+ if not (HHGear^.dY.isNegative) or (Gear^.Timer = 0) then
+ begin
+ HHGear^.State := HHGear^.State or gstMoving;
+ DeleteGear(Gear);
+ AfterAttack;
+ exit
+ end;
+
+ if CheckLandValue(hwRound(HHGear^.X), hwRound(HHGear^.Y + HHGear^.dY + SignAs(_6,Gear^.dY)),
+ lfIndestructible) then
+ HHGear^.Y := HHGear^.Y + HHGear^.dY
+end;
+
+procedure doStepFirePunch(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ AllInactive := false;
+ HHGear := Gear^.Hedgehog^.Gear;
+ DeleteCI(HHGear);
+ //HHGear^.X := int2hwFloat(hwRound(HHGear^.X)) - _0_5; WTF?
+ HHGear^.dX := SignAs(cLittle, Gear^.dX);
+
+ HHGear^.dY := - _0_3;
+
+ Gear^.X := HHGear^.X;
+ Gear^.dX := SignAs(_0_45, Gear^.dX);
+ Gear^.dY := - _0_9;
+ Gear^.doStep := @doStepFirePunchWork;
+ DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y + _1, _0_5, _0, cHHRadius * 4, 5);
+
+ PlaySoundV(TSound(ord(sndFirePunch1) + GetRandom(6)), HHGear^.Hedgehog^.Team^.voicepack)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+
+procedure doStepParachuteWork(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+
+ inc(Gear^.Timer);
+
+ if (TestCollisionYwithGear(HHGear, 1) <> 0)
+ or ((HHGear^.State and gstHHDriven) = 0)
+ or CheckGearDrowning(HHGear)
+ or ((Gear^.Message and gmAttack) <> 0) then
+ begin
+ with HHGear^ do
+ begin
+ Message := 0;
+ SetLittle(dX);
+ dY := _0;
+ State := State or gstMoving;
+ end;
+ DeleteGear(Gear);
+ isCursorVisible := false;
+ ApplyAmmoChanges(HHGear^.Hedgehog^);
+ exit
+ end;
+
+ HHGear^.X := HHGear^.X + cWindSpeed * 200;
+
+ if (Gear^.Message and gmLeft) <> 0 then
+ HHGear^.X := HHGear^.X - cMaxWindSpeed * 80
+
+ else if (Gear^.Message and gmRight) <> 0 then
+ HHGear^.X := HHGear^.X + cMaxWindSpeed * 80;
+
+ if (Gear^.Message and gmUp) <> 0 then
+ HHGear^.Y := HHGear^.Y - cGravity * 40
+
+ else if (Gear^.Message and gmDown) <> 0 then
+ HHGear^.Y := HHGear^.Y + cGravity * 40;
+
+ // don't drift into obstacles
+ if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) <> 0 then
+ HHGear^.X := HHGear^.X - int2hwFloat(hwSign(HHGear^.dX));
+ HHGear^.Y := HHGear^.Y + cGravity * 100;
+ Gear^.X := HHGear^.X;
+ Gear^.Y := HHGear^.Y
+end;
+
+procedure doStepParachute(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+
+ DeleteCI(HHGear);
+
+ AfterAttack;
+
+ HHGear^.State := HHGear^.State and (not (gstAttacking or gstAttacked or gstMoving));
+ HHGear^.Message := HHGear^.Message and (not gmAttack);
+
+ Gear^.doStep := @doStepParachuteWork;
+
+ Gear^.Message := HHGear^.Message;
+ doStepParachuteWork(Gear)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepAirAttackWork(Gear: PGear);
+begin
+ AllInactive := false;
+ Gear^.X := Gear^.X + cAirPlaneSpeed * Gear^.Tag;
+
+ if (Gear^.Health > 0)and(not (Gear^.X < Gear^.dX))and(Gear^.X < Gear^.dX + cAirPlaneSpeed) then
+ begin
+ dec(Gear^.Health);
+ case Gear^.State of
+ 0: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
+ 1: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMine, 0, cBombsSpeed * Gear^.Tag, _0, 0);
+ 2: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtNapalmBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
+ 3: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtDrill, gsttmpFlag, cBombsSpeed * Gear^.Tag, _0, Gear^.Timer + 1);
+ //4: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtWaterMelon, 0, cBombsSpeed *
+ // Gear^.Tag, _0, 5000);
+ end;
+ Gear^.dX := Gear^.dX + int2hwFloat(30 * Gear^.Tag);
+ StopSoundChan(Gear^.SoundChannel, 4000);
+ end;
+
+ if (GameTicks and $3F) = 0 then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
+
+ if (hwRound(Gear^.X) > (max(LAND_WIDTH,4096)+2048)) or (hwRound(Gear^.X) < -2048) then
+ begin
+ // avoid to play forever (is this necessary?)
+ StopSoundChan(Gear^.SoundChannel);
+ DeleteGear(Gear)
+ end;
+end;
+
+procedure doStepAirAttack(Gear: PGear);
+begin
+ AllInactive := false;
+
+ if Gear^.X.QWordValue = 0 then
+ begin
+ Gear^.Tag := 1;
+ Gear^.X := -_2048;
+ end
+ else
+ begin
+ Gear^.Tag := -1;
+ Gear^.X := int2hwFloat(max(LAND_WIDTH,4096) + 2048);
+ end;
+
+ Gear^.Y := int2hwFloat(topY-300);
+ Gear^.dX := int2hwFloat(Gear^.Target.X - 5 * Gear^.Tag * 15);
+
+ // calcs for Napalm Strike, so that it will hit the target (without wind at least :P)
+ if (Gear^.State = 2) then
+ Gear^.dX := Gear^.dX - cBombsSpeed * Gear^.Tag * 900
+ // calcs for regular falling gears
+ else if (int2hwFloat(Gear^.Target.Y) - Gear^.Y > _0) then
+ Gear^.dX := Gear^.dX - cBombsSpeed * hwSqrt((int2hwFloat(Gear^.Target.Y) - Gear^.Y) * 2 /
+ cGravity) * Gear^.Tag;
+
+ Gear^.Health := 6;
+ Gear^.doStep := @doStepAirAttackWork;
+ Gear^.SoundChannel := LoopSound(sndPlane, 4000);
+
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+
+procedure doStepAirBomb(Gear: PGear);
+begin
+ AllInactive := false;
+ doStepFallingGear(Gear);
+ if (Gear^.State and gstCollision) <> 0 then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ with mobileRecord do
+ if (performRumble <> nil) and (not fastUntilLag) then
+ performRumble(kSystemSoundID_Vibrate);
+ exit
+ end;
+ if (GameTicks and $3F) = 0 then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+
+procedure doStepGirder(Gear: PGear);
+var
+ HHGear: PGear;
+ x, y, tx, ty: hwFloat;
+ rx: LongInt;
+ LandFlags: Word;
+begin
+ AllInactive := false;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+ tx := int2hwFloat(Gear^.Target.X);
+ ty := int2hwFloat(Gear^.Target.Y);
+ x := HHGear^.X;
+ y := HHGear^.Y;
+ rx:= hwRound(x);
+
+ LandFlags:= 0;
+ if Gear^.AmmoType = amRubber then LandFlags:= lfBouncy
+ else if cIce then LandFlags:= lfIce;
+
+ if ((Distance(tx - x, ty - y) > _256) and ((WorldEdge <> weWrap) or
+ (
+ (Distance(tx - int2hwFloat(rightX+(rx-leftX)), ty - y) > _256) and
+ (Distance(tx - int2hwFloat(leftX-(rightX-rx)), ty - y) > _256)
+ )))
+ or (not TryPlaceOnLand(Gear^.Target.X - SpritesData[Ammoz[Gear^.AmmoType].PosSprite].Width div 2, Gear^.Target.Y - SpritesData[Ammoz[Gear^.AmmoType].PosSprite].Height div 2, Ammoz[Gear^.AmmoType].PosSprite, Gear^.State, true, false, LandFlags)) then
+ begin
+ PlaySound(sndDenied);
+ HHGear^.Message := HHGear^.Message and (not gmAttack);
+ HHGear^.State := HHGear^.State and (not gstAttacking);
+ HHGear^.State := HHGear^.State or gstHHChooseTarget;
+ isCursorVisible := true;
+ DeleteGear(Gear)
+ end
+ else
+ begin
+ PlaySound(sndPlaced);
+ DeleteGear(Gear);
+ AfterAttack;
+ end;
+
+ HHGear^.State := HHGear^.State and (not (gstAttacking or gstAttacked));
+ HHGear^.Message := HHGear^.Message and (not gmAttack);
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepTeleportAfter(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+ doStepHedgehogMoving(HHGear);
+ // if not infattack mode wait for hedgehog finish falling to collect cases
+ if ((GameFlags and gfInfAttack) <> 0)
+ or ((HHGear^.State and gstMoving) = 0)
+ or (Gear^.Hedgehog^.Gear^.Damage > 0)
+ or ((HHGear^.State and gstDrowning) = 1) then
+ begin
+ DeleteGear(Gear);
+ AfterAttack
+ end
+end;
+
+procedure doStepTeleportAnim(Gear: PGear);
+begin
+ if (Gear^.Hedgehog^.Gear^.Damage > 0) then
+ begin
+ DeleteGear(Gear);
+ AfterAttack;
+ end;
+ inc(Gear^.Timer);
+ if Gear^.Timer = 65 then
+ begin
+ Gear^.Timer := 0;
+ inc(Gear^.Pos);
+ if Gear^.Pos = 11 then
+ Gear^.doStep := @doStepTeleportAfter
+ end;
+end;
+
+procedure doStepTeleport(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ AllInactive := false;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+ if not TryPlaceOnLand(Gear^.Target.X - SpritesData[sprHHTelepMask].Width div 2,
+ Gear^.Target.Y - SpritesData[sprHHTelepMask].Height div 2,
+ sprHHTelepMask, 0, false, false) then
+ begin
+ HHGear^.Message := HHGear^.Message and (not gmAttack);
+ HHGear^.State := HHGear^.State and (not gstAttacking);
+ HHGear^.State := HHGear^.State or gstHHChooseTarget;
+ DeleteGear(Gear);
+ isCursorVisible := true;
+ PlaySound(sndDenied)
+ end
+ else
+ begin
+ DeleteCI(HHGear);
+ SetAllHHToActive;
+ Gear^.doStep := @doStepTeleportAnim;
+
+ // copy old HH position and direction to Gear (because we need them for drawing the vanishing hog)
+ Gear^.dX := HHGear^.dX;
+ // retrieve the cursor direction (it was previously copied to X so it doesn't get lost)
+ HHGear^.dX.isNegative := (Gear^.X.QWordValue <> 0);
+ Gear^.X := HHGear^.X;
+ Gear^.Y := HHGear^.Y;
+ HHGear^.X := int2hwFloat(Gear^.Target.X);
+ HHGear^.Y := int2hwFloat(Gear^.Target.Y);
+ HHGear^.State := HHGear^.State or gstMoving;
+ Gear^.Hedgehog^.Unplaced := false;
+ isCursorVisible := false;
+ playSound(sndWarp)
+ end;
+ Gear^.Target.X:= NoPointX
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSwitcherWork(Gear: PGear);
+var
+ HHGear: PGear;
+ hedgehog: PHedgehog;
+ State: Longword;
+begin
+ AllInactive := false;
+
+ if ((Gear^.Message and (not gmSwitch)) <> 0) or (TurnTimeLeft = 0) then
+ begin
+ hedgehog := Gear^.Hedgehog;
+ //Msg := Gear^.Message and (not gmSwitch);
+ DeleteGear(Gear);
+ ApplyAmmoChanges(hedgehog^);
+
+ HHGear := CurrentHedgehog^.Gear;
+ ApplyAmmoChanges(HHGear^.Hedgehog^);
+ //HHGear^.Message := Msg;
+ exit
+ end;
+
+ if (Gear^.Message and gmSwitch) <> 0 then
+ begin
+ HHGear := CurrentHedgehog^.Gear;
+ HHGear^.Message := HHGear^.Message and (not gmSwitch);
+ Gear^.Message := Gear^.Message and (not gmSwitch);
+ State := HHGear^.State;
+ HHGear^.State := 0;
+ HHGear^.Z := cHHZ;
+ HHGear^.Active := false;
+ HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList;
+
+ PlaySound(sndSwitchHog);
+
+ repeat
+ CurrentTeam^.CurrHedgehog := Succ(CurrentTeam^.CurrHedgehog) mod (CurrentTeam^.HedgehogsNumber);
+ until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) and
+ (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear^.Damage = 0) and
+ (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Effects[heFrozen]=0);
+
+ SwitchCurrentHedgehog(@CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog]);
+ AmmoMenuInvalidated:= true;
+
+ HHGear := CurrentHedgehog^.Gear;
+ HHGear^.State := State;
+ HHGear^.Active := true;
+ FollowGear := HHGear;
+ HHGear^.Z := cCurrHHZ;
+ HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList;
+ Gear^.X := HHGear^.X;
+ Gear^.Y := HHGear^.Y
+ end;
+end;
+
+procedure doStepSwitcher(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ Gear^.doStep := @doStepSwitcherWork;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+ OnUsedAmmo(HHGear^.Hedgehog^);
+ with HHGear^ do
+ begin
+ State := State and (not gstAttacking);
+ Message := Message and (not gmAttack)
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepMortar(Gear: PGear);
+var
+ dX, dY, gdX, gdY: hwFloat;
+ i: LongInt;
+begin
+ AllInactive := false;
+ gdX := Gear^.dX;
+ gdY := Gear^.dY;
+
+ doStepFallingGear(Gear);
+ if (Gear^.State and gstCollision) <> 0 then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLAutoSound);
+ gdX.isNegative := not gdX.isNegative;
+ gdY.isNegative := not gdY.isNegative;
+ gdX:= gdX*_0_2;
+ gdY:= gdY*_0_2;
+
+ for i:= 0 to 4 do
+ begin
+ dX := gdX + rndSign(GetRandomf) * _0_03;
+ dY := gdY + rndSign(GetRandomf) * _0_03;
+ AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtCluster, 0, dX, dY, 25);
+ end;
+
+ DeleteGear(Gear);
+ exit
+ end;
+
+ if (GameTicks and $3F) = 0 then
+ begin
+ if hwRound(Gear^.Y) > cWaterLine then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble)
+ else AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepKamikazeWork(Gear: PGear);
+var
+ i: LongWord;
+ HHGear: PGear;
+ sparkles: PVisualGear;
+ hasWishes: boolean;
+begin
+ AllInactive := false;
+ hasWishes:= ((Gear^.Message and (gmPrecise or gmSwitch)) = (gmPrecise or gmSwitch));
+ if hasWishes then
+ Gear^.AdvBounce:= 1;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+ if HHGear = nil then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+
+ HHGear^.State := HHGear^.State or gstNoDamage;
+ DeleteCI(HHGear);
+
+ Gear^.X := HHGear^.X;
+ Gear^.Y := HHGear^.Y;
+ if (GameTicks mod 2 = 0) and hasWishes then
+ begin
+ sparkles:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtDust, 1);
+ if sparkles <> nil then
+ begin
+ sparkles^.Tint:= ((random(210)+45) shl 24) or ((random(210)+45) shl 16) or ((random(210)+45) shl 8) or $FF;
+ sparkles^.Angle:= random(360);
+ end
+ end;
+
+ i := 2;
+ repeat
+
+ Gear^.X := Gear^.X + HHGear^.dX;
+ Gear^.Y := Gear^.Y + HHGear^.dY;
+ HHGear^.X := Gear^.X;
+ HHGear^.Y := Gear^.Y;
+
+ inc(Gear^.Damage, 2);
+
+ // if TestCollisionXwithGear(HHGear, hwSign(Gear^.dX))
+ // or TestCollisionYwithGear(HHGear, hwSign(Gear^.dY)) then inc(Gear^.Damage, 3);
+
+ dec(i)
+ until (i = 0)
+ or (Gear^.Damage > Gear^.Health);
+
+ inc(upd);
+ if upd > 3 then
+ begin
+ if Gear^.Health < 1500 then
+ begin
+ if Gear^.AdvBounce <> 0 then
+ Gear^.Pos := 3
+ else
+ Gear^.Pos := 2;
+ end;
+
+ AmmoShove(Gear, 30, 40);
+
+ DrawTunnel(HHGear^.X - HHGear^.dX * 10,
+ HHGear^.Y - _2 - HHGear^.dY * 10 + hwAbs(HHGear^.dY) * 2,
+ HHGear^.dX,
+ HHGear^.dY,
+ 20 + cHHRadius * 2,
+ cHHRadius * 2 + 7);
+
+ upd := 0
+ end;
+
+ if Gear^.Health < Gear^.Damage then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
+ if hasWishes then
+ for i:= 0 to 31 do
+ begin
+ sparkles:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot);
+ if sparkles <> nil then
+ with sparkles^ do
+ begin
+ Tint:= ((random(210)+45) shl 24) or ((random(210)+45) shl 16) or ((random(210)+45) shl 8) or $FF;
+ Angle:= random(360);
+ dx:= 0.001 * (random(200));
+ dy:= 0.001 * (random(200));
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ FrameTicks:= random(400) + 250
+ end
+ end;
+ AfterAttack;
+ HHGear^.Message:= HHGear^.Message or gmDestroy;
+ DeleteGear(Gear);
+ end
+ else
+ begin
+ dec(Gear^.Health, Gear^.Damage);
+ Gear^.Damage := 0
+ end
+end;
+
+procedure doStepKamikazeIdle(Gear: PGear);
+begin
+ AllInactive := false;
+ dec(Gear^.Timer);
+ if Gear^.Timer = 0 then
+ begin
+ Gear^.Pos := 1;
+ PlaySoundV(sndKamikaze, Gear^.Hedgehog^.Team^.voicepack);
+ Gear^.doStep := @doStepKamikazeWork
+ end
+end;
+
+procedure doStepKamikaze(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ AllInactive := false;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+
+ HHGear^.dX := Gear^.dX;
+ HHGear^.dY := Gear^.dY;
+
+ Gear^.dX := SignAs(_0_45, Gear^.dX);
+ Gear^.dY := - _0_9;
+
+ Gear^.Timer := 550;
+
+ Gear^.doStep := @doStepKamikazeIdle
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+
+const cakeh = 27;
+var
+ CakePoints: array[0..Pred(cakeh)] of record
+ x, y: hwFloat;
+ end;
+ CakeI: Longword;
+
+procedure doStepCakeExpl(Gear: PGear);
+begin
+ AllInactive := false;
+
+ inc(Gear^.Tag);
+ if Gear^.Tag < 2250 then
+ exit;
+
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg, Gear^.Hedgehog, EXPLAutoSound);
+ AfterAttack;
+ DeleteGear(Gear)
+end;
+
+procedure doStepCakeDown(Gear: PGear);
+var
+ gi: PGear;
+ dmg, dmgBase: LongInt;
+ fX, fY, tdX, tdY: hwFloat;
+begin
+ AllInactive := false;
+
+ inc(Gear^.Tag);
+ if Gear^.Tag < 100 then
+ exit;
+ Gear^.Tag := 0;
+
+ if Gear^.Pos = 0 then
+ begin
+///////////// adapted from doMakeExplosion ///////////////////////////
+ //fX:= Gear^.X;
+ //fY:= Gear^.Y;
+ //fX.QWordValue:= fX.QWordValue and $FFFFFFFF00000000;
+ //fY.QWordValue:= fY.QWordValue and $FFFFFFFF00000000;
+ fX:= int2hwFloat(hwRound(Gear^.X));
+ fY:= int2hwFloat(hwRound(Gear^.Y));
+ dmgBase:= cakeDmg shl 1 + cHHRadius div 2;
+ gi := GearsList;
+ while gi <> nil do
+ begin
+ if gi^.Kind = gtHedgehog then
+ begin
+ dmg:= 0;
+ tdX:= gi^.X-fX;
+ tdY:= gi^.Y-fY;
+ if hwRound(hwAbs(tdX)+hwAbs(tdY)) < dmgBase then
+ dmg:= dmgBase - max(hwRound(Distance(tdX, tdY)),gi^.Radius);
+ if (dmg > 1) then dmg:= ModifyDamage(min(dmg div 2, cakeDmg), gi);
+ if (dmg > 1) then
+ if (CurrentHedgehog^.Gear = gi) and ((gi^.Hedgehog^.Effects[heInvulnerable] = 0)) then
+ gi^.State := gi^.State or gstLoser
+ else
+ gi^.State := gi^.State or gstWinner;
+ end;
+ gi := gi^.NextGear
+ end;
+//////////////////////////////////////////////////////////////////////
+ Gear^.doStep := @doStepCakeExpl;
+ PlaySound(sndCake)
+ end
+ else dec(Gear^.Pos)
+end;
+
+
+procedure doStepCakeWork(Gear: PGear);
+var
+ tdx, tdy: hwFloat;
+begin
+ AllInactive := false;
+
+ inc(Gear^.Tag);
+ if Gear^.Tag < 7 then
+ exit;
+
+ dec(Gear^.Health);
+ Gear^.Timer := Gear^.Health*10;
+ if Gear^.Health mod 100 = 0 then
+ Gear^.PortalCounter:= 0;
+ // This is not seconds, but at least it is *some* feedback
+ if (Gear^.Health = 0) or ((Gear^.Message and gmAttack) <> 0) then
+ begin
+ FollowGear := Gear;
+ Gear^.RenderTimer := false;
+ Gear^.doStep := @doStepCakeDown;
+ exit
+ end;
+
+ cakeStep(Gear);
+
+ if Gear^.Tag = 0 then
+ begin
+ CakeI := (CakeI + 1) mod cakeh;
+ tdx := CakePoints[CakeI].x - Gear^.X;
+ tdy := - CakePoints[CakeI].y + Gear^.Y;
+ CakePoints[CakeI].x := Gear^.X;
+ CakePoints[CakeI].y := Gear^.Y;
+ Gear^.DirAngle := DxDy2Angle(tdx, tdy);
+ end;
+end;
+
+procedure doStepCakeUp(Gear: PGear);
+var
+ i: Longword;
+begin
+ AllInactive := false;
+
+ inc(Gear^.Tag);
+ if Gear^.Tag < 100 then
+ exit;
+ Gear^.Tag := 0;
+
+ if Gear^.Pos = 6 then
+ begin
+ for i:= 0 to Pred(cakeh) do
+ begin
+ CakePoints[i].x := Gear^.X;
+ CakePoints[i].y := Gear^.Y
+ end;
+ CakeI := 0;
+ Gear^.doStep := @doStepCakeWork
+ end
+ else
+ inc(Gear^.Pos)
+end;
+
+procedure doStepCakeFall(Gear: PGear);
+begin
+ AllInactive := false;
+
+ Gear^.dY := Gear^.dY + cGravity;
+ if TestCollisionYwithGear(Gear, 1) <> 0 then
+ Gear^.doStep := @doStepCakeUp
+ else
+ begin
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ if CheckGearDrowning(Gear) then
+ AfterAttack
+ end
+end;
+
+procedure doStepCake(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ AllInactive := false;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+ HHGear^.Message := HHGear^.Message and (not gmAttack);
+ Gear^.CollisionMask:= lfNotCurrentMask;
+
+ FollowGear := Gear;
+
+ Gear^.doStep := @doStepCakeFall
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSeductionWork(Gear: PGear);
+var i: LongInt;
+ hogs: PGearArrayS;
+begin
+ AllInactive := false;
+ hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Radius);
+ if hogs.size > 0 then
+ begin
+ for i:= 0 to hogs.size - 1 do
+ with hogs.ar^[i]^ do
+ begin
+ if hogs.ar^[i] <> CurrentHedgehog^.Gear then
+ begin
+ dX:= _50 * cGravity * (Gear^.X - X) / _25;
+ dY:= -_450 * cGravity;
+ Active:= true;
+ end
+ end;
+ end ;
+ AfterAttack;
+ DeleteGear(Gear);
+(*
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ x := hwRound(Gear^.X);
+ y := hwRound(Gear^.Y);
+
+ if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
+ if (Land[y, x] <> 0) then
+ begin
+ Gear^.dX.isNegative := not Gear^.dX.isNegative;
+ Gear^.dY.isNegative := not Gear^.dY.isNegative;
+ Gear^.dX := Gear^.dX * _1_5;
+ Gear^.dY := Gear^.dY * _1_5 - _0_3;
+ AmmoShove(Gear, 0, 40);
+ AfterAttack;
+ DeleteGear(Gear)
+ end
+ else
+ else
+ begin
+ AfterAttack;
+ DeleteGear(Gear)
+ end*)
+end;
+
+procedure doStepSeductionWear(Gear: PGear);
+var heart: PVisualGear;
+begin
+ AllInactive := false;
+ inc(Gear^.Timer);
+ if Gear^.Timer > 250 then
+ begin
+ Gear^.Timer := 0;
+ inc(Gear^.Pos);
+ if Gear^.Pos = 5 then
+ PlaySoundV(sndYoohoo, Gear^.Hedgehog^.Team^.voicepack)
+ end;
+
+ if (Gear^.Pos = 14) and (RealTicks and $3 = 0) then
+ begin
+ heart:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtStraightShot);
+ if heart <> nil then
+ with heart^ do
+ begin
+ dx:= 0.001 * (random(200));
+ dy:= 0.001 * (random(200));
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ FrameTicks:= random(750) + 1000;
+ State:= ord(sprSeduction)
+ end;
+ end;
+
+ if Gear^.Pos = 15 then
+ Gear^.doStep := @doStepSeductionWork
+end;
+
+procedure doStepSeduction(Gear: PGear);
+begin
+ AllInactive := false;
+ //DeleteCI(Gear^.Hedgehog^.Gear);
+ Gear^.doStep := @doStepSeductionWear
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepWaterUp(Gear: PGear);
+var
+ i: LongWord;
+begin
+ if (Gear^.Tag = 0)
+ or (cWaterLine = 0) then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+
+ AllInactive := false;
+
+ inc(Gear^.Timer);
+ if Gear^.Timer = 17 then
+ Gear^.Timer := 0
+ else
+ exit;
+
+ if cWaterLine > 0 then
+ begin
+ dec(cWaterLine);
+ for i:= 0 to LAND_WIDTH - 1 do
+ Land[cWaterLine, i] := 0;
+ SetAllToActive
+ end;
+
+ dec(Gear^.Tag);
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepDrillDrilling(Gear: PGear);
+var
+ t: PGearArray;
+ tempColl: Word;
+begin
+ AllInactive := false;
+ if (Gear^.Timer > 0) and (Gear^.Timer mod 10 <> 0) then
+ begin
+ dec(Gear^.Timer);
+ exit;
+ end;
+
+ DrawTunnel(Gear^.X, Gear^.Y, Gear^.dX, Gear^.dY, 2, 6);
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ if (Gear^.Timer mod 30) = 0 then
+ AddVisualGear(hwRound(Gear^.X + _20 * Gear^.dX), hwRound(Gear^.Y + _20 * Gear^.dY), vgtDust);
+ if (CheckGearDrowning(Gear)) then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ exit
+ end;
+
+ tempColl:= Gear^.CollisionMask;
+ Gear^.CollisionMask:= $007F;
+ if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) <> 0) or (GameTicks > Gear^.FlightTime) then
+ t := CheckGearsCollision(Gear)
+ else t := nil;
+ Gear^.CollisionMask:= tempColl;
+ //fixes drill not exploding when touching HH bug
+
+ if (Gear^.Timer = 0) or ((t <> nil) and (t^.Count <> 0))
+ or ( ((Gear^.State and gsttmpFlag) = 0) and (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) = 0))
+// CheckLandValue returns true if the type isn't matched
+ or (not CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y), lfIndestructible)) then
+ begin
+ //out of time or exited ground
+ StopSoundChan(Gear^.SoundChannel);
+ if (Gear^.State and gsttmpFlag) <> 0 then
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound)
+ else
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ exit
+ end
+
+ else if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) = 0) then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ Gear^.Tag := 1;
+ Gear^.doStep := @doStepDrill
+ end;
+
+ dec(Gear^.Timer);
+end;
+
+procedure doStepDrill(Gear: PGear);
+var
+ t: PGearArray;
+ oldDx, oldDy: hwFloat;
+ t2: hwFloat;
+begin
+ AllInactive := false;
+
+ if (Gear^.State and gsttmpFlag) = 0 then
+ Gear^.dX := Gear^.dX + cWindSpeed;
+
+ oldDx := Gear^.dX;
+ oldDy := Gear^.dY;
+
+ doStepFallingGear(Gear);
+
+ if (GameTicks and $3F) = 0 then
+ begin
+ if hwRound(Gear^.Y) > cWaterLine then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble)
+ else AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace)
+ end;
+
+ if ((Gear^.State and gstCollision) <> 0) then
+ begin
+ //hit
+ Gear^.dX := oldDx;
+ Gear^.dY := oldDy;
+
+ if GameTicks > Gear^.FlightTime then
+ t := CheckGearsCollision(Gear)
+ else
+ t := nil;
+ if (t = nil) or (t^.Count = 0) then
+ begin
+ //hit the ground not the HH
+ t2 := _0_5 / Distance(Gear^.dX, Gear^.dY);
+ Gear^.dX := Gear^.dX * t2;
+ Gear^.dY := Gear^.dY * t2;
+ end
+
+ else if (t <> nil) then
+ begin
+ //explode right on contact with HH
+ if (Gear^.State and gsttmpFlag) <> 0 then
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound)
+ else
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ exit;
+ end;
+
+ Gear^.SoundChannel := LoopSound(sndDrillRocket);
+ Gear^.doStep := @doStepDrillDrilling;
+
+ if (Gear^.State and gsttmpFlag) <> 0 then
+ gear^.RenderTimer:= true;
+ if Gear^.Timer > 0 then dec(Gear^.Timer)
+ end
+ else if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Tag <> 0) then
+ begin
+ if Gear^.Timer > 0 then
+ dec(Gear^.Timer)
+ else
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ end
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepBallgunWork(Gear: PGear);
+var
+ HHGear, ball: PGear;
+ rx, ry: hwFloat;
+ gX, gY: LongInt;
+begin
+ AllInactive := false;
+ dec(Gear^.Timer);
+ HHGear := Gear^.Hedgehog^.Gear;
+ HedgehogChAngle(HHGear);
+ gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
+ gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
+ if (Gear^.Timer mod 100) = 0 then
+ begin
+ rx := rndSign(getRandomf * _0_1);
+ ry := rndSign(getRandomf * _0_1);
+
+ ball:= AddGear(gx, gy, gtBall, 0, SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx, AngleCos(HHGear^.Angle) * ( - _0_8) + ry, 0);
+ ball^.CollisionMask:= lfNotCurrentMask;
+
+ PlaySound(sndGun);
+ end;
+
+ if (Gear^.Timer = 0) or ((HHGear^.State and gstHHDriven) = 0) then
+ begin
+ DeleteGear(Gear);
+ AfterAttack
+ end
+end;
+
+procedure doStepBallgun(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+ HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown));
+ HHGear^.State := HHGear^.State or gstNotKickable;
+ Gear^.doStep := @doStepBallgunWork
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepRCPlaneWork(Gear: PGear);
+
+const cAngleSpeed = 3;
+var
+ HHGear: PGear;
+ i: LongInt;
+ dX, dY, X, Y : hwFloat;
+ fChanged: boolean;
+ trueAngle: Longword;
+ t: PGear;
+begin
+ if WorldWrap(Gear) and (WorldEdge <> weWrap) then
+ begin
+ Y.isNegative:= false;
+ Y.QWordValue:= 4294967296 * 112;
+ X.isNegative:= false;
+ X.QWordValue:= 4294967296 * 35;
+ dX.isNegative:= false;
+ dX.QWordValue:= 4294967296 * 1152;
+
+ dY:=hwAbs(Gear^.dX*4);
+ dY:= dY + hwPow(dY,3)/_6 + _3 * hwPow(dY,5) / _40 + _5 * hwPow(dY,7) / Y + X * hwPow(dY,9) / dX;
+ Gear^.Angle:= hwRound(dY*_2048 / _PI);
+ if not Gear^.dY.isNegative then Gear^.Angle:= 2048-Gear^.Angle;
+ if Gear^.dX.isNegative then Gear^.Angle:= 4096-Gear^.Angle;
+ end;
+ AllInactive := false;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+ FollowGear := Gear;
+
+ if Gear^.Timer > 0 then
+ dec(Gear^.Timer);
+
+ fChanged := false;
+ if (HHGear = nil) or ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then
+ begin
+ fChanged := true;
+ if Gear^.Angle > 2048 then
+ dec(Gear^.Angle)
+ else if Gear^.Angle < 2048 then
+ inc(Gear^.Angle)
+ else fChanged := false
+ end
+ else
+ begin
+ if ((Gear^.Message and gmLeft) <> 0) then
+ begin
+ fChanged := true;
+ Gear^.Angle := (Gear^.Angle + (4096 - cAngleSpeed)) mod 4096
+ end;
+
+ if ((Gear^.Message and gmRight) <> 0) then
+ begin
+ fChanged := true;
+ Gear^.Angle := (Gear^.Angle + cAngleSpeed) mod 4096
+ end
+ end;
+
+ if fChanged then
+ begin
+ Gear^.dX.isNegative := (Gear^.Angle > 2048);
+ if Gear^.dX.isNegative then
+ trueAngle := 4096 - Gear^.Angle
+ else
+ trueAngle := Gear^.Angle;
+
+ Gear^.dX := SignAs(AngleSin(trueAngle), Gear^.dX) * _0_25;
+ Gear^.dY := AngleCos(trueAngle) * -_0_25;
+ end;
+
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+
+ if (GameTicks and $FF) = 0 then
+ if Gear^.Timer < 3500 then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace)
+ else
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
+
+ if (HHGear <> nil) and ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then
+ begin
+ HHGear^.Message := HHGear^.Message and (not gmAttack);
+ AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
+ _0_5, 0);
+ dec(Gear^.Health)
+ end;
+
+ if (HHGear <> nil) and ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then
+ begin
+ Gear^.State := Gear^.State or gsttmpFlag;
+ PauseMusic;
+ playSound(sndRideOfTheValkyries);
+ end;
+
+ // pickup bonuses
+ t := CheckGearNear(Gear, gtCase, 36, 36);
+ if t <> nil then
+ PickUp(HHGear, t);
+
+ CheckCollision(Gear);
+
+ if ((Gear^.State and gstCollision) <> 0) or CheckGearDrowning(Gear) then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ StopSound(sndRideOfTheValkyries);
+ ResumeMusic;
+
+ if ((Gear^.State and gstCollision) <> 0) then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, Gear^.Hedgehog, EXPLAutoSound);
+ for i:= 0 to 15 do
+ begin
+ dX := AngleCos(i * 64) * _0_5 * (GetRandomf + _1);
+ dY := AngleSin(i * 64) * _0_5 * (GetRandomf + _1);
+ AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtFlame, 0, dX, dY, 0);
+ AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtFlame, 0, dX, -dY, 0);
+ end;
+ DeleteGear(Gear)
+ end;
+
+ AfterAttack;
+ CurAmmoGear := nil;
+ if (GameFlags and gfInfAttack) = 0 then
+ begin
+ if TagTurnTimeLeft = 0 then
+ TagTurnTimeLeft:= TurnTimeLeft;
+
+ TurnTimeLeft:= 14 * 125;
+ end;
+
+ HHGear^.Message := 0;
+ ParseCommand('/taunt ' + #1, true)
+ end
+end;
+
+procedure doStepRCPlane(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+ HHGear^.Message := 0;
+ HHGear^.State := HHGear^.State or gstNotKickable;
+ Gear^.Angle := HHGear^.Angle;
+ Gear^.Tag := hwSign(HHGear^.dX);
+
+ if HHGear^.dX.isNegative then
+ Gear^.Angle := 4096 - Gear^.Angle;
+ Gear^.doStep := @doStepRCPlaneWork
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepJetpackWork(Gear: PGear);
+var
+ HHGear: PGear;
+ fuel, i: LongInt;
+ move: hwFloat;
+ isUnderwater: Boolean;
+ bubble: PVisualGear;
+begin
+ isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius;
+ if Gear^.Pos > 0 then
+ dec(Gear^.Pos);
+ AllInactive := false;
+ HHGear := Gear^.Hedgehog^.Gear;
+ //dec(Gear^.Timer);
+ move := _0_2;
+ fuel := 50;
+(*if (HHGear^.Message and gmPrecise) <> 0 then
+ begin
+ move:= _0_02;
+ fuel:= 5;
+ end;*)
+ if HHGear^.Message and gmPrecise <> 0 then
+ HedgehogChAngle(HHGear)
+ else if Gear^.Health > 0 then
+ begin
+ if HHGear^.Message and gmUp <> 0 then
+ begin
+ if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
+ begin
+ if isUnderwater then
+ begin
+ HHGear^.dY := HHGear^.dY - (move * _0_7);
+ for i:= random(10)+10 downto 0 do
+ begin
+ bubble := AddVisualGear(hwRound(HHGear^.X) - 8 + random(16), hwRound(HHGear^.Y) + 16 + random(8), vgtBubble);
+ if bubble <> nil then
+ bubble^.dY:= random(20)/10+0.1;
+ end
+ end
+ else HHGear^.dY := HHGear^.dY - move;
+ end;
+ dec(Gear^.Health, fuel);
+ Gear^.MsgParam := Gear^.MsgParam or gmUp;
+ Gear^.Timer := GameTicks
+ end;
+ move.isNegative := (HHGear^.Message and gmLeft) <> 0;
+ if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
+ begin
+ HHGear^.dX := HHGear^.dX + (move * _0_1);
+ if isUnderwater then
+ begin
+ for i:= random(5)+5 downto 0 do
+ begin
+ bubble := AddVisualGear(hwRound(HHGear^.X)+random(8), hwRound(HHGear^.Y) - 8 + random(16), vgtBubble);
+ if bubble <> nil then
+ begin
+ bubble^.dX:= (random(10)/10 + 0.02) * -1;
+ if (move.isNegative) then
+ begin
+ bubble^.X := bubble^.X + 28;
+ bubble^.dX:= bubble^.dX * (-1)
+ end
+ else bubble^.X := bubble^.X - 28;
+ end;
+ end
+ end;
+ dec(Gear^.Health, fuel div 5);
+ Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gmLeft or gmRight));
+ Gear^.Timer := GameTicks
+ end
+ end;
+
+ // erases them all at once :-/
+ if (Gear^.Timer <> 0) and (GameTicks - Gear^.Timer > 250) then
+ begin
+ Gear^.Timer := 0;
+ Gear^.MsgParam := 0
+ end;
+
+ if Gear^.Health < 0 then
+ Gear^.Health := 0;
+
+ i:= Gear^.Health div 20;
+
+ if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
+ begin
+ Gear^.Damage:= i;
+ //AddCaption('Fuel: '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
+ FreeTexture(Gear^.Tex);
+ Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(i) + '%', cWhiteColor, fntSmall)
+ end;
+
+ if (HHGear^.Message and (gmAttack or gmUp or gmLeft or gmRight) <> 0) and
+ (HHGear^.Message and gmPrecise = 0) then
+ Gear^.State := Gear^.State and (not gsttmpFlag);
+
+ if HHGear^.Message and gmPrecise = 0 then
+ HHGear^.Message := HHGear^.Message and (not (gmUp or gmLeft or gmRight));
+ HHGear^.State := HHGear^.State or gstMoving;
+
+ Gear^.X := HHGear^.X;
+ Gear^.Y := HHGear^.Y;
+
+ if not isUnderWater and hasBorder and ((HHGear^.X < _0)
+ or (hwRound(HHGear^.X) > LAND_WIDTH)) then
+ HHGear^.dY.isNegative:= false;
+
+ if ((Gear^.State and gsttmpFlag) = 0)
+ or (HHGear^.dY < _0) then
+ doStepHedgehogMoving(HHGear);
+
+ if // (Gear^.Health = 0)
+ (HHGear^.Damage <> 0)
+ //or CheckGearDrowning(HHGear)
+ or (cWaterLine + cVisibleWater * 4 < hwRound(HHGear^.Y))
+ or (TurnTimeLeft = 0)
+ // allow brief ground touches - to be fair on this, might need another counter
+ or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and (TestCollisionYwithGear(HHGear, 1) <> 0))
+ or ((Gear^.Message and gmAttack) <> 0) then
+ begin
+ with HHGear^ do
+ begin
+ Message := 0;
+ Active := true;
+ State := State or gstMoving
+ end;
+ DeleteGear(Gear);
+ isCursorVisible := false;
+ ApplyAmmoChanges(HHGear^.Hedgehog^);
+ // if Gear^.Tex <> nil then FreeTexture(Gear^.Tex);
+
+// Gear^.Tex:= RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(round(Gear^.Health / 20)) + '%', cWhiteColor, fntSmall)
+
+//AddCaption(trmsg[sidFuel]+': '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
+ end
+end;
+
+procedure doStepJetpack(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ Gear^.Pos:= 0;
+ Gear^.doStep := @doStepJetpackWork;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+ FollowGear := HHGear;
+ AfterAttack;
+ with HHGear^ do
+ begin
+ State := State and (not gstAttacking);
+ Message := Message and (not (gmAttack or gmUp or gmPrecise or gmLeft or gmRight));
+
+ if (dY < _0_1) and (dY > -_0_1) then
+ begin
+ Gear^.State := Gear^.State or gsttmpFlag;
+ dY := dY - _0_2
+ end
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepBirdyDisappear(Gear: PGear);
+begin
+ AllInactive := false;
+ Gear^.Pos := 0;
+ if Gear^.Timer < 2000 then
+ inc(Gear^.Timer, 1)
+ else
+ begin
+ DeleteGear(Gear);
+ end;
+end;
+
+procedure doStepBirdyFly(Gear: PGear);
+var
+ HHGear: PGear;
+ fuel, i: LongInt;
+ move: hwFloat;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+ if HHGear = nil then
+ begin
+ Gear^.Timer := 0;
+ Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
+ Gear^.Timer := 0;
+ Gear^.doStep := @doStepBirdyDisappear;
+ CurAmmoGear := nil;
+ isCursorVisible := false;
+ AfterAttack;
+ exit
+ end;
+
+ move := _0_2;
+ fuel := 50;
+
+ if Gear^.Pos > 0 then
+ dec(Gear^.Pos, 1)
+ else if (HHGear^.Message and (gmLeft or gmRight or gmUp)) <> 0 then
+ Gear^.Pos := 500;
+
+ if HHGear^.dX.isNegative then
+ Gear^.Tag := -1
+ else
+ Gear^.Tag := 1;
+
+ if (HHGear^.Message and gmUp) <> 0 then
+ begin
+ if (not HHGear^.dY.isNegative)
+ or (HHGear^.Y > -_256) then
+ HHGear^.dY := HHGear^.dY - move;
+
+ dec(Gear^.Health, fuel);
+ Gear^.MsgParam := Gear^.MsgParam or gmUp;
+ end;
+
+ if (HHGear^.Message and gmLeft) <> 0 then move.isNegative := true;
+ if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
+ begin
+ HHGear^.dX := HHGear^.dX + (move * _0_1);
+ dec(Gear^.Health, fuel div 5);
+ Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gmLeft or gmRight));
+ end;
+
+ if Gear^.Health < 0 then
+ Gear^.Health := 0;
+
+ if ((GameTicks and $FF) = 0) and (Gear^.Health < 500) then
+ for i:= ((500-Gear^.Health) div 250) downto 0 do
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFeather);
+
+ if (HHGear^.Message and gmAttack <> 0) then
+ begin
+ HHGear^.Message := HHGear^.Message and (not gmAttack);
+ if Gear^.FlightTime > 0 then
+ begin
+ AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + 32, gtEgg, 0, Gear^.dX * _0_5, Gear^.dY, 0);
+ PlaySound(sndBirdyLay);
+ dec(Gear^.FlightTime)
+ end;
+ end;
+
+ if HHGear^.Message and (gmUp or gmPrecise or gmLeft or gmRight) <> 0 then
+ Gear^.State := Gear^.State and (not gsttmpFlag);
+
+ HHGear^.Message := HHGear^.Message and (not (gmUp or gmPrecise or gmLeft or gmRight));
+ HHGear^.State := HHGear^.State or gstMoving;
+
+ Gear^.X := HHGear^.X;
+ Gear^.Y := HHGear^.Y - int2hwFloat(32);
+ // For some reason I need to reapply followgear here, something else grabs it otherwise.
+ // this is probably not needed anymore
+ if not CurrentTeam^.ExtDriven then FollowGear := HHGear;
+
+ if ((Gear^.State and gsttmpFlag) = 0)
+ or (HHGear^.dY < _0) then
+ doStepHedgehogMoving(HHGear);
+
+ if (Gear^.Health = 0)
+ or (HHGear^.Damage <> 0)
+ or CheckGearDrowning(HHGear)
+ or (TurnTimeLeft = 0)
+ // allow brief ground touches - to be fair on this, might need another counter
+ or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and (TestCollisionYwithGear(HHGear, 1) <> 0))
+ or ((Gear^.Message and gmAttack) <> 0) then
+ begin
+ with HHGear^ do
+ begin
+ Message := 0;
+ Active := true;
+ State := State or gstMoving
+ end;
+ Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
+ if HHGear^.dY < _0 then
+ begin
+ Gear^.dX := HHGear^.dX;
+ Gear^.dY := HHGear^.dY;
+ end;
+ Gear^.Timer := 0;
+ Gear^.doStep := @doStepBirdyDisappear;
+ CurAmmoGear := nil;
+ isCursorVisible := false;
+ AfterAttack;
+ end
+end;
+
+procedure doStepBirdyDescend(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ if Gear^.Timer > 0 then
+ dec(Gear^.Timer, 1);
+
+ HHGear := Gear^.Hedgehog^.Gear;
+ if HHGear = nil then
+ begin
+ Gear^.Timer := 0;
+ Gear^.State := Gear^.State or gstAnimation or gstTmpFlag;
+ Gear^.Timer := 0;
+ Gear^.doStep := @doStepBirdyDisappear;
+ CurAmmoGear := nil;
+ isCursorVisible := false;
+ AfterAttack;
+ exit
+ end;
+
+ HHGear^.Message := HHGear^.Message and (not (gmUp or gmPrecise or gmLeft or gmRight));
+ if abs(hwRound(HHGear^.Y - Gear^.Y)) > 32 then
+ begin
+ if Gear^.Timer = 0 then
+ Gear^.Y := Gear^.Y + _0_1
+ end
+ else if Gear^.Timer = 0 then
+ begin
+ Gear^.doStep := @doStepBirdyFly;
+ HHGear^.dY := -_0_2
+ end
+end;
+
+procedure doStepBirdyAppear(Gear: PGear);
+begin
+ Gear^.Pos := 0;
+ if Gear^.Timer < 2000 then
+ inc(Gear^.Timer, 1)
+ else
+ begin
+ Gear^.Timer := 500;
+ Gear^.dX := _0;
+ Gear^.dY := _0;
+ Gear^.State := Gear^.State and (not gstAnimation);
+ Gear^.doStep := @doStepBirdyDescend;
+ end
+end;
+
+procedure doStepBirdy(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ gear^.State := gear^.State or gstAnimation and (not gstTmpFlag);
+ Gear^.doStep := @doStepBirdyAppear;
+
+ if CurrentHedgehog = nil then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+
+ HHGear := CurrentHedgehog^.Gear;
+
+ if HHGear^.dX.isNegative then
+ Gear^.Tag := -1
+ else
+ Gear^.Tag := 1;
+ Gear^.Pos := 0;
+ AllInactive := false;
+ FollowGear := HHGear;
+ with HHGear^ do
+ begin
+ State := State and (not gstAttacking);
+ Message := Message and (not (gmAttack or gmUp or gmPrecise or gmLeft or gmRight))
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepEggWork(Gear: PGear);
+var
+ vg: PVisualGear;
+ i: LongInt;
+begin
+ AllInactive := false;
+ Gear^.dX := Gear^.dX;
+ doStepFallingGear(Gear);
+ // CheckGearDrowning(Gear); // already checked for in doStepFallingGear
+ CalcRotationDirAngle(Gear);
+
+ if (Gear^.State and gstCollision) <> 0 then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, Gear^.Hedgehog, EXPLPoisoned, $C0E0FFE0);
+ PlaySound(sndEggBreak);
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
+ vg := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
+ if vg <> nil then
+ vg^.Frame := 2;
+
+ for i:= 10 downto 0 do
+ begin
+ vg := AddVisualGear(hwRound(Gear^.X) - 3 + Random(6), hwRound(Gear^.Y) - 3 + Random(6),
+ vgtDust);
+ if vg <> nil then
+ vg^.dX := vg^.dX + (Gear^.dX.QWordValue / 21474836480);
+ end;
+
+ DeleteGear(Gear);
+ exit
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doPortalColorSwitch();
+var CurWeapon: PAmmo;
+begin
+ if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and ((CurrentHedgehog^.Gear^.Message and gmSwitch) <> 0) then
+ with CurrentHedgehog^ do
+ if (CurAmmoType = amPortalGun) then
+ begin
+ CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and (not gmSwitch);
+
+ CurWeapon:= GetCurAmmoEntry(CurrentHedgehog^);
+ if CurWeapon^.Pos <> 0 then
+ CurWeapon^.Pos := 0
+
+ else
+ CurWeapon^.Pos := 1;
+ end;
+end;
+
+procedure doStepPortal(Gear: PGear);
+var
+ iterator, conPortal: PGear;
+ s, r, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed,
+ resetx, resety, resetdx, resetdy: hwFloat;
+ sx, sy, rh, resetr: LongInt;
+ hasdxy, isbullet, iscake, isCollision: Boolean;
+begin
+ doPortalColorSwitch();
+
+ // destroy portal if ground it was attached too is gone
+ if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] <= lfAllObjMask)
+ or (Gear^.Timer < 1)
+ or (Gear^.Hedgehog^.Team <> CurrentHedgehog^.Team)
+ or (hwRound(Gear^.Y) > cWaterLine) then
+ begin
+ deleteGear(Gear);
+ EXIT;
+ end;
+
+ if (TurnTimeLeft < 1)
+ or (Gear^.Health < 1) then
+ dec(Gear^.Timer);
+
+ if Gear^.Timer < 10000 then
+ gear^.RenderTimer := true;
+
+ // abort if there is no other portal connected to this one
+ if (Gear^.LinkedGear = nil) then
+ exit;
+ if ((Gear^.LinkedGear^.Tag and 1) = 0) then // or if it's still moving;
+ exit;
+
+ conPortal := Gear^.LinkedGear;
+
+ // check all gears for stuff to port through
+ iterator := nil;
+ while true do
+ begin
+
+ // iterate through GearsList
+ if iterator = nil then
+ iterator := GearsList
+ else
+ iterator := iterator^.NextGear;
+
+ // end of list?
+ if iterator = nil then
+ break;
+
+ // don't port portals or other gear that wouldn't make sense
+ if (iterator^.Kind in [gtPortal, gtRope, gtAirAttack, gtIceGun])
+ or (iterator^.PortalCounter > 32) then
+ continue;
+
+ // don't port hogs on rope
+ // TODO: this will also prevent hogs while falling after rope use from
+ // falling through portals... fix that!
+
+ // check if gear fits through portal
+ if (iterator^.Radius > Gear^.Radius) then
+ continue;
+
+ // this is the max range we accept incoming gears in
+ r := Int2hwFloat(iterator^.Radius+Gear^.Radius);
+
+ // too far away?
+ if (iterator^.X < Gear^.X - r)
+ or (iterator^.X > Gear^.X + r)
+ or (iterator^.Y < Gear^.Y - r)
+ or (iterator^.Y > Gear^.Y + r) then
+ continue;
+
+ hasdxy := (((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0)) or ((iterator^.State or gstMoving) = 0));
+
+ // in case the object is not moving, let's asume it's falling towards the portal
+ if not hasdxy then
+ begin
+ if Gear^.Y < iterator^.Y then
+ continue;
+ ox:= Gear^.X - iterator^.X;
+ oy:= Gear^.Y - iterator^.Y;
+ end
+ else
+ begin
+ ox:= iterator^.dX;
+ oy:= iterator^.dY;
+ end;
+
+ // cake will need extra treatment... it's so delicious and moist!
+ iscake:= (iterator^.Kind = gtCake);
+
+ // won't port stuff that does not move towards the front/portal entrance
+ if iscake then
+ begin
+ if not (((iterator^.X - Gear^.X)*ox + (iterator^.Y - Gear^.Y)*oy).isNegative) then
+ continue;
+ end
+ else
+ if not ((Gear^.dX*ox + Gear^.dY*oy).isNegative) then
+ continue;
+
+ isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]);
+
+ r:= int2hwFloat(iterator^.Radius);
+
+ if not (isbullet or iscake) then
+ begin
+ // wow! good candidate there, let's see if the distance and direction is okay!
+ if hasdxy then
+ begin
+ s := Distance(iterator^.dX, iterator^.dY);
+ // if the resulting distance is 0 skip this gear
+ if s.QWordValue = 0 then
+ continue;
+ s := r / s;
+ ox:= iterator^.X + s * iterator^.dX;
+ oy:= iterator^.Y + s * iterator^.dY;
+ end
+ else
+ begin
+ ox:= iterator^.X;
+ oy:= iterator^.Y + r;
+ end;
+
+ if (hwRound(Distance(Gear^.X-ox,Gear^.Y-oy)) > Gear^.Radius + 1 ) then
+ continue;
+ end;
+
+ // draw bullet trail
+ if isbullet then
+ spawnBulletTrail(iterator);
+
+ // calc gear offset in portal vector direction
+ ox := (iterator^.X - Gear^.X);
+ oy := (iterator^.Y - Gear^.Y);
+ poffs:= (Gear^.dX * ox + Gear^.dY * oy);
+
+ if not isBullet and poffs.isNegative then
+ continue;
+
+ // only port bullets close to the portal
+ if isBullet and (not (hwAbs(poffs) < _3)) then
+ continue;
+
+ //
+ // gears that make it till here will definately be ported
+ //
+ // (but old position/movement vector might be restored in case there's
+ // not enough space on the other side)
+ //
+
+ resetr := iterator^.Radius;
+ resetx := iterator^.X;
+ resety := iterator^.Y;
+ resetdx := iterator^.dX;
+ resetdy := iterator^.dY;
+
+ // create a normal of the portal vector, but ...
+ nx := Gear^.dY;
+ ny := Gear^.dX;
+ // ... decide where the top is based on the hog's direction when firing the portal
+ if Gear^.Elasticity.isNegative then
+ nx.isNegative := (not nx.isNegative)
+ else
+ ny.isNegative := not ny.isNegative;
+
+ // calc gear offset in portal normal vector direction
+ noffs:= (nx * ox + ny * oy);
+
+ if isBullet and (noffs.Round >= Longword(Gear^.Radius)) then
+ continue;
+
+ // avoid gravity related loops of not really moving gear
+ if not (iscake or isbullet)
+ and (Gear^.dY.isNegative)
+ and (conPortal^.dY.isNegative)
+ and ((iterator^.dX.QWordValue + iterator^.dY.QWordValue) < _0_08.QWordValue)
+ and (iterator^.PortalCounter > 0) then
+ continue;
+
+ // calc gear speed along to the vector and the normal vector of the portal
+ if hasdxy then
+ begin
+ pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY);
+ nspeed:= (nx * iterator^.dX + ny * iterator^.dY);
+ end
+ else
+ begin
+ pspeed:= hwAbs(cGravity * oy);
+ nspeed:= _0;
+ end;
+
+ // creating normal vector of connected (exit) portal
+ nx := conPortal^.dY;
+ ny := conPortal^.dX;
+ if conPortal^.Elasticity.isNegative then
+ nx.isNegative := (not nx.isNegative)
+ else
+ ny.isNegative := not ny.isNegative;
+
+ // inverse cake's normal movement direction,
+ // as if it just walked through a hole
+ //if iscake then nspeed.isNegative:= not nspeed.isNegative;
+
+//AddFileLog('poffs:'+cstr(poffs)+' noffs:'+cstr(noffs)+' pspeed:'+cstr(pspeed)+' nspeed:'+cstr(nspeed));
+ iterator^.dX := -pspeed * conPortal^.dX + nspeed * nx;
+ iterator^.dY := -pspeed * conPortal^.dY + nspeed * ny;
+
+ // make the gear's exit position close to the portal while
+ // still respecting the movement direction
+
+ // determine the distance (in exit vector direction)
+ // that we want the gear at
+ if iscake then
+ ox:= (r - _0_7)
+ else
+ ox:= (r * _1_5);
+ s:= ox / poffs;
+ poffs:= ox;
+ if (nspeed.QWordValue <> 0)
+ and (pspeed > _0) then
+ noffs:= noffs * s * (nspeed / pspeed);
+
+ // move stuff with high normal offset closer to the portal's center
+ if not isbullet then
+ begin
+ s := hwAbs(noffs) + r - int2hwFloat(Gear^.Radius);
+ if s > _0 then
+ noffs:= noffs - SignAs(s,noffs)
+ end;
+
+ iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx;
+ iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny;
+
+ if not hasdxy and (not (conPortal^.dY.isNegative)) then
+ begin
+ iterator^.dY:= iterator^.dY + hwAbs(cGravity * (iterator^.Y - conPortal^.Y))
+ end;
+
+ // see if the space on the exit side actually is enough
+
+ if not (isBullet or isCake) then
+ begin
+ // TestCollisionXwithXYShift requires a hwFloat for xShift
+ ox.QWordValue := _1.QWordValue;
+ ox.isNegative := not iterator^.dX.isNegative;
+
+ sx := hwSign(iterator^.dX);
+ sy := hwSign(iterator^.dY);
+
+ if iterator^.Radius > 1 then
+ iterator^.Radius := iterator^.Radius - 1;
+
+ // check front
+ isCollision := (TestCollisionY(iterator, sy) <> 0) or (TestCollisionX(iterator, sx) <> 0);
+
+ if not isCollision then
+ begin
+ // check center area (with half the radius so that the
+ // the square check won't check more pixels than we want to)
+ iterator^.Radius := 1 + resetr div 2;
+ rh := resetr div 4;
+ isCollision := (TestCollisionYwithXYShift(iterator, 0, -sy * rh, sy, false) <> 0)
+ or (TestCollisionXwithXYShift(iterator, ox * rh, 0, sx, false) <> 0);
+ end;
+
+ iterator^.Radius := resetr;
+
+ if isCollision then
+ begin
+ // collision! oh crap! go back!
+ iterator^.X := resetx;
+ iterator^.Y := resety;
+ iterator^.dX := resetdx;
+ iterator^.dY := resetdy;
+ continue;
+ end;
+ end;
+
+ //
+ // You're now officially portaled!
+ //
+
+ // Until loops are reliably broken
+ if iscake then
+ iterator^.PortalCounter:= 33
+ else
+ begin
+ inc(iterator^.PortalCounter);
+ iterator^.Active:= true;
+ iterator^.State:= iterator^.State and (not gstHHHJump) or gstMoving;
+ end;
+
+ // is it worth adding an arcsin table? Just how often would we end up doing something like this?
+ // SYNCED ANGLE UPDATE
+ if iterator^.Kind = gtRCPlane then
+ begin
+ // recycling as temp vars
+ resety.isNegative:= false;
+ resety.QWordValue:= 4294967296 * 112;
+ resetx.isNegative:= false;
+ resetx.QWordValue:= 4294967296 * 35;
+ resetdx.isNegative:= false;
+ resetdx.QWordValue:= 4294967296 * 1152;
+
+ resetdy:=hwAbs(iterator^.dX*4);
+ resetdy:= resetdy + hwPow(resetdy,3)/_6 + _3 * hwPow(resetdy,5) / _40 + _5 * hwPow(resetdy,7) / resety + resetx * hwPow(resetdy,9) / resetdx;
+ iterator^.Angle:= hwRound(resetdy*_2048 / _PI);
+ if not iterator^.dY.isNegative then iterator^.Angle:= 2048-iterator^.Angle;
+ if iterator^.dX.isNegative then iterator^.Angle:= 4096-iterator^.Angle;
+ end
+ // VISUAL USE OF ANGLE ONLY
+ else if (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtKamikaze) and (CurAmmoGear^.Hedgehog = iterator^.Hedgehog) then
+ begin
+ iterator^.Angle:= DxDy2AttackAngle(iterator^.dX, iterator^.dY);
+ iterator^.Angle:= 2048-iterator^.Angle;
+ if iterator^.dX.isNegative then iterator^.Angle:= 4096-iterator^.Angle;
+ end;
+
+ if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
+ and (iterator = CurrentHedgehog^.Gear)
+ and (CurAmmoGear <> nil)
+ and (CurAmmoGear^.Kind = gtRope)
+ and (CurAmmoGear^.Elasticity <> _0) then
+ CurAmmoGear^.PortalCounter:= 1;
+
+ if not isbullet and (iterator^.State and gstInvisible = 0)
+ and (iterator^.Kind <> gtFlake) then
+ FollowGear := iterator;
+
+ // store X/Y values of exit for net bullet trail
+ if isbullet then
+ begin
+ iterator^.Elasticity:= iterator^.X;
+ iterator^.Friction := iterator^.Y;
+ end;
+
+ if Gear^.Health > 1 then
+ dec(Gear^.Health);
+ end;
+end;
+
+
+
+procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
+var
+ CurWeapon: PAmmo;
+begin
+ if CurrentHedgehog <> nil then
+ with CurrentHedgehog^ do
+ begin
+ CurWeapon:= GetCurAmmoEntry(CurrentHedgehog^);
+ if (CurAmmoType = amPortalGun) then
+ begin
+ if not destroyGear then
+ begin
+ // switch color of ball to opposite of oldPortal
+ if (oldPortal^.Tag and 2) = 0 then
+ CurWeapon^.Pos:= 1
+ else
+ CurWeapon^.Pos:= 0;
+ end;
+
+ // make the ball visible
+ CurWeapon^.Timer := 0;
+ end
+ end;
+ if destroyGear then
+ oldPortal^.Timer:= 0;
+end;
+
+procedure doStepMovingPortal_real(Gear: PGear);
+var
+ x, y, tx, ty: LongInt;
+ s: hwFloat;
+begin
+ WorldWrap(Gear);
+ x := hwRound(Gear^.X);
+ y := hwRound(Gear^.Y);
+ tx := 0;
+ ty := 0;
+ // avoid compiler hints
+
+ if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then
+ begin
+ Gear^.State := Gear^.State or gstCollision;
+ Gear^.State := Gear^.State and (not gstMoving);
+
+ if (Land[y, x] and lfBouncy <> 0)
+ or (not CalcSlopeTangent(Gear, x, y, tx, ty, 255))
+ or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
+ begin
+ loadNewPortalBall(Gear, true);
+ EXIT;
+ end;
+
+ // making a normalized normal vector
+ s := _1/DistanceI(tx,ty);
+ Gear^.dX := s * ty;
+ Gear^.dY := -s * tx;
+
+ Gear^.DirAngle := DxDy2Angle(-Gear^.dY,Gear^.dX);
+ if not Gear^.dX.isNegative then
+ Gear^.DirAngle := 180-Gear^.DirAngle;
+
+ if ((Gear^.LinkedGear = nil)
+ or (hwRound(Distance(Gear^.X - Gear^.LinkedGear^.X,Gear^.Y-Gear^.LinkedGear^.Y)) >=Gear^.Radius*2)) then
+ begin
+ loadNewPortalBall(Gear, false);
+ inc(Gear^.Tag);
+ Gear^.doStep := @doStepPortal;
+ end
+ else
+ loadNewPortalBall(Gear, true);
+ end
+
+ else if (y > cWaterLine)
+ or (y < -max(LAND_WIDTH,4096))
+ or (x > 2*max(LAND_WIDTH,4096))
+ or (x < -max(LAND_WIDTH,4096)) then
+ loadNewPortalBall(Gear, true);
+end;
+
+procedure doStepMovingPortal(Gear: PGear);
+begin
+ doPortalColorSwitch();
+ doStepPerPixel(Gear, @doStepMovingPortal_real, true);
+ if (Gear^.Timer < 1)
+ or (Gear^.Hedgehog^.Team <> CurrentHedgehog^.Team) then
+ deleteGear(Gear);
+end;
+
+procedure doStepPortalShot(newPortal: PGear);
+var
+ iterator: PGear;
+ s: hwFloat;
+ CurWeapon: PAmmo;
+begin
+ s:= Distance (newPortal^.dX, newPortal^.dY);
+
+ // Adds the hog speed (only that part in/directly against shot direction)
+ // to the shot speed (which we triple previously btw)
+ // (This is done my projecting the hog movement vector onto the shot movement vector and then adding the resulting length
+ // to the scaler)
+ s := (_2 * s + (newPortal^.dX * CurrentHedgehog^.Gear^.dX + newPortal^.dY * CurrentHedgehog^.Gear^.dY ) / s) / s;
+ newPortal^.dX := newPortal^.dX * s;
+ newPortal^.dY := newPortal^.dY * s;
+
+ newPortal^.LinkedGear := nil;
+
+ if CurrentHedgehog <> nil then
+ with CurrentHedgehog^ do
+ begin
+ CurWeapon:= GetCurAmmoEntry(CurrentHedgehog^);
+ // let's save the HH's dX's direction so we can decide where the "top" of the portal hole
+ newPortal^.Elasticity.isNegative := CurrentHedgehog^.Gear^.dX.isNegative;
+ // when doing a backjump the dx is the opposite of the facing direction
+ if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then
+ newPortal^.Elasticity.isNegative := not newPortal^.Elasticity.isNegative;
+
+ // make portal gun look unloaded
+ if (CurWeapon <> nil) and (CurAmmoType = amPortalGun) then
+ CurWeapon^.Timer := CurWeapon^.Timer or 2;
+
+ iterator := GearsList;
+ while iterator <> nil do
+ begin
+ if (iterator^.Kind = gtPortal) then
+ if (iterator <> newPortal) and (iterator^.Timer > 0) and (iterator^.Hedgehog = CurrentHedgehog) then
+ begin
+ if ((iterator^.Tag and 2) = (newPortal^.Tag and 2)) then
+ begin
+ iterator^.Timer:= 0;
+ end
+ else
+ begin
+ // link portals with each other
+ newPortal^.LinkedGear := iterator;
+ iterator^.LinkedGear := newPortal;
+ iterator^.Health := newPortal^.Health;
+ end;
+ end;
+ iterator^.PortalCounter:= 0;
+ iterator := iterator^.NextGear
+ end;
+
+ if newPortal^.LinkedGear <> nil then
+ begin
+ // This jiggles gears, to ensure a portal connection just placed under a gear takes effect.
+ iterator:= GearsList;
+ while iterator <> nil do
+ begin
+ if not (iterator^.Kind in [gtPortal, gtAirAttack, gtKnife]) and ((iterator^.Hedgehog <> CurrentHedgehog)
+ or ((iterator^.Message and gmAllStoppable) = 0)) then
+ begin
+ iterator^.Active:= true;
+ if iterator^.dY.QWordValue = 0 then
+ iterator^.dY.isNegative:= false;
+ iterator^.State:= iterator^.State or gstMoving;
+ DeleteCI(iterator);
+ //inc(iterator^.dY.QWordValue,10);
+ end;
+ iterator:= iterator^.NextGear
+ end
+ end
+ end;
+ newPortal^.State := newPortal^.State and (not gstCollision);
+ newPortal^.State := newPortal^.State or gstMoving;
+ newPortal^.doStep := @doStepMovingPortal;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepPiano(Gear: PGear);
+var
+ r0, r1: LongInt;
+ odY: hwFloat;
+begin
+ AllInactive := false;
+ if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and
+ ((CurrentHedgehog^.Gear^.Message and gmSlot) <> 0) then
+ begin
+ case CurrentHedgehog^.Gear^.MsgParam of
+ 0: PlaySound(sndPiano0);
+ 1: PlaySound(sndPiano1);
+ 2: PlaySound(sndPiano2);
+ 3: PlaySound(sndPiano3);
+ 4: PlaySound(sndPiano4);
+ 5: PlaySound(sndPiano5);
+ 6: PlaySound(sndPiano6);
+ 7: PlaySound(sndPiano7);
+ else PlaySound(sndPiano8);
+ end;
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtNote);
+ CurrentHedgehog^.Gear^.MsgParam := 0;
+ CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and (not gmSlot);
+ end;
+
+ if (*((Gear^.Pos = 3) and ((GameFlags and gfSolidLand) <> 0)) or*) (Gear^.Pos = 5) then
+ begin
+ Gear^.dY := Gear^.dY + cGravity * 2;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ if CheckGearDrowning(Gear) then
+ begin
+ Gear^.Y:= Gear^.Y + _50;
+ OnUsedAmmo(CurrentHedgehog^);
+ if CurrentHedgehog^.Gear <> nil then
+ begin
+ // Drown the hedgehog. Could also just delete it, but hey, this gets a caption
+ CurrentHedgehog^.Gear^.Active := true;
+ CurrentHedgehog^.Gear^.X := Gear^.X;
+ CurrentHedgehog^.Gear^.Y := int2hwFloat(cWaterLine+cVisibleWater)+_128;
+ CurrentHedgehog^.Unplaced := false;
+ if TagTurnTimeLeft = 0 then
+ TagTurnTimeLeft:= TurnTimeLeft;
+ TurnTimeLeft:= 0
+ end;
+ ResumeMusic
+ end;
+ exit
+ end;
+
+ odY:= Gear^.dY;
+ doStepFallingGear(Gear);
+
+ if (Gear^.State and gstDrowning) <> 0 then
+ begin
+ Gear^.Y:= Gear^.Y + _50;
+ OnUsedAmmo(CurrentHedgehog^);
+ if CurrentHedgehog^.Gear <> nil then
+ begin
+ // Drown the hedgehog. Could also just delete it, but hey, this gets a caption
+ CurrentHedgehog^.Gear^.Active := true;
+ CurrentHedgehog^.Gear^.X := Gear^.X;
+ CurrentHedgehog^.Gear^.Y := int2hwFloat(cWaterLine+cVisibleWater)+_128;
+ CurrentHedgehog^.Unplaced := false;
+ if TagTurnTimeLeft = 0 then
+ TagTurnTimeLeft:= TurnTimeLeft;
+ TurnTimeLeft:= 0
+ end;
+ ResumeMusic
+ end
+ else if (Gear^.State and gstCollision) <> 0 then
+ begin
+ r0 := GetRandom(21);
+ r1 := GetRandom(21);
+ doMakeExplosion(hwRound(Gear^.X) - 30 - r0, hwRound(Gear^.Y) + 40, 40 + r1, Gear^.Hedgehog, 0);
+ doMakeExplosion(hwRound(Gear^.X) + 30 + r1, hwRound(Gear^.Y) + 40, 40 + r0, Gear^.Hedgehog, 0);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 80 + r0, Gear^.Hedgehog, EXPLAutoSound);
+ for r0:= 0 to 4 do
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtNote);
+ Gear^.dY := cGravity * 2 - odY;
+ Gear^.Pos := Gear^.Pos + 1;
+ end
+ else
+ Gear^.dY := Gear^.dY + cGravity * 2;
+ // let it fall faster so itdoesn't take too long for the whole attack
+end;
+
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSineGunShotWork(Gear: PGear);
+var
+ x, y, rX, rY, t, tmp, initHealth: LongInt;
+ oX, oY, ldX, ldY, sdX, sdY, sine, lx, ly, amp: hwFloat;
+ justCollided: boolean;
+begin
+ AllInactive := false;
+ initHealth := Gear^.Health;
+ lX := Gear^.X;
+ lY := Gear^.Y;
+ ldX := Gear^.dX;
+ ldY := Gear^.dY;
+ sdy := _0_5/Distance(Gear^.dX,Gear^.dY);
+ ldX := ldX * sdy;
+ ldY := ldY * sdy;
+ sdY := hwAbs(ldX) + hwAbs(ldY);
+ sdX := _1 - hwAbs(ldX/sdY);
+ sdY := _1 - hwAbs(ldY/sdY);
+ if (ldX.isNegative = ldY.isNegative) then
+ sdY := -sdY;
+
+ // initial angle depends on current GameTicks
+ t := getRandom(4096);
+
+
+ // used for a work-around detection of area that is within land array, but outside borders
+ justCollided := false;
+
+ repeat
+ lX := lX + ldX;
+ lY := lY + ldY;
+ oX := Gear^.X;
+ oY := Gear^.Y;
+ rX := hwRound(oX);
+ rY := hwRound(oY);
+ tmp := t mod 4096;
+ amp := _128 * (_1 - hwSqr(int2hwFloat(Gear^.Health)/initHealth));
+ sine := amp * AngleSin(tmp mod 2048);
+ sine.isNegative := (tmp < 2048);
+ inc(t,Gear^.Health div 313);
+ Gear^.X := lX + (sine * sdX);
+ Gear^.Y := ly + (sine * sdY);
+ Gear^.dX := Gear^.X - oX;
+ Gear^.dY := Gear^.Y - oY;
+
+ x := hwRound(Gear^.X);
+ y := hwRound(Gear^.Y);
+
+ // if borders are on, stop outside land array
+ if hasBorder and (((x and LAND_WIDTH_MASK) <> 0) or ((y and LAND_HEIGHT_MASK) <> 0)) then
+ begin
+ Gear^.Damage := 0;
+ Gear^.Health := 0;
+ end
+ else
+ begin
+ if (rY <= cWaterLine) or (y <= cWaterLine) then
+ begin
+ if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0)
+ and (Land[y, x] <> 0) then
+ begin
+ if justCollided then
+ begin
+ Gear^.Damage := 0;
+ Gear^.Health := 0;
+ end
+ else
+ begin
+ inc(Gear^.Damage,3);
+ justCollided := true;
+ end;
+ end
+ else
+ justCollided := false;
+
+ // kick nearby hogs, dig tunnel and add some fire
+ // if at least 5 collisions occured
+ if Gear^.Damage > 0 then
+ begin
+ DrawExplosion(rX,rY,Gear^.Radius);
+
+ // kick nearby hogs
+ AmmoShove(Gear, 35, 50);
+
+ dec(Gear^.Health, Gear^.Damage);
+ Gear^.Damage := 0;
+
+ // add some fire to the tunnel
+ if getRandom(6) = 0 then
+ begin
+ tmp:= GetRandom(2 * Gear^.Radius);
+ AddGear(x - Gear^.Radius + tmp, y - GetRandom(Gear^.Radius + 1), gtFlame, gsttmpFlag, _0, _0, 0)
+ end
+ end;
+
+ if random(100) = 0 then
+ AddVisualGear(x, y, vgtSmokeTrace);
+ end
+ else dec(Gear^.Health, 5); // if underwater get additional damage
+ end;
+
+ dec(Gear^.Health);
+
+ // decrease bullet size towards the end
+ if (Gear^.Radius > 4) then
+ begin
+ if (Gear^.Health <= (initHealth div 3)) then
+ dec(Gear^.Radius)
+ end
+ else if (Gear^.Radius > 3) then
+ begin
+ if (Gear^.Health <= (initHealth div 4)) then
+ dec(Gear^.Radius)
+ end
+ else if (Gear^.Radius > 2) then begin
+ if (Gear^.Health <= (initHealth div 5)) then
+ dec(Gear^.Radius)
+ end
+ else if (Gear^.Radius > 1) then
+ begin
+ if (Gear^.Health <= (initHealth div 6)) then
+ dec(Gear^.Radius)
+ end;
+
+ until (Gear^.Health <= 0);
+
+ DeleteGear(Gear);
+ AfterAttack;
+end;
+
+procedure doStepSineGunShot(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ PlaySound(sndSineGun);
+
+ // push the shooting Hedgehog back
+ HHGear := CurrentHedgehog^.Gear;
+ Gear^.dX.isNegative := not Gear^.dX.isNegative;
+ Gear^.dY.isNegative := not Gear^.dY.isNegative;
+ HHGear^.dX := Gear^.dX;
+ HHGear^.dY := Gear^.dY;
+ AmmoShove(Gear, 0, 80);
+ Gear^.dX.isNegative := not Gear^.dX.isNegative;
+ Gear^.dY.isNegative := not Gear^.dY.isNegative;
+
+ Gear^.doStep := @doStepSineGunShotWork;
+ with mobileRecord do
+ if (performRumble <> nil) and (not fastUntilLag) then
+ performRumble(kSystemSoundID_Vibrate);
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepFlamethrowerWork(Gear: PGear);
+var
+ HHGear, flame: PGear;
+ rx, ry, speed: hwFloat;
+ i, gX, gY: LongInt;
+begin
+ AllInactive := false;
+ HHGear := Gear^.Hedgehog^.Gear;
+ HedgehogChAngle(HHGear);
+ gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
+ gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
+
+ if (GameTicks and $FF) = 0 then
+ begin
+ if (HHGear^.Message and gmRight) <> 0 then
+ begin
+ if HHGear^.dX.isNegative and (Gear^.Tag < 20) then
+ inc(Gear^.Tag)
+ else if Gear^.Tag > 5 then
+ dec(Gear^.Tag);
+ end
+ else if (HHGear^.Message and gmLeft) <> 0 then
+ begin
+ if HHGear^.dX.isNegative and (Gear^.Tag > 5) then
+ dec(Gear^.Tag)
+ else if Gear^.Tag < 20 then
+ inc(Gear^.Tag);
+ end
+ end;
+
+ dec(Gear^.Timer);
+ if Gear^.Timer = 0 then
+ begin
+ dec(Gear^.Health);
+ if (Gear^.Health mod 5) = 0 then
+ begin
+ rx := rndSign(getRandomf * _0_1);
+ ry := rndSign(getRandomf * _0_1);
+ speed := _0_5 * (_10 / Gear^.Tag);
+
+ flame:= AddGear(gx, gy, gtFlame, gstTmpFlag,
+ SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
+ AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
+ flame^.CollisionMask:= lfNotCurrentMask;
+
+ if (Gear^.Health mod 30) = 0 then
+ begin
+ flame:= AddGear(gx, gy, gtFlame, 0,
+ SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
+ AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
+ flame^.CollisionMask:= lfNotCurrentMask;
+ end
+ end;
+ Gear^.Timer:= Gear^.Tag
+ end;
+
+ if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) then
+ begin
+ DeleteGear(Gear);
+ AfterAttack
+ end
+ else
+ begin
+ i:= Gear^.Health div 5;
+ if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
+ begin
+ Gear^.Damage:= i;
+ FreeTexture(Gear^.Tex);
+ Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(i) +
+ '%', cWhiteColor, fntSmall)
+ end
+ end
+end;
+
+procedure doStepFlamethrower(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+ HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown or gmLeft or gmRight));
+ HHGear^.State := HHGear^.State or gstNotKickable;
+ Gear^.doStep := @doStepFlamethrowerWork
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepLandGunWork(Gear: PGear);
+var
+ HHGear, land: PGear;
+ rx, ry, speed: hwFloat;
+ i, gX, gY: LongInt;
+begin
+ AllInactive := false;
+ HHGear := Gear^.Hedgehog^.Gear;
+ HedgehogChAngle(HHGear);
+ gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
+ gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
+
+ if (GameTicks and $FF) = 0 then
+ begin
+ if (HHGear^.Message and gmRight) <> 0 then
+ begin
+ if HHGear^.dX.isNegative and (Gear^.Tag < 20) then
+ inc(Gear^.Tag)
+ else if Gear^.Tag > 5 then
+ dec(Gear^.Tag);
+ end
+ else if (HHGear^.Message and gmLeft) <> 0 then
+ begin
+ if HHGear^.dX.isNegative and (Gear^.Tag > 5) then
+ dec(Gear^.Tag)
+ else if Gear^.Tag < 20 then
+ inc(Gear^.Tag);
+ end
+ end;
+
+ dec(Gear^.Timer);
+ if Gear^.Timer = 0 then
+ begin
+ dec(Gear^.Health);
+
+ rx := rndSign(getRandomf * _0_1);
+ ry := rndSign(getRandomf * _0_1);
+ speed := (_3 / Gear^.Tag);
+
+ land:= AddGear(gx, gy, gtFlake, gstTmpFlag,
+ SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
+ AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
+ land^.CollisionMask:= lfNotCurrentMask;
+
+ Gear^.Timer:= Gear^.Tag
+ end;
+
+ if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) or ((HHGear^.Message and gmAttack) <> 0) then
+ begin
+ HHGear^.Message:= HHGear^.Message and (not gmAttack);
+ DeleteGear(Gear);
+ AfterAttack
+ end
+ else
+ begin
+ i:= Gear^.Health div 10;
+ if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
+ begin
+ Gear^.Damage:= i;
+ FreeTexture(Gear^.Tex);
+ Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(i) +
+ '%', cWhiteColor, fntSmall)
+ end
+ end
+end;
+
+procedure doStepLandGun(Gear: PGear);
+var
+ HHGear: PGear;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+ HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown or gmLeft or gmRight or gmAttack));
+ HHGear^.State := HHGear^.State or gstNotKickable;
+ Gear^.doStep := @doStepLandGunWork
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepPoisonCloud(Gear: PGear);
+begin
+ WorldWrap(Gear);
+ if Gear^.Timer = 0 then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+ dec(Gear^.Timer);
+ Gear^.X:= Gear^.X + Gear^.dX;
+ Gear^.Y:= Gear^.Y + Gear^.dY;
+ Gear^.dX := Gear^.dX + cWindSpeed / 4;
+ Gear^.dY := Gear^.dY + cGravity / 100;
+ if (GameTicks and $FF) = 0 then
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLDontDraw or EXPLNoGfx or EXPLNoDamage or EXPLDoNotTouchAny or EXPLPoisoned);
+ if Gear^.State and gstTmpFlag = 0 then
+ AllInactive:= false;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepHammer(Gear: PGear);
+var HHGear, tmp, tmp2: PGear;
+ t: PGearArray;
+ i: LongInt;
+begin
+HHGear:= Gear^.Hedgehog^.Gear;
+HHGear^.State:= HHGear^.State or gstNoDamage;
+DeleteCI(HHGear);
+
+t:= CheckGearsCollision(Gear);
+
+for i:= 5 downto 0 do
+ AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
+
+i:= t^.Count;
+while i > 0 do
+ begin
+ dec(i);
+ tmp:= t^.ar[i];
+ if (tmp^.State and gstNoDamage) = 0 then
+ if (tmp^.Kind = gtHedgehog) or (tmp^.Kind = gtMine) or (tmp^.Kind = gtExplosives) then
+ begin
+ //tmp^.State:= tmp^.State or gstFlatened;
+ if (tmp^.Hedgehog^.Effects[heInvulnerable] = 0) then
+ ApplyDamage(tmp, CurrentHedgehog, tmp^.Health div 3, dsUnknown);
+ //DrawTunnel(tmp^.X, tmp^.Y - _1, _0, _0_5, cHHRadius * 6, cHHRadius * 3);
+ tmp2:= AddGear(hwRound(tmp^.X), hwRound(tmp^.Y), gtHammerHit, 0, _0, _0, 0);
+ tmp2^.LinkedGear:= tmp;
+ SetAllToActive
+ end
+ else
+ begin
+ end
+ end;
+
+HHGear^.State:= HHGear^.State and (not gstNoDamage);
+Gear^.Timer:= 250;
+Gear^.doStep:= @doStepIdle
+end;
+
+procedure doStepHammerHitWork(Gear: PGear);
+var
+ i, j, ei: LongInt;
+ HitGear: PGear;
+begin
+ AllInactive := false;
+ HitGear := Gear^.LinkedGear;
+ dec(Gear^.Timer);
+ if (HitGear = nil) or (Gear^.Timer = 0) or ((Gear^.Message and gmDestroy) <> 0) then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+
+ if (Gear^.Timer mod 5) = 0 then
+ begin
+ AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
+
+ i := hwRound(Gear^.X) - HitGear^.Radius + 2;
+ ei := hwRound(Gear^.X) + HitGear^.Radius - 2;
+ for j := 1 to 4 do DrawExplosion(i - GetRandom(5), hwRound(Gear^.Y) + 6*j, 3);
+ for j := 1 to 4 do DrawExplosion(ei + LongInt(GetRandom(5)), hwRound(Gear^.Y) + 6*j, 3);
+ while i <= ei do
+ begin
+ for j := 1 to 11 do DrawExplosion(i, hwRound(Gear^.Y) + 3*j, 3);
+ inc(i, 1)
+ end;
+
+ if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9)
+ , lfIndestructible) then
+ begin
+ //Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + _1_9
+ end;
+ end;
+ if TestCollisionYwithGear(Gear, 1) <> 0 then
+ begin
+ Gear^.dY := _0;
+ SetLittle(HitGear^.dX);
+ HitGear^.dY := _0;
+ end
+ else
+ begin
+ //Gear^.dY := Gear^.dY + cGravity;
+ //Gear^.Y := Gear^.Y + Gear^.dY;
+ if hwRound(Gear^.Y) > cWaterLine then
+ Gear^.Timer := 1
+ end;
+
+ //Gear^.X := Gear^.X + HitGear^.dX;
+ HitGear^.X := Gear^.X;
+ HitGear^.Y := Gear^.Y;
+ SetLittle(HitGear^.dY);
+ HitGear^.Active:= true;
+end;
+
+procedure doStepHammerHit(Gear: PGear);
+var
+ i, y: LongInt;
+ ar: TRangeArray;
+ HHGear: PGear;
+begin
+ i := 0;
+ HHGear := Gear^.Hedgehog^.Gear;
+
+ y := hwRound(Gear^.Y) - cHHRadius * 2;
+ while y < hwRound(Gear^.Y) do
+ begin
+ ar[i].Left := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
+ ar[i].Right := hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
+ inc(y, 2);
+ inc(i)
+ end;
+
+ DrawHLinesExplosions(@ar, 3, hwRound(Gear^.Y) - cHHRadius * 2, 2, Pred(i));
+ Gear^.dY := HHGear^.dY;
+ DeleteCI(HHGear);
+
+ doStepHammerHitWork(Gear);
+ Gear^.doStep := @doStepHammerHitWork
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepResurrectorWork(Gear: PGear);
+var
+ graves: PGearArrayS;
+ resgear: PGear;
+ hh: PHedgehog;
+ i: LongInt;
+begin
+ if (TurnTimeLeft > 0) then
+ dec(TurnTimeLeft);
+
+ AllInactive := false;
+ hh := Gear^.Hedgehog;
+
+ // no, you can't do that here
+ {DrawCentered(hwRound(hh^.Gear^.X) + WorldDx, hwRound(hh^.Gear^.Y) + WorldDy -
+ cHHRadius - 14 - hh^.HealthTagTex^.h, hh^.HealthTagTex);
+ }
+ (*DrawCircle(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, 1.5, 0, 0, $FF,
+ $FF);*)
+
+ if ((Gear^.Message and gmUp) <> 0) then
+ begin
+ if (GameTicks and $F) <> 0 then
+ exit;
+ end
+ else if (GameTicks and $1FF) <> 0 then
+ exit;
+
+ if Gear^.Power < 45 then
+ begin
+ inc(Gear^.Power);
+ if TestCollisionYwithGear(hh^.Gear, -1) = 0 then
+ hh^.Gear^.Y := hh^.Gear^.Y - _1;
+ end;
+
+ graves := GearsNear(Gear^.X, Gear^.Y, gtGrave, Gear^.Radius);
+
+ if graves.size = 0 then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ Gear^.Timer := 250;
+ Gear^.doStep := @doStepIdle;
+ exit;
+ end;
+
+ if ((Gear^.Message and gmAttack) <> 0) and (hh^.Gear^.Health > 0) and (TurnTimeLeft > 0) then
+ begin
+ if LongInt(graves.size) <= Gear^.Tag then Gear^.Tag:= 0;
+ dec(hh^.Gear^.Health);
+ if (hh^.Gear^.Health = 0) and (hh^.Gear^.Damage = 0) then
+ hh^.Gear^.Damage:= 1;
+ RenderHealth(hh^);
+ RecountTeamHealth(hh^.Team);
+ inc(graves.ar^[Gear^.Tag]^.Health);
+ inc(Gear^.Tag)
+{-for i:= 0 to High(graves) do begin
+ if hh^.Gear^.Health > 0 then begin
+ dec(hh^.Gear^.Health);
+ inc(graves[i]^.Health);
+ end;
+ end; -}
+ end
+ else
+ begin
+ // now really resurrect the hogs with the hp saved in the graves
+ for i:= 0 to graves.size - 1 do
+ if graves.ar^[i]^.Health > 0 then
+ begin
+ resgear := AddGear(hwRound(graves.ar^[i]^.X), hwRound(graves.ar^[i]^.Y), gtHedgehog, gstWait, _0, _0, 0);
+ resgear^.Hedgehog := graves.ar^[i]^.Hedgehog;
+ resgear^.Health := graves.ar^[i]^.Health;
+ PHedgehog(graves.ar^[i]^.Hedgehog)^.Gear := resgear;
+ graves.ar^[i]^.Message:= graves.ar^[i]^.Message or gmDestroy;
+ graves.ar^[i]^.Active:= true;
+ RenderHealth(resgear^.Hedgehog^);
+ RecountTeamHealth(resgear^.Hedgehog^.Team);
+ resgear^.Hedgehog^.Effects[heResurrected]:= 1;
+ // only make hat-less hedgehogs look like zombies, preserve existing hats
+
+ if resgear^.Hedgehog^.Hat = 'NoHat' then
+ LoadHedgehogHat(resgear^.Hedgehog^, 'Reserved/Zombie');
+ end;
+
+ hh^.Gear^.dY := _0;
+ hh^.Gear^.dX := _0;
+ doStepHedgehogMoving(hh^.Gear);
+ StopSoundChan(Gear^.SoundChannel);
+ Gear^.Timer := 250;
+ Gear^.doStep := @doStepIdle;
+ end
+ //if hh^.Gear^.Health = 0 then doStepHedgehogFree(hh^.Gear);
+end;
+
+procedure doStepResurrector(Gear: PGear);
+var
+ graves: PGearArrayS;
+ hh: PHedgehog;
+ i: LongInt;
+begin
+ AllInactive := false;
+ graves := GearsNear(Gear^.X, Gear^.Y, gtGrave, Gear^.Radius);
+
+ if graves.size > 0 then
+ begin
+ hh := Gear^.Hedgehog;
+ for i:= 0 to graves.size - 1 do
+ begin
+ PHedgehog(graves.ar^[i]^.Hedgehog)^.Gear := nil;
+ graves.ar^[i]^.Health := 0;
+ end;
+ Gear^.doStep := @doStepResurrectorWork;
+ if ((Gear^.Message and gmAttack) <> 0) and (hh^.Gear^.Health > 0) and (TurnTimeLeft > 0) then
+ begin
+ if LongInt(graves.size) <= Gear^.Tag then Gear^.Tag:= 0;
+ dec(hh^.Gear^.Health);
+ if (hh^.Gear^.Health = 0) and (hh^.Gear^.Damage = 0) then
+ hh^.Gear^.Damage:= 1;
+ RenderHealth(hh^);
+ RecountTeamHealth(hh^.Team);
+ inc(graves.ar^[Gear^.Tag]^.Health);
+ inc(Gear^.Tag)
+ end
+ end
+ else
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ Gear^.Timer := 250;
+ Gear^.doStep := @doStepIdle;
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepNapalmBomb(Gear: PGear);
+var
+ i, gX, gY: LongInt;
+ dX, dY: hwFloat;
+begin
+ AllInactive := false;
+ doStepFallingGear(Gear);
+ if (Gear^.Timer > 0) and ((Gear^.State and gstCollision) <> 0) then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, Gear^.Hedgehog, EXPLAutoSound);
+ gX := hwRound(Gear^.X);
+ gY := hwRound(Gear^.Y);
+ for i:= 0 to 10 do
+ begin
+ dX := AngleCos(i * 2) * ((_0_1*(i div 5))) * (GetRandomf + _1);
+ dY := AngleSin(i * 8) * _0_5 * (GetRandomf + _1);
+ AddGear(gX, gY, gtFlame, 0, dX, dY, 0);
+ AddGear(gX, gY, gtFlame, 0, dX, -dY, 0);
+ AddGear(gX, gY, gtFlame, 0, -dX, dY, 0);
+ AddGear(gX, gY, gtFlame, 0, -dX, -dY, 0);
+ end;
+ DeleteGear(Gear);
+ exit
+ end;
+ if (Gear^.Timer = 0) then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, Gear^.Hedgehog, EXPLAutoSound);
+ for i:= -19 to 19 do
+ FollowGear := AddGear(hwRound(Gear^.X) + i div 3, hwRound(Gear^.Y), gtFlame, 0, _0_001 * i, _0, 0);
+ DeleteGear(Gear);
+ exit
+ end;
+ if (GameTicks and $3F) = 0 then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
+ dec(Gear^.Timer)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepStructure(Gear: PGear);
+var
+ x, y: LongInt;
+ HH: PHedgehog;
+ t: PGear;
+begin
+ HH:= Gear^.Hedgehog;
+
+ if (Gear^.State and gstMoving) <> 0 then
+ begin
+ AddCI(Gear);
+ Gear^.dX:= _0;
+ Gear^.dY:= _0;
+ Gear^.State:= Gear^.State and (not gstMoving);
+ end;
+
+ dec(Gear^.Health, Gear^.Damage);
+ Gear^.Damage:= 0;
+
+ if Gear^.Pos = 1 then
+ begin
+ AddCI(Gear);
+ AfterAttack;
+ if Gear = CurAmmoGear then
+ CurAmmoGear:= nil;
+ if HH^.Gear <> nil then
+ HideHog(HH);
+ Gear^.Pos:= 2
+ end;
+
+ if Gear^.Pos = 2 then
+ begin
+ if ((GameTicks mod 100) = 0) and (Gear^.Timer < 1000) then
+ begin
+ if (Gear^.Timer mod 10) = 0 then
+ begin
+ DeleteCI(Gear);
+ Gear^.Y:= Gear^.Y - _0_5;
+ AddCI(Gear);
+ end;
+ inc(Gear^.Timer);
+ end;
+ if Gear^.Tag <= TotalRounds then
+ Gear^.Pos:= 3;
+ end;
+
+ if Gear^.Pos = 3 then
+ if Gear^.Timer < 1000 then
+ begin
+ if (Gear^.Timer mod 10) = 0 then
+ begin
+ DeleteCI(Gear);
+ Gear^.Y:= Gear^.Y - _0_5;
+ AddCI(Gear);
+ end;
+ inc(Gear^.Timer);
+ end
+ else
+ begin
+ if HH^.GearHidden <> nil then
+ RestoreHog(HH);
+ Gear^.Pos:= 4;
+ end;
+
+ if Gear^.Pos = 4 then
+ if ((GameTicks mod 1000) = 0) and ((GameFlags and gfInvulnerable) = 0) then
+ begin
+ t:= GearsList;
+ while t <> nil do
+ begin
+ if (t^.Kind = gtHedgehog) and (t^.Hedgehog^.Team^.Clan = HH^.Team^.Clan) then
+ t^.Hedgehog^.Effects[heInvulnerable]:= 1;
+ t:= t^.NextGear;
+ end;
+ end;
+
+ if Gear^.Health <= 0 then
+ begin
+ if HH^.GearHidden <> nil then
+ RestoreHog(HH);
+
+ x := hwRound(Gear^.X);
+ y := hwRound(Gear^.Y);
+
+ DeleteCI(Gear);
+ DeleteGear(Gear);
+
+ doMakeExplosion(x, y, 50, CurrentHedgehog, EXPLAutoSound);
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+(*
+ TARDIS needs
+ Warp in. Pos = 1
+ Pause. Pos = 2
+ Hide gear (TARDIS hedgehog was nil)
+ Warp out. Pos = 3
+ ... idle active for some time period ... Pos = 4
+ Warp in. Pos = 1
+ Pause. Pos = 2
+ Restore gear (TARDIS hedgehog was not nil)
+ Warp out. Pos = 3
+*)
+
+procedure doStepTardisWarp(Gear: PGear);
+var HH: PHedgehog;
+ i,j,cnt: LongWord;
+begin
+HH:= Gear^.Hedgehog;
+if Gear^.Pos = 2 then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ if (Gear^.Timer = 0) then
+ begin
+ if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible = 0) then
+ begin
+ AfterAttack;
+ if Gear = CurAmmoGear then CurAmmoGear := nil;
+ if (HH^.Gear^.Damage = 0) and (HH^.Gear^.Health > 0) and
+ ((Gear^.State and (gstMoving or gstHHDeath or gstHHGone)) = 0) then
+ HideHog(HH)
+ end
+ //else if (HH^.Gear <> nil) and (HH^.Gear^.State and gstInvisible <> 0) then
+ else if (HH^.GearHidden <> nil) then// and (HH^.Gear^.State and gstInvisible <> 0) then
+ RestoreHog(HH)
+ end;
+
+ inc(Gear^.Timer);
+ if (Gear^.Timer > 2000) and ((GameTicks mod 2000) = 1000) then
+ begin
+ Gear^.SoundChannel := LoopSound(sndTardis);
+ Gear^.Pos:= 3
+ end
+ end;
+
+if (Gear^.Pos = 1) and (GameTicks and $1F = 0) and (Gear^.Power < 255) then
+ begin
+ inc(Gear^.Power);
+ if (Gear^.Power = 172) and (HH^.Gear <> nil) and
+ (HH^.Gear^.Damage = 0) and (HH^.Gear^.Health > 0) and
+ ((HH^.Gear^.State and (gstMoving or gstHHDeath or gstHHGone)) = 0) then
+ with HH^.Gear^ do
+ begin
+ State:= State or gstAnimation;
+ Tag:= 2;
+ Timer:= 0;
+ Pos:= 0
+ end
+ end;
+if (Gear^.Pos = 3) and (GameTicks and $1F = 0) and (Gear^.Power > 0) then
+ dec(Gear^.Power);
+if (Gear^.Pos = 1) and (Gear^.Power = 255) and ((GameTicks mod 2000) = 1000) then
+ Gear^.Pos:= 2;
+if (Gear^.Pos = 3) and (Gear^.Power = 0) then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ if HH^.GearHidden = nil then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+ Gear^.Pos:= 4;
+ // This condition might need tweaking
+ Gear^.Timer:= GetRandom(cHedgehogTurnTime*TeamsCount)+cHedgehogTurnTime
+ end;
+
+if (Gear^.Pos = 4) then
+ begin
+ cnt:= 0;
+ for j:= 0 to Pred(HH^.Team^.Clan^.TeamsNumber) do
+ with HH^.Team^.Clan^.Teams[j]^ do
+ for i:= 0 to Pred(HedgehogsNumber) do
+ if (Hedgehogs[i].Gear <> nil)
+ and ((Hedgehogs[i].Gear^.State and gstDrowning) = 0)
+ and (Hedgehogs[i].Gear^.Health > Hedgehogs[i].Gear^.Damage) then
+ inc(cnt);
+ if (cnt = 0) or SuddenDeathDmg or (Gear^.Timer = 0) then
+ begin
+ if HH^.GearHidden <> nil then
+ FindPlace(HH^.GearHidden, false, 0, LAND_WIDTH,true);
+
+ if HH^.GearHidden <> nil then
+ begin
+ Gear^.X:= HH^.GearHidden^.X;
+ Gear^.Y:= HH^.GearHidden^.Y;
+ end;
+ Gear^.Timer:= 0;
+
+ if (HH^.GearHidden <> nil) and (cnt = 0) then // do an emergency jump back in this case. the team needs you!
+ begin
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtExplosion);
+ Gear^.Pos:= 2;
+ Gear^.Power:= 255;
+ end
+ else begin
+ Gear^.SoundChannel := LoopSound(sndTardis);
+ Gear^.Pos:= 1;
+ Gear^.Power:= 0;
+ end
+ end
+ else if (CurrentHedgehog^.Team^.Clan = Gear^.Hedgehog^.Team^.Clan) then dec(Gear^.Timer)
+ end;
+
+end;
+
+procedure doStepTardis(Gear: PGear);
+var i,j,cnt: LongWord;
+ HH: PHedgehog;
+begin
+(*
+ Conditions for not activating.
+ 1. Hog is last of his clan
+ 2. Sudden Death is in play
+ 3. Hog is a king
+*)
+ HH:= Gear^.Hedgehog;
+ if HH^.Gear <> nil then
+ if (HH^.Gear = nil) or (HH^.King) or (SuddenDeathDmg) then
+ begin
+ if HH^.Gear <> nil then
+ begin
+ HH^.Gear^.Message := HH^.Gear^.Message and (not gmAttack);
+ HH^.Gear^.State:= HH^.Gear^.State and (not gstAttacking);
+ end;
+ PlaySound(sndDenied);
+ DeleteGear(gear);
+ exit
+ end;
+ cnt:= 0;
+ for j:= 0 to Pred(HH^.Team^.Clan^.TeamsNumber) do
+ for i:= 0 to Pred(HH^.Team^.Clan^.Teams[j]^.HedgehogsNumber) do
+ if (HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear <> nil)
+ and ((HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.State and gstDrowning) = 0)
+ and (HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.Health > HH^.Team^.Clan^.Teams[j]^.Hedgehogs[i].Gear^.Damage) then
+ inc(cnt);
+ if cnt < 2 then
+ begin
+ if HH^.Gear <> nil then
+ begin
+ HH^.Gear^.Message := HH^.Gear^.Message and (not gmAttack);
+ HH^.Gear^.State:= HH^.Gear^.State and (not gstAttacking);
+ end;
+ PlaySound(sndDenied);
+ DeleteGear(gear);
+ exit
+ end;
+ Gear^.SoundChannel := LoopSound(sndTardis);
+ Gear^.doStep:= @doStepTardisWarp
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+
+(*
+WIP. The ice gun will have the following effects. It has been proposed by sheepluva that it take the appearance of a large freezer
+spewing ice cubes. The cubes will be visual gears only. The scatter from them and the impact snow dust should help hide imprecisions in things like the GearsNear effect.
+For now we assume a "ray" like a deagle projected out from the gun.
+All these effects assume the ray's angle is not changed and that the target type was unchanged over a number of ticks. This is a simplifying assumption for "gun was applying freezing effect to the same target".
+ * When fired at water a layer of ice textured land is added above the water.
+ * When fired at non-ice land (land and lfLandMask and not lfIce) the land is overlaid with a thin layer of ice textured land around that point (say, 1 or 2px into land, 1px above). For attractiveness, a slope would probably be needed.
+ * When fired at a hog (land and $00FF <> 0), while the hog is targetted, the hog's state is set to frozen. As long as the gun is on the hog, a frozen hog sprite creeps up from the feet to the head. If the effect is interrupted before reaching the top, the freezing state is cleared.
+A frozen hog will animate differently. To be decided, but possibly in a similar fashion to a grave when it comes to explosions. The hog might (possibly) not be damaged by explosions. This might make freezing potentially useful for friendlies in a bad position. It might be better to allow damage though.
+A frozen hog stays frozen for a certain number of turns. Each turn the frozen overlay becomes fainter, until it fades and the hog animates normally again.
+*)
+
+
+procedure updateFuel(Gear: PGear);
+var
+ t:LongInt;
+begin
+ t:= Gear^.Health div 10;
+ if (t <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
+ begin
+ Gear^.Damage:= t;
+ FreeTexture(Gear^.Tex);
+ Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(t) +
+ '%', cWhiteColor, fntSmall)
+ end;
+ if Gear^.Message and (gmUp or gmDown) <> 0 then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ Gear^.SoundChannel:= -1;
+ if GameTicks mod 40 = 0 then dec(Gear^.Health)
+ end
+ else
+ begin
+ if Gear^.SoundChannel = -1 then
+ Gear^.SoundChannel := LoopSound(sndIceBeam);
+ if GameTicks mod 10 = 0 then dec(Gear^.Health)
+ end
+end;
+
+
+procedure updateTarget(Gear:PGear; newX, newY:HWFloat);
+// var
+// iter:PGear;
+begin
+ with Gear^ do
+ begin
+ dX:= newX;
+ dY:= newY;
+ Pos:= 0;
+ Target.X:= NoPointX;
+ LastDamage:= nil;
+ X:= Hedgehog^.Gear^.X;
+ Y:= Hedgehog^.Gear^.Y;
+ end;
+end;
+
+procedure doStepIceGun(Gear: PGear);
+const iceWaitCollision = 0;
+const iceCollideWithGround = 1;
+//const iceWaitNextTarget:Longint = 2;
+//const iceCollideWithHog:Longint = 4;
+const iceCollideWithWater = 5;
+//const waterFreezingTime:Longint = 500;
+const groundFreezingTime = 1000;
+const iceRadius = 32;
+const iceHeight = 40;
+var
+ HHGear, iter: PGear;
+ landRect: TSDL_Rect;
+ ndX, ndY: hwFloat;
+ i, t, gX, gY: LongInt;
+ hogs: PGearArrayS;
+ vg: PVisualGear;
+begin
+ HHGear := Gear^.Hedgehog^.Gear;
+ if (Gear^.Message and gmAttack <> 0) or (Gear^.Health = 0) or (HHGear = nil) or ((HHGear^.State and gstHHDriven) = 0) or (HHGear^.dX.QWordValue > 4294967) then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ DeleteGear(Gear);
+ AfterAttack;
+ exit
+ end;
+ updateFuel(Gear);
+
+ with Gear^ do
+ begin
+ HedgehogChAngle(HHGear);
+ ndX:= SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _4;
+ ndY:= -AngleCos(HHGear^.Angle) * _4;
+ if (ndX <> dX) or (ndY <> dY) or
+ ((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and
+ (Target.Y and LAND_HEIGHT_MASK = 0) and ((Land[Target.Y, Target.X] = 0))) then
+ begin
+ updateTarget(Gear, ndX, ndY);
+ Timer := iceWaitCollision;
+ end
+ else
+ begin
+ X:= X + dX;
+ Y:= Y + dY;
+ gX:= hwRound(X);
+ gY:= hwRound(Y);
+ if Target.X = NoPointX then t:= hwRound(hwSqr(X-HHGear^.X)+hwSqr(Y-HHGear^.Y));
+
+ if Target.X <> NoPointX then
+ begin
+ CheckCollision(Gear);
+ if (State and gstCollision) <> 0 then
+ begin
+ if Timer = iceWaitCollision then
+ begin
+ Timer := iceCollideWithGround;
+ Power := GameTicks;
+ end
+ end
+ else if (target.y >= cWaterLine) then
+ begin
+ if Timer = iceWaitCollision then
+ begin
+ Timer := iceCollideWithWater;
+ Power := GameTicks;
+ end;
+ end;
+
+ if (abs(gX-Target.X) < 2) and (abs(gY-Target.Y) < 2) then
+ begin
+ X:= HHGear^.X;
+ Y:= HHGear^.Y
+ end;
+
+ if (Timer = iceCollideWithGround) and ((GameTicks - Power) > groundFreezingTime) then
+ begin
+ FillRoundInLandFT(target.x, target.y, iceRadius, icePixel);
+ landRect.x := min(max(target.x - iceRadius, 0), LAND_WIDTH - 1);
+ landRect.y := min(max(target.y - iceRadius, 0), LAND_HEIGHT - 1);
+ landRect.w := min(2*iceRadius, LAND_WIDTH - landRect.x - 1);
+ landRect.h := min(2*iceRadius, LAND_HEIGHT - landRect.y - 1);
+ UpdateLandTexture(landRect.x, landRect.w, landRect.y, landRect.h, true);
+
+ // Freeze nearby mines/explosives/cases too
+ iter := GearsList;
+ while iter <> nil do
+ begin
+ if (iter^.State and gstFrozen = 0) and
+ ((iter^.Kind = gtExplosives) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine)) and
+ (abs(iter^.X.Round-target.x)+abs(iter^.Y.Round-target.y)+2<2*iceRadius) and (Distance(iter^.X-int2hwFloat(target.x),iter^.Y-int2hwFloat(target.y)) nil then
+ begin
+ i:= random(100) + 155;
+ vg^.Tint:= (i shl 24) or (i shl 16) or ($FF shl 8) or (random(200) + 55);
+ vg^.Angle:= random(360);
+ vg^.dx:= 0.001 * random(80);
+ vg^.dy:= 0.001 * random(80)
+ end
+ end;
+ PlaySound(sndHogFreeze);
+ if iter^.Kind = gtMine then // dud mine block
+ begin
+ iter^.State:= iter^.State or gstFrozen;
+ vg:= AddVisualGear(hwRound(iter^.X) - 4 + Random(8), hwRound(iter^.Y) - 4 - Random(4), vgtSmoke);
+ if vg <> nil then
+ vg^.Scale:= 0.5;
+ PlaySound(sndVaporize);
+ iter^.Health := 0;
+ iter^.Damage := 0;
+ iter^.State := iter^.State and (not gstAttacking)
+ end
+ else if iter^.Kind = gtCase then
+ begin
+ DeleteCI(iter);
+ iter^.State:= iter^.State or gstFrozen;
+ AddCI(iter)
+ end
+ else // gtExplosives
+ begin
+ iter^.State:= iter^.State or gstFrozen;
+ iter^.Health:= iter^.Health + cBarrelHealth
+ end
+ end;
+ iter:= iter^.NextGear
+ end;
+
+ // FillRoundInLandWithIce(Target.X, Target.Y, iceRadius);
+ SetAllHHToActive;
+ Timer := iceWaitCollision;
+ end;
+
+ if (Timer = iceCollideWithWater) and ((GameTicks - Power) > groundFreezingTime) then
+ begin
+ PlaySound(sndHogFreeze);
+ DrawIceBreak(Target.X, cWaterLine - iceHeight, iceRadius, iceHeight);
+ SetAllHHToActive;
+ Timer := iceWaitCollision;
+ end;
+(*
+ Any ideas for something that would look good here?
+ if (Target.X <> NoPointX) and ((Timer = iceCollideWithGround) or (Timer = iceCollideWithWater)) and (GameTicks mod max((groundFreezingTime-((GameTicks - Power)*2)),2) = 0) then //and CheckLandValue(Target.X, Target.Y, lfIce) then
+ begin
+ vg:= AddVisualGear(Target.X+random(20)-10, Target.Y+random(40)-10, vgtDust, 1);
+ if vg <> nil then
+ begin
+ i:= random(100) + 155;
+ vg^.Tint:= IceColor or $FF;
+ vg^.Angle:= random(360);
+ vg^.dx:= 0.001 * random(80);
+ vg^.dy:= 0.001 * random(80)
+ end
+ end;
+*)
+
+// freeze nearby hogs
+ hogs := GearsNear(int2hwFloat(Target.X), int2hwFloat(Target.Y), gtHedgehog, Gear^.Radius*2);
+ if hogs.size > 0 then
+ for i:= 0 to hogs.size - 1 do
+ if hogs.ar^[i] <> HHGear then
+ if GameTicks mod 5 = 0 then
+ begin
+ hogs.ar^[i]^.Active:= true;
+ if hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] < 256 then
+ hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] := hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] + 1
+ else if hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] = 256 then
+ begin
+ hogs.ar^[i]^.Hedgehog^.Effects[heFrozen]:= 200000-1;//cHedgehogTurnTime + cReadyDelay
+ PlaySound(sndHogFreeze);
+ end;
+ end;
+ inc(Pos)
+ end
+ else if (t > 400) and ((gY > cWaterLine) or
+ (((gX and LAND_WIDTH_MASK = 0) and (gY and LAND_HEIGHT_MASK = 0))
+ and (Land[gY, gX] <> 0))) then
+ begin
+ Target.X:= gX;
+ Target.Y:= gY;
+ X:= HHGear^.X;
+ Y:= HHGear^.Y
+ end;
+ if (gX > max(LAND_WIDTH,4096)*2) or
+ (gX < -max(LAND_WIDTH,4096)) or
+ (gY < -max(LAND_HEIGHT,4096)) or
+ (gY > max(LAND_HEIGHT,4096)+512) then
+ begin
+ //X:= HHGear^.X;
+ //Y:= HHGear^.Y
+ Target.X:= gX;
+ Target.Y:= gY;
+ end
+ end
+ end;
+end;
+
+procedure doStepAddAmmo(Gear: PGear);
+var a: TAmmoType;
+ gi: PGear;
+begin
+if Gear^.Timer > 0 then dec(Gear^.Timer)
+else
+ begin
+ if Gear^.Pos = posCaseUtility then
+ a:= GetUtility(Gear^.Hedgehog)
+ else
+ a:= GetAmmo(Gear^.Hedgehog);
+ CheckSum:= CheckSum xor GameTicks;
+ gi := GearsList;
+ while gi <> nil do
+ 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));
+ DeleteGear(Gear)
+ end;
+end;
+
+procedure doStepGenericFaller(Gear: PGear);
+begin
+if Gear^.Timer < $FFFFFFFF then
+ if Gear^.Timer > 0 then
+ dec(Gear^.Timer)
+ else
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+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);
+var hogs: PGearArrayS;
+ HHGear: PGear;
+ tdX: hwFloat;
+ dir: LongInt;
+begin
+doStepFallingGear(Gear);
+if Gear^.Timer > 0 then dec(Gear^.Timer);
+// creeper sleep phase
+if (Gear^.Hedgehog = nil) and (Gear^.Timer > 0) then exit;
+
+if Gear^.Hedgehog <> nil then HHGear:= Gear^.Hedgehog^.Gear
+else HHGear:= nil;
+
+// creeper boom phase
+if (Gear^.State and gstTmpFlag <> 0) then
+ begin
+ if (Gear^.Timer = 0) then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 300, CurrentHedgehog, EXPLAutoSound);
+ DeleteGear(Gear)
+ end;
+ // ssssss he essssscaped
+ if (Gear^.Timer > 250) and ((HHGear = nil) or
+ (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) > 180) and
+ (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > _180))) then
+ begin
+ Gear^.State:= Gear^.State and (not gstTmpFlag);
+ Gear^.Timer:= 0
+ end;
+ exit
+ end;
+
+// Search out a new target, as target seek time has expired, target is dead, target is out of range, or we did not have a target
+if (HHGear = nil) or (Gear^.Timer = 0) or
+ (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) > Gear^.Angle) and
+ (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > int2hwFloat(Gear^.Angle)))
+ then
+ begin
+ hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Angle);
+ if hogs.size > 1 then
+ Gear^.Hedgehog:= hogs.ar^[GetRandom(hogs.size)]^.Hedgehog
+ else if hogs.size = 1 then Gear^.Hedgehog:= hogs.ar^[0]^.Hedgehog
+ else Gear^.Hedgehog:= nil;
+ if Gear^.Hedgehog <> nil then Gear^.Timer:= 5000;
+ exit
+ end;
+
+// we have a target. move the creeper.
+if HHGear <> nil then
+ begin
+ // GOTCHA
+ if ((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) < 50) and
+ (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) < _50) then
+ begin
+ // hisssssssssss
+ Gear^.State:= Gear^.State or gstTmpFlag;
+ Gear^.Timer:= 1500;
+ exit
+ end;
+ if (Gear^.State and gstMoving <> 0) then
+ begin
+ Gear^.dY:= _0;
+ Gear^.dX:= _0;
+ end
+ else if (GameTicks and $FF = 0) then
+ begin
+ tdX:= HHGear^.X-Gear^.X;
+ dir:= hwSign(tdX);
+ if TestCollisionX(Gear, dir) = 0 then
+ Gear^.X:= Gear^.X + signAs(_1,tdX);
+ if TestCollisionXwithXYShift(Gear, signAs(_10,tdX), 0, dir) <> 0 then
+ begin
+ Gear^.dX:= SignAs(_0_15, tdX);
+ Gear^.dY:= -_0_3;
+ Gear^.State:= Gear^.State or gstMoving
+ end
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepKnife(Gear: PGear);
+//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 = 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;
+ Gear^.Damage:= 0;
+ if Gear^.Timer > 0 then dec(Gear^.Timer);
+ 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);
+ AllInactive := false;
+ a:= Gear^.DirAngle;
+ CalcRotationDirAngle(Gear);
+ Gear^.DirAngle:= a+(Gear^.DirAngle-a)*2*hwSign(Gear^.dX) // double rotation
+ end
+ else if (Gear^.CollisionIndex = -1) and (Gear^.Timer = 0) then
+ begin
+ (*ox:= 0; oy:= 0;
+ if TestCollisionYwithGear(Gear, -1) <> 0 then oy:= -1;
+ if TestCollisionXwithGear(Gear, 1) <> 0 then ox:= 1;
+ if TestCollisionXwithGear(Gear, -1) <> 0 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);
+ if la = _10000 then
+ begin
+ // debug for when we couldn't get an angle
+ //AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeWhite);
+*)
+ Gear^.DirAngle:= DxDy2Angle(Gear^.dX, Gear^.dY) + (random(30)-15);
+ if (Gear^.dX.isNegative and Gear^.dY.isNegative) or
+ ((not Gear^.dX.isNegative) and (not Gear^.dY.isNegative)) then Gear^.DirAngle:= Gear^.DirAngle-90;
+ // end
+ // else Gear^.DirAngle:= hwFloat2Float(la)*90; // sheepluva's comment claims 45deg = 0.5 - yet orientation doesn't seem consistent?
+ // AddFileLog('la: '+floattostr(la)+' DirAngle: '+inttostr(round(Gear^.DirAngle)));
+ Gear^.dX:= _0;
+ Gear^.dY:= _0;
+ Gear^.State:= Gear^.State and (not gstMoving) or gstCollision;
+ Gear^.Radius:= 16;
+ if Gear^.Health > 0 then AmmoShove(Gear, Gear^.Health, 0);
+ Gear^.Health:= 0;
+ Gear^.Timer:= 500;
+ AddCI(Gear)
+ end
+ else if GameTicks and $3F = 0 then
+ begin
+ if (TestCollisionYwithGear(Gear,-1) = 0)
+ and (TestCollisionXwithGear(Gear, 1) = 0)
+ and (TestCollisionXwithGear(Gear,-1) = 0)
+ and (TestCollisionYwithGear(Gear, 1) = 0) then Gear^.State:= Gear^.State and (not gstCollision) or gstMoving;
+ end
+end;
+(*
+ This didn't end up getting used, but, who knows, might be reasonable for javellin or something
+// Make the knife initial angle based on the hog attack angle, or is that too hard?
+procedure doStepKnife(Gear: PGear);
+var t,
+ gx, gy, ga, // gear x,y,angle
+ lx, ly, la, // land x,y,angle
+ ox, oy, // x,y offset
+ w, h, // wXh of clip area
+ tx, ty // tip position in sprite
+ : LongInt;
+ surf: PSDL_Surface;
+ s: hwFloat;
+
+begin
+ Gear^.dY := Gear^.dY + cGravity;
+ if (GameFlags and gfMoreWind) <> 0 then
+ Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density;
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ CheckGearDrowning(Gear);
+ gx:= hwRound(Gear^.X);
+ gy:= hwRound(Gear^.Y);
+ if Gear^.State and gstDrowning <> 0 then exit;
+ with Gear^ do
+ begin
+ if CheckLandValue(gx, gy, lfLandMask) then
+ begin
+ t:= Angle + hwRound((hwAbs(dX)+hwAbs(dY)) * _10);
+
+ if t < 0 then inc(t, 4096)
+ else if 4095 < t then dec(t, 4096);
+ Angle:= t;
+
+ DirAngle:= Angle / 4096 * 360
+ end
+ else
+ begin
+//This is the set of postions for the knife.
+//Using FlipSurface and copyToXY the knife can be written to the LandPixels at 32 positions, and an appropriate line drawn in Land.
+ t:= Angle mod 1024;
+ case t div 128 of
+ 0: begin
+ ox:= 2; oy:= 5;
+ w := 25; h:= 5;
+ tx:= 0; ty:= 2
+ end;
+ 1: begin
+ ox:= 2; oy:= 15;
+ w:= 24; h:= 8;
+ tx:= 0; ty:= 7
+ end;
+ 2: begin
+ ox:= 2; oy:= 27;
+ w:= 23; h:= 12;
+ tx:= -12; ty:= -5
+ end;
+ 3: begin
+ ox:= 2; oy:= 43;
+ w:= 21; h:= 15;
+ tx:= 0; ty:= 14
+ end;
+ 4: begin
+ ox:= 29; oy:= 8;
+ w:= 19; h:= 19;
+ tx:= 0; ty:= 17
+ end;
+ 5: begin
+ ox:= 29; oy:= 32;
+ w:= 15; h:= 21;
+ tx:= 0; ty:= 20
+ end;
+ 6: begin
+ ox:= 51; oy:= 3;
+ w:= 11; h:= 23;
+ tx:= 0; ty:= 22
+ end;
+ 7: begin
+ ox:= 51; oy:= 34;
+ w:= 7; h:= 24;
+ tx:= 0; ty:= 23
+ end
+ end;
+
+ surf:= SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, RMask, GMask, BMask, AMask);
+ copyToXYFromRect(SpritesData[sprKnife].Surface, surf, ox, oy, w, h, 0, 0);
+ // try to make the knife hit point first
+ lx := 0;
+ ly := 0;
+ if CalcSlopeTangent(Gear, gx, gy, lx, ly, 255) then
+ begin
+ la:= vector2Angle(int2hwFloat(lx), int2hwFloat(ly));
+ ga:= vector2Angle(dX, dY);
+ AddFileLog('la: '+inttostr(la)+' ga: '+inttostr(ga)+' Angle: '+inttostr(Angle));
+ // change to 0 to 4096 forced by LongWord in Gear
+ if la < 0 then la:= 4096+la;
+ if ga < 0 then ga:= 4096+ga;
+ if ((Angle > ga) and (Angle < la)) or ((Angle < ga) and (Angle > la)) then
+ begin
+ if Angle >= 2048 then dec(Angle, 2048)
+ else if Angle < 2048 then inc(Angle, 2048)
+ end;
+ AddFileLog('la: '+inttostr(la)+' ga: '+inttostr(ga)+' Angle: '+inttostr(Angle))
+ end;
+ case Angle div 1024 of
+ 0: begin
+ flipSurface(surf, true);
+ flipSurface(surf, true);
+ BlitImageAndGenerateCollisionInfo(gx-(w-tx), gy-(h-ty), w, surf)
+ end;
+ 1: begin
+ flipSurface(surf, false);
+ BlitImageAndGenerateCollisionInfo(gx-(w-tx), gy-ty, w, surf)
+ end;
+ 2: begin // knife was actually drawn facing this way...
+ BlitImageAndGenerateCollisionInfo(gx-tx, gy-ty, w, surf)
+ end;
+ 3: begin
+ flipSurface(surf, true);
+ BlitImageAndGenerateCollisionInfo(gx-tx, gy-(h-ty), w, surf)
+ end
+ end;
+ SDL_FreeSurface(surf);
+ // this needs to calculate actual width/height + land clipping since update texture doesn't.
+ // i.e. this will crash if you fire near sides of map, but until I get the blit right, not going to put real values
+ UpdateLandTexture(hwRound(X)-32, 64, hwRound(Y)-32, 64, true);
+ DeleteGear(Gear);
+ exit
+ end
+ end;
+end;
+*)
+
+end.
diff -Nru hedgewars-0.9.19.3/hedgewars/uGearsHandlersRope.pas hedgewars-0.9.20.5/hedgewars/uGearsHandlersRope.pas
--- hedgewars-0.9.19.3/hedgewars/uGearsHandlersRope.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uGearsHandlersRope.pas 2014-01-07 20:16:48.000000000 +0000
@@ -31,8 +31,17 @@
procedure doStepRopeAfterAttack(Gear: PGear);
var
HHGear: PGear;
+ tX: hwFloat;
begin
HHGear := Gear^.Hedgehog^.Gear;
+ tX:= HHGear^.X;
+ if WorldWrap(HHGear) and (WorldEdge = weWrap) and
+ ((TestCollisionXwithGear(HHGear, 1) <> 0) or (TestCollisionXwithGear(HHGear, -1) <> 0)) then
+ begin
+ HHGear^.X:= tX;
+ HHGear^.dX.isNegative:= hwRound(tX) > LongInt(leftX) + HHGear^.Radius * 2
+ end;
+
if (HHGear^.Hedgehog^.CurAmmoType = amParachute) and (HHGear^.dY > _0_39) then
begin
DeleteGear(Gear);
@@ -53,7 +62,7 @@
HedgehogChAngle(HHGear);
- if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
+ if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) <> 0 then
SetLittle(HHGear^.dX);
if HHGear^.dY.isNegative and (TestCollisionYwithGear(HHGear, -1) <> 0) then
@@ -116,8 +125,20 @@
HHGear := Gear^.Hedgehog^.Gear;
- if ((HHGear^.State and gstHHDriven) = 0)
- or (CheckGearDrowning(HHGear)) or (Gear^.PortalCounter <> 0) then
+ tX:= HHGear^.X;
+ if WorldWrap(HHGear) and (WorldEdge = weWrap) and
+ ((TestCollisionXwithGear(HHGear, 1) <> 0) or (TestCollisionXwithGear(HHGear, -1) <> 0)) then
+ begin
+ PlaySound(sndRopeRelease);
+ RopeDeleteMe(Gear, HHGear);
+ HHGear^.X:= tX;
+ HHGear^.dX.isNegative:= hwRound(tX) > LongInt(leftX) + HHGear^.Radius * 2;
+ exit
+ end;
+
+ tX:= HHGear^.X;
+ if ((HHGear^.State and gstHHDriven) = 0) or
+ (CheckGearDrowning(HHGear)) or (Gear^.PortalCounter <> 0) then
begin
PlaySound(sndRopeRelease);
RopeDeleteMe(Gear, HHGear);
@@ -126,17 +147,17 @@
HHGear^.dX.QWordValue:= HHGear^.dX.QWordValue shl 2;
HHGear^.dY.QWordValue:= HHGear^.dY.QWordValue shl 2;
- if (Gear^.Message and gmLeft <> 0) and (not TestCollisionXwithGear(HHGear, -1)) then
+ if (Gear^.Message and gmLeft <> 0) and (TestCollisionXwithGear(HHGear, -1) = 0) then
HHGear^.dX := HHGear^.dX - _0_0032;
- if (Gear^.Message and gmRight <> 0) and (not TestCollisionXwithGear(HHGear, 1)) then
+ if (Gear^.Message and gmRight <> 0) and (TestCollisionXwithGear(HHGear, 1) = 0) then
HHGear^.dX := HHGear^.dX + _0_0032;
// vector between hedgehog and rope attaching point
ropeDx := HHGear^.X - Gear^.X;
ropeDy := HHGear^.Y - Gear^.Y;
- if TestCollisionYwithGear(HHGear, 1) = 0 then
+ if TestCollisionYwithXYShift(HHGear, 0, 1, 1) = 0 then
begin
// depending on the rope vector we know which X-side to check for collision
@@ -147,12 +168,12 @@
cd:= 1;
// apply gravity if there is no obstacle
- if not TestCollisionXwithGear(HHGear, cd) then
+ if TestCollisionXwithXYShift(HHGear, _2*cd, 0, cd, true) = 0 then
HHGear^.dY := HHGear^.dY + cGravity * 16;
if (GameFlags and gfMoreWind) <> 0 then
// apply wind if there's no obstacle
- if not TestCollisionXwithGear(HHGear, hwSign(cWindSpeed)) then
+ if TestCollisionXwithGear(HHGear, hwSign(cWindSpeed)) = 0 then
HHGear^.dX := HHGear^.dX + cWindSpeed * 16 / HHGear^.Density;
end;
@@ -172,13 +193,13 @@
ty := HHGear^.Y;
if ((Gear^.Message and gmDown) <> 0) and (Gear^.Elasticity < Gear^.Friction) then
- if not (TestCollisionXwithGear(HHGear, hwSign(ropeDx))
- or ((ropeDy.QWordValue <> 0) and TestCollisionYwithXYShift(HHGear, 0, 1, hwSign(ropeDy)))) then
+ if not ((TestCollisionXwithXYShift(HHGear, _2*hwSign(ropeDx), 0, hwSign(ropeDx), true) <> 0)
+ or ((ropeDy.QWordValue <> 0) and (TestCollisionYwithXYShift(HHGear, 0, 1*hwSign(ropeDy), hwSign(ropeDy)) <> 0))) 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 ((ropeDy.QWordValue <> 0) and TestCollisionYwithXYShift(HHGear, 0, 1, -hwSign(ropeDy)))) then
+ if not ((TestCollisionXwithXYShift(HHGear, -_2*hwSign(ropeDx), 0, -hwSign(ropeDx), true) <> 0)
+ or ((ropeDy.QWordValue <> 0) and (TestCollisionYwithXYShift(HHGear, 0, 1*-hwSign(ropeDy), -hwSign(ropeDy)) <> 0))) then
Gear^.Elasticity := Gear^.Elasticity - _1_2;
HHGear^.X := Gear^.X + mdX * Gear^.Elasticity;
@@ -294,12 +315,12 @@
end;
haveCollision := false;
- if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
+ if TestCollisionXwithXYShift(HHGear, _2*hwSign(HHGear^.dX), 0, hwSign(HHGear^.dX), true) <> 0 then
begin
HHGear^.dX := -_0_6 * HHGear^.dX;
haveCollision := true
end;
- if TestCollisionYwithXYShift(HHGear, 0, 1, hwSign(HHGear^.dY)) then
+ if TestCollisionYwithXYShift(HHGear, 0, 1*hwSign(HHGear^.dY), hwSign(HHGear^.dY)) <> 0 then
begin
HHGear^.dY := -_0_6 * HHGear^.dY;
haveCollision := true
@@ -397,7 +418,7 @@
if (HHGear^.State and gstMoving) <> 0 then
begin
- if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
+ if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) <> 0 then
SetLittle(HHGear^.dX);
if HHGear^.dY.isNegative and (TestCollisionYwithGear(HHGear, -1) <> 0) then
HHGear^.dY := _0;
diff -Nru hedgewars-0.9.19.3/hedgewars/uGearsHedgehog.pas hedgewars-0.9.20.5/hedgewars/uGearsHedgehog.pas
--- hedgewars-0.9.19.3/hedgewars/uGearsHedgehog.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uGearsHedgehog.pas 2014-01-08 16:25:17.000000000 +0000
@@ -20,7 +20,7 @@
unit uGearsHedgehog;
interface
-uses uTypes;
+uses uTypes, uGearsHandlersMess;
procedure doStepHedgehog(Gear: PGear);
procedure AfterAttack;
@@ -33,12 +33,24 @@
implementation
uses uConsts, uVariables, uFloat, uAmmos, uSound, uCaptions,
- uCommands, uLocale, uUtils, uVisualGears, uStats, uIO, uScript,
- uGearsList, uGears, uCollisions, uRandom, uStore, uTeams,
- uGearsUtils;
+ uCommands, uLocale, uUtils, uStats, uIO, uScript,
+ uGearsList, uCollisions, uRandom, uStore, uTeams,
+ uGearsUtils, uVisualGearsList, uChat;
var GHStepTicks: LongWord = 0;
+procedure AFKSkip;
+var
+ t: byte;
+begin
+ t:= 0;
+ while (TeamsArray[t] <> CurrentTeam) do inc(t);
+
+ SendHogSpeech(#1 + char(t) + 'AFK');
+
+ ParseCommand('/skip', true)
+end;
+
// Shouldn't more of this ammo switching stuff be moved to uAmmos ?
function ChangeAmmo(HHGear: PGear): boolean;
var slot, i: Longword;
@@ -53,7 +65,7 @@
HHGear^.Message:= HHGear^.Message and (not gmSlot);
prevAmmo:= CurAmmoType;
ammoidx:= 0;
- if ((HHGear^.State and (gstAttacking or gstAttacked)) <> 0)
+ if (((HHGear^.State and (gstAttacking or gstAttacked)) <> 0) and (GameFlags and gfInfAttack = 0))
or ((HHGear^.State and gstHHDriven) = 0) then
exit;
ChangeAmmo:= true;
@@ -114,9 +126,9 @@
LoadHedgehogHat(HHGear^.Hedgehog^, Hat);
end;
// Try again in the next slot
- if CurAmmoType = prevAmmo then
+ if (CurAmmoType = prevAmmo) and (slot < cMaxSlotIndex) then
begin
- if slot >= cMaxSlotIndex then slot:= 0 else inc(slot);
+ inc(slot);
HHGear^.MsgParam:= slot;
ChangeAmmo(HHGear)
end
@@ -128,6 +140,7 @@
weap: TAmmoType;
Hedgehog: PHedgehog;
s: boolean;
+ prevState, newState: LongWord;
begin
s:= false;
@@ -143,12 +156,18 @@
HHGear^.Message:= HHGear^.Message and (not gmWeapon);
+prevState:= HHGear^.State;
+newState:= prevState;
with Hedgehog^ do
while (CurAmmoType <> weap) and (t >= 0) do
begin
s:= ChangeAmmo(HHGear);
+ if HHGear^.State <> prevState then // so we can keep gstAttacked out of consideration when looping
+ newState:= HHGear^.State;
+ HHGear^.State:= prevState;
dec(t)
end;
+HHGear^.State:= newState;
if s then
ApplyAmmoChanges(HHGear^.Hedgehog^)
@@ -334,6 +353,10 @@
amNapalm: newGear:= AddGear(CurWeapon^.Pos, 0, gtAirAttack, 2, _0, _0, 0);
amBlowTorch: newGear:= AddGear(hwRound(lx), hwRound(ly), gtBlowTorch, 0, SignAs(_0_5, dX), _0, 0);
amGirder: newGear:= AddGear(0, 0, gtGirder, CurWeapon^.Pos, _0, _0, 0);
+ amRubber: begin
+ newGear:= AddGear(0, 0, gtGirder, CurWeapon^.Pos, _0, _0, 0);
+ newGear^.AmmoType:= amRubber
+ end;
amTeleport: newGear:= AddGear(CurWeapon^.Pos, 0, gtTeleport, 0, _0, _0, 0);
amSwitch: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSwitcher, 0, _0, _0, 0);
amMortar: begin
@@ -365,7 +388,7 @@
PlaySound(sndHellishImpact4);
cDamageModifier:= _1_5
end;
- amInvulnerable: Invulnerable:= true;
+ amInvulnerable: Effects[heInvulnerable]:= 1;
amExtraTime: begin
PlaySound(sndSwitchHog);
TurnTimeLeft:= TurnTimeLeft + 30000
@@ -390,7 +413,7 @@
newGear^.SoundChannel := LoopSound(sndResurrector);
end;
//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);
+ amTardis: newGear:= AddGear(hwRound(X), hwRound(Y), gtTardis, 0, _0, _0, 0);
amIceGun: newGear:= AddGear(hwRound(X), hwRound(Y), gtIceGun, 0, _0, _0, 0);
end;
if altUse and (newGear <> nil) and
@@ -425,7 +448,7 @@
amFlamethrower, amLandGun,
amResurrector, //amStructure,
amTardis, amPiano,
- amIceGun: CurAmmoGear:= newGear;
+ amIceGun, amRubber: CurAmmoGear:= newGear;
end;
if ((CurAmmoType = amMine) or (CurAmmoType = amSMine)) and (GameFlags and gfInfAttack <> 0) then
@@ -748,13 +771,13 @@
Gear^.Message:= Gear^.Message and (not gmLJump);
DeleteCI(Gear);
if TestCollisionYwithGear(Gear, -1) = 0 then
- if not TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) then
+ if TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) = 0 then
Gear^.Y:= Gear^.Y - _2
else
- if not TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) then
+ if TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) = 0 then
Gear^.Y:= Gear^.Y - _1;
- if not (TestCollisionXwithGear(Gear, hwSign(Gear^.dX))
- or (TestCollisionYwithGear(Gear, -1) <> 0)) then
+ if (TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) = 0) and
+ (TestCollisionYwithGear(Gear, -1) = 0) then
begin
Gear^.dY:= -_0_15;
if not cArtillery then
@@ -800,7 +823,7 @@
MakeHedgehogsStep(Gear);
SetAllHHToActive(false);
- AddGearCI(Gear)
+ AddCI(Gear)
end
end;
@@ -808,7 +831,8 @@
var da: LongWord;
begin
with HHGear^.Hedgehog^ do
- if ((CurAmmoGear <> nil) and (CurAmmoGear^.AmmoType = amRope) and ((HHGear^.State and (gstMoving or gstHHJumping)) = gstMoving))
+ if (((CurAmmoType = amRope) or ((CurAmmoGear <> nil) and (CurAmmoGear^.AmmoType = amRope))) and
+ ((HHGear^.State and (gstMoving or gstHHJumping)) = gstMoving))
or ((CurAmmoType = amPortalGun) and ((HHGear^.State and gstMoving) <> 0)) then
da:= 2
else da:= 1;
@@ -841,16 +865,28 @@
Gear^.State:= Gear^.State and (not gstMoving);
exit
end;
-isFalling:= (Gear^.dY.isNegative) or (not TestCollisionYKick(Gear, 1));
+isFalling:= (Gear^.dY.isNegative) or (TestCollisionYKick(Gear, 1) = 0);
if isFalling then
begin
- if (Gear^.dY.isNegative) and TestCollisionYKick(Gear, -1) then
- Gear^.dY:= _0;
+ land:= TestCollisionYKick(Gear, -1);
+ if (Gear^.dY.isNegative) and (land <> 0) then
+ begin
+ if land and lfBouncy <> 0 then
+ begin
+ doStepFallingGear(Gear);
+ Gear^.dX:= Gear^.dX * _0_8
+ end;
+ if (land and lfBouncy = 0) or (Gear^.State and gstCollision <> 0) then
+ Gear^.dY:= _0;
+ Gear^.State:= Gear^.State and not gstCollision
+ end;
Gear^.State:= Gear^.State or gstMoving;
- if (CurrentHedgehog^.Gear = Gear)
- and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then
+ if (CurrentHedgehog^.Gear = Gear) and (CurrentHedgehog^.Gear^.State and gstHHDriven <> 0) and
+ (not CurrentTeam^.ExtDriven) and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then
begin
// TODO: why so aggressive at setting FollowGear when falling?
+ // because hog was being yanked out of frame by other stuff when doing a complicated jump/chute/saucer/roping.
+ // added a couple more conditions to make it a bit less aggressive, at cost of possibly spectator failing to follow a maneuver
FollowGear:= Gear;
end;
if isUnderwater then
@@ -868,19 +904,36 @@
else
begin
land:= TestCollisionYwithGear(Gear, 1);
- if ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_55.QWordValue) and ((land and lfIce) = 0)
+ if ((Gear^.dX.QWordValue + Gear^.dY.QWordValue) < _0_55.QWordValue) and ((land and lfIce) = 0)
+ and ((land and lfBouncy = 0) or (Gear^.State and gstCollision <> 0))
and ((Gear^.State and gstHHJumping) <> 0) then
SetLittle(Gear^.dX);
if not Gear^.dY.isNegative then
begin
+ if land and lfBouncy <> 0 then
+ begin
+ doStepFallingGear(Gear);
+ // hogs for some reason have very low friction. slippery little buggers
+ Gear^.dX:= Gear^.dX * _0_8
+ end;
+
CheckHHDamage(Gear);
- if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery)
- and (Gear^.dX.QWordValue < _0_02.QWordValue) then
- Gear^.dX.isNegative:= not Gear^.dX.isNegative; // landing after high jump
- Gear^.State:= Gear^.State and (not (gstHHJumping or gstHHHJump));
- Gear^.dY:= _0;
+ if (land and lfBouncy = 0) or (Gear^.State and gstCollision <> 0) then
+ begin
+ if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery)
+ and (Gear^.dX.QWordValue < _0_02.QWordValue) then
+ begin
+ if land and lfBouncy <> 0 then
+ Gear^.dY:= _0;
+ Gear^.dX.isNegative:= not Gear^.dX.isNegative // landing after high jump
+ end;
+ Gear^.State:= Gear^.State and (not (gstHHJumping or gstHHHJump));
+ if (land and lfBouncy = 0) or (Gear^.dX.QWordValue < _0_02.QWordValue) then
+ Gear^.dY:= _0
+ end;
+ Gear^.State:= Gear^.State and not gstCollision
end
else
Gear^.dY:= Gear^.dY + cGravity;
@@ -906,43 +959,43 @@
end;
if (Gear^.State and gstMoving) <> 0 then
- if TestCollisionXKick(Gear, hwSign(Gear^.dX)) then
+ if TestCollisionXKick(Gear, hwSign(Gear^.dX)) <> 0 then
if not isFalling then
if hwAbs(Gear^.dX) > _0_01 then
- if not (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -1, hwSign(Gear^.dX)) or
- (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1))) then
+ if (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -1, hwSign(Gear^.dX)) = 0) and
+ (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1) = 0) then
begin
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.dX:= Gear^.dX * _0_96;
Gear^.Y:= Gear^.Y - _1
end
else
- if not (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -2, hwSign(Gear^.dX)) or
- (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1))) then
+ if (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -2, hwSign(Gear^.dX)) = 0) and
+ (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1) = 0) then
begin
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.dX:= Gear^.dX * _0_93;
Gear^.Y:= Gear^.Y - _2
end
else
- if not (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -3, hwSign(Gear^.dX)) or
- (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1))) then
+ if (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -3, hwSign(Gear^.dX)) = 0) and
+ (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1) = 0) then
begin
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.dX:= Gear^.dX * _0_9 ;
Gear^.Y:= Gear^.Y - _3
end
else
- if not (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -4, hwSign(Gear^.dX)) or
- (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1))) then
+ if (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -4, hwSign(Gear^.dX)) = 0) and
+ (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1) = 0) then
begin
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.dX:= Gear^.dX * _0_87;
Gear^.Y:= Gear^.Y - _4
end
else
- if not (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -5, hwSign(Gear^.dX)) or
- (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1))) then
+ if (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -5, hwSign(Gear^.dX)) = 0) and
+ (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1) = 0) then
begin
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.dX:= Gear^.dX * _0_84;
@@ -993,12 +1046,19 @@
// ARTILLERY but not being moved by explosions
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.Y:= Gear^.Y + Gear^.dY;
- if (not Gear^.dY.isNegative) and (not TestCollisionYKick(Gear, 1))
- and TestCollisionYwithXYShift(Gear, 0, 1, 1) then
+ if (not Gear^.dY.isNegative) and (TestCollisionYKick(Gear, 1) = 0) then
begin
- CheckHHDamage(Gear);
- Gear^.dY:= _0;
- Gear^.Y:= Gear^.Y + _1
+ land:= TestCollisionYwithXYShift(Gear, 0, 1, 1);
+ if land and lfBouncy <> 0 then
+ doStepFallingGear(Gear);
+
+ if (land <> 0) and ((land and lfBouncy = 0) or (Gear^.State and gstCollision <> 0)) then
+ begin
+ CheckHHDamage(Gear);
+ Gear^.dY:= _0;
+ Gear^.Y:= Gear^.Y + _1
+ end;
+ Gear^.State:= Gear^.State and not gstCollision
end;
CheckGearDrowning(Gear);
@@ -1053,6 +1113,12 @@
exit
end;
+if isAFK and (not CurrentTeam^.ExtDriven) and (CurrentHedgehog^.BotLevel = 0) then
+ begin
+ AFKSkip;
+ exit
+ end;
+
if (HHGear^.State and gstAnimation) <> 0 then
begin
HHGear^.Message:= 0;
@@ -1136,7 +1202,7 @@
HHGear^.Message:= HHGear^.Message and (not (gmLJump or gmHJump));
- if (not cArtillery) and wasJumping and TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
+ if (not cArtillery) and wasJumping and (TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) <> 0) then
SetLittle(HHGear^.dX);
if Hedgehog^.Gear <> nil then
@@ -1144,7 +1210,7 @@
if ((HHGear^.State and (gstMoving or gstDrowning)) = 0) then
begin
- AddGearCI(HHGear);
+ AddCI(HHGear);
if wasJumping then
GHStepTicks:= 410
else
@@ -1226,7 +1292,7 @@
begin
Gear^.State:= Gear^.State and (not (gstWait or gstLoser or gstWinner or gstAttacked or gstNotKickable or gstHHChooseTarget));
if Gear^.Hedgehog^.Effects[heFrozen] = 0 then Gear^.Active:= false;
- AddGearCI(Gear);
+ AddCI(Gear);
exit
end
else dec(Gear^.Timer)
@@ -1245,7 +1311,7 @@
if (Gear^.Message and (gmAllStoppable or gmLJump or gmHJump) = 0)
and (Gear^.State and (gstHHJumping or gstHHHJump or gstAttacking) = 0)
and ((Gear^.Hedgehog = nil) or ((Gear^.Hedgehog^.Effects[heFrozen] = 0) or (Gear^.Hedgehog^.Effects[heFrozen] > 255)))
- and (not Gear^.dY.isNegative) and (TurnTimeLeft > 0) and (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
+ and (not Gear^.dY.isNegative) and TurnClockActive and (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
begin
slope:= CalcSlopeBelowGear(Gear);
if slope.QWordValue > 730144440 then // ignore mild slopes
@@ -1272,14 +1338,28 @@
////////////////////////////////////////////////////////////////////////////////
procedure doStepHedgehog(Gear: PGear);
+var tX: hwFloat;
begin
+tX:= Gear^.X;
+if WorldWrap(Gear) then
+ begin
+ if (WorldEdge <> weBounce) and (Gear = CurrentHedgehog^.Gear) and
+ (CurAmmoGear <> nil) and (CurAmmoGear^.Kind =gtRope) and (CurAmmoGear^.Elasticity <> _0) then
+ CurAmmoGear^.PortalCounter:= 1;
+ if (WorldEdge = weWrap) and ((TestCollisionXwithGear(Gear, 1) <> 0) or (TestCollisionXwithGear(Gear, -1) <> 0)) then
+ begin
+ Gear^.X:= tX;
+ Gear^.dX.isNegative:= (hwRound(tX) > LongInt(leftX) + Gear^.Radius * 2)
+ end
+ end;
+
CheckSum:= CheckSum xor Gear^.Hedgehog^.BotLevel;
if (Gear^.Message and gmDestroy) <> 0 then
begin
DeleteGear(Gear);
exit
end;
-if GameTicks mod 100 = 0 then CheckIce(Gear);
+if GameTicks mod 128 = 0 then CheckIce(Gear);
(*
if Gear^.Hedgehog^.Effects[heFrozen] > 0 then
begin
diff -Nru hedgewars-0.9.19.3/hedgewars/uGearsList.pas hedgewars-0.9.20.5/hedgewars/uGearsList.pas
--- hedgewars-0.9.19.3/hedgewars/uGearsList.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uGearsList.pas 2014-01-08 16:25:17.000000000 +0000
@@ -221,7 +221,8 @@
gear^.Timer:= 3000
end;
gtMelonPiece: begin
- gear^.Density:= _2;
+ gear^.AdvBounce:= 1;
+ gear^.Density:= _2
end;
gtHedgehog: begin
gear^.AdvBounce:= 1;
@@ -236,16 +237,20 @@
gear^.Hedgehog^.Effects[heResurrectable] := 1;
end;
gtShell: begin
+ gear^.Elasticity:= _0_8;
+ gear^.Friction:= _0_8;
gear^.Radius:= 4;
gear^.Density:= _1;
+ gear^.AdvBounce:= 1;
end;
gtSnowball: begin
gear^.ImpactSound:= sndMudballImpact;
gear^.nImpactSounds:= 1;
gear^.Radius:= 4;
- gear^.Elasticity:= _1;
- gear^.Friction:= _1;
gear^.Density:= _0_5;
+ gear^.AdvBounce:= 1;
+ gear^.Elasticity:= _0_8;
+ gear^.Friction:= _0_8;
end;
gtFlake: begin
@@ -257,15 +262,15 @@
if State and gstTmpFlag = 0 then
begin
dx.isNegative:= GetRandom(2) = 0;
- dx.QWordValue:= $40DA * GetRandom(10000) * 8;
+ dx.QWordValue:= QWord($40DA) * GetRandom(10000) * 8;
dy.isNegative:= false;
- dy.QWordValue:= $3AD3 * GetRandom(7000) * 8;
+ dy.QWordValue:= QWord($3AD3) * GetRandom(7000) * 8;
if GetRandom(2) = 0 then
dx := -dx
end;
State:= State or gstInvisible;
Health:= random(vobFrameTicks);
- Timer:= random(vobFramesCount);
+ if gear^.Timer = 0 then Timer:= random(vobFramesCount);
Damage:= (random(2) * 2 - 1) * (vobVelocity + random(vobVelocity)) * 8;
end
end;
@@ -277,25 +282,26 @@
end;
gtBee: begin
gear^.Radius:= 5;
- gear^.Timer:= 500;
+ if gear^.Timer = 0 then gear^.Timer:= 500;
gear^.RenderTimer:= true;
gear^.Elasticity:= _0_9;
gear^.Tag:= 0;
+ gear^.State:= Gear^.State or gstSubmersible
end;
gtSeduction: begin
gear^.Radius:= 250;
end;
gtShotgunShot: begin
- gear^.Timer:= 900;
+ if gear^.Timer = 0 then gear^.Timer:= 900;
gear^.Radius:= 2
end;
gtPickHammer: begin
gear^.Radius:= 10;
- gear^.Timer:= 4000
+ if gear^.Timer = 0 then gear^.Timer:= 4000
end;
gtHammerHit: begin
gear^.Radius:= 8;
- gear^.Timer:= 125
+ if gear^.Timer = 0 then gear^.Timer:= 125
end;
gtRope: begin
gear^.Radius:= 3;
@@ -311,10 +317,13 @@
gear^.Elasticity:= _0_55;
gear^.Friction:= _0_995;
gear^.Density:= _1;
- if cMinesTime < 0 then
- gear^.Timer:= getrandom(51)*100
- else
- gear^.Timer:= cMinesTime;
+ if gear^.Timer = 0 then
+ begin
+ if cMinesTime < 0 then
+ gear^.Timer:= getrandom(51)*100
+ else
+ gear^.Timer:= cMinesTime
+ end
end;
gtSMine: begin
gear^.Health:= 10;
@@ -323,9 +332,13 @@
gear^.Elasticity:= _0_55;
gear^.Friction:= _0_995;
gear^.Density:= _1_6;
- gear^.Timer:= 500;
+ gear^.AdvBounce:= 1;
+ if gear^.Timer = 0 then gear^.Timer:= 500;
end;
gtKnife: begin
+ gear^.AdvBounce:= 1;
+ gear^.Elasticity:= _0_8;
+ gear^.Friction:= _0_8;
gear^.Density:= _4;
gear^.Radius:= 7
end;
@@ -334,9 +347,10 @@
gear^.nImpactSounds:= 1;
gear^.Radius:= 16;
gear^.Elasticity:= _0_3;
- gear^.Timer:= 500
+ if gear^.Timer = 0 then gear^.Timer:= 500
end;
gtExplosives: begin
+ gear^.AdvBounce:= 1;
gear^.ImpactSound:= sndGrenadeImpact;
gear^.nImpactSounds:= 1;
gear^.Radius:= 16;
@@ -359,9 +373,12 @@
gear^.Elasticity:= _0_55;
gear^.Friction:= _0_03;
gear^.Density:= _2;
- gear^.Timer:= 5000;
+ if gear^.Timer = 0 then gear^.Timer:= 5000;
end;
gtCluster: begin
+ gear^.AdvBounce:= 1;
+ gear^.Elasticity:= _0_8;
+ gear^.Friction:= _0_8;
gear^.Radius:= 2;
gear^.Density:= _1_5;
gear^.RenderTimer:= true
@@ -379,6 +396,7 @@
end
end;
gtFirePunch: begin
+ if gear^.Timer = 0 then gear^.Timer:= 3000;
gear^.Radius:= 15;
gear^.Tag:= Y
end;
@@ -389,7 +407,7 @@
end;
gtBlowTorch: begin
gear^.Radius:= cHHRadius + cBlowTorchC;
- gear^.Timer:= 7500
+ if gear^.Timer = 0 then gear^.Timer:= 7500
end;
gtSwitcher: begin
gear^.Z:= cCurrHHZ
@@ -399,14 +417,13 @@
gear^.nImpactSounds:= 1;
gear^.Radius:= 10;
gear^.Elasticity:= _0_3;
- gear^.Timer:= 0
end;
gtTardis: begin
- gear^.Timer:= 0;
gear^.Pos:= 1;
gear^.Z:= cCurrHHZ+1;
end;
gtMortar: begin
+ gear^.AdvBounce:= 1;
gear^.Radius:= 4;
gear^.Elasticity:= _0_2;
gear^.Friction:= _0_08;
@@ -438,9 +455,12 @@
gear^.Friction:= _0_96;
gear^.Density:= _1_5;
gear^.RenderTimer:= true;
- gear^.Timer:= 5000
+ if gear^.Timer = 0 then gear^.Timer:= 5000
end;
gtDrill: begin
+ gear^.AdvBounce:= 1;
+ gear^.Elasticity:= _0_8;
+ gear^.Friction:= _0_8;
if gear^.Timer = 0 then
gear^.Timer:= 5000;
// Tag for drill strike. if 1 then first impact occured already
@@ -454,35 +474,36 @@
gear^.AdvBounce:= 1;
gear^.Radius:= 5;
gear^.Tag:= random(8);
- gear^.Timer:= 5000;
+ if gear^.Timer = 0 then gear^.Timer:= 5000;
gear^.Elasticity:= _0_7;
gear^.Friction:= _0_995;
gear^.Density:= _1_5;
end;
gtBallgun: begin
- gear^.Timer:= 5001;
+ if gear^.Timer = 0 then gear^.Timer:= 5001;
end;
gtRCPlane: begin
- gear^.Timer:= 15000;
+ if gear^.Timer = 0 then gear^.Timer:= 15000;
gear^.Health:= 3;
gear^.Radius:= 8
end;
gtJetpack: begin
gear^.Health:= 2000;
gear^.Damage:= 100;
- gear^.State:= gstSubmersible
+ gear^.State:= Gear^.State or gstSubmersible
end;
gtMolotov: begin
+ gear^.AdvBounce:= 1;
gear^.Radius:= 6;
- gear^.Density:= _2;
+ gear^.Density:= _2
end;
gtBirdy: begin
gear^.Radius:= 16; // todo: check
- gear^.Timer:= 0;
gear^.Health := 2000;
- gear^.FlightTime := 2;
+ gear^.FlightTime := 2
end;
gtEgg: begin
+ gear^.AdvBounce:= 1;
gear^.Radius:= 4;
gear^.Elasticity:= _0_6;
gear^.Friction:= _0_96;
@@ -493,7 +514,6 @@
gtPortal: begin
gear^.ImpactSound:= sndMelonImpact;
gear^.nImpactSounds:= 1;
- gear^.AdvBounce:= 0;
gear^.Radius:= 17;
// set color
gear^.Tag:= 2 * gear^.Timer;
@@ -511,18 +531,18 @@
end;
gtFlamethrower: begin
gear^.Tag:= 10;
- gear^.Timer:= 10;
+ if gear^.Timer = 0 then gear^.Timer:= 10;
gear^.Health:= 500;
gear^.Damage:= 100;
end;
gtLandGun: begin
gear^.Tag:= 10;
- gear^.Timer:= 10;
+ if gear^.Timer = 0 then gear^.Timer:= 10;
gear^.Health:= 1000;
gear^.Damage:= 100;
end;
gtPoisonCloud: begin
- gear^.Timer:= 5000;
+ if gear^.Timer = 0 then gear^.Timer:= 5000;
gear^.dY:= int2hwfloat(-4 + longint(getRandom(8))) / 1000;
end;
gtResurrector: begin
@@ -533,7 +553,9 @@
gear^.Tag := 47;
end;
gtNapalmBomb: begin
- gear^.Timer:= 1000;
+ gear^.Elasticity:= _0_8;
+ gear^.Friction:= _0_8;
+ if gear^.Timer = 0 then gear^.Timer:= 1000;
gear^.Radius:= 5;
gear^.Density:= _1_5;
end;
diff -Nru hedgewars-0.9.19.3/hedgewars/uGearsRender.pas hedgewars-0.9.20.5/hedgewars/uGearsRender.pas
--- hedgewars-0.9.19.3/hedgewars/uGearsRender.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uGearsRender.pas 2014-01-08 16:25:17.000000000 +0000
@@ -38,15 +38,7 @@
end;
implementation
-uses uRender, uUtils, uVariables, uAmmos, Math, uVisualGears;
-
-const
- // hog tag mask
- //htNone = $00;
- htTeamName = $01;
- htName = $02;
- htHealth = $04;
- htTransparent = $08;
+uses uRender, uUtils, uVariables, uAmmos, Math, uVisualGearsList;
procedure DrawRopeLinesRQ(Gear: PGear);
begin
@@ -73,7 +65,7 @@
glVertexPointer(2, GL_FLOAT, 0, @RopePoints.rounded[0]);
glDrawArrays(GL_LINE_STRIP, 0, RopePoints.Count + 2);
- Tint($FF, $FF, $FF, $FF);
+ untint;
glPopMatrix;
@@ -230,7 +222,7 @@
DrawSprite(sprHHDeath, ox - 16, oy - 26, Gear^.Pos);
Tint(HH^.Team^.Clan^.Color shl 8 or $FF);
DrawSprite(sprHHDeath, ox - 16, oy - 26, Gear^.Pos + 8);
- Tint($FF, $FF, $FF, $FF);
+ untint;
exit
end
else if (Gear^.State and gstHHGone) <> 0 then
@@ -271,7 +263,7 @@
begin
Tint($00, $FF, $40, $40);
DrawTextureRotatedF(SpritesData[sprSmokeWhite].texture, 2, 0, 0, sx, sy, 0, 1, 22, 22, (RealTicks shr 36) mod 360);
- Tint($FF, $FF, $FF, $FF)
+ untint
end;
@@ -370,11 +362,15 @@
CrosshairX := Round(hwRound(Gear^.X) + dx * 80 + GetLaunchX(HH^.CurAmmoType, sign * m, Gear^.Angle));
CrosshairY := Round(hwRound(Gear^.Y) + dy * 80 + GetLaunchY(HH^.CurAmmoType, Gear^.Angle));
-
- DrawTextureRotated(HH^.Team^.CrosshairTex,
+ setTintAdd(true);
+ Tint(HH^.Team^.Clan^.Color shl 8 or $FF);
+ DrawTextureRotated(CrosshairTexture,
12, 12, CrosshairX + WorldDx, CrosshairY + WorldDy, 0,
- sign * (Gear^.Angle * 180.0) / cMaxAngle);
+ sign * m * (Gear^.Angle * 180.0) / cMaxAngle);
+ untint;
+ setTintAdd(false);
end;
+
hx:= ox + 8 * sign;
hy:= oy - 2;
aangle:= Gear^.Angle * 180 / cMaxAngle - 90;
@@ -429,7 +425,7 @@
Tint(HH^.Team^.Clan^.Color shl 8 or $FF);
DrawTextureRotatedF(HatTex, 1.0, -1.0, -6.0, ox, oy, 32, i, 32, 32,
i*DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + hAngle);
- Tint($FF, $FF, $FF, $FF)
+ untint
end
end
end;
@@ -466,7 +462,7 @@
sign,
32,
32);
- Tint($FF, $FF, $FF, $FF)
+ untint
end
end;
defaultPos:= false
@@ -670,15 +666,35 @@
DrawCircle(ox, oy, 248, 4, $FF, $00, $00, $AA);
//Tint($FF, $0, $0, $AA);
//DrawTexture(ox - 240, oy - 240, SpritesData[sprVampiric].Texture, 10);
- //Tint($FF, $FF, $FF, $FF);
+ //untint;
end;
amVampiric: DrawSpriteRotatedF(sprHandVamp, hx, hy, (RealTicks div 125) mod 4, sign, aangle);
amRCPlane: begin
DrawSpriteRotated(sprHandPlane, hx, hy, sign, 0);
defaultPos:= false
end;
+ amRubber,
amGirder: begin
DrawSpriteRotated(sprHandConstruction, hx, hy, sign, aangle);
+ if WorldEdge = weWrap then
+ begin
+ if hwRound(Gear^.X) < LongInt(leftX) + 256 then
+ DrawSpriteClipped(sprGirder,
+ rightX+(ox-leftX)-256,
+ oy-256,
+ LongInt(topY)+WorldDy,
+ LongInt(rightX)+WorldDx,
+ cWaterLine+WorldDy,
+ LongInt(leftX)+WorldDx);
+ if hwRound(Gear^.X) > rightX-256 then
+ DrawSpriteClipped(sprGirder,
+ leftX-(rightX-ox)-256,
+ oy-256,
+ LongInt(topY)+WorldDy,
+ LongInt(rightX)+WorldDx,
+ cWaterLine+WorldDy,
+ LongInt(leftX)+WorldDx)
+ end;
DrawSpriteClipped(sprGirder,
ox-256,
oy-256,
@@ -820,9 +836,9 @@
sign,
32,
32);
- Tint($FF, $FF, $FF, $FF)
+ untint
end;
- if HH^.Team^.hasGone then Tint($FF, $FF, $FF, $FF)
+ if HH^.Team^.hasGone then untint
end
else
begin
@@ -845,7 +861,7 @@
sign*m,
32,
32);
- Tint($FF, $FF, $FF, $FF)
+ untint
end
end
end;
@@ -905,7 +921,7 @@
DrawTextureCentered(ox, t, Team^.NameTagTex)
end;
if (cTagsMask and htTransparent) <> 0 then
- Tint($FF, $FF, $FF, $FF)
+ untint
end;
if (Gear^.State and gstHHDriven) <> 0 then // Current hedgehog
begin
@@ -933,7 +949,7 @@
DrawSprite(sprVampiric, sx - 24, sy - 24, 0);
end;
- if Gear^.Invulnerable then
+ if (Gear^.Hedgehog^.Effects[heInvulnerable] <> 0) then
begin
Tint($FF, $FF, $FF, max($40, round($FF * abs(1 - ((RealTicks div 2 + Gear^.uid * 491) mod 1500) / 750))));
DrawSprite(sprInvulnerable, sx - 24, sy - 24, 0);
@@ -956,7 +972,7 @@
if HH^.Effects[heFrozen] < 150000 then
- Tint($FF, $FF, $FF, $FF);
+ untint;
end;
@@ -967,7 +983,7 @@
Tint($FF, 0, 0, max($40, round($FF * abs(1 - (RealTicks mod 1500) / 750))));
DrawSprite(sprVampiric, sx - 24, sy - 24, 0);
end;
- Tint($FF, $FF, $FF, $FF)
+ untint
end;
@@ -1005,7 +1021,7 @@
if Gear^.Tag < 0 then aangle:= 360-aangle;
Tint(Gear^.Hedgehog^.Team^.Clan^.Color shl 8 or $FF);
DrawSpriteRotatedF(sprPlane, x, y, 0, Gear^.Tag, aangle - 90);
- Tint($FF, $FF, $FF, $FF);
+ untint;
DrawSpriteRotatedF(sprPlane, x, y, 1, Gear^.Tag, aangle - 90)
end;
gtBall: DrawSpriteRotatedF(sprBalls, x, y, Gear^.Tag,0, Gear^.DirAngle);
@@ -1033,7 +1049,7 @@
Tint($f5, $db, $35, max($40, round($FF * abs(1 - (GameTicks mod 1500) / (750 + Gear^.Health)))));
//Tint($FF, $FF, $FF, max($40, round($FF * abs(1 - (RealTicks mod 1500) / 750))));
DrawSprite(sprVampiric, x - 24, y - 24, 0);
- Tint($FF, $FF, $FF, $FF)
+ untint
end
end;
gtBee: DrawSpriteRotatedF(sprBee, x, y, (GameTicks shr 5) mod 2, 0, DxDy2Angle(Gear^.dY, Gear^.dX));
@@ -1127,7 +1143,7 @@
gtAirAttack: begin
Tint(Gear^.Hedgehog^.Team^.Clan^.Color shl 8 or $FF);
DrawSpriteRotatedF(sprAirplane, x, y, 0, Gear^.Tag, 0);
- Tint($FF, $FF, $FF, $FF);
+ untint;
DrawSpriteRotatedF(sprAirplane, x, y, 1, Gear^.Tag, 0);
end;
gtAirBomb: DrawSpriteRotated(sprAirBomb, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX));
@@ -1141,7 +1157,7 @@
gtTarget: begin
Tint($FF, $FF, $FF, round($FF * Gear^.Timer / 1000));
DrawSprite(sprTarget, x - 16, y - 16, 0);
- Tint($FF, $FF, $FF, $FF);
+ untint;
end;
gtMortar: DrawSpriteRotated(sprMortar, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX));
gtCake: if Gear^.Pos = 6 then
@@ -1195,7 +1211,7 @@
Tint($FF, $FF, $FF, $10);
for i:= 8 downto 1 do
DrawTextureF(SpritesData[sprPiano].Texture, 1, x, y - hwRound(Gear^.dY * 4 * i), 0, 1, 128, 128);
- Tint($FF, $FF, $FF, $FF)
+ untint
end;
DrawTextureF(SpritesData[sprPiano].Texture, 1, x, y, 0, 1, 128, 128);
end;
@@ -1207,13 +1223,13 @@
else
Tint($C0, $C0, $00, $C0);
DrawTextureRotatedF(SpritesData[sprSmokeWhite].texture, 3, 0, 0, x, y, 0, 1, 22, 22, (RealTicks shr 36 + Gear^.UID * 100) mod 360);
- Tint($FF, $FF, $FF, $FF)
+ untint
end;
gtResurrector: begin
DrawSpriteRotated(sprCross, x, y, 0, 0);
Tint($f5, $db, $35, max($00, round($C0 * abs(1 - (GameTicks mod 6000) / 3000))));
DrawTexture(x - 108, y - 108, SpritesData[sprVampiric].Texture, 4.5);
- Tint($FF, $FF, $FF, $FF);
+ untint;
end;
gtNapalmBomb: DrawSpriteRotated(sprNapalmBomb, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX));
gtFlake: if Gear^.State and (gstDrowning or gstTmpFlag) <> 0 then
@@ -1226,7 +1242,7 @@
DrawTextureRotatedF(SpritesData[sprSnowDust].Texture, 1, 0, 0, x, y, 0, 1, 8, 8, Gear^.DirAngle);
//DrawSpriteRotated(sprSnowDust, x, y, 0, Gear^.DirAngle);
//DrawTexture(x, y, SpritesData[sprVampiric].Texture, 0.1);
- Tint($FF, $FF, $FF, $FF);
+ untint;
end
else //if not isInLag then
begin
@@ -1243,7 +1259,7 @@
//DrawSprite(sprFlake, x-SpritesData[sprFlake].Width div 2, y-SpritesData[sprFlake].Height div 2, Gear^.Timer)
//DrawSpriteRotatedF(sprFlake, x-SpritesData[sprFlake].Width div 2, y-SpritesData[sprFlake].Height div 2, Gear^.Timer, 1, Gear^.DirAngle);
if Gear^.FlightTime > 0 then
- Tint($FF, $FF, $FF, $FF);
+ untint;
end;
//gtStructure: DrawSprite(sprTarget, x - 16, y - 16, 0);
gtTardis: if Gear^.Pos <> 4 then
@@ -1254,16 +1270,16 @@
Tint(Gear^.Hedgehog^.Team^.Clan^.Color shl 8 or max($00, round(Gear^.Power * (1-abs(0.5 - (GameTicks mod 2000) / 2000)))));
DrawSprite(sprTardis, x-24, y-63,0);
if Gear^.Pos = 2 then
- Tint($FF, $FF, $FF, $FF)
+ untint
else
Tint($FF,$FF,$FF,max($00, round(Gear^.Power * (1-abs(0.5 - (GameTicks mod 2000) / 2000)))));
DrawSprite(sprTardis, x-24, y-63,1);
if Gear^.Pos <> 2 then
- Tint($FF, $FF, $FF, $FF)
+ untint
(*
Tint(Gear^.Hedgehog^.Team^.Clan^.Color shl 8 or max($00, round(Gear^.Power * abs(1 - (RealTicks mod 500) / 250))));
DrawTexture(x-6, y-70, SpritesData[sprVampiric].Texture, 0.25);
- Tint($FF, $FF, $FF, $FF)
+ untint
*)
end;
gtIceGun: begin
@@ -1301,7 +1317,7 @@
end;
if Gear^.RenderTimer and (Gear^.Tex <> nil) then
DrawTextureCentered(x + 8, y + 8, Gear^.Tex);
- if Gear^.State and gstFrozen <> 0 then Tint($FF, $FF, $FF, $FF)
+ if Gear^.State and gstFrozen <> 0 then untint
end;
end.
diff -Nru hedgewars-0.9.19.3/hedgewars/uGearsUtils.pas hedgewars-0.9.20.5/hedgewars/uGearsUtils.pas
--- hedgewars-0.9.19.3/hedgewars/uGearsUtils.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uGearsUtils.pas 2014-01-08 16:25:17.000000000 +0000
@@ -20,7 +20,7 @@
unit uGearsUtils;
interface
-uses uTypes;
+uses uTypes, uFloat;
procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord);
@@ -41,16 +41,32 @@
procedure CheckCollision(Gear: PGear); inline;
procedure CheckCollisionWithLand(Gear: PGear); inline;
+procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
+function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS;
+procedure SpawnBoxOfSmth;
+procedure ShotgunShot(Gear: PGear);
+
+procedure SetAllToActive;
+procedure SetAllHHToActive; inline;
+procedure SetAllHHToActive(Ice: boolean);
+
+function GetAmmo(Hedgehog: PHedgehog): TAmmoType;
+function GetUtility(Hedgehog: PHedgehog): TAmmoType;
+
+function WorldWrap(var Gear: PGear): boolean;
+
+
+
function MakeHedgehogsStep(Gear: PGear) : boolean;
var doStepHandlers: array[TGearType] of TGearStepProcedure;
-
implementation
-uses uFloat, uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc,
+uses uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc,
uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore,
- uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, uGears,
- uGearsList, Math;
+ uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug,
+ uGearsList, Math, uVisualGearsList, uGearsHandlersMess,
+ uGearsHedgehog;
procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
begin
@@ -119,7 +135,7 @@
//AddFileLog('Damage: ' + inttostr(dmg));
if (Mask and EXPLNoDamage) = 0 then
begin
- if not Gear^.Invulnerable then
+ if Gear^.Hedgehog^.Effects[heInvulnerable] = 0 then
ApplyDamage(Gear, AttackingHog, dmg, dsExplosion)
else
Gear^.State:= Gear^.State or gstWinner;
@@ -132,29 +148,30 @@
Gear^.State:= (Gear^.State or gstMoving) and (not gstLoser);
if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and (not gstCollision);
- if not Gear^.Invulnerable then
+ if Gear^.Hedgehog^.Effects[heInvulnerable] = 0 then
Gear^.State:= (Gear^.State or gstMoving) and (not gstWinner);
Gear^.Active:= true;
if Gear^.Kind <> gtFlame then FollowGear:= Gear
end;
- if ((Mask and EXPLPoisoned) <> 0) and (Gear^.Kind = gtHedgehog) and (not Gear^.Invulnerable) and ((Gear^.State and gstHHDeath) = 0) then
+ if ((Mask and EXPLPoisoned) <> 0) and (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heInvulnerable] = 0) and (Gear^.State and gstHHDeath = 0) then
Gear^.Hedgehog^.Effects[hePoisoned] := 1;
end;
end;
- gtGrave: begin
+ gtGrave: if Mask and EXPLDoNotTouchAny = 0 then
// Run the calcs only once we know we have a type that will need damage
- tdX:= Gear^.X-fX;
- tdY:= Gear^.Y-fY;
- if LongInt(tdX.Round + tdY.Round + 2) < dmgBase then
- dmg:= dmgBase - hwRound(Distance(tdX, tdY));
- if dmg > 1 then
begin
- dmg:= ModifyDamage(min(dmg div 2, Radius), Gear);
- Gear^.dY:= - _0_004 * dmg;
- Gear^.Active:= true
- end
- end;
+ tdX:= Gear^.X-fX;
+ tdY:= Gear^.Y-fY;
+ if LongInt(tdX.Round + tdY.Round + 2) < dmgBase then
+ dmg:= dmgBase - hwRound(Distance(tdX, tdY));
+ if dmg > 1 then
+ begin
+ dmg:= ModifyDamage(min(dmg div 2, Radius), Gear);
+ Gear^.dY:= - _0_004 * dmg;
+ Gear^.Active:= true
+ end
+ end;
end;
end;
Gear:= Gear^.NextGear
@@ -183,9 +200,9 @@
if (CurrentHedgehog <> nil) and CurrentHedgehog^.King then
i:= _1_5;
if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then
- ModifyDamage:= hwRound(_0_01 * cDamageModifier * dmg * i * cDamagePercent * _0_5)
+ ModifyDamage:= hwRound(cDamageModifier * dmg * i * cDamagePercent * _0_5 * _0_01)
else
- ModifyDamage:= hwRound(_0_01 * cDamageModifier * dmg * i * cDamagePercent)
+ ModifyDamage:= hwRound(cDamageModifier * dmg * i * cDamagePercent * _0_01)
end;
procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
@@ -233,9 +250,8 @@
end;
end
end;
- if ((GameFlags and gfKarma) <> 0) and
- ((GameFlags and gfInvulnerable) = 0)
- and (not CurrentHedgehog^.Gear^.Invulnerable) then
+ if (GameFlags and gfKarma <> 0) and (GameFlags and gfInvulnerable = 0) and
+ (CurrentHedgehog^.Effects[heInvulnerable] = 0) then
begin // this cannot just use Damage or it interrupts shotgun and gets you called stupid
inc(CurrentHedgehog^.Gear^.Karma, tmpDmg);
CurrentHedgehog^.Gear^.LastDamage := CurrentHedgehog;
@@ -286,7 +302,7 @@
procedure CheckHHDamage(Gear: PGear);
var
- dmg: Longword;
+ dmg: LongInt;
i: LongWord;
particle: PVisualGear;
begin
@@ -299,14 +315,14 @@
if dmg < 1 then
exit;
- for i:= min(12, (3 + dmg div 10)) downto 0 do
+ for i:= min(12, 3 + dmg div 10) downto 0 do
begin
particle := AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
if particle <> nil then
particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480);
end;
- if (Gear^.Invulnerable) then
+ if ((Gear^.Hedgehog^.Effects[heInvulnerable] <> 0)) then
exit;
//if _0_6 < Gear^.dY then
@@ -471,7 +487,10 @@
CurAmmoGear^.Pos := 1000
end
else
- CheckGearDrowning := false;
+ begin
+ if not (Gear^.Kind in [gtJetpack, gtBee]) then Gear^.State:= Gear^.State and not gstSubmersible; // making it temporary for most gears is more attractive I think
+ CheckGearDrowning := false
+ end
end;
@@ -574,6 +593,11 @@
ignoreNearObjects:= false; // try not skipping proximity at first
ignoreOverlap:= false; // this not only skips proximity, but allows overlapping objects (barrels, mines, hogs, crates). Saving it for a 3rd pass. With this active, winning AI Survival goes back to virtual impossibility
tryAgain:= true;
+if WorldEdge <> weNone then
+ begin
+ Left:= max(Left, LongInt(leftX) + Gear^.Radius);
+ Right:= min(Right,rightX-Gear^.Radius)
+ end;
while tryAgain do
begin
delta:= LAND_WIDTH div 16;
@@ -583,7 +607,7 @@
repeat
inc(x, Delta);
cnt:= 0;
- y:= min(1024, topY) - 2 * Gear^.Radius;
+ y:= min(1024, topY) - Gear^.Radius shl 1;
while y < cWaterLine do
begin
repeat
@@ -681,7 +705,7 @@
procedure CheckCollision(Gear: PGear); inline;
begin
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX))
+ if (TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0)
or (TestCollisionYwithGear(Gear, hwSign(Gear^.dY)) <> 0) then
Gear^.State := Gear^.State or gstCollision
else
@@ -690,8 +714,8 @@
procedure CheckCollisionWithLand(Gear: PGear); inline;
begin
- if TestCollisionX(Gear, hwSign(Gear^.dX))
- or TestCollisionY(Gear, hwSign(Gear^.dY)) then
+ if (TestCollisionX(Gear, hwSign(Gear^.dX)) <> 0)
+ or (TestCollisionY(Gear, hwSign(Gear^.dY)) <> 0) then
Gear^.State := Gear^.State or gstCollision
else
Gear^.State := Gear^.State and (not gstCollision)
@@ -699,25 +723,25 @@
function MakeHedgehogsStep(Gear: PGear) : boolean;
begin
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0 then if (TestCollisionYwithGear(Gear, -1) = 0) then
begin
Gear^.Y:= Gear^.Y - _1;
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0 then if (TestCollisionYwithGear(Gear, -1) = 0) then
begin
Gear^.Y:= Gear^.Y - _1;
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0 then if (TestCollisionYwithGear(Gear, -1) = 0) then
begin
Gear^.Y:= Gear^.Y - _1;
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0 then if (TestCollisionYwithGear(Gear, -1) = 0) then
begin
Gear^.Y:= Gear^.Y - _1;
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0 then if (TestCollisionYwithGear(Gear, -1) = 0) then
begin
Gear^.Y:= Gear^.Y - _1;
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0 then if (TestCollisionYwithGear(Gear, -1) = 0) then
begin
Gear^.Y:= Gear^.Y - _1;
- if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0 then
Gear^.Y:= Gear^.Y + _6
end else Gear^.Y:= Gear^.Y + _5 else
end else Gear^.Y:= Gear^.Y + _4 else
@@ -726,7 +750,7 @@
end else Gear^.Y:= Gear^.Y + _1
end;
- if not TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) = 0 then
begin
Gear^.X:= Gear^.X + SignAs(_1, Gear^.dX);
MakeHedgehogsStep:= true
@@ -766,4 +790,496 @@
end;
end;
+
+procedure ShotgunShot(Gear: PGear);
+var t: PGear;
+ dmg, r, dist: LongInt;
+ dx, dy: hwFloat;
+begin
+Gear^.Radius:= cShotgunRadius;
+t:= GearsList;
+while t <> nil do
+ begin
+ case t^.Kind of
+ gtHedgehog,
+ gtMine,
+ gtSMine,
+ gtKnife,
+ gtCase,
+ gtTarget,
+ 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;
+ dx:= Gear^.X-t^.X;
+ dx.isNegative:= false;
+ dy:= Gear^.Y-t^.Y;
+ dy.isNegative:= false;
+ if r-hwRound(dx+dy) > 0 then
+ begin
+ dist:= hwRound(Distance(dx, dy));
+ dmg:= ModifyDamage(min(r - dist, 25), t);
+ end;
+ if dmg > 0 then
+ begin
+ if t^.Hedgehog^.Effects[heInvulnerable] = 0 then
+ ApplyDamage(t, Gear^.Hedgehog, dmg, dsBullet)
+ else
+ Gear^.State:= Gear^.State or gstWinner;
+
+ DeleteCI(t);
+ t^.dX:= t^.dX + Gear^.dX * dmg * _0_01 + SignAs(cHHKick, Gear^.dX);
+ t^.dY:= t^.dY + Gear^.dY * dmg * _0_01;
+ t^.State:= t^.State or gstMoving;
+ if t^.Kind = gtKnife then t^.State:= t^.State and (not gstCollision);
+ t^.Active:= true;
+ FollowGear:= t
+ end
+ end;
+ gtGrave: begin
+ dmg:= 0;
+ r:= Gear^.Radius + t^.Radius;
+ dx:= Gear^.X-t^.X;
+ dx.isNegative:= false;
+ dy:= Gear^.Y-t^.Y;
+ dy.isNegative:= false;
+ if r-hwRound(dx+dy) > 0 then
+ begin
+ dist:= hwRound(Distance(dx, dy));
+ dmg:= ModifyDamage(min(r - dist, 25), t);
+ end;
+ if dmg > 0 then
+ begin
+ t^.dY:= - _0_1;
+ t^.Active:= true
+ end
+ end;
+ end;
+ t:= t^.NextGear
+ end;
+if (GameFlags and gfSolidLand) = 0 then
+ DrawExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cShotgunRadius)
+end;
+
+procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
+var t: PGearArray;
+ Gear: PGear;
+ i, j, tmpDmg: LongInt;
+ VGear: PVisualGear;
+begin
+t:= CheckGearsCollision(Ammo);
+// Just to avoid hogs on rope dodging fire.
+if (CurAmmoGear <> nil) and ((CurAmmoGear^.Kind = gtRope) or (CurAmmoGear^.Kind = gtJetpack) or (CurAmmoGear^.Kind = gtBirdy))
+and (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.CollisionIndex = -1)
+and (sqr(hwRound(Ammo^.X) - hwRound(CurrentHedgehog^.Gear^.X)) + sqr(hwRound(Ammo^.Y) - hwRound(CurrentHedgehog^.Gear^.Y)) <= sqr(cHHRadius + Ammo^.Radius)) then
+ begin
+ t^.ar[t^.Count]:= CurrentHedgehog^.Gear;
+ inc(t^.Count)
+ end;
+
+i:= t^.Count;
+
+if (Ammo^.Kind = gtFlame) and (i > 0) then
+ Ammo^.Health:= 0;
+while i > 0 do
+ begin
+ dec(i);
+ Gear:= t^.ar[i];
+ if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and
+ (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then
+ Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000);
+ tmpDmg:= ModifyDamage(Damage, Gear);
+ if (Gear^.State and gstNoDamage) = 0 then
+ begin
+
+ if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then
+ begin
+ VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit);
+ if VGear <> nil then
+ VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY);
+ end;
+
+ if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then
+ Gear^.FlightTime:= 1;
+
+
+ case Gear^.Kind of
+ gtHedgehog,
+ gtMine,
+ gtSMine,
+ gtKnife,
+ gtTarget,
+ gtCase,
+ gtExplosives: //,
+ //gtStructure:
+ begin
+ if (Ammo^.Kind = gtDrill) then
+ begin
+ Ammo^.Timer:= 0;
+ exit;
+ end;
+ if Gear^.Hedgehog^.Effects[heInvulnerable] = 0 then
+ begin
+ if (Ammo^.Kind = gtKnife) and (tmpDmg > 0) then
+ for j:= 1 to max(1,min(3,tmpDmg div 5)) do
+ begin
+ VGear:= AddVisualGear(hwRound(Ammo^.X-((Ammo^.X-Gear^.X)/_2)), hwRound(Ammo^.Y-((Ammo^.Y-Gear^.Y)/_2)), vgtStraightShot);
+ if VGear <> nil then
+ with VGear^ do
+ begin
+ Tint:= $FFCC00FF;
+ Angle:= random(360);
+ dx:= 0.0005 * (random(100));
+ dy:= 0.0005 * (random(100));
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ FrameTicks:= 600+random(200);
+ State:= ord(sprStar)
+ end
+ end;
+ ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove)
+ end
+ else
+ Gear^.State:= Gear^.State or gstWinner;
+ if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then
+ begin
+ if (Ammo^.Hedgehog^.Gear <> nil) then
+ Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable);
+ ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
+ end;
+
+ if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then
+ begin
+ Gear^.dX:= Ammo^.dX * Power * _0_005;
+ Gear^.dY:= Ammo^.dY * Power * _0_005
+ end
+ else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then
+ begin
+ Gear^.dX:= Ammo^.dX * Power * _0_01;
+ Gear^.dY:= Ammo^.dY * Power * _0_01
+ end;
+
+ if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
+ begin
+ Gear^.Active:= true;
+ DeleteCI(Gear);
+ Gear^.State:= Gear^.State or gstMoving;
+ if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and (not gstCollision);
+ // move the gear upwards a bit to throw it over tiny obstacles at start
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0 then
+ begin
+ if (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX)) = 0) and
+ (TestCollisionYwithGear(Gear, -1) = 0) then
+ Gear^.Y:= Gear^.Y - _1;
+ if (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) = 0) and
+ (TestCollisionYwithGear(Gear, -1) = 0) then
+ Gear^.Y:= Gear^.Y - _1;
+ if (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) = 0) and
+ (TestCollisionYwithGear(Gear, -1) = 0) then
+ Gear^.Y:= Gear^.Y - _1;
+ end
+ end;
+
+
+ if (Ammo^.Kind <> gtFlame) or ((Ammo^.State and gsttmpFlag) = 0) then
+ FollowGear:= Gear
+ end;
+ end
+ end;
+ end;
+if i <> 0 then
+ SetAllToActive
+end;
+
+
+function CountGears(Kind: TGearType): Longword;
+var t: PGear;
+ count: Longword = 0;
+begin
+
+t:= GearsList;
+while t <> nil do
+ begin
+ if t^.Kind = Kind then
+ inc(count);
+ t:= t^.NextGear
+ end;
+CountGears:= count;
+end;
+
+procedure SetAllToActive;
+var t: PGear;
+begin
+AllInactive:= false;
+t:= GearsList;
+while t <> nil do
+ begin
+ t^.Active:= true;
+ t:= t^.NextGear
+ end
+end;
+
+procedure SetAllHHToActive; inline;
+begin
+SetAllHHToActive(true)
+end;
+
+
+procedure SetAllHHToActive(Ice: boolean);
+var t: PGear;
+begin
+AllInactive:= false;
+t:= GearsList;
+while t <> nil do
+ begin
+ if (t^.Kind = gtHedgehog) or (t^.Kind = gtExplosives) then
+ begin
+ if (t^.Kind = gtHedgehog) and Ice then CheckIce(t);
+ t^.Active:= true
+ end;
+ t:= t^.NextGear
+ end
+end;
+
+
+var GearsNearArray : TPGearArray;
+function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS;
+var
+ t: PGear;
+ s: Longword;
+begin
+ r:= r*r;
+ s:= 0;
+ SetLength(GearsNearArray, s);
+ t := GearsList;
+ while t <> nil do
+ begin
+ if (t^.Kind = Kind)
+ and ((X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) < int2hwFloat(r)) then
+ begin
+ inc(s);
+ SetLength(GearsNearArray, s);
+ GearsNearArray[s - 1] := t;
+ end;
+ t := t^.NextGear;
+ end;
+
+ GearsNear.size:= s;
+ GearsNear.ar:= @GearsNearArray
+end;
+
+
+procedure SpawnBoxOfSmth;
+var t, aTot, uTot, a, h: LongInt;
+ i: TAmmoType;
+begin
+if (PlacingHogs) or
+ (cCaseFactor = 0)
+ or (CountGears(gtCase) >= 5)
+ or (GetRandom(cCaseFactor) <> 0) then
+ exit;
+
+FollowGear:= nil;
+aTot:= 0;
+uTot:= 0;
+for i:= Low(TAmmoType) to High(TAmmoType) do
+ if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
+ inc(aTot, Ammoz[i].Probability)
+ else
+ inc(uTot, Ammoz[i].Probability);
+
+t:=0;
+a:=aTot;
+h:= 1;
+
+if (aTot+uTot) <> 0 then
+ if ((GameFlags and gfInvulnerable) = 0) then
+ begin
+ h:= cHealthCaseProb * 100;
+ t:= GetRandom(10000);
+ a:= (10000-h)*aTot div (aTot+uTot)
+ end
+ else
+ begin
+ t:= GetRandom(aTot+uTot);
+ h:= 0
+ end;
+
+
+if t 0) then
+ begin
+ FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
+ t:= GetRandom(t);
+ i:= Low(TAmmoType);
+ FollowGear^.Pos:= posCaseAmmo;
+ FollowGear^.AmmoType:= i;
+ AddCaption(GetEventString(eidNewAmmoPack), cWhiteColor, capgrpAmmoInfo);
+ end
+ end
+else
+ begin
+ t:= uTot;
+ if (t > 0) then
+ begin
+ FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
+ t:= GetRandom(t);
+ i:= Low(TAmmoType);
+ FollowGear^.Pos:= posCaseUtility;
+ FollowGear^.AmmoType:= i;
+ AddCaption(GetEventString(eidNewUtilityPack), cWhiteColor, capgrpAmmoInfo);
+ end
+ end;
+
+// handles case of no ammo or utility crates - considered also placing booleans in uAmmos and altering probabilities
+if (FollowGear <> nil) then
+ begin
+ FindPlace(FollowGear, true, 0, LAND_WIDTH);
+
+ if (FollowGear <> nil) then
+ AddVoice(sndReinforce, CurrentTeam^.voicepack)
+ end
+end;
+
+
+function GetAmmo(Hedgehog: PHedgehog): TAmmoType;
+var t, aTot: LongInt;
+ i: TAmmoType;
+begin
+Hedgehog:= Hedgehog; // avoid hint
+
+aTot:= 0;
+for i:= Low(TAmmoType) to High(TAmmoType) do
+ if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
+ inc(aTot, Ammoz[i].Probability);
+
+t:= aTot;
+i:= Low(TAmmoType);
+if (t > 0) then
+ begin
+ t:= GetRandom(t);
+ while t >= 0 do
+ begin
+ inc(i);
+ if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
+ dec(t, Ammoz[i].Probability)
+ end
+ end;
+GetAmmo:= i
+end;
+
+function GetUtility(Hedgehog: PHedgehog): TAmmoType;
+var t, uTot: LongInt;
+ i: TAmmoType;
+begin
+
+uTot:= 0;
+for i:= Low(TAmmoType) to High(TAmmoType) do
+ if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0)
+ and ((Hedgehog^.Team^.HedgehogsNumber > 1) or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then
+ inc(uTot, Ammoz[i].Probability);
+
+t:= uTot;
+i:= Low(TAmmoType);
+if (t > 0) then
+ begin
+ t:= GetRandom(t);
+ while t >= 0 do
+ begin
+ inc(i);
+ if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0) and ((Hedgehog^.Team^.HedgehogsNumber > 1)
+ or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then
+ dec(t, Ammoz[i].Probability)
+ end
+ end;
+GetUtility:= i
+end;
+
+(*
+Intended to check Gear X/Y against the map left/right edges and apply one of the world modes
+* Normal - infinite world, do nothing
+* Wrap (entering left edge exits at same height on right edge)
+* Bounce (striking edge is treated as a 100% elasticity bounce)
+* From the depths (same as from sky, but from sea, with submersible flag set)
+
+Trying to make the checks a little broader than on first pass to catch things that don't move normally.
+*)
+function WorldWrap(var Gear: PGear): boolean;
+var tdx: hwFloat;
+begin
+WorldWrap:= false;
+if WorldEdge = weNone then exit(false);
+if (hwRound(Gear^.X) - Gear^.Radius < LongInt(leftX)) or
+ (hwRound(Gear^.X) + LongInt(Gear^.Radius) > LongInt(rightX)) then
+ begin
+ if WorldEdge = weWrap then
+ begin
+ if (hwRound(Gear^.X) - Gear^.Radius < LongInt(leftX)) then
+ Gear^.X:= int2hwfloat(rightX - Gear^.Radius)
+ else Gear^.X:= int2hwfloat(LongInt(leftX) + Gear^.Radius);
+ LeftImpactTimer:= 150;
+ RightImpactTimer:= 150
+ end
+ else if WorldEdge = weBounce then
+ begin
+ if (hwRound(Gear^.X) - Gear^.Radius < LongInt(leftX)) then
+ begin
+ LeftImpactTimer:= 333;
+ Gear^.dX.isNegative:= false;
+ Gear^.X:= int2hwfloat(LongInt(leftX) + Gear^.Radius)
+ end
+ else
+ begin
+ RightImpactTimer:= 333;
+ Gear^.dX.isNegative:= true;
+ Gear^.X:= int2hwfloat(rightX-Gear^.Radius)
+ end;
+ if (Gear^.Radius > 2) and (Gear^.dX.QWordValue > _0_001.QWordValue) then
+ PlaySound(sndMelonImpact)
+ end
+ else if WorldEdge = weSea then
+ begin
+ if (hwRound(Gear^.Y) > cWaterLine) and (Gear^.State and gstSubmersible <> 0) then
+ Gear^.State:= Gear^.State and not gstSubmersible
+ else
+ begin
+ Gear^.State:= Gear^.State or gstSubmersible;
+ Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight;
+ Gear^.Y:= int2hwFloat(cWaterLine+cVisibleWater+Gear^.Radius*2);
+ tdx:= Gear^.dX;
+ Gear^.dX:= -Gear^.dY;
+ Gear^.dY:= tdx;
+ Gear^.dY.isNegative:= true
+ end
+ end;
+(*
+* Window in the sky (Gear moved high into the sky, Y is used to determine X) [unfortunately, not a safe thing to do. shame, I thought aerial bombardment would be kinda neat
+This one would be really easy to freeze game unless it was flagged unfortunately.
+
+ else
+ begin
+ Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight;
+ Gear^.Y:= -_2048-_256-_256;
+ tdx:= Gear^.dX;
+ Gear^.dX:= Gear^.dY;
+ Gear^.dY:= tdx;
+ Gear^.dY.isNegative:= false
+ end
+*)
+ WorldWrap:= true
+ end;
+end;
+
end.
diff -Nru hedgewars-0.9.19.3/hedgewars/uIO.pas hedgewars-0.9.20.5/hedgewars/uIO.pas
--- hedgewars-0.9.19.3/hedgewars/uIO.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uIO.pas 2014-01-08 16:25:17.000000000 +0000
@@ -212,7 +212,7 @@
end;
procedure SendStat(sit: TStatInfoType; s: shortstring);
-const stc: array [TStatInfoType] of char = ('r', 'D', 'k', 'K', 'H', 'T', 'P', 's', 'S', 'B');
+const stc: array [TStatInfoType] of char = ('r', 'D', 'k', 'K', 'H', 'T', 'P', 's', 'S', 'B', 'c', 'g', 'p');
var buf: shortstring;
begin
buf:= 'i' + stc[sit] + s;
@@ -411,6 +411,9 @@
procedure chFatalError(var s: shortstring);
begin
SendIPC('E' + s);
+ // TODO: should we try to clean more stuff here?
+ SDL_Quit;
+ halt(2)
end;
procedure doPut(putX, putY: LongInt; fromAI: boolean);
diff -Nru hedgewars-0.9.19.3/hedgewars/uInputHandler.pas hedgewars-0.9.20.5/hedgewars/uInputHandler.pas
--- hedgewars-0.9.19.3/hedgewars/uInputHandler.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uInputHandler.pas 2014-01-08 16:25:17.000000000 +0000
@@ -40,6 +40,8 @@
procedure SetBinds(var binds: TBinds);
procedure SetDefaultBinds;
procedure chDefaultBind(var id: shortstring);
+procedure loadBinds(cmd, s: shortstring);
+procedure addBind(var binds: TBinds; var id: shortstring);
procedure ControllerInit;
procedure ControllerAxisEvent(joy, axis: Byte; value: Integer);
@@ -47,7 +49,7 @@
procedure ControllerButtonEvent(joy, button: Byte; pressed: Boolean);
implementation
-uses uConsole, uCommands, uMisc, uVariables, uConsts, uUtils, uDebug;
+uses uConsole, uCommands, uMisc, uVariables, uConsts, uUtils, uDebug, uPhysFSLayer;
const
LSHIFT = $0200;
@@ -70,7 +72,6 @@
//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
@@ -135,7 +136,9 @@
Trusted:= (CurrentTeam <> nil)
and (not CurrentTeam^.ExtDriven)
and (CurrentHedgehog^.BotLevel = 0);
-
+// REVIEW OR FIXME
+// ctrl/cmd + q to close engine and frontend - this seems like a bad idea, since we let people set arbitrary binds, and don't warn them of this.
+// There's no confirmation at all
// ctrl/cmd + q to close engine and frontend
if(KeyDown and (code = SDLK_q)) then
begin
@@ -166,21 +169,32 @@
if CurrentBinds[code][0] <> #0 then
begin
if (code > 3) and KeyDown and (not ((CurrentBinds[code] = 'put')) or (CurrentBinds[code] = 'ammomenu') or (CurrentBinds[code] = '+cur_u') or (CurrentBinds[code] = '+cur_d') or (CurrentBinds[code] = '+cur_l') or (CurrentBinds[code] = '+cur_r')) and (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) then bShowAmmoMenu:= false;
-
if KeyDown then
begin
+ if CurrentBinds[code] = 'switch' then
+ LocalMessage:= LocalMessage or gmSwitch
+ else if CurrentBinds[code] = '+precise' then
+ LocalMessage:= LocalMessage or gmPrecise;
+
ParseCommand(CurrentBinds[code], Trusted);
if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
ParseCommand('gencmd R', true)
end
else if (CurrentBinds[code][1] = '+') then
begin
+ if CurrentBinds[code] = '+precise' then
+ LocalMessage:= LocalMessage and not(gmPrecise);
s:= CurrentBinds[code];
s[1]:= '-';
ParseCommand(s, Trusted);
if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
ParseCommand('gencmd R', true)
- end;
+ end
+ else
+ begin
+ if CurrentBinds[code] = 'switch' then
+ LocalMessage:= LocalMessage and not(gmSwitch)
+ end
end
end;
@@ -312,10 +326,10 @@
DefaultBinds[KeyNameToCode('j0a0d')]:= '+right';
DefaultBinds[KeyNameToCode('j0a1u')]:= '+up';
DefaultBinds[KeyNameToCode('j0a1d')]:= '+down';
-for i:= 1 to 10 do DefaultBinds[KeyNameToCode('f'+IntToStr(i))]:= 'slot '+IntToStr(i);
+for i:= 1 to 10 do DefaultBinds[KeyNameToCode('f'+IntToStr(i))]:= 'slot '+char(i+48);
for i:= 1 to 5 do DefaultBinds[KeyNameToCode(IntToStr(i))]:= 'timer '+IntToStr(i);
-SetDefaultBinds();
+loadBinds('dbind', cPathz[ptData] + '/settings.ini');
end;
procedure SetBinds(var binds: TBinds);
@@ -449,22 +463,68 @@
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);
+procedure loadBinds(cmd, s: shortstring);
+var i: LongInt;
+ f: PFSFile;
+ p, l: shortstring;
+ b: byte;
+begin
+ AddFileLog('[BINDS] Loading binds from: ' + s);
+
+ l:= '';
+ if pfsExists(s) then
+ begin
+ f:= pfsOpenRead(s);
+ while (not pfsEOF(f)) and (l <> '[Binds]') do
+ pfsReadLn(f, l);
+
+ while (not pfsEOF(f)) and (l <> '') do
+ begin
+ pfsReadLn(f, l);
+
+ p:= '';
+ i:= 1;
+ while (i <= length(l)) and (l[i] <> '=') do
+ begin
+ if l[i] <> '%' then
+ begin
+ p:= p + l[i];
+ inc(i)
+ end else
+ begin
+ l[i]:= '$';
+ val(copy(l, i, 3), b);
+ p:= p + char(b);
+ inc(i, 3)
+ end;
+ end;
+
+ if i < length(l) then
+ begin
+ l:= copy(l, i + 1, length(l) - i);
+ if l <> 'default' then
+ begin
+ p:= cmd + ' ' + l + ' ' + p;
+ ParseCommand(p, true)
+ end
+ end
+ end;
+
+ pfsClose(f)
+ end
+ else
+ AddFileLog('[BINDS] file not found');
+end;
+
+
+procedure addBind(var binds: TBinds; var id: shortstring);
var KeyName, Modifier, tmp: shortstring;
- b: LongInt;
+ i, b: LongInt;
begin
KeyName:= '';
Modifier:= '';
-if (not usingDBinds) then
- begin
- usingDBinds:= true;
- FillByte(DefaultBinds, SizeOf(DefaultBinds), 0);
- end;
-
-if (Pos('mod:', id) <> 0) then
+if(Pos('mod:', id) <> 0)then
begin
tmp:= '';
SplitBySpace(id, tmp);
@@ -481,12 +541,27 @@
if b = 0 then
OutError(errmsgUnknownVariable + ' "' + id + '"', false)
else
- DefaultBinds[b]:= KeyName;
+ begin
+ // add bind: first check if this cmd is already bound, and remove old bind
+ i:= cKbdMaxIndex;
+ repeat
+ dec(i)
+ until (i < 0) or (binds[i] = KeyName);
+ if (i >= 0) then
+ binds[i]:= '';
+
+ binds[b]:= KeyName;
+ end
+end;
+
+// Bind that isn't a team bind, but overrides defaultbinds.
+procedure chDefaultBind(var id: shortstring);
+begin
+ addBind(DefaultBinds, id)
end;
procedure initModule;
begin
- usingDBinds:= false;
RegisterVariable('dbind', @chDefaultBind, true );
end;
diff -Nru hedgewars-0.9.19.3/hedgewars/uLand.pas hedgewars-0.9.20.5/hedgewars/uLand.pas
--- hedgewars-0.9.19.3/hedgewars/uLand.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uLand.pas 2014-01-08 16:25:17.000000000 +0000
@@ -20,7 +20,7 @@
unit uLand;
interface
-uses SDLh, uLandTemplates, uFloat, uConsts, GLunit, uTypes, uAILandMarks;
+uses SDLh, uLandTemplates, uFloat, uConsts, uTypes, uAILandMarks;
procedure initModule;
procedure freeModule;
@@ -60,29 +60,12 @@
end;
end;
-procedure ColorizeLand(Surface: PSDL_Surface);
+
+procedure DrawBorderFromImage(Surface: PSDL_Surface);
var tmpsurf: PSDL_Surface;
r, rr: TSDL_Rect;
x, yd, yu: LongInt;
begin
- tmpsurf:= LoadDataImage(ptCurrTheme, 'LandTex', ifCritical or ifIgnoreCaps);
- r.y:= 0;
- while r.y < LAND_HEIGHT do
- begin
- r.x:= 0;
- while r.x < LAND_WIDTH do
- begin
- SDL_UpperBlit(tmpsurf, nil, Surface, @r);
- inc(r.x, tmpsurf^.w)
- end;
- inc(r.y, tmpsurf^.h)
- end;
- SDL_FreeSurface(tmpsurf);
-
- // freed in freeModule() below
- LandBackSurface:= LoadDataImage(ptCurrTheme, 'LandBackTex', ifIgnoreCaps or ifTransparent);
- if (LandBackSurface <> nil) and GrayScale then Surface2GrayScale(LandBackSurface);
-
tmpsurf:= LoadDataImage(ptCurrTheme, 'Border', ifCritical or ifIgnoreCaps or ifTransparent);
for x:= 0 to LAND_WIDTH - 1 do
begin
@@ -127,6 +110,109 @@
SDL_FreeSurface(tmpsurf);
end;
+
+procedure DrawShoppaBorder;
+var x, y, s, i: Longword;
+ c1, c2, c: Longword;
+begin
+ c1:= AMask;
+ c2:= AMask or RMask or GMask;
+
+ // vertical
+ s:= LAND_HEIGHT;
+
+ for x:= 0 to LAND_WIDTH - 1 do
+ for y:= 0 to LAND_HEIGHT - 1 do
+ if Land[y, x] = 0 then
+ if s < y then
+ begin
+ for i:= max(s, y - 8) to y - 1 do
+ begin
+ if ((x + i) and 16) = 0 then c:= c1 else c:= c2;
+
+ if (cReducedQuality and rqBlurryLand) = 0 then
+ LandPixels[i, x]:= c
+ else
+ LandPixels[i div 2, x div 2]:= c
+ end;
+ s:= LAND_HEIGHT
+ end
+ else
+ else
+ begin
+ if s > y then s:= y;
+ if s + 8 > y then
+ begin
+ if ((x + y) and 16) = 0 then c:= c1 else c:= c2;
+
+ if (cReducedQuality and rqBlurryLand) = 0 then
+ LandPixels[y, x]:= c
+ else
+ LandPixels[y div 2, x div 2]:= c
+ end;
+ end;
+
+ // horizontal
+ s:= LAND_WIDTH;
+
+ for y:= 0 to LAND_HEIGHT - 1 do
+ for x:= 0 to LAND_WIDTH - 1 do
+ if Land[y, x] = 0 then
+ if s < x then
+ begin
+ for i:= max(s, x - 8) to x - 1 do
+ begin
+ if ((y + i) and 16) = 0 then c:= c1 else c:= c2;
+
+ if (cReducedQuality and rqBlurryLand) = 0 then
+ LandPixels[y, i]:= c
+ else
+ LandPixels[y div 2, i div 2]:= c
+ end;
+ s:= LAND_WIDTH
+ end
+ else
+ else
+ begin
+ if s > x then s:= x;
+ if s + 8 > x then
+ begin
+ if ((x + y) and 16) = 0 then c:= c1 else c:= c2;
+
+ if (cReducedQuality and rqBlurryLand) = 0 then
+ LandPixels[y, x]:= c
+ else
+ LandPixels[y div 2, x div 2]:= c
+ end;
+ end
+end;
+
+procedure ColorizeLand(Surface: PSDL_Surface);
+var tmpsurf: PSDL_Surface;
+ r: TSDL_Rect;
+ y: LongWord; // stupid SDL 1.2 uses stupid SmallInt for y which limits us to 32767. But is even worse if LandTex is large, can overflow on 32767 map.
+begin
+ tmpsurf:= LoadDataImage(ptCurrTheme, 'LandTex', ifCritical or ifIgnoreCaps);
+ r.y:= 0;
+ y:= 0;
+ while y < LAND_HEIGHT do
+ begin
+ r.x:= 0;
+ while r.x < LAND_WIDTH do
+ begin
+ SDL_UpperBlit(tmpsurf, nil, Surface, @r);
+ inc(r.x, tmpsurf^.w)
+ end;
+ inc(y, tmpsurf^.h);
+ r.y:= y
+ end;
+ SDL_FreeSurface(tmpsurf);
+
+ // freed in freeModule() below
+ LandBackSurface:= LoadDataImage(ptCurrTheme, 'LandBackTex', ifIgnoreCaps or ifTransparent);
+ if (LandBackSurface <> nil) and GrayScale then Surface2GrayScale(LandBackSurface);
+end;
+
procedure SetPoints(var Template: TEdgeTemplate; var pa: TPixAr; fps: PPointArray);
var i: LongInt;
begin
@@ -275,22 +361,34 @@
end;
function SelectTemplate: LongInt;
+var l: LongInt;
begin
if (cReducedQuality and rqLowRes) <> 0 then
SelectTemplate:= SmallTemplates[getrandom(Succ(High(SmallTemplates)))]
else
+ begin
+ if cTemplateFilter = 0 then
+ begin
+ l:= getRandom(GroupedTemplatesCount);
+ repeat
+ inc(cTemplateFilter);
+ dec(l, TemplateCounts[cTemplateFilter]);
+ until l < 0;
+ end else getRandom(1);
+
case cTemplateFilter of
- 0: SelectTemplate:= getrandom(Succ(High(EdgeTemplates)));
- 1: SelectTemplate:= SmallTemplates[getrandom(Succ(High(SmallTemplates)))];
- 2: SelectTemplate:= MediumTemplates[getrandom(Succ(High(MediumTemplates)))];
- 3: SelectTemplate:= LargeTemplates[getrandom(Succ(High(LargeTemplates)))];
- 4: SelectTemplate:= CavernTemplates[getrandom(Succ(High(CavernTemplates)))];
- 5: SelectTemplate:= WackyTemplates[getrandom(Succ(High(WackyTemplates)))];
+ 0: OutError('Ask unC0Rr about what you did wrong', true);
+ 1: SelectTemplate:= SmallTemplates[getrandom(TemplateCounts[cTemplateFilter])];
+ 2: SelectTemplate:= MediumTemplates[getrandom(TemplateCounts[cTemplateFilter])];
+ 3: SelectTemplate:= LargeTemplates[getrandom(TemplateCounts[cTemplateFilter])];
+ 4: SelectTemplate:= CavernTemplates[getrandom(TemplateCounts[cTemplateFilter])];
+ 5: SelectTemplate:= WackyTemplates[getrandom(TemplateCounts[cTemplateFilter])];
// For lua only!
6: begin
SelectTemplate:= min(LuaTemplateNumber,High(EdgeTemplates));
GetRandom(2) // burn 1
end;
+ end
end;
WriteLnToConsole('Selected template #'+inttostr(SelectTemplate)+' using filter #'+inttostr(cTemplateFilter));
@@ -333,10 +431,14 @@
TryDo(tmpsurf <> nil, 'Error creating pre-land surface', true);
ColorizeLand(tmpsurf);
+ if gameFlags and gfShoppaBorder = 0 then DrawBorderFromImage(tmpsurf);
AddOnLandObjects(tmpsurf);
LandSurface2LandPixels(tmpsurf);
SDL_FreeSurface(tmpsurf);
+
+ if gameFlags and gfShoppaBorder <> 0 then DrawShoppaBorder;
+
for x:= leftX+2 to rightX-2 do
for y:= topY+2 to LAND_HEIGHT-3 do
if (Land[y, x] = 0) and
@@ -517,7 +619,7 @@
tmpsurf:= LoadDataImage(ptMissionMaps, mapName + '/map', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
end;
// (bare) Sanity check. Considering possible LongInt comparisons as well as just how much system memoery it would take
-TryDo((tmpsurf^.w < $40000000) and (tmpsurf^.h < $40000000) and (tmpsurf^.w * tmpsurf^.h < 6*1024*1024*1024), 'Map dimensions too big!', true);
+TryDo((tmpsurf^.w < $40000000) and (tmpsurf^.h < $40000000) and (QWord(tmpsurf^.w) * tmpsurf^.h < 6*1024*1024*1024), 'Map dimensions too big!', true);
ResizeLand(tmpsurf^.w, tmpsurf^.h);
LoadMapConfig;
@@ -630,26 +732,27 @@
// also try basing cave dimensions on map/template dimensions, if they exist
for w:= 0 to 5 do // width of 3 allowed hogs to be knocked through with grenade
begin
- for y:= topY to LAND_HEIGHT - 1 do
- begin
- Land[y, leftX + w]:= lfIndestructible;
- Land[y, rightX - w]:= lfIndestructible;
- if (y + w) mod 32 < 16 then
- c:= AMask
- else
- c:= AMask or RMask or GMask; // FF00FFFF
-
- if (cReducedQuality and rqBlurryLand) = 0 then
+ if (WorldEdge <> weBounce) and (WorldEdge <> weWrap) then
+ for y:= topY to LAND_HEIGHT - 1 do
begin
- LandPixels[y, leftX + w]:= c;
- LandPixels[y, rightX - w]:= c;
- end
- else
- begin
- LandPixels[y div 2, (leftX + w) div 2]:= c;
- LandPixels[y div 2, (rightX - w) div 2]:= c;
+ Land[y, leftX + w]:= lfIndestructible;
+ Land[y, rightX - w]:= lfIndestructible;
+ if (y + w) mod 32 < 16 then
+ c:= AMask
+ else
+ c:= AMask or RMask or GMask; // FF00FFFF
+
+ if (cReducedQuality and rqBlurryLand) = 0 then
+ begin
+ LandPixels[y, leftX + w]:= c;
+ LandPixels[y, rightX - w]:= c;
+ end
+ else
+ begin
+ LandPixels[y div 2, (leftX + w) div 2]:= c;
+ LandPixels[y div 2, (rightX - w) div 2]:= c;
+ end;
end;
- end;
for x:= leftX to rightX do
begin
diff -Nru hedgewars-0.9.19.3/hedgewars/uLandGraphics.pas hedgewars-0.9.20.5/hedgewars/uLandGraphics.pas
--- hedgewars-0.9.19.3/hedgewars/uLandGraphics.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uLandGraphics.pas 2014-01-08 16:25:17.000000000 +0000
@@ -40,14 +40,15 @@
procedure DrawHLinesExplosions(ar: PRangeArray; Radius: LongInt; y, dY: LongInt; Count: Byte);
procedure DrawTunnel(X, Y, dX, dY: hwFloat; ticks, HalfWidth: LongInt);
procedure FillRoundInLand(X, Y, Radius: LongInt; Value: Longword);
-function FillRoundInLand(X, Y, Radius: LongInt; fill: fillType): LongWord;
+function FillRoundInLandFT(X, Y, Radius: LongInt; fill: fillType): Longword;
procedure ChangeRoundInLand(X, Y, Radius: LongInt; doSet, isCurrent: boolean);
function LandBackPixel(x, y: LongInt): LongWord;
procedure DrawLine(X1, Y1, X2, Y2: LongInt; Color: Longword);
procedure DrawThickLine(X1, Y1, X2, Y2, radius: LongInt; color: Longword);
procedure DumpLandToLog(x, y, r: LongInt);
procedure DrawIceBreak(x, y, iceRadius, iceHeight: Longint);
-function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; indestructible: boolean): boolean;
+function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean; inline;
+function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean; LandFlags: Word): boolean;
implementation
uses SDLh, uLandTexture, uVariables, uUtils, uDebug;
@@ -125,6 +126,7 @@
icePixels: PLongwordArray;
w: LongWord;
begin
+ if cOnlyStats then exit;
// So. 3 parameters here. Ice colour, Ice opacity, and a bias on the greyscaled pixel towards lightness
iceSurface:= SpritesData[sprIceTexture].Surface;
icePixels := iceSurface^.pixels;
@@ -169,87 +171,87 @@
end;
-function FillLandCircleLine(y, fromPix, toPix: LongInt; fill : fillType): Longword;
+function FillLandCircleLineFT(y, fromPix, toPix: LongInt; fill : fillType): Longword;
var px, py, i: LongInt;
begin
//get rid of compiler warning
px := 0;
py := 0;
- FillLandCircleLine := 0;
+ FillLandCircleLineFT := 0;
case fill of
backgroundPixel:
- for i:= fromPix to toPix do
- begin
- calculatePixelsCoordinates(i, y, px, py);
- inc(FillLandCircleLine, drawPixelBG(i, y, px, py));
- end;
+ for i:= fromPix to toPix do
+ begin
+ calculatePixelsCoordinates(i, y, px, py);
+ inc(FillLandCircleLineFT, drawPixelBG(i, y, px, py));
+ end;
ebcPixel:
- for i:= fromPix to toPix do
- begin
- calculatePixelsCoordinates(i, y, px, py);
- drawPixelEBC(i, y, px, py);
- end;
+ for i:= fromPix to toPix do
+ begin
+ calculatePixelsCoordinates(i, y, px, py);
+ drawPixelEBC(i, y, px, py);
+ end;
nullPixel:
- for i:= fromPix to toPix do
- begin
- calculatePixelsCoordinates(i, y, px, py);
- if ((Land[y, i] and lfIndestructible) = 0) and (not disableLandBack or (Land[y, i] > 255)) then
- LandPixels[py, px]:= 0
- end;
+ for i:= fromPix to toPix do
+ begin
+ calculatePixelsCoordinates(i, y, px, py);
+ if ((Land[y, i] and lfIndestructible) = 0) and (not disableLandBack or (Land[y, i] > 255)) then
+ LandPixels[py, px]:= 0
+ end;
icePixel:
- for i:= fromPix to toPix do
- begin
- calculatePixelsCoordinates(i, y, px, py);
- DrawPixelIce(i, y, px, py);
- end;
+ for i:= fromPix to toPix do
+ begin
+ calculatePixelsCoordinates(i, y, px, py);
+ DrawPixelIce(i, y, px, py);
+ end;
setNotCurrentMask:
- for i:= fromPix to toPix do
- begin
- Land[y, i]:= Land[y, i] and lfNotCurrentMask;
- end;
+ for i:= fromPix to toPix do
+ begin
+ Land[y, i]:= Land[y, i] and lfNotCurrentMask;
+ end;
changePixelSetNotCurrent:
- for i:= fromPix to toPix do
- begin
- if Land[y, i] and lfObjMask > 0 then
- Land[y, i]:= (Land[y, i] and lfNotObjMask) or ((Land[y, i] and lfObjMask) - 1);
- end;
+ for i:= fromPix to toPix do
+ begin
+ if Land[y, i] and lfObjMask > 0 then
+ Land[y, i]:= Land[y, i] - 1;
+ end;
setCurrentHog:
- for i:= fromPix to toPix do
- begin
- Land[y, i]:= Land[y, i] or lfCurrentHog
- end;
+ for i:= fromPix to toPix do
+ begin
+ Land[y, i]:= Land[y, i] or lfCurrentHog
+ end;
changePixelNotSetNotCurrent:
- for i:= fromPix to toPix do
- begin
- if Land[y, i] and lfObjMask < lfObjMask then
- Land[y, i]:= (Land[y, i] and lfNotObjMask) or ((Land[y, i] and lfObjMask) + 1)
- end;
+ for i:= fromPix to toPix do
+ begin
+ if Land[y, i] and lfObjMask < lfObjMask then
+ Land[y, i]:= Land[y, i] + 1
+ end;
end;
end;
-function FillLandCircleSegment(x, y, dx, dy: LongInt; fill : fillType): Longword; inline;
+function FillLandCircleSegmentFT(x, y, dx, dy: LongInt; fill : fillType): Longword; inline;
begin
- FillLandCircleSegment := 0;
+ FillLandCircleSegmentFT := 0;
if ((y + dy) and LAND_HEIGHT_MASK) = 0 then
- inc(FillLandCircleSegment, FillLandCircleLine(y + dy, Max(x - dx, 0), Min(x + dx, LAND_WIDTH - 1), fill));
+ inc(FillLandCircleSegmentFT, FillLandCircleLineFT(y + dy, Max(x - dx, 0), Min(x + dx, LAND_WIDTH - 1), fill));
if ((y - dy) and LAND_HEIGHT_MASK) = 0 then
- inc(FillLandCircleSegment, FillLandCircleLine(y - dy, Max(x - dx, 0), Min(x + dx, LAND_WIDTH - 1), fill));
+ inc(FillLandCircleSegmentFT, FillLandCircleLineFT(y - dy, Max(x - dx, 0), Min(x + dx, LAND_WIDTH - 1), fill));
if ((y + dx) and LAND_HEIGHT_MASK) = 0 then
- inc(FillLandCircleSegment, FillLandCircleLine(y + dx, Max(x - dy, 0), Min(x + dy, LAND_WIDTH - 1), fill));
+ inc(FillLandCircleSegmentFT, FillLandCircleLineFT(y + dx, Max(x - dy, 0), Min(x + dy, LAND_WIDTH - 1), fill));
if ((y - dx) and LAND_HEIGHT_MASK) = 0 then
- inc(FillLandCircleSegment, FillLandCircleLine(y - dx, Max(x - dy, 0), Min(x + dy, LAND_WIDTH - 1), fill));
+ inc(FillLandCircleSegmentFT, FillLandCircleLineFT(y - dx, Max(x - dy, 0), Min(x + dy, LAND_WIDTH - 1), fill));
end;
-function FillRoundInLand(X, Y, Radius: LongInt; fill: fillType): Longword; inline;
+function FillRoundInLandFT(X, Y, Radius: LongInt; fill: fillType): Longword; inline;
var dx, dy, d: LongInt;
begin
dx:= 0;
dy:= Radius;
d:= 3 - 2 * Radius;
-FillRoundInLand := 0;
+FillRoundInLandFT := 0;
while (dx < dy) do
begin
- inc(FillRoundInLand, FillLandCircleSegment(x, y, dx, dy, fill));
+ inc(FillRoundInLandFT, FillLandCircleSegmentFT(x, y, dx, dy, fill));
if (d < 0) then
d:= d + 4 * dx + 6
else
@@ -260,7 +262,7 @@
inc(dx)
end;
if (dx = dy) then
- inc (FillRoundInLand, FillLandCircleSegment(x, y, dx, dy, fill));
+ inc (FillRoundInLandFT, FillLandCircleSegmentFT(x, y, dx, dy, fill));
end;
@@ -341,13 +343,13 @@
procedure ChangeRoundInLand(X, Y, Radius: LongInt; doSet, isCurrent: boolean);
begin
if not doSet and isCurrent then
- FillRoundInLand(X, Y, Radius, setNotCurrentMask)
+ FillRoundInLandFT(X, Y, Radius, setNotCurrentMask)
else if not doSet and not IsCurrent then
- FillRoundInLand(X, Y, Radius, changePixelSetNotCurrent)
+ FillRoundInLandFT(X, Y, Radius, changePixelSetNotCurrent)
else if doSet and IsCurrent then
- FillRoundInLand(X, Y, Radius, setCurrentHog)
+ FillRoundInLandFT(X, Y, Radius, setCurrentHog)
else if doSet and not IsCurrent then
- FillRoundInLand(X, Y, Radius, changePixelNotSetNotCurrent);
+ FillRoundInLandFT(X, Y, Radius, changePixelNotSetNotCurrent);
end;
procedure DrawIceBreak(x, y, iceRadius, iceHeight: Longint);
@@ -377,11 +379,11 @@
var
tx, ty, dx, dy: Longint;
begin
- DrawExplosion := FillRoundInLand(x, y, Radius, backgroundPixel);
+ DrawExplosion := FillRoundInLandFT(x, y, Radius, backgroundPixel);
if Radius > 20 then
- FillRoundInLand(x, y, Radius - 15, nullPixel);
+ FillRoundInLandFT(x, y, Radius - 15, nullPixel);
FillRoundInLand(X, Y, Radius, 0);
- FillRoundInLand(x, y, Radius + 4, ebcPixel);
+ FillRoundInLandFT(x, y, Radius + 4, ebcPixel);
tx:= Max(X - Radius - 5, 0);
dx:= Min(X + Radius + 5, LAND_WIDTH) - tx;
ty:= Max(Y - Radius - 5, 0);
@@ -584,7 +586,12 @@
UpdateLandTexture(tx, ddx, ty, ddy, false)
end;
-function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; indestructible: boolean): boolean;
+function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean; inline;
+begin
+TryPlaceOnLand:= TryPlaceOnLand(cpX, cpY, Obj, Frame, doPlace, indestructible, 0);
+end;
+
+function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean; LandFlags: Word): boolean;
var X, Y, bpp, h, w, row, col, gx, gy, numFramesFirstCol: LongInt;
p: PByteArray;
Image: PSDL_Surface;
@@ -649,15 +656,12 @@
gY:= (cpY + y) div 2;
end;
if indestructible then
- Land[cpY + y, cpX + x]:= lfIndestructible
+ Land[cpY + y, cpX + x]:= lfIndestructible or LandFlags
else if (LandPixels[gY, gX] and AMask) shr AShift = 255 then // This test assumes lfBasic and lfObject differ only graphically
- Land[cpY + y, cpX + x]:= lfBasic
+ Land[cpY + y, cpX + x]:= lfBasic or LandFlags
else
- Land[cpY + y, cpX + x]:= lfObject;
- // For testing only. Intent is to flag this on objects with masks, or use it for an ice ray gun
- if (Theme = 'Snow') or (Theme = 'Christmas') then
- Land[cpY + y, cpX + x]:= Land[cpY + y, cpX + x] or lfIce;
- LandPixels[gY, gX]:= PLongword(@(p^[x * 4]))^
+ Land[cpY + y, cpX + x]:= lfObject or LandFlags;
+ LandPixels[gY, gX]:= PLongword(@(p^[x * 4]))^
end;
p:= @(p^[Image^.pitch]);
end;
diff -Nru hedgewars-0.9.19.3/hedgewars/uLandObjects.pas hedgewars-0.9.20.5/hedgewars/uLandObjects.pas
--- hedgewars-0.9.19.3/hedgewars/uLandObjects.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uLandObjects.pas 2014-01-08 16:25:17.000000000 +0000
@@ -26,13 +26,13 @@
procedure FreeLandObjects();
procedure LoadThemeConfig;
procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface); inline;
-procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; extraFlags: Word);
+procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word);
procedure BlitImageUsingMask(cpX, cpY: Longword; Image, Mask: PSDL_Surface);
procedure AddOnLandObjects(Surface: PSDL_Surface);
procedure SetLand(var LandWord: Word; Pixel: LongWord); inline;
implementation
-uses uStore, uConsts, uConsole, uRandom, uSound, GLunit
+uses uStore, uConsts, uConsole, uRandom, uSound
, uTypes, uVariables, uUtils, uDebug, SysUtils
, uPhysFSLayer;
@@ -95,7 +95,7 @@
BlitImageAndGenerateCollisionInfo(cpX, cpY, Width, Image, 0);
end;
-procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; extraFlags: Word);
+procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word);
var p: PLongwordArray;
x, y: Longword;
bpp: LongInt;
@@ -128,10 +128,7 @@
LandPixels[(cpY + y) div 2, (cpX + x) div 2]:= p^[x];
if (Land[cpY + y, cpX + x] <= lfAllObjMask) and ((p^[x] and AMask) <> 0) then
- begin
- Land[cpY + y, cpX + x]:= lfObject;
- Land[cpY + y, cpX + x]:= Land[cpY + y, cpX + x] or extraFlags
- end;
+ Land[cpY + y, cpX + x]:= lfObject or LandFlags
end;
p:= @(p^[Image^.pitch shr 2])
end;
@@ -280,8 +277,7 @@
rr.x:= x1;
while rr.x < x2 do
begin
- // For testing only. Intent is to flag this on objects with masks, or use it for an ice ray gun
- if (Theme = 'Snow') or (Theme = 'Christmas') then
+ if cIce then
BlitImageAndGenerateCollisionInfo(rr.x, y, min(x2 - rr.x, tmpsurf^.w), tmpsurf, lfIce)
else
BlitImageAndGenerateCollisionInfo(rr.x, y, min(x2 - rr.x, tmpsurf^.w), tmpsurf);
@@ -499,7 +495,7 @@
s:= cPathz[ptCurrTheme] + '/' + cThemeCFGFilename;
WriteLnToConsole('Reading objects info...');
f:= pfsOpenRead(s);
-TryDo(f <> nil, 'Bad data or cannot access file ' + cThemeCFGFilename, true);
+TryDo(f <> nil, 'Bad data or cannot access file ' + s, true);
ThemeObjects.Count:= 0;
SprayObjects.Count:= 0;
@@ -535,7 +531,7 @@
SkyColor.g:= t;
SkyColor.b:= t
end;
- glClearColor(SkyColor.r / 255, SkyColor.g / 255, SkyColor.b / 255, 0.99);
+ SetSkyColor(SkyColor.r / 255, SkyColor.g / 255, SkyColor.b / 255);
SDSkyColor.r:= SkyColor.r;
SDSkyColor.g:= SkyColor.g;
SDSkyColor.b:= SkyColor.b;
@@ -709,6 +705,10 @@
cFlattenFlakes:= true
else if key = 'flatten-clouds' then
cFlattenClouds:= true
+ else if key = 'ice' then
+ cIce:= true
+ else if key = 'snow' then
+ cSnow:= true
else if key = 'sd-water-top' then
begin
i:= Pos(',', s);
@@ -794,7 +794,7 @@
RQSkyColor.g:= t;
RQSkyColor.b:= t
end;
- glClearColor(RQSkyColor.r / 255, RQSkyColor.g / 255, RQSkyColor.b / 255, 0.99);
+ SetSkyColor(RQSkyColor.r / 255, RQSkyColor.g / 255, RQSkyColor.b / 255);
SDSkyColor.r:= RQSkyColor.r;
SDSkyColor.g:= RQSkyColor.g;
SDSkyColor.b:= RQSkyColor.b;
diff -Nru hedgewars-0.9.19.3/hedgewars/uLandPainted.pas hedgewars-0.9.20.5/hedgewars/uLandPainted.pas
--- hedgewars-0.9.19.3/hedgewars/uLandPainted.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uLandPainted.pas 2013-10-31 20:21:56.000000000 +0000
@@ -27,7 +27,7 @@
procedure freeModule;
implementation
-uses uLandGraphics, uConsts, uVariables, uUtils, SDLh, uCommands, uDebug;
+uses uLandGraphics, uConsts, uVariables, uUtils, SDLh, uCommands, uDebug, uScript;
type PointRec = packed record
X, Y: SmallInt;
@@ -88,7 +88,11 @@
radius:= 0;
pe:= pointsListHead;
- TryDo((pe = nil) or (pe^.point.flags and $80 <> 0), 'Corrupted draw data', true);
+ while (pe <> nil) and (pe^.point.flags and $80 = 0) do
+ begin
+ ScriptCall('onSpecialPoint', pe^.point.X, pe^.point.Y, pe^.point.flags);
+ pe:= pe^.next;
+ end;
while(pe <> nil) do
begin
@@ -110,7 +114,7 @@
end;
prevPoint:= pe^.point;
- pe:= pe^.next;
+ pe:= pe^.next;
end;
end;
diff -Nru hedgewars-0.9.19.3/hedgewars/uLandTemplates.pas hedgewars-0.9.20.5/hedgewars/uLandTemplates.pas
--- hedgewars-0.9.19.3/hedgewars/uLandTemplates.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uLandTemplates.pas 2014-01-08 16:25:17.000000000 +0000
@@ -2327,6 +2327,19 @@
const CavernTemplates: array[0..5] of Longword = (36, 2, 3, 21, 29, 45);
//const WackyTemplates: array[0..4] of Longword = (37, 38, 39, 40, 41);
const WackyTemplates: array[0..4] of Longword = (37, 38, 41, 43, 44);
+const TemplateCounts: array[0..5] of Longword = (
+ 0
+ , Succ(High(SmallTemplates))
+ , Succ(High(MediumTemplates))
+ , Succ(High(LargeTemplates))
+ , Succ(High(CavernTemplates))
+ , Succ(High(WackyTemplates))
+ );
+const GroupedTemplatesCount = Succ(High(SmallTemplates))
+ + Succ(High(MediumTemplates))
+ + Succ(High(LargeTemplates))
+ + Succ(High(CavernTemplates))
+ + Succ(High(WackyTemplates));
implementation
diff -Nru hedgewars-0.9.19.3/hedgewars/uMisc.pas hedgewars-0.9.20.5/hedgewars/uMisc.pas
--- hedgewars-0.9.19.3/hedgewars/uMisc.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uMisc.pas 2014-01-08 16:25:17.000000000 +0000
@@ -30,7 +30,7 @@
function doSurfaceConversion(tmpsurf: PSDL_Surface): PSDL_Surface;
function MakeScreenshot(filename: shortstring; k: LongInt): boolean;
function GetTeamStatString(p: PTeam): shortstring;
-{$IFDEF SDL13}
+{$IFDEF SDL2}
function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect; inline;
{$ELSE}
function SDL_RectMake(x, y: SmallInt; width, height: Word): TSDL_Rect; inline;
@@ -261,7 +261,7 @@
image^.size:= size;
image^.buffer:= p;
-SDL_CreateThread(@SaveScreenshot{$IFDEF SDL13}, 'snapshot'{$ENDIF}, image);
+SDL_CreateThread(@SaveScreenshot{$IFDEF SDL2}, 'snapshot'{$ENDIF}, image);
MakeScreenshot:= true; // possibly it is not true but we will not wait for thread to terminate
end;
@@ -279,7 +279,7 @@
end;
end;
-{$IFDEF SDL13}
+{$IFDEF SDL2}
function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect; inline;
{$ELSE}
function SDL_RectMake(x, y: SmallInt; width, height: Word): TSDL_Rect; inline;
@@ -299,14 +299,29 @@
end;
procedure initModule;
-const SDL_PIXELFORMAT_ABGR8888 = (1 shl 31) or (6 shl 24) or (7 shl 20) or (6 shl 16) or (32 shl 8) or 4;
+{$IFDEF SDL2}
+const SDL_PIXELFORMAT_ABGR8888 = (1 shl 28) or (6 shl 24) or (7 shl 20) or (6 shl 16) or (32 shl 8) or 4;
+{$ELSE}
+const format: TSDL_PixelFormat = (
+ palette: nil; BitsPerPixel: 32; BytesPerPixel: 4;
+ Rloss: 0; Gloss: 0; Bloss: 0; Aloss: 0;
+ Rshift: RShift; Gshift: GShift; Bshift: BShift; Ashift: AShift;
+ RMask: RMask; GMask: GMask; BMask: BMask; AMask: AMask;
+ colorkey: 0; alpha: 255);
+{$ENDIF}
begin
+{$IFDEF SDL2}
conversionFormat:= SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888);
+{$ELSE}
+ conversionFormat:= @format;
+{$ENDIF}
end;
procedure freeModule;
begin
+{$IFDEF SDL2}
SDL_FreeFormat(conversionFormat);
+{$ENDIF}
end;
end.
diff -Nru hedgewars-0.9.19.3/hedgewars/uPhysFSLayer.pas hedgewars-0.9.20.5/hedgewars/uPhysFSLayer.pas
--- hedgewars-0.9.19.3/hedgewars/uPhysFSLayer.pas 2013-06-04 14:22:41.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uPhysFSLayer.pas 2014-01-08 16:25:17.000000000 +0000
@@ -3,17 +3,12 @@
interface
uses SDLh, LuaPas;
-const PhysfsLibName = {$IFDEF PHYSFS_INTERNAL}'libhw_physfs'{$ELSE}'libphysfs'{$ENDIF};
+const PhysfsLibName = {$IFDEF PHYSFS_INTERNAL}'libhwphysfs'{$ELSE}'libphysfs'{$ENDIF};
const PhyslayerLibName = 'libphyslayer';
{$IFNDEF WIN32}
{$linklib physfs}
{$linklib physlayer}
-
- {statically linking physfs brings IOKit dependency on OSX}
- {$IFDEF DARWIN}
- {$linkframework IOKit}
- {$ENDIF}
{$ENDIF}
procedure initModule;
@@ -138,7 +133,7 @@
begin
{$IFDEF HWLIBRARY}
//TODO: http://icculus.org/pipermail/physfs/2011-August/001006.html
- cPhysfsId:= GetCurrentDir() + {$IFDEF DARWIN}'/Hedgewars.app/Contents/MacOS/' + {$ENDIF} ' hedgewars';
+ cPhysfsId:= GetCurrentDir() + {$IFDEF DARWIN}{$IFNDEF IPHONEOS}'/Hedgewars.app/Contents/MacOS/' + {$ENDIF}{$ENDIF} ' hedgewars';
{$ELSE}
cPhysfsId:= ParamStr(0);
{$ENDIF}
@@ -152,6 +147,10 @@
AddFileLog('[PhysFS] mount ' + UserPathPrefix + '/Data: ' + inttostr(i));
hedgewarsMountPackages;
+
+ i:= PHYSFS_mount(Str2PChar(UserPathPrefix), nil, false);
+ // need access to teams and frontend configs (for bindings)
+ AddFileLog('[PhysFS] mount ' + UserPathPrefix + ': ' + inttostr(i));
end;
procedure freeModule;
diff -Nru hedgewars-0.9.19.3/hedgewars/uRender.pas hedgewars-0.9.20.5/hedgewars/uRender.pas
--- hedgewars-0.9.19.3/hedgewars/uRender.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uRender.pas 2014-01-08 16:25:17.000000000 +0000
@@ -44,6 +44,7 @@
procedure DrawCircle (X, Y, Radius, Width: LongInt);
procedure DrawCircle (X, Y, Radius, Width: LongInt; r, g, b, a: Byte);
+procedure DrawLine (X0, Y0, X1, Y1, Width: Single; color: LongWord); inline;
procedure DrawLine (X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte);
procedure DrawFillRect (r: TSDL_Rect);
procedure DrawHedgehog (X, Y: LongInt; Dir: LongInt; Pos, Step: LongWord; Angle: real);
@@ -51,6 +52,8 @@
procedure Tint (r, g, b, a: Byte); inline;
procedure Tint (c: Longword); inline;
+procedure untint(); inline;
+procedure setTintAdd (f: boolean); inline;
implementation
@@ -332,6 +335,9 @@
if (X + SpritesData[Sprite].Width > RightX) then
r.w:= RightX - X + 1;
+if (r.h < r.y) or (r.w < r.x) then
+ exit;
+
dec(r.h, r.y);
dec(r.w, r.x);
@@ -348,6 +354,11 @@
DrawTexture(X - round(Source^.w * scale) div 2, Top, Source, scale)
end;
+procedure DrawLine(X0, Y0, X1, Y1, Width: Single; color: LongWord); inline;
+begin
+DrawLine(X0, Y0, X1, Y1, Width, (color shr 24) and $FF, (color shr 16) and $FF, (color shr 8) and $FF, color and $FF)
+end;
+
procedure DrawLine(X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte);
var VertexBuffer: array [0..1] of TVertex2f;
begin
@@ -366,7 +377,7 @@
glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
glDrawArrays(GL_LINES, 0, Length(VertexBuffer));
- Tint($FF, $FF, $FF, $FF);
+ untint;
glPopMatrix;
@@ -399,7 +410,7 @@
glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
-Tint($FF, $FF, $FF, $FF);
+untint;
glEnable(GL_TEXTURE_2D)
end;
@@ -407,7 +418,7 @@
begin
Tint(r, g, b, a);
DrawCircle(X, Y, Radius, Width);
- Tint($FF, $FF, $FF, $FF);
+ untint;
end;
procedure DrawCircle(X, Y, Radius, Width: LongInt);
@@ -521,7 +532,7 @@
begin
Tint($FF, $FF, $FF, alpha);
DrawTexture(frame.x, frame.y, spritesData[sprite].Texture, buttonScale);
- Tint($FF, $FF, $FF, $FF);
+ untint;
end;
end;
{$ELSE}
@@ -533,7 +544,7 @@
procedure Tint(r, g, b, a: Byte); inline;
var nc, tw: Longword;
begin
- nc:= (a shl 24) or (b shl 16) or (g shl 8) or r;
+ nc:= (r shl 24) or (g shl 16) or (b shl 8) or a;
if nc = lastTint then
exit;
@@ -554,7 +565,21 @@
procedure Tint(c: Longword); inline;
begin
+ if c = lastTint then exit;
Tint(((c shr 24) and $FF), ((c shr 16) and $FF), (c shr 8) and $FF, (c and $FF))
end;
+procedure untint(); inline;
+begin
+ Tint($FF, $FF, $FF, $FF)
+end;
+
+procedure setTintAdd(f: boolean); inline;
+begin
+ if f then
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD)
+ else
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+end;
+
end.
diff -Nru hedgewars-0.9.19.3/hedgewars/uScript.pas hedgewars-0.9.20.5/hedgewars/uScript.pas
--- hedgewars-0.9.19.3/hedgewars/uScript.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uScript.pas 2014-01-08 16:25:17.000000000 +0000
@@ -54,10 +54,10 @@
implementation
{$IFDEF USE_LUA_SCRIPT}
+
uses LuaPas,
uConsole,
uConsts,
- uVisualGears,
uGears,
uGearsList,
uGearsUtils,
@@ -80,10 +80,12 @@
uRenderUtils,
uTextures,
uLandGraphics,
- SDLh,
- SysUtils,
+ SysUtils,
uIO,
- uPhysFSLayer
+ uVisualGearsList,
+ uGearsHandlersMess,
+ uPhysFSLayer,
+ typinfo
;
var luaState : Plua_State;
@@ -92,10 +94,12 @@
ScriptAmmoDelay : shortstring;
ScriptAmmoReinforcement : shortstring;
ScriptLoaded : boolean;
+ mapDims : boolean;
procedure ScriptPrepareAmmoStore; forward;
procedure ScriptApplyAmmoStore; forward;
-procedure ScriptSetAmmo(ammo : TAmmoType; count, propability, delay, reinforcement: Byte); forward;
+procedure ScriptSetAmmo(ammo : TAmmoType; count, probability, delay, reinforcement: Byte); forward;
+procedure ScriptSetAmmoDelay(ammo : TAmmoType; delay: Byte); forward;
procedure LuaError(s: shortstring);
begin
@@ -103,6 +107,12 @@
AddChatString(#5 + s);
end;
+procedure LuaParameterCountError(call, paramsyntax: shortstring; wrongcount: LongInt);
+begin
+ // TODO: i18n?
+ LuaError('Lua: Wrong number of parameters (' + inttostr(wrongcount) + ') passed to ' + call + '! syntax: ' + call + ' ( ' + paramsyntax + ' )');
+end;
+
// wrapped calls //
// functions called from Lua:
@@ -112,9 +122,9 @@
function lc_band(L: PLua_State): LongInt; Cdecl;
begin
- if lua_gettop(L) <> 2 then
+ if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to band!');
+ LuaParameterCountError('band', 'value1, value2', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -124,9 +134,9 @@
function lc_bor(L: PLua_State): LongInt; Cdecl;
begin
- if lua_gettop(L) <> 2 then
+ if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to bor!');
+ LuaParameterCountError('bor', 'value1, value2', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -136,9 +146,9 @@
function lc_bnot(L: PLua_State): LongInt; Cdecl;
begin
- if lua_gettop(L) <> 1 then
+ if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to bnot!');
+ LuaParameterCountError('bnot', 'value', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -148,9 +158,9 @@
function lc_div(L: PLua_State): LongInt; Cdecl;
begin
- if lua_gettop(L) <> 2 then
+ if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to div!');
+ LuaParameterCountError('div', 'dividend, divisor', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -161,7 +171,7 @@
function lc_getinputmask(L : Plua_State) : LongInt; Cdecl;
begin
if lua_gettop(L) <> 0 then
- LuaError('Lua: Wrong number of parameters passed to GetInputMask!')
+ LuaParameterCountError('GetInputMask', '', lua_gettop(L))
else
lua_pushinteger(L, InputMask);
lc_getinputmask:= 1
@@ -170,7 +180,7 @@
function lc_setinputmask(L : Plua_State) : LongInt; Cdecl;
begin
if lua_gettop(L) <> 1 then
- LuaError('Lua: Wrong number of parameters passed to SetInputMask!')
+ LuaParameterCountError('SetInputMask', 'mask', lua_gettop(L))
else
InputMask:= lua_tointeger(L, 1);
lc_setinputmask:= 0
@@ -183,7 +193,7 @@
WriteLnToConsole('Lua: ' + lua_tostring(L ,1));
end
else
- LuaError('Lua: Wrong number of parameters passed to WriteLnToConsole!');
+ LuaParameterCountError('WriteLnToConsole', 'string', lua_gettop(L));
lc_writelntoconsole:= 0;
end;
@@ -203,7 +213,7 @@
end
else
- LuaError('Lua: Wrong number of parameters passed to ParseCommand!');
+ LuaParameterCountError('ParseCommand', 'string', lua_gettop(L));
lc_parsecommand:= 0;
end;
@@ -214,7 +224,7 @@
ShowMission(lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3), lua_tointeger(L, 4), lua_tointeger(L, 5));
end
else
- LuaError('Lua: Wrong number of parameters passed to ShowMission!');
+ LuaParameterCountError('ShowMission', 'caption, subcaption, text, icon, time', lua_gettop(L));
lc_showmission:= 0;
end;
@@ -229,8 +239,7 @@
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));
+ GameFlags := GameFlags or LongWord(lua_tointeger(L, i));
ScriptSetInteger('GameFlags', GameFlags);
lc_enablegameflags:= 0;
end;
@@ -239,8 +248,7 @@
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));
+ GameFlags := GameFlags and not(LongWord(lua_tointeger(L, i)));
ScriptSetInteger('GameFlags', GameFlags);
lc_disablegameflags:= 0;
end;
@@ -263,7 +271,7 @@
AddCaption(lua_tostring(L, 1), lua_tointeger(L, 2) shr 8, TCapGroup(lua_tointeger(L, 3)));
end
else
- LuaError('Lua: Wrong number of parameters passed to AddCaption!');
+ LuaParameterCountError('AddCaption', 'text[, color, captiongroup]', lua_gettop(L));
lc_addcaption:= 0;
end;
@@ -274,7 +282,7 @@
// to be done
end
else
- LuaError('Lua: Wrong number of parameters passed to CampaignLock!');
+ LuaParameterCountError('CampaignLock', 'TODO', lua_gettop(L));
lc_campaignlock:= 0;
end;
@@ -285,7 +293,7 @@
// to be done
end
else
- LuaError('Lua: Wrong number of parameters passed to CampaignUnlock!');
+ LuaParameterCountError('CampaignUnlock', 'TODO', lua_gettop(L));
lc_campaignunlock:= 0;
end;
@@ -294,7 +302,7 @@
begin
if lua_gettop(L) <> 4 then
begin
- LuaError('Lua: Wrong number of parameters passed to SpawnFakeHealthCrate!');
+ LuaParameterCountError('SpawnFakeHealthCrate', 'x, y, explode, poison', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -303,7 +311,7 @@
HealthCrate, lua_toboolean(L, 3), lua_toboolean(L, 4));
lua_pushinteger(L, gear^.uid);
end;
- lc_spawnfakehealthcrate := 1;
+ lc_spawnfakehealthcrate := 1;
end;
function lc_spawnfakeammocrate(L: PLua_State): LongInt; Cdecl;
@@ -311,7 +319,7 @@
begin
if lua_gettop(L) <> 4 then
begin
- LuaError('Lua: Wrong number of parameters passed to SpawnFakeAmmoCrate!');
+ LuaParameterCountError('SpawnFakeAmmoCrate', 'x, y, explode, poison', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -328,11 +336,11 @@
begin
if lua_gettop(L) <> 4 then
begin
- LuaError('Lua: Wrong number of parameters passed to SpawnFakeUtilityCrate!');
+ LuaParameterCountError('SpawnFakeUtilityCrate', 'x, y, explode, poison', lua_gettop(L));
lua_pushnil(L);
end
else
- begin
+ begin
gear := SpawnFakeCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2),
UtilityCrate, lua_toboolean(L, 3), lua_toboolean(L, 4));
lua_pushinteger(L, gear^.uid);
@@ -346,7 +354,7 @@
begin
if (lua_gettop(L) < 2) or (lua_gettop(L) > 3) then
begin
- LuaError('Lua: Wrong number of parameters passed to SpawnHealthCrate!');
+ LuaParameterCountError('SpawnHealthCrate', 'x, y[, health]', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -361,7 +369,7 @@
else
lua_pushnil(L);
end;
- lc_spawnhealthcrate := 1;
+ lc_spawnhealthcrate := 1;
end;
function lc_spawnammocrate(L: PLua_State): LongInt; Cdecl;
@@ -369,12 +377,12 @@
begin
if (lua_gettop(L) <> 3) and (lua_gettop(L) <> 4) then
begin
- LuaError('Lua: Wrong number of parameters passed to SpawnAmmoCrate!');
+ LuaParameterCountError('SpawnAmmoCrate', 'x, y, content[, amount]', lua_gettop(L));
lua_pushnil(L);
end
else
begin
- if (lua_gettop(L) = 3) then
+ if (lua_gettop(L) = 3) then
gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), AmmoCrate, lua_tointeger(L, 3), 0)
else gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), AmmoCrate, lua_tointeger(L, 3), lua_tointeger(L, 4));
if gear <> nil then
@@ -390,7 +398,7 @@
begin
if (lua_gettop(L) <> 3) and (lua_gettop(L) <> 4) then
begin
- LuaError('Lua: Wrong number of parameters passed to SpawnUtilityCrate!');
+ LuaParameterCountError('SpawnUtilityCrate', 'x, y, content[, amount]', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -414,7 +422,7 @@
begin
if lua_gettop(L) <> 7 then
begin
- LuaError('Lua: Wrong number of parameters passed to AddGear!');
+ LuaParameterCountError('AddGear', 'x, y, gearType, state, dx, dy, timer', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -439,7 +447,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to DeleteGear!');
+ LuaParameterCountError('DeleteGear', 'gearUid', lua_gettop(L));
end
else
begin
@@ -458,7 +466,7 @@
begin
if lua_gettop(L) <> 5 then
begin
- LuaError('Lua: Wrong number of parameters passed to AddVisualGear!');
+ LuaParameterCountError('AddVisualGear', 'x, y, visualGearType, state, critical', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -470,7 +478,7 @@
c:= lua_toboolean(L, 5);
vg:= AddVisualGear(x, y, vgt, s, c);
- if vg <> nil then
+ if vg <> nil then
begin
lastVisualGearByUID:= vg;
lua_pushinteger(L, vg^.uid)
@@ -486,7 +494,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to DeleteVisualGear!');
+ LuaParameterCountError('DeleteVisualGear', 'vgUid', lua_gettop(L));
end
else
begin
@@ -502,7 +510,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetVisualGearValues!');
+ LuaParameterCountError('GetVisualGearValues', 'vgUid', lua_gettop(L));
lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L);
lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L)
end
@@ -536,7 +544,7 @@
begin
if lua_gettop(L) <> 11 then
begin
- LuaError('Lua: Wrong number of parameters passed to SetVisualGearValues!');
+ LuaParameterCountError('SetVisualGearValues', 'vgUid, X, Y, dX, dY, Angle, Frame, FrameTicks, State, Timer, Tint', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -564,7 +572,7 @@
begin
if lua_gettop(L) <> 0 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetFollowGear!');
+ LuaParameterCountError('GetFollowGear', '', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -580,7 +588,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetGearType!');
+ LuaParameterCountError('GetGearType', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -599,7 +607,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetGearMessage!');
+ LuaParameterCountError('GetGearMessage', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -618,7 +626,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetGearElasticity!');
+ LuaParameterCountError('GetGearElasticity', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -636,7 +644,7 @@
var gear : PGear;
begin
if lua_gettop(L) <> 2 then
- LuaError('Lua: Wrong number of parameters passed to SetGearMessage!')
+ LuaParameterCountError('SetGearMessage', 'gearUid, message', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -651,7 +659,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetGearPos!');
+ LuaParameterCountError('GetGearPos', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -669,7 +677,7 @@
var gear : PGear;
begin
if lua_gettop(L) <> 2 then
- LuaError('Lua: Wrong number of parameters passed to SetGearPos!')
+ LuaParameterCountError('SetGearPos', 'gearUid, value', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -684,7 +692,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetGearCollisionMask!');
+ LuaParameterCountError('GetGearCollisionMask', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -702,7 +710,7 @@
var gear : PGear;
begin
if lua_gettop(L) <> 2 then
- LuaError('Lua: Wrong number of parameters passed to SetGearCollisionMask!')
+ LuaParameterCountError('SetGearCollisionMask', 'gearUid, mask', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -716,7 +724,7 @@
var gear : PGear;
begin
if lua_gettop(L) <> 1 then
- LuaError('Lua: Wrong number of parameters passed to GetHogLevel!')
+ LuaParameterCountError('GetHogLevel', 'gearUid', lua_gettop(L))
else
begin
gear := GearByUID(lua_tointeger(L, 1));
@@ -732,7 +740,7 @@
var gear : PGear;
begin
if lua_gettop(L) <> 2 then
- LuaError('Lua: Wrong number of parameters passed to SetHogLevel!')
+ LuaParameterCountError('SetHogLevel', 'gearUid, level', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -747,7 +755,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetHogClan!');
+ LuaParameterCountError('GetHogClan', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -767,7 +775,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetClanColor!');
+ LuaParameterCountError('GetClanColor', 'clan', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else lua_pushinteger(L, ClansArray[lua_tointeger(L, 1)]^.Color shl 8 or $FF);
@@ -779,22 +787,21 @@
team : PTeam;
hh : THedgehog;
i, j : LongInt;
- r, rr: TSDL_Rect;
- texsurf: PSDL_Surface;
begin
if lua_gettop(L) <> 2 then
- LuaError('Lua: Wrong number of parameters passed to SetClanColor!')
+ LuaParameterCountError('SetClanColor', 'clan, color', lua_gettop(L))
else
begin
clan := ClansArray[lua_tointeger(L, 1)];
clan^.Color:= lua_tointeger(L, 2) shr 8;
+
for i:= 0 to Pred(clan^.TeamsNumber) do
begin
team:= clan^.Teams[i];
for j:= 0 to 7 do
begin
hh:= team^.Hedgehogs[j];
- if (hh.Gear <> nil) or (hh.GearHidden <> nil) then
+ if (hh.Gear <> nil) or (hh.GearHidden <> nil) then
begin
FreeTexture(hh.NameTagTex);
hh.NameTagTex:= RenderStringTex(hh.Name, clan^.Color, fnt16);
@@ -803,24 +810,11 @@
end;
FreeTexture(team^.NameTagTex);
team^.NameTagTex:= RenderStringTex(clan^.Teams[i]^.TeamName, clan^.Color, fnt16);
- r.w:= cTeamHealthWidth + 5;
- r.h:= team^.NameTagTex^.h;
+ end;
- texsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, r.w, r.h, 32, RMask, GMask, BMask, AMask);
- TryDo(texsurf <> nil, errmsgCreateSurface, true);
- TryDo(SDL_SetColorKey(texsurf, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true);
-
- DrawRoundRect(@r, cWhiteColor, cNearBlackColor, texsurf, true);
- rr:= r;
- inc(rr.x, 2); dec(rr.w, 4); inc(rr.y, 2); dec(rr.h, 4);
- DrawRoundRect(@rr, clan^.Color, clan^.Color, texsurf, false);
-
- FreeTexture(team^.HealthTex);
- team^.HealthTex:= Surface2Tex(texsurf, false);
- SDL_FreeSurface(texsurf);
- MakeCrossHairs
- end
+ clan^.HealthTex:= makeHealthBarTexture(cTeamHealthWidth + 5, clan^.Teams[0]^.NameTagTex^.h, clan^.Color);
end;
+
lc_setclancolor:= 0
end;
@@ -829,7 +823,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetHogTeamName!');
+ LuaParameterCountError('GetHogTeamName', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -845,12 +839,36 @@
lc_gethogteamname:= 1
end;
+function lc_sethogteamname(L : Plua_State) : LongInt; Cdecl;
+var gear : PGear;
+begin
+ if lua_gettop(L) <> 2 then
+ begin
+ LuaParameterCountError('SetHogTeamName', 'gearUid, name', lua_gettop(L));
+ lua_pushnil(L); // return value on stack (nil)
+ end
+ else
+ begin
+ gear := GearByUID(lua_tointeger(L, 1));
+ if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
+ begin
+ gear^.Hedgehog^.Team^.TeamName := lua_tostring(L, 2);
+
+ FreeTexture(gear^.Hedgehog^.Team^.NameTagTex);
+ gear^.Hedgehog^.Team^.NameTagTex:= RenderStringTex(gear^.Hedgehog^.Team^.TeamName, gear^.Hedgehog^.Team^.Clan^.Color, fnt16);
+ end
+ else
+ lua_pushnil(L);
+ end;
+ lc_sethogteamname:= 1
+end;
+
function lc_gethogname(L : Plua_State) : LongInt; Cdecl;
var gear : PGear;
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetHogName!');
+ LuaParameterCountError('GetHogName', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -868,24 +886,22 @@
function lc_sethogname(L : Plua_State) : LongInt; Cdecl;
var gear : PGear;
- hogName: ShortString;
begin
if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to SetHogName!');
+ LuaParameterCountError('SetHogName', 'gearUid, name', lua_gettop(L));
lua_pushnil(L)
end
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+ begin
+ gear^.Hedgehog^.Name:= lua_tostring(L, 2);
- hogName:= lua_tostring(L, 2);
- gear^.Hedgehog^.Name:= hogName;
-
- FreeTexture(gear^.Hedgehog^.NameTagTex);
- gear^.Hedgehog^.NameTagTex:= RenderStringTex(gear^.Hedgehog^.Name, gear^.Hedgehog^.Team^.Clan^.Color, fnt16);
-
+ FreeTexture(gear^.Hedgehog^.NameTagTex);
+ gear^.Hedgehog^.NameTagTex:= RenderStringTex(gear^.Hedgehog^.Name, gear^.Hedgehog^.Team^.Clan^.Color, fnt16)
+ end
end;
lc_sethogname:= 0;
end;
@@ -895,7 +911,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetTimer!');
+ LuaParameterCountError('GetTimer', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -914,7 +930,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetHealth!');
+ LuaParameterCountError('GetHealth', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -933,7 +949,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetX!');
+ LuaParameterCountError('GetX', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -952,7 +968,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetY!');
+ LuaParameterCountError('GetY', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -971,7 +987,7 @@
begin
if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to CopyPV!');
+ LuaParameterCountError('CopyPV', 'fromGearUid, toGearUid', lua_gettop(L));
end
else
begin
@@ -992,7 +1008,7 @@
var gear : PGear;
begin
if lua_gettop(L) <> 1 then
- LuaError('Lua: Wrong number of parameters passed to FollowGear!')
+ LuaParameterCountError('FollowGear', 'gearUid', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -1024,13 +1040,14 @@
vgear^.FrameTicks:= lua_tointeger(L, 3);
if (vgear^.FrameTicks < 1) or (vgear^.FrameTicks > 3) then
vgear^.FrameTicks:= 1;
- lua_pushinteger(L, vgear^.Uid)
+ lua_pushinteger(L, vgear^.Uid);
+ AddChatString(#1+'[' + gear^.Hedgehog^.Name + '] '+vgear^.text)
end
end
else
lua_pushnil(L)
end
- else LuaError('Lua: Wrong number of parameters passed to HogSay!');
+ else LuaParameterCountError('HogSay', 'gearUid, text, manner[, vgState]', lua_gettop(L));
lc_hogsay:= 1
end;
@@ -1038,7 +1055,7 @@
var gear, prevgear : PGear;
begin
if lua_gettop(L) <> 1 then
- LuaError('Lua: Wrong number of parameters passed to SwitchHog!')
+ LuaParameterCountError('SwitchHog', 'gearUid', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -1053,7 +1070,7 @@
prevgear^.Z := cHHZ;
prevgear^.Message:= prevgear^.Message or gmRemoveFromList or gmAddToList;
end;
-
+
SwitchCurrentHedgehog(gear^.Hedgehog);
CurrentTeam:= CurrentHedgehog^.Team;
@@ -1076,7 +1093,7 @@
if (gear <> nil) and (gear^.Hedgehog <> nil) then
AddAmmoAmount(gear^.Hedgehog^, TAmmoType(lua_tointeger(L, 2)), lua_tointeger(L,3) );
end else
-
+
if lua_gettop(L) = 2 then
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -1084,7 +1101,7 @@
AddAmmo(gear^.Hedgehog^, TAmmoType(lua_tointeger(L, 2)));
end else
begin
- LuaError('Lua: Wrong number of parameters passed to AddAmmo!');
+ LuaParameterCountError('AddAmmo', 'TODO', lua_gettop(L));
end;
lc_addammo:= 0;
@@ -1103,7 +1120,7 @@
else
SetAmmo(gear^.Hedgehog^, TAmmoType(lua_tointeger(L, 2)), lua_tointeger(L, 3))
end
- else LuaError('Lua: Wrong number of parameters passed to AddAmmo!');
+ else LuaParameterCountError('AddAmmo', 'gearUid, ammoType[, ammoCount]', lua_gettop(L));
lc_addammo:= 0
end;
@@ -1114,7 +1131,7 @@
if (lua_gettop(L) = 2) then
begin
gear:= GearByUID(lua_tointeger(L, 1));
- if (gear <> nil) and (gear^.Hedgehog <> nil) then
+ if (gear <> nil) and (gear^.Hedgehog <> nil) then
begin
ammo:= GetAmmoEntry(gear^.Hedgehog^, TAmmoType(lua_tointeger(L, 2)));
if ammo^.AmmoType = amNothing then
@@ -1124,9 +1141,9 @@
end
else lua_pushinteger(L, 0)
end
- else
+ else
begin
- LuaError('Lua: Wrong number of parameters passed to GetAmmoCount!');
+ LuaParameterCountError('GetAmmoCount', 'gearUid, ammoType', lua_gettop(L));
lua_pushnil(L)
end;
lc_getammocount:= 1
@@ -1137,7 +1154,7 @@
begin
if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to SetHealth!');
+ LuaParameterCountError('SetHealth', 'gearUid, health', lua_gettop(L));
end
else
begin
@@ -1147,7 +1164,7 @@
gear^.Health:= lua_tointeger(L, 2);
if (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
- begin
+ begin
RenderHealth(gear^.Hedgehog^);
RecountTeamHealth(gear^.Hedgehog^.Team)
end;
@@ -1163,7 +1180,7 @@
begin
if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to SetTimer!');
+ LuaParameterCountError('SetTimer', 'gearUid, timer', lua_gettop(L));
end
else
begin
@@ -1177,7 +1194,7 @@
var gear: PGear;
begin
if lua_gettop(L) <> 3 then
- LuaError('Lua: Wrong number of parameters passed to SetEffect!')
+ LuaParameterCountError('SetEffect', 'gearUid, effect, enabled', lua_gettop(L))
else begin
gear := GearByUID(lua_tointeger(L, 1));
if (gear <> nil) and (gear^.Hedgehog <> nil) then
@@ -1185,12 +1202,13 @@
end;
lc_seteffect := 0;
end;
+
function lc_geteffect(L : Plua_State) : LongInt; Cdecl;
var gear : PGear;
begin
if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetEffect!');
+ LuaParameterCountError('GetEffect', 'gearUid, effect', lua_gettop(L));
end
else
begin
@@ -1208,7 +1226,7 @@
begin
if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to SetState!');
+ LuaParameterCountError('SetState', 'gearUid, state', lua_gettop(L));
end
else
begin
@@ -1227,7 +1245,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetState!');
+ LuaParameterCountError('GetState', 'gearUid', lua_gettop(L));
end
else
begin
@@ -1245,7 +1263,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetX!');
+ LuaParameterCountError('GetTag', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -1264,7 +1282,7 @@
begin
if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to SetTag!');
+ LuaParameterCountError('SetTag', 'gearUid, tag', lua_gettop(L));
end
else
begin
@@ -1285,6 +1303,64 @@
lc_endgame:= 0
end;
+function lc_sendstat(L : Plua_State) : LongInt; Cdecl;
+var statInfo : TStatInfoType;
+var i : LongInt;
+var color : shortstring;
+begin
+ statInfo := TStatInfoType(lua_tointeger(L, 1));
+ if (lua_gettop(L) <> 2) and ((statInfo <> siPlayerKills)
+ and (statInfo <> siClanHealth)) then
+ begin
+ LuaParameterCountError('SendStat', 'statInfoType, color', lua_gettop(L));
+ end
+ else if (lua_gettop(L) <> 3) and ((statInfo = siPlayerKills)
+ or (statInfo = siClanHealth)) then
+ begin
+ LuaParameterCountError('SendStat', 'siClanHealth, color, teamname', lua_gettop(L));
+ end
+ else
+ begin
+ if ((statInfo = siPlayerKills) or (statInfo = siClanHealth)) then
+ begin
+ // 3: team name
+ for i:= 0 to Pred(TeamsCount) do
+ begin
+ with TeamsArray[i]^ do
+ begin
+ if TeamName = lua_tostring(L, 3) then
+ begin
+ color := uUtils.IntToStr(Clan^.Color);
+ Break;
+ end
+ end
+ end;
+ if (statInfo = siPlayerKills) then
+ begin
+ SendStat(siPlayerKills, color + ' ' +
+ lua_tostring(L, 2) + ' ' + TeamsArray[i]^.TeamName);
+ end
+ else if (statInfo = siClanHealth) then
+ begin
+ SendStat(siClanHealth, color + ' ' +
+ lua_tostring(L, 2));
+ end
+ end
+ else
+ begin
+ SendStat(statInfo,lua_tostring(L, 2));
+ end;
+ end;
+ lc_sendstat:= 0
+end;
+
+function lc_sendhealthstatsoff(L : Plua_State) : LongInt; Cdecl;
+begin
+ L:= L; // avoid compiler hint
+ uStats.SendHealthStatsOn := false;
+ lc_sendhealthstatsoff:= 0
+end;
+
function lc_findplace(L : Plua_State) : LongInt; Cdecl;
var gear: PGear;
fall: boolean;
@@ -1293,7 +1369,7 @@
begin
tryhard:= false;
if (lua_gettop(L) <> 4) and (lua_gettop(L) <> 5) then
- LuaError('Lua: Wrong number of parameters passed to FindPlace!')
+ LuaParameterCountError('FindPlace', 'gearUid, fall, left, right[, tryHarder]', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -1323,7 +1399,7 @@
if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
AddVoice(TSound(lua_tointeger(L, 1)),gear^.Hedgehog^.Team^.Voicepack)
end
- else LuaError('Lua: Wrong number of parameters passed to PlaySound!');
+ else LuaParameterCountError('PlaySound', 'soundId', lua_gettop(L));
lc_playsound:= 0;
end;
@@ -1333,7 +1409,7 @@
np:= lua_gettop(L);
if (np < 5) or (np > 6) then
begin
- LuaError('Lua: Wrong number of parameters passed to AddTeam!');
+ LuaParameterCountError('AddTeam', 'teamname, color, grave, fort, voicepack[, flag]', lua_gettop(L));
//lua_pushnil(L)
end
else
@@ -1355,7 +1431,7 @@
begin
if lua_gettop(L) <> 4 then
begin
- LuaError('Lua: Wrong number of parameters passed to AddHog!');
+ LuaParameterCountError('AddHog', 'hogname, botlevel, health, hat', lua_gettop(L));
lua_pushnil(L)
end
else
@@ -1373,7 +1449,7 @@
begin
if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to HogTurnLeft!');
+ LuaParameterCountError('HogTurnLeft', 'gearUid, boolean', lua_gettop(L));
end
else
begin
@@ -1389,7 +1465,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetGearPosition!');
+ LuaParameterCountError('GetGearPosition', 'gearUid', lua_gettop(L));
lua_pushnil(L);
lua_pushnil(L)
end
@@ -1416,7 +1492,7 @@
x, y: LongInt;
begin
if lua_gettop(L) <> 3 then
- LuaError('Lua: Wrong number of parameters passed to SetGearPosition!')
+ LuaParameterCountError('SetGearPosition', 'gearUid, x, y', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -1430,7 +1506,7 @@
gear^.X:= int2hwfloat(x);
gear^.Y:= int2hwfloat(y);
if col then
- AddGearCI(gear);
+ AddCI(gear);
SetAllToActive
end
end;
@@ -1442,7 +1518,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetGearTarget!');
+ LuaParameterCountError('GetGearTarget', 'gearUid', lua_gettop(L));
lua_pushnil(L);
lua_pushnil(L)
end
@@ -1467,7 +1543,7 @@
var gear: PGear;
begin
if lua_gettop(L) <> 3 then
- LuaError('Lua: Wrong number of parameters passed to SetGearTarget!')
+ LuaParameterCountError('SetGearTarget', 'gearUid, x, y', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -1486,7 +1562,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetGearVelocity!');
+ LuaParameterCountError('GetGearVelocity', 'gearUid', lua_gettop(L));
lua_pushnil(L);
lua_pushnil(L)
end
@@ -1509,7 +1585,7 @@
var gear: PGear;
begin
if lua_gettop(L) <> 3 then
- LuaError('Lua: Wrong number of parameters passed to SetGearVelocity!')
+ LuaParameterCountError('SetGearVelocity', 'gearUid, dx, dy', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -1526,7 +1602,7 @@
function lc_setzoom(L : Plua_State) : LongInt; Cdecl;
begin
if lua_gettop(L) <> 1 then
- LuaError('Lua: Wrong number of parameters passed to SetZoom!')
+ LuaParameterCountError('SetZoom', 'zoomLevel', lua_gettop(L))
else
begin
ZoomValue:= lua_tonumber(L, 1);
@@ -1542,7 +1618,7 @@
begin
if lua_gettop(L) <> 0 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetZoom!');
+ LuaParameterCountError('GetZoom', '', lua_gettop(L));
lua_pushnil(L)
end
else
@@ -1555,7 +1631,7 @@
begin
np:= lua_gettop(L);
if (np < 4) or (np > 5) then
- LuaError('Lua: Wrong number of parameters passed to SetAmmo!')
+ LuaParameterCountError('SetAmmo', 'ammoType, count, probability, delay[, numberInCrate]', lua_gettop(L))
else if np = 4 then
ScriptSetAmmo(TAmmoType(lua_tointeger(L, 1)), lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4), 1)
else
@@ -1563,12 +1639,23 @@
lc_setammo:= 0
end;
+function lc_setammodelay(L : Plua_State) : LongInt; Cdecl;
+var np: LongInt;
+begin
+ np:= lua_gettop(L);
+ if (np <> 2) then
+ LuaParameterCountError('SetAmmoDelay', 'ammoType, delay', lua_gettop(L))
+ else
+ ScriptSetAmmoDelay(TAmmoType(lua_tointeger(L, 1)), lua_tointeger(L, 2));
+ lc_setammodelay:= 0
+end;
+
function lc_setammostore(L : Plua_State) : LongInt; Cdecl;
var np: LongInt;
begin
np:= lua_gettop(L);
if (np <> 4) then
- LuaError('Lua: Wrong number of parameters passed to SetAmmoStore!')
+ LuaParameterCountError('SetAmmoStore', 'loadouts, probabilities, delays, reinforments', lua_gettop(L))
else
begin
ScriptAmmoLoadout:= lua_tostring(L, 1);
@@ -1584,7 +1671,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetRandom!');
+ LuaParameterCountError('GetRandom', 'number', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -1604,7 +1691,7 @@
function lc_setwind(L : Plua_State) : LongInt; Cdecl;
begin
if lua_gettop(L) <> 1 then
- LuaError('Lua: Wrong number of parameters passed to SetWind!')
+ LuaParameterCountError('SetWind', 'windSpeed', lua_gettop(L))
else
begin
cWindSpeed:= int2hwfloat(lua_tointeger(L, 1)) / 100 * cMaxWindSpeed;
@@ -1620,7 +1707,7 @@
begin
if lua_gettop(L) <> 0 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetDataPath!');
+ LuaParameterCountError('GetDataPath', '', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -1632,7 +1719,7 @@
begin
if lua_gettop(L) <> 0 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetUserDataPath!');
+ LuaParameterCountError('GetUserDataPath', '', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -1644,7 +1731,7 @@
begin
if lua_gettop(L) <> 0 then
begin
- LuaError('Lua: Wrong number of parameters passed to MapHasBorder!');
+ LuaParameterCountError('MapHasBorder', '', lua_gettop(L));
lua_pushnil(L);
end
else
@@ -1657,7 +1744,7 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to GetGearRadius!');
+ LuaParameterCountError('GetGearRadius', 'gearUid', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -1675,7 +1762,7 @@
var gear : PGear;
begin
if lua_gettop(L) <> 1 then
- LuaError('Lua: Wrong number of parameters passed to GetHogHat!')
+ LuaParameterCountError('GetHogHat', 'gearUid', lua_gettop(L))
else begin
gear := GearByUID(lua_tointeger(L, 1));
if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
@@ -1692,20 +1779,22 @@
begin
if lua_gettop(L) <> 2 then
begin
- LuaError('Lua: Wrong number of parameters passed to SetHogHat!');
+ LuaParameterCountError('SetHogHat', 'gearUid, hat', lua_gettop(L));
lua_pushnil(L)
end
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+ begin
hat:= lua_tostring(L, 2);
gear^.Hedgehog^.Hat:= hat;
-AddFileLog('Changed hat to: '+hat);
+ AddFileLog('Changed hat to: '+hat);
if (Length(hat) > 39) and (Copy(hat,1,8) = 'Reserved') and (Copy(hat,9,32) = gear^.Hedgehog^.Team^.PlayerHash) then
LoadHedgehogHat(gear^.Hedgehog^, 'Reserved/' + Copy(hat,9,Length(hat)-8))
else
- LoadHedgehogHat(gear^.Hedgehog^, hat);
+ LoadHedgehogHat(gear^.Hedgehog^, hat)
+ end
end;
lc_sethoghat:= 0;
end;
@@ -1713,7 +1802,7 @@
function lc_placegirder(L : Plua_State) : LongInt; Cdecl;
begin
if lua_gettop(L) <> 3 then
- LuaError('Lua: Wrong number of parameters passed to PlaceGirder!')
+ LuaParameterCountError('PlaceGirder', 'x, y, state', lua_gettop(L))
else
TryPlaceOnLand(
lua_tointeger(L, 1) - SpritesData[sprAmGirder].Width div 2,
@@ -1725,7 +1814,7 @@
function lc_getcurammotype(L : Plua_State): LongInt; Cdecl;
begin
if lua_gettop(L) <> 0 then
- LuaError('Lua: Wrong number of parameters passed to GetCurAmmoType!')
+ LuaParameterCountError('GetCurAmmoType', '', lua_gettop(L))
else
lua_pushinteger(L, ord(CurrentHedgehog^.CurAmmoType));
lc_getcurammotype := 1;
@@ -1734,7 +1823,7 @@
function lc_savecampaignvar(L : Plua_State): LongInt; Cdecl;
begin
if lua_gettop(L) <> 2 then
- LuaError('Lua: Wrong number of parameters passed to SaveCampaignVar!')
+ LuaParameterCountError('SaveCampaignVar', 'varname, value', lua_gettop(L))
else begin
SendIPC('V!' + lua_tostring(L, 1) + ' ' + lua_tostring(L, 2) + #0);
end;
@@ -1744,9 +1833,9 @@
function lc_getcampaignvar(L : Plua_State): LongInt; Cdecl;
begin
if (lua_gettop(L) <> 1) then
- LuaError('Lua: Wrong number of parameters passed to GetCampaignVar!')
+ LuaParameterCountError('GetCampaignVar', 'varname', lua_gettop(L))
else
- SendIPCAndWaitReply('V?' + lua_tostring(L, 1));
+ SendIPCAndWaitReply('V?' + lua_tostring(L, 1) + #0);
lua_pushstring(L, str2pchar(CampaignVariable));
lc_getcampaignvar := 1;
end;
@@ -1755,7 +1844,7 @@
var gear: PGear;
begin
if lua_gettop(L) <> 1 then
- LuaError('Lua: Wrong number of parameters passed to HideHog!')
+ LuaParameterCountError('HideHog', 'gearUid', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -1769,7 +1858,7 @@
uid: LongWord;
begin
if lua_gettop(L) <> 1 then
- LuaError('Lua: Wrong number of parameters passed to RestoreHog!')
+ LuaParameterCountError('RestoreHog', 'gearUid', lua_gettop(L))
else
begin
uid:= LongWord(lua_tointeger(L, 1));
@@ -1791,7 +1880,7 @@
begin
if lua_gettop(L) <> 5 then
begin
- LuaError('Lua: Wrong number of parameters passed to TestRectForObstacle!');
+ LuaParameterCountError('TestRectForObstacle', 'x1, y1, x2, y2, landOnly', lua_gettop(L));
lua_pushnil(L); // return value on stack (nil)
end
else
@@ -1809,11 +1898,33 @@
end;
+function lc_getgravity(L : Plua_State) : LongInt; Cdecl;
+begin
+ if lua_gettop(L) <> 0 then
+ LuaParameterCountError('GetGravity', '', lua_gettop(L))
+ else
+ lua_pushinteger(L, hwRound(cGravity * 50 / cWindSpeed));
+ lc_getgravity:= 1
+end;
+
+function lc_setgravity(L : Plua_State) : LongInt; Cdecl;
+begin
+ if lua_gettop(L) <> 1 then
+ LuaParameterCountError('SetGravity', 'gravity', lua_gettop(L))
+ else
+ begin
+ cGravity:= cMaxWindSpeed * lua_tointeger(L, 1) * _0_02;
+ cGravityf:= 0.00025 * lua_tointeger(L, 1) * 0.02
+ end;
+ lc_setgravity:= 0
+end;
+
+
function lc_setaihintsongear(L : Plua_State) : LongInt; Cdecl;
var gear: PGear;
begin
if lua_gettop(L) <> 2 then
- LuaError('Lua: Wrong number of parameters passed to SetAIHintOnGear!')
+ LuaParameterCountError('SetAIHintOnGear', 'gearUid, aiHints', lua_gettop(L))
else
begin
gear:= GearByUID(lua_tointeger(L, 1));
@@ -1828,13 +1939,23 @@
begin
if lua_gettop(L) <> 1 then
begin
- LuaError('Lua: Wrong number of parameters passed to HedgewarsScriptLoad!');
+ LuaParameterCountError('HedgewarsScriptLoad', 'scriptPath', lua_gettop(L));
lua_pushnil(L)
end
else
ScriptLoad(lua_tostring(L, 1));
lc_hedgewarsscriptload:= 0;
end;
+
+
+function lc_declareachievement(L : Plua_State) : LongInt; Cdecl;
+begin
+ if lua_gettop(L) <> 4 then
+ LuaParameterCountError('DeclareAchievement', 'achievementId, teamname, location, value', lua_gettop(L))
+ else
+ declareAchievement(lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3), lua_tointeger(L, 4));
+ lc_declareachievement:= 0
+end;
///////////////////
procedure ScriptPrintStack;
@@ -1919,6 +2040,7 @@
ScriptSetInteger('SuddenDeathTurns', cSuddenDTurns);
ScriptSetInteger('WaterRise', cWaterRise);
ScriptSetInteger('HealthDecrease', cHealthDecrease);
+ScriptSetInteger('GetAwayTime', cGetAwayTime);
ScriptSetString('Map', cMapName);
ScriptSetString('Theme', '');
@@ -1947,6 +2069,7 @@
cSuddenDTurns := ScriptGetInteger('SuddenDeathTurns');
cWaterRise := ScriptGetInteger('WaterRise');
cHealthDecrease := ScriptGetInteger('HealthDecrease');
+cGetAwayTime := ScriptGetInteger('GetAwayTime');
if cMapName <> ScriptGetString('Map') then
ParseCommand('map ' + ScriptGetString('Map'), true, true);
@@ -1969,7 +2092,7 @@
if StoreCnt-1 < k then AddAmmoStore;
inc(k)
end
-else
+else
for i:= 0 to Pred(TeamsCount) do
begin
for j:= 0 to Pred(TeamsArray[i]^.HedgehogsNumber) do
@@ -1995,7 +2118,8 @@
end;
ScriptSetInteger('ClansCount', ClansCount);
-ScriptSetInteger('TeamsCount', TeamsCount)
+ScriptSetInteger('TeamsCount', TeamsCount);
+mapDims:= false
end;
@@ -2018,10 +2142,13 @@
begin
s:= cPathz[ptData] + name;
if not pfsExists(s) then
+ begin
+ AddFileLog('[LUA] Script not found: ' + name);
exit;
+ end;
f:= pfsOpenRead(s);
-if f = nil then
+if f = nil then
exit;
physfsReaderSetBuffer(@buf);
@@ -2049,8 +2176,9 @@
ScriptSetInteger('GameTime', GameTicks);
ScriptSetInteger('TotalRounds', TotalRounds);
ScriptSetInteger('WaterLine', cWaterLine);
-if GameTicks = 0 then
+if not mapDims then
begin
+ mapDims:= true;
ScriptSetInteger('LAND_WIDTH', LAND_WIDTH);
ScriptSetInteger('LAND_HEIGHT', LAND_HEIGHT);
ScriptSetInteger('LeftX', leftX);
@@ -2171,17 +2299,30 @@
end;
end;
-procedure ScriptSetAmmo(ammo : TAmmoType; count, propability, delay, reinforcement: Byte);
+procedure ScriptSetAmmo(ammo : TAmmoType; count, probability, delay, reinforcement: Byte);
begin
-//if (ord(ammo) < 1) or (count > 9) or (count < 0) or (propability < 0) or (propability > 8) or (delay < 0) or (delay > 9) or (reinforcement < 0) or (reinforcement > 8) then
-if (ord(ammo) < 1) or (count > 9) or (propability > 8) or (delay > 9) or (reinforcement > 8) then
+//if (ord(ammo) < 1) or (count > 9) or (count < 0) or (probability < 0) or (probability > 8) or (delay < 0) or (delay > 9) or (reinforcement < 0) or (reinforcement > 8) then
+if (ord(ammo) < 1) or (count > 9) or (probability > 8) or (delay > 9) or (reinforcement > 8) then
exit;
ScriptAmmoLoadout[ord(ammo)]:= inttostr(count)[1];
-ScriptAmmoProbability[ord(ammo)]:= inttostr(propability)[1];
-ScriptAmmoDelay[ord(ammo)]:= inttostr(delay)[1];
+ScriptAmmoProbability[ord(ammo)]:= inttostr(probability)[1];
+ScriptSetAmmoDelay(ammo, delay);
ScriptAmmoReinforcement[ord(ammo)]:= inttostr(reinforcement)[1];
end;
+procedure ScriptSetAmmoDelay(ammo : TAmmoType; delay: Byte);
+begin
+// change loadout string if ammo store hasn't been initialized yet
+if (StoreCnt = 0) then
+begin
+ if (delay <= 9) then
+ ScriptAmmoDelay[ord(ammo)]:= inttostr(delay)[1];
+end
+// change "live" delay values
+else if (CurrentTeam <> nil) then
+ ammoz[ammo].SkipTurns:= CurrentTeam^.Clan^.TurnNumber + delay;
+end;
+
procedure ScriptApplyAmmoStore;
var i, j, k : LongInt;
begin
@@ -2218,7 +2359,7 @@
AddAmmoStore;
TeamsArray[i]^.Hedgehogs[j].AmmoStore:= StoreCnt - 1
end
-else
+else
for i:= 0 to Pred(TeamsCount) do
begin
if ScriptExists('onNewAmmoStore') then
@@ -2240,6 +2381,7 @@
var at : TGearType;
vgt: TVisualGearType;
am : TAmmoType;
+ si : TStatInfoType;
st : TSound;
he : THogEffect;
cg : TCapGroup;
@@ -2284,6 +2426,7 @@
ScriptSetInteger('gfDisableWind', gfDisableWind);
ScriptSetInteger('gfMoreWind', gfMoreWind);
ScriptSetInteger('gfTagTeam', gfTagTeam);
+ScriptSetInteger('gfShoppaBorder', gfShoppaBorder);
ScriptSetInteger('gmLeft', gmLeft);
ScriptSetInteger('gmRight', gmRight);
@@ -2322,6 +2465,9 @@
for am:= Low(TAmmoType) to High(TAmmoType) do
ScriptSetInteger(EnumToStr(am), ord(am));
+for si:= Low(TStatInfoType) to High(TStatInfoType) do
+ ScriptSetInteger(EnumToStr(si), ord(si));
+
for he:= Low(THogEffect) to High(THogEffect) do
ScriptSetInteger(EnumToStr(he), ord(he));
@@ -2382,6 +2528,8 @@
lua_register(luaState, _P'WriteLnToConsole', @lc_writelntoconsole);
lua_register(luaState, _P'GetGearType', @lc_getgeartype);
lua_register(luaState, _P'EndGame', @lc_endgame);
+lua_register(luaState, _P'SendStat', @lc_sendstat);
+lua_register(luaState, _P'SendHealthStatsOff', @lc_sendhealthstatsoff);
lua_register(luaState, _P'FindPlace', @lc_findplace);
lua_register(luaState, _P'SetGearPosition', @lc_setgearposition);
lua_register(luaState, _P'GetGearPosition', @lc_getgearposition);
@@ -2394,6 +2542,7 @@
lua_register(luaState, _P'HideMission', @lc_hidemission);
lua_register(luaState, _P'AddCaption', @lc_addcaption);
lua_register(luaState, _P'SetAmmo', @lc_setammo);
+lua_register(luaState, _P'SetAmmoDelay', @lc_setammodelay);
lua_register(luaState, _P'SetAmmoStore', @lc_setammostore);
lua_register(luaState, _P'PlaySound', @lc_playsound);
lua_register(luaState, _P'AddTeam', @lc_addteam);
@@ -2408,6 +2557,7 @@
lua_register(luaState, _P'GetClanColor', @lc_getclancolor);
lua_register(luaState, _P'SetClanColor', @lc_setclancolor);
lua_register(luaState, _P'GetHogTeamName', @lc_gethogteamname);
+lua_register(luaState, _P'SetHogTeamName', @lc_sethogteamname);
lua_register(luaState, _P'GetHogName', @lc_gethogname);
lua_register(luaState, _P'SetHogName', @lc_sethogname);
lua_register(luaState, _P'GetHogLevel', @lc_gethoglevel);
@@ -2448,9 +2598,12 @@
lua_register(luaState, _P'PlaceGirder', @lc_placegirder);
lua_register(luaState, _P'GetCurAmmoType', @lc_getcurammotype);
lua_register(luaState, _P'TestRectForObstacle', @lc_testrectforobstacle);
+lua_register(luaState, _P'GetGravity', @lc_getgravity);
+lua_register(luaState, _P'SetGravity', @lc_setgravity);
lua_register(luaState, _P'SetGearAIHints', @lc_setaihintsongear);
lua_register(luaState, _P'HedgewarsScriptLoad', @lc_hedgewarsscriptload);
+lua_register(luaState, _P'DeclareAchievement', @lc_declareachievement);
ScriptClearStack; // just to be sure stack is empty
@@ -2544,6 +2697,7 @@
procedure initModule;
begin
+mapDims:= false;
end;
procedure freeModule;
diff -Nru hedgewars-0.9.19.3/hedgewars/uStats.pas hedgewars-0.9.20.5/hedgewars/uStats.pas
--- hedgewars-0.9.19.3/hedgewars/uStats.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uStats.pas 2014-01-08 16:25:17.000000000 +0000
@@ -24,7 +24,8 @@
var TotalRounds: LongInt;
FinishedTurnsTotal: LongInt;
-
+ SendHealthStatsOn : boolean = true;
+
procedure initModule;
procedure freeModule;
@@ -34,9 +35,10 @@
procedure TurnReaction;
procedure SendStats;
procedure hedgehogFlight(Gear: PGear; time: Longword);
+procedure declareAchievement(id, teamname, location: shortstring; value: LongInt);
implementation
-uses uSound, uLocale, uVariables, uUtils, uIO, uCaptions, uDebug, uMisc, uConsole;
+uses uSound, uLocale, uVariables, uUtils, uIO, uCaptions, uDebug, uMisc, uConsole, uScript;
var DamageClan : Longword = 0;
DamageTotal : Longword = 0;
@@ -162,12 +164,13 @@
StepDamageRecv:= 0;
StepDamageGiven:= 0
end;
-
-for t:= 0 to Pred(ClansCount) do
- with ClansArray[t]^ do
- begin
- SendStat(siClanHealth, IntToStr(Color) + ' ' + IntToStr(ClanHealth));
- end;
+
+if SendHealthStatsOn then
+ for t:= 0 to Pred(ClansCount) do
+ with ClansArray[t]^ do
+ begin
+ SendStat(siClanHealth, IntToStr(Color) + ' ' + IntToStr(ClanHealth));
+ end;
Kills:= 0;
KillsClan:= 0;
@@ -207,103 +210,115 @@
maxTeamDamageName : shortstring;
winnersClan : PClan;
begin
-msd:= 0; msdhh:= nil;
-msk:= 0; mskhh:= nil;
-mskcnt:= 0;
-maxTeamKills := 0;
-maxTurnSkips := 0;
-maxTeamDamage := 0;
-winnersClan:= nil;
+if SendHealthStatsOn then
+ msd:= 0; msdhh:= nil;
+ msk:= 0; mskhh:= nil;
+ mskcnt:= 0;
+ maxTeamKills := 0;
+ maxTurnSkips := 0;
+ maxTeamDamage := 0;
+ winnersClan:= nil;
-for t:= 0 to Pred(TeamsCount) do
- with TeamsArray[t]^ do
- begin
- if not ExtDriven then
- SendStat(siTeamStats, GetTeamStatString(TeamsArray[t]));
- for i:= 0 to cMaxHHIndex do
- begin
- if Hedgehogs[i].stats.MaxStepDamageGiven > msd then
+ for t:= 0 to Pred(TeamsCount) do
+ with TeamsArray[t]^ do
+ begin
+ if not ExtDriven then
+ SendStat(siTeamStats, GetTeamStatString(TeamsArray[t]));
+ for i:= 0 to cMaxHHIndex do
begin
- msdhh:= @Hedgehogs[i];
- msd:= Hedgehogs[i].stats.MaxStepDamageGiven
- end;
- if Hedgehogs[i].stats.MaxStepKills >= msk then
- if Hedgehogs[i].stats.MaxStepKills = msk then
- inc(mskcnt)
- else
+ if Hedgehogs[i].stats.MaxStepDamageGiven > msd then
begin
- mskcnt:= 1;
- mskhh:= @Hedgehogs[i];
- msk:= Hedgehogs[i].stats.MaxStepKills
+ msdhh:= @Hedgehogs[i];
+ msd:= Hedgehogs[i].stats.MaxStepDamageGiven
end;
- end;
+ if Hedgehogs[i].stats.MaxStepKills >= msk then
+ if Hedgehogs[i].stats.MaxStepKills = msk then
+ inc(mskcnt)
+ else
+ begin
+ mskcnt:= 1;
+ mskhh:= @Hedgehogs[i];
+ msk:= Hedgehogs[i].stats.MaxStepKills
+ end;
+ end;
- { send player stats for winner teams }
- if Clan^.ClanHealth > 0 then
- begin
- winnersClan:= Clan;
- SendStat(siPlayerKills, IntToStr(Clan^.Color) + ' ' +
- IntToStr(stats.Kills) + ' ' + TeamName);
- end;
+ { send player stats for winner teams }
+ if Clan^.ClanHealth > 0 then
+ begin
+ winnersClan:= Clan;
+ SendStat(siPlayerKills, IntToStr(Clan^.Color) + ' ' +
+ IntToStr(stats.Kills) + ' ' + TeamName);
+ end;
- { determine maximum values of TeamKills, TurnSkips, TeamDamage }
- if stats.TeamKills > maxTeamKills then
- begin
- maxTeamKills := stats.TeamKills;
- maxTeamKillsName := TeamName;
- end;
- if stats.TurnSkips > maxTurnSkips then
- begin
- maxTurnSkips := stats.TurnSkips;
- maxTurnSkipsName := TeamName;
- end;
- if stats.TeamDamage > maxTeamDamage then
- begin
- maxTeamDamage := stats.TeamDamage;
- maxTeamDamageName := TeamName;
- end;
+ { determine maximum values of TeamKills, TurnSkips, TeamDamage }
+ if stats.TeamKills > maxTeamKills then
+ begin
+ maxTeamKills := stats.TeamKills;
+ maxTeamKillsName := TeamName;
+ end;
+ if stats.TurnSkips > maxTurnSkips then
+ begin
+ maxTurnSkips := stats.TurnSkips;
+ maxTurnSkipsName := TeamName;
+ end;
+ if stats.TeamDamage > maxTeamDamage then
+ begin
+ maxTeamDamage := stats.TeamDamage;
+ maxTeamDamageName := TeamName;
+ end;
- end;
+ end;
-{ now send player stats for loser teams }
-for t:= 0 to Pred(TeamsCount) do
- begin
- with TeamsArray[t]^ do
+ { now send player stats for loser teams }
+ for t:= 0 to Pred(TeamsCount) do
begin
- if Clan^.ClanHealth = 0 then
+ with TeamsArray[t]^ do
begin
- SendStat(siPlayerKills, IntToStr(Clan^.Color) + ' ' +
- IntToStr(stats.Kills) + ' ' + TeamName);
+ if Clan^.ClanHealth = 0 then
+ begin
+ SendStat(siPlayerKills, IntToStr(Clan^.Color) + ' ' +
+ IntToStr(stats.Kills) + ' ' + TeamName);
+ end;
end;
end;
-end;
-if msdhh <> nil then
- SendStat(siMaxStepDamage, IntToStr(msd) + ' ' + msdhh^.Name + ' (' + msdhh^.Team^.TeamName + ')');
-if mskcnt = 1 then
- SendStat(siMaxStepKills, IntToStr(msk) + ' ' + mskhh^.Name + ' (' + mskhh^.Team^.TeamName + ')');
-
-if maxTeamKills > 1 then
- SendStat(siMaxTeamKills, IntToStr(maxTeamKills) + ' ' + maxTeamKillsName);
-if maxTurnSkips > 2 then
- SendStat(siMaxTurnSkips, IntToStr(maxTurnSkips) + ' ' + maxTurnSkipsName);
-if maxTeamDamage > 30 then
- SendStat(siMaxTeamDamage, IntToStr(maxTeamDamage) + ' ' + maxTeamDamageName);
+ if msdhh <> nil then
+ SendStat(siMaxStepDamage, IntToStr(msd) + ' ' + msdhh^.Name + ' (' + msdhh^.Team^.TeamName + ')');
+ if mskcnt = 1 then
+ SendStat(siMaxStepKills, IntToStr(msk) + ' ' + mskhh^.Name + ' (' + mskhh^.Team^.TeamName + ')');
+
+ if maxTeamKills > 1 then
+ SendStat(siMaxTeamKills, IntToStr(maxTeamKills) + ' ' + maxTeamKillsName);
+ if maxTurnSkips > 2 then
+ SendStat(siMaxTurnSkips, IntToStr(maxTurnSkips) + ' ' + maxTurnSkipsName);
+ if maxTeamDamage > 30 then
+ SendStat(siMaxTeamDamage, IntToStr(maxTeamDamage) + ' ' + maxTeamDamageName);
-if KilledHHs > 0 then
- SendStat(siKilledHHs, IntToStr(KilledHHs));
+ if KilledHHs > 0 then
+ SendStat(siKilledHHs, IntToStr(KilledHHs));
-// now to console
-if winnersClan <> nil then
- begin
- WriteLnToConsole('WINNERS');
- for t:= 0 to winnersClan^.TeamsNumber - 1 do
- WriteLnToConsole(winnersClan^.Teams[t]^.TeamName);
- end
-else
- WriteLnToConsole('DRAW');
+ // now to console
+ if winnersClan <> nil then
+ begin
+ WriteLnToConsole('WINNERS');
+ WriteLnToConsole(inttostr(winnersClan^.TeamsNumber));
+ for t:= 0 to winnersClan^.TeamsNumber - 1 do
+ WriteLnToConsole(winnersClan^.Teams[t]^.TeamName);
+ end
+ else
+ WriteLnToConsole('DRAW');
+
+ ScriptCall('onAchievementsDeclaration');
+end;
-WriteLnToConsole('');
+procedure declareAchievement(id, teamname, location: shortstring; value: LongInt);
+begin
+if (length(id) = 0) or (length(teamname) = 0) or (length(location) = 0) then exit;
+ WriteLnToConsole('ACHIEVEMENT');
+ WriteLnToConsole(id);
+ WriteLnToConsole(teamname);
+ WriteLnToConsole(location);
+ WriteLnToConsole(inttostr(value));
end;
procedure initModule;
diff -Nru hedgewars-0.9.19.3/hedgewars/uStore.pas hedgewars-0.9.20.5/hedgewars/uStore.pas
--- hedgewars-0.9.19.3/hedgewars/uStore.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uStore.pas 2014-01-08 16:25:17.000000000 +0000
@@ -29,6 +29,7 @@
procedure StoreLoad(reload: boolean);
procedure StoreRelease(reload: boolean);
procedure RenderHealth(var Hedgehog: THedgehog);
+function makeHealthBarTexture(w, h, Color: Longword): PTexture;
procedure AddProgress;
procedure FinishProgress;
function LoadImage(const filename: shortstring; imageFlags: LongInt): PSDL_Surface;
@@ -52,20 +53,23 @@
procedure InitOffscreenOpenGL;
{$ENDIF}
+{$IFDEF SDL2}
procedure WarpMouse(x, y: Word); inline;
+{$ENDIF}
procedure SwapBuffers; {$IFDEF USE_VIDEO_RECORDING}cdecl{$ELSE}inline{$ENDIF};
+procedure SetSkyColor(r, g, b: real);
implementation
uses uMisc, uConsole, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands
, uPhysFSLayer
, uDebug
{$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF}
- {$IF NOT DEFINED(SDL13) AND DEFINED(USE_VIDEO_RECORDING)}, glut {$ENDIF};
+ {$IF NOT DEFINED(SDL2) AND DEFINED(USE_VIDEO_RECORDING)}, glut {$ENDIF};
//type TGPUVendor = (gvUnknown, gvNVIDIA, gvATI, gvIntel, gvApple);
var MaxTextureSize: LongInt;
-{$IFDEF SDL13}
+{$IFDEF SDL2}
SDLwindow: PSDL_Window;
SDLGLcontext: PSDL_GLContext;
{$ELSE}
@@ -75,7 +79,7 @@
numsquares : LongInt;
ProgrTex: PTexture;
-const
+const
cHHFileName = 'Hedgehog';
cCHFileName = 'Crosshair';
@@ -107,76 +111,61 @@
end;
procedure MakeCrossHairs;
-var t: LongInt;
- tmpsurf, texsurf: PSDL_Surface;
- Color, i: Longword;
+var tmpsurf: PSDL_Surface;
begin
-tmpsurf:= LoadDataImage(ptGraphics, cCHFileName, ifAlpha or ifCritical);
-
-for t:= 0 to Pred(TeamsCount) do
- with TeamsArray[t]^ do
- begin
- texsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, tmpsurf^.w, tmpsurf^.h, 32, RMask, GMask, BMask, AMask);
- TryDo(texsurf <> nil, errmsgCreateSurface, true);
-
- Color:= Clan^.Color;
- Color:= SDL_MapRGB(texsurf^.format, Color shr 16, Color shr 8, Color and $FF);
- SDL_FillRect(texsurf, nil, Color);
+ tmpsurf:= LoadDataImage(ptGraphics, cCHFileName, ifAlpha or ifCritical);
- SDL_UpperBlit(tmpsurf, nil, texsurf, nil);
+ CrosshairTexture:= Surface2Tex(tmpsurf, false);
- TryDo(tmpsurf^.format^.BytesPerPixel = 4, 'Ooops', true);
-
- if SDL_MustLock(texsurf) then
- SDLTry(SDL_LockSurface(texsurf) >= 0, true);
+ SDL_FreeSurface(tmpsurf)
+end;
- // make black pixel be alpha-transparent
- for i:= 0 to texsurf^.w * texsurf^.h - 1 do
- if PLongwordArray(texsurf^.pixels)^[i] = AMask then
- PLongwordArray(texsurf^.pixels)^[i]:= (RMask or GMask or BMask) and Color;
+function makeHealthBarTexture(w, h, Color: Longword): PTexture;
+var
+ rr: TSDL_Rect;
+ texsurf: PSDL_Surface;
+begin
+ rr.x:= 0;
+ rr.y:= 0;
+ rr.w:= w;
+ rr.h:= h;
- if SDL_MustLock(texsurf) then
- SDL_UnlockSurface(texsurf);
+ texsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, RMask, GMask, BMask, AMask);
+ TryDo(texsurf <> nil, errmsgCreateSurface, true);
+ TryDo(SDL_SetColorKey(texsurf, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true);
- FreeTexture(CrosshairTex);
- CrosshairTex:= Surface2Tex(texsurf, false);
- SDL_FreeSurface(texsurf)
- end;
+ DrawRoundRect(@rr, cWhiteColor, cNearBlackColor, texsurf, true);
-SDL_FreeSurface(tmpsurf)
+ rr.x:= 2;
+ rr.y:= 2;
+ rr.w:= w - 4;
+ rr.h:= h - 4;
+
+ DrawRoundRect(@rr, Color, Color, texsurf, false);
+ makeHealthBarTexture:= Surface2Tex(texsurf, false);
+ SDL_FreeSurface(texsurf);
end;
-
procedure WriteNames(Font: THWFont);
var t: LongInt;
i, maxLevel: LongInt;
- r, rr: TSDL_Rect;
+ r: TSDL_Rect;
drY: LongInt;
texsurf, flagsurf, iconsurf: PSDL_Surface;
foundBot: boolean;
+ year, month, md : word;
begin
if cOnlyStats then exit;
r.x:= 0;
r.y:= 0;
drY:= - 4;
+DecodeDate(Date, year, month, md);
for t:= 0 to Pred(TeamsCount) do
with TeamsArray[t]^ do
begin
NameTagTex:= RenderStringTexLim(TeamName, Clan^.Color, Font, cTeamHealthWidth);
-
- r.w:= cTeamHealthWidth + 5;
- r.h:= NameTagTex^.h;
-
- texsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, r.w, r.h, 32, RMask, GMask, BMask, AMask);
- TryDo(texsurf <> nil, errmsgCreateSurface, true);
- TryDo(SDL_SetColorKey(texsurf, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true);
-
- DrawRoundRect(@r, cWhiteColor, cNearBlackColor, texsurf, true);
- rr:= r;
- inc(rr.x, 2); dec(rr.w, 4); inc(rr.y, 2); dec(rr.h, 4);
- DrawRoundRect(@rr, Clan^.Color, Clan^.Color, texsurf, false);
- HealthTex:= Surface2Tex(texsurf, false);
- SDL_FreeSurface(texsurf);
+ if length(Owner) > 0 then
+ OwnerTex:= RenderStringTexLim(Owner, Clan^.Color, Font, cTeamHealthWidth);
r.x:= 0;
r.y:= 0;
@@ -201,7 +190,7 @@
foundBot:= true;
// initially was going to do the highest botlevel of the team, but for now, just apply if entire team has same bot level
if maxLevel = -1 then maxLevel:= BotLevel
- else if (maxLevel > 0) and (maxLevel <> BotLevel) then maxLevel:= 0;
+ else if (maxLevel > 0) and (maxLevel <> BotLevel) then maxLevel:= 0;
//if (maxLevel > 0) and (BotLevel < maxLevel) then maxLevel:= BotLevel
end
else if Gear <> nil then maxLevel:= 0;
@@ -209,7 +198,7 @@
if foundBot then
begin
// disabled the plain flag - I think it looks ok even w/ full bars obscuring CPU
- //if (maxLevel > 0) and (maxLevel < 3) then Flag:= 'cpu_plain' else
+ //if (maxLevel > 0) and (maxLevel < 3) then Flag:= 'cpu_plain' else
Flag:= 'cpu'
end
else if (Flag = 'cpu') or (Flag = 'cpu_plain') then
@@ -219,10 +208,10 @@
TryDo(flagsurf <> nil, 'Failed to load flag "' + Flag + '" as well as the default flag', true);
case maxLevel of
- 1: copyToXY(SpritesData[sprBotlevels].Surface, flagsurf, 0, 0);
- 2: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 5, 2, 17, 13, 5, 2);
- 3: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 9, 5, 13, 10, 9, 5);
- 4: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 13, 9, 9, 6, 13, 9);
+ 1: copyToXY(SpritesData[sprBotlevels].Surface, flagsurf, 0, 0);
+ 2: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 5, 2, 17, 13, 5, 2);
+ 3: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 9, 5, 13, 10, 9, 5);
+ 4: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 13, 9, 9, 6, 13, 9);
5: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 17, 11, 5, 4, 17, 11)
end;
@@ -251,6 +240,16 @@
if Gear <> nil then
begin
NameTagTex:= RenderStringTexLim(Name, Clan^.Color, fnt16, cTeamHealthWidth);
+ if Hat = 'NoHat' then
+ begin
+ if (month = 4) and (md = 20) then
+ Hat := 'eastertop' // Easter
+ else if (month = 12) and ((md = 24) or (md = 25) or (md = 26)) then
+ Hat := 'Santa' // Christmas Eve/Christmas/Boxing Day
+ else if (month = 10) and (md = 31) then
+ Hat := 'fr_pumpkin'; // Halloween/Hedgewars' birthday
+ end;
+
if Hat <> 'NoHat' then
begin
if (Length(Hat) > 39) and (Copy(Hat,1,8) = 'Reserved') and (Copy(Hat,9,32) = PlayerHash) then
@@ -273,8 +272,16 @@
SDL_FreeSurface(iconsurf);
iconsurf:= nil;
end;
+
+
+for t:= 0 to Pred(ClansCount) do
+ with ClansArray[t]^ do
+ HealthTex:= makeHealthBarTexture(cTeamHealthWidth + 5, Teams[0]^.NameTagTex^.h, Color);
+
+GenericHealthTexture:= makeHealthBarTexture(cTeamHealthWidth + 5, TeamsArray[0]^.NameTagTex^.h, cWhiteColor)
end;
+
procedure InitHealth;
var i, t: LongInt;
begin
@@ -337,7 +344,7 @@
if (((cReducedQuality and (rqNoBackground or rqLowRes)) = 0) or // why rqLowRes?
(not (ii in [sprSky, sprSkyL, sprSkyR, sprHorizont, sprHorizontL, sprHorizontR]))) and
(((cReducedQuality and rqPlainSplash) = 0) or ((not (ii in [sprSplash, sprDroplet, sprSDSplash, sprSDDroplet])))) and
- (((cReducedQuality and rqKillFlakes) = 0) or (Theme = 'Snow') or (Theme = 'Christmas') or ((not (ii in [sprFlake, sprSDFlake])))) and
+ (((cReducedQuality and rqKillFlakes) = 0) or cSnow or ((not (ii in [sprFlake, sprSDFlake])))) and
((cCloudsNumber > 0) or (ii <> sprCloud)) and
((vobCount > 0) or (ii <> sprFlake)) then
begin
@@ -384,7 +391,7 @@
if not reload then
begin
{$IFDEF USE_CONTEXT_RESTORE}
- Surface:= tmpsurf
+ Surface:= tmpsurf
{$ELSE}
if saveSurf then
Surface:= tmpsurf
@@ -410,6 +417,7 @@
InitHealth;
PauseTexture:= RenderStringTex(trmsg[sidPaused], cYellowColor, fntBig);
+AFKTexture:= RenderStringTex(trmsg[sidAFK], cYellowColor, fntBig);
ConfirmTexture:= RenderStringTex(trmsg[sidConfirm], cYellowColor, fntBig);
SyncTexture:= RenderStringTex(trmsg[sidSync], cYellowColor, fntBig);
@@ -476,8 +484,8 @@
begin
for ii:= Low(TSprite) to High(TSprite) do
begin
- FreeTexture(SpritesData[ii].Texture);
- SpritesData[ii].Texture:= nil;
+ FreeAndNilTexture(SpritesData[ii].Texture);
+
if (SpritesData[ii].Surface <> nil) and (not reload) then
begin
SDL_FreeSurface(SpritesData[ii].Surface);
@@ -487,58 +495,47 @@
SDL_FreeSurface(MissionIcons);
// free the textures declared in uVariables
-FreeTexture(WeaponTooltipTex);
-WeaponTooltipTex:= nil;
-FreeTexture(PauseTexture);
-PauseTexture:= nil;
-FreeTexture(SyncTexture);
-SyncTexture:= nil;
-FreeTexture(ConfirmTexture);
-ConfirmTexture:= nil;
-FreeTexture(ropeIconTex);
-ropeIconTex:= nil;
-FreeTexture(HHTexture);
-HHTexture:= nil;
-
+FreeAndNilTexture(CrosshairTexture);
+FreeAndNilTexture(WeaponTooltipTex);
+FreeAndNilTexture(PauseTexture);
+FreeAndNilTexture(AFKTexture);
+FreeAndNilTexture(SyncTexture);
+FreeAndNilTexture(ConfirmTexture);
+FreeAndNilTexture(ropeIconTex);
+FreeAndNilTexture(HHTexture);
+FreeAndNilTexture(GenericHealthTexture);
// free all ammo name textures
for ai:= Low(TAmmoType) to High(TAmmoType) do
- begin
- FreeTexture(Ammoz[ai].NameTex);
- Ammoz[ai].NameTex:= nil
- end;
+ FreeAndNilTexture(Ammoz[ai].NameTex);
// free all count textures
for i:= Low(CountTexz) to High(CountTexz) do
begin
- FreeTexture(CountTexz[i]);
+ FreeAndNilTexture(CountTexz[i]);
CountTexz[i]:= nil
end;
+ for t:= 0 to Pred(ClansCount) do
+ begin
+ if ClansArray[t] <> nil then
+ FreeAndNilTexture(ClansArray[t]^.HealthTex);
+ end;
+
// free all team and hedgehog textures
for t:= 0 to Pred(TeamsCount) do
begin
if TeamsArray[t] <> nil then
begin
- FreeTexture(TeamsArray[t]^.NameTagTex);
- TeamsArray[t]^.NameTagTex:= nil;
- FreeTexture(TeamsArray[t]^.CrosshairTex);
- TeamsArray[t]^.CrosshairTex:= nil;
- FreeTexture(TeamsArray[t]^.GraveTex);
- TeamsArray[t]^.GraveTex:= nil;
- FreeTexture(TeamsArray[t]^.HealthTex);
- TeamsArray[t]^.HealthTex:= nil;
- FreeTexture(TeamsArray[t]^.AIKillsTex);
- TeamsArray[t]^.AIKillsTex:= nil;
- FreeTexture(TeamsArray[t]^.FlagTex);
- TeamsArray[t]^.FlagTex:= nil;
+ FreeAndNilTexture(TeamsArray[t]^.NameTagTex);
+ FreeAndNilTexture(TeamsArray[t]^.GraveTex);
+ FreeAndNilTexture(TeamsArray[t]^.AIKillsTex);
+ FreeAndNilTexture(TeamsArray[t]^.FlagTex);
+
for i:= 0 to cMaxHHIndex do
begin
- FreeTexture(TeamsArray[t]^.Hedgehogs[i].NameTagTex);
- TeamsArray[t]^.Hedgehogs[i].NameTagTex:= nil;
- FreeTexture(TeamsArray[t]^.Hedgehogs[i].HealthTagTex);
- TeamsArray[t]^.Hedgehogs[i].HealthTagTex:= nil;
- FreeTexture(TeamsArray[t]^.Hedgehogs[i].HatTex);
- TeamsArray[t]^.Hedgehogs[i].HatTex:= nil;
+ FreeAndNilTexture(TeamsArray[t]^.Hedgehogs[i].NameTagTex);
+ FreeAndNilTexture(TeamsArray[t]^.Hedgehogs[i].HealthTagTex);
+ FreeAndNilTexture(TeamsArray[t]^.Hedgehogs[i].HatTex);
end;
end;
end;
@@ -605,7 +602,7 @@
begin
// check for file in user dir (never critical)
tmpsurf:= LoadImage(cPathz[path] + '/' + filename, imageFlags);
-
+
LoadDataImage:= tmpsurf;
end;
@@ -647,14 +644,18 @@
procedure LoadHedgehogHat(var HH: THedgehog; newHat: shortstring);
var texsurf: PSDL_Surface;
begin
+ // free the mem of any previously assigned texture. This was previously only if the new one could be loaded, but, NoHat is usually a better choice
+ if HH.HatTex <> nil then
+ begin
+ FreeTexture(HH.HatTex);
+ HH.HatTex:= nil
+ end;
texsurf:= LoadDataImage(ptHats, newHat, ifNone);
AddFileLog('Hat => '+newHat);
// only do something if the hat could be loaded
if texsurf <> nil then
begin
AddFileLog('Got Hat');
- // free the mem of any previously assigned texture
- FreeTexture(HH.HatTex);
// assign new hat to hedgehog
HH.HatTex:= Surface2Tex(texsurf, true);
@@ -687,35 +688,38 @@
SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 1);
{$ELSE}
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-{$IFNDEF SDL13} // vsync is default in 1.3
- SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, LongInt((cReducedQuality and rqDesyncVBlank) = 0));
{$ENDIF}
+{$IFNDEF SDL2} // vsync is default in SDL2
+ SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, LongInt((cReducedQuality and rqDesyncVBlank) = 0));
{$ENDIF}
- SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); // no depth buffer
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
- SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); // no alpha channel required
- SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 16); // buffer has to be 16 bit only
- SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); // try to prefer hardware rendering
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); // no depth buffer
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); // no alpha channel
+ SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 16); // buffer should be 16
+ SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); // prefer hw rendering
end;
procedure SetupOpenGL;
-//var vendor: shortstring = '';
var buf: array[byte] of char;
-{$IFDEF USE_VIDEO_RECORDING}
- AuxBufNum: LongInt;
-{$ENDIF}
+ AuxBufNum: LongInt = 0;
tmpstr: AnsiString;
tmpint: LongInt;
tmpn: LongInt;
begin
+{$IFDEF SDL2}
+ AddFileLog('Setting up OpenGL (using driver: ' + shortstring(SDL_GetCurrentVideoDriver()) + ')');
+{$ELSE}
buf[0]:= char(0); // avoid compiler hint
AddFileLog('Setting up OpenGL (using driver: ' + shortstring(SDL_VideoDriverName(buf, sizeof(buf))) + ')');
+{$ENDIF}
+
+ AuxBufNum:= AuxBufNum;
-{$IFDEF SDL13}
- // this function creates an opengles1.1 context by default on mobile devices
- // unless you un-comment this two attributes
+{$IFDEF MOBILE}
+ // TODO: this function creates an opengles1.1 context
+ // un-comment below and add proper logic to support opengles2.0
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
if SDLGLcontext = nil then
@@ -724,7 +728,7 @@
SDL_GL_SetSwapInterval(1);
{$ENDIF}
- // get the max (horizontal and vertical) size for textures that the gpu can support
+ // get the max (h and v) size for textures that the gpu can support
glGetIntegerv(GL_MAX_TEXTURE_SIZE, @MaxTextureSize);
if MaxTextureSize <= 0 then
begin
@@ -733,29 +737,11 @@
end
else if (MaxTextureSize < 1024) and (MaxTextureSize >= 512) then
begin
- cReducedQuality := cReducedQuality or rqNoBackground;
+ cReducedQuality := cReducedQuality or rqNoBackground;
AddFileLog('Texture size too small for backgrounds, disabling.');
end;
-(* // find out which gpu we are using (for extension compatibility maybe?)
-{$IFDEF IPHONEOS}
- vendor:= vendor; // avoid hint
- cGPUVendor:= gvApple;
-{$ELSE}
- vendor:= LowerCase(shortstring(pchar(glGetString(GL_VENDOR))));
- if StrPos(Str2PChar(vendor), Str2PChar('nvidia')) <> nil then
- cGPUVendor:= gvNVIDIA
- else if StrPos(Str2PChar(vendor), Str2PChar('intel')) <> nil then
- cGPUVendor:= gvATI
- else if StrPos(Str2PChar(vendor), Str2PChar('ati')) <> nil then
- cGPUVendor:= gvIntel
- else
- AddFileLog('OpenGL Warning - unknown hardware vendor; please report');
-{$ENDIF}
-//SupportNPOTT:= glLoadExtension('GL_ARB_texture_non_power_of_two');
-*)
-
- // everyone love debugging
+ // everyone loves debugging
AddFileLog('OpenGL-- Renderer: ' + shortstring(pchar(glGetString(GL_RENDERER))));
AddFileLog(' |----- Vendor: ' + shortstring(pchar(glGetString(GL_VENDOR))));
AddFileLog(' |----- Version: ' + shortstring(pchar(glGetString(GL_VERSION))));
@@ -856,7 +842,7 @@
exit;
if f = cDefaultZoomLevel then
- glPopMatrix // "return" to default scaling
+ glPopMatrix // return to default scaling
else // other scaling
begin
glPushMatrix; // save default scaling
@@ -887,7 +873,7 @@
with mobileRecord do
if GameLoading <> nil then
GameLoading();
-
+
end;
TryDo(ProgrTex <> nil, 'Error - Progress Texure is nil!', true);
@@ -1098,11 +1084,11 @@
end;
{$IFDEF USE_VIDEO_RECORDING}
-{$IFDEF SDL13}
+{$IFDEF SDL2}
procedure InitOffscreenOpenGL;
begin
// create hidden window
- SDLwindow:= SDL_CreateWindow('hedgewars (you don''t see this)',
+ SDLwindow:= SDL_CreateWindow('hedgewars video rendering (SDL2 hidden window)',
SDL_WINDOWPOS_CENTERED_MASK, SDL_WINDOWPOS_CENTERED_MASK,
cScreenWidth, cScreenHeight,
SDL_WINDOW_HIDDEN or SDL_WINDOW_OPENGL);
@@ -1118,19 +1104,21 @@
PrgName:= 'hwengine';
glutInit(@ArgCount, @PrgName);
glutInitWindowSize(cScreenWidth, cScreenHeight);
- glutCreateWindow('hedgewars (you don''t see this)'); // we don't need a window, but if this function is not called then OpenGL will not be initialized
+ // we do not need a window, but without this call OpenGL will not initialize
+ glutCreateWindow('hedgewars video rendering (glut hidden window)');
glutHideWindow();
- glutDisplayFunc(@SwapBuffers); // we don't need a callback, but it's required for GLUT3
+ // we do not need to set this callback, but it is required for GLUT3 compat
+ glutDisplayFunc(@SwapBuffers);
SetupOpenGL();
end;
-{$ENDIF} // SDL13
+{$ENDIF} // SDL2
{$ENDIF} // USE_VIDEO_RECORDING
procedure chFullScr(var s: shortstring);
var flags: Longword = 0;
reinit: boolean = false;
{$IFNDEF DARWIN}ico: PSDL_Surface;{$ENDIF}
- {$IFDEF SDL13}x, y: LongInt;{$ENDIF}
+ {$IFDEF SDL2}x, y: LongInt;{$ENDIF}
begin
if cOnlyStats then
begin
@@ -1140,7 +1128,7 @@
if Length(s) = 0 then
cFullScreen:= (not cFullScreen)
else cFullScreen:= s = '1';
-
+
if cFullScreen then
begin
cScreenWidth:= cFullscreenWidth;
@@ -1153,14 +1141,16 @@
end;
AddFileLog('Preparing to change video parameters...');
-{$IFDEF SDL13}
+{$IFDEF SDL2}
if SDLwindow = nil then
{$ELSE}
if SDLPrimSurface = nil then
{$ENDIF}
begin
// set window title
- {$IFNDEF SDL13}SDL_WM_SetCaption(_P'Hedgewars', nil);{$ENDIF}
+ {$IFNDEF SDL2}
+ SDL_WM_SetCaption(_P'Hedgewars', nil);
+ {$ENDIF}
WriteToConsole('Init SDL_image... ');
SDLTry(IMG_Init(IMG_INIT_PNG) <> 0, true);
WriteLnToConsole(msgOK);
@@ -1189,7 +1179,7 @@
exit;
{$ELSE}
SetScale(cDefaultZoomLevel);
- {$IFDEF USE_CONTEXT_RESTORE}
+ {$IFDEF USE_CONTEXT_RESTORE}
reinit:= true;
StoreRelease(true);
ResetLand;
@@ -1197,7 +1187,7 @@
//uTextures.freeModule; //DEBUG ONLY
{$ENDIF}
AddFileLog('Freeing old primary surface...');
- {$IFNDEF SDL13}
+ {$IFNDEF SDL2}
SDL_FreeSurface(SDLPrimSurface);
SDLPrimSurface:= nil;
{$ENDIF}
@@ -1206,17 +1196,20 @@
// these attributes must be set up before creating the sdl window
{$IFNDEF WIN32}
-(* On a large number of testers machines, SDL default to software rendering when opengl attributes were set.
- These attributes were "set" after CreateWindow in .15, which probably did nothing.
- IMO we should rely on the gl_config defaults from SDL, and use SDL_GL_GetAttribute to possibly post warnings if any
- bad values are set. *)
+(* On a large number of testers machines, SDL default to software rendering
+ when opengl attributes were set. These attributes were "set" after
+ CreateWindow in .15, which probably did nothing.
+ IMO we should rely on the gl_config defaults from SDL, and use
+ SDL_GL_GetAttribute to possibly post warnings if any bad values are set.
+ *)
SetupOpenGLAttributes();
{$ENDIF}
-{$IFDEF SDL13}
+{$IFDEF SDL2}
// these values in x and y make the window appear in the center
x:= SDL_WINDOWPOS_CENTERED_MASK;
y:= SDL_WINDOWPOS_CENTERED_MASK;
- // SDL_WINDOW_RESIZABLE makes the window respond to rotation events on mobile devices
+ // SDL_WINDOW_RESIZABLE makes the window resizable and
+ // respond to rotation events on mobile devices
flags:= SDL_WINDOW_OPENGL or SDL_WINDOW_SHOWN or SDL_WINDOW_RESIZABLE;
{$IFDEF MOBILE}
@@ -1226,20 +1219,16 @@
flags:= flags or SDL_WINDOW_BORDERLESS;
{$ENDIF}
+ if cFullScreen then
+ flags:= flags or SDL_WINDOW_FULLSCREEN;
+
if SDLwindow = nil then
- if cFullScreen then
- 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;
+ SDLwindow:= SDL_CreateWindow('Hedgewars', x, y, cScreenWidth, cScreenHeight, flags);
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}
@@ -1248,7 +1237,9 @@
{$ENDIF}
SDLPrimSurface:= SDL_SetVideoMode(cScreenWidth, cScreenHeight, 0, flags);
SDLTry(SDLPrimSurface <> nil, true);
- {$IFDEF WIN32}SDL_putenv(str2pchar('SDL_VIDEO_CENTERED=' + s));{$ENDIF}
+ {$IFDEF WIN32}
+ SDL_putenv(str2pchar('SDL_VIDEO_CENTERED=' + s));
+ {$ENDIF}
end;
{$ENDIF}
@@ -1258,11 +1249,11 @@
// clean the window from any previous content
glClear(GL_COLOR_BUFFER_BIT);
if SuddenDeathDmg then
- glClearColor(SDSkyColor.r * (SDTint/255) / 255, SDSkyColor.g * (SDTint/255) / 255, SDSkyColor.b * (SDTint/255) / 255, 0.99)
- else if ((cReducedQuality and rqNoBackground) = 0) then
- glClearColor(SkyColor.r / 255, SkyColor.g / 255, SkyColor.b / 255, 0.99)
+ SetSkyColor(SDSkyColor.r * (SDTint/255) / 255, SDSkyColor.g * (SDTint/255) / 255, SDSkyColor.b * (SDTint/255) / 255)
+ else if ((cReducedQuality and rqNoBackground) = 0) then
+ SetSkyColor(SkyColor.r / 255, SkyColor.g / 255, SkyColor.b / 255)
else
- glClearColor(RQSkyColor.r / 255, RQSkyColor.g / 255, RQSkyColor.b / 255, 0.99);
+ SetSkyColor(RQSkyColor.r / 255, RQSkyColor.g / 255, RQSkyColor.b / 255);
// reload everything we had before
ReloadCaptions(false);
@@ -1273,6 +1264,33 @@
end;
end;
+{$IFDEF SDL2}
+// for sdl1.2 we directly call SDL_WarpMouse()
+// for sdl2 we provide a SDL_WarpMouse() which just calls this function
+// this has the advantage of reducing 'uses' and 'ifdef' statements
+// (SDLwindow is a private member of this module)
+procedure WarpMouse(x, y: Word); inline;
+begin
+ SDL_WarpMouseInWindow(SDLwindow, x, y);
+end;
+{$ENDIF}
+
+procedure SwapBuffers; {$IFDEF USE_VIDEO_RECORDING}cdecl{$ELSE}inline{$ENDIF};
+begin
+ if GameType = gmtRecord then
+ exit;
+{$IFDEF SDL2}
+ SDL_GL_SwapWindow(SDLwindow);
+{$ELSE}
+ SDL_GL_SwapBuffers();
+{$ENDIF}
+end;
+
+procedure SetSkyColor(r, g, b: real);
+begin
+ glClearColor(r, g, b, 0.99)
+end;
+
procedure initModule;
var ai: TAmmoType;
i: LongInt;
@@ -1292,7 +1310,7 @@
// init all count texture pointers
for i:= Low(CountTexz) to High(CountTexz) do
CountTexz[i] := nil;
-{$IFDEF SDL13}
+{$IFDEF SDL2}
SDLwindow:= nil;
SDLGLcontext:= nil;
{$ELSE}
@@ -1304,31 +1322,10 @@
begin
StoreRelease(false);
TTF_Quit();
-{$IFDEF SDL13}
+{$IFDEF SDL2}
SDL_GL_DeleteContext(SDLGLcontext);
SDL_DestroyWindow(SDLwindow);
{$ENDIF}
SDL_Quit();
end;
-
-procedure WarpMouse(x, y: Word); inline;
-begin
-{$IFDEF SDL13}
- SDL_WarpMouseInWindow(SDLwindow, x, y);
-{$ELSE}
- x:= x; y:= y; // avoid hints
-{$ENDIF}
-end;
-
-procedure SwapBuffers; {$IFDEF USE_VIDEO_RECORDING}cdecl{$ELSE}inline{$ENDIF};
-begin
- if GameType = gmtRecord then
- exit;
-{$IFDEF SDL13}
- SDL_GL_SwapWindow(SDLwindow);
-{$ELSE}
- SDL_GL_SwapBuffers();
-{$ENDIF}
-end;
-
end.
diff -Nru hedgewars-0.9.19.3/hedgewars/uTeams.pas hedgewars-0.9.20.5/hedgewars/uTeams.pas
--- hedgewars-0.9.19.3/hedgewars/uTeams.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uTeams.pas 2014-01-08 16:25:17.000000000 +0000
@@ -1,4 +1,4 @@
-(*
+ (*
* Hedgewars, a free turn based strategy game
* Copyright (c) 2004-2013 Andrey Korotaev
*
@@ -20,8 +20,8 @@
unit uTeams;
interface
-uses uConsts, uInputHandler, uGears, uRandom, uFloat, uStats, uVisualGears, uCollisions, GLunit,
- uSound, uStore, uTypes
+uses uConsts, uInputHandler, uRandom, uFloat, uStats,
+ uCollisions, uSound, uStore, uTypes, uScript
{$IFDEF USE_TOUCH_INTERFACE}, uWorld{$ENDIF};
@@ -34,18 +34,21 @@
procedure InitTeams;
function TeamSize(p: PTeam): Longword;
procedure RecountTeamHealth(team: PTeam);
+procedure RestoreHog(HH: PHedgehog);
+
procedure RestoreTeamsFromSave;
function CheckForWin: boolean;
procedure TeamGoneEffect(var Team: TTeam);
procedure SwitchCurrentHedgehog(newHog: PHedgehog);
+var MaxTeamHealth: LongInt;
+
implementation
uses uLocale, uAmmos, uChat, uVariables, uUtils, uIO, uCaptions, uCommands, uDebug,
- uGearsUtils, uGearsList
+ uGearsUtils, uGearsList, uVisualGearsList, uTextures
{$IFDEF USE_TOUCH_INTERFACE}, uTouch{$ENDIF};
-var MaxTeamHealth: LongInt;
- GameOver: boolean;
+var GameOver: boolean;
NextClan: boolean;
function CheckForWin: boolean;
@@ -96,7 +99,7 @@
if (Gear <> nil) then
Gear^.State:= gstWinner;
if Flawless then
- AddVoice(sndFlawless, Teams[0]^.voicepack)
+ AddVoice(sndFlawless, Teams[0]^.voicepack)
else
AddVoice(sndVictory, Teams[0]^.voicepack);
@@ -110,7 +113,7 @@
end;
procedure SwitchHedgehog;
-var c, i, t, j: LongWord;
+var c, i, t: LongWord;
PrevHH, PrevTeam : LongWord;
begin
TargetPoint.X:= NoPointX;
@@ -124,7 +127,7 @@
DeleteCI(Gear);
FindPlace(Gear, false, 0, LAND_WIDTH);
if Gear <> nil then
- AddGearCI(Gear)
+ AddCI(Gear)
end
end;
@@ -190,18 +193,22 @@
CurrHedgehog:= Succ(CurrHedgehog) mod HedgehogsNumber;
until ((Hedgehogs[CurrHedgehog].Gear <> nil) and (Hedgehogs[CurrHedgehog].Effects[heFrozen] < 256)) or (CurrHedgehog = PrevHH)
end
- until ((CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Effects[heFrozen] < 50256)) or (PrevTeam = CurrTeam) or ((CurrTeam = TagTeamIndex) and ((GameFlags and gfTagTeam) <> 0))
+ until ((CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Effects[heFrozen] < 256)) or (PrevTeam = CurrTeam) or ((CurrTeam = TagTeamIndex) and ((GameFlags and gfTagTeam) <> 0))
end;
if (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear = nil) or (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Effects[heFrozen] > 255) then
begin
- inc(CurrentTeam^.Clan^.TurnNumber);
with CurrentTeam^.Clan^ do
for t:= 0 to Pred(TeamsNumber) do
with Teams[t]^ do
for i:= 0 to Pred(HedgehogsNumber) do
with Hedgehogs[i] do
- if Effects[heFrozen] > 255 then
- Effects[heFrozen]:= max(255,Effects[heFrozen]-50000)
+ begin
+ if Effects[heFrozen] > 255 then Effects[heFrozen]:= max(255,Effects[heFrozen]-50000);
+ if (Gear <> nil) and (Effects[heFrozen] < 256) and (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Effects[heFrozen] > 255) then
+ CurrHedgehog:= i
+ end;
+ if (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear = nil) or (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Effects[heFrozen] > 255) then
+ inc(CurrentTeam^.Clan^.TurnNumber);
end
until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Effects[heFrozen] < 256);
@@ -357,7 +364,7 @@
inc(TeamsCount);
for t:= 0 to cKbdMaxIndex do
- team^.Binds[t]:= '';
+ team^.Binds[t]:= DefaultBinds[t];
c:= Pred(ClansCount);
while (c >= 0) and (ClansArray[c]^.Color <> TeamColor) do dec(c);
@@ -474,17 +481,11 @@
else if Hedgehogs[i].GearHidden <> nil then
inc(TeamHealth, Hedgehogs[i].GearHidden^.Health);
- if not hasGone then
- NewTeamHealthBarWidth:= TeamHealth
- else
- NewTeamHealthBarWidth:= 0;
-
- if NewTeamHealthBarWidth > MaxTeamHealth then
+ if TeamHealth > MaxTeamHealth then
begin
- MaxTeamHealth:= NewTeamHealthBarWidth;
+ MaxTeamHealth:= TeamHealth;
RecountAllTeamsHealth;
- end else if NewTeamHealthBarWidth > 0 then
- NewTeamHealthBarWidth:= (NewTeamHealthBarWidth * cTeamHealthWidth) div MaxTeamHealth
+ end
end;
RecountClanHealth(team^.Clan);
@@ -492,6 +493,17 @@
AddVisualGear(0, 0, vgtTeamHealthSorter)
end;
+procedure RestoreHog(HH: PHedgehog);
+begin
+ HH^.Gear:=HH^.GearHidden;
+ HH^.GearHidden:= nil;
+ InsertGearToList(HH^.Gear);
+ HH^.Gear^.State:= (HH^.Gear^.State and (not (gstHHDriven or gstInvisible or gstAttacking))) or gstAttacked;
+ AddCI(HH^.Gear);
+ HH^.Gear^.Active:= true;
+ ScriptCall('onHogRestore', HH^.Gear^.Uid)
+end;
+
procedure RestoreTeamsFromSave;
var t: LongInt;
begin
@@ -511,7 +523,7 @@
if Gear <> nil then
begin
- Gear^.Invulnerable:= false;
+ Gear^.Hedgehog^.Effects[heInvulnerable]:= 0;
Gear^.Damage:= Gear^.Health;
Gear^.State:= (Gear^.State or gstHHGone) and (not gstHHDriven)
end
@@ -530,11 +542,11 @@
SplitBySpace(id, s);
SwitchCurrentHedgehog(@Hedgehogs[HedgehogsNumber]);
CurrentHedgehog^.BotLevel:= StrToInt(id);
+ CurrentHedgehog^.Team:= CurrentTeam;
Gear:= AddGear(0, 0, gtHedgehog, 0, _0, _0, 0);
SplitBySpace(s, id);
Gear^.Health:= StrToInt(s);
TryDo(Gear^.Health > 0, 'Invalid hedgehog health', true);
- Gear^.Hedgehog^.Team:= CurrentTeam;
if (GameFlags and gfSharedAmmo) <> 0 then
CurrentHedgehog^.AmmoStore:= Clan^.ClanIndex
else if (GameFlags and gfPerHogAmmo) <> 0 then
@@ -551,6 +563,17 @@
end
end;
+procedure loadTeamBinds(s: shortstring);
+var i: LongInt;
+begin
+ for i:= 1 to length(s) do
+ if s[i] in ['\', '/', ':'] then s[i]:= '_';
+
+ s:= cPathz[ptTeams] + '/' + s + '.hwt';
+
+ loadBinds('bind', s);
+end;
+
procedure chAddTeam(var s: shortstring);
var Color: Longword;
ts, cs: shortstring;
@@ -569,6 +592,8 @@
AddTeam(Color);
CurrentTeam^.TeamName:= ts;
CurrentTeam^.PlayerHash:= s;
+ loadTeamBinds(ts);
+
if GameType in [gmtDemo, gmtSave, gmtRecord] then
CurrentTeam^.ExtDriven:= true;
@@ -591,33 +616,11 @@
end;
procedure chBind(var id: shortstring);
-var KeyName, Modifier, tmp: shortstring;
- b: LongInt;
begin
-KeyName:= '';
-Modifier:= '';
-
-if CurrentTeam = nil then
- exit;
+ if CurrentTeam = nil then
+ exit;
-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
- CurrentTeam^.Binds[b]:= KeyName;
+ addBind(CurrentTeam^.Binds, id)
end;
procedure chTeamGone(var s:shortstring);
@@ -671,11 +674,67 @@
CurrentHedgehog:= newHog;
if (CurrentHedgehog <> nil) and (CurrentHedgehog^.CurAmmoType = amKnife) then
LoadHedgehogHat(CurrentHedgehog^, 'Reserved/chef');
- if oldCI then AddGearCI(oldHH^.Gear);
- if newCI then AddGearCI(newHog^.Gear)
+ if oldCI then AddCI(oldHH^.Gear);
+ if newCI then AddCI(newHog^.Gear)
end;
+procedure chSetHat(var s: shortstring);
+begin
+if (not isDeveloperMode) or (CurrentTeam = nil) then exit;
+with CurrentTeam^ do
+ begin
+ if not CurrentHedgehog^.King then
+ if (s = '')
+ or (((GameFlags and gfKing) <> 0) and (s = 'crown'))
+ or ((Length(s) > 39) and (Copy(s,1,8) = 'Reserved') and (Copy(s,9,32) <> PlayerHash)) then
+ CurrentHedgehog^.Hat:= 'NoHat'
+ else
+ CurrentHedgehog^.Hat:= s
+ end;
+end;
+
+procedure chGrave(var s: shortstring);
+begin
+ if CurrentTeam = nil then
+ OutError(errmsgIncorrectUse + ' "/grave"', true);
+ if s[1]='"' then
+ Delete(s, 1, 1);
+ if s[byte(s[0])]='"' then
+ Delete(s, byte(s[0]), 1);
+ CurrentTeam^.GraveName:= s
+end;
+
+procedure chFort(var s: shortstring);
+begin
+ if CurrentTeam = nil then
+ OutError(errmsgIncorrectUse + ' "/fort"', true);
+ if s[1]='"' then
+ Delete(s, 1, 1);
+ if s[byte(s[0])]='"' then
+ Delete(s, byte(s[0]), 1);
+ CurrentTeam^.FortName:= s
+end;
+
+procedure chFlag(var s: shortstring);
+begin
+ if CurrentTeam = nil then
+ OutError(errmsgIncorrectUse + ' "/flag"', true);
+ if s[1]='"' then
+ Delete(s, 1, 1);
+ if s[byte(s[0])]='"' then
+ Delete(s, byte(s[0]), 1);
+ CurrentTeam^.flag:= s
+end;
+
+procedure chOwner(var s: shortstring);
+begin
+ if CurrentTeam = nil then
+ OutError(errmsgIncorrectUse + ' "/owner"', true);
+
+ CurrentTeam^.Owner:= s
+end;
+
procedure initModule;
begin
RegisterVariable('addhh', @chAddHH, false);
@@ -684,6 +743,11 @@
RegisterVariable('bind', @chBind, true );
RegisterVariable('teamgone', @chTeamGone, true );
RegisterVariable('finish', @chFinish, true ); // all teams gone
+RegisterVariable('fort' , @chFort , false);
+RegisterVariable('grave' , @chGrave , false);
+RegisterVariable('hat' , @chSetHat , false);
+RegisterVariable('flag' , @chFlag , false);
+RegisterVariable('owner' , @chOwner , false);
CurrentTeam:= nil;
PreviousTeam:= nil;
@@ -706,12 +770,31 @@
for i:= 0 to Pred(TeamsCount) do
begin
for h:= 0 to cMaxHHIndex do
- if TeamsArray[i]^.Hedgehogs[h].GearHidden <> nil then
- Dispose(TeamsArray[i]^.Hedgehogs[h].GearHidden);
+ with TeamsArray[i]^.Hedgehogs[h] do
+ begin
+ if GearHidden <> nil then
+ Dispose(GearHidden);
+
+ FreeTexture(NameTagTex);
+ FreeTexture(HealthTagTex);
+ FreeTexture(HatTex);
+ end;
+
+ with TeamsArray[i]^ do
+ begin
+ FreeTexture(NameTagTex);
+ FreeTexture(GraveTex);
+ FreeTexture(AIKillsTex);
+ FreeTexture(FlagTex);
+ end;
+
Dispose(TeamsArray[i]);
end;
-for i:= 0 to Pred(ClansCount) do
- Dispose(ClansArray[i]);
+ for i:= 0 to Pred(ClansCount) do
+ begin
+ FreeTexture(ClansArray[i]^.HealthTex);
+ Dispose(ClansArray[i]);
+ end
end;
TeamsCount:= 0;
ClansCount:= 0;
diff -Nru hedgewars-0.9.19.3/hedgewars/uTextures.pas hedgewars-0.9.20.5/hedgewars/uTextures.pas
--- hedgewars-0.9.19.3/hedgewars/uTextures.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uTextures.pas 2013-10-31 20:21:56.000000000 +0000
@@ -26,6 +26,7 @@
procedure Surface2GrayScale(surf: PSDL_Surface);
function Surface2Tex(surf: PSDL_Surface; enableClamp: boolean): PTexture;
procedure FreeTexture(tex: PTexture);
+procedure FreeAndNilTexture(var tex: PTexture);
procedure initModule;
procedure freeModule;
@@ -226,6 +227,12 @@
end
end;
+procedure FreeAndNilTexture(var tex: PTexture);
+begin
+ FreeTexture(tex);
+ tex:= nil
+end;
+
procedure initModule;
begin
TextureList:= nil;
diff -Nru hedgewars-0.9.19.3/hedgewars/uTouch.pas hedgewars-0.9.20.5/hedgewars/uTouch.pas
--- hedgewars-0.9.19.3/hedgewars/uTouch.pas 2013-06-03 08:01:41.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uTouch.pas 2014-01-08 16:25:17.000000000 +0000
@@ -31,16 +31,17 @@
procedure ProcessTouch;
procedure NewTurnBeginning;
-procedure onTouchDown(x,y: Longword; pointerId: TSDL_FingerId);
-procedure onTouchMotion(x,y: Longword; dx,dy: LongInt; pointerId: TSDL_FingerId);
-procedure onTouchUp(x,y: Longword; pointerId: TSDL_FingerId);
+procedure onTouchDown(x, y: Single; pointerId: TSDL_FingerId);
+procedure onTouchMotion(x, y, dx, dy: Single; pointerId: TSDL_FingerId);
+procedure onTouchUp(x, y: Single; pointerId: TSDL_FingerId);
+
function convertToCursorX(x: LongInt): LongInt;
function convertToCursorY(y: LongInt): LongInt;
-function convertToCursorDeltaX(x: LongInt): LongInt;
-function convertToCursorDeltaY(y: LongInt): LongInt;
+
function addFinger(x,y: Longword; id: TSDL_FingerId): PTouch_Data;
function updateFinger(x,y,dx,dy: Longword; id: TSDL_FingerId): PTouch_Data;
procedure deleteFinger(id: TSDL_FingerId);
+
procedure onTouchClick(finger: TTouch_Data);
procedure onTouchDoubleClick(finger: TTouch_Data);
procedure onTouchLongClick(finger: TTouch_Data);
@@ -62,7 +63,6 @@
const
clickTime = 200;
- nilFingerId = High(TSDL_FingerId);
baseRectSize = 96;
var
@@ -76,24 +76,27 @@
xTouchClick,yTouchClick : LongInt;
timeSinceClick : Longword;
- //Pinch to zoom
+ //Pinch to zoom
pinchSize : LongInt;
baseZoomValue: GLFloat;
//aiming
aimingCrosshair: boolean;
- aimingUp, aimingDown: boolean;
+ aimingUp, aimingDown: boolean;
targetAngle: LongInt;
buttonsDown: Longword;
targetting, targetted: boolean; //true when targetting an airstrike or the like
-procedure onTouchDown(x,y: Longword; pointerId: TSDL_FingerId);
-var
+procedure onTouchDown(x, y: Single; pointerId: TSDL_FingerId);
+var
finger: PTouch_Data;
+ xr, yr: LongWord;
begin
-{$IFDEF USE_TOUCH_INTERFACE}
-finger := addFinger(x,y,pointerId);
+xr:= round(x * cScreenWidth);
+yr:= round(y * cScreenHeight);
+
+finger:= addFinger(xr, yr, pointerId);
inc(buttonsDown);//inc buttonsDown, if we don't see a button down we'll dec it
@@ -161,7 +164,7 @@
ParseTeamCommand('/timer ' + inttostr((GetCurAmmoEntry(CurrentHedgeHog^)^.Timer div 1000) mod 5 + 1));
end;
exit;
- end;
+ end;
dec(buttonsDown);//no buttonsDown, undo the inc() above
if buttonsDown = 0 then
begin
@@ -177,15 +180,22 @@
end;
end;
end;
-{$ENDIF}
end;
-procedure onTouchMotion(x,y: Longword;dx,dy: LongInt; pointerId: TSDL_FingerId);
+procedure onTouchMotion(x, y, dx, dy: Single; pointerId: TSDL_FingerId);
var
finger, secondFinger: PTouch_Data;
- currentPinchDelta, zoom : single;
+ currentPinchDelta, zoom : Single;
+ xr, yr, dxr, dyr: LongWord;
begin
-finger:= updateFinger(x,y,dx,dy,pointerId);
+xr:= round(x * cScreenWidth);
+yr:= round(y * cScreenHeight);
+dxr:= round(dx * cScreenWidth);
+dyr:= round(dy * cScreenHeight);
+
+finger:= updateFinger(xr, yr, dxr, dyr, pointerId);
+if finger = nil then
+ exit;
if moveCursor then
begin
@@ -201,8 +211,8 @@
end;
exit //todo change into switch rather than ugly ifs
end;
-
-if aimingCrosshair then
+
+if aimingCrosshair then
begin
aim(finger^);
exit
@@ -222,22 +232,26 @@
end;
-procedure onTouchUp(x,y: Longword; pointerId: TSDL_FingerId);
+procedure onTouchUp(x,y: Single; pointerId: TSDL_FingerId);
var
finger: PTouch_Data;
widget: POnScreenWidget;
+ xr, yr: LongWord;
begin
-{$IFDEF USE_TOUCH_INTERFACE}
-x := x;
-y := y;
-finger:= updateFinger(x,y,0,0,pointerId);
+xr:= round(x * cScreenWidth);
+yr:= round(y * cScreenHeight);
+
+finger:= updateFinger(xr, yr, 0, 0, pointerId);
+if finger = nil then
+ exit;
+
//Check for onTouchClick event
if not(fingerHasMoved(finger^)) then
begin
if (RealTicks - finger^.timeSinceDown) < clickTime then
onTouchClick(finger^)
else
- onTouchLongClick(finger^);
+ onTouchLongClick(finger^);
end;
if aimingCrosshair then
@@ -252,10 +266,10 @@
if (buttonsDown > 0) and (widget <> nil) then
begin
dec(buttonsDown);
-
+
if widget = @arrowLeft then
ParseTeamCommand('-left');
-
+
if widget = @arrowRight then
ParseTeamCommand('-right');
@@ -267,7 +281,7 @@
if widget = @fireButton then
ParseTeamCommand('-attack');
-
+
if widget = @utilityWidget then
if (CurrentHedgehog <> nil)then
if(Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0)then
@@ -279,12 +293,11 @@
ParseTeamCommand('switch')
else WriteLnToConsole(inttostr(ord(Ammoz[CurrentHedgehog^.CurAmmoType].NameId)) + ' ' + inttostr(ord(sidSwitch)));
end;
-
+
if targetting then
AddCaption('Press the target button to mark the target', cWhiteColor, capgrpAmmoInfo);
-
+
deleteFinger(pointerId);
-{$ENDIF}
end;
procedure onTouchDoubleClick(finger: TTouch_Data);
@@ -294,14 +307,11 @@
procedure onTouchLongClick(finger: TTouch_Data);
begin
-{$IFDEF USE_TOUCH_INTERFACE}
if isOnWidget(jumpWidget, finger) then
begin
ParseTeamCommand('ljump');
exit;
end;
-
-{$ENDIF}
end;
procedure onTouchClick(finger: TTouch_Data);
@@ -309,8 +319,8 @@
//if (RealTicks - timeSinceClick < 300) and (sqrt(sqr(finger.X-xTouchClick) + sqr(finger.Y-yTouchClick)) < 30) then
// begin
// onTouchDoubleClick(finger);
-// timeSinceClick:= 0;//we make an assumption there won't be an 'click' in the first 300 ticks(milliseconds)
-// exit;
+// timeSinceClick:= 0;//we make an assumption there won't be an 'click' in the first 300 ticks(milliseconds)
+// exit;
// end;
xTouchClick:= finger.x;
@@ -318,19 +328,18 @@
timeSinceClick:= RealTicks;
if bShowAmmoMenu then
- begin
+ begin
if isOnRect(AmmoRect, finger) then
begin
CursorPoint.X:= finger.x;
CursorPoint.Y:= finger.y;
- ParseTeamCommand('put');
+ ParseTeamCommand('put');
end
else
bShowAmmoMenu:= false;
exit;
end;
-{$IFDEF USE_TOUCH_INTERFACE}
if isOnCurrentHog(finger) or isOnWidget(AMWidget, finger) then
begin
bShowAmmoMenu := true;
@@ -339,28 +348,25 @@
if isOnWidget(jumpWidget, finger) then
begin
- ParseTeamCommand('hjump');
+ ParseTeamCommand('hjump');
exit;
end;
-{$ENDIF}
end;
function addFinger(x,y: Longword; id: TSDL_FingerId): PTouch_Data;
-var
+var
xCursor, yCursor, index : LongInt;
begin
//Check array sizes
- if length(fingers) < Integer(pointerCount) then
+ if length(fingers) < pointerCount then
begin
- setLength(fingers, length(fingers)*2);
- for index := length(fingers) div 2 to length(fingers) do
- fingers[index].id := nilFingerId;
+ setLength(fingers, pointerCount * 2);
+ WriteLnToConsole('allocated ' + inttostr(length(fingers)) + ' finger elements');
end;
-
-
+
xCursor := convertToCursorX(x);
yCursor := convertToCursorY(y);
-
+
//on removing fingers, all fingers are moved to the left
//with dynamic arrays being zero based, the new position of the finger is the old pointerCount
fingers[pointerCount].id := id;
@@ -372,46 +378,53 @@
fingers[pointerCount].dy := 0;
fingers[pointerCount].timeSinceDown:= RealTicks;
fingers[pointerCount].pressedWidget:= nil;
-
+
addFinger:= @fingers[pointerCount];
inc(pointerCount);
end;
-function updateFinger(x,y,dx,dy: Longword; id: TSDL_FingerId): PTouch_Data;
+function updateFinger(x, y, dx, dy: Longword; id: TSDL_FingerId): PTouch_Data;
+var finger : PTouch_Data;
begin
- updateFinger:= findFinger(id);
+ finger:= findFinger(id);
- updateFinger^.x:= convertToCursorX(x);
- updateFinger^.y:= convertToCursorY(y);
- updateFinger^.dx:= convertToCursorDeltaX(dx);
- updateFinger^.dy:= convertToCursorDeltaY(dy);
+ if finger <> nil then
+ begin
+ finger^.x:= convertToCursorX(x);
+ finger^.y:= convertToCursorY(y);
+ finger^.dx:= dx;
+ finger^.dy:= dy;
+ end
+ else
+ WriteLnToConsole('finger ' + inttostr(id) + ' not found');
+ updateFinger:= finger
end;
procedure deleteFinger(id: TSDL_FingerId);
var
index : Longword;
begin
-
+
dec(pointerCount);
for index := 0 to pointerCount do
begin
if fingers[index].id = id then
begin
-
- //put the last finger into the spot of the finger to be removed,
+
+ //put the last finger into the spot of the finger to be removed,
//so that all fingers are packed to the far left
if pointerCount <> index then
begin
- fingers[index].id := fingers[pointerCount].id;
- fingers[index].x := fingers[pointerCount].x;
- fingers[index].y := fingers[pointerCount].y;
- fingers[index].historicalX := fingers[pointerCount].historicalX;
- fingers[index].historicalY := fingers[pointerCount].historicalY;
+ fingers[index].id := fingers[pointerCount].id;
+ fingers[index].x := fingers[pointerCount].x;
+ fingers[index].y := fingers[pointerCount].y;
+ fingers[index].historicalX := fingers[pointerCount].historicalX;
+ fingers[index].historicalY := fingers[pointerCount].historicalY;
fingers[index].timeSinceDown := fingers[pointerCount].timeSinceDown;
- fingers[pointerCount].id := nilFingerId;
+ fingers[pointerCount].id := 0;
end
- else fingers[index].id := nilFingerId;
+ else fingers[index].id := 0;
break;
end;
end;
@@ -430,12 +443,12 @@
var
deltaAngle: LongInt;
begin
-invertCursor := not(bShowAmmoMenu or targetting);
+invertCursor := not(bShowAmmoMenu or targetting);
if aimingCrosshair then
if CurrentHedgehog^.Gear <> nil then
begin
deltaAngle:= CurrentHedgehog^.Gear^.Angle - targetAngle;
- if (deltaAngle > -5) and (deltaAngle < 5) then
+ if (deltaAngle > -5) and (deltaAngle < 5) then
begin
if(aimingUp)then
begin
@@ -475,10 +488,10 @@
aimingUp:= true;
ParseTeamCommand('+up');
end;
- end;
+ end;
end;
end
- else
+ else
begin
if aimingUp then
begin
@@ -497,16 +510,17 @@
var
index: LongWord;
begin
- for index := 0 to High(fingers) do
- if fingers[index].id = id then
+ for index:= 0 to length(fingers) do
+ if fingers[index].id = id then
begin
- findFinger := @fingers[index];
- break;
+ findFinger:= @fingers[index];
+ exit;
end;
+ findFinger:= nil;
end;
procedure aim(finger: TTouch_Data);
-var
+var
hogX, hogY, touchX, touchY, deltaX, deltaY: LongInt;
begin
if CurrentHedgehog^.Gear <> nil then
@@ -519,70 +533,55 @@
convertToWorldCoord(touchX, touchY, finger);
deltaX := abs(TouchX-HogX);
deltaY := TouchY-HogY;
-
+
targetAngle:= (Round(DeltaY / sqrt(sqr(deltaX) + sqr(deltaY)) * 2048) + 2048) div 2;
end; //if CurrentHedgehog^.Gear <> nil
end;
// These 4 convertToCursor functions convert xy coords from the SDL coordinate system to our CursorPoint coor system:
-// - the SDL coordinate system goes from 0 to 32768 on the x axis and 0 to 32768 on the y axis, (0,0) being top left;
+// - the SDL coordinate system is proportional to the screen and values are normalized in the onTouch* functions
// - the CursorPoint coordinate system goes from -cScreenWidth/2 to cScreenWidth/2 on the x axis
// and 0 to cScreenHeight on the x axis, (-cScreenWidth, cScreenHeight) being top left.
function convertToCursorX(x: LongInt): LongInt;
begin
- convertToCursorX := round((x/32768)*cScreenWidth) - (cScreenWidth shr 1);
+ convertToCursorX:= x - cScreenWidth shr 1;
end;
function convertToCursorY(y: LongInt): LongInt;
begin
- convertToCursorY := cScreenHeight - round((y/32768)*cScreenHeight)
-end;
-
-function convertToCursorDeltaX(x: LongInt): LongInt;
-begin
- convertToCursorDeltaX := round(x/32768*cScreenWidth)
-end;
-
-function convertToCursorDeltaY(y: LongInt): LongInt;
-begin
- convertToCursorDeltaY := round(y/32768*cScreenHeight)
+ convertToCursorY:= cScreenHeight - y;
end;
function isOnCrosshair(finger: TTouch_Data): boolean;
var
- x,y : LongInt;
+ x, y: LongInt;
begin
- x := 0;//avoid compiler hint
- y := 0;
+ x:= 0;
+ y:= 0;
convertToFingerCoord(x, y, CrosshairX, CrosshairY);
- isOnCrosshair:= isOnRect((x-HalfRectSize), (y-HalfRectSize), RectSize, RectSize, finger);
- printFinger(finger);
- WriteLnToConsole(inttostr(finger.x) + ' ' + inttostr(x));
- WriteLnToConsole(inttostr(x) + ' ' + inttostr(y) + ' ' + inttostr(round(mobileRecord.getScreenDPI() * 10)));
+ isOnCrosshair:= isOnRect(x - HalfRectSize, y - HalfRectSize, RectSize, RectSize, finger);
end;
function isOnCurrentHog(finger: TTouch_Data): boolean;
var
- x,y : LongInt;
+ x, y: LongInt;
begin
- x := 0;
- y := 0;
- convertToFingerCoord(x,y, hwRound(CurrentHedgehog^.Gear^.X), hwRound(CurrentHedgehog^.Gear^.Y));
- isOnCurrentHog:= isOnRect((x-HalfRectSize), (y-HalfRectSize), RectSize, RectSize, finger);
+ x:= 0;
+ y:= 0;
+ convertToFingerCoord(x, y, hwRound(CurrentHedgehog^.Gear^.X), hwRound(CurrentHedgehog^.Gear^.Y));
+ isOnCurrentHog:= isOnRect(x - HalfRectSize, y - HalfRectSize, RectSize, RectSize, finger);
end;
-procedure convertToFingerCoord(var x,y : LongInt; oldX, oldY: LongInt);
+procedure convertToFingerCoord(var x, y : LongInt; oldX, oldY: LongInt);
begin
x := oldX + WorldDx;
- y := cScreenHeight - (oldY + WorldDy);
+ y := cScreenHeight - oldY - WorldDy;
end;
procedure convertToWorldCoord(var x,y: LongInt; finger: TTouch_Data);
begin
-//if x <> nil then
- x := finger.x-WorldDx;
-//if y <> nil then
- y := (cScreenHeight - finger.y)-WorldDy;
+ x := finger.x - WorldDx;
+ y := cScreenHeight - finger.y - WorldDy;
end;
//Method to calculate the distance this finger has moved since the downEvent
@@ -626,7 +625,8 @@
procedure printFinger(finger: TTouch_Data);
begin
- WriteToConsole(Format('id:%d, (%d,%d), (%d,%d), time: %d', [finger.id, finger.x, finger.y, finger.historicalX, finger.historicalY, finger.timeSinceDown]));
+ WriteLnToConsole(Format('id: %d, x: %d y: %d (rel x: %d rel y: %d), time: %d',
+ [finger.id, finger.x, finger.y, finger.historicalX, finger.historicalY, finger.timeSinceDown]));
end;
procedure initModule;
@@ -635,13 +635,14 @@
//uRenderCoordScaleX, uRenderCoordScaleY: Longword;
begin
buttonsDown:= 0;
+ pointerCount:= 0;
setLength(fingers, 4);
- for index := 0 to High(fingers) do
- fingers[index].id := nilFingerId;
+ for index := 0 to length(fingers) do
+ fingers[index].id := 0;
- rectSize:= round(baseRectSize * mobileRecord.getScreenDPI());
- halfRectSize:= rectSize shl 1;
+ rectSize:= baseRectSize;
+ halfRectSize:= baseRectSize shr 1;
end;
procedure freeModule;
diff -Nru hedgewars-0.9.19.3/hedgewars/uTypes.pas hedgewars-0.9.20.5/hedgewars/uTypes.pas
--- hedgewars-0.9.19.3/hedgewars/uTypes.pas 2013-06-11 07:26:50.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uTypes.pas 2014-01-08 16:25:17.000000000 +0000
@@ -86,7 +86,7 @@
sprHandResurrector, sprCross, sprAirDrill, sprNapalmBomb,
sprBulletHit, sprSnowball, sprHandSnowball, sprSnow,
sprSDFlake, sprSDWater, sprSDCloud, sprSDSplash, sprSDDroplet, sprTardis,
- sprSlider, sprBotlevels, sprHandKnife, sprKnife, sprStar, sprIceTexture, sprIceGun, sprFrozenHog
+ sprSlider, sprBotlevels, sprHandKnife, sprKnife, sprStar, sprIceTexture, sprIceGun, sprFrozenHog, sprAmRubber, sprBoing
);
// Gears that interact with other Gears and/or Land
@@ -152,7 +152,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, amRubber); // 56
// Different kind of crates that e.g. hedgehogs can pick up
TCrateType = (HealthCrate, AmmoCrate, UtilityCrate);
@@ -164,13 +164,16 @@
TStatInfoType = (siGameResult, siMaxStepDamage, siMaxStepKills, siKilledHHs,
siClanHealth, siTeamStats, siPlayerKills, siMaxTeamDamage,
- siMaxTeamKills, siMaxTurnSkips );
+ siMaxTeamKills, siMaxTurnSkips, siCustomAchievement, siGraphTitle,
+ siPointType);
// Various "emote" animations a hedgehog can do
TWave = (waveRollup, waveSad, waveWave, waveHurrah, waveLemonade, waveShrug, waveJuggle);
TRenderMode = (rmDefault, rmLeftEye, rmRightEye);
TStereoMode = (smNone, smRedCyan, smCyanRed, smRedBlue, smBlueRed, smRedGreen, smGreenRed, smHorizontal, smVertical);
+ TWorldEdge = (weNone, weWrap, weBounce, weSea, weSky);
+ TUIDisplay = (uiAll, uiNoTeams, uiNone);
THHFont = record
Handle: PTTF_Font;
@@ -255,7 +258,6 @@
ImpactSound: TSound; // first sound, others have to be after it in the sounds def.
nImpactSounds: Word; // count of ImpactSounds.
// Don't use these if you want to take damage normally, otherwise health/damage are commonly used for other purposes
- Invulnerable: Boolean;
Health, Damage, Karma: LongInt;
// DirAngle is a "real" - if you don't need it for rotation of sprite in uGearsRender, you can use it for any visual-only value
DirAngle: real;
@@ -367,6 +369,7 @@
King: boolean; // Flag for a bunch of hedgehog attributes
Unplaced: boolean; // Flag for hog placing mode
Timer: Longword;
+ HealthBarHealth: LongInt;
Effects: array[THogEffect] of LongInt;
end;
@@ -377,18 +380,17 @@
Binds: TBinds;
Hedgehogs: array[0..cMaxHHIndex] of THedgehog;
CurrHedgehog: LongWord;
- NameTagTex: PTexture;
- CrosshairTex,
+ NameTagTex,
+ OwnerTex: PTexture;
GraveTex,
- HealthTex,
AIKillsTex,
FlagTex: PTexture;
Flag: shortstring;
GraveName: shortstring;
FortName: shortstring;
+ Owner: shortstring;
TeamHealth: LongInt;
- TeamHealthBarWidth,
- NewTeamHealthBarWidth: LongInt;
+ TeamHealthBarHealth: LongInt;
DrawHealthY: LongInt;
AttackBar: LongWord;
HedgehogsNumber: Longword;
@@ -401,6 +403,7 @@
TClan = record
Color: Longword;
Teams: array[0..Pred(cMaxTeams)] of PTeam;
+ HealthTex: PTexture;
TeamsNumber: Longword;
TagTeamIndex: Longword;
CurrTeam: LongWord;
@@ -412,10 +415,8 @@
cdeclPtr = procedure; cdecl;
cdeclIntPtr = procedure(num: LongInt); cdecl;
- functionDoublePtr = function: Double;
TMobileRecord = record
- getScreenDPI: functionDoublePtr;
PerformRumble: cdeclIntPtr;
GameLoading: cdeclPtr;
GameLoaded: cdeclPtr;
@@ -434,13 +435,13 @@
sidMolotov, sidBirdy, sidPortalGun, sidPiano, sidGasBomb,
sidSineGun, sidFlamethrower,sidSMine, sidHammer, sidResurrector,
sidDrillStrike, sidSnowball, sidNothing, sidTardis,
- {sidStructure,} sidLandGun, sidIceGun, sidKnife);
+ {sidStructure,} sidLandGun, sidIceGun, sidKnife, sidRubber);
TMsgStrId = (sidStartFight, sidDraw, sidWinner, sidVolume, sidPaused,
sidConfirm, sidSuddenDeath, sidRemaining, sidFuel, sidSync,
sidNoEndTurn, sidNotYetAvailable, sidRoundSD, sidRoundsSD, sidReady,
sidBounce1, sidBounce2, sidBounce3, sidBounce4, sidBounce5, sidBounce,
- sidMute);
+ sidMute, sidAFK);
// Events that are important for the course of the game or at least interesting for other reasons
TEventId = (eidDied, eidDrowned, eidRoundStart, eidRoundWin, eidRoundDraw,
@@ -468,15 +469,15 @@
POnScreenWidget = ^TOnScreenWidget;
TOnScreenWidget = record
- show : boolean; // if false widget will not be drawn
- sprite : TSprite; // a convenience type
- frame : TSDL_Rect; // graphical coordinates
- active : TSDL_Rect; // active touch region
- fadeAnimStart : Longword; // time the fade started, 0 means don't fade
- moveAnim : TWidgetMovement; // the animation associated to the widget
+ show : boolean; // if false widget will not be drawn
+ sprite : TSprite; // a convenience type
+ frame : TSDL_Rect; // graphical coordinates
+ active : TSDL_Rect; // active touch region
+ fadeAnimStart : Longword; // time the fade started
+ // (0 means do not fade)
+ moveAnim : TWidgetMovement; // animation associated to widget
end;
-{$IFDEF SDL13}
PTouch_Data = ^TTouch_Data;
TTouch_Data = record
id : TSDL_FingerId;
@@ -486,7 +487,6 @@
timeSinceDown : Longword;
pressedWidget : POnScreenWidget;
end;
-{$ENDIF}
implementation
diff -Nru hedgewars-0.9.19.3/hedgewars/uUtils.pas hedgewars-0.9.20.5/hedgewars/uUtils.pas
--- hedgewars-0.9.19.3/hedgewars/uUtils.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uUtils.pas 2014-01-08 16:25:17.000000000 +0000
@@ -21,7 +21,7 @@
unit uUtils;
interface
-uses uTypes, uFloat, GLunit;
+uses uTypes, uFloat;
procedure SplitBySpace(var a, b: shortstring);
procedure SplitByChar(var a, b: shortstring; c: char);
@@ -31,6 +31,7 @@
function EnumToStr(const en : TVisualGearType) : shortstring; overload;
function EnumToStr(const en : TSound) : shortstring; overload;
function EnumToStr(const en : TAmmoType) : shortstring; overload;
+function EnumToStr(const en : TStatInfoType) : shortstring; overload;
function EnumToStr(const en : THogEffect) : shortstring; overload;
function EnumToStr(const en : TCapGroup) : shortstring; overload;
@@ -41,7 +42,7 @@
function StrToInt(s: shortstring): LongInt;
function FloatToStr(n: hwFloat): shortstring;
-function DxDy2Angle(const _dY, _dX: hwFloat): GLfloat; inline;
+function DxDy2Angle(const _dY, _dX: hwFloat): real; inline;
function DxDy2Angle32(const _dY, _dX: hwFloat): LongInt;
function DxDy2AttackAngle(const _dY, _dX: hwFloat): LongInt;
function DxDy2AttackAnglef(const _dY, _dX: extended): LongInt;
@@ -70,7 +71,6 @@
procedure WriteLn(var f: textfile; s: shortstring);
function isPhone: Boolean; inline;
-function getScreenDPI: Double; inline; //cdecl; external;
{$IFDEF IPHONEOS}
procedure startLoadingIndicator; cdecl; external;
@@ -151,6 +151,11 @@
EnumToStr:= GetEnumName(TypeInfo(TAmmoType), ord(en))
end;
+function EnumToStr(const en : TStatInfoType) : shortstring; overload;
+begin
+EnumToStr:= GetEnumName(TypeInfo(TStatInfoType), ord(en))
+end;
+
function EnumToStr(const en: THogEffect) : shortstring; overload;
begin
EnumToStr := GetEnumName(TypeInfo(THogEffect), ord(en))
@@ -200,7 +205,7 @@
end;
-function DxDy2Angle(const _dY, _dX: hwFloat): GLfloat; inline;
+function DxDy2Angle(const _dY, _dX: hwFloat): real; inline;
var dY, dX: Extended;
begin
dY:= hwFloat2Float(_dY);
@@ -428,16 +433,6 @@
{$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;
@@ -505,6 +500,19 @@
{$I+}
{$ENDIF}
+ //mobile stuff
+{$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 -Nru hedgewars-0.9.19.3/hedgewars/uVariables.pas hedgewars-0.9.20.5/hedgewars/uVariables.pas
--- hedgewars-0.9.19.3/hedgewars/uVariables.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uVariables.pas 2014-01-08 16:25:17.000000000 +0000
@@ -21,7 +21,7 @@
unit uVariables;
interface
-uses SDLh, uTypes, uFloat, GLunit, uConsts, Math, uUtils;
+uses SDLh, uTypes, uFloat, GLunit, uConsts, Math;
var
/////// init flags ///////
@@ -46,6 +46,9 @@
cShowFPS : boolean;
cFlattenFlakes : boolean;
cFlattenClouds : boolean;
+ cIce : boolean;
+ cSnow : boolean;
+
cAltDamage : boolean;
cReducedQuality : LongWord;
UserNick : shortstring;
@@ -69,6 +72,7 @@
isPaused : boolean;
isInMultiShoot : boolean;
isSpeed : boolean;
+ isAFK : boolean;
SpeedStart : LongWord;
fastUntilLag : boolean;
@@ -82,7 +86,11 @@
GameType : TGameType;
InputMask : LongWord;
GameFlags : Longword;
+ WorldEdge : TWorldEdge;
+ LeftImpactTimer : LongWord;
+ RightImpactTimer: LongWord;
TurnTimeLeft : Longword;
+ TurnClockActive : boolean;
TagTurnTimeLeft : Longword;
ReadyTimeLeft : Longword;
cSuddenDTurns : LongInt;
@@ -127,6 +135,9 @@
LAND_WIDTH_MASK : LongWord;
LAND_HEIGHT_MASK : LongWord;
+ CrosshairTexture : PTexture;
+ GenericHealthTexture : PTexture;
+
cLeftScreenBorder : LongInt;
cRightScreenBorder : LongInt;
cScreenSpace : Longword;
@@ -153,6 +164,7 @@
cMaxWindSpeed : hwFloat;
cWindSpeed : hwFloat;
cWindSpeedf : real;
+ cElastic : hwFloat;
cGravity : hwFloat;
cGravityf : real;
cDamageModifier : hwFloat;
@@ -187,6 +199,9 @@
ScreenFadeValue : LongInt;
ScreenFadeSpeed : LongInt;
+ UIDisplay : TUIDisplay;
+ LocalMessage : LongWord;
+
Theme : shortstring;
disableLandBack : boolean;
@@ -438,7 +453,7 @@
(FileName: 'amKamikaze'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
Width: 128; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprKamikaze
(FileName: 'amWhip'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
- Width: 128; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprWhip
+ Width: 128; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprWhip
(FileName: 'Kowtow'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprKowtow
(FileName: 'Sad'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
@@ -667,7 +682,11 @@
(FileName: 'amIceGun'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
Width: 32; Height: 32; imageWidth: 32; imageHeight: 32; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprIceGun
(FileName: 'amFrozenHog'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
- Width: 64; Height: 64; imageWidth: 64; imageHeight: 64; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false) // sprFrozenHog
+ Width: 64; Height: 64; imageWidth: 64; imageHeight: 64; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprFrozenHog
+ (FileName: 'amRubber'; Path: ptCurrTheme; AltPath: ptGraphics; Texture: nil; Surface: nil;
+ Width: 160; Height:160; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpMedium; getDimensions: false; getImageDimensions: true), // sprAmRubber
+ (FileName: 'boing'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
+ Width: 101; Height: 97; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false) // sprBoing
);
const
@@ -841,7 +860,8 @@
Probability: 0;
NumberInCase: 1;
Ammo: (Propz: ammoprop_ForwMsgs or
- ammoprop_NeedUpDown;
+ ammoprop_NeedUpDown or
+ ammoprop_DoesntStopTimerInMultiShoot;
Count: AMMO_INFINITE;
NumPerTurn: 1;
Timer: 0;
@@ -892,7 +912,8 @@
NameTex: nil;
Probability: 0;
NumberInCase: 1;
- Ammo: (Propz: ammoprop_NoCrosshair or
+ Ammo: (Propz: ammoprop_NoCrosshair or
+ ammoprop_AttackInMove or
ammoprop_DontHold;
Count: AMMO_INFINITE;
NumPerTurn: 0;
@@ -922,7 +943,8 @@
ammoprop_AttackInMove or
ammoprop_Utility or
ammoprop_AltAttack or
- ammoprop_NeedUpDown;
+ ammoprop_NeedUpDown or
+ ammoprop_DoesntStopTimerWhileAttacking;
Count: 5;
NumPerTurn: 0;
Timer: 0;
@@ -974,7 +996,7 @@
NameTex: nil;
Probability: 20;
NumberInCase: 2;
- Ammo: (Propz: ammoprop_NeedUpDown;
+ Ammo: (Propz: ammoprop_NeedUpDown or ammoprop_DoesntStopTimerInMultiShoot;
Count: 3;
NumPerTurn: 3;
Timer: 0;
@@ -1736,9 +1758,10 @@
NameTex: nil;
Probability: 20;
NumberInCase: 2;
- Ammo: (Propz: ammoprop_NeedUpDown or
+ Ammo: (Propz: ammoprop_NeedUpDown or
ammoprop_OscAim or
- ammoprop_NoMoveAfter;
+ ammoprop_NoMoveAfter or
+ ammoprop_DoesntStopTimerInMultiShoot;
Count: 2;
NumPerTurn: 1;
Timer: 0;
@@ -1857,7 +1880,7 @@
AmmoType: amPortalGun;
AttackVoice: sndNone;
Bounciness: 1000);
- Slot: 6;
+ Slot: 7;
TimeAfterTurn: 0;
minAngle: 0;
maxAngle: 0;
@@ -2122,7 +2145,7 @@
AmmoType: amTardis;
AttackVoice: sndNone;
Bounciness: 1000);
- Slot: 7;
+ Slot: 8;
TimeAfterTurn: 0;
minAngle: 0;
maxAngle: 0;
@@ -2235,6 +2258,33 @@
PosCount: 1;
PosSprite: sprWater;
ejectX: 0;
+ ejectY: 0),
+// Rubber
+ (NameId: sidRubber;
+ NameTex: nil;
+ Probability: 150;
+ NumberInCase: 1;
+ Ammo: (Propz: ammoprop_NoRoundEnd or
+ ammoprop_NoCrosshair or
+ ammoprop_NeedTarget or
+ ammoprop_Utility or
+ ammoprop_AttackingPut;
+ Count: 1;
+ NumPerTurn: 0;
+ Timer: 0;
+ Pos: 0;
+ AmmoType: amRubber;
+ AttackVoice: sndNone;
+ Bounciness: 1000);
+ Slot: 6;
+ TimeAfterTurn: 3000;
+ minAngle: 0;
+ maxAngle: 0;
+ isDamaging: false;
+ SkipTurns: 0;
+ PosCount: 4;
+ PosSprite: sprAmRubber;
+ ejectX: 0;
ejectY: 0)
);
@@ -2287,6 +2337,7 @@
PauseTexture,
+ AFKTexture,
SyncTexture,
ConfirmTexture: PTexture;
cScaleFactor: GLfloat;
@@ -2324,7 +2375,7 @@
procedure freeModule;
implementation
-
+uses strutils;
procedure preInitModule;
begin
@@ -2366,13 +2417,14 @@
end;
procedure initModule;
-var s: ShortString;
begin
- cLocale:= cLocaleFName;
- SplitByChar(cLocale, s, '.');
+ // TODO: we could just have one cLocale variables and drop strutils
+ cLocale:= ExtractDelimited(1, cLocaleFName, StdWordDelims);
cFlattenFlakes := false;
cFlattenClouds := false;
+ cIce := false;
+ cSnow := false;
lastVisualGearByUID := nil;
lastGearByUID := nil;
cReadyDelay := 5000;
@@ -2415,11 +2467,12 @@
WaterOpacity:= $80;
- cDrownSpeed.QWordValue := 257698038; // 0.06
+ cDrownSpeed.QWordValue := 257698038; // 0.06
cDrownSpeedf := 0.06;
cMaxWindSpeed.QWordValue:= 1073742; // 0.00025
- cWindSpeed.QWordValue := 0; // 0.0
+ cWindSpeed.QWordValue := 0; // 0.0
cWindSpeedf := 0.0;
+ cElastic := _0_9;
cGravity := cMaxWindSpeed * 2;
cGravityf := 0.00025 * 2;
cDamageModifier := _1;
@@ -2447,7 +2500,11 @@
InputMask := $FFFFFFFF;
GameFlags := 0;
+ WorldEdge := weNone;
+ LeftImpactTimer := 0;
+ RightImpactTimer := 0;
TurnTimeLeft := 0;
+ TurnClockActive := true;
TagTurnTimeLeft := 0;
cSuddenDTurns := 15;
cDamagePercent := 100;
@@ -2466,7 +2523,6 @@
cWaterRise := 47;
cHealthDecrease := 5;
- cTagsMask := 0;
InitStepsFlags := 0;
RealTicks := 0;
AttackBar := 0; // 0 - none, 1 - just bar at the right-down corner, 2 - from weapon
@@ -2489,6 +2545,7 @@
isPaused := false;
isInMultiShoot := false;
isSpeed := false;
+ isAFK := false;
SpeedStart := 0;
fastUntilLag := false;
fastScrolling := false;
@@ -2539,18 +2596,8 @@
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}
+ UIDisplay:= uiAll;
+ LocalMessage:= 0;
end;
procedure freeModule;
diff -Nru hedgewars-0.9.19.3/hedgewars/uVideoRec.pas hedgewars-0.9.20.5/hedgewars/uVideoRec.pas
--- hedgewars-0.9.19.3/hedgewars/uVideoRec.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uVideoRec.pas 2014-01-04 19:46:00.000000000 +0000
@@ -28,9 +28,6 @@
{$ELSE}
{$IFNDEF WIN32}
- {$linklib avcodec}
- {$linklib avformat}
- {$linklib avutil}
{$linklib avwrapper}
{$ENDIF}
@@ -56,12 +53,12 @@
type TAddFileLogRaw = procedure (s: pchar); cdecl;
const AvwrapperLibName = 'libavwrapper';
-procedure AVWrapper_Init(
+function AVWrapper_Init(
AddLog: TAddFileLogRaw;
filename, desc, soundFile, format, vcodec, acodec: PChar;
- width, height, framerateNum, framerateDen, vquality: LongInt); cdecl; external AvwrapperLibName;
-procedure AVWrapper_Close; cdecl; external AvwrapperLibName;
-procedure AVWrapper_WriteFrame( pY, pCb, pCr: PByte ); cdecl; external AvwrapperLibName;
+ width, height, framerateNum, framerateDen, vquality: LongInt): LongInt; cdecl; external AvwrapperLibName;
+function AVWrapper_Close: LongInt; cdecl; external AvwrapperLibName;
+function AVWrapper_WriteFrame( pY, pCb, pCr: PByte ): LongInt; cdecl; external AvwrapperLibName;
type TFrame = record
realTicks: LongWord;
@@ -112,14 +109,15 @@
filename:= UserPathPrefix + '/VideoTemp/' + RecPrefix;
soundFilePath:= UserPathPrefix + '/VideoTemp/' + RecPrefix + '.sw';
- AVWrapper_Init(@AddFileLogRaw
+ if AVWrapper_Init(@AddFileLogRaw
, PChar(ansistring(filename))
, PChar(ansistring(desc))
, PChar(ansistring(soundFilePath))
, PChar(ansistring(cAVFormat))
, PChar(ansistring(cVideoCodec))
, PChar(ansistring(cAudioCodec))
- , cScreenWidth, cScreenHeight, cVideoFramerateNum, cVideoFramerateDen, cVideoQuality);
+ , cScreenWidth, cScreenHeight, cVideoFramerateNum, cVideoFramerateDen, cVideoQuality) < 0 then
+ halt(-1);
numPixels:= cScreenWidth*cScreenHeight;
YCbCr_Planes[0]:= GetMem(numPixels);
@@ -153,7 +151,8 @@
FreeMem(YCbCr_Planes[2], numPixels div 4);
FreeMem(RGB_Buffer, 4*numPixels);
Close(cameraFile);
- AVWrapper_Close();
+ if AVWrapper_Close() < 0 then
+ halt(-1);
Erase(cameraFile);
DeleteFile(soundFilePath);
SendIPC(_S'v'); // inform frontend that we finished
@@ -188,7 +187,8 @@
YCbCr_Planes[2][y*(cScreenWidth div 2) + x]:= Byte(128 + (( 7196*r - 6026*g - 1170*b) shr 16));
end;
- AVWrapper_WriteFrame(YCbCr_Planes[0], YCbCr_Planes[1], YCbCr_Planes[2]);
+ if AVWrapper_WriteFrame(YCbCr_Planes[0], YCbCr_Planes[1], YCbCr_Planes[2]) < 0 then
+ halt(-1);
// inform frontend that we have encoded new frame
s[0]:= #3;
@@ -370,6 +370,10 @@
procedure initModule;
begin
+ // we need to make sure these variables are initialized before the main loop
+ // or the wrapper will keep the default values of preinit
+ cScreenWidth:= max(cWindowedWidth, 640);
+ cScreenHeight:= max(cWindowedHeight, 480);
end;
procedure freeModule;
diff -Nru hedgewars-0.9.19.3/hedgewars/uVisualGears.pas hedgewars-0.9.20.5/hedgewars/uVisualGears.pas
--- hedgewars-0.9.19.3/hedgewars/uVisualGears.pas 2013-06-04 14:09:28.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uVisualGears.pas 2014-01-08 16:25:17.000000000 +0000
@@ -29,19 +29,13 @@
* E.g.: background flakes, visual effects: explosion, smoke trails, etc.
*)
interface
-uses uConsts, uFloat, GLunit, uTypes, uWorld;
+uses uConsts, GLunit, uTypes;
procedure initModule;
procedure freeModule;
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline;
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear;
-
procedure ProcessVisualGears(Steps: Longword);
procedure DrawVisualGears(Layer: LongWord);
-procedure DeleteVisualGear(Gear: PVisualGear);
-function VisualGearByUID(uid : Longword) : PVisualGear;
procedure AddClouds;
procedure AddFlakes;
@@ -53,17 +47,8 @@
procedure KickFlakes(Radius, X, Y: LongInt);
implementation
-uses uSound, uVariables, uTextures, uRender, Math, uRenderUtils, uStore, uUtils;
-
-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.
-{$INCLUDE "VGSHandlers.inc"}
+uses uVariables, uRender, Math, uRenderUtils, uStore, uUtils
+ , uVisualGearsList;
procedure AddDamageTag(X, Y, Damage, Color: LongWord);
var s: shortstring;
@@ -84,436 +69,6 @@
// ==================================================================
-// ==================================================================
-const doStepHandlers: array[TVisualGearType] of TVGearStepProcedure =
- (
- @doStepFlake,
- @doStepCloud,
- @doStepExpl,
- @doStepExpl,
- @doStepFire,
- @doStepSmallDamage,
- @doStepTeamHealthSorter,
- @doStepSpeechBubble,
- @doStepBubble,
- @doStepSteam,
- @doStepAmmo,
- @doStepSmoke,
- @doStepSmoke,
- @doStepShell,
- @doStepDust,
- @doStepSplash,
- @doStepDroplet,
- @doStepSmokeRing,
- @doStepBeeTrace,
- @doStepEgg,
- @doStepFeather,
- @doStepHealthTag,
- @doStepSmokeTrace,
- @doStepSmokeTrace,
- @doStepExplosion,
- @doStepBigExplosion,
- @doStepChunk,
- @doStepNote,
- @doStepLineTrail,
- @doStepBulletHit,
- @doStepCircle,
- @doStepSmoothWindBar,
- @doStepStraightShot
- );
-
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
-begin
- AddVisualGear:= AddVisualGear(X, Y, Kind, 0, false);
-end;
-
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline;
-begin
- AddVisualGear:= AddVisualGear(X, Y, Kind, State, false);
-end;
-
-function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear;
-var gear: PVisualGear;
- t: Longword;
- sp: real;
-begin
-AddVisualGear:= nil;
-if ((GameType = gmtSave) or (fastUntilLag and (GameType = gmtNet)) or fastScrolling) and // we are scrolling now
- ((Kind <> vgtCloud) and (not Critical)) then
- exit;
-
-if ((cReducedQuality and rqAntiBoom) <> 0) and
- (not Critical) and
- (not (Kind in
- [vgtTeamHealthSorter,
- vgtSmallDamageTag,
- vgtSpeechBubble,
- vgtHealthTag,
- vgtExplosion,
- vgtSmokeTrace,
- vgtEvilTrace,
- vgtNote,
- vgtSmoothWindBar])) then
-
- exit;
-
-inc(VGCounter);
-New(gear);
-FillChar(gear^, sizeof(TVisualGear), 0);
-gear^.X:= real(X);
-gear^.Y:= real(Y);
-gear^.Kind := Kind;
-gear^.doStep:= doStepHandlers[Kind];
-gear^.State:= 0;
-gear^.Tint:= $FFFFFFFF;
-gear^.uid:= VGCounter;
-gear^.Layer:= 0;
-
-with gear^ do
- case Kind of
- vgtFlake:
- begin
- Timer:= 0;
- tdX:= 0;
- tdY:= 0;
- Scale:= 1.0;
- if SuddenDeathDmg then
- begin
- FrameTicks:= random(vobSDFrameTicks);
- Frame:= random(vobSDFramesCount);
- end
- else
- begin
- FrameTicks:= random(vobFrameTicks);
- Frame:= random(vobFramesCount);
- end;
- Angle:= random(360);
- dx:= 0.0000038654705 * random(10000);
- dy:= 0.000003506096 * random(7000);
- if random(2) = 0 then
- dx := -dx;
- if SuddenDeathDmg then
- dAngle:= (random(2) * 2 - 1) * (vobSDVelocity + random(vobSDVelocity)) / 1000
- else
- dAngle:= (random(2) * 2 - 1) * (vobVelocity + random(vobVelocity)) / 1000
- end;
- vgtCloud:
- begin
- Frame:= random(4);
- dx:= 0.5 + 0.1 * random(5); // how much the cloud will be affected by wind
- timer:= random(4096);
- Scale:= 1.0
- end;
- vgtExplPart,
- vgtExplPart2:
- begin
- t:= random(1024);
- sp:= 0.001 * (random(95) + 70);
- dx:= hwFloat2Float(AngleSin(t)) * sp;
- dy:= hwFloat2Float(AngleCos(t)) * sp;
- if random(2) = 0 then
- dx := -dx;
- if random(2) = 0 then
- dy := -dy;
- Frame:= 7 - random(3);
- FrameTicks:= cExplFrameTicks
- end;
- vgtFire:
- begin
- t:= random(1024);
- sp:= 0.001 * (random(85) + 95);
- dx:= hwFloat2Float(AngleSin(t)) * sp;
- dy:= hwFloat2Float(AngleCos(t)) * sp;
- if random(2) = 0 then
- dx := -dx;
- if random(2) = 0 then
- dy := -dy;
- FrameTicks:= 650 + random(250);
- Frame:= random(8)
- end;
- vgtEgg:
- begin
- t:= random(1024);
- sp:= 0.001 * (random(85) + 95);
- dx:= hwFloat2Float(AngleSin(t)) * sp;
- dy:= hwFloat2Float(AngleCos(t)) * sp;
- if random(2) = 0 then
- dx := -dx;
- if random(2) = 0 then
- dy := -dy;
- FrameTicks:= 650 + random(250);
- Frame:= 1
- end;
- vgtShell: FrameTicks:= 500;
- vgtSmallDamageTag:
- begin
- gear^.FrameTicks:= 1100
- end;
- vgtBubble:
- begin
- dx:= 0.0000038654705 * random(10000);
- dy:= 0;
- if random(2) = 0 then
- dx := -dx;
- FrameTicks:= 250 + random(1751);
- Frame:= random(5)
- end;
- vgtSteam:
- begin
- dx:= 0.0000038654705 * random(10000);
- dy:= 0.001 * (random(85) + 95);
- if random(2) = 0 then
- dx := -dx;
- Frame:= 7 - random(3);
- FrameTicks:= cExplFrameTicks * 2;
- end;
- vgtAmmo:
- begin
- alpha:= 1.0;
- scale:= 1.0
- end;
- vgtSmokeWhite,
- vgtSmoke:
- begin
- Scale:= 1.0;
- dx:= 0.0002 * (random(45) + 10);
- dy:= 0.0002 * (random(45) + 10);
- if random(2) = 0 then
- dx := -dx;
- Frame:= 7 - random(2);
- FrameTicks:= cExplFrameTicks * 2;
- end;
- vgtDust:
- begin
- dx:= 0.005 * (random(15) + 10);
- dy:= 0.001 * (random(40) + 20);
- if random(2) = 0 then dx := -dx;
- if random(2) = 0 then Tag:= 1
- else Tag:= -1;
- Frame:= 7 - random(2);
- FrameTicks:= random(20) + 15;
- end;
- vgtSplash:
- begin
- dx:= 0;
- dy:= 0;
- FrameTicks:= 740;
- Frame:= 19;
- Scale:= 0.75;
- Timer:= 1;
- end;
- vgtDroplet:
- begin
- dx:= 0.001 * (random(180) - 90);
- dy:= -0.001 * (random(160) + 40);
- FrameTicks:= 250 + random(1751);
- Frame:= random(3)
- end;
- vgtBeeTrace:
- begin
- FrameTicks:= 1000;
- Frame:= random(16);
- end;
- vgtSmokeRing:
- begin
- dx:= 0;
- dy:= 0;
- FrameTicks:= 600;
- Timer:= 0;
- Frame:= 0;
- scale:= 0.6;
- alpha:= 1;
- angle:= random(360);
- end;
- vgtFeather:
- begin
- t:= random(1024);
- sp:= 0.001 * (random(85) + 95);
- dx:= hwFloat2Float(AngleSin(t)) * sp;
- dy:= hwFloat2Float(AngleCos(t)) * sp;
- if random(2) = 0 then
- dx := -dx;
- if random(2) = 0 then
- dy := -dy;
- FrameTicks:= 650 + random(250);
- Frame:= 1
- end;
- vgtHealthTag:
- begin
- Frame:= 0;
- Timer:= 1500;
- dY:= -0.08;
- dX:= 0;
- //gear^.Z:= 2002;
- end;
- vgtSmokeTrace,
- vgtEvilTrace:
- begin
- gear^.X:= gear^.X - 16;
- gear^.Y:= gear^.Y - 16;
- gear^.State:= 8;
- //gear^.Z:= cSmokeZ
- end;
-vgtBigExplosion:
- begin
- gear^.Angle:= random(360);
- end;
- vgtChunk:
- begin
- gear^.Frame:= random(4);
- t:= random(1024);
- sp:= 0.001 * (random(85) + 47);
- dx:= hwFloat2Float(AngleSin(t)) * sp;
- dy:= hwFloat2Float(AngleCos(t)) * sp * -2;
- if random(2) = 0 then
- dx := -dx;
- end;
- vgtNote:
- begin
- dx:= 0.005 * (random(15) + 10);
- dy:= -0.001 * (random(40) + 20);
- if random(2) = 0 then
- dx := -dx;
- Frame:= random(4);
- FrameTicks:= random(2000) + 1500;
- end;
- vgtBulletHit:
- begin
- dx:= 0;
- dy:= 0;
- FrameTicks:= 350;
- Frame:= 7;
- Angle:= 0;
- end;
-vgtSmoothWindBar:
- begin
- Angle:= hwFloat2Float(cMaxWindSpeed)*2 / 1440; // seems rate below is supposed to change wind bar at 1px per 10ms. Max time, 1440ms. This tries to match the rate of change
- Tag:= hwRound(cWindSpeed * 72 / cMaxWindSpeed);
- end;
- vgtStraightShot:
- begin
- Angle:= 0;
- Scale:= 1.0;
- dx:= 0.001 * random(45);
- dy:= 0.001 * (random(20) + 25);
- State:= ord(sprHealth);
- if random(2) = 0 then
- dx := -dx;
- Frame:= 0;
- FrameTicks:= random(750) + 1250;
- State:= ord(sprSnowDust);
- end;
- end;
-
-if State <> 0 then
- gear^.State:= State;
-
-case Gear^.Kind of
- vgtFlake: if cFlattenFlakes then
- gear^.Layer:= 0
- else if random(3) = 0 then
- begin
- gear^.Scale:= 0.5;
- gear^.Layer:= 0 // 33% - far back
- end
- else if random(3) = 0 then
- begin
- gear^.Scale:= 0.8;
- gear^.Layer:= 4 // 22% - mid-distance
- end
- else if random(3) <> 0 then
- gear^.Layer:= 5 // 30% - just behind land
- else if random(2) = 0 then
- gear^.Layer:= 6 // 7% - just in front of land
- else
- begin
- gear^.Scale:= 1.5;
- gear^.Layer:= 2; // 7% - close up
- end;
-
- vgtCloud: if cFlattenClouds then gear^.Layer:= 5
- else if random(3) = 0 then
- begin
- gear^.Scale:= 0.25;
- gear^.Layer:= 0
- end
- else if random(2) = 0 then
- gear^.Layer:= 5
- else
- begin
- gear^.Scale:= 0.4;
- gear^.Layer:= 4
- end;
-
- // 0: this layer is very distant in the background when in stereo
- vgtTeamHealthSorter,
- vgtSmoothWindBar: gear^.Layer:= 0;
-
-
- // 1: this layer is on the land level (which is close but behind the screen plane) when stereo
- vgtSmokeTrace,
- vgtEvilTrace,
- vgtLineTrail,
- vgtSmoke,
- vgtSmokeWhite,
- vgtDust,
- vgtFire,
- vgtSplash,
- vgtDroplet,
- vgtBubble: gear^.Layer:= 1;
-
- // 3: this layer is on the screen plane (depth = 0) when stereo
- vgtSpeechBubble,
- vgtSmallDamageTag,
- vgtHealthTag,
- vgtStraightShot,
- vgtChunk: gear^.Layer:= 3;
-
- // 2: this layer is outside the screen when stereo
- vgtExplosion,
- vgtBigExplosion,
- vgtExplPart,
- vgtExplPart2,
- vgtSteam,
- vgtAmmo,
- vgtShell,
- vgtFeather,
- vgtEgg,
- vgtBeeTrace,
- vgtSmokeRing,
- vgtNote,
- vgtBulletHit,
- vgtCircle: gear^.Layer:= 2
-end;
-
-if VisualGearLayers[gear^.Layer] <> nil then
- begin
- VisualGearLayers[gear^.Layer]^.PrevGear:= gear;
- gear^.NextGear:= VisualGearLayers[gear^.Layer]
- end;
-VisualGearLayers[gear^.Layer]:= gear;
-
-AddVisualGear:= gear;
-end;
-
-procedure DeleteVisualGear(Gear: PVisualGear);
-begin
- FreeTexture(Gear^.Tex);
- Gear^.Tex:= nil;
-
- if Gear^.NextGear <> nil then
- Gear^.NextGear^.PrevGear:= Gear^.PrevGear;
- if Gear^.PrevGear <> nil then
- Gear^.PrevGear^.NextGear:= Gear^.NextGear
- else
- VisualGearLayers[Gear^.Layer]:= Gear^.NextGear;
-
- if lastVisualGearByUID = Gear then
- lastVisualGearByUID:= nil;
-
- Dispose(Gear);
-end;
-
procedure ProcessVisualGears(Steps: Longword);
var Gear, t: PVisualGear;
i: LongWord;
@@ -612,7 +167,7 @@
end;
end;
if Gear^.Tint <> $FFFFFFFF then
- Tint($FF,$FF,$FF,$FF);
+ untint;
Gear:= Gear^.NextGear
end
end;
@@ -664,10 +219,17 @@
else
DrawSprite(sprDroplet, round(Gear^.X) + WorldDx - 8, round(Gear^.Y) + WorldDy - 8, Gear^.Frame);
vgtBubble: DrawSprite(sprBubbles, round(Gear^.X) + WorldDx - 8, round(Gear^.Y) + WorldDy - 8, Gear^.Frame);//(RealTicks div 64 + Gear^.Frame) mod 8);
+ vgtStraightShot: begin
+ if Gear^.dX < 0 then
+ i:= -1
+ else
+ i:= 1;
+ DrawTextureRotatedF(SpritesData[TSprite(Gear^.State)].Texture, Gear^.Scale, 0, 0, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, Gear^.Frame, i, SpritesData[TSprite(Gear^.State)].Width, SpritesData[TSprite(Gear^.State)].Height, Gear^.Angle);
+ end;
end;
- //if (Gear^.Tint <> $FFFFFFFF) or tinted then Tint($FF,$FF,$FF,$FF);
+ //if (Gear^.Tint <> $FFFFFFFF) or tinted then untint;
if (Gear^.Tint <> $FFFFFFFF) then
- Tint($FF,$FF,$FF,$FF);
+ untint;
Gear:= Gear^.NextGear
end
end;
@@ -729,7 +291,7 @@
vgtChunk: DrawSpriteRotatedF(sprChunk, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, Gear^.Frame, 1, Gear^.Angle);
end;
if (Gear^.Tint <> $FFFFFFFF) or tinted then
- Tint($FF,$FF,$FF,$FF);
+ untint;
Gear:= Gear^.NextGear
end
end;
@@ -813,7 +375,7 @@
DrawCircle(round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, Gear^.State, Gear^.Timer);
end;
if (Gear^.Tint <> $FFFFFFFF) or tinted then
- Tint($FF,$FF,$FF,$FF);
+ untint;
Gear:= Gear^.NextGear
end
end;
@@ -841,7 +403,7 @@
DrawTextureRotatedF(SpritesData[sprFlake].Texture, Gear^.Scale, 0, 0, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, SpritesData[sprFlake].Width, SpritesData[sprFlake].Height, Gear^.Angle);
end;
if (Gear^.Tint <> $FFFFFFFF) then
- Tint($FF,$FF,$FF,$FF);
+ untint;
Gear:= Gear^.NextGear
end
end;
@@ -869,7 +431,7 @@
DrawSpriteRotatedF(sprFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, Gear^.Angle);
end;
if (Gear^.Tint <> $FFFFFFFF) then
- Tint($FF,$FF,$FF,$FF);
+ untint;
Gear:= Gear^.NextGear
end
end;
@@ -893,42 +455,13 @@
DrawSpriteRotatedF(sprFlake, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy + SkyOffset, Gear^.Frame, 1, Gear^.Angle);
end;
if (Gear^.Tint <> $FFFFFFFF) then
- Tint($FF,$FF,$FF,$FF);
+ untint;
Gear:= Gear^.NextGear
end
end;
end;
end;
-function VisualGearByUID(uid : Longword) : PVisualGear;
-var vg: PVisualGear;
- i: LongWord;
-begin
-VisualGearByUID:= nil;
-if uid = 0 then
- exit;
-if (lastVisualGearByUID <> nil) and (lastVisualGearByUID^.uid = uid) then
- begin
- VisualGearByUID:= lastVisualGearByUID;
- exit
- end;
-// search in an order that is more likely to return layers they actually use. Could perhaps track statistically AddVisualGear in uScript, since that is most likely the ones they want
-for i:= 2 to 5 do
- begin
- vg:= VisualGearLayers[i mod 4];
- while vg <> nil do
- begin
- if vg^.uid = uid then
- begin
- lastVisualGearByUID:= vg;
- VisualGearByUID:= vg;
- exit
- end;
- vg:= vg^.NextGear
- end
- end
-end;
-
procedure AddClouds;
var i: LongInt;
begin
@@ -961,7 +494,7 @@
if (cReducedQuality and rqKillFlakes) <> 0 then
exit;
-if hasBorder or ((Theme <> 'Snow') and (Theme <> 'Christmas')) then
+if hasBorder or (not cSnow) then
for i:= 0 to Pred(vobCount * cScreenSpace div 4096) do
AddVisualGear(cLeftScreenBorder + random(cScreenSpace), random(1024+200) - 100 + LAND_HEIGHT, vgtFlake)
else
@@ -989,7 +522,7 @@
end
else vg:= vg^.NextGear;
end;
-if ((GameFlags and gfBorder) <> 0) or ((Theme <> 'Snow') and (Theme <> 'Christmas')) then
+if hasBorder or (not cSnow) then
for i:= 0 to Pred(vobSDCount * cScreenSpace div 4096) do
AddVisualGear(cLeftScreenBorder + random(cScreenSpace), random(1024+200) - 100 + LAND_HEIGHT, vgtFlake)
else
diff -Nru hedgewars-0.9.19.3/hedgewars/uVisualGearsHandlers.pas hedgewars-0.9.20.5/hedgewars/uVisualGearsHandlers.pas
--- hedgewars-0.9.19.3/hedgewars/uVisualGearsHandlers.pas 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uVisualGearsHandlers.pas 2014-01-08 16:25:17.000000000 +0000
@@ -0,0 +1,917 @@
+(*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2013 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
+ *)
+
+(*
+ * This file contains the step handlers for visual gears.
+ *
+ * Since the effects of visual gears do not affect the course of the game,
+ * no "synchronization" between players is required.
+ * => The usage of safe functions or data types (e.g. GetRandom() or hwFloat)
+ * is usually not necessary and therefore undesirable.
+ *)
+
+{$INCLUDE "options.inc"}
+
+unit uVisualGearsHandlers;
+
+interface
+uses uTypes;
+
+var doStepHandlers: array[TVisualGearType] of TVGearStepProcedure;
+
+procedure doStepFlake(Gear: PVisualGear; Steps: Longword);
+procedure doStepBeeTrace(Gear: PVisualGear; Steps: Longword);
+procedure doStepCloud(Gear: PVisualGear; Steps: Longword);
+procedure doStepExpl(Gear: PVisualGear; Steps: Longword);
+procedure doStepNote(Gear: PVisualGear; Steps: Longword);
+procedure doStepLineTrail(Gear: PVisualGear; Steps: Longword);
+procedure doStepEgg(Gear: PVisualGear; Steps: Longword);
+procedure doStepFire(Gear: PVisualGear; Steps: Longword);
+procedure doStepShell(Gear: PVisualGear; Steps: Longword);
+procedure doStepSmallDamage(Gear: PVisualGear; Steps: Longword);
+procedure doStepBubble(Gear: PVisualGear; Steps: Longword);
+procedure doStepSteam(Gear: PVisualGear; Steps: Longword);
+procedure doStepAmmo(Gear: PVisualGear; Steps: Longword);
+procedure doStepSmoke(Gear: PVisualGear; Steps: Longword);
+procedure doStepDust(Gear: PVisualGear; Steps: Longword);
+procedure doStepSplash(Gear: PVisualGear; Steps: Longword);
+procedure doStepDroplet(Gear: PVisualGear; Steps: Longword);
+procedure doStepSmokeRing(Gear: PVisualGear; Steps: Longword);
+procedure doStepFeather(Gear: PVisualGear; Steps: Longword);
+procedure doStepTeamHealthSorterWork(Gear: PVisualGear; Steps: Longword);
+procedure doStepTeamHealthSorter(Gear: PVisualGear; Steps: Longword);
+procedure doStepSpeechBubbleWork(Gear: PVisualGear; Steps: Longword);
+procedure doStepSpeechBubble(Gear: PVisualGear; Steps: Longword);
+procedure doStepHealthTagWork(Gear: PVisualGear; Steps: Longword);
+procedure doStepHealthTagWorkUnderWater(Gear: PVisualGear; Steps: Longword);
+procedure doStepHealthTag(Gear: PVisualGear; Steps: Longword);
+procedure doStepSmokeTrace(Gear: PVisualGear; Steps: Longword);
+procedure doStepExplosionWork(Gear: PVisualGear; Steps: Longword);
+procedure doStepExplosion(Gear: PVisualGear; Steps: Longword);
+procedure doStepBigExplosionWork(Gear: PVisualGear; Steps: Longword);
+procedure doStepBigExplosion(Gear: PVisualGear; Steps: Longword);
+procedure doStepChunk(Gear: PVisualGear; Steps: Longword);
+procedure doStepBulletHit(Gear: PVisualGear; Steps: Longword);
+procedure doStepCircle(Gear: PVisualGear; Steps: Longword);
+procedure doStepSmoothWindBar(Gear: PVisualGear; Steps: Longword);
+procedure doStepStraightShot(Gear: PVisualGear; Steps: Longword);
+
+function isSorterActive: boolean; inline;
+procedure initModule;
+
+implementation
+uses uVariables, Math, uConsts, uVisualGearsList, uFloat, uSound, uRenderUtils, uWorld;
+
+procedure doStepFlake(Gear: PVisualGear; Steps: Longword);
+var sign: real;
+ moved: boolean;
+begin
+if vobCount = 0 then exit;
+
+sign:= 1;
+with Gear^ do
+ begin
+ inc(FrameTicks, Steps);
+ if not SuddenDeathDmg and (FrameTicks > vobFrameTicks) then
+ begin
+ dec(FrameTicks, vobFrameTicks);
+ inc(Frame);
+ if Frame = vobFramesCount then
+ Frame:= 0
+ end
+ else if SuddenDeathDmg and (FrameTicks > vobSDFrameTicks) then
+ begin
+ dec(FrameTicks, vobSDFrameTicks);
+ inc(Frame);
+ if Frame = vobSDFramesCount then
+ Frame:= 0
+ end;
+ X:= X + (cWindSpeedf * 400 + dX + tdX) * Steps * Gear^.Scale;
+ if SuddenDeathDmg then
+ Y:= Y + (dY + tdY + cGravityf * vobSDFallSpeed) * Steps * Gear^.Scale
+ else
+ Y:= Y + (dY + tdY + cGravityf * vobFallSpeed) * Steps * Gear^.Scale;
+ Angle:= Angle + dAngle * Steps;
+ if Angle > 360 then
+ Angle:= Angle - 360
+ else
+ if Angle < - 360 then
+ Angle:= Angle + 360;
+
+
+ if (round(X) >= cLeftScreenBorder)
+ and (round(X) <= cRightScreenBorder)
+ and (round(Y) - 75 <= LAND_HEIGHT)
+ and (Timer > 0) and (Timer-Steps > 0) then
+ begin
+ if tdX > 0 then
+ sign := 1
+ else
+ sign:= -1;
+ tdX:= tdX - 0.005*Steps*sign;
+ if ((sign < 0) and (tdX > 0)) or ((sign > 0) and (tdX < 0)) then
+ tdX:= 0;
+ if tdX > 0 then
+ sign := 1
+ else
+ sign:= -1;
+ tdY:= tdY - 0.005*Steps*sign;
+ if ((sign < 0) and (tdY > 0)) or ((sign > 0) and (tdY < 0)) then
+ tdY:= 0;
+ dec(Timer, Steps)
+ end
+ else
+ begin
+ moved:= false;
+ if round(X) < cLeftScreenBorder then
+ begin
+ X:= X + cScreenSpace;
+ moved:= true
+ end
+ else
+ if round(X) > cRightScreenBorder then
+ begin
+ X:= X - cScreenSpace;
+ moved:= true
+ end;
+ // if round(Y) < (LAND_HEIGHT - 1024 - 75) then Y:= Y + 25.0; // For if flag is set for flakes rising upwards?
+ if (Gear^.Layer = 2) and (round(Y) - 225 > LAND_HEIGHT) then
+ begin
+ X:= cLeftScreenBorder + random(cScreenSpace);
+ Y:= Y - (1024 + 250 + random(50)); // TODO - configure in theme (jellies for example could use limited range)
+ moved:= true
+ end
+ else if (Gear^.Layer <> 2) and (round(Y) + 50 > LAND_HEIGHT) then
+ begin
+ X:= cLeftScreenBorder + random(cScreenSpace);
+ Y:= Y - (1024 + random(25));
+ moved:= true
+ end;
+ if moved then
+ begin
+ Angle:= random(360);
+ dx:= 0.0000038654705 * random(10000);
+ dy:= 0.000003506096 * random(7000);
+ if random(2) = 0 then dx := -dx
+ end;
+ Timer:= 0;
+ tdX:= 0;
+ tdY:= 0
+ end;
+ end;
+
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepBeeTrace(Gear: PVisualGear; Steps: Longword);
+begin
+if Gear^.FrameTicks > Steps then
+ dec(Gear^.FrameTicks, Steps)
+else
+ DeleteVisualGear(Gear);
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepCloud(Gear: PVisualGear; Steps: Longword);
+var s: Longword;
+ t: real;
+begin
+Gear^.X:= Gear^.X + (cWindSpeedf * 750 * Gear^.dX * Gear^.Scale) * Steps;
+
+// up-and-down-bounce magic
+s := (GameTicks + Gear^.Timer) mod 4096;
+t := 8 * Gear^.Scale * hwFloat2Float(AngleSin(s mod 2048));
+if (s < 2048) then t := -t;
+
+Gear^.Y := LAND_HEIGHT - 1184 + LongInt(Gear^.Timer mod 8) + t;
+
+if round(Gear^.X) < cLeftScreenBorder then
+ Gear^.X:= Gear^.X + cScreenSpace
+else
+ if round(Gear^.X) > cRightScreenBorder then
+ Gear^.X:= Gear^.X - cScreenSpace
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepExpl(Gear: PVisualGear; Steps: Longword);
+var s: LongInt;
+begin
+s:= min(Steps, cExplFrameTicks);
+
+Gear^.X:= Gear^.X + Gear^.dX * s;
+Gear^.Y:= Gear^.Y + Gear^.dY * s;
+//Gear^.dY:= Gear^.dY + cGravityf;
+
+if Gear^.FrameTicks <= Steps then
+ if Gear^.Frame = 0 then
+ DeleteVisualGear(Gear)
+ else
+ begin
+ dec(Gear^.Frame);
+ Gear^.FrameTicks:= cExplFrameTicks
+ end
+ else dec(Gear^.FrameTicks, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepNote(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+
+Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
+Gear^.dY:= Gear^.dY + cGravityf * Steps / 2;
+
+Gear^.Angle:= Gear^.Angle + (Gear^.Frame + 1) * Steps / 10;
+while Gear^.Angle > cMaxAngle do
+ Gear^.Angle:= Gear^.Angle - cMaxAngle;
+
+if Gear^.FrameTicks <= Steps then
+ DeleteVisualGear(Gear)
+else
+ dec(Gear^.FrameTicks, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepLineTrail(Gear: PVisualGear; Steps: Longword);
+begin
+Steps := Steps;
+if Gear^.Timer <= Steps then
+ DeleteVisualGear(Gear)
+else
+ dec(Gear^.Timer, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepEgg(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+
+Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
+Gear^.dY:= Gear^.dY + cGravityf * Steps;
+
+Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
+
+if Gear^.FrameTicks <= Steps then
+ begin
+ DeleteVisualGear(Gear);
+ exit
+ end
+else
+ dec(Gear^.FrameTicks, Steps);
+
+if Gear^.FrameTicks < $FF then
+ Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or Gear^.FrameTicks
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepFire(Gear: PVisualGear; Steps: Longword);
+var vgt: PVisualGear;
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+
+Gear^.Y:= Gear^.Y + Gear^.dY * Steps;// + cGravityf * (Steps * Steps);
+if (Gear^.State and gstTmpFlag) = 0 then
+ begin
+ Gear^.dY:= Gear^.dY + cGravityf * Steps;
+ if ((GameTicks mod 200) < Steps + 1) then
+ begin
+ vgt:= AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtFire);
+ if vgt <> nil then
+ begin
+ vgt^.dx:= 0;
+ vgt^.dy:= 0;
+ vgt^.State:= gstTmpFlag;
+ end;
+ end
+ end
+else
+ inc(Steps, Steps);
+
+if Gear^.FrameTicks <= Steps then
+ DeleteVisualGear(Gear)
+else
+ dec(Gear^.FrameTicks, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepShell(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+
+Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
+Gear^.dY:= Gear^.dY + cGravityf * Steps;
+
+Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
+
+if Gear^.FrameTicks <= Steps then
+ DeleteVisualGear(Gear)
+else
+ dec(Gear^.FrameTicks, Steps)
+end;
+
+procedure doStepSmallDamage(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.Y:= Gear^.Y - 0.02 * Steps;
+
+if Gear^.FrameTicks <= Steps then
+ DeleteVisualGear(Gear)
+else
+ dec(Gear^.FrameTicks, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepBubble(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
+Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
+Gear^.dX := Gear^.dX / (1.001 * Steps);
+Gear^.dY := Gear^.dY / (1.001 * Steps);
+
+if (Gear^.FrameTicks <= Steps) or (round(Gear^.Y) < cWaterLine) then
+ DeleteVisualGear(Gear)
+else
+ dec(Gear^.FrameTicks, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSteam(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + (cWindSpeedf * 100 + Gear^.dX) * Steps;
+Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
+
+if Gear^.FrameTicks <= Steps then
+ if Gear^.Frame = 0 then
+ DeleteVisualGear(Gear)
+ else
+ begin
+ if Random(2) = 0 then
+ dec(Gear^.Frame);
+ Gear^.FrameTicks:= cExplFrameTicks
+ end
+else dec(Gear^.FrameTicks, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepAmmo(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
+
+Gear^.scale:= Gear^.scale + 0.0025 * Steps;
+Gear^.alpha:= Gear^.alpha - 0.0015 * Steps;
+
+if Gear^.alpha < 0 then
+ DeleteVisualGear(Gear)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSmoke(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + (cWindSpeedf + Gear^.dX) * Steps;
+Gear^.Y:= Gear^.Y - (cDrownSpeedf + Gear^.dY) * Steps;
+
+Gear^.dX := Gear^.dX + (cWindSpeedf * 0.3 * Steps);
+//Gear^.dY := Gear^.dY - (cDrownSpeedf * 0.995);
+
+if Gear^.FrameTicks <= Steps then
+ if Gear^.Frame = 0 then
+ DeleteVisualGear(Gear)
+ else
+ begin
+ if Random(2) = 0 then
+ dec(Gear^.Frame);
+ Gear^.FrameTicks:= cExplFrameTicks
+ end
+ else dec(Gear^.FrameTicks, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepDust(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + (cWindSpeedf + (cWindSpeedf * 0.03 * Steps) + Gear^.dX) * Steps;
+Gear^.Y:= Gear^.Y - (Gear^.dY) * Steps;
+
+Gear^.dX := Gear^.dX - (Gear^.dX * 0.005 * Steps);
+Gear^.dY := Gear^.dY - (cDrownSpeedf * 0.001 * Steps);
+
+if Gear^.FrameTicks <= Steps then
+ if Gear^.Frame = 0 then
+ DeleteVisualGear(Gear)
+ else
+ begin
+ dec(Gear^.Frame);
+ Gear^.FrameTicks:= cExplFrameTicks
+ end
+ else dec(Gear^.FrameTicks, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSplash(Gear: PVisualGear; Steps: Longword);
+begin
+if Gear^.FrameTicks <= Steps then
+ DeleteVisualGear(Gear)
+else
+ dec(Gear^.FrameTicks, Steps);
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepDroplet(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+
+Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
+Gear^.dY:= Gear^.dY + cGravityf * Steps;
+
+if round(Gear^.Y) > cWaterLine then
+ begin
+ DeleteVisualGear(Gear);
+ PlaySound(TSound(ord(sndDroplet1) + Random(3)));
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSmokeRing(Gear: PVisualGear; Steps: Longword);
+begin
+inc(Gear^.Timer, Steps);
+if Gear^.Timer >= Gear^.FrameTicks then
+ DeleteVisualGear(Gear)
+else
+ begin
+ Gear^.scale := 1.25 * (-power(2, -10 * Int(Gear^.Timer)/Gear^.FrameTicks) + 1) + 0.4;
+ Gear^.alpha := 1 - power(Gear^.Timer / 350, 4);
+ if Gear^.alpha < 0 then
+ Gear^.alpha:= 0;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepFeather(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+
+Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
+Gear^.dY:= Gear^.dY + cGravityf * Steps;
+
+Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
+
+if Gear^.FrameTicks <= Steps then
+ DeleteVisualGear(Gear)
+else
+ dec(Gear^.FrameTicks, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+const cSorterWorkTime = 640;
+var thexchar: array[0..cMaxTeams] of
+ record
+ dy, ny, dw: LongInt;
+ team: PTeam;
+ SortFactor: QWord;
+ hdw: array[0..cMaxHHIndex] of LongInt;
+ end;
+ currsorter: PVisualGear = nil;
+
+function isSorterActive: boolean; inline;
+begin
+ isSorterActive:= currsorter <> nil
+end;
+
+procedure doStepTeamHealthSorterWork(Gear: PVisualGear; Steps: Longword);
+var i, t, h: LongInt;
+begin
+for t:= 1 to min(Steps, Gear^.Timer) do
+ begin
+ dec(Gear^.Timer);
+ if (Gear^.Timer and 15) = 0 then
+ for i:= 0 to Pred(TeamsCount) do
+ with thexchar[i] do
+ begin
+ {$WARNINGS OFF}
+ team^.DrawHealthY:= ny + dy * LongInt(Gear^.Timer) div cSorterWorkTime;
+ team^.TeamHealthBarHealth:= team^.TeamHealth + dw * LongInt(Gear^.Timer) div cSorterWorkTime;
+
+ for h:= 0 to cMaxHHIndex do
+ if (team^.Hedgehogs[h].Gear <> nil) then
+ team^.Hedgehogs[h].HealthBarHealth:= team^.Hedgehogs[h].Gear^.Health + hdw[h] * LongInt(Gear^.Timer) div cSorterWorkTime
+ else
+ team^.Hedgehogs[h].HealthBarHealth:= hdw[h] * LongInt(Gear^.Timer) div cSorterWorkTime;
+ {$WARNINGS ON}
+ end;
+ end;
+
+if (Gear^.Timer = 0) or (currsorter <> Gear) then
+ begin
+ if currsorter = Gear then
+ currsorter:= nil;
+ DeleteVisualGear(Gear);
+ exit
+ end
+end;
+
+procedure doStepTeamHealthSorter(Gear: PVisualGear; Steps: Longword);
+var i: Longword;
+ b: boolean;
+ t, h: LongInt;
+begin
+Steps:= Steps; // avoid compiler hint
+
+for t:= 0 to Pred(TeamsCount) do
+ with thexchar[t] do
+ begin
+ team:= TeamsArray[t];
+ dy:= team^.DrawHealthY;
+ dw:= team^.TeamHealthBarHealth - team^.TeamHealth;
+ if team^.TeamHealth > 0 then
+ begin
+ SortFactor:= team^.Clan^.ClanHealth;
+ SortFactor:= (SortFactor shl 3) + team^.Clan^.ClanIndex;
+ SortFactor:= (SortFactor shl 30) + team^.TeamHealth;
+ end
+ else
+ SortFactor:= 0;
+
+ for h:= 0 to cMaxHHIndex do
+ if (team^.Hedgehogs[h].Gear <> nil) then
+ hdw[h]:= team^.Hedgehogs[h].HealthBarHealth - team^.Hedgehogs[h].Gear^.Health
+ else
+ hdw[h]:= team^.Hedgehogs[h].HealthBarHealth;
+ end;
+
+if TeamsCount > 1 then
+ repeat
+ b:= true;
+ for t:= 0 to TeamsCount - 2 do
+ if (thexchar[t].SortFactor > thexchar[Succ(t)].SortFactor) then
+ begin
+ thexchar[cMaxTeams]:= thexchar[t];
+ thexchar[t]:= thexchar[Succ(t)];
+ thexchar[Succ(t)]:= thexchar[cMaxTeams];
+ b:= false
+ end
+ until b;
+
+t:= - 4;
+for i:= 0 to Pred(TeamsCount) do
+ with thexchar[i] do
+ if team^.TeamHealth > 0 then
+ begin
+ dec(t, team^.Clan^.HealthTex^.h + 2);
+ ny:= t;
+ dy:= dy - ny
+ end;
+
+Gear^.Timer:= cSorterWorkTime;
+Gear^.doStep:= @doStepTeamHealthSorterWork;
+currsorter:= Gear;
+//doStepTeamHealthSorterWork(Gear, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSpeechBubbleWork(Gear: PVisualGear; Steps: Longword);
+begin
+if Gear^.Timer > Steps then dec(Gear^.Timer, Steps) else Gear^.Timer:= 0;
+
+if (Gear^.Hedgehog^.Gear <> nil) then
+ begin
+ Gear^.X:= hwFloat2Float(Gear^.Hedgehog^.Gear^.X) + (Gear^.Tex^.w div 2 - Gear^.Tag);
+ Gear^.Y:= hwFloat2Float(Gear^.Hedgehog^.Gear^.Y) - (16 + Gear^.Tex^.h);
+ end;
+
+if Gear^.Timer = 0 then
+ begin
+ if Gear^.Hedgehog^.SpeechGear = Gear then
+ Gear^.Hedgehog^.SpeechGear:= nil;
+ DeleteVisualGear(Gear)
+ end;
+end;
+
+procedure doStepSpeechBubble(Gear: PVisualGear; Steps: Longword);
+begin
+Steps:= Steps; // avoid compiler hint
+
+with Gear^.Hedgehog^ do
+ if SpeechGear <> nil then
+ SpeechGear^.Timer:= 0;
+
+Gear^.Hedgehog^.SpeechGear:= Gear;
+
+Gear^.Timer:= max(LongInt(Length(Gear^.Text)) * 150, 3000);
+
+Gear^.Tex:= RenderSpeechBubbleTex(Gear^.Text, Gear^.FrameTicks, fnt16);
+
+// FrameTicks cannot hold negative values
+case Gear^.FrameTicks of
+ 1: Gear^.Tag:= SpritesData[sprSpeechTail].Width-28;
+ 2: Gear^.Tag:= SpritesData[sprThoughtTail].Width-20;
+ 3: Gear^.Tag:= SpritesData[sprShoutTail].Width-10;
+ end;
+
+Gear^.doStep:= @doStepSpeechBubbleWork;
+
+Gear^.Y:= Gear^.Y - Gear^.Tex^.h
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepHealthTagWork(Gear: PVisualGear; Steps: Longword);
+begin
+if Steps > Gear^.Timer then
+ DeleteVisualGear(Gear)
+else
+ begin
+ dec(Gear^.Timer, Steps);
+ Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
+ Gear^.X:= Gear^.X + Gear^.dX * Steps
+ end;
+end;
+
+procedure doStepHealthTagWorkUnderWater(Gear: PVisualGear; Steps: Longword);
+begin
+if round(Gear^.Y) - 10 < cWaterLine then
+ DeleteVisualGear(Gear)
+else
+ Gear^.Y:= Gear^.Y - 0.08 * Steps;
+
+end;
+
+procedure doStepHealthTag(Gear: PVisualGear; Steps: Longword);
+var s: shortstring;
+begin
+s:= '';
+
+str(Gear^.State, s);
+if Gear^.Hedgehog <> nil then
+ Gear^.Tex:= RenderStringTex(s, Gear^.Hedgehog^.Team^.Clan^.Color, fnt16)
+else
+ Gear^.Tex:= RenderStringTex(s, cWhiteColor, fnt16);
+
+Gear^.doStep:= @doStepHealthTagWork;
+
+if (round(Gear^.Y) > cWaterLine) and (Gear^.Frame = 0) then
+ Gear^.doStep:= @doStepHealthTagWorkUnderWater;
+
+Gear^.Y:= Gear^.Y - Gear^.Tex^.h;
+
+if Steps > 1 then
+ Gear^.doStep(Gear, Steps-1);
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSmokeTrace(Gear: PVisualGear; Steps: Longword);
+begin
+inc(Gear^.Timer, Steps );
+if Gear^.Timer > 64 then
+ begin
+ if Gear^.State = 0 then
+ begin
+ DeleteVisualGear(Gear);
+ exit;
+ end;
+ dec(Gear^.State, Gear^.Timer div 65);
+ Gear^.Timer:= Gear^.Timer mod 65;
+ end;
+Gear^.dX:= Gear^.dX + cWindSpeedf * Steps;
+Gear^.X:= Gear^.X + Gear^.dX;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepExplosionWork(Gear: PVisualGear; Steps: Longword);
+begin
+inc(Gear^.Timer, Steps);
+if Gear^.Timer > 75 then
+ begin
+ inc(Gear^.State, Gear^.Timer div 76);
+ Gear^.Timer:= Gear^.Timer mod 76;
+ if Gear^.State > 5 then
+ DeleteVisualGear(Gear);
+ end;
+end;
+
+procedure doStepExplosion(Gear: PVisualGear; Steps: Longword);
+var i: LongWord;
+ gX,gY: LongInt;
+ vg: PVisualGear;
+begin
+gX:= round(Gear^.X);
+gY:= round(Gear^.Y);
+for i:= 0 to 31 do
+ begin
+ vg:= AddVisualGear(gX, gY, vgtFire);
+ if vg <> nil then
+ begin
+ vg^.State:= gstTmpFlag;
+ inc(vg^.FrameTicks, vg^.FrameTicks)
+ end
+ end;
+for i:= 0 to 8 do AddVisualGear(gX, gY, vgtExplPart);
+for i:= 0 to 8 do AddVisualGear(gX, gY, vgtExplPart2);
+Gear^.doStep:= @doStepExplosionWork;
+if Steps > 1 then
+ Gear^.doStep(Gear, Steps-1);
+end;
+
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepBigExplosionWork(Gear: PVisualGear; Steps: Longword);
+var maxMovement: LongInt;
+begin
+
+inc(Gear^.Timer, Steps);
+if (Gear^.Timer and 5) = 0 then
+ begin
+ maxMovement := max(1, 13 - ((Gear^.Timer * 15) div 250));
+ ShakeCamera(maxMovement);
+ end;
+
+if Gear^.Timer > 250 then
+ DeleteVisualGear(Gear);
+end;
+
+procedure doStepBigExplosion(Gear: PVisualGear; Steps: Longword);
+var i: LongWord;
+ gX,gY: LongInt;
+ vg: PVisualGear;
+begin
+//ScreenFade:= sfFromWhite;
+//ScreenFadeValue:= round(60 * zoom * zoom);
+//ScreenFadeSpeed:= 5;
+gX:= round(Gear^.X);
+gY:= round(Gear^.Y);
+AddVisualGear(gX, gY, vgtSmokeRing);
+for i:= 0 to 46 do
+ begin
+ vg:= AddVisualGear(gX, gY, vgtFire);
+ if vg <> nil then
+ begin
+ vg^.State:= gstTmpFlag;
+ inc(vg^.FrameTicks, vg^.FrameTicks)
+ end
+ end;
+for i:= 0 to 15 do
+ AddVisualGear(gX, gY, vgtExplPart);
+for i:= 0 to 15 do
+ AddVisualGear(gX, gY, vgtExplPart2);
+Gear^.doStep:= @doStepBigExplosionWork;
+if Steps > 1 then
+ Gear^.doStep(Gear, Steps-1);
+with mobileRecord do
+ if (performRumble <> nil) and (not fastUntilLag) then
+ performRumble(kSystemSoundID_Vibrate);
+end;
+
+procedure doStepChunk(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+
+Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
+Gear^.dY:= Gear^.dY + cGravityf * Steps;
+
+Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
+
+if (round(Gear^.Y) > cWaterLine) and ((cReducedQuality and rqPlainSplash) = 0) then
+ begin
+ AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtDroplet);
+ DeleteVisualGear(Gear);
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepBulletHit(Gear: PVisualGear; Steps: Longword);
+begin
+if Gear^.FrameTicks <= Steps then
+ DeleteVisualGear(Gear)
+else
+ dec(Gear^.FrameTicks, Steps);
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepCircle(Gear: PVisualGear; Steps: Longword);
+var tmp: LongInt;
+ i: LongWord;
+begin
+with Gear^ do
+ if Frame <> 0 then
+ for i:= 1 to Steps do
+ begin
+ inc(FrameTicks);
+ if (FrameTicks mod Frame) = 0 then
+ begin
+ tmp:= Gear^.Tint and $FF;
+ if tdY >= 0 then
+ inc(tmp)
+ else
+ dec(tmp);
+ if tmp < round(dX) then
+ tdY:= 1;
+ if tmp > round(dY) then
+ tdY:= -1;
+ if tmp > 255 then
+ tmp := 255;
+ if tmp < 0 then
+ tmp := 0;
+ Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or Longword(tmp)
+ end
+ end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSmoothWindBar(Gear: PVisualGear; Steps: Longword);
+begin
+inc(Gear^.Timer, Steps);
+
+while Gear^.Timer >= 10 do
+ begin
+ dec(Gear^.Timer, 10);
+ if WindBarWidth < Gear^.Tag then
+ inc(WindBarWidth)
+ else if WindBarWidth > Gear^.Tag then
+ dec(WindBarWidth);
+ end;
+if cWindspeedf > Gear^.dAngle then
+ begin
+ cWindspeedf := cWindspeedf - Gear^.Angle*Steps;
+ if cWindspeedf < Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
+ end
+else if cWindspeedf < Gear^.dAngle then
+ begin
+ cWindspeedf := cWindspeedf + Gear^.Angle*Steps;
+ if cWindspeedf > Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
+ end;
+
+if (WindBarWidth = Gear^.Tag) and (cWindspeedf = Gear^.dAngle) then
+ DeleteVisualGear(Gear)
+end;
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepStraightShot(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+Gear^.Y:= Gear^.Y - Gear^.dY * Steps;
+
+if Gear^.FrameTicks <= Steps then
+ DeleteVisualGear(Gear)
+else
+ begin
+ dec(Gear^.FrameTicks, Steps);
+ if (Gear^.FrameTicks < 501) and (Gear^.FrameTicks mod 5 = 0) then
+ Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or (((Gear^.Tint and $000000FF) * Gear^.FrameTicks) div 500)
+ end
+end;
+
+
+const handlers: array[TVisualGearType] of TVGearStepProcedure =
+ (
+ @doStepFlake,
+ @doStepCloud,
+ @doStepExpl,
+ @doStepExpl,
+ @doStepFire,
+ @doStepSmallDamage,
+ @doStepTeamHealthSorter,
+ @doStepSpeechBubble,
+ @doStepBubble,
+ @doStepSteam,
+ @doStepAmmo,
+ @doStepSmoke,
+ @doStepSmoke,
+ @doStepShell,
+ @doStepDust,
+ @doStepSplash,
+ @doStepDroplet,
+ @doStepSmokeRing,
+ @doStepBeeTrace,
+ @doStepEgg,
+ @doStepFeather,
+ @doStepHealthTag,
+ @doStepSmokeTrace,
+ @doStepSmokeTrace,
+ @doStepExplosion,
+ @doStepBigExplosion,
+ @doStepChunk,
+ @doStepNote,
+ @doStepLineTrail,
+ @doStepBulletHit,
+ @doStepCircle,
+ @doStepSmoothWindBar,
+ @doStepStraightShot
+ );
+
+procedure initModule;
+begin
+ doStepHandlers:= handlers
+end;
+
+end.
diff -Nru hedgewars-0.9.19.3/hedgewars/uVisualGearsList.pas hedgewars-0.9.20.5/hedgewars/uVisualGearsList.pas
--- hedgewars-0.9.19.3/hedgewars/uVisualGearsList.pas 1970-01-01 00:00:00.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uVisualGearsList.pas 2014-01-08 16:25:17.000000000 +0000
@@ -0,0 +1,470 @@
+(*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2013 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"}
+
+unit uVisualGearsList;
+interface
+uses uTypes;
+
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear; inline;
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean; Layer: LongInt): PVisualGear;
+procedure DeleteVisualGear(Gear: PVisualGear);
+function VisualGearByUID(uid : Longword) : PVisualGear;
+
+const
+ cExplFrameTicks = 110;
+
+var VGCounter: LongWord;
+ VisualGearLayers: array[0..6] of PVisualGear;
+
+implementation
+uses uFloat, uVariables, uConsts, uTextures, uVisualGearsHandlers;
+
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline;
+begin
+ AddVisualGear:= AddVisualGear(X, Y, Kind, 0, false, -1);
+end;
+
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline;
+begin
+ AddVisualGear:= AddVisualGear(X, Y, Kind, State, false, -1);
+end;
+
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear; inline;
+begin
+ AddVisualGear:= AddVisualGear(X, Y, Kind, State, Critical, -1);
+end;
+
+function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean; Layer: LongInt): PVisualGear;
+var gear: PVisualGear;
+ t: Longword;
+ sp: real;
+begin
+AddVisualGear:= nil;
+if ((GameType = gmtSave) or (fastUntilLag and (GameType = gmtNet)) or fastScrolling) and // we are scrolling now
+ ((Kind <> vgtCloud) and (not Critical)) then
+ exit;
+
+if ((cReducedQuality and rqAntiBoom) <> 0) and
+ (not Critical) and
+ (not (Kind in
+ [vgtTeamHealthSorter,
+ vgtSmallDamageTag,
+ vgtSpeechBubble,
+ vgtHealthTag,
+ vgtExplosion,
+ vgtSmokeTrace,
+ vgtEvilTrace,
+ vgtNote,
+ vgtSmoothWindBar])) then
+
+ exit;
+
+inc(VGCounter);
+New(gear);
+FillChar(gear^, sizeof(TVisualGear), 0);
+gear^.X:= real(X);
+gear^.Y:= real(Y);
+gear^.Kind := Kind;
+gear^.doStep:= doStepHandlers[Kind];
+gear^.State:= 0;
+gear^.Tint:= $FFFFFFFF;
+gear^.uid:= VGCounter;
+gear^.Layer:= 0;
+
+with gear^ do
+ case Kind of
+ vgtFlake:
+ begin
+ Timer:= 0;
+ tdX:= 0;
+ tdY:= 0;
+ Scale:= 1.0;
+ if SuddenDeathDmg then
+ begin
+ FrameTicks:= random(vobSDFrameTicks);
+ Frame:= random(vobSDFramesCount);
+ end
+ else
+ begin
+ FrameTicks:= random(vobFrameTicks);
+ Frame:= random(vobFramesCount);
+ end;
+ Angle:= random(360);
+ dx:= 0.0000038654705 * random(10000);
+ dy:= 0.000003506096 * random(7000);
+ if random(2) = 0 then
+ dx := -dx;
+ if SuddenDeathDmg then
+ dAngle:= (random(2) * 2 - 1) * (vobSDVelocity + random(vobSDVelocity)) / 1000
+ else
+ dAngle:= (random(2) * 2 - 1) * (vobVelocity + random(vobVelocity)) / 1000
+ end;
+ vgtCloud:
+ begin
+ Frame:= random(4);
+ dx:= 0.5 + 0.1 * random(5); // how much the cloud will be affected by wind
+ timer:= random(4096);
+ Scale:= 1.0
+ end;
+ vgtExplPart,
+ vgtExplPart2:
+ begin
+ t:= random(1024);
+ sp:= 0.001 * (random(95) + 70);
+ dx:= hwFloat2Float(AngleSin(t)) * sp;
+ dy:= hwFloat2Float(AngleCos(t)) * sp;
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ Frame:= 7 - random(3);
+ FrameTicks:= cExplFrameTicks
+ end;
+ vgtFire:
+ begin
+ t:= random(1024);
+ sp:= 0.001 * (random(85) + 95);
+ dx:= hwFloat2Float(AngleSin(t)) * sp;
+ dy:= hwFloat2Float(AngleCos(t)) * sp;
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ FrameTicks:= 650 + random(250);
+ Frame:= random(8)
+ end;
+ vgtEgg:
+ begin
+ t:= random(1024);
+ sp:= 0.001 * (random(85) + 95);
+ dx:= hwFloat2Float(AngleSin(t)) * sp;
+ dy:= hwFloat2Float(AngleCos(t)) * sp;
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ FrameTicks:= 650 + random(250);
+ Frame:= 1
+ end;
+ vgtShell: FrameTicks:= 500;
+ vgtSmallDamageTag:
+ begin
+ gear^.FrameTicks:= 1100
+ end;
+ vgtBubble:
+ begin
+ dx:= 0.0000038654705 * random(10000);
+ dy:= 0;
+ if random(2) = 0 then
+ dx := -dx;
+ FrameTicks:= 250 + random(1751);
+ Frame:= random(5)
+ end;
+ vgtSteam:
+ begin
+ dx:= 0.0000038654705 * random(10000);
+ dy:= 0.001 * (random(85) + 95);
+ if random(2) = 0 then
+ dx := -dx;
+ Frame:= 7 - random(3);
+ FrameTicks:= cExplFrameTicks * 2;
+ end;
+ vgtAmmo:
+ begin
+ alpha:= 1.0;
+ scale:= 1.0
+ end;
+ vgtSmokeWhite,
+ vgtSmoke:
+ begin
+ Scale:= 1.0;
+ dx:= 0.0002 * (random(45) + 10);
+ dy:= 0.0002 * (random(45) + 10);
+ if random(2) = 0 then
+ dx := -dx;
+ Frame:= 7 - random(2);
+ FrameTicks:= cExplFrameTicks * 2;
+ end;
+ vgtDust:
+ begin
+ dx:= 0.005 * (random(15) + 10);
+ dy:= 0.001 * (random(40) + 20);
+ if random(2) = 0 then dx := -dx;
+ if random(2) = 0 then Tag:= 1
+ else Tag:= -1;
+ Frame:= 7 - random(2);
+ FrameTicks:= random(20) + 15;
+ end;
+ vgtSplash:
+ begin
+ dx:= 0;
+ dy:= 0;
+ FrameTicks:= 740;
+ Frame:= 19;
+ Scale:= 0.75;
+ Timer:= 1;
+ end;
+ vgtDroplet:
+ begin
+ dx:= 0.001 * (random(180) - 90);
+ dy:= -0.001 * (random(160) + 40);
+ FrameTicks:= 250 + random(1751);
+ Frame:= random(3)
+ end;
+ vgtBeeTrace:
+ begin
+ FrameTicks:= 1000;
+ Frame:= random(16);
+ end;
+ vgtSmokeRing:
+ begin
+ dx:= 0;
+ dy:= 0;
+ FrameTicks:= 600;
+ Timer:= 0;
+ Frame:= 0;
+ scale:= 0.6;
+ alpha:= 1;
+ angle:= random(360);
+ end;
+ vgtFeather:
+ begin
+ t:= random(1024);
+ sp:= 0.001 * (random(85) + 95);
+ dx:= hwFloat2Float(AngleSin(t)) * sp;
+ dy:= hwFloat2Float(AngleCos(t)) * sp;
+ if random(2) = 0 then
+ dx := -dx;
+ if random(2) = 0 then
+ dy := -dy;
+ FrameTicks:= 650 + random(250);
+ Frame:= 1
+ end;
+ vgtHealthTag:
+ begin
+ Frame:= 0;
+ Timer:= 1500;
+ dY:= -0.08;
+ dX:= 0;
+ //gear^.Z:= 2002;
+ end;
+ vgtSmokeTrace,
+ vgtEvilTrace:
+ begin
+ gear^.X:= gear^.X - 16;
+ gear^.Y:= gear^.Y - 16;
+ gear^.State:= 8;
+ //gear^.Z:= cSmokeZ
+ end;
+vgtBigExplosion:
+ begin
+ gear^.Angle:= random(360);
+ end;
+ vgtChunk:
+ begin
+ gear^.Frame:= random(4);
+ t:= random(1024);
+ sp:= 0.001 * (random(85) + 47);
+ dx:= hwFloat2Float(AngleSin(t)) * sp;
+ dy:= hwFloat2Float(AngleCos(t)) * sp * -2;
+ if random(2) = 0 then
+ dx := -dx;
+ end;
+ vgtNote:
+ begin
+ dx:= 0.005 * (random(15) + 10);
+ dy:= -0.001 * (random(40) + 20);
+ if random(2) = 0 then
+ dx := -dx;
+ Frame:= random(4);
+ FrameTicks:= random(2000) + 1500;
+ end;
+ vgtBulletHit:
+ begin
+ dx:= 0;
+ dy:= 0;
+ FrameTicks:= 350;
+ Frame:= 7;
+ Angle:= 0;
+ end;
+vgtSmoothWindBar:
+ begin
+ Angle:= hwFloat2Float(cMaxWindSpeed)*2 / 1440; // seems rate below is supposed to change wind bar at 1px per 10ms. Max time, 1440ms. This tries to match the rate of change
+ Tag:= hwRound(cWindSpeed * 72 / cMaxWindSpeed);
+ end;
+ vgtStraightShot:
+ begin
+ Angle:= 0;
+ Scale:= 1.0;
+ dx:= 0.001 * random(45);
+ dy:= 0.001 * (random(20) + 25);
+ State:= ord(sprHealth);
+ if random(2) = 0 then
+ dx := -dx;
+ Frame:= 0;
+ FrameTicks:= random(750) + 1250;
+ State:= ord(sprSnowDust);
+ end;
+ end;
+
+if State <> 0 then
+ gear^.State:= State;
+
+case Gear^.Kind of
+ vgtFlake: if cFlattenFlakes then
+ gear^.Layer:= 0
+ else if random(3) = 0 then
+ begin
+ gear^.Scale:= 0.5;
+ gear^.Layer:= 0 // 33% - far back
+ end
+ else if random(3) = 0 then
+ begin
+ gear^.Scale:= 0.8;
+ gear^.Layer:= 4 // 22% - mid-distance
+ end
+ else if random(3) <> 0 then
+ gear^.Layer:= 5 // 30% - just behind land
+ else if random(2) = 0 then
+ gear^.Layer:= 6 // 7% - just in front of land
+ else
+ begin
+ gear^.Scale:= 1.5;
+ gear^.Layer:= 2; // 7% - close up
+ end;
+
+ vgtCloud: if cFlattenClouds then gear^.Layer:= 5
+ else if random(3) = 0 then
+ begin
+ gear^.Scale:= 0.25;
+ gear^.Layer:= 0
+ end
+ else if random(2) = 0 then
+ gear^.Layer:= 5
+ else
+ begin
+ gear^.Scale:= 0.4;
+ gear^.Layer:= 4
+ end;
+
+ // 0: this layer is very distant in the background when in stereo
+ vgtTeamHealthSorter,
+ vgtSmoothWindBar: gear^.Layer:= 0;
+
+
+ // 1: this layer is on the land level (which is close but behind the screen plane) when stereo
+ vgtSmokeTrace,
+ vgtEvilTrace,
+ vgtLineTrail,
+ vgtSmoke,
+ vgtSmokeWhite,
+ vgtDust,
+ vgtFire,
+ vgtSplash,
+ vgtDroplet,
+ vgtBubble: gear^.Layer:= 1;
+
+ // 3: this layer is on the screen plane (depth = 0) when stereo
+ vgtSpeechBubble,
+ vgtSmallDamageTag,
+ vgtHealthTag,
+ vgtStraightShot,
+ vgtChunk: gear^.Layer:= 3;
+
+ // 2: this layer is outside the screen when stereo
+ vgtExplosion,
+ vgtBigExplosion,
+ vgtExplPart,
+ vgtExplPart2,
+ vgtSteam,
+ vgtAmmo,
+ vgtShell,
+ vgtFeather,
+ vgtEgg,
+ vgtBeeTrace,
+ vgtSmokeRing,
+ vgtNote,
+ vgtBulletHit,
+ vgtCircle: gear^.Layer:= 2
+end;
+
+if Layer <> -1 then gear^.Layer:= Layer;
+
+if VisualGearLayers[gear^.Layer] <> nil then
+ begin
+ VisualGearLayers[gear^.Layer]^.PrevGear:= gear;
+ gear^.NextGear:= VisualGearLayers[gear^.Layer]
+ end;
+VisualGearLayers[gear^.Layer]:= gear;
+
+AddVisualGear:= gear;
+end;
+
+procedure DeleteVisualGear(Gear: PVisualGear);
+begin
+ FreeTexture(Gear^.Tex);
+ Gear^.Tex:= nil;
+
+ if Gear^.NextGear <> nil then
+ Gear^.NextGear^.PrevGear:= Gear^.PrevGear;
+ if Gear^.PrevGear <> nil then
+ Gear^.PrevGear^.NextGear:= Gear^.NextGear
+ else
+ VisualGearLayers[Gear^.Layer]:= Gear^.NextGear;
+
+ if lastVisualGearByUID = Gear then
+ lastVisualGearByUID:= nil;
+
+ Dispose(Gear);
+end;
+
+function VisualGearByUID(uid : Longword) : PVisualGear;
+var vg: PVisualGear;
+ i: LongWord;
+begin
+VisualGearByUID:= nil;
+if uid = 0 then
+ exit;
+if (lastVisualGearByUID <> nil) and (lastVisualGearByUID^.uid = uid) then
+ begin
+ VisualGearByUID:= lastVisualGearByUID;
+ exit
+ end;
+// search in an order that is more likely to return layers they actually use. Could perhaps track statistically AddVisualGear in uScript, since that is most likely the ones they want
+for i:= 2 to 5 do
+ begin
+ vg:= VisualGearLayers[i mod 4];
+ while vg <> nil do
+ begin
+ if vg^.uid = uid then
+ begin
+ lastVisualGearByUID:= vg;
+ VisualGearByUID:= vg;
+ exit
+ end;
+ vg:= vg^.NextGear
+ end
+ end
+end;
+
+
+end.
diff -Nru hedgewars-0.9.19.3/hedgewars/uWorld.pas hedgewars-0.9.20.5/hedgewars/uWorld.pas
--- hedgewars-0.9.19.3/hedgewars/uWorld.pas 2013-06-04 14:09:29.000000000 +0000
+++ hedgewars-0.9.20.5/hedgewars/uWorld.pas 2014-01-08 16:25:17.000000000 +0000
@@ -60,9 +60,10 @@
, uCaptions
, uCursor
, uCommands
-{$IFDEF USE_VIDEO_RECORDING}
+ , uTeams
+{$IFDEF USE_VIDEO_RECORDING}
, uVideoRec
-{$ENDIF}
+{$ENDIF}
;
var cWaveWidth, cWaveHeight: LongInt;
@@ -85,6 +86,7 @@
AmmoMenuTex : PTexture;
HorizontOffset: LongInt;
cOffsetY: LongInt;
+ WorldEnd, WorldFade : array[0..3] of HwColor4f;
const cStereo_Sky = 0.0500;
cStereo_Horizon = 0.0250;
@@ -244,7 +246,7 @@
{$IFDEF USE_TOUCH_INTERFACE}
//positioning of the buttons
-buttonScale:= mobileRecord.getScreenDPI()/cDefaultZoomLevel;
+buttonScale:= 1 / cDefaultZoomLevel;
with JumpWidget do
@@ -891,7 +893,7 @@
glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
-Tint($FF, $FF, $FF, $FF);
+untint;
{for i:= -1 to cWaterSprCount do
DrawSprite(sprWater,
@@ -978,7 +980,7 @@
//glPushMatrix;
//glScalef(1.0, 1.0, 1.0);
- if (not isPaused) and (GameType <> gmtRecord) then
+ if (not isPaused) and (not isAFK) and (GameType <> gmtRecord) then
MoveCamera;
if cStereoMode = smNone then
@@ -1120,14 +1122,225 @@
stereoDepth:= 0;
{$ENDIF}
end;
-
+
+
+procedure RenderWorldEdge(Lag: Longword);
+var
+ VertexBuffer: array [0..3] of TVertex2f;
+ c1, c2: LongWord; // couple of colours for edges
+begin
+if WorldEdge <> weNone then
+ begin
+(* I think for a bounded world, will fill the left and right areas with black or something. Also will probably want various border effects/animations based on border type. Prob also, say, trigger a border animation timer on an impact. *)
+
+ glDisable(GL_TEXTURE_2D);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+
+ glPushMatrix;
+ glTranslatef(WorldDx, WorldDy, 0);
+ glColorPointer(4, GL_UNSIGNED_BYTE, 0, @WorldFade[0]);
+
+ VertexBuffer[0].X:= leftX-20;
+ VertexBuffer[0].Y:= -3000;
+ VertexBuffer[1].X:= leftX-20;
+ VertexBuffer[1].Y:= cWaterLine+cVisibleWater;
+ VertexBuffer[2].X:= leftX+30;
+ VertexBuffer[2].Y:= cWaterLine+cVisibleWater;
+ VertexBuffer[3].X:= leftX+30;
+ VertexBuffer[3].Y:= -3000;
+
+ glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
+
+ VertexBuffer[0].X:= rightX+20;
+ VertexBuffer[1].X:= rightX+20;
+ VertexBuffer[2].X:= rightX-30;
+ VertexBuffer[3].X:= rightX-30;
+
+ glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
+
+ glColorPointer(4, GL_UNSIGNED_BYTE, 0, @WorldEnd[0]);
+
+ VertexBuffer[0].X:= -5000;
+ VertexBuffer[1].X:= -5000;
+ VertexBuffer[2].X:= leftX-20;
+ VertexBuffer[3].X:= leftX-20;
+
+ glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
+
+ VertexBuffer[0].X:= rightX+5000;
+ VertexBuffer[1].X:= rightX+5000;
+ VertexBuffer[2].X:= rightX+20;
+ VertexBuffer[3].X:= rightX+20;
+
+ glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
+
+ glPopMatrix;
+ glDisableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glColor4ub($FF, $FF, $FF, $FF); // must not be Tint() as color array seems to stay active and color reset is required
+ glEnable(GL_TEXTURE_2D);
+
+ // I'd still like to have things happen to the border when a wrap or bounce just occurred, based on a timer
+ if WorldEdge = weBounce then
+ begin
+ // could maybe alternate order of these on a bounce, or maybe drop the outer ones.
+ if LeftImpactTimer mod 2 = 0 then
+ begin
+ c1:= $5454FFFF; c2:= $FFFFFFFF;
+ end
+ else begin
+ c1:= $FFFFFFFF; c2:= $5454FFFF;
+ end;
+ DrawLine(leftX, -3000, leftX, cWaterLine+cVisibleWater, 7.0, c1);
+ DrawLine(leftX, -3000, leftX, cWaterLine+cVisibleWater, 5.0, c2);
+ DrawLine(leftX, -3000, leftX, cWaterLine+cVisibleWater, 3.0, c1);
+ DrawLine(leftX, -3000, leftX, cWaterLine+cVisibleWater, 1.0, c2);
+ if RightImpactTimer mod 2 = 0 then
+ begin
+ c1:= $5454FFFF; c2:= $FFFFFFFF;
+ end
+ else begin
+ c1:= $FFFFFFFF; c2:= $5454FFFF;
+ end;
+ DrawLine(rightX, -3000, rightX, cWaterLine+cVisibleWater, 7.0, c1);
+ DrawLine(rightX, -3000, rightX, cWaterLine+cVisibleWater, 5.0, c2);
+ DrawLine(rightX, -3000, rightX, cWaterLine+cVisibleWater, 3.0, c1);
+ DrawLine(rightX, -3000, rightX, cWaterLine+cVisibleWater, 1.0, c2)
+ end
+ else if WorldEdge = weWrap then
+ begin
+ DrawLine(leftX, -3000, leftX, cWaterLine+cVisibleWater, 5.0, $A0, $30, $60, max(50,255-LeftImpactTimer));
+ DrawLine(leftX, -3000, leftX, cWaterLine+cVisibleWater, 2.0, $FF0000FF);
+ DrawLine(rightX, -3000, rightX, cWaterLine+cVisibleWater, 5.0, $A0, $30, $60, max(50,255-RightImpactTimer));
+ DrawLine(rightX, -3000, rightX, cWaterLine+cVisibleWater, 2.0, $FF0000FF);
+ end
+ else
+ begin
+ DrawLine(leftX, -3000, leftX, cWaterLine+cVisibleWater, 5.0, $2E8B5780);
+ DrawLine(rightX, -3000, rightX, cWaterLine+cVisibleWater, 5.0, $2E8B5780)
+ end;
+ if LeftImpactTimer > Lag then dec(LeftImpactTimer,Lag) else LeftImpactTimer:= 0;
+ if RightImpactTimer > Lag then dec(RightImpactTimer,Lag) else RightImpactTimer:= 0
+ end;
+end;
+
+
+procedure RenderTeamsHealth;
+var t, i, h, smallScreenOffset, TeamHealthBarWidth : LongInt;
+ r: TSDL_Rect;
+ highlight: boolean;
+ htex: PTexture;
+begin
+if TeamsCount * 20 > Longword(cScreenHeight) div 7 then // take up less screen on small displays
+ begin
+ SetScale(1.5);
+ smallScreenOffset:= cScreenHeight div 6;
+ if TeamsCount * 100 > Longword(cScreenHeight) then
+ Tint($FF,$FF,$FF,$80);
+ end
+else smallScreenOffset:= 0;
+for t:= 0 to Pred(TeamsCount) do
+ with TeamsArray[t]^ do
+ if TeamHealth > 0 then
+ begin
+ highlight:= bShowFinger and (CurrentTeam = TeamsArray[t]) and ((RealTicks mod 1000) < 500);
+
+ if highlight then
+ begin
+ Tint(Clan^.Color shl 8 or $FF);
+ htex:= GenericHealthTexture
+ end
+ else
+ htex:= Clan^.HealthTex;
+
+ // draw owner
+ if OwnerTex <> nil then
+ DrawTexture(-OwnerTex^.w - NameTagTex^.w - 18, cScreenHeight + DrawHealthY + smallScreenOffset, OwnerTex);
+
+ // draw name
+ DrawTexture(-NameTagTex^.w - 16, cScreenHeight + DrawHealthY + smallScreenOffset, NameTagTex);
+
+ // draw flag
+ DrawTexture(-14, cScreenHeight + DrawHealthY + smallScreenOffset, FlagTex);
+
+ TeamHealthBarWidth:= cTeamHealthWidth * TeamHealthBarHealth div MaxTeamHealth;
+
+ // draw health bar
+ r.x:= 0;
+ r.y:= 0;
+ r.w:= 2 + TeamHealthBarWidth;
+ r.h:= htex^.h;
+ DrawTextureFromRect(14, cScreenHeight + DrawHealthY + smallScreenOffset, @r, htex);
+
+ // draw health bars right border
+ inc(r.x, cTeamHealthWidth + 2);
+ r.w:= 3;
+ DrawTextureFromRect(TeamHealthBarWidth + 15, cScreenHeight + DrawHealthY + smallScreenOffset, @r, htex);
+
+ h:= 0;
+ if not hasGone then
+ for i:= 0 to cMaxHHIndex do
+ begin
+ inc(h, Hedgehogs[i].HealthBarHealth);
+ if (h < TeamHealthBarHealth) and (Hedgehogs[i].HealthBarHealth > 0) then
+ DrawTexture(15 + h * TeamHealthBarWidth div TeamHealthBarHealth, cScreenHeight + DrawHealthY + smallScreenOffset + 1, SpritesData[sprSlider].Texture);
+ end;
+
+ // draw ai kill counter for gfAISurvival
+ if (GameFlags and gfAISurvival) <> 0 then
+ begin
+ DrawTexture(TeamHealthBarWidth + 22, cScreenHeight + DrawHealthY + smallScreenOffset, AIKillsTex);
+ end;
+
+ // if highlighted, draw flag and other contents again to keep their colors
+ // this approach should be faster than drawing all borders one by one tinted or not
+ if highlight then
+ begin
+ if TeamsCount * 100 > Longword(cScreenHeight) then
+ Tint($FF,$FF,$FF,$80)
+ else untint;
+
+ if OwnerTex <> nil then
+ begin
+ r.x:= 2;
+ r.y:= 2;
+ r.w:= OwnerTex^.w - 4;
+ r.h:= OwnerTex^.h - 4;
+ DrawTextureFromRect(-OwnerTex^.w - NameTagTex^.w - 16, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, OwnerTex)
+ end;
+ // draw name
+ r.x:= 2;
+ r.y:= 2;
+ r.w:= NameTagTex^.w - 4;
+ r.h:= NameTagTex^.h - 4;
+ DrawTextureFromRect(-NameTagTex^.w - 14, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, NameTagTex);
+ // draw flag
+ r.w:= 22;
+ r.h:= 15;
+ DrawTextureFromRect(-12, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, FlagTex);
+ end;
+ end;
+if smallScreenOffset <> 0 then
+ begin
+ SetScale(cDefaultZoomLevel);
+ if TeamsCount * 20 > Longword(cScreenHeight) div 5 then
+ Tint($FF,$FF,$FF,$FF);
+ end;
+end;
+
+
procedure DrawWorldStereo(Lag: LongInt; RM: TRenderMode);
-var i, t, h: LongInt;
+var i, t: LongInt;
r: TSDL_Rect;
tdx, tdy: Double;
s: shortstring;
- highlight: Boolean;
- smallScreenOffset, offsetX, offsetY, screenBottom: LongInt;
+ offsetX, offsetY, screenBottom: LongInt;
VertexBuffer: array [0..3] of TVertex2f;
begin
if (cReducedQuality and rqNoBackground) = 0 then
@@ -1148,7 +1361,7 @@
ChangeDepth(RM, -cStereo_Horizon);
DrawRepeated(sprHorizont, sprHorizontL, sprHorizontR, (WorldDx + LAND_WIDTH div 2) * 3 div 5, HorizontOffset);
if SuddenDeathDmg then
- Tint($FF, $FF, $FF, $FF);
+ untint;
end;
DrawVisualGears(0);
@@ -1235,41 +1448,46 @@
end;
{$WARNINGS ON}
+RenderWorldEdge(Lag);
+
// this scale is used to keep the various widgets at the same dimension at all zoom levels
SetScale(cDefaultZoomLevel);
// Turn time
+if UIDisplay <> uiNone then
+ begin
{$IFDEF USE_TOUCH_INTERFACE}
-offsetX:= cScreenHeight - 13;
+ offsetX:= cScreenHeight - 13;
{$ELSE}
-offsetX:= 48;
+ offsetX:= 48;
{$ENDIF}
-offsetY:= cOffsetY;
-if ((TurnTimeLeft <> 0) and (TurnTimeLeft < 1000000)) or (ReadyTimeLeft <> 0) then
- begin
- if ReadyTimeLeft <> 0 then
- i:= Succ(Pred(ReadyTimeLeft) div 1000)
- else
- i:= Succ(Pred(TurnTimeLeft) div 1000);
-
- if i>99 then
- t:= 112
- else if i>9 then
- t:= 96
- else
- t:= 80;
- DrawSprite(sprFrame, -(cScreenWidth shr 1) + t + offsetY, cScreenHeight - offsetX, 1);
- while i > 0 do
- begin
- dec(t, 32);
- DrawSprite(sprBigDigit, -(cScreenWidth shr 1) + t + offsetY, cScreenHeight - offsetX, i mod 10);
- i:= i div 10
+ offsetY:= cOffsetY;
+ if ((TurnTimeLeft <> 0) and (TurnTimeLeft < 1000000)) or (ReadyTimeLeft <> 0) then
+ begin
+ if ReadyTimeLeft <> 0 then
+ i:= Succ(Pred(ReadyTimeLeft) div 1000)
+ else
+ i:= Succ(Pred(TurnTimeLeft) div 1000);
+
+ if i>99 then
+ t:= 112
+ else if i>9 then
+ t:= 96
+ else
+ t:= 80;
+ DrawSprite(sprFrame, -(cScreenWidth shr 1) + t + offsetY, cScreenHeight - offsetX, 1);
+ while i > 0 do
+ begin
+ dec(t, 32);
+ DrawSprite(sprBigDigit, -(cScreenWidth shr 1) + t + offsetY, cScreenHeight - offsetX, i mod 10);
+ i:= i div 10
+ end;
+ DrawSprite(sprFrame, -(cScreenWidth shr 1) + t - 4 + offsetY, cScreenHeight - offsetX, 0);
end;
- DrawSprite(sprFrame, -(cScreenWidth shr 1) + t - 4 + offsetY, cScreenHeight - offsetX, 0);
- end;
// Captions
-DrawCaptions;
+ DrawCaptions
+ end;
{$IFDEF USE_TOUCH_INTERFACE}
// Draw buttons Related to the Touch interface
@@ -1285,106 +1503,16 @@
DrawScreenWidget(@utilityWidget);
{$ENDIF}
-// Teams Healths
-if TeamsCount * 20 > Longword(cScreenHeight) div 7 then // take up less screen on small displays
- begin
- SetScale(1.5);
- smallScreenOffset:= cScreenHeight div 6;
- if TeamsCount * 20 > Longword(cScreenHeight) div 5 then
- Tint($FF,$FF,$FF,$80);
- end
-else smallScreenOffset:= 0;
-for t:= 0 to Pred(TeamsCount) do
- with TeamsArray[t]^ do
- if TeamHealth > 0 then
- begin
- h:= 0;
- highlight:= bShowFinger and (CurrentTeam = TeamsArray[t]) and ((RealTicks mod 1000) < 500);
-
- if highlight then
- Tint(Clan^.Color shl 8 or $FF);
-
- // draw name
- DrawTexture(-NameTagTex^.w - 16, cScreenHeight + DrawHealthY + smallScreenOffset, NameTagTex);
-
- // draw flag
- DrawTexture(-14, cScreenHeight + DrawHealthY + smallScreenOffset, FlagTex);
-
- // draw health bar
- r.x:= 0;
- r.y:= 0;
- r.w:= 2 + TeamHealthBarWidth;
- r.h:= HealthTex^.h;
- DrawTextureFromRect(14, cScreenHeight + DrawHealthY + smallScreenOffset, @r, HealthTex);
-
- // draw health bars right border
- inc(r.x, cTeamHealthWidth + 2);
- r.w:= 3;
- DrawTextureFromRect(TeamHealthBarWidth + 15, cScreenHeight + DrawHealthY + smallScreenOffset, @r, HealthTex);
-
- if not highlight and (not hasGone) then
- for i:= 0 to cMaxHHIndex do
- if Hedgehogs[i].Gear <> nil then
- begin
- inc(h,Hedgehogs[i].Gear^.Health);
- if h < TeamHealth then DrawTexture(15 + h*TeamHealthBarWidth div TeamHealth, cScreenHeight + DrawHealthY + smallScreenOffset + 1, SpritesData[sprSlider].Texture);
- end;
-
- // draw ai kill counter for gfAISurvival
- if (GameFlags and gfAISurvival) <> 0 then
- begin
- DrawTexture(TeamHealthBarWidth + 22, cScreenHeight + DrawHealthY + smallScreenOffset, AIKillsTex);
- end;
-
- // if highlighted, draw flag and other contents again to keep their colors
- // this approach should be faster than drawing all borders one by one tinted or not
- if highlight then
- begin
- if TeamsCount * 20 > Longword(cScreenHeight) div 5 then
- Tint($FF,$FF,$FF,$80)
- else Tint($FF, $FF, $FF, $FF);
-
- // draw name
- r.x:= 2;
- r.y:= 2;
- r.w:= NameTagTex^.w - 4;
- r.h:= NameTagTex^.h - 4;
- DrawTextureFromRect(-NameTagTex^.w - 14, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, NameTagTex);
- // draw flag
- r.w:= 22;
- r.h:= 15;
- DrawTextureFromRect(-12, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, FlagTex);
- // draw health bar
- r.w:= TeamHealthBarWidth + 1;
- r.h:= HealthTex^.h - 4;
- DrawTextureFromRect(15, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, HealthTex);
- if not hasGone and (TeamHealth > 1) then
- begin
- Tint(Clan^.Color shl 8 or $FF);
- for i:= 0 to cMaxHHIndex do
- if Hedgehogs[i].Gear <> nil then
- begin
- inc(h,Hedgehogs[i].Gear^.Health);
- if h < TeamHealth then DrawTexture(15 + h*TeamHealthBarWidth div TeamHealth, cScreenHeight + DrawHealthY + smallScreenOffset + 1, SpritesData[sprSlider].Texture);
- end;
- if TeamsCount * 20 > Longword(cScreenHeight) div 5 then
- Tint($FF,$FF,$FF,$80)
- else Tint($FF, $FF, $FF, $FF);
- end;
- end;
- end;
-if smallScreenOffset <> 0 then
- begin
- SetScale(cDefaultZoomLevel);
- if TeamsCount * 20 > Longword(cScreenHeight) div 5 then
- Tint($FF,$FF,$FF,$FF);
- end;
+if UIDisplay = uiAll then
+ RenderTeamsHealth;
// Lag alert
if isInLag then
DrawSprite(sprLag, 32 - (cScreenWidth shr 1), 32, (RealTicks shr 7) mod 12);
// Wind bar
+if UIDisplay <> uiNone then
+ begin
{$IFDEF USE_TOUCH_INTERFACE}
offsetX:= cScreenHeight - 13;
offsetY:= (cScreenWidth shr 1) + 74;
@@ -1406,14 +1534,15 @@
else
if WindBarWidth < 0 then
begin
- {$WARNINGS OFF}
- r.x:= (Longword(WindBarWidth) + RealTicks shr 6) mod 8;
- {$WARNINGS ON}
- r.y:= 0;
- r.w:= - WindBarWidth;
- r.h:= 13;
- DrawSpriteFromRect(sprWindL, r, (cScreenWidth shr 1) - offsetY + 74 + WindBarWidth, cScreenHeight - offsetX + 2, 13, 0);
- end;
+ {$WARNINGS OFF}
+ r.x:= (Longword(WindBarWidth) + RealTicks shr 6) mod 8;
+ {$WARNINGS ON}
+ r.y:= 0;
+ r.w:= - WindBarWidth;
+ r.h:= 13;
+ DrawSpriteFromRect(sprWindL, r, (cScreenWidth shr 1) - offsetY + 74 + WindBarWidth, cScreenHeight - offsetX + 2, 13, 0);
+ end
+ end;
// AmmoMenu
if bShowAmmoMenu and ((AMState = AMHidden) or (AMState = AMHiding)) then
@@ -1448,6 +1577,8 @@
DrawTextureCentered(0, (cScreenHeight shr 1), SyncTexture);
if isPaused then
DrawTextureCentered(0, (cScreenHeight shr 1), PauseTexture);
+if isAFK then
+ DrawTextureCentered(0, (cScreenHeight shr 1), AFKTexture);
if not isFirstFrame and (missionTimer <> 0) or isPaused or fastUntilLag or (GameState = gsConfirm) then
begin
if (ReadyTimeLeft = 0) and (missionTimer > 0) then
@@ -1554,7 +1685,7 @@
glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
glEnable(GL_TEXTURE_2D);
- Tint($FF, $FF, $FF, $FF);
+ untint;
if not isFirstFrame and ((ScreenFadeValue = 0) or (ScreenFadeValue = sfMax)) then
ScreenFade:= sfNone
end
@@ -1582,7 +1713,7 @@
for i:= 0 to 20 do
glVertex2f(-(cScreenWidth shr 1) + 30 + sin(i*2*Pi/20)*10, 35 + cos(i*2*Pi/20)*10);
glEnd();
- Tint($FF, $FF, $FF, $FF);
+ untint;
glEnable(GL_TEXTURE_2D);
end;
{$ENDIF}
@@ -1631,20 +1762,22 @@
DrawSprite(sprArrow, TargetCursorPoint.X, cScreenHeight - TargetCursorPoint.Y, (RealTicks shr 6) mod 8)
end
end;
-isFirstFrame:= false
+isFirstFrame:= false;
end;
var PrevSentPointTime: LongWord = 0;
procedure MoveCamera;
var EdgesDist, wdy, shs,z, amNumOffsetX, amNumOffsetY: LongInt;
+ inbtwnTrgtAttks: Boolean;
begin
{$IFNDEF MOBILE}
if (not (CurrentTeam^.ExtDriven and isCursorVisible and (not bShowAmmoMenu) and autoCameraOn)) and cHasFocus and (GameState <> gsConfirm) then
uCursor.updatePosition();
{$ENDIF}
z:= round(200/zoom);
-if not PlacingHogs and (FollowGear <> nil) and (not isCursorVisible) and (not bShowAmmoMenu) and (not fastUntilLag) and autoCameraOn then
+inbtwnTrgtAttks := (CurrentHedgehog <> nil) and ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0) and ((GameFlags and gfInfAttack) <> 0);
+if autoCameraOn and not PlacingHogs and (FollowGear <> nil) and (not isCursorVisible) and (not bShowAmmoMenu) and (not fastUntilLag) and not inbtwnTrgtAttks then
if ((abs(CursorPoint.X - prevPoint.X) + abs(CursorPoint.Y - prevpoint.Y)) > 4) then
begin
FollowGear:= nil;
@@ -1899,6 +2032,16 @@
AMState:= AMHidden;
isFirstFrame:= true;
stereoDepth:= stereoDepth; // avoid hint
+
+ FillChar(WorldFade, sizeof(WorldFade), 0);
+ WorldFade[0].a:= 255;
+ WorldFade[1].a:= 255;
+ FillChar(WorldEnd, sizeof(WorldEnd), 0);
+ WorldEnd[0].a:= 255;
+ WorldEnd[1].a:= 255;
+ WorldEnd[2].a:= 255;
+ WorldEnd[3].a:= 255;
+
end;
procedure freeModule;
diff -Nru hedgewars-0.9.19.3/misc/Android.mk hedgewars-0.9.20.5/misc/Android.mk
--- hedgewars-0.9.19.3/misc/Android.mk 2013-06-03 08:01:42.000000000 +0000
+++ hedgewars-0.9.20.5/misc/Android.mk 2013-10-31 20:21:51.000000000 +0000
@@ -1,9 +1,7 @@
MISC_DIR := $(call my-dir)
LOCAL_PATH := MISC_DIR
-include $(MISC_DIR)/libfreetype/Android.mk
include $(MISC_DIR)/liblua/Android.mk
-include $(MISC_DIR)/libtremor/Android.mk
include $(MISC_DIR)/libphysfs/Android.mk
include $(MISC_DIR)/libphyslayer/Android.mk
Binary files /tmp/zU_wHb8V4z/hedgewars-0.9.19.3/misc/dmgBackground.png and /tmp/ldTWNrTPZC/hedgewars-0.9.20.5/misc/dmgBackground.png differ
diff -Nru hedgewars-0.9.19.3/misc/libfreetype/Android.mk hedgewars-0.9.20.5/misc/libfreetype/Android.mk
--- hedgewars-0.9.19.3/misc/libfreetype/Android.mk 2012-12-19 16:09:07.000000000 +0000
+++ hedgewars-0.9.20.5/misc/libfreetype/Android.mk 1970-01-01 00:00:00.000000000 +0000
@@ -1,45 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# compile in ARM mode, since the glyph loader/renderer is a hotspot
-# when loading complex pages in the browser
-#
-LOCAL_ARM_MODE := arm
-
-LOCAL_SRC_FILES:= \
- src/base/ftbbox.c \
- src/base/ftbitmap.c \
- src/base/ftglyph.c \
- src/base/ftstroke.c \
- src/base/ftxf86.c \
- src/base/ftbase.c \
- src/base/ftsystem.c \
- src/base/ftinit.c \
- src/base/ftgasp.c \
- src/raster/raster.c \
- src/sfnt/sfnt.c \
- src/smooth/smooth.c \
- src/autofit/autofit.c \
- src/truetype/truetype.c \
- src/cff/cff.c \
- src/psnames/psnames.c \
- src/pshinter/pshinter.c
-
-LOCAL_C_INCLUDES += \
- $(LOCAL_PATH)/builds \
- $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS += -W -Wall
-LOCAL_CFLAGS += -fPIC -DPIC
-LOCAL_CFLAGS += "-DDARWIN_NO_CARBON"
-LOCAL_CFLAGS += "-DFT2_BUILD_LIBRARY"
-
-# the following is for testing only, and should not be used in final builds
-# of the product
-#LOCAL_CFLAGS += "-DTT_CONFIG_OPTION_BYTECODE_INTERPRETER"
-
-LOCAL_CFLAGS += -O2
-
-LOCAL_MODULE:= freetype
-
-include $(BUILD_STATIC_LIBRARY)
diff -Nru hedgewars-0.9.19.3/misc/libfreetype/ChangeLog hedgewars-0.9.20.5/misc/libfreetype/ChangeLog
--- hedgewars-0.9.19.3/misc/libfreetype/ChangeLog 2012-12-19 16:09:07.000000000 +0000
+++ hedgewars-0.9.20.5/misc/libfreetype/ChangeLog 1970-01-01 00:00:00.000000000 +0000
@@ -1,2243 +0,0 @@
-2011-04-22 suzuki toshiya
-
- [autofit] Add more Indic scripts with hanging baseline.
-
- * src/autofit/afindic.c (af_indic_uniranges): Tibetan, Limbu,
- Sundanese, Meetei Mayak, Syloti Nagri and Sharada scripts are
- added.
-
-2011-04-21 Behdad Esfahbod
-
- Always ignore global advance.
-
- This makes FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH redundant,
- deprecated, and ignored. The new behavior is what every major user
- of FreeType has been requesting. Global advance is broken in many
- CJK fonts. Just ignoring it by default makes most sense.
-
- * src/truetype/ttdriver.c (tt_get_advances),
- src/truetype/ttgload.c (TT_Get_HMetrics, TT_Get_VMetrics,
- tt_get_metrics, compute_glyph_metrics, TT_Load_Glyph),
- src/truetype/ttgload.h: Implement it.
-
- * docs/CHANGES: Updated.
-
-2011-04-21 rainy6144
-
- [autofit] Blur CJK stems if too many to preserve their gaps.
-
- When there are too many stems to preserve their gaps in the
- rasterization of CJK Ideographs at a low resolution, blur the
- stems instead of showing clumped stems. See
- http://lists.gnu.org/archive/html/freetype-devel/2011-02/msg00011.html
- http://lists.gnu.org/archive/html/freetype-devel/2011-04/msg00046.html
- for details.
-
- * src/autofit/afcjk.c (af_cjk_hint_edges): Store the position of
- the previous stem by `has_last_stem' and `last_stem_pos', and skip
- a stem if the current and previous stem are too near to preserve
- the gap.
-
-2011-04-18 Werner Lemberg
-
- Integrate autofitter debugging stuff.
-
- * devel/ftoption.h, include/freetype/config/ftoption.h
- (FT_DEBUG_AUTOFIT): New macro.
-
- * include/freetype/internal/fttrace.h: Add trace components for
- autofitter.
-
- * src/autofit/aftypes.h (AF_LOG): Removed.
- (_af_debug): Removed.
-
- * src/autofit/*: s/AF_DEBUG/FT_DEBUG_AUTOFIT/.
- s/AF_LOG/FT_TRACE5/.
- Define FT_COMPONENT where necessary.
-
-2011-04-18 Werner Lemberg
-
- Synchronize config files.
-
- * builds/unix/ftconfig.in: Copy missing assembler routines from
- include/freetype/config/ftconfig.h.
-
-2011-04-13 Werner Lemberg
-
- Fix Savannah bug #33047.
-
- Patch submitted by anonymous reporter.
-
- * src/psaux/psobjs.c (ps_table_add): Use FT_PtrDist for pointer
- difference.
-
-2011-04-11 Kan-Ru Chen
-
- Fix reading of signed integers from files on 64bit platforms.
-
- Previously, signed integers were converted to unsigned integers, but
- this can fail because of sign extension. For example, 0xa344a1eb
- becomes 0xffffffffa344a1eb.
-
- We now do the reverse which is always correct because the integer
- size is the same during the cast from unsigned to signed.
-
- * include/freetype/internal/ftstream.h, src/base/ftstream.c
- (FT_Stream_Get*): Replace with...
- (FT_Stream_GetU*): Functions which read unsigned integers.
- Update all macros accordingly.
-
- * src/gzip/ftgzip.c (ft_gzip_get_uncompressed_size): Updated.
-
-2011-04-07 Werner Lemberg
-
- Update Unicode ranges for CJK autofitter; in particular, add Hangul.
-
- * src/autofit/afcjk.c (af_cjk_uniranges): Update to Unicode 6.0.
-
-2011-04-04 Werner Lemberg
-
- Fix formatting of autofit debug dumps.
-
- * src/autofit/afhints.c (af_glyph_hints_dump_points,
- af_glyph_hints_dump_segments, af_glyph_hints_dump_edges): Adjust
- column widths.
-
-2011-03-30 Werner Lemberg
-
- * src/autofit/aftypes.h (AF_OutlineRec): Removed, unused.
-
-2011-03-24 Werner Lemberg
-
- * src/cff/cfftypes.h (CFF_MAX_CID_FONTS): Increase to 256.
- This limit is given on p. 37 of Adobe Technical Note #5014.
-
-2011-03-23 Werner Lemberg
-
- * src/truetype/ttpload.c (tt_face_load_loca): Fix mismatch warning.
-
-2011-03-20 Werner Lemberg
-
- * src/sfnt/sfobjs.c (sfnt_open_font): Check number of TTC subfonts.
-
-2011-03-19 Werner Lemberg
-
- More C++ compilation fixes.
-
- * src/autofit/afhints.c (af_glyph_hints_dump_points,
- af_glyph_hints_dump_segments, af_glyph_hints_dump_edges)
- [__cplusplus]: Protect with `extern "C"'.
-
-2011-03-18 Werner Lemberg
-
- C++ compilation fixes.
-
- * src/autofit/aflatin.c (af_latin_hints_apply), src/autofit/afcjk.c
- (af_cjk_hints_apply): Use cast for `dim'.
-
-2011-03-17 Alexei Podtelezhnikov
-
- A better fix for Savannah bug #32671.
-
- * src/smooth/ftgrays.c (gray_render_conic): Clean up code and
- replace WHILE loop with a more natural DO-WHILE construct.
-
-2011-03-16 Werner Lemberg .
-
- * src/base/ftstroke.c (FT_StrokerRec): Remove unused `valid' field.
- Suggested by Graham Asher.
-
-2011-03-09 Werner Lemberg
-
- Make FT_Sfnt_Table_Info return the number of SFNT tables.
-
- * src/sfnt/sfdriver.c (sfnt_table_info): Implement it.
- * include/freetype/tttables.h: Update documentation.
- * docs/CHANGES: Updated.
-
-2011-03-07 Bram Tassyns
-
- Fix Savannah bug #27988.
-
- * src/cff/cffobjs.c (remove_style): New function.
- (cff_face_init): Use it to strip off the style part of the family
- name.
-
-2011-03-07 Werner Lemberg
-
- * docs/CHANGES: Updated.
-
-2011-03-07 Alexei Podtelezhnikov
-
- Quick fix for Savannah bug #32671.
-
- This isn't the optimal solution yet, but it restores the previous
- rendering quality (more or less).
-
- * src/smooth/ftgrays.c (gray_render_conic): Do more splitting.
-
-2011-03-06 Werner Lemberg
-
- Fix autohinting fallback.
-
- * src/base/ftobjs.c (FT_Load_Glyph): Assure that we only check TTFs,
- ignoring CFF-based OTFs.
-
-2011-02-27 Werner Lemberg
-
- Add AF_CONFIG_OPTION_USE_WARPER to control the autofit warper.
-
- * devel/ftoption.h, include/freetype/config/ftoption.h
- (AF_CONFIG_OPTION_USE_WARPER): New macro.
- * src/autofit/aftypes.h (AF_USE_WARPER): Remove.
-
- * src/autofit/*: s/AF_USE_WARPER/AF_CONFIG_OPTION_USE_WARPER/.
-
- * src/autofit/afwarp.c [!AF_CONFIG_OPTION_USE_WARPER]: Replace dummy
- variable assignment with a typedef.
-
-2011-02-26 Werner Lemberg
-
- [autofit] Slight simplifications.
-
- * src/autofit/aflatin.c (af_latin_hints_link_segments): Remove
- test which always returns false.
- (af_latin_hints_compute_blue_edges): Remove redundant assignment.
-
-2011-02-24 Werner Lemberg
-
- * docs/PROBLEMS: Mention rendering differences on different
- platforms.
- Suggested and worded by Jason Owen .
-
-2011-02-24 Werner Lemberg
-
- [autofit] Comment out unused code.
-
- * src/autofit/aflatin.c, src/autofit/aflatin2.c
- (af_latin_hints_compute_edges): Do it.
-
-2011-02-24 Werner Lemberg
-
- * src/autofit/afhints.h (AF_GlyphHints): Remove unused field.
-
-2011-02-20 suzuki toshiya
-
- [cache] Fix an off-by-one bug in `FTC_Manager_RemoveFaceID'.
- Found by , see detail in
-
- http://lists.gnu.org/archive/html/freetype/2011-01/msg00023.html
-
- * src/cache/ftccache.c (FTC_Cache_RemoveFaceID): Check the node
- buckets[cache->p + cache->mask] too.
-
-2011-02-19 Kevin Kofler
-
- Fall back to autohinting if a TTF/OTF doesn't contain any bytecode.
- This is Savannah patch #7471.
-
- * src/base/ftobjs.c (FT_Load_Glyph): Implement it.
-
-2011-02-19 John Tytgat
-
- [cff] Fix subset prefix removal.
- This is Savannah patch #7465.
-
- * src/cff/cffobjs.c (remove_subset_prefix): Update length after
- subset prefix removal.
-
-2011-02-13 Bradley Grainger
-
- Add inline assembly version of FT_MulFix for MSVC.
-
- * include/freetype/config/ftconfig.h: Ported the FT_MulFix_i386
- function from GNU inline assembly syntax (see #ifdef __GNUC__ block
- above) to MASM syntax for Microsoft Visual C++.
-
-2011-02-13 Bradley Grainger
-
- Add project and solution files in Visual Studio 2010 format.
-
- * builds/win32/.gitignore: Ignore user-specific cache files.
- * builds/win32/vc2010/: Add VS2010 project & solution files, created
- by upgrading builds/win32/vc2008/freetype.vcproj.
- * objs/.gitignore: Ignore Visual Studio output files.
-
-2011-02-01 Werner Lemberg
-
- * src/autofit/afdummy.c: Include `aferrors.h'.
- Problem reported by Chris Liddel .
-
-2011-02-01 Werner Lemberg
-
- [cff] Ignore unknown operators in charstrings.
- Patch suggested by Miles.Lau .
-
- * src/cff/cffgload.c (cff_decoder_parse_charstrings): Emit tracing
- message for unknown operators and continue instead of exiting with a
- syntax error.
-
-2011-02-01 Werner Lemberg
-
- [truetype] FT_LOAD_PEDANTIC now affects `prep' and `fpgm' also.
-
- * src/truetype/ttgload.c (tt_loader_init): Handle
- `FT_LOAD_PEDANTIC'.
- * src/truetype/ttobjs.c (tt_size_run_fpgm, tt_size_run_prep,
- tt_size_init_bytecode, tt_size_ready_bytecode): New argument to
- handle pedantic mode.
- * src/truetype/ttobjs.h: Updated.
-
-2011-01-31 Werner Lemberg
-
- [truetype] Protect jump instructions against endless loops.
-
- * src/truetype/interp.c (DO_JROT, DO_JMPR, DO_JROF): Exit with error
- if offset is zero.
-
-2011-01-31 Werner Lemberg
-
- [truetype] Improve handling of invalid references.
-
- * src/truetype/interp.c: Set even more TT_Err_Invalid_Reference
- error codes only if pedantic hinting is active. At the same time,
- try to provide sane values which hopefully allow useful
- continuation. Exception to this is CALL and LOOPCALL – due to
- possible stack corruption it is necessary to bail out.
-
-2011-01-31 Werner Lemberg
-
- [truetype] Improve handling of stack underflow.
-
- * src/truetype/ttinterp.c (TT_RunIns, Ins_FLIPPT, Ins_DELTAP,
- Ins_DELTAC): Exit with error only if `pedantic_hinting' is set.
- Otherwise, try to do something sane.
-
-2011-01-30 Werner Lemberg
-
- * src/sfnt/ttmtx.c (tt_face_load_hmtx): Fix tracing message.
-
-2011-01-30 LIU Sun-Liang
-
- [truetype]: Fix behaviour of MIAP for invalid arguments.
-
- * src/truetype/ttinterp.c (Ins_MIAP): Set reference points even in
- case of error.
-
-2011-01-18 Werner Lemberg
-
- [truetype] Fix handling of MIRP instruction.
-
- Thanks to Greg Hitchcock who explained the issue.
-
- * src/truetype/ttinterp.c (Ins_MIRP): Replace a `>=' operator with
- `>' since the description in the specification is incorrect.
- This fixes, for example, glyph `two' in font `Helvetica Neue LT Com
- 65 medium' at 15ppem.
-
-2011-01-15 suzuki toshiya
-
- Fix ARM assembly code in include/freetype/config/ftconfig.h.
-
- * include/freetype/config/ftconfig.h (FT_MulFix_arm):
- Copy the maintained code from builds/unix/ftconfig.in.
- Old GNU binutils could not accept the reduced syntax
- `orr %0, %2, lsl #16'. Un-omitted syntax like RVCT,
- `orr %0, %0, %2, lsl #16' is better. Reported by
- Johnson Y. Yan. The bug report by Qt developers is
- considered too.
-
- http://bugreports.qt.nokia.com/browse/QTBUG-6521
-
-2011-01-15 Werner Lemberg
-
- [raster] Make bbox handling the same as with Microsoft's rasterizer.
-
- Right before B/W rasterizing, the bbox gets simply rounded to
- integers. This fixes, for example, glyph `three' in font `Helvetica
- Neue LT Com 65 Medium' at 11ppem.
-
- Thanks to Greg Hitchcock who explained this behaviour.
-
- * src/raster/ftrend1.c (ft_raster1_render): Implement it.
-
-2011-01-15 suzuki toshiya
-
- Copy -mcpu=* & -march=* options from CFLAGS to LDFLAGS.
-
- * builds/unix/configure.raw: Consider recent gcc-standard
- flags to specify architecture in CFLAGS & LDFLAGS
- harmonization. Requested by Savannah bug #32114, to
- support multilib feature of BuildRoot SDK correctly.
-
-2011-01-15 suzuki toshiya
-
- Fix off-by-one bug in CFLAGS & LDFLAGS harmonizer.
-
- * builds/unix/configure.raw: Some important options that
- included in CFLAGS but not in LDFLAGS are copied to
- LDFLAGS, but the last option in CFLAGS was not checked.
-
-2011-01-13 Werner Lemberg
-
- [raster] Add undocumented drop-out rule to the other bbox side also.
-
- * src/raster/ftraster.c (Vertical_Sweep_Drop,
- Horizontal_Sweep_Drop): Implement it.
-
-2011-01-13 Werner Lemberg
-
- [raster] Reduce jitter value.
-
- This catches a rendering problem with glyph `x' from Tahoma at
- 10ppem. It seems that the increase of the precision in the change
- from 2009-06-11 makes a larger jitter value unnecessary.
-
- * src/raster/ftraster.c (Set_High_Precision): Implement it.
-
-2011-01-13 Werner Lemberg
-
- [raster] Handle drop-outs at glyph borders according to Microsoft.
-
- If a drop-out rule would switch on a pixel outside of the glyph's
- bounding box, use the right (or top) pixel instead. This is an
- undocumented feature, but some fonts like `Helvetica Neue LT Com 65
- Medium' heavily rely on it.
-
- Thanks to Greg Hitchcock who explained this behaviour.
-
- * src/raster/ftraster.c (Vertical_Sweep_Drop,
- Horizontal_Sweep_Drop): Implement it.
-
-2011-01-09 suzuki toshiya
-
- [cache] Fix Savannah bug #31923, patch drafted by Harsha.
-
- When a node comparator changes the cached nodes during the
- search of a node matching with queried properties, the
- pointers obtained before the function should be updated to
- prevent the dereference to freed or reallocated nodes.
- To minimize the rescan of the linked list, the update is
- executed when the comparator notifies the change of cached
- nodes. This change depends previous change:
- 38b272ffbbdaae276d636aec4ef84af407d16181
-
- * src/cache/ftccache.h (FTC_CACHE_LOOKUP_CMP): Rescan the
- top node if the cached nodes are changed.
- * src/cache/ftccache.c (FTC_Cache_Lookup): Ditto.
-
-2011-01-09 suzuki toshiya
-
- [cache] Notice if a cache query induced the node list change.
-
- Some node comparators (comparing the cache node contents and the
- properties specified by the query) can flush the cache node to
- prevent the cache inflation. The change may invalidate the pointers
- to the node obtained before the node comparison, so it should be
- noticed to the caller. The problem caused by the cache node
- changing is reported by Harsha, see Savannah bug #31923.
-
- * src/cache/ftccache.h (FTC_Node_CompareFunc): Add new argument
- `FT_Bool* list_changed' to indicate the change of the cached nodes
- to the caller.
- (FTC_CACHE_LOOKUP_CMP): Watch the change of the cached nodes by
- `_list_changed'.
- (FTC_CACHE_TRYLOOP_END): Take new macro argument `_list_changed'
- and update it when `FTC_Manager_FlushN' flushes any nodes.
-
- * src/cache/ftccback.h (ftc_snode_compare): Updated to fit with new
- FTC_Node_CompareFunc type.
- (ftc_gnode_compare): Ditto.
-
- * src/cache/ftcbasic.c: Include FT_INTERNAL_OBJECTS_H to use
- TRUE/FALSE macros.
- (ftc_basic_gnode_compare_faceid): New argument `FT_Bool*
- list_changed' to indicate the change of the cache nodes (anyway, it
- is always FALSE).
-
- * src/cache/ftccmap.c: Include FT_INTERNAL_OBJECTS_H to use
- TRUE/FALSE macros.
- (ftc_cmap_node_compare): New argument `FT_Bool* list_changed' to
- indicate the change of the cache nodes (anyway, it is always FALSE).
- (ftc_cmap_node_remove_faceid): Ditto.
-
- * src/cache/ftccache.c (FTC_Cache_NewNode): Pass a NULL pointer to
- `FTC_CACHE_TRYLOOP_END', because the result is not needed.
- (FTC_Cache_Lookup): Watch the change of the cache nodes by
- `list_changed'.
- (FTC_Cache_RemoveFaceID): Ditto.
-
- * src/cache/ftcglyph.c: Include FT_INTERNAL_OBJECTS_H to use
- TRUE/FALSE macros.
- (ftc_gnode_compare): New argument `FT_Bool* list_changed' to
- indicate the change of the cache nodes (anyway, it is always FALSE).
- (FTC_GNode_Compare): New argument `FT_Bool* list_changed' to be
- passed to `ftc_gnode_compare'.
- * src/cache/ftcglyph.h (FTC_GNode_Compare): Ditto.
-
- * src/cache/ftcsbits.c (ftc_snode_compare): New argument `FT_Bool*
- list_changed' to indicate the change of the cache nodes, anyway. It
- is updated by `FTC_CACHE_TRYLOOP'.
- (FTC_SNode_Compare): New argument `FT_Bool* list_changed' to be
- passed to `ftc_snode_compare'.
- * src/cache/ftcsbits.h (FTC_SNode_Compare): Ditto.
-
-2011-01-09 suzuki toshiya
-
- [cache] Fit `FTC_GNode_Compare' to `FTC_Node_CompareFunc'.
-
- * src/cache/ftcglyph.h (FTC_GNode_Compare): Add the 3rd
- argument `FTC_Cache cache' to fit FTC_Node_CompareFunc
- prototype.
- * src/cache/ftcglyph.c (FTC_GNode_Compare): Ditto. Anyway,
- `cache' is not used by its child `ftc_gnode_compare'.
-
-2011-01-09 suzuki toshiya
-
- [cache] Deduplicate the code to get the top node by a hash.
-
- There are several duplicated code fragments getting the top node
- from a cache by a given hash, like:
-
- idx = hash & cache->mask;
- if ( idx < cache->p )
- idx = hash & ( cache->mask * 2 + 1 );
- pnode = cache->buckets + idx;
-
- To remove duplication, a cpp-macro to do same work
- `FTC_NODE__TOP_FOR_HASH' is introduced. For non-inlined
- configuration, non-`ftc_get_top_node_for_hash' is also introduced.
-
- * src/cache/ftccache.h (FTC_NODE__TOP_FOR_HASH): Declare
- and implement inlined version.
- (FTC_CACHE_LOOKUP_CMP): Use `FTC_NODE__TOP_FOR_HASH'.
- * src/cache/ftccache.c (ftc_get_top_node_for_hash): Non-inlined
- version.
- (ftc_node_hash_unlink): Use `FTC_NODE__TOP_FOR_HASH'.
- (ftc_node_hash_link): Ditto.
- (FTC_Cache_Lookup): Ditto.
-
-2011-01-09 suzuki toshiya
-
- [cache] inline-specific functions are conditionalized.
-
- * src/cache/ftcglyph.c (FTC_GNode_Compare): Conditionalized for
- inlined configuration. This function is a thin wrapper of
- `ftc_gnode_compare' for inlined `FTC_CACHE_LOOKUP_CMP' (see
- `nodecmp' argument). Under non-inlined configuration,
- `ftc_gnode_compare' is invoked by `FTC_Cache_Lookup', via
- `FTC_Cache->clazz.node_compare'.
-
- * src/cache/ftcglyph.h (FTC_GNode_Compare): Ditto.
- * src/cache/ftcsbits.c (FTC_SNode_Compare): Ditto, for
- `ftc_snode_compare'.
- * src/cache/ftcsbits.h (FTC_SNode_Compare): Ditto.
-
-2011-01-09 suzuki toshiya
-
- [cache] Correct a type mismatch under non-inlined config.
-
- * src/cache/ftcglyph.h (FTC_GCACHE_LOOKUP_CMP): `FTC_GCache_Lookup'
- takes the node via a pointer `FTC_Node*', differently from cpp-macro
- `FTC_CACHE_LOOKUP_CMP'.
-
-2011-01-06 suzuki toshiya
-
- Update Jamfile to include Bzip2 support.
-
- * Jamfile: Include src/bzip2 to project.
- Comments for lzw, gzip, bzip2 are changed to clarify that
- they are for compressed PCF fonts, not others.
- (e.g. compressed BDF fonts are not supported yet)
-
-2011-01-05 suzuki toshiya
-
- Update Symbian project files to include Bzip2 support.
-
- Currently, it provides `FT_Stream_OpenBzip2' that returns
- unimplemented error always, to prevent unresolved symbol
- error for the applications designed for Unix systems.
-
- * builds/symbian/bld.inf: Include ftbzip2.h.
- * builds/symbian/freetype.mmp: Include ftbzip2.c.
-
-2011-01-05 suzuki toshiya
-
- Update classic MacOS makefiles to include Bzip2 support.
-
- Currently, it provides `FT_Stream_OpenBzip2' that returns
- unimplemented error always, to prevent unresolved symbol
- error for the applications designed for Unix systems.
-
- * builds/mac/FreeType.m68k_cfm.make.txt: Include ftbzip2.c.o.
- * builds/mac/FreeType.m68k_far.make.txt: Ditto.
- * builds/mac/FreeType.ppc_carbon.make.txt: Include ftbzip2.c.x.
- * builds/mac/FreeType.ppc_classic.make.txt: Ditto.
-
-2011-01-05 suzuki toshiya
-
- Update Amiga makefiles to include Bzip2 support.
-
- Currently, it provides `FT_Stream_OpenBzip2' that returns
- unimplemented error always, to prevent unresolved symbol
- error for the applications designed for Unix systems.
-
- * builds/amiga/makefile: Include bzip2.ppc.o built from ftbzip2.c.
- * builds/amiga/makefile.os4: Include bzip2.o built from ftbzip2.c.
- * builds/amiga/smakefile: Ditto.
-
-2011-01-05 suzuki toshiya
-
- Update pkg-config tools to reflect Bzip2 support.
-
- * builds/unix/freetype-config.in: Include `-lbz2' to
- --libs output, if built with Bzip2 support.
- * builds/unix/freetype2.in: Ditto.
-
-2011-01-05 suzuki toshiya
-
- * builds/unix/configure.raw: Remove `SYSTEM_BZ2LIB' macro.
-
- SYSTEM_ZLIB is used to switch the builtin zlib source
- or system zlib source out of FreeType2. But ftbzip2
- module has no builtin bzip2 library and always requires
- system bzip2 library. Thus SYSTEM_BZ2LIB is always yes,
- it is not used.
-
-2011-01-03 Werner Lemberg
-
- */rules.mk: Handle `*pic.c' files.
-
-2010-12-31 Werner Lemberg
-
- * src/cff/cfftypes.h (CFF_MAX_CID_FONTS): Increase to 64.
- Problem reported by Tom Bishop .
-
-2010-12-31 Werner Lemberg
-
- Improve bzip2 support.
-
- * include/freetype/ftmoderr.h: Add bzip2.
-
- * docs/INSTALL.ANY, docs/CHANGES: Updated.
-
- * src/pcf/README: Updated.
- * include/freetype/internal/pcftypes.h: Obsolete, removed.
-
-2010-12-31 Joel Klinghed
-
- Add bzip2 compression support to handle *.pcf.bz2 files.
-
- * builds/unix/configure.raw: Test for libbz2 library.
-
- * devel/ftoption.h, include/freetype/config/ftoption.h
- (FT_CONFIG_OPTION_USE_BZIP2): Define.
- * include/freetype/config/ftheader.h (FT_BZIP2_H): Define.
-
- * include/freetype/ftbzip2.h: New file.
-
- * src/bzip2/*: New files.
-
- * src/pcf/pcf.h: s/gzip_/comp_/.
- * src/pcf/pcfdrvr.c: Include FT_BZIP2_H.
- s/gzip_/comp_/.
- (PCF_Face_Init): Handle bzip2 compressed files.
-
- * docs/formats.txt, modules.cfg: Updated.
-
-2010-12-25 Harsha
-
- Apply Savannah patch #7422.
-
- If we encounter a space in a string then the sbit buffer is NULL,
- height and width are 0s. So the check in ftc_snode_compare will
- always pass for spaces (comparision with 255). Here the comments
- above the condition are proper but the implementation is not. When
- we create an snode I think it is the proper way to initialize the
- width to 255 and then put a check for being equal to 255 in snode
- compare function.
-
- * src/cache/ftcsbits.c (FTC_SNode_New): Initialize sbit widths with
- value 255.
- (ftc_snode_compare): Fix condition.
-
-2010-12-13 Werner Lemberg
-
- Fix parameter handling of `FT_Set_Renderer'.
- Reported by Kirill Tishin .
-
- * src/base/ftobjs.c (FT_Set_Renderer): Increment `parameters'.
-
-2010-12-09 Werner Lemberg
-
- [cff] Allow `hlineto' and `vlineto' without arguments.
-
- We simply ignore such instructions. This is invalid, but it doesn't
- harm; and indeed, there exist such subsetted fonts in PDFs.
-
- Reported by Albert Astals Cid .
-
- * src/cff/cffgload.c (cff_decoder_parse_charstrings)
- [cff_op_hlineto]: Ignore instruction if there aren't any arguments
- on the stack.
-
-2010-11-28 Werner Lemberg
-
- * Version 2.4.4 released.
- =========================
-
-
- Tag sources with `VER-2-4-4'.
-
- * docs/CHANGES: Updated.
-
- * docs/VERSION.DLL: Update documentation and bump version number to
- 2.4.4
-
- * README, Jamfile (RefDoc),
- builds/win32/vc2005/freetype.vcproj, builds/win32/vc2005/index.html,
- builds/win32/vc2008/freetype.vcproj, builds/win32/vc2008/index.html,
- builds/win32/visualc/freetype.dsp,
- builds/win32/visualc/freetype.vcproj,
- builds/win32/visualc/index.html, builds/win32/visualce/freetype.dsp,
- builds/win32/visualce/freetype.vcproj,
- builds/win32/visualce/index.html,
- builds/wince/vc2005-ce/freetype.vcproj,
- builds/wince/vc2005-ce/index.html,
- builds/wince/vc2008-ce/freetype.vcproj,
- builds/wince/vc2008-ce/index.html: s/2.4.3/2.4.4/, s/243/244/.
-
- * include/freetype/freetype.h (FREETYPE_PATCH): Set to 4.
-
- * builds/unix/configure.raw (version_info): Set to 12:2:6.
-
-2010-11-28 Alexei Podtelezhnikov
-
- [ftsmooth]: Minor code simplification.
-
- * src/smooth/ftgrays (gray_render_cubic): Do only one comparison
- instead of two.
-
-2010-11-26 Johnson Y. Yan
-
- [truetype] Better multi-threading support.
-
- * src/truetype/ttinterp.c (TT_Load_Context): Reset glyph zone
- references.
-
-2010-11-23 John Tytgat
-
- * src/psaux/t1decode.c (t1_decoder_parse_charstring): Expand
- start_point, check_points, add_point, add_point1, close_contour
- macros.
- Remove add_contour macro.
- Return error code from t1_builder_start_point and
- t1_builder_check_points when there was one (instead of returning 0).
-
-2010-11-22 suzuki toshiya
-
- [truetype] Identify the tricky fonts by cvt/fpgm/prep checksums.
- Some Latin TrueType fonts are still expected to be unhinted.
- Fix Savannah bug #31645.
-
- * src/truetype/ttobjs.c (tt_check_trickyness): Divided to...
- (tt_check_trickyness_family): this checking family name, and
- (tt_check_trickyness_sfnt_ids): this checking cvt/fpgm/prep.
- (tt_get_sfnt_checksum): Function to retrieve the sfnt checksum
- for specified subtable even if cleared by lazy PDF generators.
- (tt_synth_sfnt_checksum): Function to calculate the checksum.
-
-2010-11-18 Werner Lemberg
-
- [truetype] Fix `loca' handling for inconsistent number of glyphs.
- Reported by Johnson Y. Yan .
-
- * src/truetype/ttpload.c (tt_face_load_loca): While sanitizing,
- handle case where `loca' is the last table in the font.
-
-2010-11-18 Werner Lemberg
-
- [sfnt] Ignore all errors while loading `OS/2' table.
- Suggested by Johnson Y. Yan .
-
- * src/sfnt/sfobjs.c (sfnt_load_face): Do it.
-
-2010-11-18 Johnson Y. Yan
-
- [type1] Fix matrix normalization.
-
- * src/type1/t1load.c (parse_font_matrix): Handle sign of scaling
- factor.
-
-2010-11-18 Werner Lemberg
-
- [type1] Improve guard against malformed data.
- Based on a patch submitted by Johnson Y. Yan
-
-
- * src/type1/t1load.c (read_binary_data): Check `size'.
-
-2010-11-17 Werner Lemberg
-
- [sfnt] While tracing, output table checksums also.
-
- * src/sfnt/ttload.c (tt_face_load_font_dir): Do it.
-
-2010-11-04 suzuki toshiya
-
- [UVS] Fix `find_variant_selector_charmap', Savannah bug #31545.
-
- Since 2010-07-04, `find_variant_selector_charmap' returns
- the first cmap subtable always under rogue-compatible
- configuration, it causes NULL pointer dereference and
- make UVS-related functions crashed.
-
- * src/base/ftobjs.c (Fix find_variant_selector_charmap):
- Returns UVS cmap correctly.
-
-2010-11-01 Alexei Podtelezhnikov
-
- [ftsmooth] Improve rendering.
-
- * src/smooth/ftsmooth.c (gray_render_conic): Since version 2.4.3,
- cubic deviations have been estimated _after_ UPSCALE, whereas
- conic ones have been evaluated _before_ UPSCALE, which produces
- inferior rendering results. Fix this.
- Partially undo change from 2010-10-15 by using ONE_PIXEL/4; this has
- been tested with demo images sent to the mailing list. See
-
- http://lists.gnu.org/archive/html/freetype-devel/2010-10/msg00055.html
-
- and later mails in this thread.
-
-2010-10-28 Werner Lemberg
-
- [ftraster] Minor fixes.
-
- Reported by Tom Bishop .
-
- * src/raster/ftraster.c (ULong): Remove unused typedef.
- (TWorker): Remove unused variable `precision_mask'.
-
-2010-10-28 Werner Lemberg
-
- [ftraster] Fix rendering.
-
- Problem reported by Tom Bishop ; see
- thread starting with
-
- http://lists.gnu.org/archive/html/freetype/2010-10/msg00049.html
-
- * src/raster/ftraster.c (Line_Up): Replace FMulDiv with SMulDiv
- since the involved multiplication exceeds 32 bits.
-
-2010-10-25 suzuki toshiya
-
- Revert a change of `_idx' type in `FTC_CACHE_LOOKUP_CMP'.
-
- * src/cache/ftccache.h (FTC_CACHE_LOOKUP_CMP): Revert
- the type of `_idx' from FT_PtrDist (by previous change)
- to original FT_UFast, to match with FT_CacheRec.
-
-2010-10-24 suzuki toshiya
-
- [cache] Change the hash types to FT_PtrDist.
-
- On LLP64 platforms (e.g. Win64), FT_ULong (32-bit)
- variables are inappropriate to calculate hash values
- from the memory address (64-bit). The hash variables
- are extended from FT_ULong to FT_PtrDist and new
- hashing macro functions are introduced. The hash
- values on 16-bit memory platforms are changed, but
- ILP32 and LP64 are not changed. The hash value in
- the cache subsystem is not reverted to the memory
- address, so using signed type FT_PtrDist is safe.
-
- * src/cache/ftccache.h (_FTC_FACE_ID_HASH): New hash
- function to replace `FTC_FACE_ID_HASH' for portability.
- * src/cache/ftcmanag.h (FTC_SCALER_HASH): Replace
- `FTC_FACE_ID_HASH' by `_FTC_FACE_ID_HASH'.
- * src/cache/ftccmap.c (FTC_CMAP_HASH): Ditto.
-
- * src/cache/ftccache.h (FTC_NodeRec): The type of the
- member `hash' is changed from FT_UInt32 to FT_PtrDist.
-
- * src/cache/ftccache.h (FTC_Cache_Lookup): The type of the
- argument `hash' is changed from FT_UInt32 to FT_PtrDist.
- (FTC_Cache_NewNode): Ditto.
- * src/cache/ftccache.c (ftc_cache_add): Ditto.
- (FTC_Cache_Lookup): Ditto. (FTC_Cache_NewNode): Ditto.
- * src/cache/ftcglyph.h (FTC_GCache_Lookup): Ditto.
- * src/cache/ftcglyph.c (FTC_GCache_Lookup): Ditto.
-
- * src/cache/ftcbasic.c (FTC_ImageCache_Lookup): The type
- of the internal variable `hash' is changed to FT_PtrDist
- from FT_UInt32. (FTC_ImageCache_LookupScaler): Ditto.
- (FTC_SBitCache_Lookup): Ditto.
- (FTC_SBitCache_LookupScaler): Ditto.
- * src/cache/ftccmap.c (FTC_CMapCache_Lookup): Ditto.
- * src/cache/ftccache.h (FTC_CACHE_LOOKUP_CMP): Ditto.
- Also the type of the internal variable `_idx' is changed to
- FT_PtrDist from FT_UFast for better pointer calculation.
-
-2010-10-24 suzuki toshiya
-
- [cache] Hide internal macros incompatible with LLP64.
-
- `FT_POINTER_TO_ULONG', `FTC_FACE_ID_HASH', and
- `FTC_IMAGE_TYPE_HASH' are enclosed by
- FT_CONFIG_OPTION_OLD_INTERNALS and hidden from
- normal clients.
-
- For the history of these macros, see the investigation:
- http://lists.gnu.org/archive/html/freetype/2010-10/msg00022.html
-
-2010-10-24 suzuki toshiya
-
- Change the type of `FT_MEM_VAL' from FT_ULong to FT_PtrDist.
-
- On LLP64 platforms (e.g. Win64), unsigned long (32-bit)
- cannot cover the memory address (64-bit). `FT_MEM_VAL' is
- used for hashing only and not dereferred, so using signed
- type FT_PtrDist is safe.
-
- * src/base/ftdbgmem.c (FT_MEM_VAL): Change the type of the
- return value from FT_ULong to FT_PtrDist.
- (ft_mem_table_resize): The type of hash is changed to
- FT_PtrDist. (ft_mem_table_get_nodep): Ditto.
-
-2010-10-24 suzuki toshiya
-
- Replace "%lx" for memory address by "%p", LLP64 platforms.
-
- On LLP64 platforms (e.g. Win64), long (32-bit) cannot cover
- the memory address (64-bit). Also the casts from the pointer
- type to long int should be removed to preserve the address
- correctly.
-
- * src/raster/ftraster.c (New_Profile): Replace "%lx" by "%p".
- (End_Profile) Ditto.
- * src/truetype/ttinterp.c (Init_Context): Ditto.
-
-2010-10-15 Alexei Podtelezhnikov
-
- Fix thinko in spline flattening.
-
- FT_MAX_CURVE_DEVIATION is dependent on the value of ONE_PIXEL.
-
- * src/smooth/ftgrays.c (FT_MAX_CURVE_DEVIATION): Remove it and
- replace it everywhere with ONE_PIXEL/8.
-
-2010-10-13 suzuki toshiya
-
- [raccess] Skip unrequired resource access rules by Darwin VFS.
-
- When a resource fork access rule by Darwin VFS could open the
- resource fork but no font is found in it, the rest of rules
- by Darwin VFS are skipped. It reduces the warnings of the
- deprecated resource fork access method by recent Darwin kernel.
- Fix MacPorts ticket #18859:
- http://trac.macports.org/ticket/18859
-
- * src/base/ftobjs.c (load_face_in_embedded_rfork):
- When `FT_Stream_New' returns FT_Err_Cannot_Open_Stream, it
- means that the file is possible to be `fopen'-ed but zero-sized.
- Also there is a case that the resource fork is not zero-sized,
- but no supported font exists in it. If a rule by Darwin VFS
- falls into such cases, there is no need to try other Darwin VFS
- rules anymore. Such cases are marked by vfs_rfork_has_no_font.
- If it is TRUE, the Darwin VFS rules are skipped.
-
-2010-10-13 suzuki toshiya
-
- [raccess] Grouping resource access rules based on Darwin VFS.
-
- MacOS X/Darwin kernel supports a few tricky methods to access
- a resource fork via ANSI C or POSIX interface. Current resource
- fork accessor tries all possible methods to support all kernels.
- But if a method could open a resource fork but no font is found,
- there is no need to try other methods older than tested method.
- To determine whether the rule index is for Darwin VFS, a local
- function `ftrfork.c::raccess_rule_by_darwin_vfs' is introduced.
- To use this function in ftobjs.c etc but it should be inlined,
- it is exposed by ftbase.h.
-
- * src/base/ftrfork.c (FT_RFork_Rule): New enum type to identify
- the rules to access the resource fork.
- (raccess_guess_rec): New structure to bind the rule function and
- rule enum type.
- (FT_Raccess_Guess): The list of the rule functions is replaced by
- (raccess_guess_table): This. This is exposed to be used by other
- intra module functions.
- (raccess_rule_by_darwin_vfs): A function to return a boolean
- if the rule specified by the rule index is based on Darwin VFS.
-
-2010-10-13 suzuki toshiya
-
- Prevent to open a FT_Stream for zero-sized file on non-Unix.
-
- builds/unix/ftsystem.c prevents to open an useless stream from
- zero-sized file and returns FT_Err_Cannot_Open_Stream, but the
- stream drivers for ANSI C, Amiga and VMS return useless streams.
- For cross-platform consistency, all stream drivers should act
- same.
-
- * src/base/ftsystem.c (FT_Stream_Open): If the size of the opened
- file is zero, FT_Err_Cannot_Open_Stream is returned.
- * builds/amiga/src/base/ftsystem.c (FT_Stream_Open): Ditto.
- * src/vms/ftsystem.c (FT_Stream_Open): Ditto.
-
-2010-10-12 Werner Lemberg
-
- Fix Savannah bug #31310.
-
- * src/truetype/ttgxvar.c (ft_var_readpackedpoints): Protect against
- invalid `runcnt' values.
-
-2010-10-08 Chris Liddell
-
- Fix Savannah bug #31275.
-
- * src/sfnt/ttpost.c: Include FT_INTERNAL_DEBUG_H.
-
-2010-10-06 Werner Lemberg
-
- [truetype] Improve error handling of `SHZ' bytecode instruction.
- Problem reported by Chris Evans .
-
- * src/truetype/ttinterp.c (Ins_SHZ): Check `last_point'.
-
-2010-10-05 Werner Lemberg
-
- Fix Savannah bug #31253.
- Patch submitted by an anonymous reporter.
-
- * configure: Use `awk' instead of `sed' to manipulate output of `ls
- -id'.
-
-2010-10-03 Werner Lemberg
-
- * Version 2.4.3 released.
- =========================
-
-
- Tag sources with `VER-2-4-3'.
-
- * docs/CHANGES: Updated.
-
- * docs/VERSION.DLL: Update documentation and bump version number to
- 2.4.3
-
- * README, Jamfile (RefDoc),
- builds/win32/vc2005/freetype.vcproj, builds/win32/vc2005/index.html,
- builds/win32/vc2008/freetype.vcproj, builds/win32/vc2008/index.html,
- builds/win32/visualc/freetype.dsp,
- builds/win32/visualc/freetype.vcproj,
- builds/win32/visualc/index.html, builds/win32/visualce/freetype.dsp,
- builds/win32/visualce/freetype.vcproj,
- builds/win32/visualce/index.html,
- builds/wince/vc2005-ce/freetype.vcproj,
- builds/wince/vc2005-ce/index.html,
- builds/wince/vc2008-ce/freetype.vcproj,
- builds/wince/vc2008-ce/index.html: s/2.4.2/2.4.3/, s/242/243/.
-
- * include/freetype/freetype.h (FREETYPE_PATCH): Set to 3.
-
- * builds/unix/configure.raw (version_info): Set to 12:1:6.
-
-2010-10-03 Werner Lemberg
-
- Avoid `configure' issues with symbolic links.
- Based on a patch from Alexander Stohr .
-
- * configure: Compare directories using `ls -id'.
- Check existence of `reference' subdirectory before creating it.
-
-2010-10-02 Werner Lemberg
-
- Fix Savannah bug #31088 (sort of).
-
- * src/sfnt/ttload.c (tt_face_load_maxp): Always allocate at least 64
- function entries.
-
-2010-10-02 Werner Lemberg
-
- [smooth] Fix splitting of cubics for negative values.
-
- Reported by Róbert Márki ; see
- http://lists.gnu.org/archive/html/freetype/2010-09/msg00019.html.
-
- * src/smooth/ftgrays.c (gray_render_cubic): Fix thinko.
-
-2010-10-01 suzuki toshiya
-
- Fix Savannah bug #31040.
-
- * src/truetype/ttinterp.c (free_buffer_in_size): Remove.
- (TT_RunIns): Updated.
-
-2010-09-20 suzuki toshiya
-
- [sfnt] Make error message filling NULL names less verbose.
-
- * src/sfnt/ttpost.c (load_format_20): Showing 1 summary message
- when we fill `post' names by NULL, instead of per-entry message.
-
-2010-09-20 Graham Asher
- David Bevan
-
- [smooth] Fix and improve spline flattening.
-
- This fixes the flattening of cubic, S-shaped curves and speeds up
- the handling of both the conic and cubic arcs.
-
- See the discussions on the freetype-devel mailing list in late
- August and September 2010 for details.
-
- * src/smooth/ftgrays.c (FT_MAX_CURVE_DEVIATION): New macro.
- (TWorker): Remove `conic_level' and `cubic_level' elements.
- (gray_render_conic): Simplify algorithm.
- (gray_render_cubic): New algorithm; details are given in the code
- comments.
- (gray_convert_glyph): Remove heuristics.
-
-2010-09-19 Werner Lemberg
-
- Minor fixes.
-
- * src/cff/cffload.c (cff_charset_compute_cids): `charset->sids[i]'
- is `FT_UShort'.
- (cff_index_access_element): Don't use additions in comparison.
- * src/sfnt/ttpost.c (load_format_20): Make `post_limit' of type
- `FT_Long'.
- Don't use additions in comparison.
- Improve tracing messages.
- (load_format_25, load_post_names): Make `post_limit' of type
- `FT_Long'.
-
-2010-09-19 suzuki toshiya
-
- [cff] Truncate the element length at the end of the stream.
- See Savannah bug #30975.
-
- * src/cff/cffload.c (cff_index_access_element): `off2', the offset
- to the next element is truncated at the end of the stream to prevent
- invalid I/O. As `off1', the offset to the requested element has
- been checked by `FT_STREAM_SEEK', `off2' should be checked
- similarly.
-
-2010-09-19 suzuki toshiya
-
- [cff] Ignore CID > 0xFFFFU.
- See Savannah bug #30975.
-
- * src/cff/cffload.c (cff_charset_compute_cids): Ignore CID if
- greater than 0xFFFFU. CFF font spec does not mention maximum CID in
- the font, but PostScript and PDF spec define that maximum CID is
- 0xFFFFU.
-
-2010-09-19 suzuki toshiya
-
- [cff] Make trace message in` cff_charset_load' verbose.
- See Savannah bug #30975.
-
- * src/cff/cffload.c (cff_charset_load): Report the original `nleft'
- and truncated `nleft'.
-
-2010-09-19 suzuki toshiya
-
- [cff] Correct `max_cid' from CID array length to max CID.
- See Savannah bug #30975.
-
- * src/cff/cffload.c (cff_charset_compute_cids): Don't increment
- max_cid after detecting max CID. The array CFF_Charset->cids is
- allocated by max_cid + 1.
- (cff_charset_cid_to_gindex): Permit CID is less than or equal to
- CFF_Charset->max_cid.
- * src/cff/cffobjs.c (cff_face_init): FT_Face->num_glyphs is
- calculated as CFF_Charset->max_cid + 1.
-
-2010-09-19 suzuki toshiya
-
- [truetype] Sanitize the broken offsets in `loca'.
- See Savannah bug #31040.
-
- * src/truetype/ttpload.c (tt_face_get_location): If `pos1', the
- offset to the requested entry in `glyf' exceeds the end of the
- table, return offset=0, length=0. If `pos2', the offset to the next
- entry in `glyf' exceeds the end of the table, truncate the entry
- length at the end of `glyf' table.
-
-2010-09-19 suzuki toshiya
-
- [sfnt] Prevent overrunning in `post' table parser.
- See Savannah bug #31040.
-
- * src/sfnt/ttpost.c (load_post_names): Get the length of `post'
- table and pass the limit of `post' table to `load_format_20' and
- `load_format_25'.
- (load_format_20): Stop the parsing when we reached at the limit of
- `post' table. If more glyph names are required, they are filled by
- NULL names.
-
-2010-09-17 suzuki toshiya
-
- [truetype] Don't duplicate size->twilight structure to be freed.
- See Savannah bug #31040 for detail.
-
- * src/truetype/ttinterp.c (free_buffer_in_size): Don't duplicate
- FT_GlyphZoneRec size->twilight to be freed. If duplicated,
- `FT_FREE' erases the duplicated pointers only and leave original
- pointers. They can cause the double-free crash when the burst
- errors occur in TrueType interpreter and `free_buffer_in_size' is
- invoked repeatedly.
-
-2010-09-15 Werner Lemberg
-
- Make bytecode debugging with FontForge work again.
-
- * src/truetype/ttinterp.c (TT_RunIns): Don't call
- `free_buffer_in_size' in case of error if a debugger is active.
-
-2010-09-14 Werner Lemberg
-
- Improve tracing messages.
-
- * src/truetype/ttinterp.c (TT_RunIns): Improve wording of tracing
- message.
- * src/truetype/ttobjs.c (tt_size_run_fpgm, tt_size_run_prep): Add
- tracing message.
- * src/truetype/ttgload.c (tt_loader_init): Add tracing message.
- * src/cache/ftcsbits.c (ftc_snode_load): Emit tracing message if
- glyph doesn't fit into a small bitmap container.
-
-2010-09-13 Werner Lemberg
-
- Fix minor issues reported by