Merge branch 'develop' of https://github.com/vcmi/vcmi into develop
19
.gitignore
vendored
@ -1,10 +1,29 @@
|
||||
/client/vcmiclient
|
||||
/server/vcmiserver
|
||||
/launcher/vcmilauncher
|
||||
/launcher/vcmilauncher_automoc.cpp
|
||||
|
||||
*.dll
|
||||
*.exe
|
||||
*.depend
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.res
|
||||
*.layout
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
/CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
*_cotire.cmake
|
||||
cotire
|
||||
moc_*.cpp
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
/CPackConfig.cmake
|
||||
/CPackSourceConfig.cmake
|
||||
build-*
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define strcpy_s(a, b, c) strncpy(a, c, b)
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#ifdef VCMI_ANDROID
|
||||
#define GetGlobalAiVersion BattleAI_GetGlobalAiVersion
|
||||
#define GetAiName BattleAI_GetAiName
|
||||
#define GetNewBattleAI BattleAI_GetNewBattleAI
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define strcpy_s(a, b, c) strncpy(a, c, b)
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#ifdef VCMI_ANDROID
|
||||
#define GetGlobalAiVersion StupidAI_GetGlobalAiVersion
|
||||
#define GetAiName StupidAI_GetAiName
|
||||
#define GetNewBattleAI StupidAI_GetNewBattleAI
|
||||
|
@ -5,7 +5,7 @@
|
||||
#define strcpy_s(a, b, c) strncpy(a, c, b)
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#ifdef VCMI_ANDROID
|
||||
#define GetGlobalAiVersion VCAI_GetGlobalAiVersion
|
||||
#define GetAiName VCAI_GetAiName
|
||||
#define GetNewAI VCAI_GetNewAI
|
||||
|
@ -198,12 +198,27 @@ SET(PCH_PROPERTIES
|
||||
COTIRE_CXX_PREFIX_HEADER_INIT "StdInc.h"
|
||||
)
|
||||
|
||||
find_path(MINIZIP_INCLUDE_PATH NAMES minizip/unzip.h)
|
||||
find_library(MINIZIP_LIB NAMES minizip PATH_SUFFIXES dynamic)
|
||||
mark_as_advanced(MINIZIP_INCLUDE_PATH MINIZIP_LIB)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(MINIZIP MINIZIP_INCLUDE_PATH MINIZIP_LIB)
|
||||
if (MINIZIP_FOUND)
|
||||
set(MINIZIP_INCLUDE_DIR ${MINIZIP_INCLUDE_PATH})
|
||||
set(MINIZIP_LIBRARIES ${MINIZIP_LIB})
|
||||
add_definitions(-DUSE_SYSTEM_MINIZIP)
|
||||
endif()
|
||||
|
||||
if (ENABLE_ERM)
|
||||
add_subdirectory(scripting/erm)
|
||||
endif()
|
||||
if (NOT MINIZIP_FOUND)
|
||||
add_subdirectory(lib/minizip)
|
||||
set(MINIZIP_LIBRARIES minizip)
|
||||
endif()
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(client)
|
||||
add_subdirectory(lib/minizip)
|
||||
add_subdirectory(server)
|
||||
add_subdirectory(AI)
|
||||
if (ENABLE_EDITOR)
|
||||
|
@ -3,6 +3,8 @@ GENERAL:
|
||||
* VCMI can now be compiled with SDL2
|
||||
* Better upscaling when running in fullscreen mode.
|
||||
* Non-latin characters can now be entered in chat window or used for save names.
|
||||
* (windows) Moved VCMI data directory from '%userprofile%\vcmi' to '%userprofile%\Documents\My Games\vcmi'
|
||||
* (windows, OSX) Moved VCMI save directory from 'VCMI_DATA\Games' to 'VCMI_DATA\Saves'
|
||||
|
||||
RANDOM MAP GENERATOR:
|
||||
|
||||
|
80
Global.h
@ -49,10 +49,58 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
# pragma warning (disable : 4800 ) /* disable conversion to bool warning -- I think it's intended in all places */
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* System detection. */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
// Based on: http://sourceforge.net/p/predef/wiki/OperatingSystems/
|
||||
// and on: http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
|
||||
// TODO?: Should be moved to vstd\os_detect.h (and then included by Global.h)
|
||||
#ifdef _WIN16 // Defined for 16-bit environments
|
||||
# error "16-bit Windows isn't supported"
|
||||
#elif defined(_WIN64) // Defined for 64-bit environments
|
||||
# define VCMI_WINDOWS
|
||||
# define VCMI_WINDOWS_64
|
||||
#elif defined(_WIN32) // Defined for both 32-bit and 64-bit environments
|
||||
# define VCMI_WINDOWS
|
||||
# define VCMI_WINDOWS_32
|
||||
#elif defined(_WIN32_WCE)
|
||||
# error "Windows CE isn't supported"
|
||||
#elif defined(__linux__) || defined(__gnu_linux__) || defined(linux) || defined(__linux)
|
||||
# define VCMI_UNIX
|
||||
# define VCMI_LINUX
|
||||
# ifdef __ANDROID__
|
||||
# define VCMI_ANDROID
|
||||
# endif
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define VCMI_UNIX
|
||||
# define VCMI_APPLE
|
||||
# include "TargetConditionals.h"
|
||||
# if TARGET_IPHONE_SIMULATOR
|
||||
# define VCMI_IOS
|
||||
# define VCMI_IOS_SIM
|
||||
# elif TARGET_OS_IPHONE
|
||||
# define VCMI_IOS
|
||||
# elif TARGET_OS_MAC
|
||||
# define VCMI_MAC
|
||||
# else
|
||||
//# warning "Unknown Apple target."?
|
||||
# endif
|
||||
#else
|
||||
# error "VCMI supports only Windows, OSX, Linux and Android targets"
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_IOS
|
||||
# error "iOS system isn't yet supported."
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Commonly used C++, Boost headers */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#ifdef VCMI_WINDOWS
|
||||
# define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - delete this line if something is missing.
|
||||
# define NOMINMAX // Exclude min/max macros from <Windows.h>. Use std::[min/max] from <algorithm> instead.
|
||||
#endif
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include <cstdio>
|
||||
@ -86,7 +134,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#if BOOST_VERSION > 105000
|
||||
#define BOOST_THREAD_VERSION 3
|
||||
# define BOOST_THREAD_VERSION 3
|
||||
#endif
|
||||
#define BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE 1
|
||||
#define BOOST_BIND_NO_PLACEHOLDERS
|
||||
@ -99,9 +147,12 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_io.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/locale/generator.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
@ -112,13 +163,8 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/math/special_functions/round.hpp>
|
||||
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
@ -151,30 +197,20 @@ typedef boost::lock_guard<boost::recursive_mutex> TLockGuardRec;
|
||||
/* Macros */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
// Import + Export macro declarations
|
||||
#ifdef _WIN32
|
||||
#ifdef VCMI_WINDOWS
|
||||
# ifdef __GNUC__
|
||||
# define DLL_IMPORT __attribute__((dllimport))
|
||||
# define DLL_EXPORT __attribute__((dllexport))
|
||||
# else
|
||||
# define DLL_IMPORT __declspec(dllimport)
|
||||
# define DLL_EXPORT __declspec(dllexport)
|
||||
# endif
|
||||
# define ELF_VISIBILITY
|
||||
#else
|
||||
# ifdef __GNUC__
|
||||
# define DLL_IMPORT __attribute__ ((visibility("default")))
|
||||
# define DLL_EXPORT __attribute__ ((visibility("default")))
|
||||
# define ELF_VISIBILITY __attribute__ ((visibility("default")))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef __GNUC__
|
||||
# define DLL_IMPORT __attribute__((dllimport))
|
||||
# else
|
||||
# define DLL_IMPORT __declspec(dllimport)
|
||||
# endif
|
||||
# define ELF_VISIBILITY
|
||||
#else
|
||||
# ifdef __GNUC__
|
||||
# define DLL_IMPORT __attribute__ ((visibility("default")))
|
||||
# define ELF_VISIBILITY __attribute__ ((visibility("default")))
|
||||
# endif
|
||||
#endif
|
||||
|
BIN
Mods/vcmi/Data/StackQueueLarge.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
Mods/vcmi/Data/StackQueueSmall.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
Mods/vcmi/Data/questDialog.png
Normal file
After Width: | Height: | Size: 268 KiB |
BIN
Mods/vcmi/Data/stackWindow/bonus-effects.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
Mods/vcmi/Data/stackWindow/button-panel.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
Mods/vcmi/Data/stackWindow/commander-abilities.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
Mods/vcmi/Data/stackWindow/commander-bg.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
Mods/vcmi/Data/stackWindow/icons.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
Mods/vcmi/Data/stackWindow/info-panel-0.png
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
Mods/vcmi/Data/stackWindow/info-panel-1.png
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
Mods/vcmi/Data/stackWindow/info-panel-2.png
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
Mods/vcmi/Data/stackWindow/spell-effects.png
Normal file
After Width: | Height: | Size: 20 KiB |
8
Mods/vcmi/Sprites/buttons/commander.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"basepath" : "buttons/",
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "commanderNormal.png"},
|
||||
{ "frame" : 1, "file" : "commanderPressed.png"}
|
||||
]
|
||||
}
|
BIN
Mods/vcmi/Sprites/buttons/commanderNormal.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
Mods/vcmi/Sprites/buttons/commanderPressed.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
8
Mods/vcmi/Sprites/buttons/resolution.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"basepath" : "buttons/",
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "resolutionNormal.png"},
|
||||
{ "frame" : 1, "file" : "resolutionPressed.png"}
|
||||
]
|
||||
}
|
BIN
Mods/vcmi/Sprites/buttons/resolutionNormal.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
Mods/vcmi/Sprites/buttons/resolutionPressed.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/cancel-normal.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/cancel-pressed.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
8
Mods/vcmi/Sprites/stackWindow/cancelButton.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"basepath" : "stackWindow/",
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "cancel-normal.png"},
|
||||
{ "frame" : 1, "file" : "cancel-pressed.png"}
|
||||
]
|
||||
}
|
BIN
Mods/vcmi/Sprites/stackWindow/level-0.png
Normal file
After Width: | Height: | Size: 182 B |
BIN
Mods/vcmi/Sprites/stackWindow/level-1.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-10.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-2.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-3.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-4.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-5.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-6.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-7.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-8.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-9.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
17
Mods/vcmi/Sprites/stackWindow/levels.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"basepath" : "stackWindow/",
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "level-0.png"},
|
||||
{ "frame" : 1, "file" : "level-1.png"},
|
||||
{ "frame" : 2, "file" : "level-2.png"},
|
||||
{ "frame" : 3, "file" : "level-3.png"},
|
||||
{ "frame" : 4, "file" : "level-4.png"},
|
||||
{ "frame" : 5, "file" : "level-5.png"},
|
||||
{ "frame" : 6, "file" : "level-6.png"},
|
||||
{ "frame" : 7, "file" : "level-7.png"},
|
||||
{ "frame" : 8, "file" : "level-8.png"},
|
||||
{ "frame" : 9, "file" : "level-9.png"},
|
||||
{ "frame" : 10,"file" : "level-10.png"}
|
||||
]
|
||||
}
|
7
Mods/vcmi/Sprites/stackWindow/switchModeIcons.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "SECSK32:69"},
|
||||
{ "frame" : 1, "file" : "SECSK32:28"}
|
||||
]
|
||||
}
|
BIN
Mods/vcmi/Sprites/stackWindow/upgrade-normal.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/upgrade-pressed.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
8
Mods/vcmi/Sprites/stackWindow/upgradeButton.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"basepath" : "stackWindow/",
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "upgrade-normal.png"},
|
||||
{ "frame" : 1, "file" : "upgrade-pressed.png"}
|
||||
]
|
||||
}
|
29
README.linux
@ -31,43 +31,50 @@ On Debian-based systems (e.g. Ubuntu) run:
|
||||
sudo apt-get install cmake g++ libsdl1.2debian libsdl-image1.2-dev libsdl-ttf2.0-dev libsdl-mixer1.2-dev zlib1g-dev libavformat-dev libswscale-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev qtbase5-dev
|
||||
|
||||
On RPM-based distributions (e.g. Fedora) run:
|
||||
sudo yum install cmake gcc-c++ SDL-devel SDL_image-devel SDL_ttf-devel SDL_mixer-devel boost boost-devel boost-filesystem boost-system boost-thread boost-program-options boost-locale zlib-devel ffmpeg-devel ffmpeg-libs
|
||||
sudo yum install cmake gcc-c++ SDL2-devel SDL2_image-devel SDL2_ttf-devel SDL2_mixer-devel boost boost-devel boost-filesystem boost-system boost-thread boost-program-options boost-locale zlib-devel ffmpeg-devel ffmpeg-libs
|
||||
|
||||
II. Getting the sources
|
||||
|
||||
VCMI is still in development. We recommend the following initial directory structure:
|
||||
trunk
|
||||
trunk/src -> contains sources and is under SVN control
|
||||
trunk/vcmi -> contains sources and is under git control
|
||||
trunk/build -> contains build output, makefiles, object files,...
|
||||
|
||||
You can get latest sources with subversion:
|
||||
cd trunk
|
||||
svn co http://svn.code.sf.net/p/vcmi/code/trunk/
|
||||
git clone https://github.com/vcmi/vcmi.git
|
||||
|
||||
III. Compilation
|
||||
|
||||
Run configure:
|
||||
mkdir build && cd build
|
||||
cmake ../src <any other options, see below>
|
||||
cmake ../vcmi <any other options, see below>
|
||||
|
||||
Additional options that you may want to use:
|
||||
To enable debugging: -DCMAKE_BUILD_TYPE=Debug
|
||||
To enable launcher: -DENABLE_LAUNCHER=Yes
|
||||
To change installation directory: -DCMAKE_INSTALL_PREFIX=$absolute_path_to_directory
|
||||
|
||||
Notice:
|
||||
The ../src/ is not a typo, it will place makefile scripts into the build dir
|
||||
The ../vcmi/ is not a typo, it will place makefile scripts into the build dir
|
||||
as the build dir is your working dir when calling CMake.
|
||||
|
||||
Then build vcmi:
|
||||
make -j2 (j2 = compile with 2 cpu cores, you can specifiy any value)
|
||||
make -j2 (j2 = compile with 2 threads, you can specify any value)
|
||||
|
||||
That will generate vcmiclient, vcmiserver as well as 3 .so libraries.
|
||||
That will generate vcmiclient, vcmiserver, vcmilauncher as well as 3 .so libraries.
|
||||
|
||||
III. Installing binaries
|
||||
|
||||
To install VCMI you can use "make install" command however generation of distribution-specific packages is usually a better idea. In most cases this can be achieved using tool called "checkinstall"
|
||||
|
||||
If you're compiling vcmi for development puposes, it's better to use links instead.
|
||||
If you're compiling vcmi for development puposes, the easiest is to use cmake prefix and then make install:
|
||||
|
||||
# mkdir .../trunk/install
|
||||
# cmake -DCMAKE_INSTALL_PREFIX=.../trunk/install ../vcmi
|
||||
# make && make install
|
||||
# .../trunk/install/bin/vcmiclient
|
||||
|
||||
|
||||
it's better to use links instead.
|
||||
Go to /BIN_PATH/, and type:
|
||||
|
||||
ln -s .../trunk/build/client/vcmiclient
|
||||
@ -86,5 +93,3 @@ Go to /LIB_PATH/vcmi/AI, and type:
|
||||
Go to /DATA_PATH/vcmi, and type:
|
||||
ln -s .../trunk/source/config
|
||||
ln -s .../trunk/source/Mods
|
||||
|
||||
|
||||
|
@ -15,6 +15,7 @@ For building from source see project wiki at http://wiki.vcmi.eu/
|
||||
|
||||
## Copyright and license
|
||||
|
||||
VCMI Project is released under GPL version 2 or later
|
||||
VCMI Project source code is licensed under GPL version 2 or later.
|
||||
VCMI Project assets are licensed under CC-BY-SA 4.0. Assets sources and information about contributors are available under following link: [https://github.com/vcmi/vcmi-assets]
|
||||
|
||||
Copyright (C) 2007-2014 VCMI Team (check AUTHORS file for the contributors list)
|
||||
|
@ -1,935 +0,0 @@
|
||||
#include "StdInc.h"
|
||||
#include "CCreatureWindow.h"
|
||||
|
||||
#include "../lib/CCreatureSet.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/BattleState.h"
|
||||
#include "../CCallback.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "CBitmapHandler.h"
|
||||
#include "CDefHandler.h"
|
||||
#include "Graphics.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "CAnimation.h"
|
||||
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../lib/BattleState.h"
|
||||
#include "../lib/CSpellHandler.h"
|
||||
#include "../lib/CArtHandler.h"
|
||||
#include "../lib/NetPacksBase.h" //ArtifactLocation
|
||||
#include "../lib/CModHandler.h"
|
||||
#include "../lib/IBonusTypeHandler.h"
|
||||
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
|
||||
using namespace CSDL_Ext;
|
||||
|
||||
class CCreatureArtifactInstance;
|
||||
class CSelectableSkill;
|
||||
|
||||
/*
|
||||
* CCreatureWindow.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
CCreatureWindow::CCreatureWindow (const CStack &stack, CreWinType Type):
|
||||
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
|
||||
type(Type)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
if (stack.base)
|
||||
init(stack.base, &stack, dynamic_cast<const CGHeroInstance*>(stack.base->armyObj));
|
||||
else
|
||||
{
|
||||
auto s = new CStackInstance(stack.type, 1); //TODO: war machines and summons should be regular stacks
|
||||
init(s, &stack, nullptr);
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
|
||||
CCreatureWindow::CCreatureWindow (const CStackInstance &stack, CreWinType Type):
|
||||
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
|
||||
type(Type)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
init(&stack, &stack, dynamic_cast<const CGHeroInstance*>(stack.armyObj));
|
||||
}
|
||||
|
||||
CCreatureWindow::CCreatureWindow(CreatureID Cid, CreWinType Type, int creatureCount):
|
||||
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
|
||||
type(Type)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
auto stack = new CStackInstance(Cid, creatureCount); //TODO: simplify?
|
||||
init(stack, CGI->creh->creatures[Cid], nullptr);
|
||||
delete stack;
|
||||
}
|
||||
|
||||
CCreatureWindow::CCreatureWindow(const CStackInstance &st, CreWinType Type, std::function<void()> Upg, std::function<void()> Dsm, UpgradeInfo *ui):
|
||||
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
|
||||
type(Type),
|
||||
dismiss(nullptr),
|
||||
upgrade(nullptr),
|
||||
ok(nullptr),
|
||||
dsm(Dsm)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
init(&st, &st,dynamic_cast<const CGHeroInstance*>(st.armyObj));
|
||||
|
||||
//print abilities text - if r-click popup
|
||||
if(type)
|
||||
{
|
||||
if(Upg && ui)
|
||||
{
|
||||
TResources upgradeCost = ui->cost[0] * st.count;
|
||||
for(TResources::nziterator i(upgradeCost); i.valid(); i++)
|
||||
{
|
||||
BLOCK_CAPTURING;
|
||||
upgResCost.push_back(new CComponent(CComponent::resource, i->resType, i->resVal));
|
||||
}
|
||||
|
||||
if(LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost))
|
||||
{
|
||||
CFunctionList<void()> fs;
|
||||
fs += Upg;
|
||||
fs += std::bind(&CCreatureWindow::close,this);
|
||||
CFunctionList<void()> cfl;
|
||||
cfl += std::bind(&CPlayerInterface::showYesNoDialog,
|
||||
LOCPLINT, CGI->generaltexth->allTexts[207], fs, nullptr, false, upgResCost);
|
||||
upgrade = new CAdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,385, 148,"IVIEWCR.DEF",SDLK_u);
|
||||
}
|
||||
else
|
||||
{
|
||||
upgrade = new CAdventureMapButton("",CGI->generaltexth->zelp[446].second,std::function<void()>(),385, 148,"IVIEWCR.DEF");
|
||||
upgrade->callback.funcs.clear();
|
||||
upgrade->setOffset(2);
|
||||
}
|
||||
|
||||
}
|
||||
if(Dsm)
|
||||
{
|
||||
CFunctionList<void()> fs[2];
|
||||
//on dismiss confirmed
|
||||
fs[0] += Dsm; //dismiss
|
||||
fs[0] += std::bind(&CCreatureWindow::close,this);//close this window
|
||||
CFunctionList<void()> cfl;
|
||||
cfl = std::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector<CComponent*>());
|
||||
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,333, 148,"IVIEWCR2.DEF",SDLK_d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCreatureWindow::CCreatureWindow (const CCommanderInstance * Commander, const CStack * stack):
|
||||
CWindowObject(PLAYER_COLORED),
|
||||
commander (Commander)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
if (stack)
|
||||
{
|
||||
type = COMMANDER_BATTLE;
|
||||
init(commander, stack, dynamic_cast<const CGHeroInstance*>(commander->armyObj));
|
||||
}
|
||||
else
|
||||
{
|
||||
type = COMMANDER;
|
||||
init(commander, commander, dynamic_cast<const CGHeroInstance*>(commander->armyObj));
|
||||
}
|
||||
|
||||
std::function<void()> Dsm;
|
||||
CFunctionList<void()> fs[2];
|
||||
//on dismiss confirmed
|
||||
fs[0] += Dsm; //dismiss
|
||||
fs[0] += std::bind(&CCreatureWindow::close,this);//close this window
|
||||
CFunctionList<void()> cfl;
|
||||
cfl = std::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector<CComponent*>());
|
||||
if (type < COMMANDER_LEVEL_UP) //can dismiss only in regular window
|
||||
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d);
|
||||
}
|
||||
|
||||
CCreatureWindow::CCreatureWindow (std::vector<ui32> &skills, const CCommanderInstance * Commander, std::function<void(ui32)> callback):
|
||||
CWindowObject(PLAYER_COLORED),
|
||||
type(COMMANDER_LEVEL_UP),
|
||||
commander (Commander),
|
||||
selectedOption (0), //choose something before drawing
|
||||
upgradeOptions(skills), //copy skills to choose from
|
||||
levelUp (callback)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
init(commander, commander, dynamic_cast<const CGHeroInstance*>(commander->armyObj));
|
||||
|
||||
std::function<void()> Dsm;
|
||||
CFunctionList<void()> fs[2];
|
||||
//on dismiss confirmed
|
||||
fs[0] += Dsm; //dismiss
|
||||
fs[0] += std::bind(&CCreatureWindow::close,this);//close this window
|
||||
CFunctionList<void()> cfl;
|
||||
cfl = std::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector<CComponent*>());
|
||||
if (type < COMMANDER_LEVEL_UP) //can dismiss only in regular window
|
||||
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d);
|
||||
}
|
||||
|
||||
void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *StackNode, const CGHeroInstance *HeroOwner)
|
||||
{
|
||||
creatureArtifact = nullptr; //may be set later
|
||||
artifactImage = nullptr;
|
||||
spellEffectsPics = nullptr;
|
||||
stack = Stack;
|
||||
c = stack->type;
|
||||
if(!StackNode)
|
||||
stackNode = c;
|
||||
else
|
||||
stackNode = StackNode;
|
||||
const CStack *battleStack = dynamic_cast<const CStack*>(stackNode); //only during battle
|
||||
heroOwner = HeroOwner;
|
||||
|
||||
if (battleStack)
|
||||
count = boost::lexical_cast<std::string>(battleStack->count);
|
||||
else if (Stack->count)
|
||||
count = boost::lexical_cast<std::string>(Stack->count);
|
||||
|
||||
if (type < COMMANDER)
|
||||
commander = nullptr;
|
||||
|
||||
bool creArt = false;
|
||||
displayedArtifact = ArtifactPosition::CREATURE_SLOT; // 0
|
||||
|
||||
//Basic graphics - need to calculate size
|
||||
|
||||
int commanderOffset = 0;
|
||||
if (type >= COMMANDER)
|
||||
commanderOffset = 74;
|
||||
|
||||
if (commander) //secondary skills
|
||||
{
|
||||
creArt = true;
|
||||
for (int i = ECommander::ATTACK; i <= ECommander::SPELL_POWER; ++i)
|
||||
{
|
||||
if (commander->secondarySkills[i] || vstd::contains(upgradeOptions, i))
|
||||
{
|
||||
std::string file = skillToFile(i);
|
||||
|
||||
skillPictures.push_back(new CPicture(file, 0,0));
|
||||
}
|
||||
}
|
||||
|
||||
if (type == COMMANDER_LEVEL_UP)
|
||||
{
|
||||
for (auto option : upgradeOptions)
|
||||
{
|
||||
ui32 index = selectableSkills.size();
|
||||
auto selectableSkill = new CSelectableSkill();
|
||||
selectableSkill->callback = std::bind(&CCreatureWindow::selectSkill, this, index);
|
||||
|
||||
if (option < 100)
|
||||
{
|
||||
selectableSkill->pos = skillPictures[index]->pos; //resize
|
||||
selectableSkills.push_back (selectableSkill);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectableSkill->pos = Rect (95, 256, 55, 55); //TODO: scroll
|
||||
const Bonus *b = CGI->creh->skillRequirements[option-100].first;
|
||||
bonusItems.push_back (new CBonusItem (genRect(0, 0, 251, 57), stack->bonusToString(b, false), stack->bonusToString(b, true), stack->bonusToGraphics(b)));
|
||||
selectableBonuses.push_back (selectableSkill); //insert these before other bonuses
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BonusList bl, blTemp;
|
||||
blTemp = (*(stackNode->getBonuses(Selector::durationType(Bonus::PERMANENT).And(Selector::anyRange()))));
|
||||
|
||||
while (blTemp.size())
|
||||
{
|
||||
Bonus * b = blTemp.front();
|
||||
|
||||
bl.push_back (new Bonus(*b));
|
||||
bl.back()->val = blTemp.valOfBonuses(Selector::typeSubtype(b->type, b->subtype)); //merge multiple bonuses into one
|
||||
blTemp.remove_if (Selector::typeSubtype(b->type, b->subtype)); //remove used bonuses
|
||||
}
|
||||
|
||||
std::string text, img;
|
||||
for(Bonus* b : bl)
|
||||
{
|
||||
text = stack->bonusToString(b, false);
|
||||
img = stack->bonusToGraphics(b);
|
||||
if (text.size() || img.size()) //if it's possible to give any description or image for this kind of bonus
|
||||
{
|
||||
bonusItems.push_back (new CBonusItem(genRect(0, 0, 251, 57), text, stack->bonusToString(b, true), img));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//handle Magic resistance separately :/
|
||||
const IBonusBearer *temp = stack;
|
||||
|
||||
if (battleStack)
|
||||
{
|
||||
temp = battleStack;
|
||||
}
|
||||
|
||||
int magicResistance = temp->magicResistance();
|
||||
|
||||
if (magicResistance)
|
||||
{
|
||||
Bonus b;
|
||||
b.type = Bonus::MAGIC_RESISTANCE;
|
||||
|
||||
text = VLC->getBth()->bonusToString(&b,temp,false);
|
||||
const std::string description = VLC->getBth()->bonusToString(&b,temp,true);
|
||||
bonusItems.push_back (new CBonusItem(genRect(0, 0, 251, 57), text, description, stack->bonusToGraphics(&b)));
|
||||
}
|
||||
|
||||
bonusRows = std::min ((int)((bonusItems.size() + 1) / 2), (screen->h - 230) / 60);
|
||||
if (type >= COMMANDER)
|
||||
vstd::amin(bonusRows, 3);
|
||||
else
|
||||
vstd::amin(bonusRows, 4);
|
||||
vstd::amax(bonusRows, 1);
|
||||
|
||||
if (type >= COMMANDER)
|
||||
{
|
||||
setBackground("CommWin" + boost::lexical_cast<std::string>(bonusRows) + ".pcx");
|
||||
for (int i = 0; i < skillPictures.size(); ++i)
|
||||
{
|
||||
skillPictures[i]->moveTo (Point (pos.x + 37 + i * 84, pos.y + 224));
|
||||
}
|
||||
for (int i = 0; i < selectableSkills.size(); ++i)
|
||||
{
|
||||
if (upgradeOptions[i] < skillPictures.size()) // it's secondary skill
|
||||
{
|
||||
selectableSkills[i]->pos = skillPictures[upgradeOptions[i]]->pos; //dirty workaround
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
//print commander level
|
||||
new CLabel(488, 62, FONT_MEDIUM, CENTER, Colors::YELLOW,
|
||||
boost::lexical_cast<std::string>((ui16)(commander->level)));
|
||||
|
||||
new CLabel(488, 82, FONT_SMALL, CENTER, Colors::WHITE,
|
||||
boost::lexical_cast<std::string>(stack->experience));
|
||||
}
|
||||
else
|
||||
setBackground("CreWin" + boost::lexical_cast<std::string>(bonusRows) + ".pcx"); //1 to 4 rows for now
|
||||
|
||||
//Buttons
|
||||
ok = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, std::bind(&CCreatureWindow::close,this), 489, 148, "hsbtns.def", SDLK_RETURN);
|
||||
ok->assignedKeys.insert(SDLK_ESCAPE);
|
||||
|
||||
if (type <= BATTLE) //in battle or info window
|
||||
{
|
||||
upgrade = nullptr;
|
||||
dismiss = nullptr;
|
||||
}
|
||||
anim = new CCreaturePic(22, 48, c);
|
||||
|
||||
//Stats
|
||||
morale = new MoraleLuckBox(true, genRect(42, 42, 335, 100));
|
||||
morale->set(stackNode);
|
||||
luck = new MoraleLuckBox(false, genRect(42, 42, 387, 100));
|
||||
luck->set(stackNode);
|
||||
|
||||
new CAnimImage("PSKIL42", 4, 0, 387, 51); //exp icon - Print it always?
|
||||
if (type) //not in fort window
|
||||
{
|
||||
if (CGI->modh->modules.STACK_EXP && type < COMMANDER)
|
||||
{
|
||||
int rank = std::min(stack->getExpRank(), 10); //hopefully nobody adds more
|
||||
new CLabel(488, 82, FONT_SMALL, CENTER, Colors::WHITE, boost::lexical_cast<std::string>(stack->experience));
|
||||
new CLabel(488, 62, FONT_MEDIUM, CENTER, Colors::YELLOW,
|
||||
CGI->generaltexth->zcrexp[rank] + " [" + boost::lexical_cast<std::string>(rank) + "]");
|
||||
|
||||
if (type > BATTLE) //we need it only on adv. map
|
||||
{
|
||||
int tier = stack->type->level;
|
||||
if (!vstd::iswithin(tier, 1, 7))
|
||||
tier = 0;
|
||||
int number;
|
||||
std::string expText = CGI->generaltexth->zcrexp[324];
|
||||
boost::replace_first (expText, "%s", c->namePl);
|
||||
boost::replace_first (expText, "%s", CGI->generaltexth->zcrexp[rank]);
|
||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(rank));
|
||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->experience));
|
||||
number = CGI->creh->expRanks[tier][rank] - stack->experience;
|
||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
|
||||
|
||||
number = CGI->creh->maxExpPerBattle[tier]; //percent
|
||||
boost::replace_first (expText, "%i%", boost::lexical_cast<std::string>(number));
|
||||
number *= CGI->creh->expRanks[tier].back() / 100; //actual amount
|
||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
|
||||
|
||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->count)); //Number of Creatures in stack
|
||||
|
||||
int expmin = std::max(CGI->creh->expRanks[tier][std::max(rank-1, 0)], (ui32)1);
|
||||
number = (stack->count * (stack->experience - expmin)) / expmin; //Maximum New Recruits without losing current Rank
|
||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //TODO
|
||||
|
||||
boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(1)); //TODO Experience Multiplier
|
||||
number = CGI->creh->expAfterUpgrade;
|
||||
boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(number) + "%"); //Upgrade Multiplier
|
||||
|
||||
expmin = CGI->creh->expRanks[tier][9];
|
||||
int expmax = CGI->creh->expRanks[tier][10];
|
||||
number = expmax - expmin;
|
||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //Experience after Rank 10
|
||||
number = (stack->count * (expmax - expmin)) / expmin;
|
||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //Maximum New Recruits to remain at Rank 10 if at Maximum Experience
|
||||
|
||||
expArea = new LRClickableAreaWTextComp(Rect(334, 49, 160, 44),CComponent::experience);
|
||||
expArea->text = expText;
|
||||
expArea->bonusValue = 0; //TDO: some specific value or no number at all
|
||||
}
|
||||
}
|
||||
|
||||
if (CGI->modh->modules.STACK_ARTIFACT)
|
||||
{
|
||||
creArt = true;
|
||||
}
|
||||
}
|
||||
if (creArt) //stack or commander artifacts
|
||||
{
|
||||
setArt (stack->getArt(ArtifactPosition::CREATURE_SLOT));
|
||||
if (type > BATTLE && type < COMMANDER_BATTLE) //artifact buttons inactive in battle
|
||||
{
|
||||
//TODO: disable buttons if no artifact is equipped
|
||||
leftArtRoll = new CAdventureMapButton(std::string(), std::string(), std::bind (&CCreatureWindow::scrollArt, this, -1), 437, 98, "hsbtns3.def", SDLK_LEFT);
|
||||
rightArtRoll = new CAdventureMapButton(std::string(), std::string(), std::bind (&CCreatureWindow::scrollArt, this, +1), 516, 98, "hsbtns5.def", SDLK_RIGHT);
|
||||
if (heroOwner)
|
||||
passArtToHero = new CAdventureMapButton(std::string(), std::string(), std::bind (&CCreatureWindow::passArtifactToHero, this), 437, 148, "OVBUTN1.DEF", SDLK_HOME);
|
||||
}
|
||||
}
|
||||
|
||||
if (battleStack) //only during battle
|
||||
{
|
||||
spellEffectsPics = new CAnimation("SpellInt.def");
|
||||
|
||||
//spell effects
|
||||
int printed=0; //how many effect pics have been printed
|
||||
std::vector<si32> spells = battleStack->activeSpells();
|
||||
for(si32 effect : spells)
|
||||
{
|
||||
const si32 imageIndex = effect+1; //there is "null" frame with index 0 in SpellInt.def
|
||||
std::string spellText;
|
||||
spellEffectsPics->load(imageIndex);
|
||||
IImage * effectIcon = spellEffectsPics->getImage(imageIndex,0,false); //todo: better way to determine presence of icon
|
||||
spellEffectsPics->unload(imageIndex);
|
||||
if (effectIcon != nullptr) //not all effects have graphics (for eg. Acid Breath)
|
||||
{
|
||||
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
|
||||
boost::replace_first (spellText, "%s", CGI->spellh->objects[effect]->name);
|
||||
int duration = battleStack->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT,effect))->turnsRemain;
|
||||
boost::replace_first (spellText, "%d", boost::lexical_cast<std::string>(duration));
|
||||
|
||||
new CAnimImage("SpellInt.def", imageIndex, 0, 20 + 52 * printed, 184);
|
||||
spellEffects.push_back(new LRClickableAreaWText(Rect(20 + 52 * printed, 184, 50, 38), spellText, spellText));
|
||||
if (++printed >= 10) //we can fit only 10 effects
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//print current health
|
||||
printLine (5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
|
||||
}
|
||||
|
||||
if (bonusItems.size() > (bonusRows << 1)) //only after graphics are created
|
||||
{
|
||||
slider = new CSlider(528, 231 + commanderOffset, bonusRows*60, std::bind (&CCreatureWindow::sliderMoved, this, _1),
|
||||
bonusRows, (bonusItems.size() + 1) >> 1, 0, false, 0);
|
||||
}
|
||||
else //slider automatically places bonus Items
|
||||
recreateSkillList (0);
|
||||
|
||||
showAll(screen2);
|
||||
|
||||
//AUIDAT.DEF
|
||||
}
|
||||
|
||||
void CCreatureWindow::printLine(int nr, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
|
||||
{
|
||||
new CLabel(162, 48 + nr*19, FONT_SMALL, TOPLEFT, Colors::WHITE, text);
|
||||
|
||||
std::string hlp;
|
||||
if(range && baseVal != val)
|
||||
hlp = boost::str(boost::format("%d - %d") % baseVal % val);
|
||||
else if(baseVal != val && val>=0)
|
||||
hlp = boost::str(boost::format("%d (%d)") % baseVal % val);
|
||||
else
|
||||
hlp = boost::lexical_cast<std::string>(baseVal);
|
||||
|
||||
new CLabel(325, 64 + nr*19, FONT_SMALL, BOTTOMRIGHT, Colors::WHITE, hlp);
|
||||
}
|
||||
|
||||
void CCreatureWindow::recreateSkillList(int Pos)
|
||||
{
|
||||
int commanderOffset = 0;
|
||||
if (type >= COMMANDER)
|
||||
commanderOffset = 74;
|
||||
|
||||
int n = 0, i = 0, j = 0;
|
||||
int numSkills = std::min ((bonusRows + Pos) << 1, (int)bonusItems.size());
|
||||
for (n = 0; n < Pos << 1; ++n)
|
||||
{
|
||||
bonusItems[n]->visible = false;
|
||||
if (n < selectableBonuses.size())
|
||||
selectableBonuses[n]->deactivate(); //we assume that bonuses are at front of the list
|
||||
}
|
||||
for (n = Pos << 1; n < numSkills; ++n)
|
||||
{
|
||||
int offsetx = 257*j - (bonusRows == 4 ? 1 : 0);
|
||||
int offsety = 60*i + (bonusRows > 1 ? 1 : 0) + commanderOffset; //lack of precision :/
|
||||
|
||||
bonusItems[n]->moveTo (Point(pos.x + offsetx + 10, pos.y + offsety + 230), true);
|
||||
bonusItems[n]->visible = true;
|
||||
if (n < selectableBonuses.size())
|
||||
{
|
||||
selectableBonuses[n]->moveTo (Point(bonusItems[n]->pos.x + 12, bonusItems[n]->pos.y + 2)); //for some reason bonusItems have dimensions 0?
|
||||
//selectableBonuses[n]->pos = bonusItems[n]->bonusGraphics->pos;
|
||||
selectableBonuses[n]->activate();
|
||||
}
|
||||
|
||||
if (++j > 1) //next line
|
||||
{
|
||||
++i;
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
for (n = numSkills; n < bonusItems.size(); ++n)
|
||||
{
|
||||
bonusItems[n]->visible = false;
|
||||
if (n < selectableBonuses.size())
|
||||
selectableBonuses[n]->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void CCreatureWindow::showAll(SDL_Surface * to)
|
||||
{
|
||||
CIntObject::showAll(to);
|
||||
|
||||
printAtMiddleLoc((type >= COMMANDER ? c->nameSing : c->namePl), 180, 30, FONT_SMALL, Colors::YELLOW, to); //creature name
|
||||
|
||||
printLine(0, CGI->generaltexth->primarySkillNames[0], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->Attack());
|
||||
printLine(1, CGI->generaltexth->primarySkillNames[1], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->Defense());
|
||||
|
||||
if (stackNode->valOfBonuses(Bonus::SHOTS) && stackNode->hasBonusOfType(Bonus::SHOOTER))
|
||||
{//only for shooting units - important with wog exp shooters
|
||||
if (type == BATTLE)
|
||||
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS), dynamic_cast<const CStack*>(stackNode)->shots);
|
||||
else
|
||||
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS));
|
||||
}
|
||||
if (stackNode->valOfBonuses(Bonus::CASTS))
|
||||
{
|
||||
printAtMiddleLoc(CGI->generaltexth->allTexts[399], 356, 62, FONT_SMALL, Colors::WHITE, to);
|
||||
std::string casts;
|
||||
if (type == BATTLE)
|
||||
casts = boost::lexical_cast<std::string>((ui16)dynamic_cast<const CStack*>(stackNode)->casts); //ui8 is converted to char :(
|
||||
else
|
||||
casts = boost::lexical_cast<std::string>(stackNode->valOfBonuses(Bonus::CASTS));
|
||||
printAtMiddleLoc(casts, 356, 82, FONT_SMALL, Colors::WHITE, to);
|
||||
}
|
||||
|
||||
//TODO
|
||||
int dmgMultiply = 1;
|
||||
if(heroOwner && stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
||||
dmgMultiply += heroOwner->Attack();
|
||||
|
||||
printLine(3, CGI->generaltexth->allTexts[199], stackNode->getMinDamage() * dmgMultiply, stackNode->getMaxDamage() * dmgMultiply, true);
|
||||
printLine(4, CGI->generaltexth->allTexts[388], c->valOfBonuses(Bonus::STACK_HEALTH), stackNode->valOfBonuses(Bonus::STACK_HEALTH));
|
||||
printLine(6, CGI->generaltexth->zelp[441].first, c->Speed(), stackNode->Speed());
|
||||
|
||||
for(CBonusItem* b : bonusItems)
|
||||
b->showAll (to);
|
||||
|
||||
for(auto s : selectableSkills)
|
||||
s->showAll (to);
|
||||
|
||||
for (int i = 0; i < skillPictures.size(); i++)
|
||||
{
|
||||
skillPictures[i]->bg = BitmapHandler::loadBitmap (skillToFile(i));
|
||||
skillPictures[i]->showAll (to);
|
||||
}
|
||||
|
||||
if (upgradeOptions.size() && (type == COMMANDER_LEVEL_UP && upgradeOptions[selectedOption] >= 100)) //add frame to selected skill
|
||||
{
|
||||
int index = selectedOption - selectableSkills.size(); //this is screwed
|
||||
CSDL_Ext::drawBorder(to, Rect::around(selectableBonuses[index]->pos), int3(Colors::METALLIC_GOLD.r, Colors::METALLIC_GOLD.g, Colors::METALLIC_GOLD.b));
|
||||
}
|
||||
}
|
||||
|
||||
void CCreatureWindow::show(SDL_Surface * to)
|
||||
{
|
||||
CIntObject::show(to);
|
||||
if (!count.empty()) //army stack
|
||||
graphics->fonts[FONT_TIMES]->renderTextRight(to, count, Colors::WHITE, Point(pos.x + 114, pos.y + 174));
|
||||
}
|
||||
|
||||
|
||||
void CCreatureWindow::close()
|
||||
{
|
||||
if (upgradeOptions.size()) //a skill for commander was chosen
|
||||
levelUp (selectedOption); //callback value is vector index
|
||||
|
||||
GH.popIntTotally(this);
|
||||
}
|
||||
|
||||
void CCreatureWindow::sliderMoved(int newpos)
|
||||
{
|
||||
recreateSkillList(newpos); //move components
|
||||
redraw();
|
||||
}
|
||||
|
||||
std::string CCreatureWindow::skillToFile (int skill)
|
||||
{
|
||||
std::string file = "zvs/Lib1.res/_";
|
||||
switch (skill)
|
||||
{
|
||||
case ECommander::ATTACK:
|
||||
file += "AT";
|
||||
break;
|
||||
case ECommander::DEFENSE:
|
||||
file += "DF";
|
||||
break;
|
||||
case ECommander::HEALTH:
|
||||
file += "HP";
|
||||
break;
|
||||
case ECommander::DAMAGE:
|
||||
file += "DM";
|
||||
break;
|
||||
case ECommander::SPEED:
|
||||
file += "SP";
|
||||
break;
|
||||
case ECommander::SPELL_POWER:
|
||||
file += "MP";
|
||||
break;
|
||||
}
|
||||
std::string sufix = boost::lexical_cast<std::string>((int)(commander->secondarySkills[skill])); //casting ui8 causes ascii char conversion
|
||||
if (type == COMMANDER_LEVEL_UP)
|
||||
{
|
||||
if (upgradeOptions.size() && upgradeOptions[selectedOption] == skill)//that one specific skill is selected
|
||||
sufix += "="; //level-up highlight
|
||||
else if (!vstd::contains(upgradeOptions, skill))
|
||||
sufix = "no"; //not available - no number
|
||||
}
|
||||
file += sufix += ".bmp";
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
void CCreatureWindow::setArt(const CArtifactInstance *art)
|
||||
{
|
||||
creatureArtifact = art;
|
||||
if (creatureArtifact)
|
||||
{
|
||||
if (artifactImage == nullptr)
|
||||
artifactImage = new CAnimImage("ARTIFACT", creatureArtifact->artType->iconIndex, 0, 466, 100);
|
||||
else
|
||||
artifactImage->setFrame(creatureArtifact->artType->iconIndex);
|
||||
}
|
||||
else
|
||||
artifactImage = nullptr;
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
void CCreatureWindow::scrollArt(int dir)
|
||||
{
|
||||
//TODO: get next artifact
|
||||
int size = stack->artifactsWorn.size();
|
||||
displayedArtifact = size ? static_cast<ArtifactPosition>((displayedArtifact + dir) % size)
|
||||
: static_cast<ArtifactPosition>(ArtifactPosition::CREATURE_SLOT);
|
||||
setArt (stack->getArt(displayedArtifact));
|
||||
}
|
||||
|
||||
void CCreatureWindow::passArtifactToHero()
|
||||
{
|
||||
const CGHeroInstance * h = dynamic_cast<const CGHeroInstance *>(stack->armyObj);
|
||||
if (h && creatureArtifact)
|
||||
{
|
||||
LOCPLINT->cb->swapArtifacts (ArtifactLocation (stack, displayedArtifact), ArtifactLocation(h, creatureArtifact->firstBackpackSlot(h)));
|
||||
}
|
||||
else
|
||||
logGlobal->warnStream() << "Pass artifact to hero should be disabled, no hero or no artifact!";
|
||||
|
||||
//redraw is handled via CArtifactHolder interface
|
||||
}
|
||||
|
||||
void CCreatureWindow::artifactRemoved (const ArtifactLocation &artLoc)
|
||||
{
|
||||
//align artifacts to remove holes
|
||||
for (auto al : stack->artifactsWorn)
|
||||
{
|
||||
ArtifactPosition freeSlot = al.second.artifact->firstAvailableSlot(stack);
|
||||
if (freeSlot < al.first)
|
||||
LOCPLINT->cb->swapArtifacts (ArtifactLocation(stack, al.first), ArtifactLocation(stack, freeSlot));
|
||||
}
|
||||
int size = stack->artifactsWorn.size();
|
||||
displayedArtifact = size ? static_cast<ArtifactPosition>(displayedArtifact % size)
|
||||
: static_cast<ArtifactPosition>(ArtifactPosition::CREATURE_SLOT); //0
|
||||
setArt (stack->getArt(displayedArtifact));
|
||||
}
|
||||
void CCreatureWindow::artifactMoved (const ArtifactLocation &artLoc, const ArtifactLocation &destLoc)
|
||||
{
|
||||
artifactRemoved (artLoc); //same code
|
||||
}
|
||||
|
||||
void CCreatureWindow::selectSkill (ui32 which)
|
||||
{
|
||||
selectedOption = which;
|
||||
redraw();
|
||||
}
|
||||
|
||||
CCreatureWindow::~CCreatureWindow()
|
||||
{
|
||||
for (auto & elem : upgResCost)
|
||||
delete elem;
|
||||
bonusItems.clear();
|
||||
|
||||
if(spellEffectsPics!=nullptr)
|
||||
delete spellEffectsPics;
|
||||
}
|
||||
|
||||
CBonusItem::CBonusItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CBonusItem::CBonusItem(const Rect &Pos, const std::string &Name, const std::string &Description, const std::string &graphicsName)
|
||||
{
|
||||
OBJ_CONSTRUCTION;
|
||||
visible = false;
|
||||
|
||||
name = Name;
|
||||
description = Description;
|
||||
if (graphicsName.size())
|
||||
bonusGraphics = new CPicture(graphicsName, 26, 232);
|
||||
else
|
||||
bonusGraphics = nullptr;
|
||||
|
||||
removeUsedEvents(ALL); //no actions atm
|
||||
}
|
||||
|
||||
void CBonusItem::showAll (SDL_Surface * to)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
graphics->fonts[FONT_SMALL]->renderTextLeft(to, name, Colors::YELLOW, Point(pos.x + 72, pos.y + 6));
|
||||
graphics->fonts[FONT_SMALL]->renderTextLeft(to, description, Colors::WHITE, Point(pos.x + 72, pos.y + 30));
|
||||
if (bonusGraphics && bonusGraphics->bg)
|
||||
blitAtLoc(bonusGraphics->bg, 12, 2, to);
|
||||
}
|
||||
}
|
||||
|
||||
CBonusItem::~CBonusItem()
|
||||
{
|
||||
//delete bonusGraphics; //automatic destruction
|
||||
}
|
||||
|
||||
void CSelectableSkill::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if (down)
|
||||
callback();
|
||||
}
|
||||
|
||||
void CCreInfoWindow::show(SDL_Surface * to)
|
||||
{
|
||||
CIntObject::show(to);
|
||||
creatureCount->showAll(to);
|
||||
}
|
||||
|
||||
CCreInfoWindow::CCreInfoWindow(const CStackInstance &stack, bool LClicked, std::function<void()> upgradeFunc, std::function<void()> dismissFunc, UpgradeInfo *upgradeInfo):
|
||||
CWindowObject(PLAYER_COLORED | (LClicked ? 0 : RCLICK_POPUP), "CRSTKPU")
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
init(stack.type, &stack, dynamic_cast<const CGHeroInstance*>(stack.armyObj), stack.count, LClicked);
|
||||
|
||||
//additional buttons if opened with left click
|
||||
if(LClicked)
|
||||
{
|
||||
std::function<void()> closeFunc = std::bind(&CCreInfoWindow::close,this);
|
||||
|
||||
if(upgradeFunc && upgradeInfo)
|
||||
{
|
||||
TResources upgradeCost = upgradeInfo->cost[0] * stack.count;
|
||||
for(TResources::nziterator i(upgradeCost); i.valid(); i++)
|
||||
{
|
||||
BLOCK_CAPTURING;
|
||||
upgResCost.push_back(new CComponent(CComponent::resource, i->resType, i->resVal));
|
||||
}
|
||||
|
||||
CFunctionList<void()> onUpgrade;
|
||||
onUpgrade += upgradeFunc;
|
||||
onUpgrade += closeFunc;
|
||||
|
||||
std::function<void()> dialog = std::bind(&CPlayerInterface::showYesNoDialog,
|
||||
LOCPLINT,
|
||||
CGI->generaltexth->allTexts[207],
|
||||
onUpgrade, 0, false,
|
||||
std::ref(upgResCost));
|
||||
|
||||
upgrade = new CAdventureMapButton("", CGI->generaltexth->zelp[446].second, dialog, 76, 237, "IVIEWCR", SDLK_u);
|
||||
upgrade->block(!LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost));
|
||||
}
|
||||
|
||||
if(dismissFunc)
|
||||
{
|
||||
CFunctionList<void()> onDismiss;
|
||||
onDismiss += dismissFunc;
|
||||
onDismiss += closeFunc;
|
||||
|
||||
std::function<void()> dialog = std::bind(&CPlayerInterface::showYesNoDialog,
|
||||
LOCPLINT,
|
||||
CGI->generaltexth->allTexts[12],
|
||||
onDismiss, 0, true, std::vector<CComponent*>());
|
||||
|
||||
dismiss = new CAdventureMapButton("", CGI->generaltexth->zelp[445].second, dialog, 21, 237, "IVIEWCR2",SDLK_d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCreInfoWindow::CCreInfoWindow(int creatureID, bool LClicked, int creatureCount):
|
||||
CWindowObject(PLAYER_COLORED | (LClicked ? 0 : RCLICK_POPUP), "CRSTKPU")
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
const CCreature *creature = CGI->creh->creatures[creatureID];
|
||||
init(creature, nullptr, nullptr, creatureCount, LClicked);
|
||||
}
|
||||
|
||||
CCreInfoWindow::CCreInfoWindow(const CStack &stack, bool LClicked):
|
||||
CWindowObject(PLAYER_COLORED | (LClicked ? 0 : RCLICK_POPUP), "CRSTKPU")
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
init(stack.getCreature(), &stack, stack.getMyHero(), stack.count, LClicked);
|
||||
}
|
||||
|
||||
CCreInfoWindow::~CCreInfoWindow()
|
||||
{
|
||||
for(CComponent* object : upgResCost)
|
||||
delete object;
|
||||
}
|
||||
|
||||
void CCreInfoWindow::printLine(int position, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
|
||||
{
|
||||
infoTexts[position].first = new CLabel(155, 48 + position*19, FONT_SMALL, TOPLEFT, Colors::WHITE, text);
|
||||
std::string valueStr;
|
||||
|
||||
if(range && baseVal != val)
|
||||
valueStr = boost::str(boost::format("%d - %d") % baseVal % val);
|
||||
|
||||
else if(baseVal != val && val>=0)
|
||||
valueStr = boost::str(boost::format("%d (%d)") % baseVal % val);
|
||||
|
||||
else
|
||||
valueStr = boost::lexical_cast<std::string>(baseVal);
|
||||
|
||||
infoTexts[position].second = new CLabel(276, 63 + position*19, FONT_SMALL, BOTTOMRIGHT, Colors::WHITE, valueStr);
|
||||
}
|
||||
|
||||
void CCreInfoWindow::init(const CCreature *creature, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner, int count, bool LClicked)
|
||||
{
|
||||
removeUsedEvents(ALL);
|
||||
if (!LClicked)
|
||||
addUsedEvents(RCLICK);
|
||||
|
||||
if(!stackNode)
|
||||
stackNode = creature;
|
||||
|
||||
animation = new CCreaturePic(21, 48, creature);
|
||||
|
||||
std::string countStr = boost::lexical_cast<std::string>(count);
|
||||
creatureCount = new CLabel(114, 174, FONT_TIMES, BOTTOMRIGHT, Colors::WHITE, countStr);
|
||||
|
||||
creatureName = new CLabel(149, 30, FONT_SMALL, CENTER, Colors::YELLOW, creature->namePl);
|
||||
|
||||
printLine(0, CGI->generaltexth->primarySkillNames[0], creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK));
|
||||
printLine(1, CGI->generaltexth->primarySkillNames[1], creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE));
|
||||
|
||||
if(stackNode->valOfBonuses(Bonus::SHOTS))
|
||||
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS));
|
||||
|
||||
//TODO
|
||||
int dmgMultiply = 1;
|
||||
if(heroOwner && stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
||||
dmgMultiply += heroOwner->Attack();
|
||||
|
||||
printLine(3, CGI->generaltexth->allTexts[199], stackNode->getMinDamage() * dmgMultiply, stackNode->getMaxDamage() * dmgMultiply, true);
|
||||
printLine(4, CGI->generaltexth->allTexts[388], creature->valOfBonuses(Bonus::STACK_HEALTH), stackNode->valOfBonuses(Bonus::STACK_HEALTH));
|
||||
printLine(6, CGI->generaltexth->zelp[441].first, creature->valOfBonuses(Bonus::STACKS_SPEED), stackNode->valOfBonuses(Bonus::STACKS_SPEED));
|
||||
|
||||
//setting morale
|
||||
morale = new MoraleLuckBox(true, genRect(42, 42, 22, 186));
|
||||
morale->set(stackNode);
|
||||
//setting luck
|
||||
luck = new MoraleLuckBox(false, genRect(42, 42, 75, 186));
|
||||
luck->set(stackNode);
|
||||
|
||||
if(!LClicked)
|
||||
{
|
||||
abilityText = new CLabel(17, 231, FONT_SMALL, TOPLEFT, Colors::WHITE, creature->abilityText);
|
||||
}
|
||||
else
|
||||
{
|
||||
abilityText = nullptr;
|
||||
ok = new CAdventureMapButton("", CGI->generaltexth->zelp[445].second,
|
||||
std::bind(&CCreInfoWindow::close,this), 216, 237, "IOKAY.DEF", SDLK_RETURN);
|
||||
ok->assignedKeys.insert(SDLK_ESCAPE);
|
||||
}
|
||||
|
||||
//if we are displying window fo r stack in battle, there are several more things that we need to display
|
||||
if(const CStack *battleStack = dynamic_cast<const CStack*>(stackNode))
|
||||
{
|
||||
//print at most 3 spell effects
|
||||
std::vector<si32> spells = battleStack->activeSpells();
|
||||
for (size_t i=0; i< std::min(spells.size(), size_t(3)); i++)
|
||||
effects.push_back(new CAnimImage("SpellInt", spells[i]+1, 0, 127 + 52*i, 186));
|
||||
|
||||
//print current health
|
||||
printLine(5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
|
||||
}
|
||||
}
|
||||
|
||||
CIntObject * createCreWindow(
|
||||
const CStack *s, bool lclick/* = false*/)
|
||||
{
|
||||
auto c = dynamic_cast<const CCommanderInstance *>(s->base);
|
||||
if (c)
|
||||
{
|
||||
return new CCreatureWindow (c, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(settings["general"]["classicCreatureWindow"].Bool())
|
||||
return new CCreInfoWindow(*s, lclick);
|
||||
else
|
||||
return new CCreatureWindow(*s, LOCPLINT->battleInt ? CCreatureWindow::BATTLE : CCreatureWindow::OTHER);
|
||||
}
|
||||
}
|
||||
|
||||
CIntObject * createCreWindow(CreatureID Cid, CCreatureWindow::CreWinType Type, int creatureCount)
|
||||
{
|
||||
if(settings["general"]["classicCreatureWindow"].Bool())
|
||||
return new CCreInfoWindow(Cid, Type, creatureCount);
|
||||
else
|
||||
return new CCreatureWindow(Cid, Type, creatureCount);
|
||||
}
|
||||
|
||||
CIntObject * createCreWindow(const CStackInstance *s, CCreatureWindow::CreWinType type, std::function<void()> Upg, std::function<void()> Dsm, UpgradeInfo *ui)
|
||||
{
|
||||
if(settings["general"]["classicCreatureWindow"].Bool())
|
||||
return new CCreInfoWindow(*s, type==CCreatureWindow::HERO, Upg, Dsm, ui);
|
||||
else
|
||||
return new CCreatureWindow(*s, type, Upg, Dsm, ui);
|
||||
}
|
@ -1,163 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "gui/CIntObject.h"
|
||||
#include "../lib/HeroBonus.h"
|
||||
#include "GUIClasses.h"
|
||||
|
||||
/*
|
||||
* CCreatureWindow.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
struct Bonus;
|
||||
class CCreature;
|
||||
class CStackInstance;
|
||||
class CCommanderInstance;
|
||||
class CStack;
|
||||
struct ArtifactLocation;
|
||||
class CCreatureArtifactInstance;
|
||||
class CAdventureMapButton;
|
||||
class CBonusItem;
|
||||
class CGHeroInstance;
|
||||
class CComponent;
|
||||
class LRClickableAreaWText;
|
||||
class MoraleLuckBox;
|
||||
class CAdventureMapButton;
|
||||
struct UpgradeInfo;
|
||||
class CPicture;
|
||||
class CCreaturePic;
|
||||
class LRClickableAreaWTextComp;
|
||||
class CSlider;
|
||||
class CLabel;
|
||||
class CAnimImage;
|
||||
class CSelectableSkill;
|
||||
|
||||
// New creature window
|
||||
class CCreatureWindow : public CWindowObject, public CArtifactHolder
|
||||
{
|
||||
public:
|
||||
enum CreWinType {OTHER = 0, BATTLE = 1, ARMY = 2, HERO = 3, COMMANDER = 4, COMMANDER_LEVEL_UP = 5, COMMANDER_BATTLE = 6}; // > 3 are opened permanently
|
||||
//bool active; //TODO: comment me
|
||||
CreWinType type;
|
||||
int bonusRows; //height of skill window
|
||||
ArtifactPosition displayedArtifact;
|
||||
|
||||
std::string count; //creature count in text format
|
||||
const CCreature *c; //related creature
|
||||
const CStackInstance *stack;
|
||||
const CBonusSystemNode *stackNode;
|
||||
const CCommanderInstance * commander;
|
||||
const CGHeroInstance *heroOwner;
|
||||
const CArtifactInstance *creatureArtifact; //currently worn artifact
|
||||
std::vector<CComponent*> upgResCost; //cost of upgrade (if not possible then empty)
|
||||
std::vector<CBonusItem*> bonusItems;
|
||||
std::vector<LRClickableAreaWText*> spellEffects;
|
||||
|
||||
CCreaturePic *anim; //related creature's animation
|
||||
MoraleLuckBox *luck, *morale;
|
||||
LRClickableAreaWTextComp * expArea; //displays exp details
|
||||
CSlider * slider; //Abilities
|
||||
CAdventureMapButton *dismiss, *upgrade, *ok;
|
||||
CAdventureMapButton * leftArtRoll, * rightArtRoll; //artifact selection
|
||||
CAdventureMapButton * passArtToHero;
|
||||
CAnimImage * artifactImage;
|
||||
CAnimation * spellEffectsPics; //bitmaps representing spells affecting a stack in battle
|
||||
|
||||
//commander level-up
|
||||
int selectedOption; //index for upgradeOptions
|
||||
std::vector<ui32> upgradeOptions; //value 0-5 - secondary skills, 100+ - special skills
|
||||
std::vector<CSelectableSkill *> selectableSkills, selectableBonuses;
|
||||
std::vector<CPicture *> skillPictures; //secondary skills
|
||||
|
||||
std::string skillToFile(int skill); //return bitmap for secondary skill depending on selection / avaliability
|
||||
void selectSkill (ui32 which);
|
||||
void setArt(const CArtifactInstance *creatureArtifact);
|
||||
|
||||
void artifactRemoved (const ArtifactLocation &artLoc);
|
||||
void artifactMoved (const ArtifactLocation &artLoc, const ArtifactLocation &destLoc);
|
||||
void artifactDisassembled (const ArtifactLocation &artLoc) {return;};
|
||||
void artifactAssembled (const ArtifactLocation &artLoc) {return;};
|
||||
|
||||
std::function<void()> dsm; //dismiss button callback
|
||||
std::function<void()> Upg; //upgrade button callback
|
||||
std::function<void(ui32)> levelUp; //choose commander skill to level up
|
||||
|
||||
CCreatureWindow(const CStack & stack, CreWinType type); //battle c-tor
|
||||
CCreatureWindow (const CStackInstance &stack, CreWinType Type); //pop-up c-tor
|
||||
CCreatureWindow(const CStackInstance &st, CreWinType Type, std::function<void()> Upg, std::function<void()> Dsm, UpgradeInfo *ui); //full garrison window
|
||||
CCreatureWindow(const CCommanderInstance * commander, const CStack * stack = nullptr); //commander window
|
||||
CCreatureWindow(std::vector<ui32> &skills, const CCommanderInstance * commander, std::function<void(ui32)> callback);
|
||||
CCreatureWindow(CreatureID Cid, CreWinType Type, int creatureCount); //c-tor
|
||||
|
||||
void init(const CStackInstance *stack, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner);
|
||||
void showAll(SDL_Surface * to);
|
||||
void show(SDL_Surface * to);
|
||||
void printLine(int nr, const std::string &text, int baseVal, int val=-1, bool range=false);
|
||||
void sliderMoved(int newpos);
|
||||
void close();
|
||||
~CCreatureWindow(); //d-tor
|
||||
|
||||
void recreateSkillList(int pos);
|
||||
void scrollArt(int dir);
|
||||
void passArtifactToHero();
|
||||
};
|
||||
|
||||
class CBonusItem : public LRClickableAreaWTextComp //responsible for displaying creature skill, active or not
|
||||
{
|
||||
public:
|
||||
std::string name, description;
|
||||
CPicture * bonusGraphics;
|
||||
bool visible;
|
||||
|
||||
CBonusItem();
|
||||
CBonusItem(const Rect &Pos, const std::string &Name, const std::string &Description, const std::string &graphicsName);
|
||||
~CBonusItem();
|
||||
|
||||
void showAll (SDL_Surface * to);
|
||||
};
|
||||
|
||||
class CSelectableSkill : public LRClickableAreaWText
|
||||
{
|
||||
public:
|
||||
std::function<void()> callback; //TODO: create more generic clickable class than AdvMapButton?
|
||||
|
||||
virtual void clickLeft(tribool down, bool previousState);
|
||||
virtual void clickRight(tribool down, bool previousState){};
|
||||
};
|
||||
|
||||
/// original creature info window
|
||||
class CCreInfoWindow : public CWindowObject
|
||||
{
|
||||
public:
|
||||
CLabel * creatureCount;
|
||||
CLabel * creatureName;
|
||||
CLabel * abilityText;
|
||||
|
||||
CCreaturePic * animation;
|
||||
std::vector<CComponent *> upgResCost; //cost of upgrade (if not possible then empty)
|
||||
std::vector<CAnimImage *> effects;
|
||||
std::map<size_t, std::pair<CLabel *, CLabel * > > infoTexts;
|
||||
|
||||
MoraleLuckBox * luck, * morale;
|
||||
|
||||
CAdventureMapButton * dismiss, * upgrade, * ok;
|
||||
|
||||
CCreInfoWindow(const CStackInstance & st, bool LClicked, std::function<void()> Upg = nullptr, std::function<void()> Dsm = nullptr, UpgradeInfo * ui = nullptr);
|
||||
CCreInfoWindow(const CStack & st, bool LClicked = 0);
|
||||
CCreInfoWindow(int Cid, bool LClicked, int creatureCount);
|
||||
~CCreInfoWindow();
|
||||
|
||||
void init(const CCreature * cre, const CBonusSystemNode * stackNode, const CGHeroInstance * heroOwner, int creatureCount, bool LClicked);
|
||||
void printLine(int nr, const std::string & text, int baseVal, int val = -1, bool range = false);
|
||||
|
||||
void show(SDL_Surface * to);
|
||||
};
|
||||
|
||||
CIntObject *createCreWindow(const CStack *s, bool lclick = false);
|
||||
CIntObject *createCreWindow(CreatureID Cid, CCreatureWindow::CreWinType Type, int creatureCount);
|
||||
CIntObject *createCreWindow(const CStackInstance *s, CCreatureWindow::CreWinType type, std::function<void()> Upg = nullptr, std::function<void()> Dsm = nullptr, UpgradeInfo *ui = nullptr);
|
@ -8,13 +8,13 @@
|
||||
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "CPreGame.h"
|
||||
#include "CCastleInterface.h"
|
||||
#include "windows/CCastleInterface.h"
|
||||
#include "../lib/CConsoleHandler.h"
|
||||
#include "gui/CCursorHandler.h"
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../CCallback.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "CAdvmapInterface.h"
|
||||
#include "windows/CAdvmapInterface.h"
|
||||
#include "../lib/CBuildingHandler.h"
|
||||
#include "CVideoHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
@ -39,8 +39,9 @@
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "../lib/logging/CBasicLogConfigurator.h"
|
||||
#include "../lib/CondSh.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef VCMI_WINDOWS
|
||||
#include "SDL_syswm.h"
|
||||
#endif
|
||||
#include "../lib/UnlockGuard.h"
|
||||
@ -51,6 +52,7 @@
|
||||
#endif
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace bfs = boost::filesystem;
|
||||
|
||||
/*
|
||||
* CMT.cpp, part of VCMI engine
|
||||
@ -72,13 +74,12 @@ int preferredDriverIndex = -1;
|
||||
SDL_Window * mainWindow = nullptr;
|
||||
SDL_Renderer * mainRenderer = nullptr;
|
||||
SDL_Texture * screenTexture = nullptr;
|
||||
|
||||
#endif // VCMI_SDL1
|
||||
|
||||
extern boost::thread_specific_ptr<bool> inGuiThread;
|
||||
|
||||
SDL_Surface *screen = nullptr, //main screen surface
|
||||
*screen2 = nullptr,//and hlp surface (used to store not-active interfaces layer)
|
||||
*screen2 = nullptr, //and hlp surface (used to store not-active interfaces layer)
|
||||
*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
|
||||
|
||||
std::queue<SDL_Event> events;
|
||||
@ -99,31 +100,29 @@ static void mainLoop();
|
||||
void startGame(StartInfo * options, CConnection *serv = nullptr);
|
||||
void endGame();
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifndef VCMI_WINDOWS
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
void startGameFromFile(const std::string &fname)
|
||||
void startGameFromFile(const bfs::path &fname)
|
||||
{
|
||||
StartInfo si;
|
||||
try //attempt retrieving start info from given file
|
||||
{
|
||||
if(!fname.size() || !boost::filesystem::exists(fname))
|
||||
throw std::runtime_error("Startfile \"" + fname + "\" does not exist!");
|
||||
if(fname.empty() || !bfs::exists(fname))
|
||||
throw std::runtime_error("Startfile \"" + fname.string() + "\" does not exist!");
|
||||
|
||||
CLoadFile out(fname);
|
||||
if(!out.sfile || !*out.sfile)
|
||||
{
|
||||
throw std::runtime_error("Cannot read from startfile \"" + fname + "\"!");
|
||||
}
|
||||
if (!out.sfile || !*out.sfile)
|
||||
throw std::runtime_error("Cannot read from startfile \"" + fname.string() +"\"!");
|
||||
out >> si;
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
logGlobal->errorStream() << "Failed to start from the file: " + fname << ". Error: " << e.what()
|
||||
logGlobal->errorStream() << "Failed to start from the file: " << fname << ". Error: " << e.what()
|
||||
<< " Falling back to main menu.";
|
||||
GH.curInt = CGPreGame::create();
|
||||
return;
|
||||
@ -183,19 +182,19 @@ static void prog_help(const po::options_description &opts)
|
||||
// printf(" -v, --version display version information and exit\n");
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
#ifdef VCMI_APPLE
|
||||
void OSX_checkForUpdates();
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined (__GNUC__)
|
||||
#if defined(VCMI_WINDOWS) && !defined (__GNUC__)
|
||||
int wmain(int argc, wchar_t* argv[])
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(VCMI_APPLE)
|
||||
int SDL_main(int argc, char *argv[])
|
||||
#else
|
||||
int main(int argc, char** argv)
|
||||
#endif
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
#ifdef VCMI_APPLE
|
||||
// Correct working dir executable folder (not bundle folder) so we can use executable relative paths
|
||||
std::string executablePath = argv[0];
|
||||
std::string workDir = executablePath.substr(0, executablePath.rfind('/'));
|
||||
@ -205,7 +204,7 @@ int main(int argc, char** argv)
|
||||
OSX_checkForUpdates();
|
||||
|
||||
// Check that game data is prepared. Otherwise run vcmibuilder helper application
|
||||
FILE* check = fopen((VCMIDirs::get().userDataPath() + "/game_data_prepared").c_str(), "r");
|
||||
FILE* check = fopen((VCMIDirs::get().userDataPath() / "game_data_prepared").string().c_str(), "r");
|
||||
if (check == nullptr) {
|
||||
system("open ./vcmibuilder.app");
|
||||
return 0;
|
||||
@ -218,7 +217,7 @@ int main(int argc, char** argv)
|
||||
("help,h", "display help and exit")
|
||||
("version,v", "display version information and exit")
|
||||
("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
|
||||
("start", po::value<std::string>(), "starts game from saved StartInfo file")
|
||||
("start", po::value<bfs::path>(), "starts game from saved StartInfo file")
|
||||
("onlyAI", "runs without human player, all players will be default AI")
|
||||
("noGUI", "runs without GUI, implies --onlyAI")
|
||||
("ai", po::value<std::vector<std::string>>(), "AI to be used for the player, can be specified several times for the consecutive players")
|
||||
@ -271,17 +270,17 @@ int main(int argc, char** argv)
|
||||
CStopWatch total, pomtime;
|
||||
std::cout.flags(std::ios::unitbuf);
|
||||
console = new CConsoleHandler;
|
||||
*console->cb = std::bind(&processCommand, _1);
|
||||
*console->cb = processCommand;
|
||||
console->start();
|
||||
atexit(dispose);
|
||||
|
||||
const auto logPath = VCMIDirs::get().userCachePath() + "/VCMI_Client_log.txt";
|
||||
const bfs::path logPath = VCMIDirs::get().userCachePath() / "VCMI_Client_log.txt";
|
||||
CBasicLogConfigurator logConfig(logPath, console);
|
||||
logConfig.configureDefault();
|
||||
logGlobal->infoStream() << "Creating console and configuring logger: " << pomtime.getDiff();
|
||||
logGlobal->infoStream() << "The log file will be saved to " << logPath;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#ifdef VCMI_ANDROID
|
||||
// boost will crash without this
|
||||
setenv("LANG", "C", 1);
|
||||
#endif
|
||||
@ -303,8 +302,7 @@ int main(int argc, char** argv)
|
||||
};
|
||||
|
||||
if (!testFile("DATA/HELP.TXT", "Heroes III data") ||
|
||||
!testFile("MODS/VCMI/MOD.JSON", "VCMI mod") ||
|
||||
!testFile("DATA/StackQueueBgBig.PCX", "VCMI data"))
|
||||
!testFile("MODS/VCMI/MOD.JSON", "VCMI data"))
|
||||
exit(1); // These are unrecoverable errors
|
||||
|
||||
// these two are optional + some installs have them on CD and not in data directory
|
||||
@ -388,7 +386,7 @@ int main(int argc, char** argv)
|
||||
|
||||
logGlobal->infoStream()<<"\tInitializing video: "<<pomtime.getDiff();
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(VCMI_ANDROID)
|
||||
//on Android threaded init is broken
|
||||
#define VCMI_NO_THREADED_LOAD
|
||||
#endif // defined
|
||||
@ -430,15 +428,15 @@ int main(int argc, char** argv)
|
||||
session["autoSkip"].Bool() = vm.count("autoSkip");
|
||||
session["oneGoodAI"].Bool() = vm.count("oneGoodAI");
|
||||
|
||||
std::string fileToStartFrom; //none by default
|
||||
bfs::path fileToStartFrom; //none by default
|
||||
if(vm.count("start"))
|
||||
fileToStartFrom = vm["start"].as<std::string>();
|
||||
fileToStartFrom = vm["start"].as<bfs::path>();
|
||||
|
||||
if(fileToStartFrom.size() && boost::filesystem::exists(fileToStartFrom))
|
||||
if(!fileToStartFrom.empty() && bfs::exists(fileToStartFrom))
|
||||
startGameFromFile(fileToStartFrom); //ommit pregame and start the game using settings from file
|
||||
else
|
||||
{
|
||||
if(fileToStartFrom.size())
|
||||
if(!fileToStartFrom.empty())
|
||||
{
|
||||
logGlobal->warnStream() << "Warning: cannot find given file to start from (" << fileToStartFrom
|
||||
<< "). Falling back to main menu.";
|
||||
@ -584,7 +582,8 @@ void processCommand(const std::string &message)
|
||||
{
|
||||
std::cout<<"Command accepted.\t";
|
||||
|
||||
std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
|
||||
const bfs::path outPath =
|
||||
VCMIDirs::get().userCachePath() / "extracted";
|
||||
|
||||
auto list = CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
|
||||
{
|
||||
@ -593,18 +592,18 @@ void processCommand(const std::string &message)
|
||||
|
||||
for (auto & filename : list)
|
||||
{
|
||||
std::string outName = outPath + filename.getName();
|
||||
const bfs::path filePath = outPath / (filename.getName() + ".TXT");
|
||||
|
||||
bfs::create_directories(filePath.parent_path());
|
||||
|
||||
boost::filesystem::create_directories(outName.substr(0, outName.find_last_of("/")));
|
||||
|
||||
std::ofstream file(outName + ".TXT");
|
||||
bfs::ofstream file(filePath);
|
||||
auto text = CResourceHandler::get()->load(filename)->readAll();
|
||||
|
||||
file.write((char*)text.first.get(), text.second);
|
||||
}
|
||||
|
||||
std::cout << "\rExtracting done :)\n";
|
||||
std::cout << " Extracted files can be found in " << outPath << " directory\n";
|
||||
std::cout << " Extracted files can be found in " << outPath << " directory\n";
|
||||
}
|
||||
else if(cn=="crash")
|
||||
{
|
||||
@ -710,15 +709,13 @@ void processCommand(const std::string &message)
|
||||
{
|
||||
CDefEssential * cde = CDefHandler::giveDefEss(URI);
|
||||
|
||||
std::string outName = URI;
|
||||
std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
|
||||
const bfs::path outPath = VCMIDirs::get().userCachePath() / "extracted" / URI;
|
||||
bfs::create_directories(outPath);
|
||||
|
||||
boost::filesystem::create_directories(outPath + outName);
|
||||
|
||||
for (size_t i=0; i<cde->ourImages.size(); i++)
|
||||
for (size_t i = 0; i < cde->ourImages.size(); ++i)
|
||||
{
|
||||
std::string filename = outPath + outName + '/' + boost::lexical_cast<std::string>(i) + ".bmp";
|
||||
SDL_SaveBMP(cde->ourImages[i].bitmap, filename.c_str());
|
||||
const bfs::path filePath = outPath / (boost::lexical_cast<std::string>(i)+".bmp");
|
||||
SDL_SaveBMP(cde->ourImages[i].bitmap, filePath.string().c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -731,14 +728,12 @@ void processCommand(const std::string &message)
|
||||
|
||||
if (CResourceHandler::get()->existsResource(ResourceID(URI)))
|
||||
{
|
||||
std::string outName = URI;
|
||||
std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
|
||||
std::string fullPath = outPath + outName;
|
||||
const bfs::path outPath = VCMIDirs::get().userCachePath() / "extracted" / URI;
|
||||
|
||||
auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
|
||||
|
||||
boost::filesystem::create_directories(fullPath.substr(0, fullPath.find_last_of("/")));
|
||||
std::ofstream outFile(outPath + outName, std::ofstream::binary);
|
||||
bfs::create_directories(outPath.parent_path());
|
||||
bfs::ofstream outFile(outPath, bfs::ofstream::binary);
|
||||
outFile.write((char*)data.first.get(), data.second);
|
||||
}
|
||||
else
|
||||
@ -1013,7 +1008,7 @@ static void setScreenRes(int w, int h, int bpp, bool fullscreen, bool resetVideo
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef VCMI_WINDOWS
|
||||
SDL_SysWMinfo wm;
|
||||
SDL_VERSION(&wm.version);
|
||||
int getwm = SDL_GetWMInfo(&wm);
|
||||
|
@ -14,39 +14,56 @@ set(client_SRCS
|
||||
battle/CBattleInterfaceClasses.cpp
|
||||
battle/CCreatureAnimation.cpp
|
||||
|
||||
gui/CAnimation.cpp
|
||||
gui/CCursorHandler.cpp
|
||||
gui/CGuiHandler.cpp
|
||||
gui/CIntObject.cpp
|
||||
gui/CIntObjectClasses.cpp
|
||||
gui/Fonts.cpp
|
||||
gui/Geometries.cpp
|
||||
gui/CCursorHandler.cpp
|
||||
gui/SDL_Extensions.cpp
|
||||
|
||||
CPreGame.cpp
|
||||
Client.cpp
|
||||
CPlayerInterface.cpp
|
||||
CMT.cpp
|
||||
GUIClasses.cpp
|
||||
AdventureMapClasses.cpp
|
||||
CAdvmapInterface.cpp
|
||||
CAnimation.cpp
|
||||
widgets/AdventureMapClasses.cpp
|
||||
widgets/Buttons.cpp
|
||||
widgets/CArtifactHolder.cpp
|
||||
widgets/CComponent.cpp
|
||||
widgets/CGarrisonInt.cpp
|
||||
widgets/Images.cpp
|
||||
widgets/MiscWidgets.cpp
|
||||
widgets/ObjectLists.cpp
|
||||
widgets/TextControls.cpp
|
||||
|
||||
windows/CAdvmapInterface.cpp
|
||||
windows/CCastleInterface.cpp
|
||||
windows/CCreatureWindow.cpp
|
||||
windows/CHeroWindow.cpp
|
||||
windows/CKingdomInterface.cpp
|
||||
windows/CQuestLog.cpp
|
||||
windows/CSpellWindow.cpp
|
||||
windows/CTradeWindow.cpp
|
||||
windows/CWindowObject
|
||||
windows/InfoWindows.cpp
|
||||
windows/GUIClasses.cpp
|
||||
|
||||
CBitmapHandler.cpp
|
||||
CCastleInterface.cpp
|
||||
CCreatureWindow.cpp
|
||||
CDefHandler.cpp
|
||||
CGameInfo.cpp
|
||||
CHeroWindow.cpp
|
||||
CKingdomInterface.cpp
|
||||
Client.cpp
|
||||
CMessage.cpp
|
||||
CMT.cpp
|
||||
CMusicHandler.cpp
|
||||
CSpellWindow.cpp
|
||||
CPlayerInterface.cpp
|
||||
CPreGame.cpp
|
||||
CVideoHandler.cpp
|
||||
CQuestLog.cpp
|
||||
Graphics.cpp
|
||||
mapHandler.cpp
|
||||
NetPacksClient.cpp
|
||||
)
|
||||
|
||||
set(client_HEADERS
|
||||
gui/SDL_Pixels.h
|
||||
gui/SDL_Compat.h
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
# OS X specific includes
|
||||
include_directories(${SPARKLE_INCLUDE_DIR})
|
||||
|
@ -11,17 +11,19 @@
|
||||
#include "StdInc.h"
|
||||
#include "CMessage.h"
|
||||
|
||||
#include "SDL_ttf.h"
|
||||
#include "CDefHandler.h"
|
||||
#include "CAnimation.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "Graphics.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "windows/GUIClasses.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "CBitmapHandler.h"
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
|
||||
#include "widgets/CComponent.h"
|
||||
#include "windows/InfoWindows.h"
|
||||
#include "widgets/Buttons.h"
|
||||
#include "widgets/TextControls.h"
|
||||
|
||||
const int BETWEEN_COMPS_ROWS = 10;
|
||||
const int BEFORE_COMPONENTS = 30;
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/CSoundBase.h"
|
||||
#include "../lib/CCreatureHandler.h"
|
||||
|
||||
/*
|
||||
* CMusicHandler.h, part of VCMI engine
|
||||
|
@ -1,27 +1,31 @@
|
||||
#include "StdInc.h"
|
||||
#include "CAdvmapInterface.h"
|
||||
#include "windows/CAdvmapInterface.h"
|
||||
#include "battle/CBattleInterface.h"
|
||||
#include "battle/CBattleInterfaceClasses.h"
|
||||
#include "../CCallback.h"
|
||||
#include "CCastleInterface.h"
|
||||
#include "windows/CCastleInterface.h"
|
||||
#include "gui/CCursorHandler.h"
|
||||
#include "CKingdomInterface.h"
|
||||
#include "windows/CKingdomInterface.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "CHeroWindow.h"
|
||||
#include "CCreatureWindow.h"
|
||||
#include "CQuestLog.h"
|
||||
#include "windows/CHeroWindow.h"
|
||||
#include "windows/CCreatureWindow.h"
|
||||
#include "windows/CQuestLog.h"
|
||||
#include "CMessage.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "widgets/CComponent.h"
|
||||
#include "windows/CTradeWindow.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "battle/CCreatureAnimation.h"
|
||||
#include "Graphics.h"
|
||||
#include "windows/GUIClasses.h"
|
||||
#include "../lib/CArtHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/Connection.h"
|
||||
#include "../lib/CSpellHandler.h"
|
||||
#include "../lib/CTownHandler.h"
|
||||
#include "../lib/mapObjects/CObjectClassesHandler.h" // For displaying correct UI when interacting with objects
|
||||
#include "../lib/BattleState.h"
|
||||
#include "../lib/JsonNode.h"
|
||||
#include "CMusicHandler.h"
|
||||
@ -35,14 +39,9 @@
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "windows/InfoWindows.h"
|
||||
#include "../lib/UnlockGuard.h"
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
#include <SDL.h>
|
||||
|
||||
/*
|
||||
* CPlayerInterface.cpp, part of VCMI engine
|
||||
@ -245,10 +244,6 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
return;
|
||||
}
|
||||
|
||||
adventureInt->centerOn(hero); //actualizing screen pos
|
||||
adventureInt->minimap.redraw();
|
||||
adventureInt->heroList.redraw();
|
||||
|
||||
bool directlyAttackingCreature =
|
||||
details.attackedFrom
|
||||
&& adventureInt->terrain.currentPath //in case if movement has been canceled in the meantime and path was already erased
|
||||
@ -305,12 +300,30 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
return;
|
||||
}
|
||||
|
||||
ui32 speed;
|
||||
if (makingTurn) // our turn, our hero moves
|
||||
speed = settings["adventure"]["heroSpeed"].Float();
|
||||
else
|
||||
speed = settings["adventure"]["enemySpeed"].Float();
|
||||
|
||||
if (speed == 0)
|
||||
{
|
||||
//FIXME: is this a proper solution?
|
||||
CGI->mh->hideObject(hero);
|
||||
CGI->mh->printObject(hero);
|
||||
return; // no animation
|
||||
}
|
||||
|
||||
|
||||
adventureInt->centerOn(hero); //actualizing screen pos
|
||||
adventureInt->minimap.redraw();
|
||||
adventureInt->heroList.redraw();
|
||||
|
||||
initMovement(details, hero, hp);
|
||||
|
||||
//first initializing done
|
||||
GH.mainFPSmng->framerateDelay(); // after first move
|
||||
|
||||
ui32 speed = settings["adventure"]["heroSpeed"].Float();
|
||||
//main moving
|
||||
for(int i=1; i<32; i+=2*speed)
|
||||
{
|
||||
@ -319,14 +332,14 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
adventureInt->show(screen);
|
||||
{
|
||||
//evil returns here ...
|
||||
//todo: get rid of it
|
||||
//todo: get rid of it
|
||||
logGlobal->traceStream() << "before [un]locks in " << __FUNCTION__;
|
||||
auto unlockPim = vstd::makeUnlockGuard(*pim); //let frame to be rendered
|
||||
GH.mainFPSmng->framerateDelay(); //for animation purposes
|
||||
logGlobal->traceStream() << "after [un]locks in " << __FUNCTION__;
|
||||
logGlobal->traceStream() << "after [un]locks in " << __FUNCTION__;
|
||||
}
|
||||
//CSDL_Ext::update(screen);
|
||||
|
||||
|
||||
} //for(int i=1; i<32; i+=4)
|
||||
//main moving done
|
||||
|
||||
@ -494,10 +507,12 @@ void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander,
|
||||
waitWhileDialog();
|
||||
CCS->soundh->playSound(soundBase::heroNewLevel);
|
||||
|
||||
CCreatureWindow * cw = new CCreatureWindow(skills, commander,
|
||||
[=](ui32 selection){ cb->selectionMade(selection, queryID); });
|
||||
GH.pushInt(cw);
|
||||
GH.pushInt(new CStackWindow(commander, skills, [=](ui32 selection)
|
||||
{
|
||||
cb->selectionMade(selection, queryID);
|
||||
}));
|
||||
}
|
||||
|
||||
void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
@ -1285,8 +1300,8 @@ void CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
|
||||
|
||||
if (adventureInt && adventureInt->isHeroSleeping(h))
|
||||
{
|
||||
adventureInt->sleepWake.clickLeft(true, false);
|
||||
adventureInt->sleepWake.clickLeft(false, true);
|
||||
adventureInt->sleepWake->clickLeft(true, false);
|
||||
adventureInt->sleepWake->clickLeft(false, true);
|
||||
//could've just called
|
||||
//adventureInt->fsleepWake();
|
||||
//but no authentic button click/sound ;-)
|
||||
@ -1321,7 +1336,7 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
|
||||
waitForAllDialogs();
|
||||
|
||||
auto cgw = new CGarrisonWindow(up,down,removableUnits);
|
||||
cgw->quit->callback += onEnd;
|
||||
cgw->quit->addCallback(onEnd);
|
||||
GH.pushInt(cgw);
|
||||
}
|
||||
|
||||
@ -1515,6 +1530,16 @@ void CPlayerInterface::centerView (int3 pos, int focusTime)
|
||||
void CPlayerInterface::objectRemoved( const CGObjectInstance *obj )
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
if (LOCPLINT->cb->getCurrentPlayer() == playerID) {
|
||||
std::string handlerName = VLC->objtypeh->getObjectHandlerName(obj->ID);
|
||||
if ((handlerName == "pickable") || (handlerName == "scholar") || (handlerName== "artifact") || (handlerName == "pandora")) {
|
||||
waitWhileDialog();
|
||||
CCS->soundh->playSoundFromSet(CCS->soundh->pickupSounds);
|
||||
} else if ((handlerName == "monster") || (handlerName == "hero")) {
|
||||
waitWhileDialog();
|
||||
CCS->soundh->playSound(soundBase::KillFade);
|
||||
}
|
||||
}
|
||||
if(obj->ID == Obj::HERO && obj->tempOwner == playerID)
|
||||
{
|
||||
const CGHeroInstance *h = static_cast<const CGHeroInstance*>(obj);
|
||||
@ -1601,22 +1626,20 @@ int CPlayerInterface::getLastIndex( std::string namePrefix)
|
||||
path gamesDir = VCMIDirs::get().userSavePath();
|
||||
std::map<std::time_t, int> dates; //save number => datestamp
|
||||
|
||||
directory_iterator enddir;
|
||||
const directory_iterator enddir;
|
||||
if(!exists(gamesDir))
|
||||
create_directory(gamesDir);
|
||||
|
||||
for (directory_iterator dir(gamesDir); dir!=enddir; dir++)
|
||||
else
|
||||
for (directory_iterator dir(gamesDir); dir != enddir; ++dir)
|
||||
{
|
||||
if(is_regular(dir->status()))
|
||||
{
|
||||
std::string name = dir->path().leaf().string();
|
||||
std::string name = dir->path().filename().string();
|
||||
if(starts_with(name, namePrefix) && ends_with(name, ".vcgm1"))
|
||||
{
|
||||
char nr = name[namePrefix.size()];
|
||||
if(std::isdigit(nr))
|
||||
{
|
||||
dates[last_write_time(dir->path())] = boost::lexical_cast<int>(nr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2239,7 +2262,7 @@ void CPlayerInterface::acceptTurn()
|
||||
if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt()))
|
||||
iw->close();
|
||||
|
||||
adventureInt->endTurn.callback();
|
||||
adventureInt->fendTurn();
|
||||
}
|
||||
|
||||
// warn player if he has no town
|
||||
|
@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../lib/CondSh.h"
|
||||
//#include "../lib/CondSh.h"
|
||||
#include "../lib/FunctionList.h"
|
||||
#include "../lib/CGameInterface.h"
|
||||
#include "../lib/NetPacksBase.h"
|
||||
#include "gui/CIntObject.h"
|
||||
#include "../lib/CGameState.h"
|
||||
//#include "../lib/CGameState.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define sprintf_s snprintf
|
||||
@ -29,8 +30,8 @@
|
||||
*/
|
||||
|
||||
class CDefEssential;
|
||||
class CAdventureMapButton;
|
||||
class CHighlightableButtonsGroup;
|
||||
class CButton;
|
||||
class CToggleGroup;
|
||||
class CDefHandler;
|
||||
struct TryMoveHero;
|
||||
class CDefEssential;
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "gui/CCursorHandler.h"
|
||||
#include "CAnimation.h"
|
||||
#include "CDefHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CTownHandler.h"
|
||||
@ -23,7 +22,7 @@
|
||||
#include "../lib/Connection.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "windows/GUIClasses.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "../CCallback.h"
|
||||
#include "CMessage.h"
|
||||
@ -38,7 +37,13 @@
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
#include "gui/CAnimation.h"
|
||||
#include "widgets/CComponent.h"
|
||||
#include "widgets/Buttons.h"
|
||||
#include "widgets/MiscWidgets.h"
|
||||
#include "widgets/ObjectLists.h"
|
||||
#include "widgets/TextControls.h"
|
||||
#include "windows/InfoWindows.h"
|
||||
#include "../lib/mapping/CMapService.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
@ -367,7 +372,7 @@ static std::function<void()> genCommand(CMenuScreen* menu, std::vector<std::stri
|
||||
return std::function<void()>();
|
||||
}
|
||||
|
||||
CAdventureMapButton* CMenuEntry::createButton(CMenuScreen* parent, const JsonNode& button)
|
||||
CButton* CMenuEntry::createButton(CMenuScreen* parent, const JsonNode& button)
|
||||
{
|
||||
std::function<void()> command = genCommand(parent, parent->menuNameToEntry, button["command"].String());
|
||||
|
||||
@ -383,7 +388,7 @@ CAdventureMapButton* CMenuEntry::createButton(CMenuScreen* parent, const JsonNod
|
||||
if (posy < 0)
|
||||
posy = pos.h + posy;
|
||||
|
||||
return new CAdventureMapButton(help, command, posx, posy, button["name"].String(), button["hotkey"].Float());
|
||||
return new CButton(Point(posx, posy), button["name"].String(), help, command, button["hotkey"].Float());
|
||||
}
|
||||
|
||||
CMenuEntry::CMenuEntry(CMenuScreen* parent, const JsonNode &config)
|
||||
@ -639,38 +644,39 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
||||
{
|
||||
case CMenuScreen::newGame:
|
||||
{
|
||||
card->difficulty->onChange = std::bind(&CSelectionScreen::difficultyChange, this, _1);
|
||||
card->difficulty->select(1, 0);
|
||||
CAdventureMapButton * select = new CAdventureMapButton(CGI->generaltexth->zelp[45], 0, 411, 80, "GSPBUTT.DEF", SDLK_s);
|
||||
select->callback = [&]()
|
||||
SDL_Color orange = {232, 184, 32, 0};
|
||||
SDL_Color overlayColor = multiPlayer == CMenuScreen::MULTI_NETWORK_GUEST ? orange : Colors::WHITE;
|
||||
|
||||
card->difficulty->addCallback(std::bind(&CSelectionScreen::difficultyChange, this, _1));
|
||||
card->difficulty->setSelected(1);
|
||||
CButton * select = new CButton(Point(411, 80), "GSPBUTT.DEF", CGI->generaltexth->zelp[45], 0, SDLK_s);
|
||||
select->addCallback([&]()
|
||||
{
|
||||
toggleTab(sel);
|
||||
changeSelection(sel->getSelectedMapInfo());
|
||||
};
|
||||
select->addTextOverlay(CGI->generaltexth->allTexts[500], FONT_SMALL);
|
||||
});
|
||||
select->addTextOverlay(CGI->generaltexth->allTexts[500], FONT_SMALL, overlayColor);
|
||||
|
||||
CAdventureMapButton *opts = new CAdventureMapButton(CGI->generaltexth->zelp[46], std::bind(&CSelectionScreen::toggleTab, this, opt), 411, 510, "GSPBUTT.DEF", SDLK_a);
|
||||
opts->addTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL);
|
||||
CButton *opts = new CButton(Point(411, 510), "GSPBUTT.DEF", CGI->generaltexth->zelp[46], std::bind(&CSelectionScreen::toggleTab, this, opt), SDLK_a);
|
||||
opts->addTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL, overlayColor);
|
||||
|
||||
CAdventureMapButton * randomBtn = new CAdventureMapButton(CGI->generaltexth->zelp[47], 0, 411, 105, "GSPBUTT.DEF", SDLK_r);
|
||||
randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL);
|
||||
randomBtn->callback = [&]()
|
||||
CButton * randomBtn = new CButton(Point(411, 105), "GSPBUTT.DEF", CGI->generaltexth->zelp[47], 0, SDLK_r);
|
||||
randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL, overlayColor);
|
||||
randomBtn->addCallback([&]()
|
||||
{
|
||||
toggleTab(randMapTab);
|
||||
changeSelection(randMapTab->getMapInfo());
|
||||
};
|
||||
});
|
||||
|
||||
start = new CAdventureMapButton(CGI->generaltexth->zelp[103], std::bind(&CSelectionScreen::startScenario, this), 411, 535, "SCNRBEG.DEF", SDLK_b);
|
||||
start = new CButton(Point(411, 535), "SCNRBEG.DEF", CGI->generaltexth->zelp[103], std::bind(&CSelectionScreen::startScenario, this), SDLK_b);
|
||||
|
||||
if(network)
|
||||
{
|
||||
CAdventureMapButton *hideChat = new CAdventureMapButton(CGI->generaltexth->zelp[48], std::bind(&InfoCard::toggleChat, card), 619, 83, "GSPBUT2.DEF", SDLK_h);
|
||||
CButton *hideChat = new CButton(Point(619, 83), "GSPBUT2.DEF", CGI->generaltexth->zelp[48], std::bind(&InfoCard::toggleChat, card), SDLK_h);
|
||||
hideChat->addTextOverlay(CGI->generaltexth->allTexts[531], FONT_SMALL);
|
||||
|
||||
if(multiPlayer == CMenuScreen::MULTI_NETWORK_GUEST)
|
||||
{
|
||||
SDL_Color orange = {232, 184, 32, 0};
|
||||
select->text->color = opts->text->color = randomBtn->text->color = orange;
|
||||
select->block(true);
|
||||
opts->block(true);
|
||||
randomBtn->block(true);
|
||||
@ -681,21 +687,21 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
||||
break;
|
||||
case CMenuScreen::loadGame:
|
||||
sel->recActions = 255;
|
||||
start = new CAdventureMapButton(CGI->generaltexth->zelp[103], std::bind(&CSelectionScreen::startScenario, this), 411, 535, "SCNRLOD.DEF", SDLK_l);
|
||||
start = new CButton(Point(411, 535), "SCNRLOD.DEF", CGI->generaltexth->zelp[103], std::bind(&CSelectionScreen::startScenario, this), SDLK_l);
|
||||
break;
|
||||
case CMenuScreen::saveGame:
|
||||
sel->recActions = 255;
|
||||
start = new CAdventureMapButton("", CGI->generaltexth->zelp[103].second, std::bind(&CSelectionScreen::startScenario, this), 411, 535, "SCNRSAV.DEF");
|
||||
start = new CButton(Point(411, 535), "SCNRSAV.DEF", CGI->generaltexth->zelp[103], std::bind(&CSelectionScreen::startScenario, this), SDLK_s);
|
||||
break;
|
||||
case CMenuScreen::campaignList:
|
||||
sel->recActions = 255;
|
||||
start = new CAdventureMapButton(std::pair<std::string, std::string>(), std::bind(&CSelectionScreen::startCampaign, this), 411, 535, "SCNRLOD.DEF", SDLK_b);
|
||||
start = new CButton(Point(411, 535), "SCNRLOD.DEF", CButton::tooltip(), std::bind(&CSelectionScreen::startCampaign, this), SDLK_b);
|
||||
break;
|
||||
}
|
||||
|
||||
start->assignedKeys.insert(SDLK_RETURN);
|
||||
|
||||
back = new CAdventureMapButton("", CGI->generaltexth->zelp[105].second, std::bind(&CGuiHandler::popIntTotally, &GH, this), 581, 535, "SCNRBACK.DEF", SDLK_ESCAPE);
|
||||
back = new CButton(Point(581, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], std::bind(&CGuiHandler::popIntTotally, &GH, this), SDLK_ESCAPE);
|
||||
|
||||
if(network)
|
||||
{
|
||||
@ -995,7 +1001,7 @@ void CSelectionScreen::setSInfo(const StartInfo &si)
|
||||
if(current)
|
||||
opt->recreate(); //will force to recreate using current sInfo
|
||||
|
||||
card->difficulty->select(si.difficulty, 0);
|
||||
card->difficulty->setSelected(si.difficulty);
|
||||
|
||||
GH.totalRedraw();
|
||||
}
|
||||
@ -1258,7 +1264,7 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const std::function<void(CM
|
||||
int sizes[] = {36, 72, 108, 144, 0};
|
||||
const char * names[] = {"SCSMBUT.DEF", "SCMDBUT.DEF", "SCLGBUT.DEF", "SCXLBUT.DEF", "SCALBUT.DEF"};
|
||||
for(int i = 0; i < 5; i++)
|
||||
new CAdventureMapButton("", CGI->generaltexth->zelp[54+i].second, std::bind(&SelectionTab::filter, this, sizes[i], true), 158 + 47*i, 46, names[i]);
|
||||
new CButton(Point(158 + 47*i, 46), names[i], CGI->generaltexth->zelp[54+i], std::bind(&SelectionTab::filter, this, sizes[i], true));
|
||||
}
|
||||
|
||||
//sort buttons buttons
|
||||
@ -1272,20 +1278,19 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const std::function<void(CM
|
||||
if(criteria == _name)
|
||||
criteria = generalSortingBy;
|
||||
|
||||
new CAdventureMapButton("", CGI->generaltexth->zelp[107+i].second, std::bind(&SelectionTab::sortBy, this, criteria), xpos[i], 86, names[i]);
|
||||
new CButton(Point(xpos[i], 86), names[i], CGI->generaltexth->zelp[107+i], std::bind(&SelectionTab::sortBy, this, criteria));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//sort by buttons
|
||||
new CAdventureMapButton("", "", std::bind(&SelectionTab::sortBy, this, _numOfMaps), 23, 86, "CamCusM.DEF"); //by num of maps
|
||||
new CAdventureMapButton("", "", std::bind(&SelectionTab::sortBy, this, _name), 55, 86, "CamCusL.DEF"); //by name
|
||||
new CButton(Point(23, 86), "CamCusM.DEF", CButton::tooltip(), std::bind(&SelectionTab::sortBy, this, _numOfMaps)); //by num of maps
|
||||
new CButton(Point(55, 86), "CamCusL.DEF", CButton::tooltip(), std::bind(&SelectionTab::sortBy, this, _name)); //by name
|
||||
}
|
||||
|
||||
slider = new CSlider(372, 86, tabType != CMenuScreen::saveGame ? 480 : 430, std::bind(&SelectionTab::sliderMove, this, _1), positions, curItems.size(), 0, false, 1);
|
||||
slider = new CSlider(Point(372, 86), tabType != CMenuScreen::saveGame ? 480 : 430, std::bind(&SelectionTab::sliderMove, this, _1), positions, curItems.size(), 0, false, CSlider::BLUE);
|
||||
slider->addUsedEvents(WHEEL);
|
||||
slider->slider->keepFrame = true;
|
||||
format = CDefHandler::giveDef("SCSELC.DEF");
|
||||
|
||||
sortingBy = _format;
|
||||
@ -1351,16 +1356,16 @@ void SelectionTab::select( int position )
|
||||
if(!curItems.size()) return;
|
||||
|
||||
// New selection. py is the index in curItems.
|
||||
int py = position + slider->value;
|
||||
int py = position + slider->getValue();
|
||||
vstd::amax(py, 0);
|
||||
vstd::amin(py, curItems.size()-1);
|
||||
|
||||
selectionPos = py;
|
||||
|
||||
if(position < 0)
|
||||
slider->moveTo(slider->value + position);
|
||||
slider->moveBy(position);
|
||||
else if(position >= positions)
|
||||
slider->moveTo(slider->value + position - positions + 1);
|
||||
slider->moveBy(position - positions + 1);
|
||||
|
||||
if(txt)
|
||||
{
|
||||
@ -1374,7 +1379,7 @@ void SelectionTab::select( int position )
|
||||
|
||||
void SelectionTab::selectAbs( int position )
|
||||
{
|
||||
select(position - slider->value);
|
||||
select(position - slider->getValue());
|
||||
}
|
||||
|
||||
int SelectionTab::getPosition( int x, int y )
|
||||
@ -1397,7 +1402,7 @@ void SelectionTab::sliderMove( int slidPos )
|
||||
void SelectionTab::printMaps(SDL_Surface *to)
|
||||
{
|
||||
|
||||
int elemIdx = slider->value;
|
||||
int elemIdx = slider->getValue();
|
||||
|
||||
// Display all elements if there's enough space
|
||||
//if(slider->amount < slider->capacity)
|
||||
@ -1555,15 +1560,15 @@ void SelectionTab::keyPressed( const SDL_KeyboardEvent & key )
|
||||
moveBy = +positions-1;
|
||||
break;
|
||||
case SDLK_HOME:
|
||||
select(-slider->value);
|
||||
select(-slider->getValue());
|
||||
return;
|
||||
case SDLK_END:
|
||||
select(curItems.size() - slider->value);
|
||||
select(curItems.size() - slider->getValue());
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
select(selectionPos - slider->value + moveBy);
|
||||
select(selectionPos - slider->getValue() + moveBy);
|
||||
}
|
||||
|
||||
void SelectionTab::onDoubleClick()
|
||||
@ -1571,7 +1576,7 @@ void SelectionTab::onDoubleClick()
|
||||
if(getLine() != -1) //double clicked scenarios list
|
||||
{
|
||||
//act as if start button was pressed
|
||||
(static_cast<CSelectionScreen*>(parent))->start->callback();
|
||||
(static_cast<CSelectionScreen*>(parent))->start->clickLeft(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1616,27 +1621,25 @@ CRandomMapTab::CRandomMapTab()
|
||||
bg = new CPicture("RANMAPBK", 0, 6);
|
||||
|
||||
// Map Size
|
||||
mapSizeBtnGroup = new CHighlightableButtonsGroup(0);
|
||||
mapSizeBtnGroup = new CToggleGroup(0);
|
||||
mapSizeBtnGroup->pos.y += 81;
|
||||
mapSizeBtnGroup->pos.x += 158;
|
||||
const std::vector<std::string> mapSizeBtns = boost::assign::list_of("RANSIZS")("RANSIZM")("RANSIZL")("RANSIZX");
|
||||
addButtonsToGroup(mapSizeBtnGroup, mapSizeBtns, 0, 3, 47, 198);
|
||||
mapSizeBtnGroup->select(1, false);
|
||||
mapSizeBtnGroup->onChange = [&](int btnId)
|
||||
mapSizeBtnGroup->setSelected(1);
|
||||
mapSizeBtnGroup->addCallback([&](int btnId)
|
||||
{
|
||||
const std::vector<int> mapSizeVal = boost::assign::list_of(CMapHeader::MAP_SIZE_SMALL)(CMapHeader::MAP_SIZE_MIDDLE)
|
||||
(CMapHeader::MAP_SIZE_LARGE)(CMapHeader::MAP_SIZE_XLARGE);
|
||||
mapGenOptions.setWidth(mapSizeVal[btnId]);
|
||||
mapGenOptions.setHeight(mapSizeVal[btnId]);
|
||||
updateMapInfo();
|
||||
};
|
||||
});
|
||||
|
||||
// Two levels
|
||||
twoLevelsBtn = new CHighlightableButton(0, 0, std::map<int,std::string>(),
|
||||
CGI->generaltexth->zelp[202].second, false, "RANUNDR", nullptr, 346, 81);
|
||||
twoLevelsBtn = new CToggleButton(Point(346, 81), "RANUNDR", CGI->generaltexth->zelp[202]);
|
||||
//twoLevelsBtn->select(true); for now, deactivated
|
||||
twoLevelsBtn->callback = [&]() { mapGenOptions.setHasTwoLevels(true); updateMapInfo(); };
|
||||
twoLevelsBtn->callback2 = [&]() { mapGenOptions.setHasTwoLevels(false); updateMapInfo(); };
|
||||
twoLevelsBtn->addCallback([&](bool on) { mapGenOptions.setHasTwoLevels(on); updateMapInfo(); });
|
||||
|
||||
// Create number defs list
|
||||
std::vector<std::string> numberDefs;
|
||||
@ -1648,128 +1651,130 @@ CRandomMapTab::CRandomMapTab()
|
||||
const int NUMBERS_WIDTH = 32;
|
||||
const int BTNS_GROUP_LEFT_MARGIN = 67;
|
||||
// Amount of players
|
||||
playersCntGroup = new CHighlightableButtonsGroup(0);
|
||||
playersCntGroup = new CToggleGroup(0);
|
||||
playersCntGroup->pos.y += 153;
|
||||
playersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(playersCntGroup, numberDefs, 1, 8, NUMBERS_WIDTH, 204, 212);
|
||||
playersCntGroup->onChange = [&](int btnId)
|
||||
playersCntGroup->addCallback([&](int btnId)
|
||||
{
|
||||
mapGenOptions.setPlayerCount(btnId);
|
||||
deactivateButtonsFrom(teamsCntGroup, btnId);
|
||||
deactivateButtonsFrom(compOnlyPlayersCntGroup, 8 - btnId + 1);
|
||||
validatePlayersCnt(btnId);
|
||||
updateMapInfo();
|
||||
};
|
||||
});
|
||||
|
||||
// Amount of teams
|
||||
teamsCntGroup = new CHighlightableButtonsGroup(0);
|
||||
teamsCntGroup = new CToggleGroup(0);
|
||||
teamsCntGroup->pos.y += 219;
|
||||
teamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(teamsCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 214, 222);
|
||||
teamsCntGroup->onChange = [&](int btnId)
|
||||
teamsCntGroup->addCallback([&](int btnId)
|
||||
{
|
||||
mapGenOptions.setTeamCount(btnId);
|
||||
updateMapInfo();
|
||||
};
|
||||
});
|
||||
|
||||
// Computer only players
|
||||
compOnlyPlayersCntGroup = new CHighlightableButtonsGroup(0);
|
||||
compOnlyPlayersCntGroup = new CToggleGroup(0);
|
||||
compOnlyPlayersCntGroup->pos.y += 285;
|
||||
compOnlyPlayersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(compOnlyPlayersCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 224, 232);
|
||||
compOnlyPlayersCntGroup->select(0, true);
|
||||
compOnlyPlayersCntGroup->onChange = [&](int btnId)
|
||||
compOnlyPlayersCntGroup->setSelected(0);
|
||||
compOnlyPlayersCntGroup->addCallback([&](int btnId)
|
||||
{
|
||||
mapGenOptions.setCompOnlyPlayerCount(btnId);
|
||||
deactivateButtonsFrom(compOnlyTeamsCntGroup, btnId);
|
||||
validateCompOnlyPlayersCnt(btnId);
|
||||
updateMapInfo();
|
||||
};
|
||||
});
|
||||
|
||||
// Computer only teams
|
||||
compOnlyTeamsCntGroup = new CHighlightableButtonsGroup(0);
|
||||
compOnlyTeamsCntGroup = new CToggleGroup(0);
|
||||
compOnlyTeamsCntGroup->pos.y += 351;
|
||||
compOnlyTeamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(compOnlyTeamsCntGroup, numberDefs, 0, 6, NUMBERS_WIDTH, 234, 241);
|
||||
deactivateButtonsFrom(compOnlyTeamsCntGroup, 0);
|
||||
compOnlyTeamsCntGroup->onChange = [&](int btnId)
|
||||
compOnlyTeamsCntGroup->addCallback([&](int btnId)
|
||||
{
|
||||
mapGenOptions.setCompOnlyTeamCount(btnId);
|
||||
updateMapInfo();
|
||||
};
|
||||
});
|
||||
|
||||
const int WIDE_BTN_WIDTH = 85;
|
||||
// Water content
|
||||
waterContentGroup = new CHighlightableButtonsGroup(0);
|
||||
waterContentGroup = new CToggleGroup(0);
|
||||
waterContentGroup->pos.y += 419;
|
||||
waterContentGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
const std::vector<std::string> waterContentBtns = boost::assign::list_of("RANNONE")("RANNORM")("RANISLD");
|
||||
addButtonsWithRandToGroup(waterContentGroup, waterContentBtns, 0, 2, WIDE_BTN_WIDTH, 243, 246);
|
||||
waterContentGroup->onChange = [&](int btnId)
|
||||
waterContentGroup->addCallback([&](int btnId)
|
||||
{
|
||||
mapGenOptions.setWaterContent(static_cast<EWaterContent::EWaterContent>(btnId));
|
||||
};
|
||||
});
|
||||
|
||||
// Monster strength
|
||||
monsterStrengthGroup = new CHighlightableButtonsGroup(0);
|
||||
monsterStrengthGroup = new CToggleGroup(0);
|
||||
monsterStrengthGroup->pos.y += 485;
|
||||
monsterStrengthGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
const std::vector<std::string> monsterStrengthBtns = boost::assign::list_of("RANWEAK")("RANNORM")("RANSTRG");
|
||||
addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251);
|
||||
monsterStrengthGroup->onChange = [&](int btnId)
|
||||
monsterStrengthGroup->addCallback([&](int btnId)
|
||||
{
|
||||
if (btnId < 0)
|
||||
mapGenOptions.setMonsterStrength(EMonsterStrength::RANDOM);
|
||||
else
|
||||
mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId + EMonsterStrength::GLOBAL_WEAK)); //value 2 to 4
|
||||
};
|
||||
});
|
||||
|
||||
// Show random maps btn
|
||||
showRandMaps = new CAdventureMapButton("", CGI->generaltexth->zelp[252].second, 0, 54, 535, "RANSHOW");
|
||||
showRandMaps = new CButton(Point(54, 535), "RANSHOW", CGI->generaltexth->zelp[252]);
|
||||
|
||||
// Initialize map info object
|
||||
updateMapInfo();
|
||||
}
|
||||
|
||||
void CRandomMapTab::addButtonsWithRandToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex, int helpRandIndex) const
|
||||
void CRandomMapTab::addButtonsWithRandToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex, int helpRandIndex) const
|
||||
{
|
||||
addButtonsToGroup(group, defs, nStart, nEnd, btnWidth, helpStartIndex);
|
||||
|
||||
// Buttons are relative to button group, TODO better solution?
|
||||
SObjectConstruction obj__i(group);
|
||||
const std::string RANDOM_DEF = "RANRAND";
|
||||
group->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[helpRandIndex].second, 0, 256, 0, RANDOM_DEF, CMapGenOptions::RANDOM_SIZE));
|
||||
group->select(CMapGenOptions::RANDOM_SIZE, true);
|
||||
group->addToggle(CMapGenOptions::RANDOM_SIZE, new CToggleButton(Point(256, 0), RANDOM_DEF, CGI->generaltexth->zelp[helpRandIndex]));
|
||||
group->setSelected(CMapGenOptions::RANDOM_SIZE);
|
||||
}
|
||||
|
||||
void CRandomMapTab::addButtonsToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex) const
|
||||
void CRandomMapTab::addButtonsToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex) const
|
||||
{
|
||||
// Buttons are relative to button group, TODO better solution?
|
||||
SObjectConstruction obj__i(group);
|
||||
int cnt = nEnd - nStart + 1;
|
||||
for(int i = 0; i < cnt; ++i)
|
||||
{
|
||||
group->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[helpStartIndex + i].second, 0, i * btnWidth, 0, defs[i + nStart], i + nStart));
|
||||
auto button = new CToggleButton(Point(i * btnWidth, 0), defs[i + nStart], CGI->generaltexth->zelp[helpStartIndex + i]);
|
||||
// For blocked state we should use pressed image actually
|
||||
button->setImageOrder(0, 1, 1, 3);
|
||||
|
||||
group->addToggle(i + nStart, button);
|
||||
}
|
||||
}
|
||||
|
||||
void CRandomMapTab::deactivateButtonsFrom(CHighlightableButtonsGroup * group, int startId)
|
||||
void CRandomMapTab::deactivateButtonsFrom(CToggleGroup * group, int startId)
|
||||
{
|
||||
for(CHighlightableButton * btn : group->buttons)
|
||||
logGlobal->infoStream() << "Blocking buttons from " << startId;
|
||||
for(auto toggle : group->buttons)
|
||||
{
|
||||
if(startId == CMapGenOptions::RANDOM_SIZE || btn->ID < startId)
|
||||
if (auto button = dynamic_cast<CToggleButton*>(toggle.second))
|
||||
{
|
||||
if(btn->isBlocked())
|
||||
if(startId == CMapGenOptions::RANDOM_SIZE || toggle.first < startId)
|
||||
{
|
||||
btn->setOffset(0);
|
||||
btn->setState(CButtonBase::NORMAL);
|
||||
button->block(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
button->block(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Blocked state looks like frame 'selected'=1
|
||||
btn->setOffset(-1);
|
||||
btn->setState(CButtonBase::BLOCKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1784,12 +1789,12 @@ void CRandomMapTab::validatePlayersCnt(int playersCnt)
|
||||
if(mapGenOptions.getTeamCount() >= playersCnt)
|
||||
{
|
||||
mapGenOptions.setTeamCount(playersCnt - 1);
|
||||
teamsCntGroup->select(mapGenOptions.getTeamCount(), true);
|
||||
teamsCntGroup->setSelected(mapGenOptions.getTeamCount());
|
||||
}
|
||||
if(mapGenOptions.getCompOnlyPlayerCount() > 8 - playersCnt)
|
||||
{
|
||||
mapGenOptions.setCompOnlyPlayerCount(8 - playersCnt);
|
||||
compOnlyPlayersCntGroup->select(mapGenOptions.getCompOnlyPlayerCount(), true);
|
||||
compOnlyPlayersCntGroup->setSelected(mapGenOptions.getCompOnlyPlayerCount());
|
||||
}
|
||||
|
||||
validateCompOnlyPlayersCnt(mapGenOptions.getCompOnlyPlayerCount());
|
||||
@ -1805,7 +1810,7 @@ void CRandomMapTab::validateCompOnlyPlayersCnt(int compOnlyPlayersCnt)
|
||||
if(mapGenOptions.getCompOnlyTeamCount() >= compOnlyPlayersCnt)
|
||||
{
|
||||
mapGenOptions.setCompOnlyTeamCount(compOnlyPlayersCnt - 1);
|
||||
compOnlyTeamsCntGroup->select(mapGenOptions.getCompOnlyTeamCount(), true);
|
||||
compOnlyTeamsCntGroup->setSelected(mapGenOptions.getCompOnlyTeamCount());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1960,20 +1965,20 @@ InfoCard::InfoCard( bool Network )
|
||||
pos.h = bg->pos.h;
|
||||
sizes = CDefHandler::giveDef("SCNRMPSZ.DEF");
|
||||
sFlags = CDefHandler::giveDef("ITGFLAGS.DEF");
|
||||
difficulty = new CHighlightableButtonsGroup(0);
|
||||
difficulty = new CToggleGroup(0);
|
||||
{
|
||||
static const char *difButns[] = {"GSPBUT3.DEF", "GSPBUT4.DEF", "GSPBUT5.DEF", "GSPBUT6.DEF", "GSPBUT7.DEF"};
|
||||
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
difficulty->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[24+i].second, 0, 110 + i*32, 450, difButns[i], i));
|
||||
auto button = new CToggleButton(Point(110 + i*32, 450), difButns[i], CGI->generaltexth->zelp[24+i]);
|
||||
|
||||
difficulty->addToggle(i, button);
|
||||
if(SEL->screenType != CMenuScreen::newGame)
|
||||
button->block(true);
|
||||
}
|
||||
}
|
||||
|
||||
if(SEL->screenType != CMenuScreen::newGame)
|
||||
difficulty->block(true);
|
||||
|
||||
|
||||
if(network)
|
||||
{
|
||||
playerListBg = new CPicture("CHATPLUG.bmp", 16, 276);
|
||||
@ -2161,8 +2166,8 @@ void InfoCard::changeSelection( const CMapInfo *to )
|
||||
mapDescription->setText(to->mapHeader->description);
|
||||
|
||||
if(SEL->screenType != CMenuScreen::newGame && SEL->screenType != CMenuScreen::campaignList) {
|
||||
difficulty->block(true);
|
||||
difficulty->select(SEL->sInfo.difficulty, 0);
|
||||
//difficulty->block(true);
|
||||
difficulty->setSelected(SEL->sInfo.difficulty);
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
@ -2242,7 +2247,7 @@ OptionsTab::OptionsTab():
|
||||
pos = bg->pos;
|
||||
|
||||
if(SEL->screenType == CMenuScreen::newGame)
|
||||
turnDuration = new CSlider(55, 551, 194, std::bind(&OptionsTab::setTurnLength, this, _1), 1, 11, 11, true, 1);
|
||||
turnDuration = new CSlider(Point(55, 551), 194, std::bind(&OptionsTab::setTurnLength, this, _1), 1, 11, 11, true, CSlider::BLUE);
|
||||
}
|
||||
|
||||
OptionsTab::~OptionsTab()
|
||||
@ -2261,7 +2266,7 @@ void OptionsTab::showAll(SDL_Surface * to)
|
||||
printAtMiddleWBLoc(CGI->generaltexth->allTexts[520], 349, 110, FONT_SMALL, 70, Colors::YELLOW, to); //Starting Bonus
|
||||
printAtMiddleLoc(CGI->generaltexth->allTexts[521], 222, 538, FONT_SMALL, Colors::YELLOW, to); // Player Turn Duration
|
||||
if (turnDuration)
|
||||
printAtMiddleLoc(CGI->generaltexth->turnDurations[turnDuration->value], 319,559, FONT_SMALL, Colors::WHITE, to);//Turn duration value
|
||||
printAtMiddleLoc(CGI->generaltexth->turnDurations[turnDuration->getValue()], 319,559, FONT_SMALL, Colors::WHITE, to);//Turn duration value
|
||||
}
|
||||
|
||||
void OptionsTab::nextCastle( PlayerColor player, int dir )
|
||||
@ -2546,12 +2551,12 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry( OptionsTab *owner, PlayerSet
|
||||
bg = new CPicture(BitmapHandler::loadBitmap(bgs[s.color.getNum()]), 0, 0, true);
|
||||
if(SEL->screenType == CMenuScreen::newGame)
|
||||
{
|
||||
btns[0] = new CAdventureMapButton(CGI->generaltexth->zelp[132], std::bind(&OptionsTab::nextCastle, owner, s.color, -1), 107, 5, "ADOPLFA.DEF");
|
||||
btns[1] = new CAdventureMapButton(CGI->generaltexth->zelp[133], std::bind(&OptionsTab::nextCastle, owner, s.color, +1), 168, 5, "ADOPRTA.DEF");
|
||||
btns[2] = new CAdventureMapButton(CGI->generaltexth->zelp[148], std::bind(&OptionsTab::nextHero, owner, s.color, -1), 183, 5, "ADOPLFA.DEF");
|
||||
btns[3] = new CAdventureMapButton(CGI->generaltexth->zelp[149], std::bind(&OptionsTab::nextHero, owner, s.color, +1), 244, 5, "ADOPRTA.DEF");
|
||||
btns[4] = new CAdventureMapButton(CGI->generaltexth->zelp[164], std::bind(&OptionsTab::nextBonus, owner, s.color, -1), 259, 5, "ADOPLFA.DEF");
|
||||
btns[5] = new CAdventureMapButton(CGI->generaltexth->zelp[165], std::bind(&OptionsTab::nextBonus, owner, s.color, +1), 320, 5, "ADOPRTA.DEF");
|
||||
btns[0] = new CButton(Point(107, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[132], std::bind(&OptionsTab::nextCastle, owner, s.color, -1));
|
||||
btns[1] = new CButton(Point(168, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[133], std::bind(&OptionsTab::nextCastle, owner, s.color, +1));
|
||||
btns[2] = new CButton(Point(183, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[148], std::bind(&OptionsTab::nextHero, owner, s.color, -1));
|
||||
btns[3] = new CButton(Point(244, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[149], std::bind(&OptionsTab::nextHero, owner, s.color, +1));
|
||||
btns[4] = new CButton(Point(259, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[164], std::bind(&OptionsTab::nextBonus, owner, s.color, -1));
|
||||
btns[5] = new CButton(Point(320, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[165], std::bind(&OptionsTab::nextBonus, owner, s.color, +1));
|
||||
}
|
||||
else
|
||||
for(auto & elem : btns)
|
||||
@ -2573,7 +2578,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry( OptionsTab *owner, PlayerSet
|
||||
&& SEL->current->mapHeader->players[s.color.getNum()].canHumanPlay
|
||||
&& SEL->multiPlayer != CMenuScreen::MULTI_NETWORK_GUEST)
|
||||
{
|
||||
flag = new CAdventureMapButton(CGI->generaltexth->zelp[180], std::bind(&OptionsTab::flagPressed, owner, s.color), -43, 2, flags[s.color.getNum()]);
|
||||
flag = new CButton(Point(-43, 2), flags[s.color.getNum()], CGI->generaltexth->zelp[180], std::bind(&OptionsTab::flagPressed, owner, s.color));
|
||||
flag->hoverable = true;
|
||||
}
|
||||
else
|
||||
@ -2979,8 +2984,8 @@ CScenarioInfo::CScenarioInfo(const CMapHeader *mapHeader, const StartInfo *start
|
||||
opt->recreate();
|
||||
card->changeSelection(current);
|
||||
|
||||
card->difficulty->select(startInfo->difficulty, 0);
|
||||
back = new CAdventureMapButton("", CGI->generaltexth->zelp[105].second, std::bind(&CGuiHandler::popIntTotally, &GH, this), 584, 535, "SCNRBACK.DEF", SDLK_ESCAPE);
|
||||
card->difficulty->setSelected(startInfo->difficulty);
|
||||
back = new CButton(Point(584, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], std::bind(&CGuiHandler::popIntTotally, &GH, this), SDLK_ESCAPE);
|
||||
}
|
||||
|
||||
CScenarioInfo::~CScenarioInfo()
|
||||
@ -3059,10 +3064,10 @@ CMultiMode::CMultiMode()
|
||||
txt = new CTextInput(Rect(19, 436, 334, 16), *bg);
|
||||
txt->setText(settings["general"]["playerName"].String()); //Player
|
||||
|
||||
btns[0] = new CAdventureMapButton(CGI->generaltexth->zelp[266], std::bind(&CMultiMode::openHotseat, this), 373, 78, "MUBHOT.DEF");
|
||||
btns[1] = new CAdventureMapButton("Host TCP/IP game", "", std::bind(&CMultiMode::hostTCP, this), 373, 78 + 57*1, "MUBHOST.DEF");
|
||||
btns[2] = new CAdventureMapButton("Join TCP/IP game", "", std::bind(&CMultiMode::joinTCP, this), 373, 78 + 57*2, "MUBJOIN.DEF");
|
||||
btns[6] = new CAdventureMapButton(CGI->generaltexth->zelp[288], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 373, 424, "MUBCANC.DEF", SDLK_ESCAPE);
|
||||
btns[0] = new CButton(Point(373, 78), "MUBHOT.DEF", CGI->generaltexth->zelp[266], std::bind(&CMultiMode::openHotseat, this));
|
||||
btns[1] = new CButton(Point(373, 78 + 57*1), "MUBHOST.DEF", CButton::tooltip("Host TCP/IP game", ""), std::bind(&CMultiMode::hostTCP, this));
|
||||
btns[2] = new CButton(Point(373, 78 + 57*2), "MUBJOIN.DEF", CButton::tooltip("Join TCP/IP game", ""), std::bind(&CMultiMode::joinTCP, this));
|
||||
btns[6] = new CButton(Point(373, 424), "MUBCANC.DEF", CGI->generaltexth->zelp[288], [&] { GH.popIntTotally(this);}, SDLK_ESCAPE);
|
||||
}
|
||||
|
||||
void CMultiMode::openHotseat()
|
||||
@ -3102,8 +3107,8 @@ CHotSeatPlayers::CHotSeatPlayers(const std::string &firstPlayer)
|
||||
txt[i]->cb += std::bind(&CHotSeatPlayers::onChange, this, _1);
|
||||
}
|
||||
|
||||
ok = new CAdventureMapButton(CGI->generaltexth->zelp[560], std::bind(&CHotSeatPlayers::enterSelectionScreen, this), 95, 338, "MUBCHCK.DEF", SDLK_RETURN);
|
||||
cancel = new CAdventureMapButton(CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 205, 338, "MUBCANC.DEF", SDLK_ESCAPE);
|
||||
ok = new CButton(Point(95, 338), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CHotSeatPlayers::enterSelectionScreen, this), SDLK_RETURN);
|
||||
cancel = new CButton(Point(205, 338), "MUBCANC.DEF", CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), SDLK_ESCAPE);
|
||||
bar = new CGStatusBar(new CPicture(Rect(7, 381, 348, 18), 0));//226, 472
|
||||
|
||||
txt[0]->setText(firstPlayer, true);
|
||||
@ -3166,9 +3171,9 @@ void CBonusSelection::init()
|
||||
|
||||
blitAt(panel, 456, 6, background);
|
||||
|
||||
startB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::startMap, this), 475, 536, "CBBEGIB.DEF", SDLK_RETURN);
|
||||
restartB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::restartMap, this), 475, 536, "CBRESTB.DEF", SDLK_RETURN);
|
||||
backB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::goBack, this), 624, 536, "CBCANCB.DEF", SDLK_ESCAPE);
|
||||
startB = new CButton(Point(475, 536), "CBBEGIB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::startMap, this), SDLK_RETURN);
|
||||
restartB = new CButton(Point(475, 536), "CBRESTB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::restartMap, this), SDLK_RETURN);
|
||||
backB = new CButton(Point(624, 536), "CBCANCB.DEF", CButton::tooltip(), std::bind(&CBonusSelection::goBack, this), SDLK_ESCAPE);
|
||||
|
||||
//campaign name
|
||||
if (ourCampaign->camp->header.name.length())
|
||||
@ -3190,7 +3195,7 @@ void CBonusSelection::init()
|
||||
|
||||
//bonus choosing
|
||||
graphics->fonts[FONT_MEDIUM]->renderTextLeft(background, CGI->generaltexth->allTexts[71], Colors::WHITE, Point(511, 432));
|
||||
bonuses = new CHighlightableButtonsGroup(bind(&CBonusSelection::selectBonus, this, _1));
|
||||
bonuses = new CToggleGroup(bind(&CBonusSelection::selectBonus, this, _1));
|
||||
|
||||
//set left part of window
|
||||
bool isCurrentMapConquerable = ourCampaign->currentMap && ourCampaign->camp->conquerable(*ourCampaign->currentMap);
|
||||
@ -3241,8 +3246,8 @@ void CBonusSelection::init()
|
||||
//difficulty selection buttons
|
||||
if (ourCampaign->camp->header.difficultyChoosenByPlayer)
|
||||
{
|
||||
diffLb = new CAdventureMapButton("", "", std::bind(&CBonusSelection::decreaseDifficulty, this), 694, 508, "SCNRBLF.DEF");
|
||||
diffRb = new CAdventureMapButton("", "", std::bind(&CBonusSelection::increaseDifficulty, this), 738, 508, "SCNRBRT.DEF");
|
||||
diffLb = new CButton(Point(694, 508), "SCNRBLF.DEF", CButton::tooltip(), std::bind(&CBonusSelection::decreaseDifficulty, this));
|
||||
diffRb = new CButton(Point(738, 508), "SCNRBRT.DEF", CButton::tooltip(), std::bind(&CBonusSelection::increaseDifficulty, this));
|
||||
}
|
||||
|
||||
//load miniflags
|
||||
@ -3442,13 +3447,8 @@ void CBonusSelection::updateBonusSelection()
|
||||
|
||||
updateStartButtonState(-1);
|
||||
|
||||
for (auto & elem : bonuses->buttons)
|
||||
{
|
||||
if (elem->active)
|
||||
elem->deactivate();
|
||||
delete elem;
|
||||
}
|
||||
bonuses->buttons.clear();
|
||||
delete bonuses;
|
||||
bonuses = new CToggleGroup(bind(&CBonusSelection::selectBonus, this, _1));
|
||||
|
||||
static const char *bonusPics[] = {"SPELLBON.DEF", "TWCRPORT.DEF", "", "ARTIFBON.DEF", "SPELLBON.DEF",
|
||||
"PSKILBON.DEF", "SSKILBON.DEF", "BORES.DEF", "PORTRAITSLARGE", "PORTRAITSLARGE"};
|
||||
@ -3602,7 +3602,7 @@ void CBonusSelection::updateBonusSelection()
|
||||
break;
|
||||
}
|
||||
|
||||
CHighlightableButton *bonusButton = new CHighlightableButton(desc, desc, 0, 475 + i*68, 455, "", i);
|
||||
CToggleButton *bonusButton = new CToggleButton(Point(475 + i*68, 455), "", CButton::tooltip(desc, desc));
|
||||
|
||||
if (picNumber != -1)
|
||||
picName += ":" + boost::lexical_cast<std::string>(picNumber);
|
||||
@ -3612,13 +3612,13 @@ void CBonusSelection::updateBonusSelection()
|
||||
bonusButton->setImage(anim);
|
||||
const SDL_Color brightYellow = { 242, 226, 110, 0 };
|
||||
bonusButton->borderColor = brightYellow;
|
||||
bonuses->addButton(bonusButton);
|
||||
bonuses->addToggle(i, bonusButton);
|
||||
}
|
||||
|
||||
// set bonus if already chosen
|
||||
if(vstd::contains(ourCampaign->chosenCampaignBonuses, selectedMap))
|
||||
{
|
||||
bonuses->select(ourCampaign->chosenCampaignBonuses[selectedMap], false);
|
||||
bonuses->setSelected(ourCampaign->chosenCampaignBonuses[selectedMap]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3727,11 +3727,11 @@ void CBonusSelection::updateStartButtonState(int selected /*= -1*/)
|
||||
{
|
||||
if(selected == -1)
|
||||
{
|
||||
startB->setState(ourCampaign->camp->scenarios[selectedMap].travelOptions.bonusesToChoose.size() ? CButtonBase::BLOCKED : CButtonBase::NORMAL);
|
||||
startB->block(ourCampaign->camp->scenarios[selectedMap].travelOptions.bonusesToChoose.size());
|
||||
}
|
||||
else if(startB->getState() == CButtonBase::BLOCKED)
|
||||
else if(startB->isBlocked())
|
||||
{
|
||||
startB->setState(CButtonBase::NORMAL);
|
||||
startB->block(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4091,14 +4091,14 @@ void CCampaignScreen::CCampaignButton::show(SDL_Surface * to)
|
||||
}
|
||||
}
|
||||
|
||||
CAdventureMapButton* CCampaignScreen::createExitButton(const JsonNode& button)
|
||||
CButton* CCampaignScreen::createExitButton(const JsonNode& button)
|
||||
{
|
||||
std::pair<std::string, std::string> help;
|
||||
if (!button["help"].isNull() && button["help"].Float() > 0)
|
||||
help = CGI->generaltexth->zelp[button["help"].Float()];
|
||||
|
||||
std::function<void()> close = std::bind(&CGuiHandler::popIntTotally, &GH, this);
|
||||
return new CAdventureMapButton(help, close, button["x"].Float(), button["y"].Float(), button["name"].String(), button["hotkey"].Float());
|
||||
std::function<void()> close = std::bind(&CGuiHandler::popIntTotally, &GH, this);
|
||||
return new CButton(Point(button["x"].Float(), button["y"].Float()), button["name"].String(), help, close, button["hotkey"].Float());
|
||||
}
|
||||
|
||||
|
||||
@ -4239,8 +4239,8 @@ CSimpleJoinScreen::CSimpleJoinScreen()
|
||||
port->cb += std::bind(&CSimpleJoinScreen::onChange, this, _1);
|
||||
port->filters.add(std::bind(&CTextInput::numberFilter, _1, _2, 0, 65535));
|
||||
|
||||
ok = new CAdventureMapButton(CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::enterSelectionScreen, this), 26, 142, "MUBCHCK.DEF", SDLK_RETURN);
|
||||
cancel = new CAdventureMapButton(CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 142, 142, "MUBCANC.DEF", SDLK_ESCAPE);
|
||||
ok = new CButton(Point( 26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::enterSelectionScreen, this), SDLK_RETURN);
|
||||
cancel = new CButton(Point(142, 142), "MUBCANC.DEF", CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), SDLK_ESCAPE);
|
||||
bar = new CGStatusBar(new CPicture(Rect(7, 186, 218, 18), 0));
|
||||
|
||||
port->setText(boost::lexical_cast<std::string>(settings["server"]["port"].Float()), true);
|
||||
|
@ -1,12 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include <SDL.h>
|
||||
//#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/StartInfo.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "../lib/FunctionList.h"
|
||||
#include "../lib/mapping/CMapInfo.h"
|
||||
#include "../lib/rmg/CMapGenerator.h"
|
||||
#include "windows/CWindowObject.h"
|
||||
|
||||
/*
|
||||
* CPreGame.h, part of VCMI engine
|
||||
@ -18,6 +17,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
class CMapInfo;
|
||||
class CMusicHandler;
|
||||
class CMapHeader;
|
||||
class CCampaignHeader;
|
||||
@ -32,6 +32,12 @@ class CMapGenOptions;
|
||||
class CRandomMapTab;
|
||||
struct CPackForSelectionScreen;
|
||||
struct PlayerInfo;
|
||||
class CMultiLineLabel;
|
||||
class CToggleButton;
|
||||
class CToggleGroup;
|
||||
class CTabbedInt;
|
||||
class CButton;
|
||||
class CSlider;
|
||||
|
||||
namespace boost{ class thread; class recursive_mutex;}
|
||||
|
||||
@ -80,9 +86,9 @@ public:
|
||||
class CMenuEntry : public CIntObject
|
||||
{
|
||||
std::vector<CPicture*> images;
|
||||
std::vector<CAdventureMapButton*> buttons;
|
||||
std::vector<CButton*> buttons;
|
||||
|
||||
CAdventureMapButton* createButton(CMenuScreen* parent, const JsonNode& button);
|
||||
CButton* createButton(CMenuScreen* parent, const JsonNode& button);
|
||||
public:
|
||||
CMenuEntry(CMenuScreen* parent, const JsonNode &config);
|
||||
};
|
||||
@ -126,7 +132,7 @@ public:
|
||||
CChatBox *chat;
|
||||
CPicture *playerListBg;
|
||||
|
||||
CHighlightableButtonsGroup *difficulty;
|
||||
CToggleGroup *difficulty;
|
||||
CDefHandler *sizes, *sFlags;
|
||||
|
||||
void changeSelection(const CMapInfo *to);
|
||||
@ -239,8 +245,8 @@ public:
|
||||
PlayerInfo π
|
||||
PlayerSettings &s;
|
||||
CPicture *bg;
|
||||
CAdventureMapButton *btns[6]; //left and right for town, hero, bonus
|
||||
CAdventureMapButton *flag;
|
||||
CButton *btns[6]; //left and right for town, hero, bonus
|
||||
CButton *flag;
|
||||
SelectedBox *town;
|
||||
SelectedBox *hero;
|
||||
SelectedBox *bonus;
|
||||
@ -296,17 +302,17 @@ public:
|
||||
const CMapGenOptions & getMapGenOptions() const;
|
||||
|
||||
private:
|
||||
void addButtonsToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex) const;
|
||||
void addButtonsWithRandToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex, int helpRandIndex) const;
|
||||
void deactivateButtonsFrom(CHighlightableButtonsGroup * group, int startId);
|
||||
void addButtonsToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex) const;
|
||||
void addButtonsWithRandToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex, int helpRandIndex) const;
|
||||
void deactivateButtonsFrom(CToggleGroup * group, int startId);
|
||||
void validatePlayersCnt(int playersCnt);
|
||||
void validateCompOnlyPlayersCnt(int compOnlyPlayersCnt);
|
||||
|
||||
CPicture * bg;
|
||||
CHighlightableButton * twoLevelsBtn;
|
||||
CHighlightableButtonsGroup * mapSizeBtnGroup, * playersCntGroup, * teamsCntGroup, * compOnlyPlayersCntGroup,
|
||||
CToggleButton * twoLevelsBtn;
|
||||
CToggleGroup * mapSizeBtnGroup, * playersCntGroup, * teamsCntGroup, * compOnlyPlayersCntGroup,
|
||||
* compOnlyTeamsCntGroup, * waterContentGroup, * monsterStrengthGroup;
|
||||
CAdventureMapButton * showRandMaps;
|
||||
CButton * showRandMaps;
|
||||
CMapGenOptions mapGenOptions;
|
||||
unique_ptr<CMapInfo> mapInfo;
|
||||
CFunctionList<void(const CMapInfo *)> mapInfoChanged;
|
||||
@ -347,7 +353,7 @@ public:
|
||||
InfoCard *card;
|
||||
OptionsTab *opt;
|
||||
CRandomMapTab * randMapTab;
|
||||
CAdventureMapButton *start, *back;
|
||||
CButton *start, *back;
|
||||
|
||||
SelectionTab *sel;
|
||||
CIntObject *curTab;
|
||||
@ -395,7 +401,7 @@ public:
|
||||
class CScenarioInfo : public CIntObject, public ISelectionScreenInfo
|
||||
{
|
||||
public:
|
||||
CAdventureMapButton *back;
|
||||
CButton *back;
|
||||
InfoCard *card;
|
||||
OptionsTab *opt;
|
||||
|
||||
@ -409,7 +415,7 @@ class CMultiMode : public CIntObject
|
||||
public:
|
||||
CPicture *bg;
|
||||
CTextInput *txt;
|
||||
CAdventureMapButton *btns[7]; //0 - hotseat, 6 - cancel
|
||||
CButton *btns[7]; //0 - hotseat, 6 - cancel
|
||||
CGStatusBar *bar;
|
||||
|
||||
CMultiMode();
|
||||
@ -424,7 +430,7 @@ class CHotSeatPlayers : public CIntObject
|
||||
CPicture *bg;
|
||||
CTextBox *title;
|
||||
CTextInput* txt[8];
|
||||
CAdventureMapButton *ok, *cancel;
|
||||
CButton *ok, *cancel;
|
||||
CGStatusBar *bar;
|
||||
|
||||
void onChange(std::string newText);
|
||||
@ -512,14 +518,14 @@ private:
|
||||
|
||||
// GUI components
|
||||
SDL_Surface * background;
|
||||
CAdventureMapButton * startB, * restartB, * backB;
|
||||
CButton * startB, * restartB, * backB;
|
||||
CTextBox * campaignDescription, * mapDescription;
|
||||
std::vector<SCampPositions> campDescriptions;
|
||||
std::vector<CRegion *> regions;
|
||||
CRegion * highlightedRegion;
|
||||
CHighlightableButtonsGroup * bonuses;
|
||||
CToggleGroup * bonuses;
|
||||
SDL_Surface * diffPics[5]; //pictures of difficulties, user-selectable (or not if campaign locks this)
|
||||
CAdventureMapButton * diffLb, * diffRb; //buttons for changing difficulty
|
||||
CButton * diffLb, * diffRb; //buttons for changing difficulty
|
||||
CDefHandler * sizes; //icons of map sizes
|
||||
CDefHandler * sFlags;
|
||||
|
||||
@ -560,11 +566,11 @@ private:
|
||||
void show(SDL_Surface * to);
|
||||
};
|
||||
|
||||
CAdventureMapButton *back;
|
||||
CButton *back;
|
||||
std::vector<CCampaignButton*> campButtons;
|
||||
std::vector<CPicture*> images;
|
||||
|
||||
CAdventureMapButton* createExitButton(const JsonNode& button);
|
||||
CButton* createExitButton(const JsonNode& button);
|
||||
|
||||
public:
|
||||
enum CampaignSet {ROE, AB, SOD, WOG};
|
||||
@ -630,7 +636,7 @@ class CSimpleJoinScreen : public CIntObject
|
||||
{
|
||||
CPicture * bg;
|
||||
CTextBox * title;
|
||||
CAdventureMapButton * ok, * cancel;
|
||||
CButton * ok, * cancel;
|
||||
CGStatusBar * bar;
|
||||
CTextInput * address;
|
||||
CTextInput * port;
|
||||
|
@ -21,9 +21,6 @@ static bool keyDown()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "avcodec.lib")
|
||||
@ -32,9 +29,6 @@ static bool keyDown()
|
||||
#pragma comment(lib, "swscale.lib")
|
||||
#endif // _MSC_VER
|
||||
|
||||
|
||||
#ifndef DISABLE_VIDEO
|
||||
|
||||
// Define a set of functions to read data
|
||||
static int lodRead(void* opaque, uint8_t* buf, int size)
|
||||
{
|
||||
|
@ -30,18 +30,17 @@ public:
|
||||
|
||||
class CEmptyVideoPlayer : public IMainVideoPlayer
|
||||
{
|
||||
public:
|
||||
public:
|
||||
int curFrame() const override {return -1;};
|
||||
int frameCount() const override {return -1;};
|
||||
void redraw(int x, int y, SDL_Surface *dst, bool update = true) override {};
|
||||
void show(int x, int y, SDL_Surface *dst, bool update = true) override{};
|
||||
void redraw( int x, int y, SDL_Surface *dst, bool update = true ) override {};
|
||||
void show( int x, int y, SDL_Surface *dst, bool update = true ) override {};
|
||||
bool nextFrame() override {return false;};
|
||||
void close() override {};
|
||||
bool wait() override {return false;};
|
||||
bool open(std::string name, bool scale = false) override {return false;};
|
||||
};
|
||||
|
||||
|
||||
#ifndef DISABLE_VIDEO
|
||||
|
||||
#include "../lib/filesystem/CInputStream.h"
|
||||
|
@ -1,4 +1,7 @@
|
||||
#include "StdInc.h"
|
||||
#include "Client.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "CMusicHandler.h"
|
||||
#include "../lib/mapping/CCampaignHandler.h"
|
||||
@ -17,7 +20,7 @@
|
||||
#include "../lib/CBuildingHandler.h"
|
||||
#include "../lib/CSpellHandler.h"
|
||||
#include "../lib/Connection.h"
|
||||
#ifndef __ANDROID__
|
||||
#ifndef VCMI_ANDROID
|
||||
#include "../lib/Interprocess.h"
|
||||
#endif
|
||||
#include "../lib/NetPacks.h"
|
||||
@ -37,7 +40,7 @@
|
||||
#include "CMT.h"
|
||||
|
||||
extern std::string NAME;
|
||||
#ifndef __ANDROID__
|
||||
#ifndef VCMI_ANDROID
|
||||
namespace intpr = boost::interprocess;
|
||||
#endif
|
||||
|
||||
@ -777,8 +780,9 @@ std::string CClient::aiNameForPlayer(const PlayerSettings &ps, bool battleAI)
|
||||
{
|
||||
if(ps.name.size())
|
||||
{
|
||||
std::string filename = VCMIDirs::get().libraryPath() + "/AI/" + VCMIDirs::get().libraryName(ps.name);
|
||||
if(boost::filesystem::exists(filename))
|
||||
const boost::filesystem::path aiPath =
|
||||
VCMIDirs::get().libraryPath() / "AI" / VCMIDirs::get().libraryName(ps.name);
|
||||
if (boost::filesystem::exists(aiPath))
|
||||
return ps.name;
|
||||
}
|
||||
|
||||
@ -811,7 +815,7 @@ void CServerHandler::waitForServer()
|
||||
startServer();
|
||||
|
||||
th.update();
|
||||
#ifndef __ANDROID__
|
||||
#ifndef VCMI_ANDROID
|
||||
intpr::scoped_lock<intpr::interprocess_mutex> slock(shared->sr->mutex);
|
||||
while(!shared->sr->ready)
|
||||
{
|
||||
@ -824,7 +828,7 @@ void CServerHandler::waitForServer()
|
||||
|
||||
CConnection * CServerHandler::connectToServer()
|
||||
{
|
||||
#ifndef __ANDROID__
|
||||
#ifndef VCMI_ANDROID
|
||||
if(!shared->sr->ready)
|
||||
waitForServer();
|
||||
#else
|
||||
@ -847,7 +851,7 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
|
||||
port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
|
||||
verbose = true;
|
||||
|
||||
#ifndef __ANDROID__
|
||||
#ifndef VCMI_ANDROID
|
||||
boost::interprocess::shared_memory_object::remove("vcmi_memory"); //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it
|
||||
try
|
||||
{
|
||||
@ -865,8 +869,8 @@ CServerHandler::~CServerHandler()
|
||||
void CServerHandler::callServer()
|
||||
{
|
||||
setThreadName("CServerHandler::callServer");
|
||||
std::string logName = VCMIDirs::get().userCachePath() + "/server_log.txt";
|
||||
std::string comm = VCMIDirs::get().serverPath() + " --port=" + port + " > " + logName;
|
||||
const std::string logName = (VCMIDirs::get().userCachePath() / "server_log.txt").string();
|
||||
const std::string comm = VCMIDirs::get().serverPath().string() + " --port=" + port + " > \"" + logName + '\"';
|
||||
int result = std::system(comm.c_str());
|
||||
if (result == 0)
|
||||
logNetwork->infoStream() << "Server closed correctly";
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
|
||||
#include "../lib/IGameCallback.h"
|
||||
#include "../lib/CondSh.h"
|
||||
#include "../lib/BattleAction.h"
|
||||
#include "../lib/CStopWatch.h"
|
||||
#include "../lib/int3.h"
|
||||
|
||||
/*
|
||||
* Client.h, part of VCMI engine
|
||||
@ -15,6 +16,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
class CPack;
|
||||
class CCampaignState;
|
||||
class CBattleCallback;
|
||||
class IGameEventsReceiver;
|
||||
class IBattleEventsReceiver;
|
||||
class CBattleGameInterface;
|
||||
|
1202
client/GUIClasses.h
@ -21,7 +21,6 @@
|
||||
#include "../lib/vcmi_endian.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "../lib/CStopWatch.h"
|
||||
#include "CAnimation.h"
|
||||
#include "../lib/mapObjects/CObjectClassesHandler.h"
|
||||
|
||||
using namespace boost::assign;
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "../lib/CSoundBase.h"
|
||||
#include "../lib/StartInfo.h"
|
||||
#include "mapHandler.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "windows/GUIClasses.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "battle/CBattleInterface.h"
|
||||
@ -26,6 +26,8 @@
|
||||
#include "../lib/BattleState.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "widgets/MiscWidgets.h"
|
||||
#include "widgets/AdventureMapClasses.h"
|
||||
#include "CMT.h"
|
||||
|
||||
//macros to avoid code duplication - calls given method with given arguments if interface for specific player is present
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "../../CCallback.h"
|
||||
#include "../../lib/BattleState.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
|
||||
/*
|
||||
* CBattleAnimations.cpp, part of VCMI engine
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../CAnimation.h"
|
||||
#include "../../lib/BattleHex.h"
|
||||
#include "../widgets/Images.h"
|
||||
|
||||
class CBattleInterface;
|
||||
class CStack;
|
||||
|
@ -1,40 +1,38 @@
|
||||
#include "StdInc.h"
|
||||
#include "CBattleInterface.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../CAdvmapInterface.h"
|
||||
#include "../CAnimation.h"
|
||||
#include "../CBitmapHandler.h"
|
||||
#include "../../lib/CHeroHandler.h"
|
||||
# include "../CDefHandler.h"
|
||||
#include "../../lib/CSpellHandler.h"
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../CMessage.h"
|
||||
#include "../../CCallback.h"
|
||||
#include "../../lib/BattleState.h"
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "CCreatureAnimation.h"
|
||||
#include "../Graphics.h"
|
||||
#include "../CSpellWindow.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../../lib/CondSh.h"
|
||||
#include "../../lib/NetPacks.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CCreatureWindow.h"
|
||||
#include "../CVideoHandler.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
#include "../../lib/mapping/CMap.h"
|
||||
#include "../../lib/CRandomGenerator.h"
|
||||
|
||||
#include "CBattleAnimations.h"
|
||||
#include "CBattleInterfaceClasses.h"
|
||||
#include "CCreatureAnimation.h"
|
||||
|
||||
#include "../CBitmapHandler.h"
|
||||
#include "../CDefHandler.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CMessage.h"
|
||||
#include "../CMT.h"
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CVideoHandler.h"
|
||||
#include "../Graphics.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../CMT.h"
|
||||
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../windows/CAdvmapInterface.h"
|
||||
#include "../windows/CCreatureWindow.h"
|
||||
#include "../windows/CSpellWindow.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
#include "../../lib/BattleState.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/CHeroHandler.h"
|
||||
#include "../../lib/CondSh.h"
|
||||
#include "../../lib/CRandomGenerator.h"
|
||||
#include "../../lib/CSpellHandler.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
#include "../../lib/CGameState.h"
|
||||
#include "../../lib/mapping/CMap.h"
|
||||
#include "../../lib/NetPacks.h"
|
||||
#include "../../lib/UnlockGuard.h"
|
||||
|
||||
using namespace boost::assign;
|
||||
@ -224,17 +222,17 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
||||
// blitAt(menu, pos.x, 556 + pos.y);
|
||||
|
||||
//preparing buttons and console
|
||||
bOptions = new CAdventureMapButton (CGI->generaltexth->zelp[381].first, CGI->generaltexth->zelp[381].second, std::bind(&CBattleInterface::bOptionsf,this), 3, 561, "icm003.def", SDLK_o);
|
||||
bSurrender = new CAdventureMapButton (CGI->generaltexth->zelp[379].first, CGI->generaltexth->zelp[379].second, std::bind(&CBattleInterface::bSurrenderf,this), 54, 561, "icm001.def", SDLK_s);
|
||||
bFlee = new CAdventureMapButton (CGI->generaltexth->zelp[380].first, CGI->generaltexth->zelp[380].second, std::bind(&CBattleInterface::bFleef,this), 105, 561, "icm002.def", SDLK_r);
|
||||
bAutofight = new CAdventureMapButton (CGI->generaltexth->zelp[382].first, CGI->generaltexth->zelp[382].second, std::bind(&CBattleInterface::bAutofightf,this), 157, 561, "icm004.def", SDLK_a);
|
||||
bSpell = new CAdventureMapButton (CGI->generaltexth->zelp[385].first, CGI->generaltexth->zelp[385].second, std::bind(&CBattleInterface::bSpellf,this), 645, 561, "icm005.def", SDLK_c);
|
||||
bWait = new CAdventureMapButton (CGI->generaltexth->zelp[386].first, CGI->generaltexth->zelp[386].second, std::bind(&CBattleInterface::bWaitf,this), 696, 561, "icm006.def", SDLK_w);
|
||||
bDefence = new CAdventureMapButton (CGI->generaltexth->zelp[387].first, CGI->generaltexth->zelp[387].second, std::bind(&CBattleInterface::bDefencef,this), 747, 561, "icm007.def", SDLK_d);
|
||||
bOptions = new CButton (Point( 3, 561), "icm003.def", CGI->generaltexth->zelp[381], std::bind(&CBattleInterface::bOptionsf,this), SDLK_o);
|
||||
bSurrender = new CButton (Point( 54, 561), "icm001.def", CGI->generaltexth->zelp[379], std::bind(&CBattleInterface::bSurrenderf,this), SDLK_s);
|
||||
bFlee = new CButton (Point(105, 561), "icm002.def", CGI->generaltexth->zelp[380], std::bind(&CBattleInterface::bFleef,this), SDLK_r);
|
||||
bAutofight = new CButton (Point(157, 561), "icm004.def", CGI->generaltexth->zelp[382], std::bind(&CBattleInterface::bAutofightf,this), SDLK_a);
|
||||
bSpell = new CButton (Point(645, 561), "icm005.def", CGI->generaltexth->zelp[385], std::bind(&CBattleInterface::bSpellf,this), SDLK_c);
|
||||
bWait = new CButton (Point(696, 561), "icm006.def", CGI->generaltexth->zelp[386], std::bind(&CBattleInterface::bWaitf,this), SDLK_w);
|
||||
bDefence = new CButton (Point(747, 561), "icm007.def", CGI->generaltexth->zelp[387], std::bind(&CBattleInterface::bDefencef,this), SDLK_d);
|
||||
bDefence->assignedKeys.insert(SDLK_SPACE);
|
||||
bConsoleUp = new CAdventureMapButton (std::string(), std::string(), std::bind(&CBattleInterface::bConsoleUpf,this), 624, 561, "ComSlide.def", SDLK_UP);
|
||||
bConsoleDown = new CAdventureMapButton (std::string(), std::string(), std::bind(&CBattleInterface::bConsoleDownf,this), 624, 580, "ComSlide.def", SDLK_DOWN);
|
||||
bConsoleDown->setOffset(2);
|
||||
bConsoleUp = new CButton (Point(624, 561), "ComSlide.def", std::make_pair("", ""), std::bind(&CBattleInterface::bConsoleUpf,this), SDLK_UP);
|
||||
bConsoleDown = new CButton (Point(624, 580), "ComSlide.def", std::make_pair("", ""), std::bind(&CBattleInterface::bConsoleDownf,this), SDLK_DOWN);
|
||||
bConsoleDown->setImageOrder(2, 3, 4, 5);
|
||||
console = new CBattleConsole();
|
||||
console->pos.x += 211;
|
||||
console->pos.y += 560;
|
||||
@ -242,8 +240,8 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
||||
console->pos.h = 38;
|
||||
if(tacticsMode)
|
||||
{
|
||||
btactNext = new CAdventureMapButton(std::string(), std::string(), std::bind(&CBattleInterface::bTacticNextStack,this, (CStack*)nullptr), 213, 560, "icm011.def", SDLK_SPACE);
|
||||
btactEnd = new CAdventureMapButton(std::string(), std::string(), std::bind(&CBattleInterface::bEndTacticPhase,this), 419, 560, "icm012.def", SDLK_RETURN);
|
||||
btactNext = new CButton(Point(213, 560), "icm011.def", std::make_pair("", ""), [&]{ bTacticNextStack(nullptr);}, SDLK_SPACE);
|
||||
btactEnd = new CButton(Point(419, 560), "icm012.def", std::make_pair("", ""), [&]{ bEndTacticPhase();}, SDLK_RETURN);
|
||||
menu = BitmapHandler::loadBitmap("COPLACBR.BMP");
|
||||
}
|
||||
else
|
||||
@ -2432,7 +2430,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
||||
{
|
||||
cursorFrame = ECursor::COMBAT_QUERY;
|
||||
consoleMsg = (boost::format(CGI->generaltexth->allTexts[297]) % shere->getName()).str();
|
||||
realizeAction = [=]{ GH.pushInt(createCreWindow(shere, true)); };
|
||||
realizeAction = [=]{ GH.pushInt(new CStackWindow(shere, false)); };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../../lib/CCreatureSet.h"
|
||||
//#include "../../lib/CCreatureSet.h"
|
||||
#include "../../lib/ConstTransitivePtr.h" //may be reundant
|
||||
#include "../CAnimation.h"
|
||||
#include "../../lib/GameConstants.h"
|
||||
|
||||
#include "CBattleAnimations.h"
|
||||
|
||||
/*
|
||||
@ -23,9 +23,9 @@ class CGHeroInstance;
|
||||
class CDefHandler;
|
||||
class CStack;
|
||||
class CCallback;
|
||||
class CAdventureMapButton;
|
||||
class CHighlightableButton;
|
||||
class CHighlightableButtonsGroup;
|
||||
class CButton;
|
||||
class CToggleButton;
|
||||
class CToggleGroup;
|
||||
struct BattleResult;
|
||||
struct BattleSpellCast;
|
||||
struct CObstacleInstance;
|
||||
@ -120,7 +120,7 @@ class CBattleInterface : public CIntObject
|
||||
};
|
||||
private:
|
||||
SDL_Surface * background, * menu, * amountNormal, * amountNegative, * amountPositive, * amountEffNeutral, * cellBorders, * backgroundWithHexes;
|
||||
CAdventureMapButton * bOptions, * bSurrender, * bFlee, * bAutofight, * bSpell,
|
||||
CButton * bOptions, * bSurrender, * bFlee, * bAutofight, * bSpell,
|
||||
* bWait, * bDefence, * bConsoleUp, * bConsoleDown, *btactNext, *btactEnd;
|
||||
CBattleConsole * console;
|
||||
CBattleHero * attackingHero, * defendingHero; //fighting heroes
|
||||
@ -338,7 +338,7 @@ public:
|
||||
InfoAboutHero enemyHero() const;
|
||||
|
||||
friend class CPlayerInterface;
|
||||
friend class CAdventureMapButton;
|
||||
friend class CButton;
|
||||
friend class CInGameConsole;
|
||||
|
||||
friend class CBattleResultWindow;
|
||||
|
@ -1,29 +1,34 @@
|
||||
#include "StdInc.h"
|
||||
#include "CBattleInterfaceClasses.h"
|
||||
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "CBattleInterface.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CDefHandler.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../../CCallback.h"
|
||||
#include "../CSpellWindow.h"
|
||||
#include "../Graphics.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/CIntObjectClasses.h"
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/NetPacks.h"
|
||||
#include "../../lib/CCreatureHandler.h"
|
||||
#include "../../lib/BattleState.h"
|
||||
#include "../../lib/StartInfo.h"
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../CVideoHandler.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
|
||||
#include "../CBitmapHandler.h"
|
||||
#include "../CCreatureWindow.h"
|
||||
#include "../CDefHandler.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CMessage.h"
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CVideoHandler.h"
|
||||
#include "../Graphics.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../widgets/Buttons.h"
|
||||
#include "../widgets/TextControls.h"
|
||||
#include "../windows/CCreatureWindow.h"
|
||||
#include "../windows/CSpellWindow.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
#include "../../lib/BattleState.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../../lib/CCreatureHandler.h"
|
||||
#include "../../lib/CGameState.h"
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
#include "../../lib/NetPacks.h"
|
||||
#include "../../lib/StartInfo.h"
|
||||
#include "../../lib/CondSh.h"
|
||||
|
||||
/*
|
||||
* CBattleInterfaceClasses.cpp, part of VCMI engine
|
||||
@ -258,26 +263,23 @@ CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInt
|
||||
background = new CPicture("comopbck.bmp");
|
||||
background->colorize(owner->getCurrentPlayerInterface()->playerID);
|
||||
|
||||
viewGrid = new CHighlightableButton(std::bind(&CBattleInterface::setPrintCellBorders, owner, true), std::bind(&CBattleInterface::setPrintCellBorders, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[427].first)(3,CGI->generaltexth->zelp[427].first), CGI->generaltexth->zelp[427].second, false, "sysopchk.def", nullptr, 25, 56, false);
|
||||
viewGrid->select(settings["battle"]["cellBorders"].Bool());
|
||||
movementShadow = new CHighlightableButton(std::bind(&CBattleInterface::setPrintStackRange, owner, true), std::bind(&CBattleInterface::setPrintStackRange, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[428].first)(3,CGI->generaltexth->zelp[428].first), CGI->generaltexth->zelp[428].second, false, "sysopchk.def", nullptr, 25, 89, false);
|
||||
movementShadow->select(settings["battle"]["stackRange"].Bool());
|
||||
mouseShadow = new CHighlightableButton(std::bind(&CBattleInterface::setPrintMouseShadow, owner, true), std::bind(&CBattleInterface::setPrintMouseShadow, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[429].first)(3,CGI->generaltexth->zelp[429].first), CGI->generaltexth->zelp[429].second, false, "sysopchk.def", nullptr, 25, 122, false);
|
||||
mouseShadow->select(settings["battle"]["mouseShadow"].Bool());
|
||||
viewGrid = new CToggleButton(Point(25, 56), "sysopchk.def", CGI->generaltexth->zelp[427], [&](bool on){owner->setPrintCellBorders(on);} );
|
||||
viewGrid->setSelected(settings["battle"]["cellBorders"].Bool());
|
||||
movementShadow = new CToggleButton(Point(25, 89), "sysopchk.def", CGI->generaltexth->zelp[428], [&](bool on){owner->setPrintStackRange(on);});
|
||||
movementShadow->setSelected(settings["battle"]["stackRange"].Bool());
|
||||
mouseShadow = new CToggleButton(Point(25, 122), "sysopchk.def", CGI->generaltexth->zelp[429], [&](bool on){owner->setPrintMouseShadow(on);});
|
||||
mouseShadow->setSelected(settings["battle"]["mouseShadow"].Bool());
|
||||
|
||||
animSpeeds = new CHighlightableButtonsGroup(0);
|
||||
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[422].first),CGI->generaltexth->zelp[422].second, "sysopb9.def", 28, 225, 40);
|
||||
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[423].first),CGI->generaltexth->zelp[423].second, "sysob10.def", 92, 225, 63);
|
||||
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[424].first),CGI->generaltexth->zelp[424].second, "sysob11.def",156, 225, 100);
|
||||
animSpeeds->select(owner->getAnimSpeed(), 1);
|
||||
animSpeeds->onChange = std::bind(&CBattleInterface::setAnimSpeed, owner, _1);
|
||||
animSpeeds = new CToggleGroup([&](int value){ owner->setAnimSpeed(value);});
|
||||
animSpeeds->addToggle(40, new CToggleButton(Point( 28, 225), "sysopb9.def", CGI->generaltexth->zelp[422]));
|
||||
animSpeeds->addToggle(63, new CToggleButton(Point( 92, 225), "sysob10.def", CGI->generaltexth->zelp[423]));
|
||||
animSpeeds->addToggle(100, new CToggleButton(Point(156, 225), "sysob11.def", CGI->generaltexth->zelp[424]));
|
||||
animSpeeds->setSelected(owner->getAnimSpeed());
|
||||
|
||||
setToDefault = new CAdventureMapButton (CGI->generaltexth->zelp[393], std::bind(&CBattleOptionsWindow::bDefaultf,this), 246, 359, "codefaul.def");
|
||||
setToDefault->swappedImages = true;
|
||||
setToDefault->update();
|
||||
exit = new CAdventureMapButton (CGI->generaltexth->zelp[392], std::bind(&CBattleOptionsWindow::bExitf,this), 357, 359, "soretrn.def",SDLK_RETURN);
|
||||
exit->swappedImages = true;
|
||||
exit->update();
|
||||
setToDefault = new CButton (Point(246, 359), "codefaul.def", CGI->generaltexth->zelp[393], [&]{ bDefaultf(); });
|
||||
setToDefault->setImageOrder(1, 0, 2, 3);
|
||||
exit = new CButton (Point(357, 359), "soretrn.def", CGI->generaltexth->zelp[392], [&]{ bExitf();}, SDLK_RETURN);
|
||||
exit->setImageOrder(1, 0, 2, 3);
|
||||
|
||||
//creating labels
|
||||
labels.push_back(new CLabel(242, 32, FONT_BIG, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[392]));//window title
|
||||
@ -307,6 +309,7 @@ CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInt
|
||||
|
||||
void CBattleOptionsWindow::bDefaultf()
|
||||
{
|
||||
//TODO: implement
|
||||
}
|
||||
|
||||
void CBattleOptionsWindow::bExitf()
|
||||
@ -322,9 +325,8 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
|
||||
CPicture * bg = new CPicture("CPRESULT");
|
||||
bg->colorize(owner.playerID);
|
||||
|
||||
exit = new CAdventureMapButton ("", "", std::bind(&CBattleResultWindow::bExitf,this), 384, 505, "iok6432.def", SDLK_RETURN);
|
||||
exit = new CButton (Point(384, 505), "iok6432.def", std::make_pair("", ""), [&]{ bExitf();}, SDLK_RETURN);
|
||||
exit->borderColor = Colors::METALLIC_GOLD;
|
||||
exit->borderEnabled = true;
|
||||
|
||||
if(br.winner==0) //attacker won
|
||||
{
|
||||
@ -606,7 +608,7 @@ void CClickableHex::clickRight(tribool down, bool previousState)
|
||||
if(!myst->alive()) return;
|
||||
if(down)
|
||||
{
|
||||
GH.pushInt(createCreWindow(myst));
|
||||
GH.pushInt(new CStackWindow(myst, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -701,7 +703,7 @@ CStackQueue::StackBox::StackBox(bool small):
|
||||
small(small)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
bg = new CPicture(small ? "StackQueueBgSmall" : "StackQueueBgBig" );
|
||||
bg = new CPicture(small ? "StackQueueSmall" : "StackQueueLarge" );
|
||||
|
||||
if (small)
|
||||
{
|
||||
|
@ -8,9 +8,9 @@ class CDefHandler;
|
||||
class CGHeroInstance;
|
||||
class CBattleInterface;
|
||||
class CPicture;
|
||||
class CAdventureMapButton;
|
||||
class CHighlightableButton;
|
||||
class CHighlightableButtonsGroup;
|
||||
class CButton;
|
||||
class CToggleButton;
|
||||
class CToggleGroup;
|
||||
class CLabel;
|
||||
struct BattleResult;
|
||||
class CStack;
|
||||
@ -72,9 +72,9 @@ class CBattleOptionsWindow : public CIntObject
|
||||
{
|
||||
private:
|
||||
CPicture * background;
|
||||
CAdventureMapButton * setToDefault, * exit;
|
||||
CHighlightableButton * viewGrid, * movementShadow, * mouseShadow;
|
||||
CHighlightableButtonsGroup * animSpeeds;
|
||||
CButton * setToDefault, * exit;
|
||||
CToggleButton * viewGrid, * movementShadow, * mouseShadow;
|
||||
CToggleGroup * animSpeeds;
|
||||
|
||||
std::vector<CLabel*> labels;
|
||||
public:
|
||||
@ -88,7 +88,7 @@ public:
|
||||
class CBattleResultWindow : public CIntObject
|
||||
{
|
||||
private:
|
||||
CAdventureMapButton *exit;
|
||||
CButton *exit;
|
||||
CPlayerInterface &owner;
|
||||
public:
|
||||
CBattleResultWindow(const BattleResult & br, const SDL_Rect & pos, CPlayerInterface &_owner); //c-tor
|
||||
@ -152,4 +152,4 @@ public:
|
||||
void update();
|
||||
void showAll(SDL_Surface *to);
|
||||
void blitBg(SDL_Surface * to);
|
||||
};
|
||||
};
|
||||
|
@ -1,16 +1,16 @@
|
||||
#include "StdInc.h"
|
||||
#include "CCreatureAnimation.h"
|
||||
|
||||
#include "../../lib/vcmi_endian.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../../lib/CCreatureHandler.h"
|
||||
#include "../../lib/vcmi_endian.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../gui/SDL_Pixels.h"
|
||||
|
||||
#include "../../lib/filesystem/Filesystem.h"
|
||||
#include "../../lib/filesystem/CBinaryReader.h"
|
||||
#include "../../lib/filesystem/CMemoryStream.h"
|
||||
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../gui/SDL_Pixels.h"
|
||||
|
||||
/*
|
||||
* CCreatureAnimation.cpp, part of VCMI engine
|
||||
*
|
||||
|
@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/FunctionList.h"
|
||||
#include "../CAnimation.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../widgets/Images.h"
|
||||
|
||||
/*
|
||||
* CCreatureAnimation.h, part of VCMI engine
|
||||
|
@ -1,17 +1,18 @@
|
||||
#include "StdInc.h"
|
||||
#include "CAnimation.h"
|
||||
|
||||
#include <SDL_image.h>
|
||||
|
||||
#include "../CBitmapHandler.h"
|
||||
#include "../Graphics.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../gui/SDL_Pixels.h"
|
||||
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/filesystem/ISimpleResourceLoader.h"
|
||||
#include "../lib/JsonNode.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
|
||||
#include "CBitmapHandler.h"
|
||||
#include "Graphics.h"
|
||||
#include "CAnimation.h"
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "gui/SDL_Pixels.h"
|
||||
|
||||
/*
|
||||
* CAnimation.cpp, part of VCMI engine
|
||||
*
|
||||
@ -1221,319 +1222,3 @@ void CAnimation::getAnimInfo()
|
||||
logGlobal->errorStream()<<", "<<anim->images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first;
|
||||
}
|
||||
}
|
||||
|
||||
CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
|
||||
frame(Frame),
|
||||
group(Group),
|
||||
player(-1),
|
||||
flags(Flags)
|
||||
{
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
anim = new CAnimation(name);
|
||||
init();
|
||||
}
|
||||
|
||||
CAnimImage::CAnimImage(CAnimation *Anim, size_t Frame, size_t Group, int x, int y, ui8 Flags):
|
||||
anim(Anim),
|
||||
frame(Frame),
|
||||
group(Group),
|
||||
player(-1),
|
||||
flags(Flags)
|
||||
{
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
init();
|
||||
}
|
||||
|
||||
size_t CAnimImage::size()
|
||||
{
|
||||
return anim->size(group);
|
||||
}
|
||||
|
||||
void CAnimImage::init()
|
||||
{
|
||||
anim->load(frame, group);
|
||||
if (flags & CShowableAnim::BASE)
|
||||
anim->load(0,group);
|
||||
|
||||
IImage *img = anim->getImage(frame, group);
|
||||
if (img)
|
||||
{
|
||||
pos.w = img->width();
|
||||
pos.h = img->height();
|
||||
}
|
||||
}
|
||||
|
||||
CAnimImage::~CAnimImage()
|
||||
{
|
||||
anim->unload(frame, group);
|
||||
if (flags & CShowableAnim::BASE)
|
||||
anim->unload(0,group);
|
||||
delete anim;
|
||||
}
|
||||
|
||||
void CAnimImage::showAll(SDL_Surface * to)
|
||||
{
|
||||
IImage *img;
|
||||
|
||||
if ( flags & CShowableAnim::BASE && frame != 0)
|
||||
if ((img = anim->getImage(0, group)))
|
||||
img->draw(to, pos.x, pos.y);
|
||||
|
||||
if ((img = anim->getImage(frame, group)))
|
||||
img->draw(to, pos.x, pos.y);
|
||||
}
|
||||
|
||||
void CAnimImage::setFrame(size_t Frame, size_t Group)
|
||||
{
|
||||
if (frame == Frame && group==Group)
|
||||
return;
|
||||
if (anim->size(Group) > Frame)
|
||||
{
|
||||
anim->load(Frame, Group);
|
||||
anim->unload(frame, group);
|
||||
frame = Frame;
|
||||
group = Group;
|
||||
IImage *img = anim->getImage(frame, group);
|
||||
if (img)
|
||||
{
|
||||
if (flags & CShowableAnim::PLAYER_COLORED)
|
||||
img->playerColored(player);
|
||||
pos.w = img->width();
|
||||
pos.h = img->height();
|
||||
}
|
||||
}
|
||||
else
|
||||
logGlobal->errorStream() << "Error: accessing unavailable frame " << Group << ":" << Frame << " in CAnimation!";
|
||||
}
|
||||
|
||||
void CAnimImage::playerColored(PlayerColor currPlayer)
|
||||
{
|
||||
player = currPlayer;
|
||||
flags |= CShowableAnim::PLAYER_COLORED;
|
||||
anim->getImage(frame, group)->playerColored(player);
|
||||
if (flags & CShowableAnim::BASE)
|
||||
anim->getImage(0, group)->playerColored(player);
|
||||
}
|
||||
|
||||
CShowableAnim::CShowableAnim(int x, int y, std::string name, ui8 Flags, ui32 Delay, size_t Group):
|
||||
anim(name, Flags & USE_RLE),
|
||||
group(Group),
|
||||
frame(0),
|
||||
first(0),
|
||||
frameDelay(Delay),
|
||||
value(0),
|
||||
flags(Flags),
|
||||
xOffset(0),
|
||||
yOffset(0),
|
||||
alpha(255)
|
||||
{
|
||||
anim.loadGroup(group);
|
||||
last = anim.size(group);
|
||||
|
||||
pos.w = anim.getImage(0, group)->width();
|
||||
pos.h = anim.getImage(0, group)->height();
|
||||
pos.x+= x;
|
||||
pos.y+= y;
|
||||
}
|
||||
|
||||
CShowableAnim::~CShowableAnim()
|
||||
{
|
||||
anim.unloadGroup(group);
|
||||
}
|
||||
|
||||
void CShowableAnim::setAlpha(ui32 alphaValue)
|
||||
{
|
||||
alpha = std::min<ui32>(alphaValue, 255);
|
||||
}
|
||||
|
||||
bool CShowableAnim::set(size_t Group, size_t from, size_t to)
|
||||
{
|
||||
size_t max = anim.size(Group);
|
||||
|
||||
if (to < max)
|
||||
max = to;
|
||||
|
||||
if (max < from || max == 0)
|
||||
return false;
|
||||
|
||||
anim.load(Group);
|
||||
anim.unload(group);
|
||||
group = Group;
|
||||
frame = first = from;
|
||||
last = max;
|
||||
value = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CShowableAnim::set(size_t Group)
|
||||
{
|
||||
if (anim.size(Group)== 0)
|
||||
return false;
|
||||
if (group != Group)
|
||||
{
|
||||
anim.loadGroup(Group);
|
||||
anim.unloadGroup(group);
|
||||
first = 0;
|
||||
group = Group;
|
||||
last = anim.size(Group);
|
||||
}
|
||||
frame = value = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CShowableAnim::reset()
|
||||
{
|
||||
value = 0;
|
||||
frame = first;
|
||||
|
||||
if (callback)
|
||||
callback();
|
||||
}
|
||||
|
||||
void CShowableAnim::clipRect(int posX, int posY, int width, int height)
|
||||
{
|
||||
xOffset = posX;
|
||||
yOffset = posY;
|
||||
pos.w = width;
|
||||
pos.h = height;
|
||||
}
|
||||
|
||||
void CShowableAnim::show(SDL_Surface * to)
|
||||
{
|
||||
if ( flags & BASE )// && frame != first) // FIXME: results in graphical glytch in Fortress, upgraded hydra's dwelling
|
||||
blitImage(first, group, to);
|
||||
blitImage(frame, group, to);
|
||||
|
||||
if ((flags & PLAY_ONCE) && frame + 1 == last)
|
||||
return;
|
||||
|
||||
if ( ++value == frameDelay )
|
||||
{
|
||||
value = 0;
|
||||
if ( ++frame >= last)
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CShowableAnim::showAll(SDL_Surface * to)
|
||||
{
|
||||
if ( flags & BASE )// && frame != first)
|
||||
blitImage(first, group, to);
|
||||
blitImage(frame, group, to);
|
||||
}
|
||||
|
||||
void CShowableAnim::blitImage(size_t frame, size_t group, SDL_Surface *to)
|
||||
{
|
||||
assert(to);
|
||||
Rect src( xOffset, yOffset, pos.w, pos.h);
|
||||
IImage * img = anim.getImage(frame, group);
|
||||
if (img)
|
||||
img->draw(to, pos.x-xOffset, pos.y-yOffset, &src, alpha);
|
||||
}
|
||||
|
||||
void CShowableAnim::rotate(bool on, bool vertical)
|
||||
{
|
||||
ui8 flag = vertical? VERTICAL_FLIP:HORIZONTAL_FLIP;
|
||||
if (on)
|
||||
flags |= flag;
|
||||
else
|
||||
flags &= ~flag;
|
||||
}
|
||||
|
||||
CCreatureAnim::CCreatureAnim(int x, int y, std::string name, Rect picPos, ui8 flags, EAnimType type):
|
||||
CShowableAnim(x,y,name,flags,4,type)
|
||||
{
|
||||
xOffset = picPos.x;
|
||||
yOffset = picPos.y;
|
||||
if (picPos.w)
|
||||
pos.w = picPos.w;
|
||||
if (picPos.h)
|
||||
pos.h = picPos.h;
|
||||
};
|
||||
|
||||
void CCreatureAnim::loopPreview(bool warMachine)
|
||||
{
|
||||
std::vector<EAnimType> available;
|
||||
|
||||
static const EAnimType creaPreviewList[] = {HOLDING, HITTED, DEFENCE, ATTACK_FRONT, CAST_FRONT};
|
||||
static const EAnimType machPreviewList[] = {HOLDING, MOVING, SHOOT_UP, SHOOT_FRONT, SHOOT_DOWN};
|
||||
auto & previewList = warMachine ? machPreviewList : creaPreviewList;
|
||||
|
||||
for (auto & elem : previewList)
|
||||
if (anim.size(elem))
|
||||
available.push_back(elem);
|
||||
|
||||
size_t rnd = CRandomGenerator::getDefault().nextInt(available.size() * 2 - 1);
|
||||
|
||||
if (rnd >= available.size())
|
||||
{
|
||||
EAnimType type;
|
||||
if ( anim.size(MOVING) == 0 )//no moving animation present
|
||||
type = HOLDING;
|
||||
else
|
||||
type = MOVING;
|
||||
|
||||
//display this anim for ~1 second (time is random, but it looks good)
|
||||
for (size_t i=0; i< 12/anim.size(type) + 1; i++)
|
||||
addLast(type);
|
||||
}
|
||||
else
|
||||
addLast(available[rnd]);
|
||||
}
|
||||
|
||||
void CCreatureAnim::addLast(EAnimType newType)
|
||||
{
|
||||
if (type != MOVING && newType == MOVING)//starting moving - play init sequence
|
||||
{
|
||||
queue.push( MOVE_START );
|
||||
}
|
||||
else if (type == MOVING && newType != MOVING )//previous anim was moving - finish it
|
||||
{
|
||||
queue.push( MOVE_END );
|
||||
}
|
||||
if (newType == TURN_L || newType == TURN_R)
|
||||
queue.push(newType);
|
||||
|
||||
queue.push(newType);
|
||||
}
|
||||
|
||||
void CCreatureAnim::reset()
|
||||
{
|
||||
//if we are in the middle of rotation - set flag
|
||||
if (type == TURN_L && !queue.empty() && queue.front() == TURN_L)
|
||||
rotate(true);
|
||||
if (type == TURN_R && !queue.empty() && queue.front() == TURN_R)
|
||||
rotate(false);
|
||||
|
||||
while (!queue.empty())
|
||||
{
|
||||
EAnimType at = queue.front();
|
||||
queue.pop();
|
||||
if (set(at))
|
||||
return;
|
||||
}
|
||||
if (callback)
|
||||
callback();
|
||||
while (!queue.empty())
|
||||
{
|
||||
EAnimType at = queue.front();
|
||||
queue.pop();
|
||||
if (set(at))
|
||||
return;
|
||||
}
|
||||
set(HOLDING);
|
||||
}
|
||||
|
||||
void CCreatureAnim::startPreview(bool warMachine)
|
||||
{
|
||||
callback = std::bind(&CCreatureAnim::loopPreview, this, warMachine);
|
||||
}
|
||||
|
||||
void CCreatureAnim::clearAndSet(EAnimType type)
|
||||
{
|
||||
while (!queue.empty())
|
||||
queue.pop();
|
||||
set(type);
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../lib/vcmi_endian.h"
|
||||
#include "gui/CIntObject.h"
|
||||
#include "../../lib/vcmi_endian.h"
|
||||
#include "gui/Geometries.h"
|
||||
#include "../../lib/GameConstants.h"
|
||||
|
||||
/*
|
||||
* CAnimation.h, part of VCMI engine
|
||||
@ -219,162 +220,3 @@ public:
|
||||
//total count of frames in group (including not loaded)
|
||||
size_t size(size_t group=0) const;
|
||||
};
|
||||
|
||||
|
||||
/// Class for displaying one image from animation
|
||||
class CAnimImage: public CIntObject
|
||||
{
|
||||
private:
|
||||
CAnimation* anim;
|
||||
//displayed frame/group
|
||||
size_t frame;
|
||||
size_t group;
|
||||
PlayerColor player;
|
||||
ui8 flags;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
CAnimImage(std::string name, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
|
||||
CAnimImage(CAnimation* anim, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
|
||||
~CAnimImage();//d-tor
|
||||
|
||||
//size of animation
|
||||
size_t size();
|
||||
|
||||
//change displayed frame on this one
|
||||
void setFrame(size_t Frame, size_t Group=0);
|
||||
|
||||
//makes image player-colored
|
||||
void playerColored(PlayerColor player);
|
||||
|
||||
void showAll(SDL_Surface * to);
|
||||
};
|
||||
|
||||
/// Base class for displaying animation, used as superclass for different animations
|
||||
class CShowableAnim: public CIntObject
|
||||
{
|
||||
public:
|
||||
enum EFlags
|
||||
{
|
||||
BASE=1, //base frame will be blitted before current one
|
||||
HORIZONTAL_FLIP=2, //TODO: will be displayed rotated
|
||||
VERTICAL_FLIP=4, //TODO: will be displayed rotated
|
||||
USE_RLE=8, //RLE-d version, support full alpha-channel for 8-bit images
|
||||
PLAYER_COLORED=16, //TODO: all loaded images will be player-colored
|
||||
PLAY_ONCE=32 //play animation only once and stop at last frame
|
||||
};
|
||||
protected:
|
||||
CAnimation anim;
|
||||
|
||||
size_t group, frame;//current frame
|
||||
|
||||
size_t first, last; //animation range
|
||||
|
||||
//TODO: replace with time delay(needed for battles)
|
||||
ui32 frameDelay;//delay in frames of each image
|
||||
ui32 value;//how many times current frame was showed
|
||||
|
||||
ui8 flags;//Flags from EFlags enum
|
||||
|
||||
//blit image with optional rotation, fitting into rect, etc
|
||||
void blitImage(size_t frame, size_t group, SDL_Surface *to);
|
||||
|
||||
//For clipping in rect, offsets of picture coordinates
|
||||
int xOffset, yOffset;
|
||||
|
||||
ui8 alpha;
|
||||
|
||||
public:
|
||||
//called when next animation sequence is required
|
||||
std::function<void()> callback;
|
||||
|
||||
//Set per-surface alpha, 0 = transparent, 255 = opaque
|
||||
void setAlpha(ui32 alphaValue);
|
||||
|
||||
CShowableAnim(int x, int y, std::string name, ui8 flags=0, ui32 Delay=4, size_t Group=0);
|
||||
~CShowableAnim();
|
||||
|
||||
//set animation to group or part of group
|
||||
bool set(size_t Group);
|
||||
bool set(size_t Group, size_t from, size_t to=-1);
|
||||
|
||||
//set rotation flags
|
||||
void rotate(bool on, bool vertical=false);
|
||||
|
||||
//move displayed part of picture (if picture is clipped to rect)
|
||||
void clipRect(int posX, int posY, int width, int height);
|
||||
|
||||
//set frame to first, call callback
|
||||
virtual void reset();
|
||||
|
||||
//show current frame and increase counter
|
||||
void show(SDL_Surface * to);
|
||||
void showAll(SDL_Surface * to);
|
||||
};
|
||||
|
||||
/// Creature-dependend animations like attacking, moving,...
|
||||
class CCreatureAnim: public CShowableAnim
|
||||
{
|
||||
public:
|
||||
|
||||
enum EHeroAnimType
|
||||
{
|
||||
HERO_HOLDING = 0,
|
||||
HERO_IDLE = 1, // idling movement that happens from time to time
|
||||
HERO_DEFEAT = 2, // played when army loses stack or on friendly fire
|
||||
HERO_VICTORY = 3, // when enemy stack killed or huge damage is dealt
|
||||
HERO_CAST_SPELL = 4 // spellcasting
|
||||
};
|
||||
|
||||
enum EAnimType // list of creature animations, numbers were taken from def files
|
||||
{
|
||||
MOVING=0,
|
||||
MOUSEON=1,
|
||||
HOLDING=2,
|
||||
HITTED=3,
|
||||
DEFENCE=4,
|
||||
DEATH=5,
|
||||
//DEATH2=6, //unused?
|
||||
TURN_L=7,
|
||||
TURN_R=8, //same
|
||||
//TURN_L2=9, //identical to previous?
|
||||
//TURN_R2=10,
|
||||
ATTACK_UP=11,
|
||||
ATTACK_FRONT=12,
|
||||
ATTACK_DOWN=13,
|
||||
SHOOT_UP=14,
|
||||
SHOOT_FRONT=15,
|
||||
SHOOT_DOWN=16,
|
||||
CAST_UP=17,
|
||||
CAST_FRONT=18,
|
||||
CAST_DOWN=19,
|
||||
MOVE_START=20,
|
||||
MOVE_END=21,
|
||||
DEAD = 22 // new group, used to show dead stacks. If empty - last frame from "DEATH" will be copied here
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
//queue of animations waiting to be displayed
|
||||
std::queue<EAnimType> queue;
|
||||
|
||||
//this function is used as callback if preview flag was set during construction
|
||||
void loopPreview(bool warMachine);
|
||||
|
||||
public:
|
||||
//change anim to next if queue is not empty, call callback othervice
|
||||
void reset();
|
||||
|
||||
//add sequence to the end of queue
|
||||
void addLast(EAnimType newType);
|
||||
|
||||
void startPreview(bool warMachine);
|
||||
|
||||
//clear queue and set animation to this sequence
|
||||
void clearAndSet(EAnimType type);
|
||||
|
||||
CCreatureAnim(int x, int y, std::string name, Rect picPos,
|
||||
ui8 flags= USE_RLE, EAnimType = HOLDING );
|
||||
|
||||
};
|
@ -2,9 +2,11 @@
|
||||
#include "CCursorHandler.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "SDL_Extensions.h"
|
||||
#include "../CAnimation.h"
|
||||
#include "CGuiHandler.h"
|
||||
#include "widgets/Images.h"
|
||||
|
||||
#include "../CMT.h"
|
||||
|
||||
/*
|
||||
|
@ -1,10 +1,12 @@
|
||||
#include "StdInc.h"
|
||||
#include "CGuiHandler.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "CIntObject.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "CCursorHandler.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../../lib/CThreadHelper.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../CMT.h"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/CStopWatch.h"
|
||||
//#include "../../lib/CStopWatch.h"
|
||||
#include "Geometries.h"
|
||||
#include "SDL_Extensions.h"
|
||||
|
||||
|
@ -1,9 +1,15 @@
|
||||
#include "StdInc.h"
|
||||
#include "CIntObject.h"
|
||||
|
||||
#include "CGuiHandler.h"
|
||||
#include "SDL_Extensions.h"
|
||||
#include "../CMessage.h"
|
||||
|
||||
IShowActivatable::IShowActivatable()
|
||||
{
|
||||
type = 0;
|
||||
}
|
||||
|
||||
void ILockedUpdatable::runLocked(std::function<void(IUpdateable*)> cb)
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(updateGuard);
|
||||
@ -317,6 +323,19 @@ bool CIntObject::captureThisEvent(const SDL_KeyboardEvent & key)
|
||||
return captureAllKeys;
|
||||
}
|
||||
|
||||
CKeyShortcut::CKeyShortcut()
|
||||
{}
|
||||
|
||||
CKeyShortcut::CKeyShortcut(int key)
|
||||
{
|
||||
if (key != SDLK_UNKNOWN)
|
||||
assignedKeys.insert(key);
|
||||
}
|
||||
|
||||
CKeyShortcut::CKeyShortcut(std::set<int> Keys)
|
||||
:assignedKeys(Keys)
|
||||
{}
|
||||
|
||||
void CKeyShortcut::keyPressed(const SDL_KeyboardEvent & key)
|
||||
{
|
||||
if(vstd::contains(assignedKeys,key.keysym.sym)
|
||||
|
@ -18,6 +18,8 @@ struct SDL_Surface;
|
||||
class CPicture;
|
||||
class CGuiHandler;
|
||||
|
||||
struct SDL_KeyboardEvent;
|
||||
|
||||
using boost::logic::tribool;
|
||||
|
||||
// Defines a activate/deactive method
|
||||
@ -216,8 +218,8 @@ class CKeyShortcut : public virtual CIntObject
|
||||
{
|
||||
public:
|
||||
std::set<int> assignedKeys;
|
||||
CKeyShortcut(){}; //c-tor
|
||||
CKeyShortcut(int key){assignedKeys.insert(key);}; //c-tor
|
||||
CKeyShortcut(std::set<int> Keys):assignedKeys(Keys){}; //c-tor
|
||||
CKeyShortcut();
|
||||
CKeyShortcut(int key);
|
||||
CKeyShortcut(std::set<int> Keys);
|
||||
virtual void keyPressed(const SDL_KeyboardEvent & key); //call-in
|
||||
};
|
||||
|
@ -1,557 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CIntObject.h"
|
||||
#include "SDL_Extensions.h"
|
||||
#include "../../lib/FunctionList.h"
|
||||
|
||||
struct SDL_Surface;
|
||||
struct Rect;
|
||||
class CAnimImage;
|
||||
class CLabel;
|
||||
class CAnimation;
|
||||
class CDefHandler;
|
||||
|
||||
/*
|
||||
* CPicture.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
// Window GUI class
|
||||
class CSimpleWindow : public CIntObject
|
||||
{
|
||||
public:
|
||||
SDL_Surface * bitmap; //background
|
||||
virtual void show(SDL_Surface * to);
|
||||
CSimpleWindow():bitmap(nullptr){}; //c-tor
|
||||
virtual ~CSimpleWindow(); //d-tor
|
||||
};
|
||||
|
||||
// Image class
|
||||
class CPicture : public CIntObject
|
||||
{
|
||||
void setSurface(SDL_Surface *to);
|
||||
public:
|
||||
SDL_Surface * bg;
|
||||
Rect * srcRect; //if nullptr then whole surface will be used
|
||||
bool freeSurf; //whether surface will be freed upon CPicture destruction
|
||||
bool needRefresh;//Surface needs to be displayed each frame
|
||||
|
||||
operator SDL_Surface*()
|
||||
{
|
||||
return bg;
|
||||
}
|
||||
|
||||
CPicture(const Rect & r, const SDL_Color & color, bool screenFormat = false); //rect filled with given color
|
||||
CPicture(const Rect & r, ui32 color, bool screenFormat = false); //rect filled with given color
|
||||
CPicture(SDL_Surface * BG, int x = 0, int y=0, bool Free = true); //wrap existing SDL_Surface
|
||||
CPicture(const std::string &bmpname, int x=0, int y=0);
|
||||
CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0, bool free = false); //wrap subrect of given surface
|
||||
~CPicture();
|
||||
void init();
|
||||
|
||||
//set alpha value for whole surface. Note: may be messed up if surface is shared
|
||||
// 0=transparent, 255=opaque
|
||||
void setAlpha(int value);
|
||||
|
||||
void scaleTo(Point size);
|
||||
void createSimpleRect(const Rect &r, bool screenFormat, ui32 color);
|
||||
void show(SDL_Surface * to);
|
||||
void showAll(SDL_Surface * to);
|
||||
void convertToScreenBPP();
|
||||
void colorizeAndConvert(PlayerColor player);
|
||||
void colorize(PlayerColor player);
|
||||
};
|
||||
|
||||
/// area filled with specific texture
|
||||
class CFilledTexture : CIntObject
|
||||
{
|
||||
SDL_Surface * texture;
|
||||
|
||||
public:
|
||||
CFilledTexture(std::string imageName, Rect position);
|
||||
~CFilledTexture();
|
||||
void showAll(SDL_Surface *to);
|
||||
};
|
||||
|
||||
namespace config{struct ButtonInfo;}
|
||||
|
||||
/// Base class for buttons.
|
||||
class CButtonBase : public CKeyShortcut
|
||||
{
|
||||
public:
|
||||
enum ButtonState
|
||||
{
|
||||
NORMAL=0,
|
||||
PRESSED=1,
|
||||
BLOCKED=2,
|
||||
HIGHLIGHTED=3
|
||||
};
|
||||
private:
|
||||
int bitmapOffset; // base offset of visible bitmap from animation
|
||||
ButtonState state;//current state of button from enum
|
||||
|
||||
public:
|
||||
bool swappedImages,//fix for some buttons: normal and pressed image are swapped
|
||||
keepFrame; // don't change visual representation
|
||||
|
||||
void addTextOverlay(const std::string &Text, EFonts font, SDL_Color color = Colors::WHITE);
|
||||
void update();//to refresh button after image or text change
|
||||
|
||||
void setOffset(int newOffset);
|
||||
void setState(ButtonState newState);
|
||||
ButtonState getState();
|
||||
|
||||
//just to make code clearer
|
||||
void block(bool on);
|
||||
bool isBlocked();
|
||||
bool isHighlighted();
|
||||
|
||||
CAnimImage * image; //image for this button
|
||||
CLabel * text;//text overlay
|
||||
|
||||
CButtonBase(); //c-tor
|
||||
virtual ~CButtonBase(); //d-tor
|
||||
};
|
||||
|
||||
/// Typical Heroes 3 button which can be inactive or active and can
|
||||
/// hold further information if you right-click it
|
||||
class CAdventureMapButton : public CButtonBase
|
||||
{
|
||||
std::vector<std::string> imageNames;//store list of images that can be used by this button
|
||||
size_t currentImage;
|
||||
|
||||
void onButtonClicked(); // calls callback
|
||||
public:
|
||||
std::map<int, std::string> hoverTexts; //text for statusbar
|
||||
std::string helpBox; //for right-click help
|
||||
CFunctionList<void()> callback;
|
||||
bool actOnDown,//runs when mouse is pressed down over it, not when up
|
||||
hoverable,//if true, button will be highlighted when hovered
|
||||
borderEnabled,
|
||||
soundDisabled;
|
||||
SDL_Color borderColor;
|
||||
|
||||
void clickRight(tribool down, bool previousState);
|
||||
virtual void clickLeft(tribool down, bool previousState);
|
||||
void hover (bool on);
|
||||
|
||||
CAdventureMapButton(); //c-tor
|
||||
CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
|
||||
CAdventureMapButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
|
||||
CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, config::ButtonInfo *info, int key=0);//c-tor
|
||||
|
||||
void init(const CFunctionList<void()> &Callback, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key );
|
||||
|
||||
void setIndex(size_t index, bool playerColoredButton=false);
|
||||
void setImage(CAnimation* anim, bool playerColoredButton=false, int animFlags=0);
|
||||
void setPlayerColor(PlayerColor player);
|
||||
void showAll(SDL_Surface * to);
|
||||
};
|
||||
|
||||
/// A button which can be selected/deselected
|
||||
class CHighlightableButton
|
||||
: public CAdventureMapButton
|
||||
{
|
||||
public:
|
||||
CHighlightableButton(const CFunctionList<void()> &onSelect, const CFunctionList<void()> &onDeselect, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key=0);
|
||||
CHighlightableButton(const std::pair<std::string, std::string> &help, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
|
||||
CHighlightableButton(const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
|
||||
bool onlyOn;//button can not be de-selected
|
||||
bool selected;//state of highlightable button
|
||||
int ID; //for identification
|
||||
CFunctionList<void()> callback2; //when de-selecting
|
||||
void select(bool on);
|
||||
void clickLeft(tribool down, bool previousState);
|
||||
};
|
||||
|
||||
/// A group of buttons where one button can be selected
|
||||
class CHighlightableButtonsGroup : public CIntObject
|
||||
{
|
||||
public:
|
||||
CFunctionList<void(int)> onChange; //called when changing selected button with new button's id
|
||||
std::vector<CHighlightableButton*> buttons;
|
||||
bool musicLike; //determines the behaviour of this group
|
||||
|
||||
//void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid);
|
||||
void addButton(CHighlightableButton* bt);//add existing button, it'll be deleted by CHighlightableButtonsGroup destructor
|
||||
void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList<void()> &OnSelect=0, int key=0); //creates new button
|
||||
CHighlightableButtonsGroup(const CFunctionList<void(int)> & OnChange, bool musicLikeButtons = false);
|
||||
~CHighlightableButtonsGroup();
|
||||
void select(int id, bool mode); //mode==0: id is serial; mode==1: id is unique button id
|
||||
void selectionChanged(int to);
|
||||
void show(SDL_Surface * to);
|
||||
void showAll(SDL_Surface * to);
|
||||
void block(ui8 on);
|
||||
};
|
||||
|
||||
/// A typical slider which can be orientated horizontally/vertically.
|
||||
class CSlider : public CIntObject
|
||||
{
|
||||
public:
|
||||
CAdventureMapButton *left, *right, *slider; //if vertical then left=up
|
||||
int capacity;//how many elements can be active at same time (e.g. hero list = 5)
|
||||
int amount; //total amount of elements (e.g. hero list = 0-8)
|
||||
int positions; //number of highest position (0 if there is only one)
|
||||
int value; //first active element
|
||||
int scrollStep; // how many elements will be scrolled via one click, default = 1
|
||||
bool horizontal;
|
||||
bool wheelScrolling;
|
||||
bool keyScrolling;
|
||||
|
||||
std::function<void(int)> moved;
|
||||
|
||||
void redrawSlider();
|
||||
void sliderClicked();
|
||||
void moveLeft();
|
||||
void moveRight();
|
||||
void moveTo(int to);
|
||||
void block(bool on);
|
||||
void setAmount(int to);
|
||||
|
||||
void keyPressed(const SDL_KeyboardEvent & key);
|
||||
void wheelScrolled(bool down, bool in);
|
||||
void clickLeft(tribool down, bool previousState);
|
||||
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
|
||||
void showAll(SDL_Surface * to);
|
||||
|
||||
CSlider(int x, int y, int totalw, std::function<void(int)> Moved, int Capacity, int Amount,
|
||||
int Value=0, bool Horizontal=true, int style = 0); //style 0 - brown, 1 - blue
|
||||
~CSlider();
|
||||
void moveToMax();
|
||||
};
|
||||
|
||||
/// Used as base for Tabs and List classes
|
||||
class CObjectList : public CIntObject
|
||||
{
|
||||
public:
|
||||
typedef std::function<CIntObject* (size_t)> CreateFunc;
|
||||
typedef std::function<void(CIntObject *)> DestroyFunc;
|
||||
|
||||
private:
|
||||
CreateFunc createObject;
|
||||
DestroyFunc destroyObject;
|
||||
|
||||
protected:
|
||||
//Internal methods for safe creation of items (Children capturing and activation/deactivation if needed)
|
||||
void deleteItem(CIntObject* item);
|
||||
CIntObject* createItem(size_t index);
|
||||
|
||||
CObjectList(CreateFunc create, DestroyFunc destroy = DestroyFunc());//Protected constructor
|
||||
};
|
||||
|
||||
/// Window element with multiple tabs
|
||||
class CTabbedInt : public CObjectList
|
||||
{
|
||||
private:
|
||||
CIntObject * activeTab;
|
||||
size_t activeID;
|
||||
|
||||
public:
|
||||
//CreateFunc, DestroyFunc - see CObjectList
|
||||
//Pos - position of object, all tabs will be moved to this position
|
||||
//ActiveID - ID of initially active tab
|
||||
CTabbedInt(CreateFunc create, DestroyFunc destroy = DestroyFunc(), Point position=Point(), size_t ActiveID=0);
|
||||
|
||||
void setActive(size_t which);
|
||||
//recreate active tab
|
||||
void reset();
|
||||
|
||||
//return currently active item
|
||||
CIntObject * getItem();
|
||||
};
|
||||
|
||||
/// List of IntObjects with optional slider
|
||||
class CListBox : public CObjectList
|
||||
{
|
||||
private:
|
||||
std::list< CIntObject* > items;
|
||||
size_t first;
|
||||
size_t totalSize;
|
||||
|
||||
Point itemOffset;
|
||||
CSlider * slider;
|
||||
|
||||
void updatePositions();
|
||||
public:
|
||||
//CreateFunc, DestroyFunc - see CObjectList
|
||||
//Pos - position of first item
|
||||
//ItemOffset - distance between items in the list
|
||||
//VisibleSize - maximal number of displayable at once items
|
||||
//TotalSize
|
||||
//Slider - slider style, bit field: 1 = present(disabled), 2=horisontal(vertical), 4=blue(brown)
|
||||
//SliderPos - position of slider, if present
|
||||
CListBox(CreateFunc create, DestroyFunc destroy, Point Pos, Point ItemOffset, size_t VisibleSize,
|
||||
size_t TotalSize, size_t InitialPos=0, int Slider=0, Rect SliderPos=Rect() );
|
||||
|
||||
//recreate all visible items
|
||||
void reset();
|
||||
|
||||
//change or get total amount of items in the list
|
||||
void resize(size_t newSize);
|
||||
size_t size();
|
||||
|
||||
//return item with index which or null if not present
|
||||
CIntObject * getItem(size_t which);
|
||||
|
||||
//return currently active items
|
||||
const std::list< CIntObject * > & getItems();
|
||||
|
||||
//get index of this item. -1 if not found
|
||||
size_t getIndexOf(CIntObject * item);
|
||||
|
||||
//scroll list to make item which visible
|
||||
void scrollTo(size_t which);
|
||||
|
||||
//scroll list to specified position
|
||||
void moveToPos(size_t which);
|
||||
void moveToNext();
|
||||
void moveToPrev();
|
||||
|
||||
size_t getPos();
|
||||
};
|
||||
|
||||
/// Small helper class to manage group of similar labels
|
||||
class CLabelGroup : public CIntObject
|
||||
{
|
||||
std::list<CLabel*> labels;
|
||||
EFonts font;
|
||||
EAlignment align;
|
||||
SDL_Color color;
|
||||
public:
|
||||
CLabelGroup(EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE);
|
||||
void add(int x=0, int y=0, const std::string &text = "");
|
||||
};
|
||||
|
||||
/// Base class for all text-related widgets.
|
||||
/// Controls text blitting-related options
|
||||
class CTextContainer : public virtual CIntObject
|
||||
{
|
||||
protected:
|
||||
/// returns size of border, for left- or right-aligned text
|
||||
virtual Point getBorderSize() = 0;
|
||||
/// do actual blitting of line. Text "what" will be placed at "where" and aligned according to alignment
|
||||
void blitLine(SDL_Surface * to, Rect where, std::string what);
|
||||
|
||||
CTextContainer(EAlignment alignment, EFonts font, SDL_Color color);
|
||||
|
||||
public:
|
||||
EAlignment alignment;
|
||||
EFonts font;
|
||||
SDL_Color color; // default font color. Can be overridden by placing "{}" into the string
|
||||
};
|
||||
|
||||
/// Label which shows text
|
||||
class CLabel : public CTextContainer
|
||||
{
|
||||
protected:
|
||||
Point getBorderSize() override;
|
||||
virtual std::string visibleText();
|
||||
|
||||
CPicture *bg;
|
||||
public:
|
||||
|
||||
std::string text;
|
||||
bool autoRedraw; //whether control will redraw itself on setTxt
|
||||
|
||||
std::string getText();
|
||||
virtual void setText(const std::string &Txt);
|
||||
|
||||
CLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT,
|
||||
const SDL_Color &Color = Colors::WHITE, const std::string &Text = "");
|
||||
void showAll(SDL_Surface * to); //shows statusbar (with current text)
|
||||
};
|
||||
|
||||
/// Multi-line label that can display multiple lines of text
|
||||
/// If text is too big to fit into requested area remaining part will not be visible
|
||||
class CMultiLineLabel : public CLabel
|
||||
{
|
||||
// text to blit, split into lines that are no longer than widget width
|
||||
std::vector<std::string> lines;
|
||||
|
||||
// area of text that actually will be printed, default is widget size
|
||||
Rect visibleSize;
|
||||
|
||||
void splitText(const std::string &Txt);
|
||||
Rect getTextLocation();
|
||||
public:
|
||||
// total size of text, x = longest line of text, y = total height of lines
|
||||
Point textSize;
|
||||
|
||||
CMultiLineLabel(Rect position, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE, const std::string &Text = "");
|
||||
|
||||
void setText(const std::string &Txt);
|
||||
void showAll(SDL_Surface * to);
|
||||
|
||||
void setVisibleSize(Rect visibleSize);
|
||||
// scrolls text visible in widget. Positive value will move text up
|
||||
void scrollTextTo(int distance);
|
||||
void scrollTextBy(int distance);
|
||||
};
|
||||
|
||||
/// a multi-line label that tries to fit text with given available width and height;
|
||||
/// if not possible, it creates a slider for scrolling text
|
||||
class CTextBox : public CIntObject
|
||||
{
|
||||
int sliderStyle;
|
||||
public:
|
||||
CMultiLineLabel * label;
|
||||
CSlider *slider;
|
||||
|
||||
CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE);
|
||||
|
||||
void resize(Point newSize);
|
||||
void setText(const std::string &Txt);
|
||||
void sliderMoved(int to);
|
||||
};
|
||||
|
||||
/// Status bar which is shown at the bottom of the in-game screens
|
||||
class CGStatusBar : public CLabel
|
||||
{
|
||||
bool textLock; //Used for blocking changes to the text
|
||||
void init();
|
||||
|
||||
CGStatusBar *oldStatusBar;
|
||||
protected:
|
||||
Point getBorderSize() override;
|
||||
|
||||
public:
|
||||
|
||||
void clear();//clears statusbar and refreshes
|
||||
void setText(const std::string & Text) override; //prints text and refreshes statusbar
|
||||
|
||||
void show(SDL_Surface * to); //shows statusbar (with current text)
|
||||
|
||||
CGStatusBar(CPicture *BG, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = Colors::WHITE); //given CPicture will be captured by created sbar and it's pos will be used as pos for sbar
|
||||
CGStatusBar(int x, int y, std::string name, int maxw=-1);
|
||||
~CGStatusBar();
|
||||
|
||||
void lock(bool shouldLock); //If true, current text cannot be changed until lock(false) is called
|
||||
};
|
||||
|
||||
/// UIElement which can get input focus
|
||||
class CFocusable : public virtual CIntObject
|
||||
{
|
||||
protected:
|
||||
virtual void focusGot(){};
|
||||
virtual void focusLost(){};
|
||||
public:
|
||||
bool focus; //only one focusable control can have focus at one moment
|
||||
|
||||
void giveFocus(); //captures focus
|
||||
void moveFocus(); //moves focus to next active control (may be used for tab switching)
|
||||
|
||||
static std::list<CFocusable*> focusables; //all existing objs
|
||||
static CFocusable *inputWithFocus; //who has focus now
|
||||
CFocusable();
|
||||
~CFocusable();
|
||||
};
|
||||
|
||||
/// Text input box where players can enter text
|
||||
class CTextInput : public CLabel, public CFocusable
|
||||
{
|
||||
std::string newText;
|
||||
protected:
|
||||
std::string visibleText() override;
|
||||
|
||||
void focusGot() override;
|
||||
void focusLost() override;
|
||||
public:
|
||||
CFunctionList<void(const std::string &)> cb;
|
||||
CFunctionList<void(std::string &, const std::string &)> filters;
|
||||
void setText(const std::string &nText, bool callCb = false);
|
||||
|
||||
CTextInput(const Rect &Pos, EFonts font, const CFunctionList<void(const std::string &)> &CB);
|
||||
CTextInput(const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList<void(const std::string &)> &CB);
|
||||
CTextInput(const Rect &Pos, SDL_Surface *srf = nullptr);
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void keyPressed(const SDL_KeyboardEvent & key) override;
|
||||
bool captureThisEvent(const SDL_KeyboardEvent & key) override;
|
||||
|
||||
#ifndef VCMI_SDL1
|
||||
void textInputed(const SDL_TextInputEvent & event) override;
|
||||
void textEdited(const SDL_TextEditingEvent & event) override;
|
||||
|
||||
|
||||
#endif // VCMI_SDL1
|
||||
|
||||
//Filter that will block all characters not allowed in filenames
|
||||
static void filenameFilter(std::string &text, const std::string & oldText);
|
||||
//Filter that will allow only input of numbers in range min-max (min-max are allowed)
|
||||
//min-max should be set via something like std::bind
|
||||
static void numberFilter(std::string &text, const std::string & oldText, int minValue, int maxValue);
|
||||
};
|
||||
|
||||
/// Shows a text by moving the mouse cursor over the object
|
||||
class CHoverableArea: public virtual CIntObject
|
||||
{
|
||||
public:
|
||||
std::string hoverText;
|
||||
|
||||
virtual void hover (bool on);
|
||||
|
||||
CHoverableArea();
|
||||
virtual ~CHoverableArea();
|
||||
};
|
||||
|
||||
/// Can interact on left and right mouse clicks, plus it shows a text when by hovering over it
|
||||
class LRClickableAreaWText: public CHoverableArea
|
||||
{
|
||||
public:
|
||||
std::string text;
|
||||
|
||||
LRClickableAreaWText();
|
||||
LRClickableAreaWText(const Rect &Pos, const std::string &HoverText = "", const std::string &ClickText = "");
|
||||
virtual ~LRClickableAreaWText();
|
||||
void init();
|
||||
|
||||
virtual void clickLeft(tribool down, bool previousState);
|
||||
virtual void clickRight(tribool down, bool previousState);
|
||||
};
|
||||
|
||||
/// Basic class for windows
|
||||
class CWindowObject : public CIntObject
|
||||
{
|
||||
CPicture * createBg(std::string imageName, bool playerColored);
|
||||
int getUsedEvents(int options);
|
||||
|
||||
CIntObject *shadow;
|
||||
void setShadow(bool on);
|
||||
|
||||
int options;
|
||||
|
||||
protected:
|
||||
CPicture * background;
|
||||
|
||||
//Simple function with call to GH.popInt
|
||||
void close();
|
||||
//Used only if RCLICK_POPUP was set
|
||||
void clickRight(tribool down, bool previousState);
|
||||
//To display border
|
||||
void showAll(SDL_Surface *to);
|
||||
//change or set background image
|
||||
void setBackground(std::string filename);
|
||||
void updateShadow();
|
||||
public:
|
||||
enum EOptions
|
||||
{
|
||||
PLAYER_COLORED=1, //background will be player-colored
|
||||
RCLICK_POPUP=2, // window will behave as right-click popup
|
||||
BORDERED=4, // window will have border if current resolution is bigger than size of window
|
||||
SHADOW_DISABLED=8 //this window won't display any shadow
|
||||
};
|
||||
|
||||
/*
|
||||
* options - EOpions enum
|
||||
* imageName - name for background image, can be empty
|
||||
* centerAt - position of window center. Default - center of the screen
|
||||
*/
|
||||
CWindowObject(int options, std::string imageName, Point centerAt);
|
||||
CWindowObject(int options, std::string imageName = "");
|
||||
~CWindowObject();
|
||||
};
|
@ -1,6 +1,11 @@
|
||||
#include "StdInc.h"
|
||||
#include "Geometries.h"
|
||||
#include "../CMT.h"
|
||||
#include <SDL_events.h>
|
||||
|
||||
Point::Point(const SDL_MouseMotionEvent &a)
|
||||
:x(a.x),y(a.y)
|
||||
{}
|
||||
|
||||
Rect Rect::createCentered( int w, int h )
|
||||
{
|
||||
@ -15,4 +20,4 @@ Rect Rect::around(const Rect &r, int width /*= 1*/) /*creates rect around anothe
|
||||
Rect Rect::centerIn(const Rect &r)
|
||||
{
|
||||
return Rect(r.x + (r.w - w) / 2, r.y + (r.h - h) / 2, w, h);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL_video.h>
|
||||
#include <SDL_events.h>
|
||||
#include "../../lib/int3.h"
|
||||
|
||||
/*
|
||||
@ -21,6 +20,7 @@
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
struct SDL_MouseMotionEvent;
|
||||
|
||||
// A point with x/y coordinate, used mostly for graphic rendering
|
||||
struct Point
|
||||
@ -38,9 +38,7 @@ struct Point
|
||||
Point(const int3 &a)
|
||||
:x(a.x),y(a.y)
|
||||
{}
|
||||
Point(const SDL_MouseMotionEvent &a)
|
||||
:x(a.x),y(a.y)
|
||||
{}
|
||||
Point(const SDL_MouseMotionEvent &a);
|
||||
|
||||
template<typename T>
|
||||
Point operator+(const T &b) const
|
||||
@ -265,4 +263,4 @@ struct Rect : public SDL_Rect
|
||||
ret.h = y2 -ret.y;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "SDL_Extensions.h"
|
||||
#include "SDL_Pixels.h"
|
||||
|
||||
#include <SDL_ttf.h>
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CMessage.h"
|
||||
#include "../CDefHandler.h"
|
||||
|
@ -16,10 +16,11 @@
|
||||
#endif
|
||||
|
||||
#include <SDL_video.h>
|
||||
#include <SDL_ttf.h>
|
||||
#include <SDL_events.h>
|
||||
#include "../../lib/int3.h"
|
||||
#include "../Graphics.h"
|
||||
//#include "../Graphics.h"
|
||||
#include "Geometries.h"
|
||||
#include "../../lib/GameConstants.h"
|
||||
|
||||
|
||||
//A macro to force inlining some of our functions. Compiler (at least MSVC) is not so smart here-> without that displaying is MUCH slower
|
||||
@ -141,15 +142,16 @@ typename boost::enable_if_c<boost::is_unsigned<T>::type, T>::type abs(T arg)
|
||||
}
|
||||
|
||||
template<typename IntType>
|
||||
std::string makeNumberShort(IntType number) //the output is a string containing at most 5 characters [4 if positive] (eg. intead 10000 it gives 10k)
|
||||
std::string makeNumberShort(IntType number, IntType maxLength = 3) //the output is a string containing at most 5 characters [4 if positive] (eg. intead 10000 it gives 10k)
|
||||
{
|
||||
if (abs(number) < 1000)
|
||||
IntType max = pow(10, maxLength);
|
||||
if (abs(number) < max)
|
||||
return boost::lexical_cast<std::string>(number);
|
||||
|
||||
std::string symbols = "kMGTPE";
|
||||
std::string symbols = " kMGTPE";
|
||||
auto iter = symbols.begin();
|
||||
|
||||
while (number >= 1000)
|
||||
while (number >= max)
|
||||
{
|
||||
number /= 1000;
|
||||
iter++;
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL_endian.h>
|
||||
|
||||
#include "SDL_Extensions.h"
|
||||
|
||||
/*
|
||||
|
@ -1,30 +1,43 @@
|
||||
#include "StdInc.h"
|
||||
#include "AdventureMapClasses.h"
|
||||
|
||||
#include "../CCallback.h"
|
||||
#include "../lib/JsonNode.h"
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/CModHandler.h"
|
||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CTownHandler.h"
|
||||
#include "../lib/NetPacksBase.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/StringConstants.h"
|
||||
#include "CAdvmapInterface.h"
|
||||
#include "CAnimation.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "CMusicHandler.h"
|
||||
#include "Graphics.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "gui/SDL_Pixels.h"
|
||||
#include <SDL.h>
|
||||
|
||||
#include "MiscWidgets.h"
|
||||
#include "CComponent.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CPreGame.h"
|
||||
#include "../Graphics.h"
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/SDL_Pixels.h"
|
||||
|
||||
#include "../windows/InfoWindows.h"
|
||||
#include "../windows/CAdvmapInterface.h"
|
||||
#include "../windows/GUIClasses.h"
|
||||
|
||||
#include "../battle/CBattleInterfaceClasses.h"
|
||||
#include "../battle/CBattleInterface.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
#include "../../lib/StartInfo.h"
|
||||
#include "../../lib/CGameState.h"
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/CHeroHandler.h"
|
||||
#include "../../lib/CModHandler.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
#include "../../lib/filesystem/Filesystem.h"
|
||||
#include "../../lib/JsonNode.h"
|
||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../../lib/mapping/CMap.h"
|
||||
#include "../../lib/NetPacksBase.h"
|
||||
#include "../../lib/StringConstants.h"
|
||||
|
||||
/*
|
||||
* CAdventureMapClasses.h, part of VCMI engine
|
||||
* CAdventureMapClasses.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@ -93,15 +106,15 @@ CList::CList(int Size, Point position, std::string btnUp, std::string btnDown, s
|
||||
selected(nullptr)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
scrollUp = new CAdventureMapButton(CGI->generaltexth->zelp[helpUp], 0, 0, 0, btnUp);
|
||||
scrollUp = new CButton(Point(0, 0), btnUp, CGI->generaltexth->zelp[helpUp]);
|
||||
list = new CListBox(create, destroy, Point(1,scrollUp->pos.h), Point(0, 32), size, listAmount);
|
||||
|
||||
//assign callback only after list was created
|
||||
scrollUp->callback = std::bind(&CListBox::moveToPrev, list);
|
||||
scrollDown = new CAdventureMapButton(CGI->generaltexth->zelp[helpDown], std::bind(&CListBox::moveToNext, list), 0, scrollUp->pos.h + 32*size, btnDown);
|
||||
scrollUp->addCallback(std::bind(&CListBox::moveToPrev, list));
|
||||
scrollDown = new CButton(Point(0, scrollUp->pos.h + 32*size), btnDown, CGI->generaltexth->zelp[helpDown], std::bind(&CListBox::moveToNext, list));
|
||||
|
||||
scrollDown->callback += std::bind(&CList::update, this);
|
||||
scrollUp->callback += std::bind(&CList::update, this);
|
||||
scrollDown->addCallback(std::bind(&CList::update, this));
|
||||
scrollUp->addCallback(std::bind(&CList::update, this));
|
||||
|
||||
update();
|
||||
}
|
||||
@ -950,3 +963,248 @@ void CInfoBar::showGameStatus()
|
||||
setTimer(3000);
|
||||
redraw();
|
||||
}
|
||||
|
||||
void CInGameConsole::show(SDL_Surface * to)
|
||||
{
|
||||
int number = 0;
|
||||
|
||||
std::vector<std::list< std::pair< std::string, int > >::iterator> toDel;
|
||||
|
||||
boost::unique_lock<boost::mutex> lock(texts_mx);
|
||||
for(auto it = texts.begin(); it != texts.end(); ++it, ++number)
|
||||
{
|
||||
Point leftBottomCorner(0, screen->h);
|
||||
if(LOCPLINT->battleInt)
|
||||
{
|
||||
leftBottomCorner = LOCPLINT->battleInt->pos.bottomLeft();
|
||||
}
|
||||
graphics->fonts[FONT_MEDIUM]->renderTextLeft(to, it->first, Colors::GREEN,
|
||||
Point(leftBottomCorner.x + 50, leftBottomCorner.y - texts.size() * 20 - 80 + number*20));
|
||||
|
||||
if(SDL_GetTicks() - it->second > defaultTimeout)
|
||||
{
|
||||
toDel.push_back(it);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto & elem : toDel)
|
||||
{
|
||||
texts.erase(elem);
|
||||
}
|
||||
}
|
||||
|
||||
void CInGameConsole::print(const std::string &txt)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(texts_mx);
|
||||
int lineLen = conf.go()->ac.outputLineLength;
|
||||
|
||||
if(txt.size() < lineLen)
|
||||
{
|
||||
texts.push_back(std::make_pair(txt, SDL_GetTicks()));
|
||||
if(texts.size() > maxDisplayedTexts)
|
||||
{
|
||||
texts.pop_front();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(lineLen);
|
||||
for(int g=0; g<txt.size() / lineLen + 1; ++g)
|
||||
{
|
||||
std::string part = txt.substr(g * lineLen, lineLen);
|
||||
if(part.size() == 0)
|
||||
break;
|
||||
|
||||
texts.push_back(std::make_pair(part, SDL_GetTicks()));
|
||||
if(texts.size() > maxDisplayedTexts)
|
||||
{
|
||||
texts.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
|
||||
{
|
||||
if(key.type != SDL_KEYDOWN) return;
|
||||
|
||||
if(!captureAllKeys && key.keysym.sym != SDLK_TAB) return; //because user is not entering any text
|
||||
|
||||
switch(key.keysym.sym)
|
||||
{
|
||||
case SDLK_TAB:
|
||||
case SDLK_ESCAPE:
|
||||
{
|
||||
if(captureAllKeys)
|
||||
{
|
||||
captureAllKeys = false;
|
||||
endEnteringText(false);
|
||||
}
|
||||
else if(SDLK_TAB)
|
||||
{
|
||||
captureAllKeys = true;
|
||||
startEnteringText();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDLK_RETURN: //enter key
|
||||
{
|
||||
if(enteredText.size() > 0 && captureAllKeys)
|
||||
{
|
||||
captureAllKeys = false;
|
||||
endEnteringText(true);
|
||||
CCS->soundh->playSound("CHAT");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDLK_BACKSPACE:
|
||||
{
|
||||
if(enteredText.size() > 1)
|
||||
{
|
||||
Unicode::trimRight(enteredText,2);
|
||||
enteredText += '_';
|
||||
refreshEnteredText();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDLK_UP: //up arrow
|
||||
{
|
||||
if(previouslyEntered.size() == 0)
|
||||
break;
|
||||
|
||||
if(prevEntDisp == -1)
|
||||
{
|
||||
prevEntDisp = previouslyEntered.size() - 1;
|
||||
enteredText = previouslyEntered[prevEntDisp] + "_";
|
||||
refreshEnteredText();
|
||||
}
|
||||
else if( prevEntDisp > 0)
|
||||
{
|
||||
--prevEntDisp;
|
||||
enteredText = previouslyEntered[prevEntDisp] + "_";
|
||||
refreshEnteredText();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDLK_DOWN: //down arrow
|
||||
{
|
||||
if(prevEntDisp != -1 && prevEntDisp+1 < previouslyEntered.size())
|
||||
{
|
||||
++prevEntDisp;
|
||||
enteredText = previouslyEntered[prevEntDisp] + "_";
|
||||
refreshEnteredText();
|
||||
}
|
||||
else if(prevEntDisp+1 == previouslyEntered.size()) //useful feature
|
||||
{
|
||||
prevEntDisp = -1;
|
||||
enteredText = "_";
|
||||
refreshEnteredText();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
#ifdef VCMI_SDL1
|
||||
if(enteredText.size() > 0 && enteredText.size() < conf.go()->ac.inputLineLength)
|
||||
{
|
||||
if( key.keysym.unicode < 0x80 && key.keysym.unicode > 0 )
|
||||
{
|
||||
enteredText[enteredText.size()-1] = (char)key.keysym.unicode;
|
||||
enteredText += "_";
|
||||
refreshEnteredText();
|
||||
}
|
||||
}
|
||||
#endif // VCMI_SDL1
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef VCMI_SDL1
|
||||
|
||||
void CInGameConsole::textInputed(const SDL_TextInputEvent & event)
|
||||
{
|
||||
if(!captureAllKeys || enteredText.size() == 0)
|
||||
return;
|
||||
enteredText.resize(enteredText.size()-1);
|
||||
|
||||
enteredText += event.text;
|
||||
enteredText += "_";
|
||||
|
||||
refreshEnteredText();
|
||||
}
|
||||
|
||||
void CInGameConsole::textEdited(const SDL_TextEditingEvent & event)
|
||||
{
|
||||
//do nothing here
|
||||
}
|
||||
|
||||
#endif // VCMI_SDL1
|
||||
|
||||
void CInGameConsole::startEnteringText()
|
||||
{
|
||||
CSDL_Ext::startTextInput(&pos);
|
||||
|
||||
enteredText = "_";
|
||||
if(GH.topInt() == adventureInt)
|
||||
{
|
||||
GH.statusbar->alignment = TOPLEFT;
|
||||
GH.statusbar->setText(enteredText);
|
||||
|
||||
//Prevent changes to the text from mouse interaction with the adventure map
|
||||
GH.statusbar->lock(true);
|
||||
}
|
||||
else if(LOCPLINT->battleInt)
|
||||
{
|
||||
LOCPLINT->battleInt->console->ingcAlter = enteredText;
|
||||
}
|
||||
}
|
||||
|
||||
void CInGameConsole::endEnteringText(bool printEnteredText)
|
||||
{
|
||||
CSDL_Ext::stopTextInput();
|
||||
|
||||
prevEntDisp = -1;
|
||||
if(printEnteredText)
|
||||
{
|
||||
std::string txt = enteredText.substr(0, enteredText.size()-1);
|
||||
LOCPLINT->cb->sendMessage(txt);
|
||||
previouslyEntered.push_back(txt);
|
||||
//print(txt);
|
||||
}
|
||||
enteredText = "";
|
||||
if(GH.topInt() == adventureInt)
|
||||
{
|
||||
GH.statusbar->alignment = CENTER;
|
||||
GH.statusbar->lock(false);
|
||||
GH.statusbar->clear();
|
||||
}
|
||||
else if(LOCPLINT->battleInt)
|
||||
{
|
||||
LOCPLINT->battleInt->console->ingcAlter = "";
|
||||
}
|
||||
}
|
||||
|
||||
void CInGameConsole::refreshEnteredText()
|
||||
{
|
||||
if(GH.topInt() == adventureInt)
|
||||
{
|
||||
GH.statusbar->lock(false);
|
||||
GH.statusbar->clear();
|
||||
GH.statusbar->setText(enteredText);
|
||||
GH.statusbar->lock(true);
|
||||
}
|
||||
else if(LOCPLINT->battleInt)
|
||||
{
|
||||
LOCPLINT->battleInt->console->ingcAlter = enteredText;
|
||||
}
|
||||
}
|
||||
|
||||
CInGameConsole::CInGameConsole() : prevEntDisp(-1), defaultTimeout(10000), maxDisplayedTexts(10)
|
||||
{
|
||||
#ifdef VCMI_SDL1
|
||||
addUsedEvents(KEYBOARD);
|
||||
#else
|
||||
addUsedEvents(KEYBOARD | TEXTINPUT);
|
||||
#endif
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "gui/CIntObject.h"
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
#include "ObjectLists.h"
|
||||
#include "../../lib/FunctionList.h"
|
||||
|
||||
class CArmedInstance;
|
||||
class CShowableAnim;
|
||||
@ -9,6 +9,7 @@ class CGGarrison;
|
||||
class CGObjectInstance;
|
||||
class CGHeroInstance;
|
||||
class CGTownInstance;
|
||||
class CButton;
|
||||
struct Component;
|
||||
struct InfoAboutArmy;
|
||||
struct InfoAboutHero;
|
||||
@ -82,8 +83,8 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
CAdventureMapButton * scrollUp;
|
||||
CAdventureMapButton * scrollDown;
|
||||
CButton * scrollUp;
|
||||
CButton * scrollDown;
|
||||
|
||||
/// functions that will be called when selection changes
|
||||
CFunctionList<void()> onSelect;
|
||||
@ -313,3 +314,30 @@ public:
|
||||
/// for 3 seconds shows amount of town halls and players status
|
||||
void showGameStatus();
|
||||
};
|
||||
|
||||
class CInGameConsole : public CIntObject
|
||||
{
|
||||
private:
|
||||
std::list< std::pair< std::string, int > > texts; //list<text to show, time of add>
|
||||
boost::mutex texts_mx; // protects texts
|
||||
std::vector< std::string > previouslyEntered; //previously entered texts, for up/down arrows to work
|
||||
int prevEntDisp; //displayed entry from previouslyEntered - if none it's -1
|
||||
int defaultTimeout; //timeout for new texts (in ms)
|
||||
int maxDisplayedTexts; //hiw many texts can be displayed simultaneously
|
||||
public:
|
||||
std::string enteredText;
|
||||
void show(SDL_Surface * to);
|
||||
void print(const std::string &txt);
|
||||
void keyPressed (const SDL_KeyboardEvent & key); //call-in
|
||||
|
||||
#ifndef VCMI_SDL1
|
||||
void textInputed(const SDL_TextInputEvent & event) override;
|
||||
void textEdited(const SDL_TextEditingEvent & event) override;
|
||||
#endif // VCMI_SDL1
|
||||
|
||||
void startEnteringText();
|
||||
void endEnteringText(bool printEnteredText);
|
||||
void refreshEnteredText();
|
||||
|
||||
CInGameConsole(); //c-tor
|
||||
};
|
742
client/widgets/Buttons.cpp
Normal file
@ -0,0 +1,742 @@
|
||||
#include "StdInc.h"
|
||||
#include "Buttons.h"
|
||||
|
||||
#include "Images.h"
|
||||
#include "TextControls.h"
|
||||
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../battle/CBattleInterface.h"
|
||||
#include "../battle/CBattleInterfaceClasses.h"
|
||||
#include "../gui/CAnimation.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../windows/InfoWindows.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
|
||||
/*
|
||||
* Buttons.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
ClickableArea::ClickableArea(CIntObject * object, CFunctionList<void()> callback):
|
||||
callback(callback),
|
||||
area(nullptr)
|
||||
{
|
||||
if (object)
|
||||
pos = object->pos;
|
||||
setArea(object);
|
||||
}
|
||||
|
||||
void ClickableArea::addCallback(std::function<void()> callback)
|
||||
{
|
||||
this->callback += callback;
|
||||
}
|
||||
|
||||
void ClickableArea::setArea(CIntObject * object)
|
||||
{
|
||||
delete area;
|
||||
addChild(area);
|
||||
pos.w = object->pos.w;
|
||||
pos.h = object->pos.h;
|
||||
}
|
||||
|
||||
void ClickableArea::onClick()
|
||||
{
|
||||
callback();
|
||||
}
|
||||
|
||||
void ClickableArea::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if (down)
|
||||
onClick();
|
||||
}
|
||||
|
||||
void CButton::update()
|
||||
{
|
||||
if (overlay)
|
||||
{
|
||||
if (state == PRESSED)
|
||||
overlay->moveTo(overlay->pos.centerIn(pos).topLeft() + Point(1,1));
|
||||
else
|
||||
overlay->moveTo(overlay->pos.centerIn(pos).topLeft());
|
||||
}
|
||||
|
||||
int newPos = stateToIndex[int(state)];
|
||||
if (newPos < 0)
|
||||
newPos = 0;
|
||||
|
||||
if (state == HIGHLIGHTED && image->size() < 4)
|
||||
newPos = image->size()-1;
|
||||
image->setFrame(newPos);
|
||||
|
||||
if (active)
|
||||
redraw();
|
||||
}
|
||||
|
||||
void CButton::addCallback(std::function<void()> callback)
|
||||
{
|
||||
this->callback += callback;
|
||||
}
|
||||
|
||||
void CButton::addTextOverlay( const std::string &Text, EFonts font, SDL_Color color)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
addOverlay(new CLabel(pos.w/2, pos.h/2, font, CENTER, color, Text));
|
||||
update();
|
||||
}
|
||||
|
||||
void CButton::addOverlay(CIntObject *newOverlay)
|
||||
{
|
||||
delete overlay;
|
||||
overlay = newOverlay;
|
||||
addChild(newOverlay);
|
||||
overlay->moveTo(overlay->pos.centerIn(pos).topLeft());
|
||||
update();
|
||||
}
|
||||
|
||||
void CButton::addImage(std::string filename)
|
||||
{
|
||||
imageNames.push_back(filename);
|
||||
}
|
||||
|
||||
void CButton::addHoverText(ButtonState state, std::string text)
|
||||
{
|
||||
hoverTexts[state] = text;
|
||||
}
|
||||
|
||||
void CButton::setImageOrder(int state1, int state2, int state3, int state4)
|
||||
{
|
||||
stateToIndex[0] = state1;
|
||||
stateToIndex[1] = state2;
|
||||
stateToIndex[2] = state3;
|
||||
stateToIndex[3] = state4;
|
||||
update();
|
||||
}
|
||||
|
||||
void CButton::setState(ButtonState newState)
|
||||
{
|
||||
if (state == newState)
|
||||
return;
|
||||
state = newState;
|
||||
update();
|
||||
}
|
||||
|
||||
CButton::ButtonState CButton::getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
bool CButton::isBlocked()
|
||||
{
|
||||
return state == BLOCKED;
|
||||
}
|
||||
|
||||
bool CButton::isHighlighted()
|
||||
{
|
||||
return state == HIGHLIGHTED;
|
||||
}
|
||||
|
||||
void CButton::block(bool on)
|
||||
{
|
||||
setState(on?BLOCKED:NORMAL);
|
||||
}
|
||||
|
||||
void CButton::onButtonClicked()
|
||||
{
|
||||
// debug logging to figure out pressed button (and as result - player actions) in case of crash
|
||||
logAnim->traceStream() << "Button clicked at " << pos.x << "x" << pos.y << ", " << callback.funcs.size() << " functions";
|
||||
CIntObject * parent = this->parent;
|
||||
std::string prefix = "Parent is";
|
||||
while (parent)
|
||||
{
|
||||
logAnim->traceStream() << prefix << typeid(*parent).name() << " at " << parent->pos.x << "x" << parent->pos.y;
|
||||
parent = parent->parent;
|
||||
prefix = '\t' + prefix;
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
void CButton::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if(isBlocked())
|
||||
return;
|
||||
|
||||
if (down)
|
||||
{
|
||||
if (!soundDisabled)
|
||||
CCS->soundh->playSound(soundBase::button);
|
||||
setState(PRESSED);
|
||||
}
|
||||
else if(hoverable && hovered)
|
||||
setState(HIGHLIGHTED);
|
||||
else
|
||||
setState(NORMAL);
|
||||
|
||||
if (actOnDown && down)
|
||||
{
|
||||
onButtonClicked();
|
||||
}
|
||||
else if (!actOnDown && previousState && (down==false))
|
||||
{
|
||||
onButtonClicked();
|
||||
}
|
||||
}
|
||||
|
||||
void CButton::clickRight(tribool down, bool previousState)
|
||||
{
|
||||
if(down && helpBox.size()) //there is no point to show window with nothing inside...
|
||||
CRClickPopup::createAndPush(helpBox);
|
||||
}
|
||||
|
||||
void CButton::hover (bool on)
|
||||
{
|
||||
if(hoverable && !isBlocked())
|
||||
{
|
||||
if(on)
|
||||
setState(HIGHLIGHTED);
|
||||
else
|
||||
setState(NORMAL);
|
||||
}
|
||||
|
||||
/*if(pressedL && on) // WTF is this? When this is used?
|
||||
setState(PRESSED);*/
|
||||
|
||||
std::string name = hoverTexts[getState()].empty()
|
||||
? hoverTexts[getState()]
|
||||
: hoverTexts[0];
|
||||
|
||||
if(!name.empty() && !isBlocked()) //if there is no name, there is nohing to display also
|
||||
{
|
||||
if (LOCPLINT && LOCPLINT->battleInt) //for battle buttons
|
||||
{
|
||||
if(on && LOCPLINT->battleInt->console->alterTxt == "")
|
||||
{
|
||||
LOCPLINT->battleInt->console->alterTxt = name;
|
||||
LOCPLINT->battleInt->console->whoSetAlter = 1;
|
||||
}
|
||||
else if (LOCPLINT->battleInt->console->alterTxt == name)
|
||||
{
|
||||
LOCPLINT->battleInt->console->alterTxt = "";
|
||||
LOCPLINT->battleInt->console->whoSetAlter = 0;
|
||||
}
|
||||
}
|
||||
else if(GH.statusbar) //for other buttons
|
||||
{
|
||||
if (on)
|
||||
GH.statusbar->setText(name);
|
||||
else if ( GH.statusbar->getText()==(name) )
|
||||
GH.statusbar->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CButton::CButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help, CFunctionList<void()> Callback, int key, bool playerColoredButton):
|
||||
CKeyShortcut(key),
|
||||
callback(Callback)
|
||||
{
|
||||
addUsedEvents(LCLICK | RCLICK | HOVER | KEYBOARD);
|
||||
|
||||
stateToIndex[0] = 0;
|
||||
stateToIndex[1] = 1;
|
||||
stateToIndex[2] = 2;
|
||||
stateToIndex[3] = 3;
|
||||
|
||||
state=NORMAL;
|
||||
image = nullptr;
|
||||
overlay = nullptr;
|
||||
|
||||
currentImage = -1;
|
||||
hoverable = actOnDown = soundDisabled = false;
|
||||
hoverTexts[0] = help.first;
|
||||
helpBox=help.second;
|
||||
|
||||
pos.x += position.x;
|
||||
pos.y += position.y;
|
||||
|
||||
if (!defName.empty())
|
||||
{
|
||||
imageNames.push_back(defName);
|
||||
setIndex(0, playerColoredButton);
|
||||
}
|
||||
}
|
||||
|
||||
void CButton::setIndex(size_t index, bool playerColoredButton)
|
||||
{
|
||||
if (index == currentImage || index>=imageNames.size())
|
||||
return;
|
||||
currentImage = index;
|
||||
setImage(new CAnimation(imageNames[index]), playerColoredButton);
|
||||
}
|
||||
|
||||
void CButton::setImage(CAnimation* anim, bool playerColoredButton, int animFlags)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
image = new CAnimImage(anim, getState(), 0, 0, 0, animFlags);
|
||||
if (playerColoredButton)
|
||||
image->playerColored(LOCPLINT->playerID);
|
||||
pos = image->pos;
|
||||
}
|
||||
|
||||
void CButton::setPlayerColor(PlayerColor player)
|
||||
{
|
||||
if (image)
|
||||
image->playerColored(player);
|
||||
}
|
||||
|
||||
void CButton::showAll(SDL_Surface * to)
|
||||
{
|
||||
CIntObject::showAll(to);
|
||||
|
||||
#ifdef VCMI_SDL1
|
||||
if (borderColor && borderColor->unused == 0)
|
||||
CSDL_Ext::drawBorder(to, pos.x-1, pos.y-1, pos.w+2, pos.h+2, int3(borderColor->r, borderColor->g, borderColor->b));
|
||||
#else
|
||||
if (borderColor && borderColor->a == 0)
|
||||
CSDL_Ext::drawBorder(to, pos.x-1, pos.y-1, pos.w+2, pos.h+2, int3(borderColor->r, borderColor->g, borderColor->b));
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> CButton::tooltip()
|
||||
{
|
||||
return std::pair<std::string, std::string>();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> CButton::tooltip(const JsonNode & localizedTexts)
|
||||
{
|
||||
return std::make_pair(localizedTexts["label"].String(), localizedTexts["help"].String());
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> CButton::tooltip(const std::string & hover, const std::string & help)
|
||||
{
|
||||
return std::make_pair(hover, help);
|
||||
}
|
||||
|
||||
CToggleBase::CToggleBase(CFunctionList<void (bool)> callback):
|
||||
callback(callback),
|
||||
selected(false),
|
||||
allowDeselection(true)
|
||||
{
|
||||
}
|
||||
|
||||
CToggleBase::~CToggleBase()
|
||||
{
|
||||
}
|
||||
|
||||
void CToggleBase::doSelect(bool on)
|
||||
{
|
||||
// for overrides
|
||||
}
|
||||
|
||||
void CToggleBase::setSelected(bool on)
|
||||
{
|
||||
bool changed = (on != selected);
|
||||
selected = on;
|
||||
doSelect(on);
|
||||
if (changed)
|
||||
callback(on);
|
||||
}
|
||||
|
||||
bool CToggleBase::canActivate()
|
||||
{
|
||||
if (selected && !allowDeselection)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CToggleBase::addCallback(std::function<void(bool)> function)
|
||||
{
|
||||
callback.add(function);
|
||||
}
|
||||
|
||||
CToggleButton::CToggleButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
|
||||
CFunctionList<void(bool)> callback, int key, bool playerColoredButton):
|
||||
CButton(position, defName, help, 0, key, playerColoredButton),
|
||||
CToggleBase(callback)
|
||||
{
|
||||
allowDeselection = true;
|
||||
}
|
||||
|
||||
void CToggleButton::doSelect(bool on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
setState(HIGHLIGHTED);
|
||||
}
|
||||
else
|
||||
{
|
||||
setState(NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void CToggleButton::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
// force refresh
|
||||
hover(false);
|
||||
hover(true);
|
||||
|
||||
if(isBlocked())
|
||||
return;
|
||||
|
||||
if (down && canActivate())
|
||||
{
|
||||
CCS->soundh->playSound(soundBase::button);
|
||||
setState(PRESSED);
|
||||
}
|
||||
|
||||
if(previousState)//mouse up
|
||||
{
|
||||
if(down == false && getState() == PRESSED && canActivate())
|
||||
{
|
||||
onButtonClicked();
|
||||
setSelected(!selected);
|
||||
}
|
||||
else
|
||||
doSelect(selected); // restore
|
||||
}
|
||||
}
|
||||
|
||||
void CToggleGroup::addCallback(std::function<void(int)> callback)
|
||||
{
|
||||
onChange += callback;
|
||||
}
|
||||
|
||||
void CToggleGroup::addToggle(int identifier, CToggleBase* bt)
|
||||
{
|
||||
if (auto intObj = dynamic_cast<CIntObject*>(bt)) // hack-ish workagound to avoid diamond problem with inheritance
|
||||
{
|
||||
if (intObj->parent)
|
||||
intObj->parent->removeChild(intObj);
|
||||
addChild(intObj);
|
||||
}
|
||||
|
||||
bt->addCallback([=] (bool on) { if (on) selectionChanged(identifier);});
|
||||
bt->allowDeselection = false;
|
||||
|
||||
assert(buttons[identifier] == nullptr);
|
||||
buttons[identifier] = bt;
|
||||
}
|
||||
|
||||
CToggleGroup::CToggleGroup(const CFunctionList<void(int)> &OnChange, bool musicLikeButtons)
|
||||
: onChange(OnChange), musicLike(musicLikeButtons)
|
||||
{}
|
||||
|
||||
void CToggleGroup::setSelected(int id)
|
||||
{
|
||||
selectionChanged(id);
|
||||
}
|
||||
|
||||
void CToggleGroup::selectionChanged(int to)
|
||||
{
|
||||
if (to == selectedID)
|
||||
return;
|
||||
|
||||
int oldSelection = selectedID;
|
||||
selectedID = to;
|
||||
|
||||
if (buttons.count(oldSelection))
|
||||
buttons[oldSelection]->setSelected(false);
|
||||
|
||||
if (buttons.count(to))
|
||||
buttons[to]->setSelected(true);
|
||||
|
||||
onChange(to);
|
||||
if (parent)
|
||||
parent->redraw();
|
||||
}
|
||||
|
||||
void CToggleGroup::show(SDL_Surface * to)
|
||||
{
|
||||
if (musicLike)
|
||||
{
|
||||
if (auto intObj = dynamic_cast<CIntObject*>(buttons[selectedID])) // hack-ish workagound to avoid diamond problem with inheritance
|
||||
intObj->show(to);
|
||||
}
|
||||
else
|
||||
CIntObject::show(to);
|
||||
}
|
||||
|
||||
void CToggleGroup::showAll(SDL_Surface * to)
|
||||
{
|
||||
if (musicLike)
|
||||
{
|
||||
if (auto intObj = dynamic_cast<CIntObject*>(buttons[selectedID])) // hack-ish workagound to avoid diamond problem with inheritance
|
||||
intObj->showAll(to);
|
||||
}
|
||||
else
|
||||
CIntObject::showAll(to);
|
||||
}
|
||||
|
||||
void CSlider::sliderClicked()
|
||||
{
|
||||
if(!(active & MOVE))
|
||||
addUsedEvents(MOVE);
|
||||
}
|
||||
|
||||
void CSlider::mouseMoved (const SDL_MouseMotionEvent & sEvent)
|
||||
{
|
||||
double v = 0;
|
||||
if(horizontal)
|
||||
{
|
||||
if( std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2+40 || std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2 )
|
||||
return;
|
||||
v = sEvent.x - pos.x - 24;
|
||||
v *= positions;
|
||||
v /= (pos.w - 48);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2+40 || std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2 )
|
||||
return;
|
||||
v = sEvent.y - pos.y - 24;
|
||||
v *= positions;
|
||||
v /= (pos.h - 48);
|
||||
}
|
||||
v += 0.5;
|
||||
if(v!=value)
|
||||
{
|
||||
moveTo(v);
|
||||
}
|
||||
}
|
||||
|
||||
void CSlider::setScrollStep(int to)
|
||||
{
|
||||
scrollStep = to;
|
||||
}
|
||||
|
||||
int CSlider::getAmount()
|
||||
{
|
||||
return amount;
|
||||
}
|
||||
|
||||
int CSlider::getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
void CSlider::moveLeft()
|
||||
{
|
||||
moveTo(value-1);
|
||||
}
|
||||
|
||||
void CSlider::moveRight()
|
||||
{
|
||||
moveTo(value+1);
|
||||
}
|
||||
|
||||
void CSlider::moveBy(int amount)
|
||||
{
|
||||
moveTo(value + amount);
|
||||
}
|
||||
|
||||
void CSlider::updateSliderPos()
|
||||
{
|
||||
if(horizontal)
|
||||
{
|
||||
if(positions)
|
||||
{
|
||||
double part = static_cast<double>(value) / positions;
|
||||
part*=(pos.w-48);
|
||||
int newPos = part + pos.x + 16 - slider->pos.x;
|
||||
slider->moveBy(Point(newPos, 0));
|
||||
}
|
||||
else
|
||||
slider->moveTo(Point(pos.x+16, pos.y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(positions)
|
||||
{
|
||||
double part = static_cast<double>(value) / positions;
|
||||
part*=(pos.h-48);
|
||||
int newPos = part + pos.y + 16 - slider->pos.y;
|
||||
slider->moveBy(Point(0, newPos));
|
||||
}
|
||||
else
|
||||
slider->moveTo(Point(pos.x, pos.y+16));
|
||||
}
|
||||
}
|
||||
|
||||
void CSlider::moveTo(int to)
|
||||
{
|
||||
vstd::amax(to, 0);
|
||||
vstd::amin(to, positions);
|
||||
|
||||
//same, old position?
|
||||
if(value == to)
|
||||
return;
|
||||
value = to;
|
||||
|
||||
updateSliderPos();
|
||||
|
||||
moved(to);
|
||||
}
|
||||
|
||||
void CSlider::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if(down && !slider->isBlocked())
|
||||
{
|
||||
double pw = 0;
|
||||
double rw = 0;
|
||||
if(horizontal)
|
||||
{
|
||||
pw = GH.current->motion.x-pos.x-25;
|
||||
rw = pw / static_cast<double>(pos.w - 48);
|
||||
}
|
||||
else
|
||||
{
|
||||
pw = GH.current->motion.y-pos.y-24;
|
||||
rw = pw / (pos.h-48);
|
||||
}
|
||||
if(pw < -8 || pw > (horizontal ? pos.w : pos.h) - 40)
|
||||
return;
|
||||
// if (rw>1) return;
|
||||
// if (rw<0) return;
|
||||
slider->clickLeft(true, slider->pressedL);
|
||||
moveTo(rw * positions + 0.5);
|
||||
return;
|
||||
}
|
||||
if(active & MOVE)
|
||||
removeUsedEvents(MOVE);
|
||||
}
|
||||
|
||||
CSlider::~CSlider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CSlider::CSlider(Point position, int totalw, std::function<void(int)> Moved, int Capacity, int Amount, int Value, bool Horizontal, CSlider::EStyle style):
|
||||
capacity(Capacity),
|
||||
horizontal(Horizontal),
|
||||
amount(Amount),
|
||||
value(Value),
|
||||
scrollStep(1),
|
||||
moved(Moved)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
setAmount(amount);
|
||||
vstd::amax(value, 0);
|
||||
vstd::amin(value, positions);
|
||||
|
||||
addUsedEvents(LCLICK | KEYBOARD | WHEEL);
|
||||
strongInterest = true;
|
||||
|
||||
pos.x += position.x;
|
||||
pos.y += position.y;
|
||||
|
||||
if(style == BROWN)
|
||||
{
|
||||
std::string name = horizontal?"IGPCRDIV.DEF":"OVBUTN2.DEF";
|
||||
//NOTE: this images do not have "blocked" frames. They should be implemented somehow (e.g. palette transform or something...)
|
||||
|
||||
left = new CButton(Point(), name, CButton::tooltip());
|
||||
right = new CButton(Point(), name, CButton::tooltip());
|
||||
slider = new CButton(Point(), name, CButton::tooltip());
|
||||
|
||||
left->setImageOrder(0, 1, 1, 1);
|
||||
right->setImageOrder(2, 3, 3, 3);
|
||||
slider->setImageOrder(4, 4, 4, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
left = new CButton(Point(), horizontal ? "SCNRBLF.DEF" : "SCNRBUP.DEF", CButton::tooltip());
|
||||
right = new CButton(Point(), horizontal ? "SCNRBRT.DEF" : "SCNRBDN.DEF", CButton::tooltip());
|
||||
slider = new CButton(Point(), "SCNRBSL.DEF", CButton::tooltip());
|
||||
}
|
||||
slider->actOnDown = true;
|
||||
slider->soundDisabled = true;
|
||||
left->soundDisabled = true;
|
||||
right->soundDisabled = true;
|
||||
|
||||
if (horizontal)
|
||||
right->moveBy(Point(totalw - right->pos.w, 0));
|
||||
else
|
||||
right->moveBy(Point(0, totalw - right->pos.h));
|
||||
|
||||
left->addCallback(std::bind(&CSlider::moveLeft,this));
|
||||
right->addCallback(std::bind(&CSlider::moveRight,this));
|
||||
slider->addCallback(std::bind(&CSlider::sliderClicked,this));
|
||||
|
||||
if(horizontal)
|
||||
{
|
||||
pos.h = slider->pos.h;
|
||||
pos.w = totalw;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.w = slider->pos.w;
|
||||
pos.h = totalw;
|
||||
}
|
||||
|
||||
updateSliderPos();
|
||||
}
|
||||
|
||||
void CSlider::block( bool on )
|
||||
{
|
||||
left->block(on);
|
||||
right->block(on);
|
||||
slider->block(on);
|
||||
}
|
||||
|
||||
void CSlider::setAmount( int to )
|
||||
{
|
||||
amount = to;
|
||||
positions = to - capacity;
|
||||
vstd::amax(positions, 0);
|
||||
}
|
||||
|
||||
void CSlider::showAll(SDL_Surface * to)
|
||||
{
|
||||
CSDL_Ext::fillRectBlack(to, &pos);
|
||||
CIntObject::showAll(to);
|
||||
}
|
||||
|
||||
void CSlider::wheelScrolled(bool down, bool in)
|
||||
{
|
||||
moveTo(value + 3 * (down ? +scrollStep : -scrollStep));
|
||||
}
|
||||
|
||||
void CSlider::keyPressed(const SDL_KeyboardEvent & key)
|
||||
{
|
||||
if(key.state != SDL_PRESSED) return;
|
||||
|
||||
int moveDest = 0;
|
||||
switch(key.keysym.sym)
|
||||
{
|
||||
case SDLK_UP:
|
||||
case SDLK_LEFT:
|
||||
moveDest = value - scrollStep;
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
case SDLK_RIGHT:
|
||||
moveDest = value + scrollStep;
|
||||
break;
|
||||
case SDLK_PAGEUP:
|
||||
moveDest = value - capacity + scrollStep;
|
||||
break;
|
||||
case SDLK_PAGEDOWN:
|
||||
moveDest = value + capacity - scrollStep;
|
||||
break;
|
||||
case SDLK_HOME:
|
||||
moveDest = 0;
|
||||
break;
|
||||
case SDLK_END:
|
||||
moveDest = amount - capacity;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
moveTo(moveDest);
|
||||
}
|
||||
|
||||
void CSlider::moveToMax()
|
||||
{
|
||||
moveTo(amount);
|
||||
}
|
261
client/widgets/Buttons.h
Normal file
@ -0,0 +1,261 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gui/CIntObject.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
|
||||
#include "../../lib/FunctionList.h"
|
||||
|
||||
struct SDL_Surface;
|
||||
struct Rect;
|
||||
class CAnimImage;
|
||||
class CLabel;
|
||||
class CAnimation;
|
||||
class CDefHandler;
|
||||
|
||||
namespace config
|
||||
{
|
||||
struct ButtonInfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Buttons.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
class ClickableArea : public CIntObject //TODO: derive from LRCLickableArea? Or somehow use its right-click/hover data?
|
||||
{
|
||||
CFunctionList<void()> callback;
|
||||
|
||||
CIntObject * area;
|
||||
|
||||
protected:
|
||||
void onClick();
|
||||
|
||||
public:
|
||||
ClickableArea(CIntObject * object, CFunctionList<void()> callback);
|
||||
|
||||
void addCallback(std::function<void()> callback);
|
||||
void setArea(CIntObject * object);
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
};
|
||||
|
||||
/// Typical Heroes 3 button which can be inactive or active and can
|
||||
/// hold further information if you right-click it
|
||||
class CButton : public CKeyShortcut
|
||||
{
|
||||
CFunctionList<void()> callback;
|
||||
|
||||
public:
|
||||
enum ButtonState
|
||||
{
|
||||
NORMAL=0,
|
||||
PRESSED=1,
|
||||
BLOCKED=2,
|
||||
HIGHLIGHTED=3
|
||||
};
|
||||
private:
|
||||
std::vector<std::string> imageNames;//store list of images that can be used by this button
|
||||
size_t currentImage;
|
||||
|
||||
ButtonState state;//current state of button from enum
|
||||
|
||||
std::array<int, 4> stateToIndex; // mapping of button state to index of frame in animation
|
||||
std::array<std::string, 4> hoverTexts; //texts for statusbar, if empty - first entry will be used
|
||||
std::string helpBox; //for right-click help
|
||||
|
||||
CAnimImage * image; //image for this button
|
||||
CIntObject * overlay;//object-overlay, can be null
|
||||
|
||||
protected:
|
||||
void onButtonClicked(); // calls callback
|
||||
void update();//to refresh button after image or text change
|
||||
|
||||
// internal method to change state. Public change can be done only via block()
|
||||
void setState(ButtonState newState);
|
||||
ButtonState getState();
|
||||
|
||||
public:
|
||||
bool actOnDown,//runs when mouse is pressed down over it, not when up
|
||||
hoverable,//if true, button will be highlighted when hovered (e.g. main menu)
|
||||
soundDisabled;
|
||||
|
||||
// if set, button will have 1-px border around it with this color
|
||||
boost::optional<SDL_Color> borderColor;
|
||||
|
||||
/// adds one more callback to on-click actions
|
||||
void addCallback(std::function<void()> callback);
|
||||
|
||||
/// adds overlay on top of button image. Only one overlay can be active at once
|
||||
void addOverlay(CIntObject * newOverlay);
|
||||
void addTextOverlay(const std::string &Text, EFonts font, SDL_Color color = Colors::WHITE);
|
||||
|
||||
void addImage(std::string filename);
|
||||
void addHoverText(ButtonState state, std::string text);
|
||||
|
||||
void setImageOrder(int state1, int state2, int state3, int state4);
|
||||
void block(bool on);
|
||||
|
||||
/// State modifiers
|
||||
bool isBlocked();
|
||||
bool isHighlighted();
|
||||
|
||||
/// Constructor
|
||||
CButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
|
||||
CFunctionList<void()> Callback = 0, int key=0, bool playerColoredButton = false );
|
||||
|
||||
/// Appearance modifiers
|
||||
void setIndex(size_t index, bool playerColoredButton=false);
|
||||
void setImage(CAnimation* anim, bool playerColoredButton=false, int animFlags=0);
|
||||
void setPlayerColor(PlayerColor player);
|
||||
|
||||
/// CIntObject overrides
|
||||
void clickRight(tribool down, bool previousState) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void hover (bool on) override;
|
||||
void showAll(SDL_Surface * to) override;
|
||||
|
||||
/// generates tooltip that can be passed into constructor
|
||||
static std::pair<std::string, std::string> tooltip();
|
||||
static std::pair<std::string, std::string> tooltip(const JsonNode & localizedTexts);
|
||||
static std::pair<std::string, std::string> tooltip(const std::string & hover, const std::string & help = "");
|
||||
};
|
||||
|
||||
class CToggleBase
|
||||
{
|
||||
CFunctionList<void(bool)> callback;
|
||||
protected:
|
||||
|
||||
bool selected;
|
||||
|
||||
// internal method for overrides
|
||||
virtual void doSelect(bool on);
|
||||
|
||||
// returns true if toggle can change its state
|
||||
bool canActivate();
|
||||
|
||||
public:
|
||||
/// if set to false - button can not be deselected normally
|
||||
bool allowDeselection;
|
||||
|
||||
CToggleBase(CFunctionList<void(bool)> callback);
|
||||
virtual ~CToggleBase();
|
||||
|
||||
/// Changes selection to "on", and calls callback
|
||||
void setSelected(bool on);
|
||||
|
||||
void addCallback(std::function<void(bool)> callback);
|
||||
};
|
||||
|
||||
class ClickableToggle : public ClickableArea, public CToggleBase
|
||||
{
|
||||
public:
|
||||
ClickableToggle(CIntObject * object, CFunctionList<void()> selectFun, CFunctionList<void()> deselectFun);
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
};
|
||||
|
||||
/// A button which can be selected/deselected, checkbox
|
||||
class CToggleButton : public CButton, public CToggleBase
|
||||
{
|
||||
void doSelect(bool on) override;
|
||||
public:
|
||||
CToggleButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
|
||||
CFunctionList<void(bool)> Callback = 0, int key=0, bool playerColoredButton = false );
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
|
||||
// bring overrides into scope
|
||||
//using CButton::addCallback;
|
||||
using CToggleBase::addCallback;
|
||||
};
|
||||
|
||||
class CToggleGroup : public CIntObject
|
||||
{
|
||||
CFunctionList<void(int)> onChange; //called when changing selected button with new button's id
|
||||
|
||||
int selectedID;
|
||||
bool musicLike; //determines the behaviour of this group
|
||||
void selectionChanged(int to);
|
||||
public:
|
||||
std::map<int, CToggleBase*> buttons;
|
||||
|
||||
CToggleGroup(const CFunctionList<void(int)> & OnChange, bool musicLikeButtons = false);
|
||||
|
||||
void addCallback(std::function<void(int)> callback);
|
||||
|
||||
/// add one toggle/button into group
|
||||
void addToggle(int index, CToggleBase * button);
|
||||
/// Changes selection to specific value. Will select toggle with this ID, if present
|
||||
void setSelected(int id);
|
||||
|
||||
void show(SDL_Surface * to);
|
||||
void showAll(SDL_Surface * to);
|
||||
};
|
||||
|
||||
/// A typical slider which can be orientated horizontally/vertically.
|
||||
class CSlider : public CIntObject
|
||||
{
|
||||
CButton *left, *right, *slider; //if vertical then left=up
|
||||
int capacity;//how many elements can be active at same time (e.g. hero list = 5)
|
||||
int positions; //number of highest position (0 if there is only one)
|
||||
bool horizontal;
|
||||
bool wheelScrolling;
|
||||
bool keyScrolling;
|
||||
|
||||
int amount; //total amount of elements (e.g. hero list = 0-8)
|
||||
int value; //first active element
|
||||
int scrollStep; // how many elements will be scrolled via one click, default = 1
|
||||
CFunctionList<void(int)> moved;
|
||||
|
||||
void updateSliderPos();
|
||||
void sliderClicked();
|
||||
|
||||
public:
|
||||
enum EStyle {
|
||||
BROWN,
|
||||
BLUE
|
||||
};
|
||||
|
||||
void block(bool on);
|
||||
|
||||
/// Controls how many items wil be scrolled via one click
|
||||
void setScrollStep(int to);
|
||||
|
||||
/// Value modifiers
|
||||
void moveLeft();
|
||||
void moveRight();
|
||||
void moveTo(int value);
|
||||
void moveBy(int amount);
|
||||
void moveToMax();
|
||||
|
||||
/// Amount modifier
|
||||
void setAmount(int to);
|
||||
|
||||
/// Accessors
|
||||
int getAmount();
|
||||
int getValue();
|
||||
|
||||
void addCallback(std::function<void(int)> callback);
|
||||
|
||||
void keyPressed(const SDL_KeyboardEvent & key);
|
||||
void wheelScrolled(bool down, bool in);
|
||||
void clickLeft(tribool down, bool previousState);
|
||||
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
|
||||
void showAll(SDL_Surface * to);
|
||||
|
||||
/**
|
||||
* @param position, coordinates of slider
|
||||
* @param length, length of slider ribbon, including left/right buttons
|
||||
* @param Moved, function that will be called whenever slider moves
|
||||
* @param Capacity, maximal number of visible at once elements
|
||||
* @param Amount, total amount of elements, including not visible
|
||||
* @param Value, starting position
|
||||
*/
|
||||
CSlider(Point position, int length, std::function<void(int)> Moved, int Capacity, int Amount,
|
||||
int Value=0, bool Horizontal=true, EStyle style = BROWN);
|
||||
~CSlider();
|
||||
};
|
1017
client/widgets/CArtifactHolder.cpp
Normal file
145
client/widgets/CArtifactHolder.h
Normal file
@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
|
||||
//#include "CComponent.h"
|
||||
#include "MiscWidgets.h"
|
||||
|
||||
/*
|
||||
* CArtifactHolder.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
class CArtifactsOfHero;
|
||||
class CAnimImage;
|
||||
class CButton;
|
||||
|
||||
struct ArtifactLocation;
|
||||
|
||||
class CArtifactHolder
|
||||
{
|
||||
public:
|
||||
CArtifactHolder();
|
||||
|
||||
virtual void artifactRemoved(const ArtifactLocation &artLoc)=0;
|
||||
virtual void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc)=0;
|
||||
virtual void artifactDisassembled(const ArtifactLocation &artLoc)=0;
|
||||
virtual void artifactAssembled(const ArtifactLocation &artLoc)=0;
|
||||
};
|
||||
|
||||
class CWindowWithArtifacts : public CArtifactHolder
|
||||
{
|
||||
public:
|
||||
std::vector<CArtifactsOfHero *> artSets;
|
||||
|
||||
void artifactRemoved(const ArtifactLocation &artLoc);
|
||||
void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc);
|
||||
void artifactDisassembled(const ArtifactLocation &artLoc);
|
||||
void artifactAssembled(const ArtifactLocation &artLoc);
|
||||
};
|
||||
|
||||
/// Artifacts can be placed there. Gets shown at the hero window
|
||||
class CArtPlace: public LRClickableAreaWTextComp
|
||||
{
|
||||
CAnimImage *image;
|
||||
CAnimImage *selection;
|
||||
|
||||
void createImage();
|
||||
|
||||
public:
|
||||
// consider these members as const - change them only with appropriate methods e.g. lockSlot()
|
||||
bool locked;
|
||||
bool picked;
|
||||
bool marked;
|
||||
|
||||
ArtifactPosition slotID; //Arts::EPOS enum + backpack starting from Arts::BACKPACK_START
|
||||
|
||||
void lockSlot(bool on);
|
||||
void pickSlot(bool on);
|
||||
void selectSlot(bool on);
|
||||
|
||||
CArtifactsOfHero * ourOwner;
|
||||
const CArtifactInstance * ourArt; // should be changed only with setArtifact()
|
||||
|
||||
CArtPlace(Point position, const CArtifactInstance * Art = nullptr); //c-tor
|
||||
void clickLeft(tribool down, bool previousState);
|
||||
void clickRight(tribool down, bool previousState);
|
||||
void select ();
|
||||
void deselect ();
|
||||
void showAll(SDL_Surface * to);
|
||||
bool fitsHere (const CArtifactInstance * art) const; //returns true if given artifact can be placed here
|
||||
|
||||
void setMeAsDest(bool backpackAsVoid = true);
|
||||
void setArtifact(const CArtifactInstance *art);
|
||||
};
|
||||
|
||||
/// Contains artifacts of hero. Distincts which artifacts are worn or backpacked
|
||||
class CArtifactsOfHero : public CIntObject
|
||||
{
|
||||
const CGHeroInstance * curHero;
|
||||
|
||||
std::vector<CArtPlace *> artWorn; // 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
|
||||
std::vector<CArtPlace *> backpack; //hero's visible backpack (only 5 elements!)
|
||||
int backpackPos; //number of first art visible in backpack (in hero's vector)
|
||||
|
||||
public:
|
||||
struct SCommonPart
|
||||
{
|
||||
struct Artpos
|
||||
{
|
||||
ArtifactPosition slotID;
|
||||
const CArtifactsOfHero *AOH;
|
||||
const CArtifactInstance *art;
|
||||
|
||||
Artpos();
|
||||
void clear();
|
||||
void setTo(const CArtPlace *place, bool dontTakeBackpack);
|
||||
bool valid();
|
||||
bool operator==(const ArtifactLocation &al) const;
|
||||
} src, dst;
|
||||
|
||||
std::set<CArtifactsOfHero *> participants; // Needed to mark slots.
|
||||
|
||||
void reset();
|
||||
} * commonInfo; //when we have more than one CArtifactsOfHero in one window with exchange possibility, we use this (eg. in exchange window); to be provided externally
|
||||
|
||||
bool updateState; // Whether the commonInfo should be updated on setHero or not.
|
||||
|
||||
CButton * leftArtRoll, * rightArtRoll;
|
||||
bool allowedAssembling;
|
||||
std::multiset<const CArtifactInstance*> artifactsOnAltar; //artifacts id that are technically present in backpack but in GUI are moved to the altar - they'll be omitted in backpack slots
|
||||
std::function<void(CArtPlace*)> highlightModeCallback; //if set, clicking on art place doesn't pick artifact but highlights the slot and calls this function
|
||||
|
||||
void realizeCurrentTransaction(); //calls callback with parameters stored in commonInfo
|
||||
void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst);
|
||||
void artifactRemoved(const ArtifactLocation &al);
|
||||
void artifactAssembled(const ArtifactLocation &al);
|
||||
void artifactDisassembled(const ArtifactLocation &al);
|
||||
CArtPlace *getArtPlace(int slot);
|
||||
|
||||
void setHero(const CGHeroInstance * hero);
|
||||
const CGHeroInstance *getHero() const;
|
||||
void dispose(); //free resources not needed after closing windows and reset state
|
||||
void scrollBackpack(int dir); //dir==-1 => to left; dir==1 => to right
|
||||
|
||||
void safeRedraw();
|
||||
void markPossibleSlots(const CArtifactInstance* art);
|
||||
void unmarkSlots(bool withRedraw = true); //unmarks slots in all visible AOHs
|
||||
void unmarkLocalSlots(bool withRedraw = true); //unmarks slots in that particular AOH
|
||||
void setSlotData (CArtPlace* artPlace, ArtifactPosition slotID);
|
||||
void updateWornSlots (bool redrawParent = true);
|
||||
|
||||
void updateSlot(ArtifactPosition i);
|
||||
void eraseSlotData (CArtPlace* artPlace, ArtifactPosition slotID);
|
||||
|
||||
CArtifactsOfHero(const Point& position, bool createCommonPart = false);
|
||||
//Alternative constructor, used if custom artifacts positioning required (Kingdom interface)
|
||||
CArtifactsOfHero(std::vector<CArtPlace *> ArtWorn, std::vector<CArtPlace *> Backpack,
|
||||
CButton *leftScroll, CButton *rightScroll, bool createCommonPart = false);
|
||||
~CArtifactsOfHero(); //d-tor
|
||||
void updateParentWindow();
|
||||
friend class CArtPlace;
|
||||
};
|
453
client/widgets/CComponent.cpp
Normal file
@ -0,0 +1,453 @@
|
||||
#include "StdInc.h"
|
||||
#include "CComponent.h"
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
|
||||
#include "../CMessage.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../widgets/Images.h"
|
||||
#include "../windows/CAdvmapInterface.h"
|
||||
|
||||
#include "../../lib/CArtHandler.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
#include "../../lib/CCreatureHandler.h"
|
||||
#include "../../lib/CSpellHandler.h"
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/NetPacksBase.h"
|
||||
|
||||
/*
|
||||
* CComponent.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
CComponent::CComponent(Etype Type, int Subtype, int Val, ESize imageSize):
|
||||
image(nullptr),
|
||||
perDay(false)
|
||||
{
|
||||
addUsedEvents(RCLICK);
|
||||
init(Type, Subtype, Val, imageSize);
|
||||
}
|
||||
|
||||
CComponent::CComponent(const Component &c):
|
||||
image(nullptr),
|
||||
perDay(false)
|
||||
{
|
||||
addUsedEvents(RCLICK);
|
||||
|
||||
if(c.id == Component::RESOURCE && c.when==-1)
|
||||
perDay = true;
|
||||
|
||||
init((Etype)c.id,c.subtype,c.val, large);
|
||||
}
|
||||
|
||||
void CComponent::init(Etype Type, int Subtype, int Val, ESize imageSize)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
compType = Type;
|
||||
subtype = Subtype;
|
||||
val = Val;
|
||||
size = imageSize;
|
||||
|
||||
assert(compType < typeInvalid);
|
||||
assert(size < sizeInvalid);
|
||||
|
||||
setSurface(getFileName()[size], getIndex());
|
||||
|
||||
pos.w = image->pos.w;
|
||||
pos.h = image->pos.h;
|
||||
|
||||
EFonts font = FONT_SMALL;
|
||||
if (imageSize < small)
|
||||
font = FONT_TINY; //other sizes?
|
||||
|
||||
pos.h += 4; //distance between text and image
|
||||
|
||||
std::vector<std::string> textLines = CMessage::breakText(getSubtitle(), std::max<int>(80, pos.w), font);
|
||||
for(auto & line : textLines)
|
||||
{
|
||||
int height = graphics->fonts[font]->getLineHeight();
|
||||
auto label = new CLabel(pos.w/2, pos.h + height/2, font, CENTER, Colors::WHITE, line);
|
||||
|
||||
pos.h += height;
|
||||
if (label->pos.w > pos.w)
|
||||
{
|
||||
pos.x -= (label->pos.w - pos.w)/2;
|
||||
pos.w = label->pos.w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::string> CComponent::getFileName()
|
||||
{
|
||||
static const std::string primSkillsArr [] = {"PSKIL32", "PSKIL32", "PSKIL42", "PSKILL"};
|
||||
static const std::string secSkillsArr [] = {"SECSK32", "SECSK32", "SECSKILL", "SECSK82"};
|
||||
static const std::string resourceArr [] = {"SMALRES", "RESOURCE", "RESOUR82", "RESOUR82"};
|
||||
static const std::string creatureArr [] = {"CPRSMALL", "CPRSMALL", "TWCRPORT", "TWCRPORT"};
|
||||
static const std::string artifactArr[] = {"Artifact", "Artifact", "Artifact", "Artifact"};
|
||||
static const std::string spellsArr [] = {"SpellInt", "SpellInt", "SPELLSCR", "SPELLSCR"};
|
||||
static const std::string moraleArr [] = {"IMRL22", "IMRL30", "IMRL42", "imrl82"};
|
||||
static const std::string luckArr [] = {"ILCK22", "ILCK30", "ILCK42", "ilck82"};
|
||||
static const std::string heroArr [] = {"PortraitsSmall", "PortraitsSmall", "PortraitsLarge", "PortraitsLarge"};
|
||||
static const std::string flagArr [] = {"CREST58", "CREST58", "CREST58", "CREST58"};
|
||||
|
||||
auto gen = [](const std::string * arr)
|
||||
{
|
||||
return std::vector<std::string>(arr, arr + 4);
|
||||
};
|
||||
|
||||
switch(compType)
|
||||
{
|
||||
case primskill: return gen(primSkillsArr);
|
||||
case secskill: return gen(secSkillsArr);
|
||||
case resource: return gen(resourceArr);
|
||||
case creature: return gen(creatureArr);
|
||||
case artifact: return gen(artifactArr);
|
||||
case experience: return gen(primSkillsArr);
|
||||
case spell: return gen(spellsArr);
|
||||
case morale: return gen(moraleArr);
|
||||
case luck: return gen(luckArr);
|
||||
case building: return std::vector<std::string>(4, CGI->townh->factions[subtype]->town->clientInfo.buildingsIcons);
|
||||
case hero: return gen(heroArr);
|
||||
case flag: return gen(flagArr);
|
||||
}
|
||||
assert(0);
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
size_t CComponent::getIndex()
|
||||
{
|
||||
switch(compType)
|
||||
{
|
||||
case primskill: return subtype;
|
||||
case secskill: return subtype*3 + 3 + val - 1;
|
||||
case resource: return subtype;
|
||||
case creature: return CGI->creh->creatures[subtype]->iconIndex;
|
||||
case artifact: return CGI->arth->artifacts[subtype]->iconIndex;
|
||||
case experience: return 4;
|
||||
case spell: return subtype;
|
||||
case morale: return val+3;
|
||||
case luck: return val+3;
|
||||
case building: return val;
|
||||
case hero: return subtype;
|
||||
case flag: return subtype;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string CComponent::getDescription()
|
||||
{
|
||||
switch (compType)
|
||||
{
|
||||
case primskill: return (subtype < 4)? CGI->generaltexth->arraytxt[2+subtype] //Primary skill
|
||||
: CGI->generaltexth->allTexts[149]; //mana
|
||||
case secskill: return CGI->generaltexth->skillInfoTexts[subtype][val-1];
|
||||
case resource: return CGI->generaltexth->allTexts[242];
|
||||
case creature: return "";
|
||||
case artifact: return CGI->arth->artifacts[subtype]->Description();
|
||||
case experience: return CGI->generaltexth->allTexts[241];
|
||||
case spell: return CGI->spellh->objects[subtype]->getLevelInfo(val).description;
|
||||
case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
|
||||
case luck: return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)];
|
||||
case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Description();
|
||||
case hero: return "";
|
||||
case flag: return "";
|
||||
}
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string CComponent::getSubtitle()
|
||||
{
|
||||
if (!perDay)
|
||||
return getSubtitleInternal();
|
||||
|
||||
std::string ret = CGI->generaltexth->allTexts[3];
|
||||
boost::replace_first(ret, "%d", getSubtitleInternal());
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string CComponent::getSubtitleInternal()
|
||||
{
|
||||
//FIXME: some of these are horrible (e.g creature)
|
||||
switch(compType)
|
||||
{
|
||||
case primskill: return boost::str(boost::format("%+d %s") % val % (subtype < 4 ? CGI->generaltexth->primarySkillNames[subtype] : CGI->generaltexth->allTexts[387]));
|
||||
case secskill: return CGI->generaltexth->levels[val-1] + "\n" + CGI->generaltexth->skillName[subtype];
|
||||
case resource: return boost::lexical_cast<std::string>(val);
|
||||
case creature: return (val? boost::lexical_cast<std::string>(val) + " " : "") + CGI->creh->creatures[subtype]->*(val != 1 ? &CCreature::namePl : &CCreature::nameSing);
|
||||
case artifact: return CGI->arth->artifacts[subtype]->Name();
|
||||
case experience:
|
||||
{
|
||||
if (subtype == 1) //+1 level - tree of knowledge
|
||||
{
|
||||
std::string level = CGI->generaltexth->allTexts[442];
|
||||
boost::replace_first(level, "1", boost::lexical_cast<std::string>(val));
|
||||
return level;
|
||||
}
|
||||
else
|
||||
return boost::lexical_cast<std::string>(val); //amount of experience OR level required for seer hut;
|
||||
}
|
||||
case spell: return CGI->spellh->objects[subtype]->name;
|
||||
case morale: return "";
|
||||
case luck: return "";
|
||||
case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Name();
|
||||
case hero: return "";
|
||||
case flag: return CGI->generaltexth->capColors[subtype];
|
||||
}
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
|
||||
void CComponent::setSurface(std::string defName, int imgPos)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
vstd::clear_pointer(image);
|
||||
image = new CAnimImage(defName, imgPos);
|
||||
}
|
||||
|
||||
void CComponent::clickRight(tribool down, bool previousState)
|
||||
{
|
||||
if(!getDescription().empty())
|
||||
adventureInt->handleRightClick(getDescription(), down);
|
||||
}
|
||||
|
||||
void CSelectableComponent::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if (down)
|
||||
{
|
||||
if(onSelect)
|
||||
onSelect();
|
||||
}
|
||||
}
|
||||
|
||||
void CSelectableComponent::init()
|
||||
{
|
||||
selected = false;
|
||||
}
|
||||
|
||||
CSelectableComponent::CSelectableComponent(const Component &c, std::function<void()> OnSelect):
|
||||
CComponent(c),onSelect(OnSelect)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
addUsedEvents(LCLICK | KEYBOARD);
|
||||
init();
|
||||
}
|
||||
|
||||
CSelectableComponent::CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize, std::function<void()> OnSelect):
|
||||
CComponent(Type,Sub,Val, imageSize),onSelect(OnSelect)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
addUsedEvents(LCLICK | KEYBOARD);
|
||||
init();
|
||||
}
|
||||
|
||||
void CSelectableComponent::select(bool on)
|
||||
{
|
||||
if(on != selected)
|
||||
{
|
||||
selected = on;
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void CSelectableComponent::showAll(SDL_Surface * to)
|
||||
{
|
||||
CComponent::showAll(to);
|
||||
if(selected)
|
||||
{
|
||||
CSDL_Ext::drawBorder(to, Rect::around(image->pos), int3(239,215,123));
|
||||
}
|
||||
}
|
||||
|
||||
void CComponentBox::selectionChanged(CSelectableComponent * newSelection)
|
||||
{
|
||||
if (newSelection == selected)
|
||||
return;
|
||||
|
||||
if (selected)
|
||||
selected->select(false);
|
||||
|
||||
selected = newSelection;
|
||||
if (onSelect)
|
||||
onSelect(selectedIndex());
|
||||
|
||||
if (selected)
|
||||
selected->select(true);
|
||||
}
|
||||
|
||||
int CComponentBox::selectedIndex()
|
||||
{
|
||||
if (selected)
|
||||
return std::find(components.begin(), components.end(), selected) - components.begin();
|
||||
return -1;
|
||||
}
|
||||
|
||||
Point CComponentBox::getOrTextPos(CComponent *left, CComponent *right)
|
||||
{
|
||||
int leftSubtitle = ( left->pos.w - left->image->pos.w) / 2;
|
||||
int rightSubtitle = (right->pos.w - right->image->pos.w) / 2;
|
||||
int fullDistance = getDistance(left, right) + leftSubtitle + rightSubtitle;
|
||||
|
||||
return Point(fullDistance/2 - leftSubtitle, (left->image->pos.h + right->image->pos.h) / 4);
|
||||
}
|
||||
|
||||
int CComponentBox::getDistance(CComponent *left, CComponent *right)
|
||||
{
|
||||
static const int betweenImagesMin = 20;
|
||||
static const int betweenSubtitlesMin = 10;
|
||||
|
||||
int leftSubtitle = ( left->pos.w - left->image->pos.w) / 2;
|
||||
int rightSubtitle = (right->pos.w - right->image->pos.w) / 2;
|
||||
int subtitlesOffset = leftSubtitle + rightSubtitle;
|
||||
|
||||
return std::max(betweenSubtitlesMin, betweenImagesMin - subtitlesOffset);
|
||||
}
|
||||
|
||||
void CComponentBox::placeComponents(bool selectable)
|
||||
{
|
||||
static const int betweenRows = 22;
|
||||
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
if (components.empty())
|
||||
return;
|
||||
|
||||
//prepare components
|
||||
for(auto & comp : components)
|
||||
{
|
||||
addChild(comp);
|
||||
comp->moveTo(Point(pos.x, pos.y));
|
||||
}
|
||||
|
||||
struct RowData
|
||||
{
|
||||
size_t comps;
|
||||
int width;
|
||||
int height;
|
||||
RowData (size_t Comps, int Width, int Height):
|
||||
comps(Comps), width (Width), height (Height){};
|
||||
};
|
||||
std::vector<RowData> rows;
|
||||
rows.push_back (RowData (0,0,0));
|
||||
|
||||
//split components in rows
|
||||
CComponent * prevComp = nullptr;
|
||||
|
||||
for(CComponent * comp : components)
|
||||
{
|
||||
//make sure that components are smaller than our width
|
||||
//assert(pos.w == 0 || pos.w < comp->pos.w);
|
||||
|
||||
const int distance = prevComp ? getDistance(prevComp, comp) : 0;
|
||||
|
||||
//start next row
|
||||
if ((pos.w != 0 && rows.back().width + comp->pos.w + distance > pos.w) // row is full
|
||||
|| rows.back().comps >= 4) // no more than 4 comps per row
|
||||
{
|
||||
prevComp = nullptr;
|
||||
rows.push_back (RowData (0,0,0));
|
||||
}
|
||||
|
||||
if (prevComp)
|
||||
rows.back().width += distance;
|
||||
|
||||
rows.back().comps++;
|
||||
rows.back().width += comp->pos.w;
|
||||
|
||||
vstd::amax(rows.back().height, comp->pos.h);
|
||||
prevComp = comp;
|
||||
}
|
||||
|
||||
if (pos.w == 0)
|
||||
{
|
||||
for(auto & row : rows)
|
||||
vstd::amax(pos.w, row.width);
|
||||
}
|
||||
|
||||
int height = (rows.size() - 1) * betweenRows;
|
||||
for(auto & row : rows)
|
||||
height += row.height;
|
||||
|
||||
//assert(pos.h == 0 || pos.h < height);
|
||||
if (pos.h == 0)
|
||||
pos.h = height;
|
||||
|
||||
auto iter = components.begin();
|
||||
int currentY = (pos.h - height) / 2;
|
||||
|
||||
//move components to their positions
|
||||
for (auto & rows_row : rows)
|
||||
{
|
||||
// amount of free space we may add on each side of every component
|
||||
int freeSpace = (pos.w - rows_row.width) / (rows_row.comps * 2);
|
||||
prevComp = nullptr;
|
||||
|
||||
int currentX = 0;
|
||||
for (size_t col = 0; col < rows_row.comps; col++)
|
||||
{
|
||||
currentX += freeSpace;
|
||||
if (prevComp)
|
||||
{
|
||||
if (selectable)
|
||||
{
|
||||
Point orPos = Point(currentX - freeSpace, currentY) + getOrTextPos(prevComp, *iter);
|
||||
|
||||
new CLabel(orPos.x, orPos.y, FONT_MEDIUM, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[4]);
|
||||
}
|
||||
currentX += getDistance(prevComp, *iter);
|
||||
}
|
||||
|
||||
(*iter)->moveBy(Point(currentX, currentY));
|
||||
currentX += (*iter)->pos.w;
|
||||
currentX += freeSpace;
|
||||
|
||||
prevComp = *(iter++);
|
||||
}
|
||||
currentY += rows_row.height + betweenRows;
|
||||
}
|
||||
}
|
||||
|
||||
CComponentBox::CComponentBox(CComponent * _components, Rect position):
|
||||
components(1, _components),
|
||||
selected(nullptr)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
pos = position + pos;
|
||||
placeComponents(false);
|
||||
}
|
||||
|
||||
CComponentBox::CComponentBox(std::vector<CComponent *> _components, Rect position):
|
||||
components(_components),
|
||||
selected(nullptr)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
pos = position + pos;
|
||||
placeComponents(false);
|
||||
}
|
||||
|
||||
CComponentBox::CComponentBox(std::vector<CSelectableComponent *> _components, Rect position, std::function<void(int newID)> _onSelect):
|
||||
components(_components.begin(), _components.end()),
|
||||
selected(nullptr),
|
||||
onSelect(_onSelect)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
pos = position + pos;
|
||||
placeComponents(true);
|
||||
|
||||
assert(!components.empty());
|
||||
|
||||
int key = SDLK_1;
|
||||
for(auto & comp : _components)
|
||||
{
|
||||
comp->onSelect = std::bind(&CComponentBox::selectionChanged, this, comp);
|
||||
comp->assignedKeys.insert(key++);
|
||||
}
|
||||
selectionChanged(_components.front());
|
||||
}
|
112
client/widgets/CComponent.h
Normal file
@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gui/CIntObject.h"
|
||||
|
||||
/*
|
||||
* CComponent.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
struct Component;
|
||||
class CAnimImage;
|
||||
|
||||
/// common popup window component
|
||||
class CComponent : public virtual CIntObject
|
||||
{
|
||||
public:
|
||||
enum Etype
|
||||
{
|
||||
primskill, secskill, resource, creature, artifact, experience, spell, morale, luck, building, hero, flag, typeInvalid
|
||||
};
|
||||
|
||||
//NOTE: not all types have exact these sizes or have less than 4 of them. In such cases closest one will be used
|
||||
enum ESize
|
||||
{
|
||||
tiny, // ~22-24px
|
||||
small, // ~30px
|
||||
medium,// ~42px
|
||||
large, // ~82px
|
||||
sizeInvalid
|
||||
};
|
||||
|
||||
private:
|
||||
size_t getIndex();
|
||||
const std::vector<std::string> getFileName();
|
||||
void setSurface(std::string defName, int imgPos);
|
||||
std::string getSubtitleInternal();
|
||||
|
||||
void init(Etype Type, int Subtype, int Val, ESize imageSize);
|
||||
|
||||
public:
|
||||
CAnimImage *image; //our image
|
||||
|
||||
Etype compType; //component type
|
||||
ESize size; //component size.
|
||||
int subtype; //type-dependant subtype. See getSomething methods for details
|
||||
int val; // value \ strength \ amount of component. See getSomething methods for details
|
||||
bool perDay; // add "per day" text to subtitle
|
||||
|
||||
std::string getDescription();
|
||||
std::string getSubtitle();
|
||||
|
||||
CComponent(Etype Type, int Subtype, int Val = 0, ESize imageSize=large);//c-tor
|
||||
CComponent(const Component &c); //c-tor
|
||||
|
||||
void clickRight(tribool down, bool previousState); //call-in
|
||||
};
|
||||
|
||||
/// component that can be selected or deselected
|
||||
class CSelectableComponent : public CComponent, public CKeyShortcut
|
||||
{
|
||||
void init();
|
||||
public:
|
||||
bool selected; //if true, this component is selected
|
||||
std::function<void()> onSelect; //function called on selection change
|
||||
|
||||
void showAll(SDL_Surface * to);
|
||||
void select(bool on);
|
||||
|
||||
void clickLeft(tribool down, bool previousState); //call-in
|
||||
CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize=large, std::function<void()> OnSelect = nullptr); //c-tor
|
||||
CSelectableComponent(const Component &c, std::function<void()> OnSelect = nullptr); //c-tor
|
||||
};
|
||||
|
||||
/// box with multiple components (up to 8?)
|
||||
/// will take ownership on components and delete them afterwards
|
||||
class CComponentBox : public CIntObject
|
||||
{
|
||||
std::vector<CComponent *> components;
|
||||
|
||||
CSelectableComponent * selected;
|
||||
std::function<void(int newID)> onSelect;
|
||||
|
||||
void selectionChanged(CSelectableComponent * newSelection);
|
||||
|
||||
//get position of "or" text between these comps
|
||||
//it will place "or" equidistant to both images
|
||||
Point getOrTextPos(CComponent *left, CComponent * right);
|
||||
|
||||
//get distance between these copmonents
|
||||
int getDistance(CComponent *left, CComponent * right);
|
||||
void placeComponents(bool selectable);
|
||||
|
||||
public:
|
||||
/// return index of selected item
|
||||
int selectedIndex();
|
||||
|
||||
/// constructor for quite common 1-components popups
|
||||
/// if position width or height are 0 then it will be determined automatically
|
||||
CComponentBox(CComponent * components, Rect position);
|
||||
/// constructor for non-selectable components
|
||||
CComponentBox(std::vector<CComponent *> components, Rect position);
|
||||
|
||||
/// constructor for selectable components
|
||||
/// will also create "or" labels between components
|
||||
/// onSelect - optional function that will be called every time on selection change
|
||||
CComponentBox(std::vector<CSelectableComponent *> components, Rect position, std::function<void(int newID)> onSelect = nullptr);
|
||||
};
|
512
client/widgets/CGarrisonInt.cpp
Normal file
@ -0,0 +1,512 @@
|
||||
#include "StdInc.h"
|
||||
#include "CGarrisonInt.h"
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../widgets/Buttons.h"
|
||||
#include "../widgets/TextControls.h"
|
||||
#include "../windows/CCreatureWindow.h"
|
||||
#include "../windows/GUIClasses.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/CCreatureHandler.h"
|
||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||
|
||||
#include "../../lib/CGameState.h"
|
||||
|
||||
/*
|
||||
* CGarrisonInt.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
void CGarrisonSlot::setHighlight(bool on)
|
||||
{
|
||||
if (on)
|
||||
selectionImage->enable(); //show
|
||||
else
|
||||
selectionImage->disable(); //hide
|
||||
}
|
||||
|
||||
void CGarrisonSlot::hover (bool on)
|
||||
{
|
||||
////Hoverable::hover(on);
|
||||
if(on)
|
||||
{
|
||||
std::string temp;
|
||||
if(creature)
|
||||
{
|
||||
if(owner->getSelection())
|
||||
{
|
||||
if(owner->getSelection() == this)
|
||||
{
|
||||
temp = CGI->generaltexth->tcommands[4]; //View %s
|
||||
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
|
||||
}
|
||||
else if (owner->getSelection()->creature == creature)
|
||||
{
|
||||
temp = CGI->generaltexth->tcommands[2]; //Combine %s armies
|
||||
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
|
||||
}
|
||||
else if (owner->getSelection()->creature)
|
||||
{
|
||||
temp = CGI->generaltexth->tcommands[7]; //Exchange %s with %s
|
||||
boost::algorithm::replace_first(temp,"%s",owner->getSelection()->creature->nameSing);
|
||||
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
|
||||
}
|
||||
else
|
||||
{
|
||||
logGlobal->warnStream() << "Warning - shouldn't be - highlighted void slot "<<owner->getSelection();
|
||||
logGlobal->warnStream() << "Highlighted set to nullptr";
|
||||
owner->selectSlot(nullptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(upg)
|
||||
{
|
||||
temp = CGI->generaltexth->tcommands[32]; //Select %s (visiting)
|
||||
}
|
||||
else if(owner->armedObjs[0] && owner->armedObjs[0]->ID == Obj::TOWN)
|
||||
{
|
||||
temp = CGI->generaltexth->tcommands[12]; //Select %s (in garrison)
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = CGI->generaltexth->allTexts[481]; //Select %s
|
||||
}
|
||||
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if(owner->getSelection())
|
||||
{
|
||||
const CArmedInstance *highl = owner->getSelection()->getObj();
|
||||
if( highl->needsLastStack() //we are moving stack from hero's
|
||||
&& highl->stacksCount() == 1 //it's only stack
|
||||
&& owner->getSelection()->upg != upg //we're moving it to the other garrison
|
||||
)
|
||||
{
|
||||
temp = CGI->generaltexth->tcommands[5]; //Cannot move last army to garrison
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = CGI->generaltexth->tcommands[6]; //Move %s
|
||||
boost::algorithm::replace_first(temp,"%s",owner->getSelection()->creature->nameSing);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = CGI->generaltexth->tcommands[11]; //Empty
|
||||
}
|
||||
}
|
||||
GH.statusbar->setText(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
GH.statusbar->clear();
|
||||
}
|
||||
}
|
||||
|
||||
const CArmedInstance * CGarrisonSlot::getObj() const
|
||||
{
|
||||
return (!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]);
|
||||
}
|
||||
|
||||
bool CGarrisonSlot::our() const
|
||||
{
|
||||
return upg?(owner->owned[1]):(owner->owned[0]);
|
||||
}
|
||||
|
||||
void CGarrisonSlot::clickRight(tribool down, bool previousState)
|
||||
{
|
||||
if(down && creature)
|
||||
{
|
||||
GH.pushInt(new CStackWindow(myStack, true));
|
||||
}
|
||||
}
|
||||
void CGarrisonSlot::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if(down)
|
||||
{
|
||||
bool refr = false;
|
||||
if(owner->getSelection())
|
||||
{
|
||||
if(owner->getSelection() == this) //view info
|
||||
{
|
||||
UpgradeInfo pom;
|
||||
LOCPLINT->cb->getUpgradeInfo(getObj(), ID, pom);
|
||||
|
||||
bool canUpgrade = getObj()->tempOwner == LOCPLINT->playerID && pom.oldID>=0; //upgrade is possible
|
||||
bool canDismiss = getObj()->tempOwner == LOCPLINT->playerID && (getObj()->stacksCount()>1 || !getObj()->needsLastStack());
|
||||
std::function<void(CreatureID)> upgr = nullptr;
|
||||
std::function<void()> dism = nullptr;
|
||||
if(canUpgrade) upgr = [=] (CreatureID newID) { LOCPLINT->cb->upgradeCreature(getObj(), ID, newID); };
|
||||
if(canDismiss) dism = [=] { LOCPLINT->cb->dismissCreature(getObj(), ID); };
|
||||
|
||||
owner->selectSlot(nullptr);
|
||||
owner->setSplittingMode(false);
|
||||
|
||||
for(auto & elem : owner->splitButtons)
|
||||
elem->block(true);
|
||||
|
||||
redraw();
|
||||
refr = true;
|
||||
GH.pushInt(new CStackWindow(myStack, dism, pom, upgr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only allow certain moves if troops aren't removable or not ours.
|
||||
if ( ( owner->getSelection()->our()//our creature is selected
|
||||
|| owner->getSelection()->creature == creature )//or we are rebalancing army
|
||||
&& ( owner->removableUnits
|
||||
|| (upg == 0 && ( owner->getSelection()->upg == 1 && !creature ) )
|
||||
|| (upg == 1 && owner->getSelection()->upg == 1 ) ) )
|
||||
{
|
||||
//we want to split
|
||||
if((owner->getSplittingMode() || LOCPLINT->shiftPressed())
|
||||
&& (!creature
|
||||
|| (creature == owner->getSelection()->creature)))
|
||||
{
|
||||
owner->p2 = ID; //store the second stack pos
|
||||
owner->pb = upg;//store the second stack owner (up or down army)
|
||||
owner->setSplittingMode(false);
|
||||
|
||||
int minLeft=0, minRight=0;
|
||||
|
||||
if(upg != owner->getSelection()->upg) //not splitting within same army
|
||||
{
|
||||
if(owner->getSelection()->getObj()->stacksCount() == 1 //we're splitting away the last stack
|
||||
&& owner->getSelection()->getObj()->needsLastStack() )
|
||||
{
|
||||
minLeft = 1;
|
||||
}
|
||||
if(getObj()->stacksCount() == 1 //destination army can't be emptied, unless we're rebalancing two stacks of same creature
|
||||
&& owner->getSelection()->creature == creature
|
||||
&& getObj()->needsLastStack() )
|
||||
{
|
||||
minRight = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int countLeft = owner->getSelection()->myStack ? owner->getSelection()->myStack->count : 0;
|
||||
int countRight = myStack ? myStack->count : 0;
|
||||
|
||||
GH.pushInt(new CSplitWindow(owner->getSelection()->creature, std::bind(&CGarrisonInt::splitStacks, owner, _1, _2),
|
||||
minLeft, minRight, countLeft, countRight));
|
||||
refr = true;
|
||||
}
|
||||
else if(creature != owner->getSelection()->creature) //swap
|
||||
{
|
||||
LOCPLINT->cb->swapCreatures(
|
||||
(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
|
||||
(!owner->getSelection()->upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
|
||||
ID,owner->getSelection()->ID);
|
||||
}
|
||||
else //merge
|
||||
{
|
||||
LOCPLINT->cb->mergeStacks(
|
||||
(!owner->getSelection()->upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
|
||||
(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
|
||||
owner->getSelection()->ID,ID);
|
||||
}
|
||||
}
|
||||
else // Highlight
|
||||
{
|
||||
if(creature)
|
||||
owner->selectSlot(this);
|
||||
redraw();
|
||||
refr = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else //highlight or drop artifact
|
||||
{
|
||||
bool artSelected = false;
|
||||
if (CWindowWithArtifacts* chw = dynamic_cast<CWindowWithArtifacts*>(GH.topInt())) //dirty solution
|
||||
{
|
||||
const CArtifactsOfHero::SCommonPart *commonInfo = chw->artSets.front()->commonInfo;
|
||||
if (const CArtifactInstance *art = commonInfo->src.art)
|
||||
{
|
||||
const CGHeroInstance *srcHero = commonInfo->src.AOH->getHero();
|
||||
artSelected = true;
|
||||
ArtifactLocation src(srcHero, commonInfo->src.slotID);
|
||||
ArtifactLocation dst(myStack, ArtifactPosition::CREATURE_SLOT);
|
||||
if (art->canBePutAt(dst, true))
|
||||
{ //equip clicked stack
|
||||
if(dst.getArt())
|
||||
{
|
||||
//creature can wear only one active artifact
|
||||
//if we are placing a new one, the old one will be returned to the hero's backpack
|
||||
LOCPLINT->cb->swapArtifacts(dst, ArtifactLocation(srcHero, dst.getArt()->firstBackpackSlot(srcHero)));
|
||||
}
|
||||
LOCPLINT->cb->swapArtifacts(src, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!artSelected && creature)
|
||||
{
|
||||
owner->selectSlot(this);
|
||||
if(creature)
|
||||
{
|
||||
for(auto & elem : owner->splitButtons)
|
||||
elem->block(false);
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
refr = true;
|
||||
}
|
||||
if(refr) {hover(false); hover(true); } //to refresh statusbar
|
||||
}
|
||||
}
|
||||
|
||||
void CGarrisonSlot::update()
|
||||
{
|
||||
if (getObj() != nullptr)
|
||||
{
|
||||
addUsedEvents(LCLICK | RCLICK | HOVER);
|
||||
myStack = getObj()->getStackPtr(ID);
|
||||
creature = myStack ? myStack->type : nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
removeUsedEvents(LCLICK | RCLICK | HOVER);
|
||||
myStack = nullptr;
|
||||
creature = nullptr;
|
||||
}
|
||||
|
||||
if (creature)
|
||||
{
|
||||
creatureImage->enable();
|
||||
creatureImage->setFrame(creature->iconIndex);
|
||||
|
||||
stackCount->enable();
|
||||
stackCount->setText(boost::lexical_cast<std::string>(myStack->count));
|
||||
}
|
||||
else
|
||||
{
|
||||
creatureImage->disable();
|
||||
stackCount->disable();
|
||||
}
|
||||
}
|
||||
|
||||
CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, int Upg, const CStackInstance * Creature):
|
||||
ID(IID),
|
||||
owner(Owner),
|
||||
myStack(Creature),
|
||||
creature(Creature ? Creature->type : nullptr),
|
||||
upg(Upg)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
if (getObj())
|
||||
addUsedEvents(LCLICK | RCLICK | HOVER);
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
|
||||
std::string imgName = owner->smallIcons ? "cprsmall" : "TWCRPORT";
|
||||
|
||||
creatureImage = new CAnimImage(imgName, creature ? creature->iconIndex : 0);
|
||||
if (!creature)
|
||||
creatureImage->disable();
|
||||
|
||||
selectionImage = new CAnimImage(imgName, 1);
|
||||
selectionImage->disable();
|
||||
|
||||
if(Owner->smallIcons)
|
||||
{
|
||||
pos.w = 32;
|
||||
pos.h = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.w = 58;
|
||||
pos.h = 64;
|
||||
}
|
||||
|
||||
stackCount = new CLabel(pos.w, pos.h, owner->smallIcons ? FONT_TINY : FONT_MEDIUM, BOTTOMRIGHT, Colors::WHITE);
|
||||
if (!creature)
|
||||
stackCount->disable();
|
||||
else
|
||||
stackCount->setText(boost::lexical_cast<std::string>(myStack->count));
|
||||
}
|
||||
|
||||
void CGarrisonInt::addSplitBtn(CButton * button)
|
||||
{
|
||||
addChild(button);
|
||||
button->recActions = defActions;
|
||||
splitButtons.push_back(button);
|
||||
button->block(getSelection() == nullptr);
|
||||
}
|
||||
|
||||
void CGarrisonInt::createSet(std::vector<CGarrisonSlot*> &ret, const CCreatureSet * set, int posX, int posY, int distance, int Upg )
|
||||
{
|
||||
ret.resize(7);
|
||||
|
||||
if (set)
|
||||
{
|
||||
for(auto & elem : set->Slots())
|
||||
{
|
||||
ret[elem.first.getNum()] = new CGarrisonSlot(this, posX + (elem.first.getNum()*distance), posY, elem.first, Upg, elem.second);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<ret.size(); i++)
|
||||
if(!ret[i])
|
||||
ret[i] = new CGarrisonSlot(this, posX + (i*distance), posY, SlotID(i), Upg, nullptr);
|
||||
|
||||
if (twoRows)
|
||||
for (int i=4; i<ret.size(); i++)
|
||||
{
|
||||
ret[i]->pos.x -= 126;
|
||||
ret[i]->pos.y += 37;
|
||||
};
|
||||
}
|
||||
|
||||
void CGarrisonInt::createSlots()
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
int width = smallIcons? 32 : 58;
|
||||
|
||||
createSet(slotsUp, armedObjs[0], 0, 0, width+interx, 0);
|
||||
createSet(slotsDown, armedObjs[1], garOffset.x, garOffset.y, width+interx, 1);
|
||||
}
|
||||
|
||||
void CGarrisonInt::recreateSlots()
|
||||
{
|
||||
selectSlot(nullptr);
|
||||
setSplittingMode(false);
|
||||
|
||||
for(auto & elem : splitButtons)
|
||||
elem->block(true);
|
||||
|
||||
|
||||
for(CGarrisonSlot * slot : slotsUp)
|
||||
slot->update();
|
||||
|
||||
for(CGarrisonSlot * slot : slotsDown)
|
||||
slot->update();
|
||||
}
|
||||
|
||||
void CGarrisonInt::splitClick()
|
||||
{
|
||||
if(!getSelection())
|
||||
return;
|
||||
setSplittingMode(!getSplittingMode());
|
||||
redraw();
|
||||
}
|
||||
void CGarrisonInt::splitStacks(int, int amountRight)
|
||||
{
|
||||
LOCPLINT->cb->splitStack(armedObjs[getSelection()->upg], armedObjs[pb], getSelection()->ID, p2, amountRight);
|
||||
}
|
||||
|
||||
CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point &garsOffset,
|
||||
SDL_Surface *pomsur, const Point& SurOffset,
|
||||
const CArmedInstance *s1, const CArmedInstance *s2,
|
||||
bool _removableUnits, bool smallImgs, bool _twoRows ) :
|
||||
highlighted(nullptr),
|
||||
inSplittingMode(false),
|
||||
interx(inx),
|
||||
garOffset(garsOffset),
|
||||
smallIcons(smallImgs),
|
||||
removableUnits(_removableUnits),
|
||||
twoRows(_twoRows)
|
||||
{
|
||||
setArmy(s1, false);
|
||||
setArmy(s2, true);
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
createSlots();
|
||||
}
|
||||
|
||||
const CGarrisonSlot * CGarrisonInt::getSelection()
|
||||
{
|
||||
return highlighted;
|
||||
}
|
||||
|
||||
void CGarrisonInt::selectSlot(CGarrisonSlot *slot)
|
||||
{
|
||||
if (slot != highlighted)
|
||||
{
|
||||
if (highlighted)
|
||||
highlighted->setHighlight(false);
|
||||
|
||||
highlighted = slot;
|
||||
for (auto button : splitButtons)
|
||||
button->block(highlighted == nullptr);
|
||||
|
||||
if (highlighted)
|
||||
highlighted->setHighlight(true);
|
||||
}
|
||||
}
|
||||
|
||||
void CGarrisonInt::setSplittingMode(bool on)
|
||||
{
|
||||
assert(on == false || highlighted != nullptr); //can't be in splitting mode without selection
|
||||
|
||||
if (inSplittingMode || on)
|
||||
{
|
||||
for(CGarrisonSlot * slot : slotsUp)
|
||||
slot->setHighlight( ( on && (slot->creature == nullptr || slot->creature == getSelection()->creature)));
|
||||
|
||||
for(CGarrisonSlot * slot : slotsDown)
|
||||
slot->setHighlight( ( on && (slot->creature == nullptr || slot->creature == getSelection()->creature)));
|
||||
inSplittingMode = on;
|
||||
}
|
||||
}
|
||||
|
||||
bool CGarrisonInt::getSplittingMode()
|
||||
{
|
||||
return inSplittingMode;
|
||||
}
|
||||
|
||||
void CGarrisonInt::setArmy(const CArmedInstance *army, bool bottomGarrison)
|
||||
{
|
||||
owned[bottomGarrison] = army ? (army->tempOwner == LOCPLINT->playerID || army->tempOwner == PlayerColor::UNFLAGGABLE) : false;
|
||||
armedObjs[bottomGarrison] = army;
|
||||
}
|
||||
|
||||
CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits ):
|
||||
CWindowObject(PLAYER_COLORED, "GARRISON")
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
garr = new CGarrisonInt(92, 127, 4, Point(0,96), background->bg, Point(93,127), up, down, removableUnits);
|
||||
{
|
||||
CButton *split = new CButton(Point(88, 314), "IDV6432.DEF", CButton::tooltip(CGI->generaltexth->tcommands[3], ""), [&]{ garr->splitClick(); } );
|
||||
removeChild(split);
|
||||
garr->addSplitBtn(split);
|
||||
}
|
||||
quit = new CButton(Point(399, 314), "IOK6432.DEF", CButton::tooltip(CGI->generaltexth->tcommands[8], ""), [&]{ close(); }, SDLK_RETURN);
|
||||
|
||||
std::string titleText;
|
||||
if (garr->armedObjs[1]->tempOwner == garr->armedObjs[0]->tempOwner)
|
||||
titleText = CGI->generaltexth->allTexts[709];
|
||||
else
|
||||
{
|
||||
titleText = CGI->generaltexth->allTexts[35];
|
||||
boost::algorithm::replace_first(titleText, "%s", garr->armedObjs[0]->Slots().begin()->second->type->namePl);
|
||||
}
|
||||
new CLabel(275, 30, FONT_BIG, CENTER, Colors::YELLOW, titleText);
|
||||
|
||||
new CAnimImage("CREST58", garr->armedObjs[0]->getOwner().getNum(), 0, 28, 124);
|
||||
new CAnimImage("PortraitsLarge", dynamic_cast<const CGHeroInstance*>(garr->armedObjs[1])->portrait, 0, 29, 222);
|
||||
}
|
||||
|
||||
CGarrisonHolder::CGarrisonHolder()
|
||||
{
|
||||
}
|
||||
|
||||
void CWindowWithGarrison::updateGarrisons()
|
||||
{
|
||||
garr->recreateSlots();
|
||||
}
|
122
client/widgets/CGarrisonInt.h
Normal file
@ -0,0 +1,122 @@
|
||||
#pragma once
|
||||
|
||||
#include "../windows/CWindowObject.h"
|
||||
|
||||
/*
|
||||
* CGarrisonInt.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
class CGarrisonInt;
|
||||
class CButton;
|
||||
class CArmedInstance;
|
||||
class CAnimImage;
|
||||
class CCreatureSet;
|
||||
class CGarrisonSlot;
|
||||
class CStackInstance;
|
||||
class CLabel;
|
||||
|
||||
/// A single garrison slot which holds one creature of a specific amount
|
||||
class CGarrisonSlot : public CIntObject
|
||||
{
|
||||
SlotID ID; //for identification
|
||||
CGarrisonInt *owner;
|
||||
const CStackInstance *myStack; //nullptr if slot is empty
|
||||
const CCreature *creature;
|
||||
int upg; //0 - up garrison, 1 - down garrison
|
||||
|
||||
CAnimImage * creatureImage;
|
||||
CAnimImage * selectionImage; // image for selection, not always visible
|
||||
CLabel * stackCount;
|
||||
|
||||
void setHighlight(bool on);
|
||||
public:
|
||||
virtual void hover (bool on); //call-in
|
||||
const CArmedInstance * getObj() const;
|
||||
bool our() const;
|
||||
void clickRight(tribool down, bool previousState);
|
||||
void clickLeft(tribool down, bool previousState);
|
||||
void update();
|
||||
CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, int Upg=0, const CStackInstance * Creature=nullptr);
|
||||
|
||||
friend class CGarrisonInt;
|
||||
};
|
||||
|
||||
/// Class which manages slots of upper and lower garrison, splitting of units
|
||||
class CGarrisonInt :public CIntObject
|
||||
{
|
||||
CGarrisonSlot *highlighted; //chosen slot. Should be changed only via selectSlot
|
||||
bool inSplittingMode;
|
||||
|
||||
public:
|
||||
void selectSlot(CGarrisonSlot * slot); //null = deselect
|
||||
const CGarrisonSlot * getSelection();
|
||||
|
||||
void setSplittingMode(bool on);
|
||||
bool getSplittingMode();
|
||||
|
||||
int interx; //space between slots
|
||||
Point garOffset; //offset between garrisons (not used if only one hero)
|
||||
std::vector<CButton *> splitButtons; //may be empty if no buttons
|
||||
|
||||
SlotID p2; //TODO: comment me
|
||||
int shiftPos;//1st slot of the second row, set shiftPoint for effect
|
||||
bool pb,
|
||||
smallIcons, //true - 32x32 imgs, false - 58x64
|
||||
removableUnits,//player can remove units from up
|
||||
twoRows,//slots will be placed in 2 rows
|
||||
owned[2];//player owns up or down army [0] upper, [1] lower
|
||||
|
||||
// const CCreatureSet *set1; //top set of creatures
|
||||
// const CCreatureSet *set2; //bottom set of creatures
|
||||
|
||||
std::vector<CGarrisonSlot*> slotsUp, slotsDown; //slots of upper and lower garrison
|
||||
const CArmedInstance *armedObjs[2]; //[0] is upper, [1] is down
|
||||
//const CArmedInstance *oup, *odown; //upper and lower garrisons (heroes or towns)
|
||||
|
||||
void setArmy(const CArmedInstance *army, bool bottomGarrison);
|
||||
void addSplitBtn(CButton * button);
|
||||
void createSet(std::vector<CGarrisonSlot*> &ret, const CCreatureSet * set, int posX, int distance, int posY, int Upg );
|
||||
|
||||
void createSlots();
|
||||
void recreateSlots();
|
||||
|
||||
void splitClick(); //handles click on split button
|
||||
void splitStacks(int amountLeft, int amountRight); //TODO: comment me
|
||||
//x, y - position;
|
||||
//inx - distance between slots;
|
||||
//pomsur, SurOffset - UNUSED
|
||||
//s1, s2 - top and bottom armies;
|
||||
//removableUnits - you can take units from top;
|
||||
//smallImgs - units images size 64x58 or 32x32;
|
||||
//twoRows - display slots in 2 row (1st row = 4 slots, 2nd = 3 slots)
|
||||
CGarrisonInt(int x, int y, int inx, const Point &garsOffset, SDL_Surface *pomsur, const Point &SurOffset, const CArmedInstance *s1, const CArmedInstance *s2=nullptr, bool _removableUnits = true, bool smallImgs = false, bool _twoRows=false); //c-tor
|
||||
};
|
||||
|
||||
class CGarrisonHolder
|
||||
{
|
||||
public:
|
||||
CGarrisonHolder();
|
||||
virtual void updateGarrisons()=0;
|
||||
};
|
||||
|
||||
class CWindowWithGarrison : public virtual CGarrisonHolder
|
||||
{
|
||||
public:
|
||||
CGarrisonInt *garr;
|
||||
virtual void updateGarrisons();
|
||||
};
|
||||
|
||||
/// Garrison window where you can take creatures out of the hero to place it on the garrison
|
||||
class CGarrisonWindow : public CWindowObject, public CWindowWithGarrison
|
||||
{
|
||||
public:
|
||||
CButton * quit;
|
||||
|
||||
CGarrisonWindow(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits); //c-tor
|
||||
};
|
533
client/widgets/Images.cpp
Normal file
@ -0,0 +1,533 @@
|
||||
#include "StdInc.h"
|
||||
#include "Images.h"
|
||||
|
||||
#include "MiscWidgets.h"
|
||||
|
||||
#include "../gui/CAnimation.h"
|
||||
#include "../gui/SDL_Pixels.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
|
||||
#include "../battle/CBattleInterface.h"
|
||||
#include "../battle/CBattleInterfaceClasses.h"
|
||||
|
||||
#include "../CBitmapHandler.h"
|
||||
#include "../Graphics.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CMessage.h"
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../windows/CAdvmapInterface.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
|
||||
#include "../../lib/CRandomGenerator.h"
|
||||
|
||||
/*
|
||||
* Images.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free )
|
||||
{
|
||||
init();
|
||||
bg = BG;
|
||||
freeSurf = Free;
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
pos.w = BG->w;
|
||||
pos.h = BG->h;
|
||||
}
|
||||
|
||||
CPicture::CPicture( const std::string &bmpname, int x, int y )
|
||||
{
|
||||
init();
|
||||
bg = BitmapHandler::loadBitmap(bmpname);
|
||||
freeSurf = true;;
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
if(bg)
|
||||
{
|
||||
pos.w = bg->w;
|
||||
pos.h = bg->h;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.w = pos.h = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CPicture::CPicture(const Rect &r, const SDL_Color &color, bool screenFormat /*= false*/)
|
||||
{
|
||||
init();
|
||||
createSimpleRect(r, screenFormat, SDL_MapRGB(bg->format, color.r, color.g,color.b));
|
||||
}
|
||||
|
||||
CPicture::CPicture(const Rect &r, ui32 color, bool screenFormat /*= false*/)
|
||||
{
|
||||
init();
|
||||
createSimpleRect(r, screenFormat, color);
|
||||
}
|
||||
|
||||
CPicture::CPicture(SDL_Surface *BG, const Rect &SrcRect, int x /*= 0*/, int y /*= 0*/, bool free /*= false*/)
|
||||
{
|
||||
needRefresh = false;
|
||||
srcRect = new Rect(SrcRect);
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
pos.w = srcRect->w;
|
||||
pos.h = srcRect->h;
|
||||
bg = BG;
|
||||
freeSurf = free;
|
||||
}
|
||||
|
||||
void CPicture::setSurface(SDL_Surface *to)
|
||||
{
|
||||
bg = to;
|
||||
if (srcRect)
|
||||
{
|
||||
pos.w = srcRect->w;
|
||||
pos.h = srcRect->h;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.w = bg->w;
|
||||
pos.h = bg->h;
|
||||
}
|
||||
}
|
||||
|
||||
CPicture::~CPicture()
|
||||
{
|
||||
if(freeSurf)
|
||||
SDL_FreeSurface(bg);
|
||||
delete srcRect;
|
||||
}
|
||||
|
||||
void CPicture::init()
|
||||
{
|
||||
needRefresh = false;
|
||||
srcRect = nullptr;
|
||||
}
|
||||
|
||||
void CPicture::show(SDL_Surface * to)
|
||||
{
|
||||
if (needRefresh)
|
||||
showAll(to);
|
||||
}
|
||||
|
||||
void CPicture::showAll(SDL_Surface * to)
|
||||
{
|
||||
if(bg)
|
||||
{
|
||||
if(srcRect)
|
||||
{
|
||||
SDL_Rect srcRectCpy = *srcRect;
|
||||
SDL_Rect dstRect = srcRectCpy;
|
||||
dstRect.x = pos.x;
|
||||
dstRect.y = pos.y;
|
||||
|
||||
CSDL_Ext::blitSurface(bg, &srcRectCpy, to, &dstRect);
|
||||
}
|
||||
else
|
||||
blitAt(bg, pos, to);
|
||||
}
|
||||
}
|
||||
|
||||
void CPicture::convertToScreenBPP()
|
||||
{
|
||||
SDL_Surface *hlp = bg;
|
||||
bg = SDL_ConvertSurface(hlp,screen->format,0);
|
||||
CSDL_Ext::setDefaultColorKey(bg);
|
||||
SDL_FreeSurface(hlp);
|
||||
}
|
||||
|
||||
void CPicture::setAlpha(int value)
|
||||
{
|
||||
#ifdef VCMI_SDL1
|
||||
SDL_SetAlpha(bg, SDL_SRCALPHA, value);
|
||||
#else
|
||||
SDL_SetSurfaceAlphaMod(bg,value);
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
void CPicture::scaleTo(Point size)
|
||||
{
|
||||
SDL_Surface * scaled = CSDL_Ext::scaleSurface(bg, size.x, size.y);
|
||||
|
||||
if(freeSurf)
|
||||
SDL_FreeSurface(bg);
|
||||
|
||||
setSurface(scaled);
|
||||
freeSurf = false;
|
||||
}
|
||||
|
||||
void CPicture::createSimpleRect(const Rect &r, bool screenFormat, ui32 color)
|
||||
{
|
||||
pos += r;
|
||||
pos.w = r.w;
|
||||
pos.h = r.h;
|
||||
if(screenFormat)
|
||||
bg = CSDL_Ext::newSurface(r.w, r.h);
|
||||
else
|
||||
bg = SDL_CreateRGBSurface(SDL_SWSURFACE, r.w, r.h, 8, 0, 0, 0, 0);
|
||||
|
||||
SDL_FillRect(bg, nullptr, color);
|
||||
freeSurf = true;
|
||||
}
|
||||
|
||||
void CPicture::colorizeAndConvert(PlayerColor player)
|
||||
{
|
||||
assert(bg);
|
||||
colorize(player);
|
||||
convertToScreenBPP();
|
||||
}
|
||||
|
||||
void CPicture::colorize(PlayerColor player)
|
||||
{
|
||||
assert(bg);
|
||||
graphics->blueToPlayersAdv(bg, player);
|
||||
}
|
||||
|
||||
CFilledTexture::CFilledTexture(std::string imageName, Rect position):
|
||||
CIntObject(0, position.topLeft()),
|
||||
texture(BitmapHandler::loadBitmap(imageName))
|
||||
{
|
||||
pos.w = position.w;
|
||||
pos.h = position.h;
|
||||
}
|
||||
|
||||
CFilledTexture::~CFilledTexture()
|
||||
{
|
||||
SDL_FreeSurface(texture);
|
||||
}
|
||||
|
||||
void CFilledTexture::showAll(SDL_Surface *to)
|
||||
{
|
||||
CSDL_Ext::CClipRectGuard guard(to, pos);
|
||||
CSDL_Ext::fillTexture(to, texture);
|
||||
}
|
||||
|
||||
CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
|
||||
frame(Frame),
|
||||
group(Group),
|
||||
player(-1),
|
||||
flags(Flags)
|
||||
{
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
anim = new CAnimation(name);
|
||||
init();
|
||||
}
|
||||
|
||||
CAnimImage::CAnimImage(CAnimation *Anim, size_t Frame, size_t Group, int x, int y, ui8 Flags):
|
||||
anim(Anim),
|
||||
frame(Frame),
|
||||
group(Group),
|
||||
player(-1),
|
||||
flags(Flags)
|
||||
{
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
init();
|
||||
}
|
||||
|
||||
size_t CAnimImage::size()
|
||||
{
|
||||
return anim->size(group);
|
||||
}
|
||||
|
||||
void CAnimImage::init()
|
||||
{
|
||||
anim->load(frame, group);
|
||||
if (flags & CShowableAnim::BASE)
|
||||
anim->load(0,group);
|
||||
|
||||
IImage *img = anim->getImage(frame, group);
|
||||
if (img)
|
||||
{
|
||||
pos.w = img->width();
|
||||
pos.h = img->height();
|
||||
}
|
||||
}
|
||||
|
||||
CAnimImage::~CAnimImage()
|
||||
{
|
||||
anim->unload(frame, group);
|
||||
if (flags & CShowableAnim::BASE)
|
||||
anim->unload(0,group);
|
||||
delete anim;
|
||||
}
|
||||
|
||||
void CAnimImage::showAll(SDL_Surface * to)
|
||||
{
|
||||
IImage *img;
|
||||
|
||||
if ( flags & CShowableAnim::BASE && frame != 0)
|
||||
if ((img = anim->getImage(0, group)))
|
||||
img->draw(to, pos.x, pos.y);
|
||||
|
||||
if ((img = anim->getImage(frame, group)))
|
||||
img->draw(to, pos.x, pos.y);
|
||||
}
|
||||
|
||||
void CAnimImage::setFrame(size_t Frame, size_t Group)
|
||||
{
|
||||
if (frame == Frame && group==Group)
|
||||
return;
|
||||
if (anim->size(Group) > Frame)
|
||||
{
|
||||
anim->load(Frame, Group);
|
||||
anim->unload(frame, group);
|
||||
frame = Frame;
|
||||
group = Group;
|
||||
IImage *img = anim->getImage(frame, group);
|
||||
if (img)
|
||||
{
|
||||
if (flags & CShowableAnim::PLAYER_COLORED)
|
||||
img->playerColored(player);
|
||||
pos.w = img->width();
|
||||
pos.h = img->height();
|
||||
}
|
||||
}
|
||||
else
|
||||
logGlobal->errorStream() << "Error: accessing unavailable frame " << Group << ":" << Frame << " in CAnimation!";
|
||||
}
|
||||
|
||||
void CAnimImage::playerColored(PlayerColor currPlayer)
|
||||
{
|
||||
player = currPlayer;
|
||||
flags |= CShowableAnim::PLAYER_COLORED;
|
||||
anim->getImage(frame, group)->playerColored(player);
|
||||
if (flags & CShowableAnim::BASE)
|
||||
anim->getImage(0, group)->playerColored(player);
|
||||
}
|
||||
|
||||
CShowableAnim::CShowableAnim(int x, int y, std::string name, ui8 Flags, ui32 Delay, size_t Group):
|
||||
anim(new CAnimation(name, Flags & USE_RLE)),
|
||||
group(Group),
|
||||
frame(0),
|
||||
first(0),
|
||||
frameDelay(Delay),
|
||||
value(0),
|
||||
flags(Flags),
|
||||
xOffset(0),
|
||||
yOffset(0),
|
||||
alpha(255)
|
||||
{
|
||||
anim->loadGroup(group);
|
||||
last = anim->size(group);
|
||||
|
||||
pos.w = anim->getImage(0, group)->width();
|
||||
pos.h = anim->getImage(0, group)->height();
|
||||
pos.x+= x;
|
||||
pos.y+= y;
|
||||
}
|
||||
|
||||
CShowableAnim::~CShowableAnim()
|
||||
{
|
||||
anim->unloadGroup(group);
|
||||
delete anim;
|
||||
}
|
||||
|
||||
void CShowableAnim::setAlpha(ui32 alphaValue)
|
||||
{
|
||||
alpha = std::min<ui32>(alphaValue, 255);
|
||||
}
|
||||
|
||||
bool CShowableAnim::set(size_t Group, size_t from, size_t to)
|
||||
{
|
||||
size_t max = anim->size(Group);
|
||||
|
||||
if (to < max)
|
||||
max = to;
|
||||
|
||||
if (max < from || max == 0)
|
||||
return false;
|
||||
|
||||
anim->load(Group);
|
||||
anim->unload(group);
|
||||
group = Group;
|
||||
frame = first = from;
|
||||
last = max;
|
||||
value = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CShowableAnim::set(size_t Group)
|
||||
{
|
||||
if (anim->size(Group)== 0)
|
||||
return false;
|
||||
if (group != Group)
|
||||
{
|
||||
anim->loadGroup(Group);
|
||||
anim->unloadGroup(group);
|
||||
first = 0;
|
||||
group = Group;
|
||||
last = anim->size(Group);
|
||||
}
|
||||
frame = value = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CShowableAnim::reset()
|
||||
{
|
||||
value = 0;
|
||||
frame = first;
|
||||
|
||||
if (callback)
|
||||
callback();
|
||||
}
|
||||
|
||||
void CShowableAnim::clipRect(int posX, int posY, int width, int height)
|
||||
{
|
||||
xOffset = posX;
|
||||
yOffset = posY;
|
||||
pos.w = width;
|
||||
pos.h = height;
|
||||
}
|
||||
|
||||
void CShowableAnim::show(SDL_Surface * to)
|
||||
{
|
||||
if ( flags & BASE )// && frame != first) // FIXME: results in graphical glytch in Fortress, upgraded hydra's dwelling
|
||||
blitImage(first, group, to);
|
||||
blitImage(frame, group, to);
|
||||
|
||||
if ((flags & PLAY_ONCE) && frame + 1 == last)
|
||||
return;
|
||||
|
||||
if ( ++value == frameDelay )
|
||||
{
|
||||
value = 0;
|
||||
if ( ++frame >= last)
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CShowableAnim::showAll(SDL_Surface * to)
|
||||
{
|
||||
if ( flags & BASE )// && frame != first)
|
||||
blitImage(first, group, to);
|
||||
blitImage(frame, group, to);
|
||||
}
|
||||
|
||||
void CShowableAnim::blitImage(size_t frame, size_t group, SDL_Surface *to)
|
||||
{
|
||||
assert(to);
|
||||
Rect src( xOffset, yOffset, pos.w, pos.h);
|
||||
IImage * img = anim->getImage(frame, group);
|
||||
if (img)
|
||||
img->draw(to, pos.x-xOffset, pos.y-yOffset, &src, alpha);
|
||||
}
|
||||
|
||||
void CShowableAnim::rotate(bool on, bool vertical)
|
||||
{
|
||||
ui8 flag = vertical? VERTICAL_FLIP:HORIZONTAL_FLIP;
|
||||
if (on)
|
||||
flags |= flag;
|
||||
else
|
||||
flags &= ~flag;
|
||||
}
|
||||
|
||||
CCreatureAnim::CCreatureAnim(int x, int y, std::string name, Rect picPos, ui8 flags, EAnimType type):
|
||||
CShowableAnim(x,y,name,flags,4,type)
|
||||
{
|
||||
xOffset = picPos.x;
|
||||
yOffset = picPos.y;
|
||||
if (picPos.w)
|
||||
pos.w = picPos.w;
|
||||
if (picPos.h)
|
||||
pos.h = picPos.h;
|
||||
};
|
||||
|
||||
void CCreatureAnim::loopPreview(bool warMachine)
|
||||
{
|
||||
std::vector<EAnimType> available;
|
||||
|
||||
static const EAnimType creaPreviewList[] = {HOLDING, HITTED, DEFENCE, ATTACK_FRONT, CAST_FRONT};
|
||||
static const EAnimType machPreviewList[] = {HOLDING, MOVING, SHOOT_UP, SHOOT_FRONT, SHOOT_DOWN};
|
||||
auto & previewList = warMachine ? machPreviewList : creaPreviewList;
|
||||
|
||||
for (auto & elem : previewList)
|
||||
if (anim->size(elem))
|
||||
available.push_back(elem);
|
||||
|
||||
size_t rnd = CRandomGenerator::getDefault().nextInt(available.size() * 2 - 1);
|
||||
|
||||
if (rnd >= available.size())
|
||||
{
|
||||
EAnimType type;
|
||||
if ( anim->size(MOVING) == 0 )//no moving animation present
|
||||
type = HOLDING;
|
||||
else
|
||||
type = MOVING;
|
||||
|
||||
//display this anim for ~1 second (time is random, but it looks good)
|
||||
for (size_t i=0; i< 12/anim->size(type) + 1; i++)
|
||||
addLast(type);
|
||||
}
|
||||
else
|
||||
addLast(available[rnd]);
|
||||
}
|
||||
|
||||
void CCreatureAnim::addLast(EAnimType newType)
|
||||
{
|
||||
if (type != MOVING && newType == MOVING)//starting moving - play init sequence
|
||||
{
|
||||
queue.push( MOVE_START );
|
||||
}
|
||||
else if (type == MOVING && newType != MOVING )//previous anim was moving - finish it
|
||||
{
|
||||
queue.push( MOVE_END );
|
||||
}
|
||||
if (newType == TURN_L || newType == TURN_R)
|
||||
queue.push(newType);
|
||||
|
||||
queue.push(newType);
|
||||
}
|
||||
|
||||
void CCreatureAnim::reset()
|
||||
{
|
||||
//if we are in the middle of rotation - set flag
|
||||
if (type == TURN_L && !queue.empty() && queue.front() == TURN_L)
|
||||
rotate(true);
|
||||
if (type == TURN_R && !queue.empty() && queue.front() == TURN_R)
|
||||
rotate(false);
|
||||
|
||||
while (!queue.empty())
|
||||
{
|
||||
EAnimType at = queue.front();
|
||||
queue.pop();
|
||||
if (set(at))
|
||||
return;
|
||||
}
|
||||
if (callback)
|
||||
callback();
|
||||
while (!queue.empty())
|
||||
{
|
||||
EAnimType at = queue.front();
|
||||
queue.pop();
|
||||
if (set(at))
|
||||
return;
|
||||
}
|
||||
set(HOLDING);
|
||||
}
|
||||
|
||||
void CCreatureAnim::startPreview(bool warMachine)
|
||||
{
|
||||
callback = std::bind(&CCreatureAnim::loopPreview, this, warMachine);
|
||||
}
|
||||
|
||||
void CCreatureAnim::clearAndSet(EAnimType type)
|
||||
{
|
||||
while (!queue.empty())
|
||||
queue.pop();
|
||||
set(type);
|
||||
}
|
226
client/widgets/Images.h
Normal file
@ -0,0 +1,226 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gui/CIntObject.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
|
||||
struct SDL_Surface;
|
||||
struct Rect;
|
||||
class CAnimImage;
|
||||
class CLabel;
|
||||
class CAnimation;
|
||||
class CDefHandler;
|
||||
|
||||
/*
|
||||
* Images.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
// Image class
|
||||
class CPicture : public CIntObject
|
||||
{
|
||||
void setSurface(SDL_Surface *to);
|
||||
public:
|
||||
SDL_Surface * bg;
|
||||
Rect * srcRect; //if nullptr then whole surface will be used
|
||||
bool freeSurf; //whether surface will be freed upon CPicture destruction
|
||||
bool needRefresh;//Surface needs to be displayed each frame
|
||||
|
||||
operator SDL_Surface*()
|
||||
{
|
||||
return bg;
|
||||
}
|
||||
|
||||
CPicture(const Rect & r, const SDL_Color & color, bool screenFormat = false); //rect filled with given color
|
||||
CPicture(const Rect & r, ui32 color, bool screenFormat = false); //rect filled with given color
|
||||
CPicture(SDL_Surface * BG, int x = 0, int y=0, bool Free = true); //wrap existing SDL_Surface
|
||||
CPicture(const std::string &bmpname, int x=0, int y=0);
|
||||
CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0, bool free = false); //wrap subrect of given surface
|
||||
~CPicture();
|
||||
void init();
|
||||
|
||||
//set alpha value for whole surface. Note: may be messed up if surface is shared
|
||||
// 0=transparent, 255=opaque
|
||||
void setAlpha(int value);
|
||||
|
||||
void scaleTo(Point size);
|
||||
void createSimpleRect(const Rect &r, bool screenFormat, ui32 color);
|
||||
void show(SDL_Surface * to);
|
||||
void showAll(SDL_Surface * to);
|
||||
void convertToScreenBPP();
|
||||
void colorizeAndConvert(PlayerColor player);
|
||||
void colorize(PlayerColor player);
|
||||
};
|
||||
|
||||
/// area filled with specific texture
|
||||
class CFilledTexture : CIntObject
|
||||
{
|
||||
SDL_Surface * texture;
|
||||
|
||||
public:
|
||||
CFilledTexture(std::string imageName, Rect position);
|
||||
~CFilledTexture();
|
||||
void showAll(SDL_Surface *to);
|
||||
};
|
||||
|
||||
/// Class for displaying one image from animation
|
||||
class CAnimImage: public CIntObject
|
||||
{
|
||||
private:
|
||||
CAnimation* anim;
|
||||
//displayed frame/group
|
||||
size_t frame;
|
||||
size_t group;
|
||||
PlayerColor player;
|
||||
ui8 flags;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
CAnimImage(std::string name, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
|
||||
CAnimImage(CAnimation* anim, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
|
||||
~CAnimImage();//d-tor
|
||||
|
||||
//size of animation
|
||||
size_t size();
|
||||
|
||||
//change displayed frame on this one
|
||||
void setFrame(size_t Frame, size_t Group=0);
|
||||
|
||||
//makes image player-colored
|
||||
void playerColored(PlayerColor player);
|
||||
|
||||
void showAll(SDL_Surface * to);
|
||||
};
|
||||
|
||||
/// Base class for displaying animation, used as superclass for different animations
|
||||
class CShowableAnim: public CIntObject
|
||||
{
|
||||
public:
|
||||
enum EFlags
|
||||
{
|
||||
BASE=1, //base frame will be blitted before current one
|
||||
HORIZONTAL_FLIP=2, //TODO: will be displayed rotated
|
||||
VERTICAL_FLIP=4, //TODO: will be displayed rotated
|
||||
USE_RLE=8, //RLE-d version, support full alpha-channel for 8-bit images
|
||||
PLAYER_COLORED=16, //TODO: all loaded images will be player-colored
|
||||
PLAY_ONCE=32 //play animation only once and stop at last frame
|
||||
};
|
||||
protected:
|
||||
CAnimation * anim;
|
||||
|
||||
size_t group, frame;//current frame
|
||||
|
||||
size_t first, last; //animation range
|
||||
|
||||
//TODO: replace with time delay(needed for battles)
|
||||
ui32 frameDelay;//delay in frames of each image
|
||||
ui32 value;//how many times current frame was showed
|
||||
|
||||
ui8 flags;//Flags from EFlags enum
|
||||
|
||||
//blit image with optional rotation, fitting into rect, etc
|
||||
void blitImage(size_t frame, size_t group, SDL_Surface *to);
|
||||
|
||||
//For clipping in rect, offsets of picture coordinates
|
||||
int xOffset, yOffset;
|
||||
|
||||
ui8 alpha;
|
||||
|
||||
public:
|
||||
//called when next animation sequence is required
|
||||
std::function<void()> callback;
|
||||
|
||||
//Set per-surface alpha, 0 = transparent, 255 = opaque
|
||||
void setAlpha(ui32 alphaValue);
|
||||
|
||||
CShowableAnim(int x, int y, std::string name, ui8 flags=0, ui32 Delay=4, size_t Group=0);
|
||||
~CShowableAnim();
|
||||
|
||||
//set animation to group or part of group
|
||||
bool set(size_t Group);
|
||||
bool set(size_t Group, size_t from, size_t to=-1);
|
||||
|
||||
//set rotation flags
|
||||
void rotate(bool on, bool vertical=false);
|
||||
|
||||
//move displayed part of picture (if picture is clipped to rect)
|
||||
void clipRect(int posX, int posY, int width, int height);
|
||||
|
||||
//set frame to first, call callback
|
||||
virtual void reset();
|
||||
|
||||
//show current frame and increase counter
|
||||
void show(SDL_Surface * to);
|
||||
void showAll(SDL_Surface * to);
|
||||
};
|
||||
|
||||
/// Creature-dependend animations like attacking, moving,...
|
||||
class CCreatureAnim: public CShowableAnim
|
||||
{
|
||||
public:
|
||||
|
||||
enum EHeroAnimType
|
||||
{
|
||||
HERO_HOLDING = 0,
|
||||
HERO_IDLE = 1, // idling movement that happens from time to time
|
||||
HERO_DEFEAT = 2, // played when army loses stack or on friendly fire
|
||||
HERO_VICTORY = 3, // when enemy stack killed or huge damage is dealt
|
||||
HERO_CAST_SPELL = 4 // spellcasting
|
||||
};
|
||||
|
||||
enum EAnimType // list of creature animations, numbers were taken from def files
|
||||
{
|
||||
MOVING=0,
|
||||
MOUSEON=1,
|
||||
HOLDING=2,
|
||||
HITTED=3,
|
||||
DEFENCE=4,
|
||||
DEATH=5,
|
||||
//DEATH2=6, //unused?
|
||||
TURN_L=7,
|
||||
TURN_R=8, //same
|
||||
//TURN_L2=9, //identical to previous?
|
||||
//TURN_R2=10,
|
||||
ATTACK_UP=11,
|
||||
ATTACK_FRONT=12,
|
||||
ATTACK_DOWN=13,
|
||||
SHOOT_UP=14,
|
||||
SHOOT_FRONT=15,
|
||||
SHOOT_DOWN=16,
|
||||
CAST_UP=17,
|
||||
CAST_FRONT=18,
|
||||
CAST_DOWN=19,
|
||||
MOVE_START=20,
|
||||
MOVE_END=21,
|
||||
DEAD = 22 // new group, used to show dead stacks. If empty - last frame from "DEATH" will be copied here
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
//queue of animations waiting to be displayed
|
||||
std::queue<EAnimType> queue;
|
||||
|
||||
//this function is used as callback if preview flag was set during construction
|
||||
void loopPreview(bool warMachine);
|
||||
|
||||
public:
|
||||
//change anim to next if queue is not empty, call callback othervice
|
||||
void reset();
|
||||
|
||||
//add sequence to the end of queue
|
||||
void addLast(EAnimType newType);
|
||||
|
||||
void startPreview(bool warMachine);
|
||||
|
||||
//clear queue and set animation to this sequence
|
||||
void clearAndSet(EAnimType type);
|
||||
|
||||
CCreatureAnim(int x, int y, std::string name, Rect picPos,
|
||||
ui8 flags= USE_RLE, EAnimType = HOLDING );
|
||||
|
||||
};
|
442
client/widgets/MiscWidgets.cpp
Normal file
@ -0,0 +1,442 @@
|
||||
#include "StdInc.h"
|
||||
#include "MiscWidgets.h"
|
||||
|
||||
#include "CComponent.h"
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
|
||||
#include "../CBitmapHandler.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CMessage.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../windows/CAdvmapInterface.h"
|
||||
#include "../windows/CCastleInterface.h"
|
||||
#include "../windows/InfoWindows.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
|
||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/CModHandler.h"
|
||||
#include "../../lib/CGameState.h"
|
||||
|
||||
/*
|
||||
* MiscWidgets.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
void CHoverableArea::hover (bool on)
|
||||
{
|
||||
if (on)
|
||||
GH.statusbar->setText(hoverText);
|
||||
else if (GH.statusbar->getText()==hoverText)
|
||||
GH.statusbar->clear();
|
||||
}
|
||||
|
||||
CHoverableArea::CHoverableArea()
|
||||
{
|
||||
addUsedEvents(HOVER);
|
||||
}
|
||||
|
||||
CHoverableArea::~CHoverableArea()
|
||||
{
|
||||
}
|
||||
|
||||
void LRClickableAreaWText::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if(!down && previousState && !text.empty())
|
||||
{
|
||||
LOCPLINT->showInfoDialog(text);
|
||||
}
|
||||
}
|
||||
void LRClickableAreaWText::clickRight(tribool down, bool previousState)
|
||||
{
|
||||
if (!text.empty())
|
||||
adventureInt->handleRightClick(text, down);
|
||||
}
|
||||
|
||||
LRClickableAreaWText::LRClickableAreaWText()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LRClickableAreaWText::LRClickableAreaWText(const Rect &Pos, const std::string &HoverText /*= ""*/, const std::string &ClickText /*= ""*/)
|
||||
{
|
||||
init();
|
||||
pos = Pos + pos;
|
||||
hoverText = HoverText;
|
||||
text = ClickText;
|
||||
}
|
||||
|
||||
LRClickableAreaWText::~LRClickableAreaWText()
|
||||
{
|
||||
}
|
||||
|
||||
void LRClickableAreaWText::init()
|
||||
{
|
||||
addUsedEvents(LCLICK | RCLICK | HOVER);
|
||||
}
|
||||
|
||||
void LRClickableAreaWTextComp::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if((!down) && previousState)
|
||||
{
|
||||
std::vector<CComponent*> comp(1, createComponent());
|
||||
LOCPLINT->showInfoDialog(text, comp);
|
||||
}
|
||||
}
|
||||
|
||||
LRClickableAreaWTextComp::LRClickableAreaWTextComp(const Rect &Pos, int BaseType)
|
||||
: LRClickableAreaWText(Pos), baseType(BaseType), bonusValue(-1)
|
||||
{
|
||||
}
|
||||
|
||||
CComponent * LRClickableAreaWTextComp::createComponent() const
|
||||
{
|
||||
if(baseType >= 0)
|
||||
return new CComponent(CComponent::Etype(baseType), type, bonusValue);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void LRClickableAreaWTextComp::clickRight(tribool down, bool previousState)
|
||||
{
|
||||
if(down)
|
||||
{
|
||||
if(CComponent *comp = createComponent())
|
||||
{
|
||||
CRClickPopup::createAndPush(text, CInfoWindow::TCompsInfo(1, comp));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LRClickableAreaWText::clickRight(down, previousState); //only if with-component variant not occurred
|
||||
}
|
||||
|
||||
CHeroArea::CHeroArea(int x, int y, const CGHeroInstance * _hero):hero(_hero)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
addUsedEvents(LCLICK | RCLICK | HOVER);
|
||||
pos.x += x; pos.w = 58;
|
||||
pos.y += y; pos.h = 64;
|
||||
|
||||
if (hero)
|
||||
new CAnimImage("PortraitsLarge", hero->portrait);
|
||||
}
|
||||
|
||||
void CHeroArea::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if((!down) && previousState && hero)
|
||||
LOCPLINT->openHeroWindow(hero);
|
||||
}
|
||||
|
||||
void CHeroArea::clickRight(tribool down, bool previousState)
|
||||
{
|
||||
if((!down) && previousState && hero)
|
||||
LOCPLINT->openHeroWindow(hero);
|
||||
}
|
||||
|
||||
void CHeroArea::hover(bool on)
|
||||
{
|
||||
if (on && hero)
|
||||
GH.statusbar->setText(hero->getObjectName());
|
||||
else
|
||||
GH.statusbar->clear();
|
||||
}
|
||||
|
||||
void LRClickableAreaOpenTown::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if((!down) && previousState && town)
|
||||
{
|
||||
LOCPLINT->openTownWindow(town);
|
||||
if ( type == 2 )
|
||||
LOCPLINT->castleInt->builds->buildingClicked(BuildingID::VILLAGE_HALL);
|
||||
else if ( type == 3 && town->fortLevel() )
|
||||
LOCPLINT->castleInt->builds->buildingClicked(BuildingID::FORT);
|
||||
}
|
||||
}
|
||||
|
||||
void LRClickableAreaOpenTown::clickRight(tribool down, bool previousState)
|
||||
{
|
||||
if((!down) && previousState && town)
|
||||
LOCPLINT->openTownWindow(town);//TODO: popup?
|
||||
}
|
||||
|
||||
LRClickableAreaOpenTown::LRClickableAreaOpenTown()
|
||||
: LRClickableAreaWTextComp(Rect(0,0,0,0), -1)
|
||||
{
|
||||
}
|
||||
|
||||
void CMinorResDataBar::show(SDL_Surface * to)
|
||||
{
|
||||
}
|
||||
|
||||
void CMinorResDataBar::showAll(SDL_Surface * to)
|
||||
{
|
||||
blitAt(bg,pos.x,pos.y,to);
|
||||
for (Res::ERes i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1))
|
||||
{
|
||||
std::string text = boost::lexical_cast<std::string>(LOCPLINT->cb->getResourceAmount(i));
|
||||
|
||||
graphics->fonts[FONT_SMALL]->renderTextCenter(to, text, Colors::WHITE, Point(pos.x + 50 + 76 * i, pos.y + pos.h/2));
|
||||
}
|
||||
std::vector<std::string> temp;
|
||||
|
||||
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::MONTH)));
|
||||
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::WEEK)));
|
||||
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK)));
|
||||
|
||||
std::string datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63]
|
||||
+ ": %s, " + CGI->generaltexth->allTexts[64] + ": %s";
|
||||
|
||||
graphics->fonts[FONT_SMALL]->renderTextCenter(to, CSDL_Ext::processStr(datetext,temp), Colors::WHITE, Point(pos.x+545+(pos.w-545)/2,pos.y+pos.h/2));
|
||||
}
|
||||
|
||||
CMinorResDataBar::CMinorResDataBar()
|
||||
{
|
||||
bg = BitmapHandler::loadBitmap("KRESBAR.bmp");
|
||||
CSDL_Ext::setDefaultColorKey(bg);
|
||||
graphics->blueToPlayersAdv(bg,LOCPLINT->playerID);
|
||||
pos.x = 7;
|
||||
pos.y = 575;
|
||||
pos.w = bg->w;
|
||||
pos.h = bg->h;
|
||||
}
|
||||
|
||||
CMinorResDataBar::~CMinorResDataBar()
|
||||
{
|
||||
SDL_FreeSurface(bg);
|
||||
}
|
||||
|
||||
void CArmyTooltip::init(const InfoAboutArmy &army)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
new CLabel(66, 2, FONT_SMALL, TOPLEFT, Colors::WHITE, army.name);
|
||||
|
||||
std::vector<Point> slotsPos;
|
||||
slotsPos.push_back(Point(36,73));
|
||||
slotsPos.push_back(Point(72,73));
|
||||
slotsPos.push_back(Point(108,73));
|
||||
slotsPos.push_back(Point(18,122));
|
||||
slotsPos.push_back(Point(54,122));
|
||||
slotsPos.push_back(Point(90,122));
|
||||
slotsPos.push_back(Point(126,122));
|
||||
|
||||
for(auto & slot : army.army)
|
||||
{
|
||||
if(slot.first.getNum() >= GameConstants::ARMY_SIZE)
|
||||
{
|
||||
logGlobal->warnStream() << "Warning: " << army.name << " has stack in slot " << slot.first;
|
||||
continue;
|
||||
}
|
||||
|
||||
new CAnimImage("CPRSMALL", slot.second.type->iconIndex, 0, slotsPos[slot.first.getNum()].x, slotsPos[slot.first.getNum()].y);
|
||||
|
||||
std::string subtitle;
|
||||
if(army.army.isDetailed)
|
||||
subtitle = boost::lexical_cast<std::string>(slot.second.count);
|
||||
else
|
||||
{
|
||||
//if =0 - we have no information about stack size at all
|
||||
if (slot.second.count)
|
||||
subtitle = CGI->generaltexth->arraytxt[171 + 3*(slot.second.count)];
|
||||
}
|
||||
|
||||
new CLabel(slotsPos[slot.first.getNum()].x + 17, slotsPos[slot.first.getNum()].y + 41, FONT_TINY, CENTER, Colors::WHITE, subtitle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CArmyTooltip::CArmyTooltip(Point pos, const InfoAboutArmy &army):
|
||||
CIntObject(0, pos)
|
||||
{
|
||||
init(army);
|
||||
}
|
||||
|
||||
CArmyTooltip::CArmyTooltip(Point pos, const CArmedInstance * army):
|
||||
CIntObject(0, pos)
|
||||
{
|
||||
init(InfoAboutArmy(army, true));
|
||||
}
|
||||
|
||||
void CHeroTooltip::init(const InfoAboutHero &hero)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
new CAnimImage("PortraitsLarge", hero.portrait, 0, 3, 2);
|
||||
|
||||
if(hero.details)
|
||||
{
|
||||
for (size_t i = 0; i < hero.details->primskills.size(); i++)
|
||||
new CLabel(75 + 28 * i, 58, FONT_SMALL, CENTER, Colors::WHITE,
|
||||
boost::lexical_cast<std::string>(hero.details->primskills[i]));
|
||||
|
||||
new CLabel(158, 98, FONT_TINY, CENTER, Colors::WHITE,
|
||||
boost::lexical_cast<std::string>(hero.details->mana));
|
||||
|
||||
new CAnimImage("IMRL22", hero.details->morale + 3, 0, 5, 74);
|
||||
new CAnimImage("ILCK22", hero.details->luck + 3, 0, 5, 91);
|
||||
}
|
||||
}
|
||||
|
||||
CHeroTooltip::CHeroTooltip(Point pos, const InfoAboutHero &hero):
|
||||
CArmyTooltip(pos, hero)
|
||||
{
|
||||
init(hero);
|
||||
}
|
||||
|
||||
CHeroTooltip::CHeroTooltip(Point pos, const CGHeroInstance * hero):
|
||||
CArmyTooltip(pos, InfoAboutHero(hero, true))
|
||||
{
|
||||
init(InfoAboutHero(hero, true));
|
||||
}
|
||||
|
||||
void CTownTooltip::init(const InfoAboutTown &town)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
//order of icons in def: fort, citadel, castle, no fort
|
||||
size_t fortIndex = town.fortLevel ? town.fortLevel - 1 : 3;
|
||||
|
||||
new CAnimImage("ITMCLS", fortIndex, 0, 105, 31);
|
||||
|
||||
assert(town.tType);
|
||||
|
||||
size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
|
||||
|
||||
new CAnimImage("itpt", iconIndex, 0, 3, 2);
|
||||
|
||||
if(town.details)
|
||||
{
|
||||
new CAnimImage("ITMTLS", town.details->hallLevel, 0, 67, 31);
|
||||
|
||||
if (town.details->goldIncome)
|
||||
new CLabel(157, 58, FONT_TINY, CENTER, Colors::WHITE,
|
||||
boost::lexical_cast<std::string>(town.details->goldIncome));
|
||||
|
||||
if(town.details->garrisonedHero) //garrisoned hero icon
|
||||
new CPicture("TOWNQKGH", 149, 76);
|
||||
|
||||
if(town.details->customRes)//silo is built
|
||||
{
|
||||
if (town.tType->primaryRes == Res::WOOD_AND_ORE )// wood & ore
|
||||
{
|
||||
new CAnimImage("SMALRES", Res::WOOD, 0, 7, 75);
|
||||
new CAnimImage("SMALRES", Res::ORE , 0, 7, 88);
|
||||
}
|
||||
else
|
||||
new CAnimImage("SMALRES", town.tType->primaryRes, 0, 7, 81);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CTownTooltip::CTownTooltip(Point pos, const InfoAboutTown &town):
|
||||
CArmyTooltip(pos, town)
|
||||
{
|
||||
init(town);
|
||||
}
|
||||
|
||||
CTownTooltip::CTownTooltip(Point pos, const CGTownInstance * town):
|
||||
CArmyTooltip(pos, InfoAboutTown(town, true))
|
||||
{
|
||||
init(InfoAboutTown(town, true));
|
||||
}
|
||||
|
||||
|
||||
void MoraleLuckBox::set(const IBonusBearer *node)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
const int textId[] = {62, 88}; //eg %s \n\n\n {Current Luck Modifiers:}
|
||||
const int noneTxtId = 108; //Russian version uses same text for neutral morale\luck
|
||||
const int neutralDescr[] = {60, 86}; //eg {Neutral Morale} \n\n Neutral morale means your armies will neither be blessed with extra attacks or freeze in combat.
|
||||
const int componentType[] = {CComponent::luck, CComponent::morale};
|
||||
const int hoverTextBase[] = {7, 4};
|
||||
const Bonus::BonusType bonusType[] = {Bonus::LUCK, Bonus::MORALE};
|
||||
int (IBonusBearer::*getValue[])() const = {&IBonusBearer::LuckVal, &IBonusBearer::MoraleVal};
|
||||
|
||||
int mrlt = -9;
|
||||
TModDescr mrl;
|
||||
|
||||
if (node)
|
||||
{
|
||||
node->getModifiersWDescr(mrl, bonusType[morale]);
|
||||
bonusValue = (node->*getValue[morale])();
|
||||
}
|
||||
else
|
||||
bonusValue = 0;
|
||||
|
||||
mrlt = (bonusValue>0)-(bonusValue<0); //signum: -1 - bad luck / morale, 0 - neutral, 1 - good
|
||||
hoverText = CGI->generaltexth->heroscrn[hoverTextBase[morale] - mrlt];
|
||||
baseType = componentType[morale];
|
||||
text = CGI->generaltexth->arraytxt[textId[morale]];
|
||||
boost::algorithm::replace_first(text,"%s",CGI->generaltexth->arraytxt[neutralDescr[morale]-mrlt]);
|
||||
if (!mrl.size())
|
||||
text += CGI->generaltexth->arraytxt[noneTxtId];
|
||||
else
|
||||
{
|
||||
//it's a creature window
|
||||
if ((morale && node->hasBonusOfType(Bonus::UNDEAD)) ||
|
||||
node->hasBonusOfType(Bonus::BLOCK_MORALE) || node->hasBonusOfType(Bonus::NON_LIVING))
|
||||
{
|
||||
text += CGI->generaltexth->arraytxt[113]; //unaffected by morale
|
||||
}
|
||||
else
|
||||
{
|
||||
for(auto & elem : mrl)
|
||||
{
|
||||
if (elem.first) //no bonuses with value 0
|
||||
text += "\n" + elem.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string imageName;
|
||||
if (small)
|
||||
imageName = morale ? "IMRL30": "ILCK30";
|
||||
else
|
||||
imageName = morale ? "IMRL42" : "ILCK42";
|
||||
|
||||
delete image;
|
||||
image = new CAnimImage(imageName, bonusValue + 3);
|
||||
image->moveBy(Point(pos.w/2 - image->pos.w/2, pos.h/2 - image->pos.h/2));//center icon
|
||||
}
|
||||
|
||||
MoraleLuckBox::MoraleLuckBox(bool Morale, const Rect &r, bool Small):
|
||||
image(nullptr),
|
||||
morale(Morale),
|
||||
small(Small)
|
||||
{
|
||||
bonusValue = 0;
|
||||
pos = r + pos;
|
||||
}
|
||||
|
||||
CCreaturePic::CCreaturePic(int x, int y, const CCreature *cre, bool Big, bool Animated)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
pos.x+=x;
|
||||
pos.y+=y;
|
||||
|
||||
TFaction faction = cre->faction;
|
||||
|
||||
assert(CGI->townh->factions.size() > faction);
|
||||
|
||||
if(Big)
|
||||
bg = new CPicture(CGI->townh->factions[faction]->creatureBg130);
|
||||
else
|
||||
bg = new CPicture(CGI->townh->factions[faction]->creatureBg120);
|
||||
bg->needRefresh = true;
|
||||
anim = new CCreatureAnim(0, 0, cre->animDefName, Rect());
|
||||
anim->clipRect(cre->isDoubleWide()?170:150, 155, bg->pos.w, bg->pos.h);
|
||||
anim->startPreview(cre->hasBonusOfType(Bonus::SIEGE_WEAPON));
|
||||
|
||||
pos.w = bg->pos.w;
|
||||
pos.h = bg->pos.h;
|
||||
}
|
150
client/widgets/MiscWidgets.h
Normal file
@ -0,0 +1,150 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gui/CIntObject.h"
|
||||
|
||||
/*
|
||||
* MiscWidgets.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
class CCreatureAnim;
|
||||
class CComponent;
|
||||
class CGGarrison;
|
||||
class CSelectableComponent;
|
||||
class InfoAboutArmy;
|
||||
class CArmedInstance;
|
||||
class IBonusBearer;
|
||||
class CAnimImage;
|
||||
|
||||
/// Shows a text by moving the mouse cursor over the object
|
||||
class CHoverableArea: public virtual CIntObject
|
||||
{
|
||||
public:
|
||||
std::string hoverText;
|
||||
|
||||
virtual void hover (bool on);
|
||||
|
||||
CHoverableArea();
|
||||
virtual ~CHoverableArea();
|
||||
};
|
||||
|
||||
/// Can interact on left and right mouse clicks, plus it shows a text when by hovering over it
|
||||
class LRClickableAreaWText: public CHoverableArea
|
||||
{
|
||||
public:
|
||||
std::string text;
|
||||
|
||||
LRClickableAreaWText();
|
||||
LRClickableAreaWText(const Rect &Pos, const std::string &HoverText = "", const std::string &ClickText = "");
|
||||
virtual ~LRClickableAreaWText();
|
||||
void init();
|
||||
|
||||
virtual void clickLeft(tribool down, bool previousState);
|
||||
virtual void clickRight(tribool down, bool previousState);
|
||||
};
|
||||
|
||||
/// base class for hero/town/garrison tooltips
|
||||
class CArmyTooltip : public CIntObject
|
||||
{
|
||||
void init(const InfoAboutArmy &army);
|
||||
public:
|
||||
CArmyTooltip(Point pos, const InfoAboutArmy &army);
|
||||
CArmyTooltip(Point pos, const CArmedInstance * army);
|
||||
};
|
||||
|
||||
/// Class for hero tooltip. Does not have any background!
|
||||
/// background for infoBox: ADSTATHR
|
||||
/// background for tooltip: HEROQVBK
|
||||
class CHeroTooltip : public CArmyTooltip
|
||||
{
|
||||
void init(const InfoAboutHero &hero);
|
||||
public:
|
||||
CHeroTooltip(Point pos, const InfoAboutHero &hero);
|
||||
CHeroTooltip(Point pos, const CGHeroInstance * hero);
|
||||
};
|
||||
|
||||
/// Class for town tooltip. Does not have any background!
|
||||
/// background for infoBox: ADSTATCS
|
||||
/// background for tooltip: TOWNQVBK
|
||||
class CTownTooltip : public CArmyTooltip
|
||||
{
|
||||
void init(const InfoAboutTown &town);
|
||||
public:
|
||||
CTownTooltip(Point pos, const InfoAboutTown &town);
|
||||
CTownTooltip(Point pos, const CGTownInstance * town);
|
||||
};
|
||||
|
||||
/// draws picture with creature on background, use Animated=true to get animation
|
||||
class CCreaturePic : public CIntObject
|
||||
{
|
||||
private:
|
||||
CPicture *bg;
|
||||
CCreatureAnim *anim; //displayed animation
|
||||
|
||||
public:
|
||||
CCreaturePic(int x, int y, const CCreature *cre, bool Big=true, bool Animated=true); //c-tor
|
||||
};
|
||||
|
||||
/// Resource bar like that at the bottom of the adventure map screen
|
||||
class CMinorResDataBar : public CIntObject
|
||||
{
|
||||
public:
|
||||
SDL_Surface *bg; //background bitmap
|
||||
void show(SDL_Surface * to);
|
||||
void showAll(SDL_Surface * to);
|
||||
CMinorResDataBar(); //c-tor
|
||||
~CMinorResDataBar(); //d-tor
|
||||
};
|
||||
|
||||
/// Opens hero window by left-clicking on it
|
||||
class CHeroArea: public CIntObject
|
||||
{
|
||||
const CGHeroInstance * hero;
|
||||
public:
|
||||
|
||||
CHeroArea(int x, int y, const CGHeroInstance * _hero);
|
||||
|
||||
void clickLeft(tribool down, bool previousState);
|
||||
void clickRight(tribool down, bool previousState);
|
||||
void hover(bool on);
|
||||
};
|
||||
|
||||
/// Can interact on left and right mouse clicks
|
||||
class LRClickableAreaWTextComp: public LRClickableAreaWText
|
||||
{
|
||||
public:
|
||||
int baseType;
|
||||
int bonusValue, type;
|
||||
virtual void clickLeft(tribool down, bool previousState);
|
||||
virtual void clickRight(tribool down, bool previousState);
|
||||
|
||||
LRClickableAreaWTextComp(const Rect &Pos = Rect(0,0,0,0), int BaseType = -1);
|
||||
CComponent * createComponent() const;
|
||||
};
|
||||
|
||||
/// Opens town screen by left-clicking on it
|
||||
class LRClickableAreaOpenTown: public LRClickableAreaWTextComp
|
||||
{
|
||||
public:
|
||||
const CGTownInstance * town;
|
||||
void clickLeft(tribool down, bool previousState);
|
||||
void clickRight(tribool down, bool previousState);
|
||||
LRClickableAreaOpenTown();
|
||||
};
|
||||
|
||||
class MoraleLuckBox : public LRClickableAreaWTextComp
|
||||
{
|
||||
CAnimImage *image;
|
||||
public:
|
||||
bool morale; //true if morale, false if luck
|
||||
bool small;
|
||||
|
||||
void set(const IBonusBearer *node);
|
||||
|
||||
MoraleLuckBox(bool Morale, const Rect &r, bool Small=false);
|
||||
};
|