1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-11 11:31:52 +02:00

Merge branch 'develop' of https://github.com/vcmi/vcmi into develop

This commit is contained in:
DjWarmonger 2014-09-05 15:59:29 +02:00
commit 3f49860d13
180 changed files with 14241 additions and 13586 deletions

19
.gitignore vendored
View File

@ -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-*

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,8 @@
{
"basepath" : "buttons/",
"images" :
[
{ "frame" : 0, "file" : "commanderNormal.png"},
{ "frame" : 1, "file" : "commanderPressed.png"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,8 @@
{
"basepath" : "buttons/",
"images" :
[
{ "frame" : 0, "file" : "resolutionNormal.png"},
{ "frame" : 1, "file" : "resolutionPressed.png"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,8 @@
{
"basepath" : "stackWindow/",
"images" :
[
{ "frame" : 0, "file" : "cancel-normal.png"},
{ "frame" : 1, "file" : "cancel-pressed.png"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View 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"}
]
}

View File

@ -0,0 +1,7 @@
{
"images" :
[
{ "frame" : 0, "file" : "SECSK32:69"},
{ "frame" : 1, "file" : "SECSK32:28"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,8 @@
{
"basepath" : "stackWindow/",
"images" :
[
{ "frame" : 0, "file" : "upgrade-normal.png"},
{ "frame" : 1, "file" : "upgrade-pressed.png"}
]
}

View File

@ -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

View File

@ -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)

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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})

View File

@ -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;

View File

@ -2,7 +2,6 @@
#include "../lib/CConfigHandler.h"
#include "../lib/CSoundBase.h"
#include "../lib/CCreatureHandler.h"
/*
* CMusicHandler.h, part of VCMI engine

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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 &pi;
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;

View File

@ -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)
{

View File

@ -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"

View File

@ -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";

View File

@ -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;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -1,7 +1,7 @@
#pragma once
#include "../CAnimation.h"
#include "../../lib/BattleHex.h"
#include "../widgets/Images.h"
class CBattleInterface;
class CStack;

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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);
};
};

View File

@ -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
*

View File

@ -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

View File

@ -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);
}

View File

@ -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 );
};

View File

@ -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"
/*

View File

@ -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"

View File

@ -1,6 +1,6 @@
#pragma once
#include "../../lib/CStopWatch.h"
//#include "../../lib/CStopWatch.h"
#include "Geometries.h"
#include "SDL_Extensions.h"

View File

@ -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)

View File

@ -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
};

File diff suppressed because it is too large Load Diff

View File

@ -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();
};

View File

@ -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);
}
}

View File

@ -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;
}
};
};

View File

@ -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"

View File

@ -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++;

View File

@ -1,5 +1,7 @@
#pragma once
#include <SDL_endian.h>
#include "SDL_Extensions.h"
/*

View File

@ -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
}

View File

@ -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
View 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
View 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();
};

File diff suppressed because it is too large Load Diff

View 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;
};

View 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
View 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);
};

View 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();
}

View 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
View 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
View 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 );
};

View 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;
}

View 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);
};

Some files were not shown because too many files have changed in this diff Show More