Merged GUI refactoring into develop, fixed conflicts
BIN
Mods/vcmi/Data/StackQueueLarge.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
Mods/vcmi/Data/StackQueueSmall.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
Mods/vcmi/Data/questDialog.png
Normal file
After Width: | Height: | Size: 268 KiB |
BIN
Mods/vcmi/Data/stackWindow/bonus-effects.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
Mods/vcmi/Data/stackWindow/button-panel.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
Mods/vcmi/Data/stackWindow/commander-abilities.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
Mods/vcmi/Data/stackWindow/commander-bg.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
Mods/vcmi/Data/stackWindow/icons.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
Mods/vcmi/Data/stackWindow/info-panel-0.png
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
Mods/vcmi/Data/stackWindow/info-panel-1.png
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
Mods/vcmi/Data/stackWindow/info-panel-2.png
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
Mods/vcmi/Data/stackWindow/spell-effects.png
Normal file
After Width: | Height: | Size: 20 KiB |
8
Mods/vcmi/Sprites/buttons/commander.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"basepath" : "buttons/",
|
||||||
|
"images" :
|
||||||
|
[
|
||||||
|
{ "frame" : 0, "file" : "commanderNormal.png"},
|
||||||
|
{ "frame" : 1, "file" : "commanderPressed.png"}
|
||||||
|
]
|
||||||
|
}
|
BIN
Mods/vcmi/Sprites/buttons/commanderNormal.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
Mods/vcmi/Sprites/buttons/commanderPressed.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
8
Mods/vcmi/Sprites/buttons/resolution.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"basepath" : "buttons/",
|
||||||
|
"images" :
|
||||||
|
[
|
||||||
|
{ "frame" : 0, "file" : "resolutionNormal.png"},
|
||||||
|
{ "frame" : 1, "file" : "resolutionPressed.png"}
|
||||||
|
]
|
||||||
|
}
|
BIN
Mods/vcmi/Sprites/buttons/resolutionNormal.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
Mods/vcmi/Sprites/buttons/resolutionPressed.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/cancel-normal.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/cancel-pressed.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
8
Mods/vcmi/Sprites/stackWindow/cancelButton.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"basepath" : "stackWindow/",
|
||||||
|
"images" :
|
||||||
|
[
|
||||||
|
{ "frame" : 0, "file" : "cancel-normal.png"},
|
||||||
|
{ "frame" : 1, "file" : "cancel-pressed.png"}
|
||||||
|
]
|
||||||
|
}
|
BIN
Mods/vcmi/Sprites/stackWindow/level-0.png
Normal file
After Width: | Height: | Size: 182 B |
BIN
Mods/vcmi/Sprites/stackWindow/level-1.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-10.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-2.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-3.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-4.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-5.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-6.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-7.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-8.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-9.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
17
Mods/vcmi/Sprites/stackWindow/levels.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"basepath" : "stackWindow/",
|
||||||
|
"images" :
|
||||||
|
[
|
||||||
|
{ "frame" : 0, "file" : "level-0.png"},
|
||||||
|
{ "frame" : 1, "file" : "level-1.png"},
|
||||||
|
{ "frame" : 2, "file" : "level-2.png"},
|
||||||
|
{ "frame" : 3, "file" : "level-3.png"},
|
||||||
|
{ "frame" : 4, "file" : "level-4.png"},
|
||||||
|
{ "frame" : 5, "file" : "level-5.png"},
|
||||||
|
{ "frame" : 6, "file" : "level-6.png"},
|
||||||
|
{ "frame" : 7, "file" : "level-7.png"},
|
||||||
|
{ "frame" : 8, "file" : "level-8.png"},
|
||||||
|
{ "frame" : 9, "file" : "level-9.png"},
|
||||||
|
{ "frame" : 10,"file" : "level-10.png"}
|
||||||
|
]
|
||||||
|
}
|
7
Mods/vcmi/Sprites/stackWindow/switchModeIcons.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"images" :
|
||||||
|
[
|
||||||
|
{ "frame" : 0, "file" : "SECSK32:69"},
|
||||||
|
{ "frame" : 1, "file" : "SECSK32:28"}
|
||||||
|
]
|
||||||
|
}
|
BIN
Mods/vcmi/Sprites/stackWindow/upgrade-normal.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/upgrade-pressed.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
8
Mods/vcmi/Sprites/stackWindow/upgradeButton.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"basepath" : "stackWindow/",
|
||||||
|
"images" :
|
||||||
|
[
|
||||||
|
{ "frame" : 0, "file" : "upgrade-normal.png"},
|
||||||
|
{ "frame" : 1, "file" : "upgrade-pressed.png"}
|
||||||
|
]
|
||||||
|
}
|
@ -15,6 +15,7 @@ For building from source see project wiki at http://wiki.vcmi.eu/
|
|||||||
|
|
||||||
## Copyright and license
|
## 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)
|
Copyright (C) 2007-2014 VCMI Team (check AUTHORS file for the contributors list)
|
||||||
|
@ -1,935 +0,0 @@
|
|||||||
#include "StdInc.h"
|
|
||||||
#include "CCreatureWindow.h"
|
|
||||||
|
|
||||||
#include "../lib/CCreatureSet.h"
|
|
||||||
#include "CGameInfo.h"
|
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
|
||||||
#include "../lib/BattleState.h"
|
|
||||||
#include "../CCallback.h"
|
|
||||||
|
|
||||||
#include <SDL.h>
|
|
||||||
#include "gui/SDL_Extensions.h"
|
|
||||||
#include "CBitmapHandler.h"
|
|
||||||
#include "CDefHandler.h"
|
|
||||||
#include "Graphics.h"
|
|
||||||
#include "CPlayerInterface.h"
|
|
||||||
#include "../lib/CConfigHandler.h"
|
|
||||||
#include "CAnimation.h"
|
|
||||||
|
|
||||||
#include "../lib/CGameState.h"
|
|
||||||
#include "../lib/BattleState.h"
|
|
||||||
#include "../lib/CSpellHandler.h"
|
|
||||||
#include "../lib/CArtHandler.h"
|
|
||||||
#include "../lib/NetPacksBase.h" //ArtifactLocation
|
|
||||||
#include "../lib/CModHandler.h"
|
|
||||||
#include "../lib/IBonusTypeHandler.h"
|
|
||||||
|
|
||||||
#include "gui/CGuiHandler.h"
|
|
||||||
#include "gui/CIntObjectClasses.h"
|
|
||||||
|
|
||||||
using namespace CSDL_Ext;
|
|
||||||
|
|
||||||
class CCreatureArtifactInstance;
|
|
||||||
class CSelectableSkill;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CCreatureWindow.cpp, part of VCMI engine
|
|
||||||
*
|
|
||||||
* Authors: listed in file AUTHORS in main folder
|
|
||||||
*
|
|
||||||
* License: GNU General Public License v2.0 or later
|
|
||||||
* Full text of license available in license.txt file, in main folder
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
CCreatureWindow::CCreatureWindow (const CStack &stack, CreWinType Type):
|
|
||||||
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
|
|
||||||
type(Type)
|
|
||||||
{
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
||||||
if (stack.base)
|
|
||||||
init(stack.base, &stack, dynamic_cast<const CGHeroInstance*>(stack.base->armyObj));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto s = new CStackInstance(stack.type, 1); //TODO: war machines and summons should be regular stacks
|
|
||||||
init(s, &stack, nullptr);
|
|
||||||
delete s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CCreatureWindow::CCreatureWindow (const CStackInstance &stack, CreWinType Type):
|
|
||||||
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
|
|
||||||
type(Type)
|
|
||||||
{
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
||||||
|
|
||||||
init(&stack, &stack, dynamic_cast<const CGHeroInstance*>(stack.armyObj));
|
|
||||||
}
|
|
||||||
|
|
||||||
CCreatureWindow::CCreatureWindow(CreatureID Cid, CreWinType Type, int creatureCount):
|
|
||||||
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
|
|
||||||
type(Type)
|
|
||||||
{
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
||||||
|
|
||||||
auto stack = new CStackInstance(Cid, creatureCount); //TODO: simplify?
|
|
||||||
init(stack, CGI->creh->creatures[Cid], nullptr);
|
|
||||||
delete stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
CCreatureWindow::CCreatureWindow(const CStackInstance &st, CreWinType Type, std::function<void()> Upg, std::function<void()> Dsm, UpgradeInfo *ui):
|
|
||||||
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
|
|
||||||
type(Type),
|
|
||||||
dismiss(nullptr),
|
|
||||||
upgrade(nullptr),
|
|
||||||
ok(nullptr),
|
|
||||||
dsm(Dsm)
|
|
||||||
{
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
||||||
init(&st, &st,dynamic_cast<const CGHeroInstance*>(st.armyObj));
|
|
||||||
|
|
||||||
//print abilities text - if r-click popup
|
|
||||||
if(type)
|
|
||||||
{
|
|
||||||
if(Upg && ui)
|
|
||||||
{
|
|
||||||
TResources upgradeCost = ui->cost[0] * st.count;
|
|
||||||
for(TResources::nziterator i(upgradeCost); i.valid(); i++)
|
|
||||||
{
|
|
||||||
BLOCK_CAPTURING;
|
|
||||||
upgResCost.push_back(new CComponent(CComponent::resource, i->resType, i->resVal));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost))
|
|
||||||
{
|
|
||||||
CFunctionList<void()> fs;
|
|
||||||
fs += Upg;
|
|
||||||
fs += std::bind(&CCreatureWindow::close,this);
|
|
||||||
CFunctionList<void()> cfl;
|
|
||||||
cfl += std::bind(&CPlayerInterface::showYesNoDialog,
|
|
||||||
LOCPLINT, CGI->generaltexth->allTexts[207], fs, nullptr, false, upgResCost);
|
|
||||||
upgrade = new CAdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,385, 148,"IVIEWCR.DEF",SDLK_u);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
upgrade = new CAdventureMapButton("",CGI->generaltexth->zelp[446].second,std::function<void()>(),385, 148,"IVIEWCR.DEF");
|
|
||||||
upgrade->callback.funcs.clear();
|
|
||||||
upgrade->setOffset(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if(Dsm)
|
|
||||||
{
|
|
||||||
CFunctionList<void()> fs[2];
|
|
||||||
//on dismiss confirmed
|
|
||||||
fs[0] += Dsm; //dismiss
|
|
||||||
fs[0] += std::bind(&CCreatureWindow::close,this);//close this window
|
|
||||||
CFunctionList<void()> cfl;
|
|
||||||
cfl = std::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector<CComponent*>());
|
|
||||||
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,333, 148,"IVIEWCR2.DEF",SDLK_d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CCreatureWindow::CCreatureWindow (const CCommanderInstance * Commander, const CStack * stack):
|
|
||||||
CWindowObject(PLAYER_COLORED),
|
|
||||||
commander (Commander)
|
|
||||||
{
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
||||||
if (stack)
|
|
||||||
{
|
|
||||||
type = COMMANDER_BATTLE;
|
|
||||||
init(commander, stack, dynamic_cast<const CGHeroInstance*>(commander->armyObj));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
type = COMMANDER;
|
|
||||||
init(commander, commander, dynamic_cast<const CGHeroInstance*>(commander->armyObj));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::function<void()> Dsm;
|
|
||||||
CFunctionList<void()> fs[2];
|
|
||||||
//on dismiss confirmed
|
|
||||||
fs[0] += Dsm; //dismiss
|
|
||||||
fs[0] += std::bind(&CCreatureWindow::close,this);//close this window
|
|
||||||
CFunctionList<void()> cfl;
|
|
||||||
cfl = std::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector<CComponent*>());
|
|
||||||
if (type < COMMANDER_LEVEL_UP) //can dismiss only in regular window
|
|
||||||
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d);
|
|
||||||
}
|
|
||||||
|
|
||||||
CCreatureWindow::CCreatureWindow (std::vector<ui32> &skills, const CCommanderInstance * Commander, std::function<void(ui32)> callback):
|
|
||||||
CWindowObject(PLAYER_COLORED),
|
|
||||||
type(COMMANDER_LEVEL_UP),
|
|
||||||
commander (Commander),
|
|
||||||
selectedOption (0), //choose something before drawing
|
|
||||||
upgradeOptions(skills), //copy skills to choose from
|
|
||||||
levelUp (callback)
|
|
||||||
{
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
||||||
|
|
||||||
init(commander, commander, dynamic_cast<const CGHeroInstance*>(commander->armyObj));
|
|
||||||
|
|
||||||
std::function<void()> Dsm;
|
|
||||||
CFunctionList<void()> fs[2];
|
|
||||||
//on dismiss confirmed
|
|
||||||
fs[0] += Dsm; //dismiss
|
|
||||||
fs[0] += std::bind(&CCreatureWindow::close,this);//close this window
|
|
||||||
CFunctionList<void()> cfl;
|
|
||||||
cfl = std::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector<CComponent*>());
|
|
||||||
if (type < COMMANDER_LEVEL_UP) //can dismiss only in regular window
|
|
||||||
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *StackNode, const CGHeroInstance *HeroOwner)
|
|
||||||
{
|
|
||||||
creatureArtifact = nullptr; //may be set later
|
|
||||||
artifactImage = nullptr;
|
|
||||||
spellEffectsPics = nullptr;
|
|
||||||
stack = Stack;
|
|
||||||
c = stack->type;
|
|
||||||
if(!StackNode)
|
|
||||||
stackNode = c;
|
|
||||||
else
|
|
||||||
stackNode = StackNode;
|
|
||||||
const CStack *battleStack = dynamic_cast<const CStack*>(stackNode); //only during battle
|
|
||||||
heroOwner = HeroOwner;
|
|
||||||
|
|
||||||
if (battleStack)
|
|
||||||
count = boost::lexical_cast<std::string>(battleStack->count);
|
|
||||||
else if (Stack->count)
|
|
||||||
count = boost::lexical_cast<std::string>(Stack->count);
|
|
||||||
|
|
||||||
if (type < COMMANDER)
|
|
||||||
commander = nullptr;
|
|
||||||
|
|
||||||
bool creArt = false;
|
|
||||||
displayedArtifact = ArtifactPosition::CREATURE_SLOT; // 0
|
|
||||||
|
|
||||||
//Basic graphics - need to calculate size
|
|
||||||
|
|
||||||
int commanderOffset = 0;
|
|
||||||
if (type >= COMMANDER)
|
|
||||||
commanderOffset = 74;
|
|
||||||
|
|
||||||
if (commander) //secondary skills
|
|
||||||
{
|
|
||||||
creArt = true;
|
|
||||||
for (int i = ECommander::ATTACK; i <= ECommander::SPELL_POWER; ++i)
|
|
||||||
{
|
|
||||||
if (commander->secondarySkills[i] || vstd::contains(upgradeOptions, i))
|
|
||||||
{
|
|
||||||
std::string file = skillToFile(i);
|
|
||||||
|
|
||||||
skillPictures.push_back(new CPicture(file, 0,0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == COMMANDER_LEVEL_UP)
|
|
||||||
{
|
|
||||||
for (auto option : upgradeOptions)
|
|
||||||
{
|
|
||||||
ui32 index = selectableSkills.size();
|
|
||||||
auto selectableSkill = new CSelectableSkill();
|
|
||||||
selectableSkill->callback = std::bind(&CCreatureWindow::selectSkill, this, index);
|
|
||||||
|
|
||||||
if (option < 100)
|
|
||||||
{
|
|
||||||
selectableSkill->pos = skillPictures[index]->pos; //resize
|
|
||||||
selectableSkills.push_back (selectableSkill);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
selectableSkill->pos = Rect (95, 256, 55, 55); //TODO: scroll
|
|
||||||
const Bonus *b = CGI->creh->skillRequirements[option-100].first;
|
|
||||||
bonusItems.push_back (new CBonusItem (genRect(0, 0, 251, 57), stack->bonusToString(b, false), stack->bonusToString(b, true), stack->bonusToGraphics(b)));
|
|
||||||
selectableBonuses.push_back (selectableSkill); //insert these before other bonuses
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BonusList bl, blTemp;
|
|
||||||
blTemp = (*(stackNode->getBonuses(Selector::durationType(Bonus::PERMANENT).And(Selector::anyRange()))));
|
|
||||||
|
|
||||||
while (blTemp.size())
|
|
||||||
{
|
|
||||||
Bonus * b = blTemp.front();
|
|
||||||
|
|
||||||
bl.push_back (new Bonus(*b));
|
|
||||||
bl.back()->val = blTemp.valOfBonuses(Selector::typeSubtype(b->type, b->subtype)); //merge multiple bonuses into one
|
|
||||||
blTemp.remove_if (Selector::typeSubtype(b->type, b->subtype)); //remove used bonuses
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string text, img;
|
|
||||||
for(Bonus* b : bl)
|
|
||||||
{
|
|
||||||
text = stack->bonusToString(b, false);
|
|
||||||
img = stack->bonusToGraphics(b);
|
|
||||||
if (text.size() || img.size()) //if it's possible to give any description or image for this kind of bonus
|
|
||||||
{
|
|
||||||
bonusItems.push_back (new CBonusItem(genRect(0, 0, 251, 57), text, stack->bonusToString(b, true), img));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//handle Magic resistance separately :/
|
|
||||||
const IBonusBearer *temp = stack;
|
|
||||||
|
|
||||||
if (battleStack)
|
|
||||||
{
|
|
||||||
temp = battleStack;
|
|
||||||
}
|
|
||||||
|
|
||||||
int magicResistance = temp->magicResistance();
|
|
||||||
|
|
||||||
if (magicResistance)
|
|
||||||
{
|
|
||||||
Bonus b;
|
|
||||||
b.type = Bonus::MAGIC_RESISTANCE;
|
|
||||||
|
|
||||||
text = VLC->getBth()->bonusToString(&b,temp,false);
|
|
||||||
const std::string description = VLC->getBth()->bonusToString(&b,temp,true);
|
|
||||||
bonusItems.push_back (new CBonusItem(genRect(0, 0, 251, 57), text, description, stack->bonusToGraphics(&b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
bonusRows = std::min ((int)((bonusItems.size() + 1) / 2), (screen->h - 230) / 60);
|
|
||||||
if (type >= COMMANDER)
|
|
||||||
vstd::amin(bonusRows, 3);
|
|
||||||
else
|
|
||||||
vstd::amin(bonusRows, 4);
|
|
||||||
vstd::amax(bonusRows, 1);
|
|
||||||
|
|
||||||
if (type >= COMMANDER)
|
|
||||||
{
|
|
||||||
setBackground("CommWin" + boost::lexical_cast<std::string>(bonusRows) + ".pcx");
|
|
||||||
for (int i = 0; i < skillPictures.size(); ++i)
|
|
||||||
{
|
|
||||||
skillPictures[i]->moveTo (Point (pos.x + 37 + i * 84, pos.y + 224));
|
|
||||||
}
|
|
||||||
for (int i = 0; i < selectableSkills.size(); ++i)
|
|
||||||
{
|
|
||||||
if (upgradeOptions[i] < skillPictures.size()) // it's secondary skill
|
|
||||||
{
|
|
||||||
selectableSkills[i]->pos = skillPictures[upgradeOptions[i]]->pos; //dirty workaround
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//print commander level
|
|
||||||
new CLabel(488, 62, FONT_MEDIUM, CENTER, Colors::YELLOW,
|
|
||||||
boost::lexical_cast<std::string>((ui16)(commander->level)));
|
|
||||||
|
|
||||||
new CLabel(488, 82, FONT_SMALL, CENTER, Colors::WHITE,
|
|
||||||
boost::lexical_cast<std::string>(stack->experience));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
setBackground("CreWin" + boost::lexical_cast<std::string>(bonusRows) + ".pcx"); //1 to 4 rows for now
|
|
||||||
|
|
||||||
//Buttons
|
|
||||||
ok = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, std::bind(&CCreatureWindow::close,this), 489, 148, "hsbtns.def", SDLK_RETURN);
|
|
||||||
ok->assignedKeys.insert(SDLK_ESCAPE);
|
|
||||||
|
|
||||||
if (type <= BATTLE) //in battle or info window
|
|
||||||
{
|
|
||||||
upgrade = nullptr;
|
|
||||||
dismiss = nullptr;
|
|
||||||
}
|
|
||||||
anim = new CCreaturePic(22, 48, c);
|
|
||||||
|
|
||||||
//Stats
|
|
||||||
morale = new MoraleLuckBox(true, genRect(42, 42, 335, 100));
|
|
||||||
morale->set(stackNode);
|
|
||||||
luck = new MoraleLuckBox(false, genRect(42, 42, 387, 100));
|
|
||||||
luck->set(stackNode);
|
|
||||||
|
|
||||||
new CAnimImage("PSKIL42", 4, 0, 387, 51); //exp icon - Print it always?
|
|
||||||
if (type) //not in fort window
|
|
||||||
{
|
|
||||||
if (CGI->modh->modules.STACK_EXP && type < COMMANDER)
|
|
||||||
{
|
|
||||||
int rank = std::min(stack->getExpRank(), 10); //hopefully nobody adds more
|
|
||||||
new CLabel(488, 82, FONT_SMALL, CENTER, Colors::WHITE, boost::lexical_cast<std::string>(stack->experience));
|
|
||||||
new CLabel(488, 62, FONT_MEDIUM, CENTER, Colors::YELLOW,
|
|
||||||
CGI->generaltexth->zcrexp[rank] + " [" + boost::lexical_cast<std::string>(rank) + "]");
|
|
||||||
|
|
||||||
if (type > BATTLE) //we need it only on adv. map
|
|
||||||
{
|
|
||||||
int tier = stack->type->level;
|
|
||||||
if (!vstd::iswithin(tier, 1, 7))
|
|
||||||
tier = 0;
|
|
||||||
int number;
|
|
||||||
std::string expText = CGI->generaltexth->zcrexp[324];
|
|
||||||
boost::replace_first (expText, "%s", c->namePl);
|
|
||||||
boost::replace_first (expText, "%s", CGI->generaltexth->zcrexp[rank]);
|
|
||||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(rank));
|
|
||||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->experience));
|
|
||||||
number = CGI->creh->expRanks[tier][rank] - stack->experience;
|
|
||||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
|
|
||||||
|
|
||||||
number = CGI->creh->maxExpPerBattle[tier]; //percent
|
|
||||||
boost::replace_first (expText, "%i%", boost::lexical_cast<std::string>(number));
|
|
||||||
number *= CGI->creh->expRanks[tier].back() / 100; //actual amount
|
|
||||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
|
|
||||||
|
|
||||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->count)); //Number of Creatures in stack
|
|
||||||
|
|
||||||
int expmin = std::max(CGI->creh->expRanks[tier][std::max(rank-1, 0)], (ui32)1);
|
|
||||||
number = (stack->count * (stack->experience - expmin)) / expmin; //Maximum New Recruits without losing current Rank
|
|
||||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //TODO
|
|
||||||
|
|
||||||
boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(1)); //TODO Experience Multiplier
|
|
||||||
number = CGI->creh->expAfterUpgrade;
|
|
||||||
boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(number) + "%"); //Upgrade Multiplier
|
|
||||||
|
|
||||||
expmin = CGI->creh->expRanks[tier][9];
|
|
||||||
int expmax = CGI->creh->expRanks[tier][10];
|
|
||||||
number = expmax - expmin;
|
|
||||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //Experience after Rank 10
|
|
||||||
number = (stack->count * (expmax - expmin)) / expmin;
|
|
||||||
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //Maximum New Recruits to remain at Rank 10 if at Maximum Experience
|
|
||||||
|
|
||||||
expArea = new LRClickableAreaWTextComp(Rect(334, 49, 160, 44),CComponent::experience);
|
|
||||||
expArea->text = expText;
|
|
||||||
expArea->bonusValue = 0; //TDO: some specific value or no number at all
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CGI->modh->modules.STACK_ARTIFACT)
|
|
||||||
{
|
|
||||||
creArt = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (creArt) //stack or commander artifacts
|
|
||||||
{
|
|
||||||
setArt (stack->getArt(ArtifactPosition::CREATURE_SLOT));
|
|
||||||
if (type > BATTLE && type < COMMANDER_BATTLE) //artifact buttons inactive in battle
|
|
||||||
{
|
|
||||||
//TODO: disable buttons if no artifact is equipped
|
|
||||||
leftArtRoll = new CAdventureMapButton(std::string(), std::string(), std::bind (&CCreatureWindow::scrollArt, this, -1), 437, 98, "hsbtns3.def", SDLK_LEFT);
|
|
||||||
rightArtRoll = new CAdventureMapButton(std::string(), std::string(), std::bind (&CCreatureWindow::scrollArt, this, +1), 516, 98, "hsbtns5.def", SDLK_RIGHT);
|
|
||||||
if (heroOwner)
|
|
||||||
passArtToHero = new CAdventureMapButton(std::string(), std::string(), std::bind (&CCreatureWindow::passArtifactToHero, this), 437, 148, "OVBUTN1.DEF", SDLK_HOME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (battleStack) //only during battle
|
|
||||||
{
|
|
||||||
spellEffectsPics = new CAnimation("SpellInt.def");
|
|
||||||
|
|
||||||
//spell effects
|
|
||||||
int printed=0; //how many effect pics have been printed
|
|
||||||
std::vector<si32> spells = battleStack->activeSpells();
|
|
||||||
for(si32 effect : spells)
|
|
||||||
{
|
|
||||||
const si32 imageIndex = effect+1; //there is "null" frame with index 0 in SpellInt.def
|
|
||||||
std::string spellText;
|
|
||||||
spellEffectsPics->load(imageIndex);
|
|
||||||
IImage * effectIcon = spellEffectsPics->getImage(imageIndex,0,false); //todo: better way to determine presence of icon
|
|
||||||
spellEffectsPics->unload(imageIndex);
|
|
||||||
if (effectIcon != nullptr) //not all effects have graphics (for eg. Acid Breath)
|
|
||||||
{
|
|
||||||
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
|
|
||||||
boost::replace_first (spellText, "%s", CGI->spellh->objects[effect]->name);
|
|
||||||
int duration = battleStack->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT,effect))->turnsRemain;
|
|
||||||
boost::replace_first (spellText, "%d", boost::lexical_cast<std::string>(duration));
|
|
||||||
|
|
||||||
new CAnimImage("SpellInt.def", imageIndex, 0, 20 + 52 * printed, 184);
|
|
||||||
spellEffects.push_back(new LRClickableAreaWText(Rect(20 + 52 * printed, 184, 50, 38), spellText, spellText));
|
|
||||||
if (++printed >= 10) //we can fit only 10 effects
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//print current health
|
|
||||||
printLine (5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bonusItems.size() > (bonusRows << 1)) //only after graphics are created
|
|
||||||
{
|
|
||||||
slider = new CSlider(528, 231 + commanderOffset, bonusRows*60, std::bind (&CCreatureWindow::sliderMoved, this, _1),
|
|
||||||
bonusRows, (bonusItems.size() + 1) >> 1, 0, false, 0);
|
|
||||||
}
|
|
||||||
else //slider automatically places bonus Items
|
|
||||||
recreateSkillList (0);
|
|
||||||
|
|
||||||
showAll(screen2);
|
|
||||||
|
|
||||||
//AUIDAT.DEF
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::printLine(int nr, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
|
|
||||||
{
|
|
||||||
new CLabel(162, 48 + nr*19, FONT_SMALL, TOPLEFT, Colors::WHITE, text);
|
|
||||||
|
|
||||||
std::string hlp;
|
|
||||||
if(range && baseVal != val)
|
|
||||||
hlp = boost::str(boost::format("%d - %d") % baseVal % val);
|
|
||||||
else if(baseVal != val && val>=0)
|
|
||||||
hlp = boost::str(boost::format("%d (%d)") % baseVal % val);
|
|
||||||
else
|
|
||||||
hlp = boost::lexical_cast<std::string>(baseVal);
|
|
||||||
|
|
||||||
new CLabel(325, 64 + nr*19, FONT_SMALL, BOTTOMRIGHT, Colors::WHITE, hlp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::recreateSkillList(int Pos)
|
|
||||||
{
|
|
||||||
int commanderOffset = 0;
|
|
||||||
if (type >= COMMANDER)
|
|
||||||
commanderOffset = 74;
|
|
||||||
|
|
||||||
int n = 0, i = 0, j = 0;
|
|
||||||
int numSkills = std::min ((bonusRows + Pos) << 1, (int)bonusItems.size());
|
|
||||||
for (n = 0; n < Pos << 1; ++n)
|
|
||||||
{
|
|
||||||
bonusItems[n]->visible = false;
|
|
||||||
if (n < selectableBonuses.size())
|
|
||||||
selectableBonuses[n]->deactivate(); //we assume that bonuses are at front of the list
|
|
||||||
}
|
|
||||||
for (n = Pos << 1; n < numSkills; ++n)
|
|
||||||
{
|
|
||||||
int offsetx = 257*j - (bonusRows == 4 ? 1 : 0);
|
|
||||||
int offsety = 60*i + (bonusRows > 1 ? 1 : 0) + commanderOffset; //lack of precision :/
|
|
||||||
|
|
||||||
bonusItems[n]->moveTo (Point(pos.x + offsetx + 10, pos.y + offsety + 230), true);
|
|
||||||
bonusItems[n]->visible = true;
|
|
||||||
if (n < selectableBonuses.size())
|
|
||||||
{
|
|
||||||
selectableBonuses[n]->moveTo (Point(bonusItems[n]->pos.x + 12, bonusItems[n]->pos.y + 2)); //for some reason bonusItems have dimensions 0?
|
|
||||||
//selectableBonuses[n]->pos = bonusItems[n]->bonusGraphics->pos;
|
|
||||||
selectableBonuses[n]->activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (++j > 1) //next line
|
|
||||||
{
|
|
||||||
++i;
|
|
||||||
j = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (n = numSkills; n < bonusItems.size(); ++n)
|
|
||||||
{
|
|
||||||
bonusItems[n]->visible = false;
|
|
||||||
if (n < selectableBonuses.size())
|
|
||||||
selectableBonuses[n]->deactivate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::showAll(SDL_Surface * to)
|
|
||||||
{
|
|
||||||
CIntObject::showAll(to);
|
|
||||||
|
|
||||||
printAtMiddleLoc((type >= COMMANDER ? c->nameSing : c->namePl), 180, 30, FONT_SMALL, Colors::YELLOW, to); //creature name
|
|
||||||
|
|
||||||
printLine(0, CGI->generaltexth->primarySkillNames[0], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->Attack());
|
|
||||||
printLine(1, CGI->generaltexth->primarySkillNames[1], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->Defense());
|
|
||||||
|
|
||||||
if (stackNode->valOfBonuses(Bonus::SHOTS) && stackNode->hasBonusOfType(Bonus::SHOOTER))
|
|
||||||
{//only for shooting units - important with wog exp shooters
|
|
||||||
if (type == BATTLE)
|
|
||||||
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS), dynamic_cast<const CStack*>(stackNode)->shots);
|
|
||||||
else
|
|
||||||
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS));
|
|
||||||
}
|
|
||||||
if (stackNode->valOfBonuses(Bonus::CASTS))
|
|
||||||
{
|
|
||||||
printAtMiddleLoc(CGI->generaltexth->allTexts[399], 356, 62, FONT_SMALL, Colors::WHITE, to);
|
|
||||||
std::string casts;
|
|
||||||
if (type == BATTLE)
|
|
||||||
casts = boost::lexical_cast<std::string>((ui16)dynamic_cast<const CStack*>(stackNode)->casts); //ui8 is converted to char :(
|
|
||||||
else
|
|
||||||
casts = boost::lexical_cast<std::string>(stackNode->valOfBonuses(Bonus::CASTS));
|
|
||||||
printAtMiddleLoc(casts, 356, 82, FONT_SMALL, Colors::WHITE, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO
|
|
||||||
int dmgMultiply = 1;
|
|
||||||
if(heroOwner && stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
|
||||||
dmgMultiply += heroOwner->Attack();
|
|
||||||
|
|
||||||
printLine(3, CGI->generaltexth->allTexts[199], stackNode->getMinDamage() * dmgMultiply, stackNode->getMaxDamage() * dmgMultiply, true);
|
|
||||||
printLine(4, CGI->generaltexth->allTexts[388], c->valOfBonuses(Bonus::STACK_HEALTH), stackNode->valOfBonuses(Bonus::STACK_HEALTH));
|
|
||||||
printLine(6, CGI->generaltexth->zelp[441].first, c->Speed(), stackNode->Speed());
|
|
||||||
|
|
||||||
for(CBonusItem* b : bonusItems)
|
|
||||||
b->showAll (to);
|
|
||||||
|
|
||||||
for(auto s : selectableSkills)
|
|
||||||
s->showAll (to);
|
|
||||||
|
|
||||||
for (int i = 0; i < skillPictures.size(); i++)
|
|
||||||
{
|
|
||||||
skillPictures[i]->bg = BitmapHandler::loadBitmap (skillToFile(i));
|
|
||||||
skillPictures[i]->showAll (to);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (upgradeOptions.size() && (type == COMMANDER_LEVEL_UP && upgradeOptions[selectedOption] >= 100)) //add frame to selected skill
|
|
||||||
{
|
|
||||||
int index = selectedOption - selectableSkills.size(); //this is screwed
|
|
||||||
CSDL_Ext::drawBorder(to, Rect::around(selectableBonuses[index]->pos), int3(Colors::METALLIC_GOLD.r, Colors::METALLIC_GOLD.g, Colors::METALLIC_GOLD.b));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::show(SDL_Surface * to)
|
|
||||||
{
|
|
||||||
CIntObject::show(to);
|
|
||||||
if (!count.empty()) //army stack
|
|
||||||
graphics->fonts[FONT_TIMES]->renderTextRight(to, count, Colors::WHITE, Point(pos.x + 114, pos.y + 174));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CCreatureWindow::close()
|
|
||||||
{
|
|
||||||
if (upgradeOptions.size()) //a skill for commander was chosen
|
|
||||||
levelUp (selectedOption); //callback value is vector index
|
|
||||||
|
|
||||||
GH.popIntTotally(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::sliderMoved(int newpos)
|
|
||||||
{
|
|
||||||
recreateSkillList(newpos); //move components
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CCreatureWindow::skillToFile (int skill)
|
|
||||||
{
|
|
||||||
std::string file = "zvs/Lib1.res/_";
|
|
||||||
switch (skill)
|
|
||||||
{
|
|
||||||
case ECommander::ATTACK:
|
|
||||||
file += "AT";
|
|
||||||
break;
|
|
||||||
case ECommander::DEFENSE:
|
|
||||||
file += "DF";
|
|
||||||
break;
|
|
||||||
case ECommander::HEALTH:
|
|
||||||
file += "HP";
|
|
||||||
break;
|
|
||||||
case ECommander::DAMAGE:
|
|
||||||
file += "DM";
|
|
||||||
break;
|
|
||||||
case ECommander::SPEED:
|
|
||||||
file += "SP";
|
|
||||||
break;
|
|
||||||
case ECommander::SPELL_POWER:
|
|
||||||
file += "MP";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
std::string sufix = boost::lexical_cast<std::string>((int)(commander->secondarySkills[skill])); //casting ui8 causes ascii char conversion
|
|
||||||
if (type == COMMANDER_LEVEL_UP)
|
|
||||||
{
|
|
||||||
if (upgradeOptions.size() && upgradeOptions[selectedOption] == skill)//that one specific skill is selected
|
|
||||||
sufix += "="; //level-up highlight
|
|
||||||
else if (!vstd::contains(upgradeOptions, skill))
|
|
||||||
sufix = "no"; //not available - no number
|
|
||||||
}
|
|
||||||
file += sufix += ".bmp";
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::setArt(const CArtifactInstance *art)
|
|
||||||
{
|
|
||||||
creatureArtifact = art;
|
|
||||||
if (creatureArtifact)
|
|
||||||
{
|
|
||||||
if (artifactImage == nullptr)
|
|
||||||
artifactImage = new CAnimImage("ARTIFACT", creatureArtifact->artType->iconIndex, 0, 466, 100);
|
|
||||||
else
|
|
||||||
artifactImage->setFrame(creatureArtifact->artType->iconIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
artifactImage = nullptr;
|
|
||||||
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::scrollArt(int dir)
|
|
||||||
{
|
|
||||||
//TODO: get next artifact
|
|
||||||
int size = stack->artifactsWorn.size();
|
|
||||||
displayedArtifact = size ? static_cast<ArtifactPosition>((displayedArtifact + dir) % size)
|
|
||||||
: static_cast<ArtifactPosition>(ArtifactPosition::CREATURE_SLOT);
|
|
||||||
setArt (stack->getArt(displayedArtifact));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::passArtifactToHero()
|
|
||||||
{
|
|
||||||
const CGHeroInstance * h = dynamic_cast<const CGHeroInstance *>(stack->armyObj);
|
|
||||||
if (h && creatureArtifact)
|
|
||||||
{
|
|
||||||
LOCPLINT->cb->swapArtifacts (ArtifactLocation (stack, displayedArtifact), ArtifactLocation(h, creatureArtifact->firstBackpackSlot(h)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
logGlobal->warnStream() << "Pass artifact to hero should be disabled, no hero or no artifact!";
|
|
||||||
|
|
||||||
//redraw is handled via CArtifactHolder interface
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::artifactRemoved (const ArtifactLocation &artLoc)
|
|
||||||
{
|
|
||||||
//align artifacts to remove holes
|
|
||||||
for (auto al : stack->artifactsWorn)
|
|
||||||
{
|
|
||||||
ArtifactPosition freeSlot = al.second.artifact->firstAvailableSlot(stack);
|
|
||||||
if (freeSlot < al.first)
|
|
||||||
LOCPLINT->cb->swapArtifacts (ArtifactLocation(stack, al.first), ArtifactLocation(stack, freeSlot));
|
|
||||||
}
|
|
||||||
int size = stack->artifactsWorn.size();
|
|
||||||
displayedArtifact = size ? static_cast<ArtifactPosition>(displayedArtifact % size)
|
|
||||||
: static_cast<ArtifactPosition>(ArtifactPosition::CREATURE_SLOT); //0
|
|
||||||
setArt (stack->getArt(displayedArtifact));
|
|
||||||
}
|
|
||||||
void CCreatureWindow::artifactMoved (const ArtifactLocation &artLoc, const ArtifactLocation &destLoc)
|
|
||||||
{
|
|
||||||
artifactRemoved (artLoc); //same code
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreatureWindow::selectSkill (ui32 which)
|
|
||||||
{
|
|
||||||
selectedOption = which;
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
CCreatureWindow::~CCreatureWindow()
|
|
||||||
{
|
|
||||||
for (auto & elem : upgResCost)
|
|
||||||
delete elem;
|
|
||||||
bonusItems.clear();
|
|
||||||
|
|
||||||
if(spellEffectsPics!=nullptr)
|
|
||||||
delete spellEffectsPics;
|
|
||||||
}
|
|
||||||
|
|
||||||
CBonusItem::CBonusItem()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CBonusItem::CBonusItem(const Rect &Pos, const std::string &Name, const std::string &Description, const std::string &graphicsName)
|
|
||||||
{
|
|
||||||
OBJ_CONSTRUCTION;
|
|
||||||
visible = false;
|
|
||||||
|
|
||||||
name = Name;
|
|
||||||
description = Description;
|
|
||||||
if (graphicsName.size())
|
|
||||||
bonusGraphics = new CPicture(graphicsName, 26, 232);
|
|
||||||
else
|
|
||||||
bonusGraphics = nullptr;
|
|
||||||
|
|
||||||
removeUsedEvents(ALL); //no actions atm
|
|
||||||
}
|
|
||||||
|
|
||||||
void CBonusItem::showAll (SDL_Surface * to)
|
|
||||||
{
|
|
||||||
if (visible)
|
|
||||||
{
|
|
||||||
graphics->fonts[FONT_SMALL]->renderTextLeft(to, name, Colors::YELLOW, Point(pos.x + 72, pos.y + 6));
|
|
||||||
graphics->fonts[FONT_SMALL]->renderTextLeft(to, description, Colors::WHITE, Point(pos.x + 72, pos.y + 30));
|
|
||||||
if (bonusGraphics && bonusGraphics->bg)
|
|
||||||
blitAtLoc(bonusGraphics->bg, 12, 2, to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CBonusItem::~CBonusItem()
|
|
||||||
{
|
|
||||||
//delete bonusGraphics; //automatic destruction
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSelectableSkill::clickLeft(tribool down, bool previousState)
|
|
||||||
{
|
|
||||||
if (down)
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreInfoWindow::show(SDL_Surface * to)
|
|
||||||
{
|
|
||||||
CIntObject::show(to);
|
|
||||||
creatureCount->showAll(to);
|
|
||||||
}
|
|
||||||
|
|
||||||
CCreInfoWindow::CCreInfoWindow(const CStackInstance &stack, bool LClicked, std::function<void()> upgradeFunc, std::function<void()> dismissFunc, UpgradeInfo *upgradeInfo):
|
|
||||||
CWindowObject(PLAYER_COLORED | (LClicked ? 0 : RCLICK_POPUP), "CRSTKPU")
|
|
||||||
{
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
||||||
init(stack.type, &stack, dynamic_cast<const CGHeroInstance*>(stack.armyObj), stack.count, LClicked);
|
|
||||||
|
|
||||||
//additional buttons if opened with left click
|
|
||||||
if(LClicked)
|
|
||||||
{
|
|
||||||
std::function<void()> closeFunc = std::bind(&CCreInfoWindow::close,this);
|
|
||||||
|
|
||||||
if(upgradeFunc && upgradeInfo)
|
|
||||||
{
|
|
||||||
TResources upgradeCost = upgradeInfo->cost[0] * stack.count;
|
|
||||||
for(TResources::nziterator i(upgradeCost); i.valid(); i++)
|
|
||||||
{
|
|
||||||
BLOCK_CAPTURING;
|
|
||||||
upgResCost.push_back(new CComponent(CComponent::resource, i->resType, i->resVal));
|
|
||||||
}
|
|
||||||
|
|
||||||
CFunctionList<void()> onUpgrade;
|
|
||||||
onUpgrade += upgradeFunc;
|
|
||||||
onUpgrade += closeFunc;
|
|
||||||
|
|
||||||
std::function<void()> dialog = std::bind(&CPlayerInterface::showYesNoDialog,
|
|
||||||
LOCPLINT,
|
|
||||||
CGI->generaltexth->allTexts[207],
|
|
||||||
onUpgrade, 0, false,
|
|
||||||
std::ref(upgResCost));
|
|
||||||
|
|
||||||
upgrade = new CAdventureMapButton("", CGI->generaltexth->zelp[446].second, dialog, 76, 237, "IVIEWCR", SDLK_u);
|
|
||||||
upgrade->block(!LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(dismissFunc)
|
|
||||||
{
|
|
||||||
CFunctionList<void()> onDismiss;
|
|
||||||
onDismiss += dismissFunc;
|
|
||||||
onDismiss += closeFunc;
|
|
||||||
|
|
||||||
std::function<void()> dialog = std::bind(&CPlayerInterface::showYesNoDialog,
|
|
||||||
LOCPLINT,
|
|
||||||
CGI->generaltexth->allTexts[12],
|
|
||||||
onDismiss, 0, true, std::vector<CComponent*>());
|
|
||||||
|
|
||||||
dismiss = new CAdventureMapButton("", CGI->generaltexth->zelp[445].second, dialog, 21, 237, "IVIEWCR2",SDLK_d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CCreInfoWindow::CCreInfoWindow(int creatureID, bool LClicked, int creatureCount):
|
|
||||||
CWindowObject(PLAYER_COLORED | (LClicked ? 0 : RCLICK_POPUP), "CRSTKPU")
|
|
||||||
{
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
||||||
const CCreature *creature = CGI->creh->creatures[creatureID];
|
|
||||||
init(creature, nullptr, nullptr, creatureCount, LClicked);
|
|
||||||
}
|
|
||||||
|
|
||||||
CCreInfoWindow::CCreInfoWindow(const CStack &stack, bool LClicked):
|
|
||||||
CWindowObject(PLAYER_COLORED | (LClicked ? 0 : RCLICK_POPUP), "CRSTKPU")
|
|
||||||
{
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
||||||
init(stack.getCreature(), &stack, stack.getMyHero(), stack.count, LClicked);
|
|
||||||
}
|
|
||||||
|
|
||||||
CCreInfoWindow::~CCreInfoWindow()
|
|
||||||
{
|
|
||||||
for(CComponent* object : upgResCost)
|
|
||||||
delete object;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreInfoWindow::printLine(int position, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
|
|
||||||
{
|
|
||||||
infoTexts[position].first = new CLabel(155, 48 + position*19, FONT_SMALL, TOPLEFT, Colors::WHITE, text);
|
|
||||||
std::string valueStr;
|
|
||||||
|
|
||||||
if(range && baseVal != val)
|
|
||||||
valueStr = boost::str(boost::format("%d - %d") % baseVal % val);
|
|
||||||
|
|
||||||
else if(baseVal != val && val>=0)
|
|
||||||
valueStr = boost::str(boost::format("%d (%d)") % baseVal % val);
|
|
||||||
|
|
||||||
else
|
|
||||||
valueStr = boost::lexical_cast<std::string>(baseVal);
|
|
||||||
|
|
||||||
infoTexts[position].second = new CLabel(276, 63 + position*19, FONT_SMALL, BOTTOMRIGHT, Colors::WHITE, valueStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CCreInfoWindow::init(const CCreature *creature, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner, int count, bool LClicked)
|
|
||||||
{
|
|
||||||
removeUsedEvents(ALL);
|
|
||||||
if (!LClicked)
|
|
||||||
addUsedEvents(RCLICK);
|
|
||||||
|
|
||||||
if(!stackNode)
|
|
||||||
stackNode = creature;
|
|
||||||
|
|
||||||
animation = new CCreaturePic(21, 48, creature);
|
|
||||||
|
|
||||||
std::string countStr = boost::lexical_cast<std::string>(count);
|
|
||||||
creatureCount = new CLabel(114, 174, FONT_TIMES, BOTTOMRIGHT, Colors::WHITE, countStr);
|
|
||||||
|
|
||||||
creatureName = new CLabel(149, 30, FONT_SMALL, CENTER, Colors::YELLOW, creature->namePl);
|
|
||||||
|
|
||||||
printLine(0, CGI->generaltexth->primarySkillNames[0], creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK));
|
|
||||||
printLine(1, CGI->generaltexth->primarySkillNames[1], creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE));
|
|
||||||
|
|
||||||
if(stackNode->valOfBonuses(Bonus::SHOTS))
|
|
||||||
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS));
|
|
||||||
|
|
||||||
//TODO
|
|
||||||
int dmgMultiply = 1;
|
|
||||||
if(heroOwner && stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
|
||||||
dmgMultiply += heroOwner->Attack();
|
|
||||||
|
|
||||||
printLine(3, CGI->generaltexth->allTexts[199], stackNode->getMinDamage() * dmgMultiply, stackNode->getMaxDamage() * dmgMultiply, true);
|
|
||||||
printLine(4, CGI->generaltexth->allTexts[388], creature->valOfBonuses(Bonus::STACK_HEALTH), stackNode->valOfBonuses(Bonus::STACK_HEALTH));
|
|
||||||
printLine(6, CGI->generaltexth->zelp[441].first, creature->valOfBonuses(Bonus::STACKS_SPEED), stackNode->valOfBonuses(Bonus::STACKS_SPEED));
|
|
||||||
|
|
||||||
//setting morale
|
|
||||||
morale = new MoraleLuckBox(true, genRect(42, 42, 22, 186));
|
|
||||||
morale->set(stackNode);
|
|
||||||
//setting luck
|
|
||||||
luck = new MoraleLuckBox(false, genRect(42, 42, 75, 186));
|
|
||||||
luck->set(stackNode);
|
|
||||||
|
|
||||||
if(!LClicked)
|
|
||||||
{
|
|
||||||
abilityText = new CLabel(17, 231, FONT_SMALL, TOPLEFT, Colors::WHITE, creature->abilityText);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
abilityText = nullptr;
|
|
||||||
ok = new CAdventureMapButton("", CGI->generaltexth->zelp[445].second,
|
|
||||||
std::bind(&CCreInfoWindow::close,this), 216, 237, "IOKAY.DEF", SDLK_RETURN);
|
|
||||||
ok->assignedKeys.insert(SDLK_ESCAPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we are displying window fo r stack in battle, there are several more things that we need to display
|
|
||||||
if(const CStack *battleStack = dynamic_cast<const CStack*>(stackNode))
|
|
||||||
{
|
|
||||||
//print at most 3 spell effects
|
|
||||||
std::vector<si32> spells = battleStack->activeSpells();
|
|
||||||
for (size_t i=0; i< std::min(spells.size(), size_t(3)); i++)
|
|
||||||
effects.push_back(new CAnimImage("SpellInt", spells[i]+1, 0, 127 + 52*i, 186));
|
|
||||||
|
|
||||||
//print current health
|
|
||||||
printLine(5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CIntObject * createCreWindow(
|
|
||||||
const CStack *s, bool lclick/* = false*/)
|
|
||||||
{
|
|
||||||
auto c = dynamic_cast<const CCommanderInstance *>(s->base);
|
|
||||||
if (c)
|
|
||||||
{
|
|
||||||
return new CCreatureWindow (c, s);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(settings["general"]["classicCreatureWindow"].Bool())
|
|
||||||
return new CCreInfoWindow(*s, lclick);
|
|
||||||
else
|
|
||||||
return new CCreatureWindow(*s, LOCPLINT->battleInt ? CCreatureWindow::BATTLE : CCreatureWindow::OTHER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CIntObject * createCreWindow(CreatureID Cid, CCreatureWindow::CreWinType Type, int creatureCount)
|
|
||||||
{
|
|
||||||
if(settings["general"]["classicCreatureWindow"].Bool())
|
|
||||||
return new CCreInfoWindow(Cid, Type, creatureCount);
|
|
||||||
else
|
|
||||||
return new CCreatureWindow(Cid, Type, creatureCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
CIntObject * createCreWindow(const CStackInstance *s, CCreatureWindow::CreWinType type, std::function<void()> Upg, std::function<void()> Dsm, UpgradeInfo *ui)
|
|
||||||
{
|
|
||||||
if(settings["general"]["classicCreatureWindow"].Bool())
|
|
||||||
return new CCreInfoWindow(*s, type==CCreatureWindow::HERO, Upg, Dsm, ui);
|
|
||||||
else
|
|
||||||
return new CCreatureWindow(*s, type, Upg, Dsm, ui);
|
|
||||||
}
|
|
@ -1,163 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "gui/CIntObject.h"
|
|
||||||
#include "../lib/HeroBonus.h"
|
|
||||||
#include "GUIClasses.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CCreatureWindow.h, part of VCMI engine
|
|
||||||
*
|
|
||||||
* Authors: listed in file AUTHORS in main folder
|
|
||||||
*
|
|
||||||
* License: GNU General Public License v2.0 or later
|
|
||||||
* Full text of license available in license.txt file, in main folder
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct Bonus;
|
|
||||||
class CCreature;
|
|
||||||
class CStackInstance;
|
|
||||||
class CCommanderInstance;
|
|
||||||
class CStack;
|
|
||||||
struct ArtifactLocation;
|
|
||||||
class CCreatureArtifactInstance;
|
|
||||||
class CAdventureMapButton;
|
|
||||||
class CBonusItem;
|
|
||||||
class CGHeroInstance;
|
|
||||||
class CComponent;
|
|
||||||
class LRClickableAreaWText;
|
|
||||||
class MoraleLuckBox;
|
|
||||||
class CAdventureMapButton;
|
|
||||||
struct UpgradeInfo;
|
|
||||||
class CPicture;
|
|
||||||
class CCreaturePic;
|
|
||||||
class LRClickableAreaWTextComp;
|
|
||||||
class CSlider;
|
|
||||||
class CLabel;
|
|
||||||
class CAnimImage;
|
|
||||||
class CSelectableSkill;
|
|
||||||
|
|
||||||
// New creature window
|
|
||||||
class CCreatureWindow : public CWindowObject, public CArtifactHolder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum CreWinType {OTHER = 0, BATTLE = 1, ARMY = 2, HERO = 3, COMMANDER = 4, COMMANDER_LEVEL_UP = 5, COMMANDER_BATTLE = 6}; // > 3 are opened permanently
|
|
||||||
//bool active; //TODO: comment me
|
|
||||||
CreWinType type;
|
|
||||||
int bonusRows; //height of skill window
|
|
||||||
ArtifactPosition displayedArtifact;
|
|
||||||
|
|
||||||
std::string count; //creature count in text format
|
|
||||||
const CCreature *c; //related creature
|
|
||||||
const CStackInstance *stack;
|
|
||||||
const CBonusSystemNode *stackNode;
|
|
||||||
const CCommanderInstance * commander;
|
|
||||||
const CGHeroInstance *heroOwner;
|
|
||||||
const CArtifactInstance *creatureArtifact; //currently worn artifact
|
|
||||||
std::vector<CComponent*> upgResCost; //cost of upgrade (if not possible then empty)
|
|
||||||
std::vector<CBonusItem*> bonusItems;
|
|
||||||
std::vector<LRClickableAreaWText*> spellEffects;
|
|
||||||
|
|
||||||
CCreaturePic *anim; //related creature's animation
|
|
||||||
MoraleLuckBox *luck, *morale;
|
|
||||||
LRClickableAreaWTextComp * expArea; //displays exp details
|
|
||||||
CSlider * slider; //Abilities
|
|
||||||
CAdventureMapButton *dismiss, *upgrade, *ok;
|
|
||||||
CAdventureMapButton * leftArtRoll, * rightArtRoll; //artifact selection
|
|
||||||
CAdventureMapButton * passArtToHero;
|
|
||||||
CAnimImage * artifactImage;
|
|
||||||
CAnimation * spellEffectsPics; //bitmaps representing spells affecting a stack in battle
|
|
||||||
|
|
||||||
//commander level-up
|
|
||||||
int selectedOption; //index for upgradeOptions
|
|
||||||
std::vector<ui32> upgradeOptions; //value 0-5 - secondary skills, 100+ - special skills
|
|
||||||
std::vector<CSelectableSkill *> selectableSkills, selectableBonuses;
|
|
||||||
std::vector<CPicture *> skillPictures; //secondary skills
|
|
||||||
|
|
||||||
std::string skillToFile(int skill); //return bitmap for secondary skill depending on selection / avaliability
|
|
||||||
void selectSkill (ui32 which);
|
|
||||||
void setArt(const CArtifactInstance *creatureArtifact);
|
|
||||||
|
|
||||||
void artifactRemoved (const ArtifactLocation &artLoc);
|
|
||||||
void artifactMoved (const ArtifactLocation &artLoc, const ArtifactLocation &destLoc);
|
|
||||||
void artifactDisassembled (const ArtifactLocation &artLoc) {return;};
|
|
||||||
void artifactAssembled (const ArtifactLocation &artLoc) {return;};
|
|
||||||
|
|
||||||
std::function<void()> dsm; //dismiss button callback
|
|
||||||
std::function<void()> Upg; //upgrade button callback
|
|
||||||
std::function<void(ui32)> levelUp; //choose commander skill to level up
|
|
||||||
|
|
||||||
CCreatureWindow(const CStack & stack, CreWinType type); //battle c-tor
|
|
||||||
CCreatureWindow (const CStackInstance &stack, CreWinType Type); //pop-up c-tor
|
|
||||||
CCreatureWindow(const CStackInstance &st, CreWinType Type, std::function<void()> Upg, std::function<void()> Dsm, UpgradeInfo *ui); //full garrison window
|
|
||||||
CCreatureWindow(const CCommanderInstance * commander, const CStack * stack = nullptr); //commander window
|
|
||||||
CCreatureWindow(std::vector<ui32> &skills, const CCommanderInstance * commander, std::function<void(ui32)> callback);
|
|
||||||
CCreatureWindow(CreatureID Cid, CreWinType Type, int creatureCount); //c-tor
|
|
||||||
|
|
||||||
void init(const CStackInstance *stack, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner);
|
|
||||||
void showAll(SDL_Surface * to);
|
|
||||||
void show(SDL_Surface * to);
|
|
||||||
void printLine(int nr, const std::string &text, int baseVal, int val=-1, bool range=false);
|
|
||||||
void sliderMoved(int newpos);
|
|
||||||
void close();
|
|
||||||
~CCreatureWindow(); //d-tor
|
|
||||||
|
|
||||||
void recreateSkillList(int pos);
|
|
||||||
void scrollArt(int dir);
|
|
||||||
void passArtifactToHero();
|
|
||||||
};
|
|
||||||
|
|
||||||
class CBonusItem : public LRClickableAreaWTextComp //responsible for displaying creature skill, active or not
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::string name, description;
|
|
||||||
CPicture * bonusGraphics;
|
|
||||||
bool visible;
|
|
||||||
|
|
||||||
CBonusItem();
|
|
||||||
CBonusItem(const Rect &Pos, const std::string &Name, const std::string &Description, const std::string &graphicsName);
|
|
||||||
~CBonusItem();
|
|
||||||
|
|
||||||
void showAll (SDL_Surface * to);
|
|
||||||
};
|
|
||||||
|
|
||||||
class CSelectableSkill : public LRClickableAreaWText
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::function<void()> callback; //TODO: create more generic clickable class than AdvMapButton?
|
|
||||||
|
|
||||||
virtual void clickLeft(tribool down, bool previousState);
|
|
||||||
virtual void clickRight(tribool down, bool previousState){};
|
|
||||||
};
|
|
||||||
|
|
||||||
/// original creature info window
|
|
||||||
class CCreInfoWindow : public CWindowObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CLabel * creatureCount;
|
|
||||||
CLabel * creatureName;
|
|
||||||
CLabel * abilityText;
|
|
||||||
|
|
||||||
CCreaturePic * animation;
|
|
||||||
std::vector<CComponent *> upgResCost; //cost of upgrade (if not possible then empty)
|
|
||||||
std::vector<CAnimImage *> effects;
|
|
||||||
std::map<size_t, std::pair<CLabel *, CLabel * > > infoTexts;
|
|
||||||
|
|
||||||
MoraleLuckBox * luck, * morale;
|
|
||||||
|
|
||||||
CAdventureMapButton * dismiss, * upgrade, * ok;
|
|
||||||
|
|
||||||
CCreInfoWindow(const CStackInstance & st, bool LClicked, std::function<void()> Upg = nullptr, std::function<void()> Dsm = nullptr, UpgradeInfo * ui = nullptr);
|
|
||||||
CCreInfoWindow(const CStack & st, bool LClicked = 0);
|
|
||||||
CCreInfoWindow(int Cid, bool LClicked, int creatureCount);
|
|
||||||
~CCreInfoWindow();
|
|
||||||
|
|
||||||
void init(const CCreature * cre, const CBonusSystemNode * stackNode, const CGHeroInstance * heroOwner, int creatureCount, bool LClicked);
|
|
||||||
void printLine(int nr, const std::string & text, int baseVal, int val = -1, bool range = false);
|
|
||||||
|
|
||||||
void show(SDL_Surface * to);
|
|
||||||
};
|
|
||||||
|
|
||||||
CIntObject *createCreWindow(const CStack *s, bool lclick = false);
|
|
||||||
CIntObject *createCreWindow(CreatureID Cid, CCreatureWindow::CreWinType Type, int creatureCount);
|
|
||||||
CIntObject *createCreWindow(const CStackInstance *s, CCreatureWindow::CreWinType type, std::function<void()> Upg = nullptr, std::function<void()> Dsm = nullptr, UpgradeInfo *ui = nullptr);
|
|
@ -8,13 +8,13 @@
|
|||||||
|
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "CPreGame.h"
|
#include "CPreGame.h"
|
||||||
#include "CCastleInterface.h"
|
#include "windows/CCastleInterface.h"
|
||||||
#include "../lib/CConsoleHandler.h"
|
#include "../lib/CConsoleHandler.h"
|
||||||
#include "gui/CCursorHandler.h"
|
#include "gui/CCursorHandler.h"
|
||||||
#include "../lib/CGameState.h"
|
#include "../lib/CGameState.h"
|
||||||
#include "../CCallback.h"
|
#include "../CCallback.h"
|
||||||
#include "CPlayerInterface.h"
|
#include "CPlayerInterface.h"
|
||||||
#include "CAdvmapInterface.h"
|
#include "windows/CAdvmapInterface.h"
|
||||||
#include "../lib/CBuildingHandler.h"
|
#include "../lib/CBuildingHandler.h"
|
||||||
#include "CVideoHandler.h"
|
#include "CVideoHandler.h"
|
||||||
#include "../lib/CHeroHandler.h"
|
#include "../lib/CHeroHandler.h"
|
||||||
@ -39,6 +39,7 @@
|
|||||||
#include "../lib/GameConstants.h"
|
#include "../lib/GameConstants.h"
|
||||||
#include "gui/CGuiHandler.h"
|
#include "gui/CGuiHandler.h"
|
||||||
#include "../lib/logging/CBasicLogConfigurator.h"
|
#include "../lib/logging/CBasicLogConfigurator.h"
|
||||||
|
#include "../lib/CondSh.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "SDL_syswm.h"
|
#include "SDL_syswm.h"
|
||||||
|
@ -14,39 +14,56 @@ set(client_SRCS
|
|||||||
battle/CBattleInterfaceClasses.cpp
|
battle/CBattleInterfaceClasses.cpp
|
||||||
battle/CCreatureAnimation.cpp
|
battle/CCreatureAnimation.cpp
|
||||||
|
|
||||||
|
gui/CAnimation.cpp
|
||||||
|
gui/CCursorHandler.cpp
|
||||||
gui/CGuiHandler.cpp
|
gui/CGuiHandler.cpp
|
||||||
gui/CIntObject.cpp
|
gui/CIntObject.cpp
|
||||||
gui/CIntObjectClasses.cpp
|
|
||||||
gui/Fonts.cpp
|
gui/Fonts.cpp
|
||||||
gui/Geometries.cpp
|
gui/Geometries.cpp
|
||||||
gui/CCursorHandler.cpp
|
|
||||||
gui/SDL_Extensions.cpp
|
gui/SDL_Extensions.cpp
|
||||||
|
|
||||||
CPreGame.cpp
|
widgets/AdventureMapClasses.cpp
|
||||||
Client.cpp
|
widgets/Buttons.cpp
|
||||||
CPlayerInterface.cpp
|
widgets/CArtifactHolder.cpp
|
||||||
CMT.cpp
|
widgets/CComponent.cpp
|
||||||
GUIClasses.cpp
|
widgets/CGarrisonInt.cpp
|
||||||
AdventureMapClasses.cpp
|
widgets/Images.cpp
|
||||||
CAdvmapInterface.cpp
|
widgets/MiscWidgets.cpp
|
||||||
CAnimation.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
|
CBitmapHandler.cpp
|
||||||
CCastleInterface.cpp
|
|
||||||
CCreatureWindow.cpp
|
|
||||||
CDefHandler.cpp
|
CDefHandler.cpp
|
||||||
CGameInfo.cpp
|
CGameInfo.cpp
|
||||||
CHeroWindow.cpp
|
Client.cpp
|
||||||
CKingdomInterface.cpp
|
|
||||||
CMessage.cpp
|
CMessage.cpp
|
||||||
|
CMT.cpp
|
||||||
CMusicHandler.cpp
|
CMusicHandler.cpp
|
||||||
CSpellWindow.cpp
|
CPlayerInterface.cpp
|
||||||
|
CPreGame.cpp
|
||||||
CVideoHandler.cpp
|
CVideoHandler.cpp
|
||||||
CQuestLog.cpp
|
|
||||||
Graphics.cpp
|
Graphics.cpp
|
||||||
mapHandler.cpp
|
mapHandler.cpp
|
||||||
NetPacksClient.cpp
|
NetPacksClient.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(client_HEADERS
|
||||||
|
gui/SDL_Pixels.h
|
||||||
|
gui/SDL_Compat.h
|
||||||
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
# OS X specific includes
|
# OS X specific includes
|
||||||
include_directories(${SPARKLE_INCLUDE_DIR})
|
include_directories(${SPARKLE_INCLUDE_DIR})
|
||||||
|
@ -11,17 +11,19 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CMessage.h"
|
#include "CMessage.h"
|
||||||
|
|
||||||
#include "SDL_ttf.h"
|
|
||||||
#include "CDefHandler.h"
|
#include "CDefHandler.h"
|
||||||
#include "CAnimation.h"
|
|
||||||
#include "CGameInfo.h"
|
#include "CGameInfo.h"
|
||||||
#include "gui/SDL_Extensions.h"
|
#include "gui/SDL_Extensions.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../lib/CGeneralTextHandler.h"
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
#include "GUIClasses.h"
|
#include "windows/GUIClasses.h"
|
||||||
#include "../lib/CConfigHandler.h"
|
#include "../lib/CConfigHandler.h"
|
||||||
#include "CBitmapHandler.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 BETWEEN_COMPS_ROWS = 10;
|
||||||
const int BEFORE_COMPONENTS = 30;
|
const int BEFORE_COMPONENTS = 30;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "../lib/CConfigHandler.h"
|
#include "../lib/CConfigHandler.h"
|
||||||
#include "../lib/CSoundBase.h"
|
#include "../lib/CSoundBase.h"
|
||||||
#include "../lib/CCreatureHandler.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CMusicHandler.h, part of VCMI engine
|
* CMusicHandler.h, part of VCMI engine
|
||||||
|
@ -1,21 +1,24 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CAdvmapInterface.h"
|
#include "windows/CAdvmapInterface.h"
|
||||||
#include "battle/CBattleInterface.h"
|
#include "battle/CBattleInterface.h"
|
||||||
#include "battle/CBattleInterfaceClasses.h"
|
#include "battle/CBattleInterfaceClasses.h"
|
||||||
#include "../CCallback.h"
|
#include "../CCallback.h"
|
||||||
#include "CCastleInterface.h"
|
#include "windows/CCastleInterface.h"
|
||||||
#include "gui/CCursorHandler.h"
|
#include "gui/CCursorHandler.h"
|
||||||
#include "CKingdomInterface.h"
|
#include "windows/CKingdomInterface.h"
|
||||||
#include "CGameInfo.h"
|
#include "CGameInfo.h"
|
||||||
#include "CHeroWindow.h"
|
#include "windows/CHeroWindow.h"
|
||||||
#include "CCreatureWindow.h"
|
#include "windows/CCreatureWindow.h"
|
||||||
#include "CQuestLog.h"
|
#include "windows/CQuestLog.h"
|
||||||
#include "CMessage.h"
|
#include "CMessage.h"
|
||||||
#include "CPlayerInterface.h"
|
#include "CPlayerInterface.h"
|
||||||
#include "gui/SDL_Extensions.h"
|
#include "gui/SDL_Extensions.h"
|
||||||
|
#include "widgets/CComponent.h"
|
||||||
|
#include "windows/CTradeWindow.h"
|
||||||
#include "../lib/CConfigHandler.h"
|
#include "../lib/CConfigHandler.h"
|
||||||
#include "battle/CCreatureAnimation.h"
|
#include "battle/CCreatureAnimation.h"
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
|
#include "windows/GUIClasses.h"
|
||||||
#include "../lib/CArtHandler.h"
|
#include "../lib/CArtHandler.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../lib/CGeneralTextHandler.h"
|
||||||
#include "../lib/CHeroHandler.h"
|
#include "../lib/CHeroHandler.h"
|
||||||
@ -35,7 +38,9 @@
|
|||||||
#include "../lib/CGameState.h"
|
#include "../lib/CGameState.h"
|
||||||
#include "../lib/GameConstants.h"
|
#include "../lib/GameConstants.h"
|
||||||
#include "gui/CGuiHandler.h"
|
#include "gui/CGuiHandler.h"
|
||||||
|
#include "windows/InfoWindows.h"
|
||||||
#include "../lib/UnlockGuard.h"
|
#include "../lib/UnlockGuard.h"
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
#ifdef min
|
#ifdef min
|
||||||
#undef min
|
#undef min
|
||||||
@ -494,10 +499,12 @@ void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander,
|
|||||||
waitWhileDialog();
|
waitWhileDialog();
|
||||||
CCS->soundh->playSound(soundBase::heroNewLevel);
|
CCS->soundh->playSound(soundBase::heroNewLevel);
|
||||||
|
|
||||||
CCreatureWindow * cw = new CCreatureWindow(skills, commander,
|
GH.pushInt(new CStackWindow(commander, skills, [=](ui32 selection)
|
||||||
[=](ui32 selection){ cb->selectionMade(selection, queryID); });
|
{
|
||||||
GH.pushInt(cw);
|
cb->selectionMade(selection, queryID);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
|
void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
|
||||||
{
|
{
|
||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
@ -1285,8 +1292,8 @@ void CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
|
|||||||
|
|
||||||
if (adventureInt && adventureInt->isHeroSleeping(h))
|
if (adventureInt && adventureInt->isHeroSleeping(h))
|
||||||
{
|
{
|
||||||
adventureInt->sleepWake.clickLeft(true, false);
|
adventureInt->sleepWake->clickLeft(true, false);
|
||||||
adventureInt->sleepWake.clickLeft(false, true);
|
adventureInt->sleepWake->clickLeft(false, true);
|
||||||
//could've just called
|
//could've just called
|
||||||
//adventureInt->fsleepWake();
|
//adventureInt->fsleepWake();
|
||||||
//but no authentic button click/sound ;-)
|
//but no authentic button click/sound ;-)
|
||||||
@ -1321,7 +1328,7 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
|
|||||||
waitForAllDialogs();
|
waitForAllDialogs();
|
||||||
|
|
||||||
auto cgw = new CGarrisonWindow(up,down,removableUnits);
|
auto cgw = new CGarrisonWindow(up,down,removableUnits);
|
||||||
cgw->quit->callback += onEnd;
|
cgw->quit->addCallback(onEnd);
|
||||||
GH.pushInt(cgw);
|
GH.pushInt(cgw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2239,7 +2246,7 @@ void CPlayerInterface::acceptTurn()
|
|||||||
if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt()))
|
if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt()))
|
||||||
iw->close();
|
iw->close();
|
||||||
|
|
||||||
adventureInt->endTurn.callback();
|
adventureInt->fendTurn();
|
||||||
}
|
}
|
||||||
|
|
||||||
// warn player if he has no town
|
// warn player if he has no town
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
#include "../lib/CondSh.h"
|
//#include "../lib/CondSh.h"
|
||||||
#include "../lib/FunctionList.h"
|
#include "../lib/FunctionList.h"
|
||||||
#include "../lib/CGameInterface.h"
|
#include "../lib/CGameInterface.h"
|
||||||
|
#include "../lib/NetPacksBase.h"
|
||||||
#include "gui/CIntObject.h"
|
#include "gui/CIntObject.h"
|
||||||
#include "../lib/CGameState.h"
|
//#include "../lib/CGameState.h"
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#define sprintf_s snprintf
|
#define sprintf_s snprintf
|
||||||
@ -29,8 +30,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class CDefEssential;
|
class CDefEssential;
|
||||||
class CAdventureMapButton;
|
class CButton;
|
||||||
class CHighlightableButtonsGroup;
|
class CToggleGroup;
|
||||||
class CDefHandler;
|
class CDefHandler;
|
||||||
struct TryMoveHero;
|
struct TryMoveHero;
|
||||||
class CDefEssential;
|
class CDefEssential;
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "gui/SDL_Extensions.h"
|
#include "gui/SDL_Extensions.h"
|
||||||
#include "CGameInfo.h"
|
#include "CGameInfo.h"
|
||||||
#include "gui/CCursorHandler.h"
|
#include "gui/CCursorHandler.h"
|
||||||
#include "CAnimation.h"
|
|
||||||
#include "CDefHandler.h"
|
#include "CDefHandler.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../lib/CGeneralTextHandler.h"
|
||||||
#include "../lib/CTownHandler.h"
|
#include "../lib/CTownHandler.h"
|
||||||
@ -23,7 +22,7 @@
|
|||||||
#include "../lib/Connection.h"
|
#include "../lib/Connection.h"
|
||||||
#include "../lib/VCMIDirs.h"
|
#include "../lib/VCMIDirs.h"
|
||||||
#include "../lib/mapping/CMap.h"
|
#include "../lib/mapping/CMap.h"
|
||||||
#include "GUIClasses.h"
|
#include "windows/GUIClasses.h"
|
||||||
#include "CPlayerInterface.h"
|
#include "CPlayerInterface.h"
|
||||||
#include "../CCallback.h"
|
#include "../CCallback.h"
|
||||||
#include "CMessage.h"
|
#include "CMessage.h"
|
||||||
@ -38,7 +37,13 @@
|
|||||||
#include "../lib/CConfigHandler.h"
|
#include "../lib/CConfigHandler.h"
|
||||||
#include "../lib/GameConstants.h"
|
#include "../lib/GameConstants.h"
|
||||||
#include "gui/CGuiHandler.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/CMapService.h"
|
||||||
#include "../lib/mapping/CMap.h"
|
#include "../lib/mapping/CMap.h"
|
||||||
#include "../lib/CRandomGenerator.h"
|
#include "../lib/CRandomGenerator.h"
|
||||||
@ -367,7 +372,7 @@ static std::function<void()> genCommand(CMenuScreen* menu, std::vector<std::stri
|
|||||||
return std::function<void()>();
|
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());
|
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)
|
if (posy < 0)
|
||||||
posy = pos.h + posy;
|
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)
|
CMenuEntry::CMenuEntry(CMenuScreen* parent, const JsonNode &config)
|
||||||
@ -639,38 +644,39 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
|||||||
{
|
{
|
||||||
case CMenuScreen::newGame:
|
case CMenuScreen::newGame:
|
||||||
{
|
{
|
||||||
card->difficulty->onChange = std::bind(&CSelectionScreen::difficultyChange, this, _1);
|
SDL_Color orange = {232, 184, 32, 0};
|
||||||
card->difficulty->select(1, 0);
|
SDL_Color overlayColor = multiPlayer == CMenuScreen::MULTI_NETWORK_GUEST ? orange : Colors::WHITE;
|
||||||
CAdventureMapButton * select = new CAdventureMapButton(CGI->generaltexth->zelp[45], 0, 411, 80, "GSPBUTT.DEF", SDLK_s);
|
|
||||||
select->callback = [&]()
|
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);
|
toggleTab(sel);
|
||||||
changeSelection(sel->getSelectedMapInfo());
|
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);
|
CButton *opts = new CButton(Point(411, 510), "GSPBUTT.DEF", CGI->generaltexth->zelp[46], boost::bind(&CSelectionScreen::toggleTab, this, opt), SDLK_a);
|
||||||
opts->addTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL);
|
opts->addTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL, overlayColor);
|
||||||
|
|
||||||
CAdventureMapButton * randomBtn = new CAdventureMapButton(CGI->generaltexth->zelp[47], 0, 411, 105, "GSPBUTT.DEF", SDLK_r);
|
CButton * randomBtn = new CButton(Point(411, 105), "GSPBUTT.DEF", CGI->generaltexth->zelp[47], 0, SDLK_r);
|
||||||
randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL);
|
randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL, overlayColor);
|
||||||
randomBtn->callback = [&]()
|
randomBtn->addCallback([&]()
|
||||||
{
|
{
|
||||||
toggleTab(randMapTab);
|
toggleTab(randMapTab);
|
||||||
changeSelection(randMapTab->getMapInfo());
|
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], boost::bind(&CSelectionScreen::startScenario, this), SDLK_b);
|
||||||
|
|
||||||
if(network)
|
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], boost::bind(&InfoCard::toggleChat, card), SDLK_h);
|
||||||
hideChat->addTextOverlay(CGI->generaltexth->allTexts[531], FONT_SMALL);
|
hideChat->addTextOverlay(CGI->generaltexth->allTexts[531], FONT_SMALL);
|
||||||
|
|
||||||
if(multiPlayer == CMenuScreen::MULTI_NETWORK_GUEST)
|
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);
|
select->block(true);
|
||||||
opts->block(true);
|
opts->block(true);
|
||||||
randomBtn->block(true);
|
randomBtn->block(true);
|
||||||
@ -681,21 +687,21 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
|||||||
break;
|
break;
|
||||||
case CMenuScreen::loadGame:
|
case CMenuScreen::loadGame:
|
||||||
sel->recActions = 255;
|
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], boost::bind(&CSelectionScreen::startScenario, this), SDLK_l);
|
||||||
break;
|
break;
|
||||||
case CMenuScreen::saveGame:
|
case CMenuScreen::saveGame:
|
||||||
sel->recActions = 255;
|
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], boost::bind(&CSelectionScreen::startScenario, this), SDLK_s);
|
||||||
break;
|
break;
|
||||||
case CMenuScreen::campaignList:
|
case CMenuScreen::campaignList:
|
||||||
sel->recActions = 255;
|
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(), boost::bind(&CSelectionScreen::startCampaign, this), SDLK_b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
start->assignedKeys.insert(SDLK_RETURN);
|
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], boost::bind(&CGuiHandler::popIntTotally, &GH, this), SDLK_ESCAPE);
|
||||||
|
|
||||||
if(network)
|
if(network)
|
||||||
{
|
{
|
||||||
@ -995,7 +1001,7 @@ void CSelectionScreen::setSInfo(const StartInfo &si)
|
|||||||
if(current)
|
if(current)
|
||||||
opt->recreate(); //will force to recreate using current sInfo
|
opt->recreate(); //will force to recreate using current sInfo
|
||||||
|
|
||||||
card->difficulty->select(si.difficulty, 0);
|
card->difficulty->setSelected(si.difficulty);
|
||||||
|
|
||||||
GH.totalRedraw();
|
GH.totalRedraw();
|
||||||
}
|
}
|
||||||
@ -1258,7 +1264,7 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const std::function<void(CM
|
|||||||
int sizes[] = {36, 72, 108, 144, 0};
|
int sizes[] = {36, 72, 108, 144, 0};
|
||||||
const char * names[] = {"SCSMBUT.DEF", "SCMDBUT.DEF", "SCLGBUT.DEF", "SCXLBUT.DEF", "SCALBUT.DEF"};
|
const char * names[] = {"SCSMBUT.DEF", "SCMDBUT.DEF", "SCLGBUT.DEF", "SCXLBUT.DEF", "SCALBUT.DEF"};
|
||||||
for(int i = 0; i < 5; i++)
|
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], boost::bind(&SelectionTab::filter, this, sizes[i], true));
|
||||||
}
|
}
|
||||||
|
|
||||||
//sort buttons buttons
|
//sort buttons buttons
|
||||||
@ -1272,20 +1278,19 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const std::function<void(CM
|
|||||||
if(criteria == _name)
|
if(criteria == _name)
|
||||||
criteria = generalSortingBy;
|
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], boost::bind(&SelectionTab::sortBy, this, criteria));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//sort by buttons
|
//sort by buttons
|
||||||
new CAdventureMapButton("", "", std::bind(&SelectionTab::sortBy, this, _numOfMaps), 23, 86, "CamCusM.DEF"); //by num of maps
|
new CButton(Point(23, 86), "CamCusM.DEF", CButton::tooltip(), boost::bind(&SelectionTab::sortBy, this, _numOfMaps)); //by num of maps
|
||||||
new CAdventureMapButton("", "", std::bind(&SelectionTab::sortBy, this, _name), 55, 86, "CamCusL.DEF"); //by name
|
new CButton(Point(55, 86), "CamCusL.DEF", CButton::tooltip(), boost::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, boost::bind(&SelectionTab::sliderMove, this, _1), positions, curItems.size(), 0, false, CSlider::BLUE);
|
||||||
slider->addUsedEvents(WHEEL);
|
slider->addUsedEvents(WHEEL);
|
||||||
slider->slider->keepFrame = true;
|
|
||||||
format = CDefHandler::giveDef("SCSELC.DEF");
|
format = CDefHandler::giveDef("SCSELC.DEF");
|
||||||
|
|
||||||
sortingBy = _format;
|
sortingBy = _format;
|
||||||
@ -1351,16 +1356,16 @@ void SelectionTab::select( int position )
|
|||||||
if(!curItems.size()) return;
|
if(!curItems.size()) return;
|
||||||
|
|
||||||
// New selection. py is the index in curItems.
|
// New selection. py is the index in curItems.
|
||||||
int py = position + slider->value;
|
int py = position + slider->getValue();
|
||||||
vstd::amax(py, 0);
|
vstd::amax(py, 0);
|
||||||
vstd::amin(py, curItems.size()-1);
|
vstd::amin(py, curItems.size()-1);
|
||||||
|
|
||||||
selectionPos = py;
|
selectionPos = py;
|
||||||
|
|
||||||
if(position < 0)
|
if(position < 0)
|
||||||
slider->moveTo(slider->value + position);
|
slider->moveBy(position);
|
||||||
else if(position >= positions)
|
else if(position >= positions)
|
||||||
slider->moveTo(slider->value + position - positions + 1);
|
slider->moveBy(position - positions + 1);
|
||||||
|
|
||||||
if(txt)
|
if(txt)
|
||||||
{
|
{
|
||||||
@ -1374,7 +1379,7 @@ void SelectionTab::select( int position )
|
|||||||
|
|
||||||
void SelectionTab::selectAbs( int position )
|
void SelectionTab::selectAbs( int position )
|
||||||
{
|
{
|
||||||
select(position - slider->value);
|
select(position - slider->getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
int SelectionTab::getPosition( int x, int y )
|
int SelectionTab::getPosition( int x, int y )
|
||||||
@ -1397,7 +1402,7 @@ void SelectionTab::sliderMove( int slidPos )
|
|||||||
void SelectionTab::printMaps(SDL_Surface *to)
|
void SelectionTab::printMaps(SDL_Surface *to)
|
||||||
{
|
{
|
||||||
|
|
||||||
int elemIdx = slider->value;
|
int elemIdx = slider->getValue();
|
||||||
|
|
||||||
// Display all elements if there's enough space
|
// Display all elements if there's enough space
|
||||||
//if(slider->amount < slider->capacity)
|
//if(slider->amount < slider->capacity)
|
||||||
@ -1555,15 +1560,15 @@ void SelectionTab::keyPressed( const SDL_KeyboardEvent & key )
|
|||||||
moveBy = +positions-1;
|
moveBy = +positions-1;
|
||||||
break;
|
break;
|
||||||
case SDLK_HOME:
|
case SDLK_HOME:
|
||||||
select(-slider->value);
|
select(-slider->getValue());
|
||||||
return;
|
return;
|
||||||
case SDLK_END:
|
case SDLK_END:
|
||||||
select(curItems.size() - slider->value);
|
select(curItems.size() - slider->getValue());
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
select(selectionPos - slider->value + moveBy);
|
select(selectionPos - slider->getValue() + moveBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectionTab::onDoubleClick()
|
void SelectionTab::onDoubleClick()
|
||||||
@ -1571,7 +1576,7 @@ void SelectionTab::onDoubleClick()
|
|||||||
if(getLine() != -1) //double clicked scenarios list
|
if(getLine() != -1) //double clicked scenarios list
|
||||||
{
|
{
|
||||||
//act as if start button was pressed
|
//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);
|
bg = new CPicture("RANMAPBK", 0, 6);
|
||||||
|
|
||||||
// Map Size
|
// Map Size
|
||||||
mapSizeBtnGroup = new CHighlightableButtonsGroup(0);
|
mapSizeBtnGroup = new CToggleGroup(0);
|
||||||
mapSizeBtnGroup->pos.y += 81;
|
mapSizeBtnGroup->pos.y += 81;
|
||||||
mapSizeBtnGroup->pos.x += 158;
|
mapSizeBtnGroup->pos.x += 158;
|
||||||
const std::vector<std::string> mapSizeBtns = boost::assign::list_of("RANSIZS")("RANSIZM")("RANSIZL")("RANSIZX");
|
const std::vector<std::string> mapSizeBtns = boost::assign::list_of("RANSIZS")("RANSIZM")("RANSIZL")("RANSIZX");
|
||||||
addButtonsToGroup(mapSizeBtnGroup, mapSizeBtns, 0, 3, 47, 198);
|
addButtonsToGroup(mapSizeBtnGroup, mapSizeBtns, 0, 3, 47, 198);
|
||||||
mapSizeBtnGroup->select(1, false);
|
mapSizeBtnGroup->setSelected(1);
|
||||||
mapSizeBtnGroup->onChange = [&](int btnId)
|
mapSizeBtnGroup->addCallback([&](int btnId)
|
||||||
{
|
{
|
||||||
const std::vector<int> mapSizeVal = boost::assign::list_of(CMapHeader::MAP_SIZE_SMALL)(CMapHeader::MAP_SIZE_MIDDLE)
|
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);
|
(CMapHeader::MAP_SIZE_LARGE)(CMapHeader::MAP_SIZE_XLARGE);
|
||||||
mapGenOptions.setWidth(mapSizeVal[btnId]);
|
mapGenOptions.setWidth(mapSizeVal[btnId]);
|
||||||
mapGenOptions.setHeight(mapSizeVal[btnId]);
|
mapGenOptions.setHeight(mapSizeVal[btnId]);
|
||||||
updateMapInfo();
|
updateMapInfo();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Two levels
|
// Two levels
|
||||||
twoLevelsBtn = new CHighlightableButton(0, 0, std::map<int,std::string>(),
|
twoLevelsBtn = new CToggleButton(Point(346, 81), "RANUNDR", CGI->generaltexth->zelp[202]);
|
||||||
CGI->generaltexth->zelp[202].second, false, "RANUNDR", nullptr, 346, 81);
|
|
||||||
//twoLevelsBtn->select(true); for now, deactivated
|
//twoLevelsBtn->select(true); for now, deactivated
|
||||||
twoLevelsBtn->callback = [&]() { mapGenOptions.setHasTwoLevels(true); updateMapInfo(); };
|
twoLevelsBtn->addCallback([&](bool on) { mapGenOptions.setHasTwoLevels(on); updateMapInfo(); });
|
||||||
twoLevelsBtn->callback2 = [&]() { mapGenOptions.setHasTwoLevels(false); updateMapInfo(); };
|
|
||||||
|
|
||||||
// Create number defs list
|
// Create number defs list
|
||||||
std::vector<std::string> numberDefs;
|
std::vector<std::string> numberDefs;
|
||||||
@ -1648,128 +1651,130 @@ CRandomMapTab::CRandomMapTab()
|
|||||||
const int NUMBERS_WIDTH = 32;
|
const int NUMBERS_WIDTH = 32;
|
||||||
const int BTNS_GROUP_LEFT_MARGIN = 67;
|
const int BTNS_GROUP_LEFT_MARGIN = 67;
|
||||||
// Amount of players
|
// Amount of players
|
||||||
playersCntGroup = new CHighlightableButtonsGroup(0);
|
playersCntGroup = new CToggleGroup(0);
|
||||||
playersCntGroup->pos.y += 153;
|
playersCntGroup->pos.y += 153;
|
||||||
playersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
playersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||||
addButtonsWithRandToGroup(playersCntGroup, numberDefs, 1, 8, NUMBERS_WIDTH, 204, 212);
|
addButtonsWithRandToGroup(playersCntGroup, numberDefs, 1, 8, NUMBERS_WIDTH, 204, 212);
|
||||||
playersCntGroup->onChange = [&](int btnId)
|
playersCntGroup->addCallback([&](int btnId)
|
||||||
{
|
{
|
||||||
mapGenOptions.setPlayerCount(btnId);
|
mapGenOptions.setPlayerCount(btnId);
|
||||||
deactivateButtonsFrom(teamsCntGroup, btnId);
|
deactivateButtonsFrom(teamsCntGroup, btnId);
|
||||||
deactivateButtonsFrom(compOnlyPlayersCntGroup, 8 - btnId + 1);
|
deactivateButtonsFrom(compOnlyPlayersCntGroup, 8 - btnId + 1);
|
||||||
validatePlayersCnt(btnId);
|
validatePlayersCnt(btnId);
|
||||||
updateMapInfo();
|
updateMapInfo();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Amount of teams
|
// Amount of teams
|
||||||
teamsCntGroup = new CHighlightableButtonsGroup(0);
|
teamsCntGroup = new CToggleGroup(0);
|
||||||
teamsCntGroup->pos.y += 219;
|
teamsCntGroup->pos.y += 219;
|
||||||
teamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
teamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||||
addButtonsWithRandToGroup(teamsCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 214, 222);
|
addButtonsWithRandToGroup(teamsCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 214, 222);
|
||||||
teamsCntGroup->onChange = [&](int btnId)
|
teamsCntGroup->addCallback([&](int btnId)
|
||||||
{
|
{
|
||||||
mapGenOptions.setTeamCount(btnId);
|
mapGenOptions.setTeamCount(btnId);
|
||||||
updateMapInfo();
|
updateMapInfo();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Computer only players
|
// Computer only players
|
||||||
compOnlyPlayersCntGroup = new CHighlightableButtonsGroup(0);
|
compOnlyPlayersCntGroup = new CToggleGroup(0);
|
||||||
compOnlyPlayersCntGroup->pos.y += 285;
|
compOnlyPlayersCntGroup->pos.y += 285;
|
||||||
compOnlyPlayersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
compOnlyPlayersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||||
addButtonsWithRandToGroup(compOnlyPlayersCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 224, 232);
|
addButtonsWithRandToGroup(compOnlyPlayersCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 224, 232);
|
||||||
compOnlyPlayersCntGroup->select(0, true);
|
compOnlyPlayersCntGroup->setSelected(0);
|
||||||
compOnlyPlayersCntGroup->onChange = [&](int btnId)
|
compOnlyPlayersCntGroup->addCallback([&](int btnId)
|
||||||
{
|
{
|
||||||
mapGenOptions.setCompOnlyPlayerCount(btnId);
|
mapGenOptions.setCompOnlyPlayerCount(btnId);
|
||||||
deactivateButtonsFrom(compOnlyTeamsCntGroup, btnId);
|
deactivateButtonsFrom(compOnlyTeamsCntGroup, btnId);
|
||||||
validateCompOnlyPlayersCnt(btnId);
|
validateCompOnlyPlayersCnt(btnId);
|
||||||
updateMapInfo();
|
updateMapInfo();
|
||||||
};
|
});
|
||||||
|
|
||||||
// Computer only teams
|
// Computer only teams
|
||||||
compOnlyTeamsCntGroup = new CHighlightableButtonsGroup(0);
|
compOnlyTeamsCntGroup = new CToggleGroup(0);
|
||||||
compOnlyTeamsCntGroup->pos.y += 351;
|
compOnlyTeamsCntGroup->pos.y += 351;
|
||||||
compOnlyTeamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
compOnlyTeamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||||
addButtonsWithRandToGroup(compOnlyTeamsCntGroup, numberDefs, 0, 6, NUMBERS_WIDTH, 234, 241);
|
addButtonsWithRandToGroup(compOnlyTeamsCntGroup, numberDefs, 0, 6, NUMBERS_WIDTH, 234, 241);
|
||||||
deactivateButtonsFrom(compOnlyTeamsCntGroup, 0);
|
deactivateButtonsFrom(compOnlyTeamsCntGroup, 0);
|
||||||
compOnlyTeamsCntGroup->onChange = [&](int btnId)
|
compOnlyTeamsCntGroup->addCallback([&](int btnId)
|
||||||
{
|
{
|
||||||
mapGenOptions.setCompOnlyTeamCount(btnId);
|
mapGenOptions.setCompOnlyTeamCount(btnId);
|
||||||
updateMapInfo();
|
updateMapInfo();
|
||||||
};
|
});
|
||||||
|
|
||||||
const int WIDE_BTN_WIDTH = 85;
|
const int WIDE_BTN_WIDTH = 85;
|
||||||
// Water content
|
// Water content
|
||||||
waterContentGroup = new CHighlightableButtonsGroup(0);
|
waterContentGroup = new CToggleGroup(0);
|
||||||
waterContentGroup->pos.y += 419;
|
waterContentGroup->pos.y += 419;
|
||||||
waterContentGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
waterContentGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||||
const std::vector<std::string> waterContentBtns = boost::assign::list_of("RANNONE")("RANNORM")("RANISLD");
|
const std::vector<std::string> waterContentBtns = boost::assign::list_of("RANNONE")("RANNORM")("RANISLD");
|
||||||
addButtonsWithRandToGroup(waterContentGroup, waterContentBtns, 0, 2, WIDE_BTN_WIDTH, 243, 246);
|
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));
|
mapGenOptions.setWaterContent(static_cast<EWaterContent::EWaterContent>(btnId));
|
||||||
};
|
});
|
||||||
|
|
||||||
// Monster strength
|
// Monster strength
|
||||||
monsterStrengthGroup = new CHighlightableButtonsGroup(0);
|
monsterStrengthGroup = new CToggleGroup(0);
|
||||||
monsterStrengthGroup->pos.y += 485;
|
monsterStrengthGroup->pos.y += 485;
|
||||||
monsterStrengthGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
monsterStrengthGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||||
const std::vector<std::string> monsterStrengthBtns = boost::assign::list_of("RANWEAK")("RANNORM")("RANSTRG");
|
const std::vector<std::string> monsterStrengthBtns = boost::assign::list_of("RANWEAK")("RANNORM")("RANSTRG");
|
||||||
addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251);
|
addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251);
|
||||||
monsterStrengthGroup->onChange = [&](int btnId)
|
monsterStrengthGroup->addCallback([&](int btnId)
|
||||||
{
|
{
|
||||||
if (btnId < 0)
|
if (btnId < 0)
|
||||||
mapGenOptions.setMonsterStrength(EMonsterStrength::RANDOM);
|
mapGenOptions.setMonsterStrength(EMonsterStrength::RANDOM);
|
||||||
else
|
else
|
||||||
mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId + EMonsterStrength::GLOBAL_WEAK)); //value 2 to 4
|
mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId + EMonsterStrength::GLOBAL_WEAK)); //value 2 to 4
|
||||||
};
|
});
|
||||||
|
|
||||||
// Show random maps btn
|
// 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
|
// Initialize map info object
|
||||||
updateMapInfo();
|
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);
|
addButtonsToGroup(group, defs, nStart, nEnd, btnWidth, helpStartIndex);
|
||||||
|
|
||||||
// Buttons are relative to button group, TODO better solution?
|
// Buttons are relative to button group, TODO better solution?
|
||||||
SObjectConstruction obj__i(group);
|
SObjectConstruction obj__i(group);
|
||||||
const std::string RANDOM_DEF = "RANRAND";
|
const std::string RANDOM_DEF = "RANRAND";
|
||||||
group->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[helpRandIndex].second, 0, 256, 0, RANDOM_DEF, CMapGenOptions::RANDOM_SIZE));
|
group->addToggle(CMapGenOptions::RANDOM_SIZE, new CToggleButton(Point(256, 0), RANDOM_DEF, CGI->generaltexth->zelp[helpRandIndex]));
|
||||||
group->select(CMapGenOptions::RANDOM_SIZE, true);
|
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?
|
// Buttons are relative to button group, TODO better solution?
|
||||||
SObjectConstruction obj__i(group);
|
SObjectConstruction obj__i(group);
|
||||||
int cnt = nEnd - nStart + 1;
|
int cnt = nEnd - nStart + 1;
|
||||||
for(int i = 0; i < cnt; ++i)
|
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);
|
button->block(false);
|
||||||
btn->setState(CButtonBase::NORMAL);
|
}
|
||||||
|
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)
|
if(mapGenOptions.getTeamCount() >= playersCnt)
|
||||||
{
|
{
|
||||||
mapGenOptions.setTeamCount(playersCnt - 1);
|
mapGenOptions.setTeamCount(playersCnt - 1);
|
||||||
teamsCntGroup->select(mapGenOptions.getTeamCount(), true);
|
teamsCntGroup->setSelected(mapGenOptions.getTeamCount());
|
||||||
}
|
}
|
||||||
if(mapGenOptions.getCompOnlyPlayerCount() > 8 - playersCnt)
|
if(mapGenOptions.getCompOnlyPlayerCount() > 8 - playersCnt)
|
||||||
{
|
{
|
||||||
mapGenOptions.setCompOnlyPlayerCount(8 - playersCnt);
|
mapGenOptions.setCompOnlyPlayerCount(8 - playersCnt);
|
||||||
compOnlyPlayersCntGroup->select(mapGenOptions.getCompOnlyPlayerCount(), true);
|
compOnlyPlayersCntGroup->setSelected(mapGenOptions.getCompOnlyPlayerCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
validateCompOnlyPlayersCnt(mapGenOptions.getCompOnlyPlayerCount());
|
validateCompOnlyPlayersCnt(mapGenOptions.getCompOnlyPlayerCount());
|
||||||
@ -1805,7 +1810,7 @@ void CRandomMapTab::validateCompOnlyPlayersCnt(int compOnlyPlayersCnt)
|
|||||||
if(mapGenOptions.getCompOnlyTeamCount() >= compOnlyPlayersCnt)
|
if(mapGenOptions.getCompOnlyTeamCount() >= compOnlyPlayersCnt)
|
||||||
{
|
{
|
||||||
mapGenOptions.setCompOnlyTeamCount(compOnlyPlayersCnt - 1);
|
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;
|
pos.h = bg->pos.h;
|
||||||
sizes = CDefHandler::giveDef("SCNRMPSZ.DEF");
|
sizes = CDefHandler::giveDef("SCNRMPSZ.DEF");
|
||||||
sFlags = CDefHandler::giveDef("ITGFLAGS.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"};
|
static const char *difButns[] = {"GSPBUT3.DEF", "GSPBUT4.DEF", "GSPBUT5.DEF", "GSPBUT6.DEF", "GSPBUT7.DEF"};
|
||||||
|
|
||||||
for(int i = 0; i < 5; i++)
|
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)
|
if(network)
|
||||||
{
|
{
|
||||||
playerListBg = new CPicture("CHATPLUG.bmp", 16, 276);
|
playerListBg = new CPicture("CHATPLUG.bmp", 16, 276);
|
||||||
@ -2161,8 +2166,8 @@ void InfoCard::changeSelection( const CMapInfo *to )
|
|||||||
mapDescription->setText(to->mapHeader->description);
|
mapDescription->setText(to->mapHeader->description);
|
||||||
|
|
||||||
if(SEL->screenType != CMenuScreen::newGame && SEL->screenType != CMenuScreen::campaignList) {
|
if(SEL->screenType != CMenuScreen::newGame && SEL->screenType != CMenuScreen::campaignList) {
|
||||||
difficulty->block(true);
|
//difficulty->block(true);
|
||||||
difficulty->select(SEL->sInfo.difficulty, 0);
|
difficulty->setSelected(SEL->sInfo.difficulty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
redraw();
|
redraw();
|
||||||
@ -2242,7 +2247,7 @@ OptionsTab::OptionsTab():
|
|||||||
pos = bg->pos;
|
pos = bg->pos;
|
||||||
|
|
||||||
if(SEL->screenType == CMenuScreen::newGame)
|
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, boost::bind(&OptionsTab::setTurnLength, this, _1), 1, 11, 11, true, CSlider::BLUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionsTab::~OptionsTab()
|
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
|
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
|
printAtMiddleLoc(CGI->generaltexth->allTexts[521], 222, 538, FONT_SMALL, Colors::YELLOW, to); // Player Turn Duration
|
||||||
if (turnDuration)
|
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 )
|
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);
|
bg = new CPicture(BitmapHandler::loadBitmap(bgs[s.color.getNum()]), 0, 0, true);
|
||||||
if(SEL->screenType == CMenuScreen::newGame)
|
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[0] = new CButton(Point(107, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[132], boost::bind(&OptionsTab::nextCastle, owner, s.color, -1));
|
||||||
btns[1] = new CAdventureMapButton(CGI->generaltexth->zelp[133], std::bind(&OptionsTab::nextCastle, owner, s.color, +1), 168, 5, "ADOPRTA.DEF");
|
btns[1] = new CButton(Point(168, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[133], boost::bind(&OptionsTab::nextCastle, owner, s.color, +1));
|
||||||
btns[2] = new CAdventureMapButton(CGI->generaltexth->zelp[148], std::bind(&OptionsTab::nextHero, owner, s.color, -1), 183, 5, "ADOPLFA.DEF");
|
btns[2] = new CButton(Point(183, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[148], boost::bind(&OptionsTab::nextHero, owner, s.color, -1));
|
||||||
btns[3] = new CAdventureMapButton(CGI->generaltexth->zelp[149], std::bind(&OptionsTab::nextHero, owner, s.color, +1), 244, 5, "ADOPRTA.DEF");
|
btns[3] = new CButton(Point(244, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[149], boost::bind(&OptionsTab::nextHero, owner, s.color, +1));
|
||||||
btns[4] = new CAdventureMapButton(CGI->generaltexth->zelp[164], std::bind(&OptionsTab::nextBonus, owner, s.color, -1), 259, 5, "ADOPLFA.DEF");
|
btns[4] = new CButton(Point(259, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[164], boost::bind(&OptionsTab::nextBonus, owner, s.color, -1));
|
||||||
btns[5] = new CAdventureMapButton(CGI->generaltexth->zelp[165], std::bind(&OptionsTab::nextBonus, owner, s.color, +1), 320, 5, "ADOPRTA.DEF");
|
btns[5] = new CButton(Point(320, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[165], boost::bind(&OptionsTab::nextBonus, owner, s.color, +1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for(auto & elem : btns)
|
for(auto & elem : btns)
|
||||||
@ -2573,7 +2578,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry( OptionsTab *owner, PlayerSet
|
|||||||
&& SEL->current->mapHeader->players[s.color.getNum()].canHumanPlay
|
&& SEL->current->mapHeader->players[s.color.getNum()].canHumanPlay
|
||||||
&& SEL->multiPlayer != CMenuScreen::MULTI_NETWORK_GUEST)
|
&& 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], boost::bind(&OptionsTab::flagPressed, owner, s.color));
|
||||||
flag->hoverable = true;
|
flag->hoverable = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2979,8 +2984,8 @@ CScenarioInfo::CScenarioInfo(const CMapHeader *mapHeader, const StartInfo *start
|
|||||||
opt->recreate();
|
opt->recreate();
|
||||||
card->changeSelection(current);
|
card->changeSelection(current);
|
||||||
|
|
||||||
card->difficulty->select(startInfo->difficulty, 0);
|
card->difficulty->setSelected(startInfo->difficulty);
|
||||||
back = new CAdventureMapButton("", CGI->generaltexth->zelp[105].second, std::bind(&CGuiHandler::popIntTotally, &GH, this), 584, 535, "SCNRBACK.DEF", SDLK_ESCAPE);
|
back = new CButton(Point(584, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], boost::bind(&CGuiHandler::popIntTotally, &GH, this), SDLK_ESCAPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
CScenarioInfo::~CScenarioInfo()
|
CScenarioInfo::~CScenarioInfo()
|
||||||
@ -3059,10 +3064,10 @@ CMultiMode::CMultiMode()
|
|||||||
txt = new CTextInput(Rect(19, 436, 334, 16), *bg);
|
txt = new CTextInput(Rect(19, 436, 334, 16), *bg);
|
||||||
txt->setText(settings["general"]["playerName"].String()); //Player
|
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[0] = new CButton(Point(373, 78), "MUBHOT.DEF", CGI->generaltexth->zelp[266], boost::bind(&CMultiMode::openHotseat, this));
|
||||||
btns[1] = new CAdventureMapButton("Host TCP/IP game", "", std::bind(&CMultiMode::hostTCP, this), 373, 78 + 57*1, "MUBHOST.DEF");
|
btns[1] = new CButton(Point(373, 78 + 57*1), "MUBHOST.DEF", CButton::tooltip("Host TCP/IP game", ""), boost::bind(&CMultiMode::hostTCP, this));
|
||||||
btns[2] = new CAdventureMapButton("Join TCP/IP game", "", std::bind(&CMultiMode::joinTCP, this), 373, 78 + 57*2, "MUBJOIN.DEF");
|
btns[2] = new CButton(Point(373, 78 + 57*2), "MUBJOIN.DEF", CButton::tooltip("Join TCP/IP game", ""), boost::bind(&CMultiMode::joinTCP, this));
|
||||||
btns[6] = new CAdventureMapButton(CGI->generaltexth->zelp[288], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 373, 424, "MUBCANC.DEF", SDLK_ESCAPE);
|
btns[6] = new CButton(Point(373, 424), "MUBCANC.DEF", CGI->generaltexth->zelp[288], [&] { GH.popIntTotally(this);}, SDLK_ESCAPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMultiMode::openHotseat()
|
void CMultiMode::openHotseat()
|
||||||
@ -3102,8 +3107,8 @@ CHotSeatPlayers::CHotSeatPlayers(const std::string &firstPlayer)
|
|||||||
txt[i]->cb += std::bind(&CHotSeatPlayers::onChange, this, _1);
|
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);
|
ok = new CButton(Point(95, 338), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], boost::bind(&CHotSeatPlayers::enterSelectionScreen, this), SDLK_RETURN);
|
||||||
cancel = new CAdventureMapButton(CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 205, 338, "MUBCANC.DEF", SDLK_ESCAPE);
|
cancel = new CButton(Point(205, 338), "MUBCANC.DEF", CGI->generaltexth->zelp[561], boost::bind(&CGuiHandler::popIntTotally, boost::ref(GH), this), SDLK_ESCAPE);
|
||||||
bar = new CGStatusBar(new CPicture(Rect(7, 381, 348, 18), 0));//226, 472
|
bar = new CGStatusBar(new CPicture(Rect(7, 381, 348, 18), 0));//226, 472
|
||||||
|
|
||||||
txt[0]->setText(firstPlayer, true);
|
txt[0]->setText(firstPlayer, true);
|
||||||
@ -3166,9 +3171,9 @@ void CBonusSelection::init()
|
|||||||
|
|
||||||
blitAt(panel, 456, 6, background);
|
blitAt(panel, 456, 6, background);
|
||||||
|
|
||||||
startB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::startMap, this), 475, 536, "CBBEGIB.DEF", SDLK_RETURN);
|
startB = new CButton(Point(475, 536), "CBBEGIB.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::startMap, this), SDLK_RETURN);
|
||||||
restartB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::restartMap, this), 475, 536, "CBRESTB.DEF", SDLK_RETURN);
|
restartB = new CButton(Point(475, 536), "CBRESTB.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::restartMap, this), SDLK_RETURN);
|
||||||
backB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::goBack, this), 624, 536, "CBCANCB.DEF", SDLK_ESCAPE);
|
backB = new CButton(Point(624, 536), "CBCANCB.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::goBack, this), SDLK_ESCAPE);
|
||||||
|
|
||||||
//campaign name
|
//campaign name
|
||||||
if (ourCampaign->camp->header.name.length())
|
if (ourCampaign->camp->header.name.length())
|
||||||
@ -3190,7 +3195,7 @@ void CBonusSelection::init()
|
|||||||
|
|
||||||
//bonus choosing
|
//bonus choosing
|
||||||
graphics->fonts[FONT_MEDIUM]->renderTextLeft(background, CGI->generaltexth->allTexts[71], Colors::WHITE, Point(511, 432));
|
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
|
//set left part of window
|
||||||
bool isCurrentMapConquerable = ourCampaign->currentMap && ourCampaign->camp->conquerable(*ourCampaign->currentMap);
|
bool isCurrentMapConquerable = ourCampaign->currentMap && ourCampaign->camp->conquerable(*ourCampaign->currentMap);
|
||||||
@ -3241,8 +3246,8 @@ void CBonusSelection::init()
|
|||||||
//difficulty selection buttons
|
//difficulty selection buttons
|
||||||
if (ourCampaign->camp->header.difficultyChoosenByPlayer)
|
if (ourCampaign->camp->header.difficultyChoosenByPlayer)
|
||||||
{
|
{
|
||||||
diffLb = new CAdventureMapButton("", "", std::bind(&CBonusSelection::decreaseDifficulty, this), 694, 508, "SCNRBLF.DEF");
|
diffLb = new CButton(Point(694, 508), "SCNRBLF.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::decreaseDifficulty, this));
|
||||||
diffRb = new CAdventureMapButton("", "", std::bind(&CBonusSelection::increaseDifficulty, this), 738, 508, "SCNRBRT.DEF");
|
diffRb = new CButton(Point(738, 508), "SCNRBRT.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::increaseDifficulty, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
//load miniflags
|
//load miniflags
|
||||||
@ -3442,13 +3447,8 @@ void CBonusSelection::updateBonusSelection()
|
|||||||
|
|
||||||
updateStartButtonState(-1);
|
updateStartButtonState(-1);
|
||||||
|
|
||||||
for (auto & elem : bonuses->buttons)
|
delete bonuses;
|
||||||
{
|
bonuses = new CToggleGroup(bind(&CBonusSelection::selectBonus, this, _1));
|
||||||
if (elem->active)
|
|
||||||
elem->deactivate();
|
|
||||||
delete elem;
|
|
||||||
}
|
|
||||||
bonuses->buttons.clear();
|
|
||||||
|
|
||||||
static const char *bonusPics[] = {"SPELLBON.DEF", "TWCRPORT.DEF", "", "ARTIFBON.DEF", "SPELLBON.DEF",
|
static const char *bonusPics[] = {"SPELLBON.DEF", "TWCRPORT.DEF", "", "ARTIFBON.DEF", "SPELLBON.DEF",
|
||||||
"PSKILBON.DEF", "SSKILBON.DEF", "BORES.DEF", "PORTRAITSLARGE", "PORTRAITSLARGE"};
|
"PSKILBON.DEF", "SSKILBON.DEF", "BORES.DEF", "PORTRAITSLARGE", "PORTRAITSLARGE"};
|
||||||
@ -3602,7 +3602,7 @@ void CBonusSelection::updateBonusSelection()
|
|||||||
break;
|
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)
|
if (picNumber != -1)
|
||||||
picName += ":" + boost::lexical_cast<std::string>(picNumber);
|
picName += ":" + boost::lexical_cast<std::string>(picNumber);
|
||||||
@ -3612,13 +3612,13 @@ void CBonusSelection::updateBonusSelection()
|
|||||||
bonusButton->setImage(anim);
|
bonusButton->setImage(anim);
|
||||||
const SDL_Color brightYellow = { 242, 226, 110, 0 };
|
const SDL_Color brightYellow = { 242, 226, 110, 0 };
|
||||||
bonusButton->borderColor = brightYellow;
|
bonusButton->borderColor = brightYellow;
|
||||||
bonuses->addButton(bonusButton);
|
bonuses->addToggle(i, bonusButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set bonus if already chosen
|
// set bonus if already chosen
|
||||||
if(vstd::contains(ourCampaign->chosenCampaignBonuses, selectedMap))
|
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)
|
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;
|
std::pair<std::string, std::string> help;
|
||||||
if (!button["help"].isNull() && button["help"].Float() > 0)
|
if (!button["help"].isNull() && button["help"].Float() > 0)
|
||||||
help = CGI->generaltexth->zelp[button["help"].Float()];
|
help = CGI->generaltexth->zelp[button["help"].Float()];
|
||||||
|
|
||||||
std::function<void()> close = std::bind(&CGuiHandler::popIntTotally, &GH, this);
|
std::function<void()> close = boost::bind(&CGuiHandler::popIntTotally, &GH, this);
|
||||||
return new CAdventureMapButton(help, close, button["x"].Float(), button["y"].Float(), button["name"].String(), button["hotkey"].Float());
|
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->cb += std::bind(&CSimpleJoinScreen::onChange, this, _1);
|
||||||
port->filters.add(std::bind(&CTextInput::numberFilter, _1, _2, 0, 65535));
|
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);
|
ok = new CButton(Point( 26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], boost::bind(&CSimpleJoinScreen::enterSelectionScreen, this), SDLK_RETURN);
|
||||||
cancel = new CAdventureMapButton(CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 142, 142, "MUBCANC.DEF", SDLK_ESCAPE);
|
cancel = new CButton(Point(142, 142), "MUBCANC.DEF", CGI->generaltexth->zelp[561], boost::bind(&CGuiHandler::popIntTotally, boost::ref(GH), this), SDLK_ESCAPE);
|
||||||
bar = new CGStatusBar(new CPicture(Rect(7, 186, 218, 18), 0));
|
bar = new CGStatusBar(new CPicture(Rect(7, 186, 218, 18), 0));
|
||||||
|
|
||||||
port->setText(boost::lexical_cast<std::string>(settings["server"]["port"].Float()), true);
|
port->setText(boost::lexical_cast<std::string>(settings["server"]["port"].Float()), true);
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
//#include "../lib/filesystem/Filesystem.h"
|
||||||
#include <SDL.h>
|
|
||||||
#include "../lib/StartInfo.h"
|
#include "../lib/StartInfo.h"
|
||||||
#include "GUIClasses.h"
|
|
||||||
#include "../lib/FunctionList.h"
|
#include "../lib/FunctionList.h"
|
||||||
#include "../lib/mapping/CMapInfo.h"
|
#include "../lib/mapping/CMapInfo.h"
|
||||||
#include "../lib/rmg/CMapGenerator.h"
|
#include "../lib/rmg/CMapGenerator.h"
|
||||||
|
#include "windows/CWindowObject.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CPreGame.h, part of VCMI engine
|
* CPreGame.h, part of VCMI engine
|
||||||
@ -18,6 +17,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
class CMapInfo;
|
||||||
class CMusicHandler;
|
class CMusicHandler;
|
||||||
class CMapHeader;
|
class CMapHeader;
|
||||||
class CCampaignHeader;
|
class CCampaignHeader;
|
||||||
@ -32,6 +32,12 @@ class CMapGenOptions;
|
|||||||
class CRandomMapTab;
|
class CRandomMapTab;
|
||||||
struct CPackForSelectionScreen;
|
struct CPackForSelectionScreen;
|
||||||
struct PlayerInfo;
|
struct PlayerInfo;
|
||||||
|
class CMultiLineLabel;
|
||||||
|
class CToggleButton;
|
||||||
|
class CToggleGroup;
|
||||||
|
class CTabbedInt;
|
||||||
|
class CButton;
|
||||||
|
class CSlider;
|
||||||
|
|
||||||
namespace boost{ class thread; class recursive_mutex;}
|
namespace boost{ class thread; class recursive_mutex;}
|
||||||
|
|
||||||
@ -80,9 +86,9 @@ public:
|
|||||||
class CMenuEntry : public CIntObject
|
class CMenuEntry : public CIntObject
|
||||||
{
|
{
|
||||||
std::vector<CPicture*> images;
|
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:
|
public:
|
||||||
CMenuEntry(CMenuScreen* parent, const JsonNode &config);
|
CMenuEntry(CMenuScreen* parent, const JsonNode &config);
|
||||||
};
|
};
|
||||||
@ -126,7 +132,7 @@ public:
|
|||||||
CChatBox *chat;
|
CChatBox *chat;
|
||||||
CPicture *playerListBg;
|
CPicture *playerListBg;
|
||||||
|
|
||||||
CHighlightableButtonsGroup *difficulty;
|
CToggleGroup *difficulty;
|
||||||
CDefHandler *sizes, *sFlags;
|
CDefHandler *sizes, *sFlags;
|
||||||
|
|
||||||
void changeSelection(const CMapInfo *to);
|
void changeSelection(const CMapInfo *to);
|
||||||
@ -239,8 +245,8 @@ public:
|
|||||||
PlayerInfo π
|
PlayerInfo π
|
||||||
PlayerSettings &s;
|
PlayerSettings &s;
|
||||||
CPicture *bg;
|
CPicture *bg;
|
||||||
CAdventureMapButton *btns[6]; //left and right for town, hero, bonus
|
CButton *btns[6]; //left and right for town, hero, bonus
|
||||||
CAdventureMapButton *flag;
|
CButton *flag;
|
||||||
SelectedBox *town;
|
SelectedBox *town;
|
||||||
SelectedBox *hero;
|
SelectedBox *hero;
|
||||||
SelectedBox *bonus;
|
SelectedBox *bonus;
|
||||||
@ -296,17 +302,17 @@ public:
|
|||||||
const CMapGenOptions & getMapGenOptions() const;
|
const CMapGenOptions & getMapGenOptions() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addButtonsToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex) const;
|
void addButtonsToGroup(CToggleGroup * 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 addButtonsWithRandToGroup(CToggleGroup * 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 deactivateButtonsFrom(CToggleGroup * group, int startId);
|
||||||
void validatePlayersCnt(int playersCnt);
|
void validatePlayersCnt(int playersCnt);
|
||||||
void validateCompOnlyPlayersCnt(int compOnlyPlayersCnt);
|
void validateCompOnlyPlayersCnt(int compOnlyPlayersCnt);
|
||||||
|
|
||||||
CPicture * bg;
|
CPicture * bg;
|
||||||
CHighlightableButton * twoLevelsBtn;
|
CToggleButton * twoLevelsBtn;
|
||||||
CHighlightableButtonsGroup * mapSizeBtnGroup, * playersCntGroup, * teamsCntGroup, * compOnlyPlayersCntGroup,
|
CToggleGroup * mapSizeBtnGroup, * playersCntGroup, * teamsCntGroup, * compOnlyPlayersCntGroup,
|
||||||
* compOnlyTeamsCntGroup, * waterContentGroup, * monsterStrengthGroup;
|
* compOnlyTeamsCntGroup, * waterContentGroup, * monsterStrengthGroup;
|
||||||
CAdventureMapButton * showRandMaps;
|
CButton * showRandMaps;
|
||||||
CMapGenOptions mapGenOptions;
|
CMapGenOptions mapGenOptions;
|
||||||
unique_ptr<CMapInfo> mapInfo;
|
unique_ptr<CMapInfo> mapInfo;
|
||||||
CFunctionList<void(const CMapInfo *)> mapInfoChanged;
|
CFunctionList<void(const CMapInfo *)> mapInfoChanged;
|
||||||
@ -347,7 +353,7 @@ public:
|
|||||||
InfoCard *card;
|
InfoCard *card;
|
||||||
OptionsTab *opt;
|
OptionsTab *opt;
|
||||||
CRandomMapTab * randMapTab;
|
CRandomMapTab * randMapTab;
|
||||||
CAdventureMapButton *start, *back;
|
CButton *start, *back;
|
||||||
|
|
||||||
SelectionTab *sel;
|
SelectionTab *sel;
|
||||||
CIntObject *curTab;
|
CIntObject *curTab;
|
||||||
@ -395,7 +401,7 @@ public:
|
|||||||
class CScenarioInfo : public CIntObject, public ISelectionScreenInfo
|
class CScenarioInfo : public CIntObject, public ISelectionScreenInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CAdventureMapButton *back;
|
CButton *back;
|
||||||
InfoCard *card;
|
InfoCard *card;
|
||||||
OptionsTab *opt;
|
OptionsTab *opt;
|
||||||
|
|
||||||
@ -409,7 +415,7 @@ class CMultiMode : public CIntObject
|
|||||||
public:
|
public:
|
||||||
CPicture *bg;
|
CPicture *bg;
|
||||||
CTextInput *txt;
|
CTextInput *txt;
|
||||||
CAdventureMapButton *btns[7]; //0 - hotseat, 6 - cancel
|
CButton *btns[7]; //0 - hotseat, 6 - cancel
|
||||||
CGStatusBar *bar;
|
CGStatusBar *bar;
|
||||||
|
|
||||||
CMultiMode();
|
CMultiMode();
|
||||||
@ -424,7 +430,7 @@ class CHotSeatPlayers : public CIntObject
|
|||||||
CPicture *bg;
|
CPicture *bg;
|
||||||
CTextBox *title;
|
CTextBox *title;
|
||||||
CTextInput* txt[8];
|
CTextInput* txt[8];
|
||||||
CAdventureMapButton *ok, *cancel;
|
CButton *ok, *cancel;
|
||||||
CGStatusBar *bar;
|
CGStatusBar *bar;
|
||||||
|
|
||||||
void onChange(std::string newText);
|
void onChange(std::string newText);
|
||||||
@ -512,14 +518,14 @@ private:
|
|||||||
|
|
||||||
// GUI components
|
// GUI components
|
||||||
SDL_Surface * background;
|
SDL_Surface * background;
|
||||||
CAdventureMapButton * startB, * restartB, * backB;
|
CButton * startB, * restartB, * backB;
|
||||||
CTextBox * campaignDescription, * mapDescription;
|
CTextBox * campaignDescription, * mapDescription;
|
||||||
std::vector<SCampPositions> campDescriptions;
|
std::vector<SCampPositions> campDescriptions;
|
||||||
std::vector<CRegion *> regions;
|
std::vector<CRegion *> regions;
|
||||||
CRegion * highlightedRegion;
|
CRegion * highlightedRegion;
|
||||||
CHighlightableButtonsGroup * bonuses;
|
CToggleGroup * bonuses;
|
||||||
SDL_Surface * diffPics[5]; //pictures of difficulties, user-selectable (or not if campaign locks this)
|
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 * sizes; //icons of map sizes
|
||||||
CDefHandler * sFlags;
|
CDefHandler * sFlags;
|
||||||
|
|
||||||
@ -560,11 +566,11 @@ private:
|
|||||||
void show(SDL_Surface * to);
|
void show(SDL_Surface * to);
|
||||||
};
|
};
|
||||||
|
|
||||||
CAdventureMapButton *back;
|
CButton *back;
|
||||||
std::vector<CCampaignButton*> campButtons;
|
std::vector<CCampaignButton*> campButtons;
|
||||||
std::vector<CPicture*> images;
|
std::vector<CPicture*> images;
|
||||||
|
|
||||||
CAdventureMapButton* createExitButton(const JsonNode& button);
|
CButton* createExitButton(const JsonNode& button);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum CampaignSet {ROE, AB, SOD, WOG};
|
enum CampaignSet {ROE, AB, SOD, WOG};
|
||||||
@ -630,7 +636,7 @@ class CSimpleJoinScreen : public CIntObject
|
|||||||
{
|
{
|
||||||
CPicture * bg;
|
CPicture * bg;
|
||||||
CTextBox * title;
|
CTextBox * title;
|
||||||
CAdventureMapButton * ok, * cancel;
|
CButton * ok, * cancel;
|
||||||
CGStatusBar * bar;
|
CGStatusBar * bar;
|
||||||
CTextInput * address;
|
CTextInput * address;
|
||||||
CTextInput * port;
|
CTextInput * port;
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
|
#include "Client.h"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
#include "CMusicHandler.h"
|
#include "CMusicHandler.h"
|
||||||
#include "../lib/mapping/CCampaignHandler.h"
|
#include "../lib/mapping/CCampaignHandler.h"
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "../lib/IGameCallback.h"
|
#include "../lib/IGameCallback.h"
|
||||||
#include "../lib/CondSh.h"
|
#include "../lib/BattleAction.h"
|
||||||
#include "../lib/CStopWatch.h"
|
#include "../lib/CStopWatch.h"
|
||||||
|
#include "../lib/int3.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Client.h, part of VCMI engine
|
* Client.h, part of VCMI engine
|
||||||
@ -15,6 +16,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
class CPack;
|
||||||
|
class CCampaignState;
|
||||||
|
class CBattleCallback;
|
||||||
class IGameEventsReceiver;
|
class IGameEventsReceiver;
|
||||||
class IBattleEventsReceiver;
|
class IBattleEventsReceiver;
|
||||||
class CBattleGameInterface;
|
class CBattleGameInterface;
|
||||||
|
1202
client/GUIClasses.h
@ -21,7 +21,6 @@
|
|||||||
#include "../lib/vcmi_endian.h"
|
#include "../lib/vcmi_endian.h"
|
||||||
#include "../lib/GameConstants.h"
|
#include "../lib/GameConstants.h"
|
||||||
#include "../lib/CStopWatch.h"
|
#include "../lib/CStopWatch.h"
|
||||||
#include "CAnimation.h"
|
|
||||||
#include "../lib/mapObjects/CObjectClassesHandler.h"
|
#include "../lib/mapObjects/CObjectClassesHandler.h"
|
||||||
|
|
||||||
using namespace boost::assign;
|
using namespace boost::assign;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include "../lib/CSoundBase.h"
|
#include "../lib/CSoundBase.h"
|
||||||
#include "../lib/StartInfo.h"
|
#include "../lib/StartInfo.h"
|
||||||
#include "mapHandler.h"
|
#include "mapHandler.h"
|
||||||
#include "GUIClasses.h"
|
#include "windows/GUIClasses.h"
|
||||||
#include "../lib/CConfigHandler.h"
|
#include "../lib/CConfigHandler.h"
|
||||||
#include "gui/SDL_Extensions.h"
|
#include "gui/SDL_Extensions.h"
|
||||||
#include "battle/CBattleInterface.h"
|
#include "battle/CBattleInterface.h"
|
||||||
@ -26,6 +26,8 @@
|
|||||||
#include "../lib/BattleState.h"
|
#include "../lib/BattleState.h"
|
||||||
#include "../lib/GameConstants.h"
|
#include "../lib/GameConstants.h"
|
||||||
#include "gui/CGuiHandler.h"
|
#include "gui/CGuiHandler.h"
|
||||||
|
#include "widgets/MiscWidgets.h"
|
||||||
|
#include "widgets/AdventureMapClasses.h"
|
||||||
#include "CMT.h"
|
#include "CMT.h"
|
||||||
|
|
||||||
//macros to avoid code duplication - calls given method with given arguments if interface for specific player is present
|
//macros to avoid code duplication - calls given method with given arguments if interface for specific player is present
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "../../CCallback.h"
|
#include "../../CCallback.h"
|
||||||
#include "../../lib/BattleState.h"
|
#include "../../lib/BattleState.h"
|
||||||
#include "../../lib/CTownHandler.h"
|
#include "../../lib/CTownHandler.h"
|
||||||
|
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CBattleAnimations.cpp, part of VCMI engine
|
* CBattleAnimations.cpp, part of VCMI engine
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../CAnimation.h"
|
|
||||||
#include "../../lib/BattleHex.h"
|
#include "../../lib/BattleHex.h"
|
||||||
|
#include "../widgets/Images.h"
|
||||||
|
|
||||||
class CBattleInterface;
|
class CBattleInterface;
|
||||||
class CStack;
|
class CStack;
|
||||||
|
@ -1,40 +1,38 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CBattleInterface.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 "CBattleAnimations.h"
|
||||||
#include "CBattleInterfaceClasses.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/CCursorHandler.h"
|
||||||
#include "../gui/CGuiHandler.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"
|
#include "../../lib/UnlockGuard.h"
|
||||||
|
|
||||||
using namespace boost::assign;
|
using namespace boost::assign;
|
||||||
@ -224,17 +222,17 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
|||||||
// blitAt(menu, pos.x, 556 + pos.y);
|
// blitAt(menu, pos.x, 556 + pos.y);
|
||||||
|
|
||||||
//preparing buttons and console
|
//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);
|
bOptions = new CButton (Point( 3, 561), "icm003.def", CGI->generaltexth->zelp[381], boost::bind(&CBattleInterface::bOptionsf,this), 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);
|
bSurrender = new CButton (Point( 54, 561), "icm001.def", CGI->generaltexth->zelp[379], boost::bind(&CBattleInterface::bSurrenderf,this), 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);
|
bFlee = new CButton (Point(105, 561), "icm002.def", CGI->generaltexth->zelp[380], boost::bind(&CBattleInterface::bFleef,this), 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);
|
bAutofight = new CButton (Point(157, 561), "icm004.def", CGI->generaltexth->zelp[382], boost::bind(&CBattleInterface::bAutofightf,this), 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);
|
bSpell = new CButton (Point(645, 561), "icm005.def", CGI->generaltexth->zelp[385], boost::bind(&CBattleInterface::bSpellf,this), 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);
|
bWait = new CButton (Point(696, 561), "icm006.def", CGI->generaltexth->zelp[386], boost::bind(&CBattleInterface::bWaitf,this), 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);
|
bDefence = new CButton (Point(747, 561), "icm007.def", CGI->generaltexth->zelp[387], boost::bind(&CBattleInterface::bDefencef,this), SDLK_d);
|
||||||
bDefence->assignedKeys.insert(SDLK_SPACE);
|
bDefence->assignedKeys.insert(SDLK_SPACE);
|
||||||
bConsoleUp = new CAdventureMapButton (std::string(), std::string(), std::bind(&CBattleInterface::bConsoleUpf,this), 624, 561, "ComSlide.def", SDLK_UP);
|
bConsoleUp = new CButton (Point(624, 561), "ComSlide.def", std::make_pair("", ""), boost::bind(&CBattleInterface::bConsoleUpf,this), SDLK_UP);
|
||||||
bConsoleDown = new CAdventureMapButton (std::string(), std::string(), std::bind(&CBattleInterface::bConsoleDownf,this), 624, 580, "ComSlide.def", SDLK_DOWN);
|
bConsoleDown = new CButton (Point(624, 580), "ComSlide.def", std::make_pair("", ""), boost::bind(&CBattleInterface::bConsoleDownf,this), SDLK_DOWN);
|
||||||
bConsoleDown->setOffset(2);
|
bConsoleDown->setImageOrder(2, 3, 4, 5);
|
||||||
console = new CBattleConsole();
|
console = new CBattleConsole();
|
||||||
console->pos.x += 211;
|
console->pos.x += 211;
|
||||||
console->pos.y += 560;
|
console->pos.y += 560;
|
||||||
@ -242,8 +240,8 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
|||||||
console->pos.h = 38;
|
console->pos.h = 38;
|
||||||
if(tacticsMode)
|
if(tacticsMode)
|
||||||
{
|
{
|
||||||
btactNext = new CAdventureMapButton(std::string(), std::string(), std::bind(&CBattleInterface::bTacticNextStack,this, (CStack*)nullptr), 213, 560, "icm011.def", SDLK_SPACE);
|
btactNext = new CButton(Point(213, 560), "icm011.def", std::make_pair("", ""), [&]{ bTacticNextStack(nullptr);}, SDLK_SPACE);
|
||||||
btactEnd = new CAdventureMapButton(std::string(), std::string(), std::bind(&CBattleInterface::bEndTacticPhase,this), 419, 560, "icm012.def", SDLK_RETURN);
|
btactEnd = new CButton(Point(419, 560), "icm012.def", std::make_pair("", ""), [&]{ bEndTacticPhase();}, SDLK_RETURN);
|
||||||
menu = BitmapHandler::loadBitmap("COPLACBR.BMP");
|
menu = BitmapHandler::loadBitmap("COPLACBR.BMP");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2432,7 +2430,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
|||||||
{
|
{
|
||||||
cursorFrame = ECursor::COMBAT_QUERY;
|
cursorFrame = ECursor::COMBAT_QUERY;
|
||||||
consoleMsg = (boost::format(CGI->generaltexth->allTexts[297]) % shere->getName()).str();
|
consoleMsg = (boost::format(CGI->generaltexth->allTexts[297]) % shere->getName()).str();
|
||||||
realizeAction = [=]{ GH.pushInt(createCreWindow(shere, true)); };
|
realizeAction = [=]{ GH.pushInt(new CStackWindow(shere, false)); };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
#include "../../lib/CCreatureSet.h"
|
//#include "../../lib/CCreatureSet.h"
|
||||||
#include "../../lib/ConstTransitivePtr.h" //may be reundant
|
#include "../../lib/ConstTransitivePtr.h" //may be reundant
|
||||||
#include "../CAnimation.h"
|
|
||||||
#include "../../lib/GameConstants.h"
|
#include "../../lib/GameConstants.h"
|
||||||
|
|
||||||
#include "CBattleAnimations.h"
|
#include "CBattleAnimations.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -23,9 +23,9 @@ class CGHeroInstance;
|
|||||||
class CDefHandler;
|
class CDefHandler;
|
||||||
class CStack;
|
class CStack;
|
||||||
class CCallback;
|
class CCallback;
|
||||||
class CAdventureMapButton;
|
class CButton;
|
||||||
class CHighlightableButton;
|
class CToggleButton;
|
||||||
class CHighlightableButtonsGroup;
|
class CToggleGroup;
|
||||||
struct BattleResult;
|
struct BattleResult;
|
||||||
struct BattleSpellCast;
|
struct BattleSpellCast;
|
||||||
struct CObstacleInstance;
|
struct CObstacleInstance;
|
||||||
@ -120,7 +120,7 @@ class CBattleInterface : public CIntObject
|
|||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
SDL_Surface * background, * menu, * amountNormal, * amountNegative, * amountPositive, * amountEffNeutral, * cellBorders, * backgroundWithHexes;
|
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;
|
* bWait, * bDefence, * bConsoleUp, * bConsoleDown, *btactNext, *btactEnd;
|
||||||
CBattleConsole * console;
|
CBattleConsole * console;
|
||||||
CBattleHero * attackingHero, * defendingHero; //fighting heroes
|
CBattleHero * attackingHero, * defendingHero; //fighting heroes
|
||||||
@ -338,7 +338,7 @@ public:
|
|||||||
InfoAboutHero enemyHero() const;
|
InfoAboutHero enemyHero() const;
|
||||||
|
|
||||||
friend class CPlayerInterface;
|
friend class CPlayerInterface;
|
||||||
friend class CAdventureMapButton;
|
friend class CButton;
|
||||||
friend class CInGameConsole;
|
friend class CInGameConsole;
|
||||||
|
|
||||||
friend class CBattleResultWindow;
|
friend class CBattleResultWindow;
|
||||||
|
@ -1,29 +1,34 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CBattleInterfaceClasses.h"
|
#include "CBattleInterfaceClasses.h"
|
||||||
|
|
||||||
#include "../gui/SDL_Extensions.h"
|
|
||||||
#include "CBattleInterface.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 "../CBitmapHandler.h"
|
||||||
#include "../CCreatureWindow.h"
|
#include "../CDefHandler.h"
|
||||||
|
#include "../CGameInfo.h"
|
||||||
#include "../CMessage.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
|
* CBattleInterfaceClasses.cpp, part of VCMI engine
|
||||||
@ -258,26 +263,23 @@ CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInt
|
|||||||
background = new CPicture("comopbck.bmp");
|
background = new CPicture("comopbck.bmp");
|
||||||
background->colorize(owner->getCurrentPlayerInterface()->playerID);
|
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 = new CToggleButton(Point(25, 56), "sysopchk.def", CGI->generaltexth->zelp[427], [&](bool on){owner->setPrintCellBorders(on);} );
|
||||||
viewGrid->select(settings["battle"]["cellBorders"].Bool());
|
viewGrid->setSelected(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 = new CToggleButton(Point(25, 89), "sysopchk.def", CGI->generaltexth->zelp[428], [&](bool on){owner->setPrintStackRange(on);});
|
||||||
movementShadow->select(settings["battle"]["stackRange"].Bool());
|
movementShadow->setSelected(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 = new CToggleButton(Point(25, 122), "sysopchk.def", CGI->generaltexth->zelp[429], [&](bool on){owner->setPrintMouseShadow(on);});
|
||||||
mouseShadow->select(settings["battle"]["mouseShadow"].Bool());
|
mouseShadow->setSelected(settings["battle"]["mouseShadow"].Bool());
|
||||||
|
|
||||||
animSpeeds = new CHighlightableButtonsGroup(0);
|
animSpeeds = new CToggleGroup([&](int value){ owner->setAnimSpeed(value);});
|
||||||
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[422].first),CGI->generaltexth->zelp[422].second, "sysopb9.def", 28, 225, 40);
|
animSpeeds->addToggle(40, new CToggleButton(Point( 28, 225), "sysopb9.def", CGI->generaltexth->zelp[422]));
|
||||||
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[423].first),CGI->generaltexth->zelp[423].second, "sysob10.def", 92, 225, 63);
|
animSpeeds->addToggle(63, new CToggleButton(Point( 92, 225), "sysob10.def", CGI->generaltexth->zelp[423]));
|
||||||
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[424].first),CGI->generaltexth->zelp[424].second, "sysob11.def",156, 225, 100);
|
animSpeeds->addToggle(100, new CToggleButton(Point(156, 225), "sysob11.def", CGI->generaltexth->zelp[424]));
|
||||||
animSpeeds->select(owner->getAnimSpeed(), 1);
|
animSpeeds->setSelected(owner->getAnimSpeed());
|
||||||
animSpeeds->onChange = std::bind(&CBattleInterface::setAnimSpeed, owner, _1);
|
|
||||||
|
|
||||||
setToDefault = new CAdventureMapButton (CGI->generaltexth->zelp[393], std::bind(&CBattleOptionsWindow::bDefaultf,this), 246, 359, "codefaul.def");
|
setToDefault = new CButton (Point(246, 359), "codefaul.def", CGI->generaltexth->zelp[393], [&]{ bDefaultf(); });
|
||||||
setToDefault->swappedImages = true;
|
setToDefault->setImageOrder(1, 0, 2, 3);
|
||||||
setToDefault->update();
|
exit = new CButton (Point(357, 359), "soretrn.def", CGI->generaltexth->zelp[392], [&]{ bExitf();}, SDLK_RETURN);
|
||||||
exit = new CAdventureMapButton (CGI->generaltexth->zelp[392], std::bind(&CBattleOptionsWindow::bExitf,this), 357, 359, "soretrn.def",SDLK_RETURN);
|
exit->setImageOrder(1, 0, 2, 3);
|
||||||
exit->swappedImages = true;
|
|
||||||
exit->update();
|
|
||||||
|
|
||||||
//creating labels
|
//creating labels
|
||||||
labels.push_back(new CLabel(242, 32, FONT_BIG, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[392]));//window title
|
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()
|
void CBattleOptionsWindow::bDefaultf()
|
||||||
{
|
{
|
||||||
|
//TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBattleOptionsWindow::bExitf()
|
void CBattleOptionsWindow::bExitf()
|
||||||
@ -322,9 +325,8 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
|
|||||||
CPicture * bg = new CPicture("CPRESULT");
|
CPicture * bg = new CPicture("CPRESULT");
|
||||||
bg->colorize(owner.playerID);
|
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->borderColor = Colors::METALLIC_GOLD;
|
||||||
exit->borderEnabled = true;
|
|
||||||
|
|
||||||
if(br.winner==0) //attacker won
|
if(br.winner==0) //attacker won
|
||||||
{
|
{
|
||||||
@ -606,7 +608,7 @@ void CClickableHex::clickRight(tribool down, bool previousState)
|
|||||||
if(!myst->alive()) return;
|
if(!myst->alive()) return;
|
||||||
if(down)
|
if(down)
|
||||||
{
|
{
|
||||||
GH.pushInt(createCreWindow(myst));
|
GH.pushInt(new CStackWindow(myst, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -701,7 +703,7 @@ CStackQueue::StackBox::StackBox(bool small):
|
|||||||
small(small)
|
small(small)
|
||||||
{
|
{
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
bg = new CPicture(small ? "StackQueueBgSmall" : "StackQueueBgBig" );
|
bg = new CPicture(small ? "StackQueueSmall" : "StackQueueLarge" );
|
||||||
|
|
||||||
if (small)
|
if (small)
|
||||||
{
|
{
|
||||||
|
@ -8,9 +8,9 @@ class CDefHandler;
|
|||||||
class CGHeroInstance;
|
class CGHeroInstance;
|
||||||
class CBattleInterface;
|
class CBattleInterface;
|
||||||
class CPicture;
|
class CPicture;
|
||||||
class CAdventureMapButton;
|
class CButton;
|
||||||
class CHighlightableButton;
|
class CToggleButton;
|
||||||
class CHighlightableButtonsGroup;
|
class CToggleGroup;
|
||||||
class CLabel;
|
class CLabel;
|
||||||
struct BattleResult;
|
struct BattleResult;
|
||||||
class CStack;
|
class CStack;
|
||||||
@ -72,9 +72,9 @@ class CBattleOptionsWindow : public CIntObject
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
CPicture * background;
|
CPicture * background;
|
||||||
CAdventureMapButton * setToDefault, * exit;
|
CButton * setToDefault, * exit;
|
||||||
CHighlightableButton * viewGrid, * movementShadow, * mouseShadow;
|
CToggleButton * viewGrid, * movementShadow, * mouseShadow;
|
||||||
CHighlightableButtonsGroup * animSpeeds;
|
CToggleGroup * animSpeeds;
|
||||||
|
|
||||||
std::vector<CLabel*> labels;
|
std::vector<CLabel*> labels;
|
||||||
public:
|
public:
|
||||||
@ -88,7 +88,7 @@ public:
|
|||||||
class CBattleResultWindow : public CIntObject
|
class CBattleResultWindow : public CIntObject
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
CAdventureMapButton *exit;
|
CButton *exit;
|
||||||
CPlayerInterface &owner;
|
CPlayerInterface &owner;
|
||||||
public:
|
public:
|
||||||
CBattleResultWindow(const BattleResult & br, const SDL_Rect & pos, CPlayerInterface &_owner); //c-tor
|
CBattleResultWindow(const BattleResult & br, const SDL_Rect & pos, CPlayerInterface &_owner); //c-tor
|
||||||
@ -152,4 +152,4 @@ public:
|
|||||||
void update();
|
void update();
|
||||||
void showAll(SDL_Surface *to);
|
void showAll(SDL_Surface *to);
|
||||||
void blitBg(SDL_Surface * to);
|
void blitBg(SDL_Surface * to);
|
||||||
};
|
};
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CCreatureAnimation.h"
|
#include "CCreatureAnimation.h"
|
||||||
|
|
||||||
|
#include "../../lib/vcmi_endian.h"
|
||||||
#include "../../lib/CConfigHandler.h"
|
#include "../../lib/CConfigHandler.h"
|
||||||
#include "../../lib/CCreatureHandler.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/Filesystem.h"
|
||||||
#include "../../lib/filesystem/CBinaryReader.h"
|
#include "../../lib/filesystem/CBinaryReader.h"
|
||||||
#include "../../lib/filesystem/CMemoryStream.h"
|
#include "../../lib/filesystem/CMemoryStream.h"
|
||||||
|
|
||||||
|
#include "../gui/SDL_Extensions.h"
|
||||||
|
#include "../gui/SDL_Pixels.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CCreatureAnimation.cpp, part of VCMI engine
|
* CCreatureAnimation.cpp, part of VCMI engine
|
||||||
*
|
*
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../../lib/FunctionList.h"
|
#include "../../lib/FunctionList.h"
|
||||||
#include "../CAnimation.h"
|
#include "../gui/SDL_Extensions.h"
|
||||||
|
#include "../widgets/Images.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CCreatureAnimation.h, part of VCMI engine
|
* CCreatureAnimation.h, part of VCMI engine
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
|
#include "CAnimation.h"
|
||||||
|
|
||||||
#include <SDL_image.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/Filesystem.h"
|
||||||
#include "../lib/filesystem/ISimpleResourceLoader.h"
|
#include "../lib/filesystem/ISimpleResourceLoader.h"
|
||||||
#include "../lib/JsonNode.h"
|
#include "../lib/JsonNode.h"
|
||||||
#include "../lib/CRandomGenerator.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
|
* CAnimation.cpp, part of VCMI engine
|
||||||
*
|
*
|
||||||
@ -1221,6 +1222,7 @@ void CAnimation::getAnimInfo()
|
|||||||
logGlobal->errorStream()<<", "<<anim->images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first;
|
logGlobal->errorStream()<<", "<<anim->images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
<<<<<<< HEAD:client/CAnimation.cpp
|
||||||
|
|
||||||
CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
|
CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
|
||||||
frame(Frame),
|
frame(Frame),
|
||||||
@ -1537,3 +1539,5 @@ void CCreatureAnim::clearAndSet(EAnimType type)
|
|||||||
queue.pop();
|
queue.pop();
|
||||||
set(type);
|
set(type);
|
||||||
}
|
}
|
||||||
|
=======
|
||||||
|
>>>>>>> refactoring/guiClasses:client/gui/CAnimation.cpp
|
@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../lib/vcmi_endian.h"
|
#include "../../lib/vcmi_endian.h"
|
||||||
#include "gui/CIntObject.h"
|
#include "gui/Geometries.h"
|
||||||
|
#include "../../lib/GameConstants.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CAnimation.h, part of VCMI engine
|
* CAnimation.h, part of VCMI engine
|
||||||
@ -219,162 +220,3 @@ public:
|
|||||||
//total count of frames in group (including not loaded)
|
//total count of frames in group (including not loaded)
|
||||||
size_t size(size_t group=0) const;
|
size_t size(size_t group=0) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Class for displaying one image from animation
|
|
||||||
class CAnimImage: public CIntObject
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
CAnimation* anim;
|
|
||||||
//displayed frame/group
|
|
||||||
size_t frame;
|
|
||||||
size_t group;
|
|
||||||
PlayerColor player;
|
|
||||||
ui8 flags;
|
|
||||||
|
|
||||||
void init();
|
|
||||||
|
|
||||||
public:
|
|
||||||
CAnimImage(std::string name, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
|
|
||||||
CAnimImage(CAnimation* anim, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
|
|
||||||
~CAnimImage();//d-tor
|
|
||||||
|
|
||||||
//size of animation
|
|
||||||
size_t size();
|
|
||||||
|
|
||||||
//change displayed frame on this one
|
|
||||||
void setFrame(size_t Frame, size_t Group=0);
|
|
||||||
|
|
||||||
//makes image player-colored
|
|
||||||
void playerColored(PlayerColor player);
|
|
||||||
|
|
||||||
void showAll(SDL_Surface * to);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Base class for displaying animation, used as superclass for different animations
|
|
||||||
class CShowableAnim: public CIntObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum EFlags
|
|
||||||
{
|
|
||||||
BASE=1, //base frame will be blitted before current one
|
|
||||||
HORIZONTAL_FLIP=2, //TODO: will be displayed rotated
|
|
||||||
VERTICAL_FLIP=4, //TODO: will be displayed rotated
|
|
||||||
USE_RLE=8, //RLE-d version, support full alpha-channel for 8-bit images
|
|
||||||
PLAYER_COLORED=16, //TODO: all loaded images will be player-colored
|
|
||||||
PLAY_ONCE=32 //play animation only once and stop at last frame
|
|
||||||
};
|
|
||||||
protected:
|
|
||||||
CAnimation anim;
|
|
||||||
|
|
||||||
size_t group, frame;//current frame
|
|
||||||
|
|
||||||
size_t first, last; //animation range
|
|
||||||
|
|
||||||
//TODO: replace with time delay(needed for battles)
|
|
||||||
ui32 frameDelay;//delay in frames of each image
|
|
||||||
ui32 value;//how many times current frame was showed
|
|
||||||
|
|
||||||
ui8 flags;//Flags from EFlags enum
|
|
||||||
|
|
||||||
//blit image with optional rotation, fitting into rect, etc
|
|
||||||
void blitImage(size_t frame, size_t group, SDL_Surface *to);
|
|
||||||
|
|
||||||
//For clipping in rect, offsets of picture coordinates
|
|
||||||
int xOffset, yOffset;
|
|
||||||
|
|
||||||
ui8 alpha;
|
|
||||||
|
|
||||||
public:
|
|
||||||
//called when next animation sequence is required
|
|
||||||
std::function<void()> callback;
|
|
||||||
|
|
||||||
//Set per-surface alpha, 0 = transparent, 255 = opaque
|
|
||||||
void setAlpha(ui32 alphaValue);
|
|
||||||
|
|
||||||
CShowableAnim(int x, int y, std::string name, ui8 flags=0, ui32 Delay=4, size_t Group=0);
|
|
||||||
~CShowableAnim();
|
|
||||||
|
|
||||||
//set animation to group or part of group
|
|
||||||
bool set(size_t Group);
|
|
||||||
bool set(size_t Group, size_t from, size_t to=-1);
|
|
||||||
|
|
||||||
//set rotation flags
|
|
||||||
void rotate(bool on, bool vertical=false);
|
|
||||||
|
|
||||||
//move displayed part of picture (if picture is clipped to rect)
|
|
||||||
void clipRect(int posX, int posY, int width, int height);
|
|
||||||
|
|
||||||
//set frame to first, call callback
|
|
||||||
virtual void reset();
|
|
||||||
|
|
||||||
//show current frame and increase counter
|
|
||||||
void show(SDL_Surface * to);
|
|
||||||
void showAll(SDL_Surface * to);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Creature-dependend animations like attacking, moving,...
|
|
||||||
class CCreatureAnim: public CShowableAnim
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum EHeroAnimType
|
|
||||||
{
|
|
||||||
HERO_HOLDING = 0,
|
|
||||||
HERO_IDLE = 1, // idling movement that happens from time to time
|
|
||||||
HERO_DEFEAT = 2, // played when army loses stack or on friendly fire
|
|
||||||
HERO_VICTORY = 3, // when enemy stack killed or huge damage is dealt
|
|
||||||
HERO_CAST_SPELL = 4 // spellcasting
|
|
||||||
};
|
|
||||||
|
|
||||||
enum EAnimType // list of creature animations, numbers were taken from def files
|
|
||||||
{
|
|
||||||
MOVING=0,
|
|
||||||
MOUSEON=1,
|
|
||||||
HOLDING=2,
|
|
||||||
HITTED=3,
|
|
||||||
DEFENCE=4,
|
|
||||||
DEATH=5,
|
|
||||||
//DEATH2=6, //unused?
|
|
||||||
TURN_L=7,
|
|
||||||
TURN_R=8, //same
|
|
||||||
//TURN_L2=9, //identical to previous?
|
|
||||||
//TURN_R2=10,
|
|
||||||
ATTACK_UP=11,
|
|
||||||
ATTACK_FRONT=12,
|
|
||||||
ATTACK_DOWN=13,
|
|
||||||
SHOOT_UP=14,
|
|
||||||
SHOOT_FRONT=15,
|
|
||||||
SHOOT_DOWN=16,
|
|
||||||
CAST_UP=17,
|
|
||||||
CAST_FRONT=18,
|
|
||||||
CAST_DOWN=19,
|
|
||||||
MOVE_START=20,
|
|
||||||
MOVE_END=21,
|
|
||||||
DEAD = 22 // new group, used to show dead stacks. If empty - last frame from "DEATH" will be copied here
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
//queue of animations waiting to be displayed
|
|
||||||
std::queue<EAnimType> queue;
|
|
||||||
|
|
||||||
//this function is used as callback if preview flag was set during construction
|
|
||||||
void loopPreview(bool warMachine);
|
|
||||||
|
|
||||||
public:
|
|
||||||
//change anim to next if queue is not empty, call callback othervice
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
//add sequence to the end of queue
|
|
||||||
void addLast(EAnimType newType);
|
|
||||||
|
|
||||||
void startPreview(bool warMachine);
|
|
||||||
|
|
||||||
//clear queue and set animation to this sequence
|
|
||||||
void clearAndSet(EAnimType type);
|
|
||||||
|
|
||||||
CCreatureAnim(int x, int y, std::string name, Rect picPos,
|
|
||||||
ui8 flags= USE_RLE, EAnimType = HOLDING );
|
|
||||||
|
|
||||||
};
|
|
@ -2,9 +2,11 @@
|
|||||||
#include "CCursorHandler.h"
|
#include "CCursorHandler.h"
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
#include "SDL_Extensions.h"
|
#include "SDL_Extensions.h"
|
||||||
#include "../CAnimation.h"
|
|
||||||
#include "CGuiHandler.h"
|
#include "CGuiHandler.h"
|
||||||
|
#include "widgets/Images.h"
|
||||||
|
|
||||||
#include "../CMT.h"
|
#include "../CMT.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CGuiHandler.h"
|
#include "CGuiHandler.h"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
#include "CIntObject.h"
|
#include "CIntObject.h"
|
||||||
#include "../CGameInfo.h"
|
|
||||||
#include "CCursorHandler.h"
|
#include "CCursorHandler.h"
|
||||||
|
|
||||||
|
#include "../CGameInfo.h"
|
||||||
#include "../../lib/CThreadHelper.h"
|
#include "../../lib/CThreadHelper.h"
|
||||||
#include "../../lib/CConfigHandler.h"
|
#include "../../lib/CConfigHandler.h"
|
||||||
#include "../CMT.h"
|
#include "../CMT.h"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../../lib/CStopWatch.h"
|
//#include "../../lib/CStopWatch.h"
|
||||||
#include "Geometries.h"
|
#include "Geometries.h"
|
||||||
#include "SDL_Extensions.h"
|
#include "SDL_Extensions.h"
|
||||||
|
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CIntObject.h"
|
#include "CIntObject.h"
|
||||||
|
|
||||||
#include "CGuiHandler.h"
|
#include "CGuiHandler.h"
|
||||||
#include "SDL_Extensions.h"
|
#include "SDL_Extensions.h"
|
||||||
#include "../CMessage.h"
|
#include "../CMessage.h"
|
||||||
|
|
||||||
|
IShowActivatable::IShowActivatable()
|
||||||
|
{
|
||||||
|
type = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ILockedUpdatable::runLocked(std::function<void(IUpdateable*)> cb)
|
void ILockedUpdatable::runLocked(std::function<void(IUpdateable*)> cb)
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::recursive_mutex> lock(updateGuard);
|
boost::unique_lock<boost::recursive_mutex> lock(updateGuard);
|
||||||
@ -317,6 +323,19 @@ bool CIntObject::captureThisEvent(const SDL_KeyboardEvent & key)
|
|||||||
return captureAllKeys;
|
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)
|
void CKeyShortcut::keyPressed(const SDL_KeyboardEvent & key)
|
||||||
{
|
{
|
||||||
if(vstd::contains(assignedKeys,key.keysym.sym)
|
if(vstd::contains(assignedKeys,key.keysym.sym)
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SDL_events.h>
|
//#include <SDL_events.h>
|
||||||
#include "Geometries.h"
|
#include "Geometries.h"
|
||||||
#include "../Graphics.h"
|
#include "../Graphics.h"
|
||||||
|
|
||||||
@ -18,6 +18,8 @@ struct SDL_Surface;
|
|||||||
class CPicture;
|
class CPicture;
|
||||||
class CGuiHandler;
|
class CGuiHandler;
|
||||||
|
|
||||||
|
struct SDL_KeyboardEvent;
|
||||||
|
|
||||||
using boost::logic::tribool;
|
using boost::logic::tribool;
|
||||||
|
|
||||||
// Defines a activate/deactive method
|
// Defines a activate/deactive method
|
||||||
@ -216,8 +218,8 @@ class CKeyShortcut : public virtual CIntObject
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::set<int> assignedKeys;
|
std::set<int> assignedKeys;
|
||||||
CKeyShortcut(){}; //c-tor
|
CKeyShortcut();
|
||||||
CKeyShortcut(int key){assignedKeys.insert(key);}; //c-tor
|
CKeyShortcut(int key);
|
||||||
CKeyShortcut(std::set<int> Keys):assignedKeys(Keys){}; //c-tor
|
CKeyShortcut(std::set<int> Keys);
|
||||||
virtual void keyPressed(const SDL_KeyboardEvent & key); //call-in
|
virtual void keyPressed(const SDL_KeyboardEvent & key); //call-in
|
||||||
};
|
};
|
||||||
|
@ -1,557 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CIntObject.h"
|
|
||||||
#include "SDL_Extensions.h"
|
|
||||||
#include "../../lib/FunctionList.h"
|
|
||||||
|
|
||||||
struct SDL_Surface;
|
|
||||||
struct Rect;
|
|
||||||
class CAnimImage;
|
|
||||||
class CLabel;
|
|
||||||
class CAnimation;
|
|
||||||
class CDefHandler;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CPicture.h, part of VCMI engine
|
|
||||||
*
|
|
||||||
* Authors: listed in file AUTHORS in main folder
|
|
||||||
*
|
|
||||||
* License: GNU General Public License v2.0 or later
|
|
||||||
* Full text of license available in license.txt file, in main folder
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Window GUI class
|
|
||||||
class CSimpleWindow : public CIntObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SDL_Surface * bitmap; //background
|
|
||||||
virtual void show(SDL_Surface * to);
|
|
||||||
CSimpleWindow():bitmap(nullptr){}; //c-tor
|
|
||||||
virtual ~CSimpleWindow(); //d-tor
|
|
||||||
};
|
|
||||||
|
|
||||||
// Image class
|
|
||||||
class CPicture : public CIntObject
|
|
||||||
{
|
|
||||||
void setSurface(SDL_Surface *to);
|
|
||||||
public:
|
|
||||||
SDL_Surface * bg;
|
|
||||||
Rect * srcRect; //if nullptr then whole surface will be used
|
|
||||||
bool freeSurf; //whether surface will be freed upon CPicture destruction
|
|
||||||
bool needRefresh;//Surface needs to be displayed each frame
|
|
||||||
|
|
||||||
operator SDL_Surface*()
|
|
||||||
{
|
|
||||||
return bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
CPicture(const Rect & r, const SDL_Color & color, bool screenFormat = false); //rect filled with given color
|
|
||||||
CPicture(const Rect & r, ui32 color, bool screenFormat = false); //rect filled with given color
|
|
||||||
CPicture(SDL_Surface * BG, int x = 0, int y=0, bool Free = true); //wrap existing SDL_Surface
|
|
||||||
CPicture(const std::string &bmpname, int x=0, int y=0);
|
|
||||||
CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0, bool free = false); //wrap subrect of given surface
|
|
||||||
~CPicture();
|
|
||||||
void init();
|
|
||||||
|
|
||||||
//set alpha value for whole surface. Note: may be messed up if surface is shared
|
|
||||||
// 0=transparent, 255=opaque
|
|
||||||
void setAlpha(int value);
|
|
||||||
|
|
||||||
void scaleTo(Point size);
|
|
||||||
void createSimpleRect(const Rect &r, bool screenFormat, ui32 color);
|
|
||||||
void show(SDL_Surface * to);
|
|
||||||
void showAll(SDL_Surface * to);
|
|
||||||
void convertToScreenBPP();
|
|
||||||
void colorizeAndConvert(PlayerColor player);
|
|
||||||
void colorize(PlayerColor player);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// area filled with specific texture
|
|
||||||
class CFilledTexture : CIntObject
|
|
||||||
{
|
|
||||||
SDL_Surface * texture;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CFilledTexture(std::string imageName, Rect position);
|
|
||||||
~CFilledTexture();
|
|
||||||
void showAll(SDL_Surface *to);
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace config{struct ButtonInfo;}
|
|
||||||
|
|
||||||
/// Base class for buttons.
|
|
||||||
class CButtonBase : public CKeyShortcut
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum ButtonState
|
|
||||||
{
|
|
||||||
NORMAL=0,
|
|
||||||
PRESSED=1,
|
|
||||||
BLOCKED=2,
|
|
||||||
HIGHLIGHTED=3
|
|
||||||
};
|
|
||||||
private:
|
|
||||||
int bitmapOffset; // base offset of visible bitmap from animation
|
|
||||||
ButtonState state;//current state of button from enum
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool swappedImages,//fix for some buttons: normal and pressed image are swapped
|
|
||||||
keepFrame; // don't change visual representation
|
|
||||||
|
|
||||||
void addTextOverlay(const std::string &Text, EFonts font, SDL_Color color = Colors::WHITE);
|
|
||||||
void update();//to refresh button after image or text change
|
|
||||||
|
|
||||||
void setOffset(int newOffset);
|
|
||||||
void setState(ButtonState newState);
|
|
||||||
ButtonState getState();
|
|
||||||
|
|
||||||
//just to make code clearer
|
|
||||||
void block(bool on);
|
|
||||||
bool isBlocked();
|
|
||||||
bool isHighlighted();
|
|
||||||
|
|
||||||
CAnimImage * image; //image for this button
|
|
||||||
CLabel * text;//text overlay
|
|
||||||
|
|
||||||
CButtonBase(); //c-tor
|
|
||||||
virtual ~CButtonBase(); //d-tor
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Typical Heroes 3 button which can be inactive or active and can
|
|
||||||
/// hold further information if you right-click it
|
|
||||||
class CAdventureMapButton : public CButtonBase
|
|
||||||
{
|
|
||||||
std::vector<std::string> imageNames;//store list of images that can be used by this button
|
|
||||||
size_t currentImage;
|
|
||||||
|
|
||||||
void onButtonClicked(); // calls callback
|
|
||||||
public:
|
|
||||||
std::map<int, std::string> hoverTexts; //text for statusbar
|
|
||||||
std::string helpBox; //for right-click help
|
|
||||||
CFunctionList<void()> callback;
|
|
||||||
bool actOnDown,//runs when mouse is pressed down over it, not when up
|
|
||||||
hoverable,//if true, button will be highlighted when hovered
|
|
||||||
borderEnabled,
|
|
||||||
soundDisabled;
|
|
||||||
SDL_Color borderColor;
|
|
||||||
|
|
||||||
void clickRight(tribool down, bool previousState);
|
|
||||||
virtual void clickLeft(tribool down, bool previousState);
|
|
||||||
void hover (bool on);
|
|
||||||
|
|
||||||
CAdventureMapButton(); //c-tor
|
|
||||||
CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
|
|
||||||
CAdventureMapButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
|
|
||||||
CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, config::ButtonInfo *info, int key=0);//c-tor
|
|
||||||
|
|
||||||
void init(const CFunctionList<void()> &Callback, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key );
|
|
||||||
|
|
||||||
void setIndex(size_t index, bool playerColoredButton=false);
|
|
||||||
void setImage(CAnimation* anim, bool playerColoredButton=false, int animFlags=0);
|
|
||||||
void setPlayerColor(PlayerColor player);
|
|
||||||
void showAll(SDL_Surface * to);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A button which can be selected/deselected
|
|
||||||
class CHighlightableButton
|
|
||||||
: public CAdventureMapButton
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CHighlightableButton(const CFunctionList<void()> &onSelect, const CFunctionList<void()> &onDeselect, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key=0);
|
|
||||||
CHighlightableButton(const std::pair<std::string, std::string> &help, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
|
|
||||||
CHighlightableButton(const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
|
|
||||||
bool onlyOn;//button can not be de-selected
|
|
||||||
bool selected;//state of highlightable button
|
|
||||||
int ID; //for identification
|
|
||||||
CFunctionList<void()> callback2; //when de-selecting
|
|
||||||
void select(bool on);
|
|
||||||
void clickLeft(tribool down, bool previousState);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A group of buttons where one button can be selected
|
|
||||||
class CHighlightableButtonsGroup : public CIntObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CFunctionList<void(int)> onChange; //called when changing selected button with new button's id
|
|
||||||
std::vector<CHighlightableButton*> buttons;
|
|
||||||
bool musicLike; //determines the behaviour of this group
|
|
||||||
|
|
||||||
//void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid);
|
|
||||||
void addButton(CHighlightableButton* bt);//add existing button, it'll be deleted by CHighlightableButtonsGroup destructor
|
|
||||||
void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList<void()> &OnSelect=0, int key=0); //creates new button
|
|
||||||
CHighlightableButtonsGroup(const CFunctionList<void(int)> & OnChange, bool musicLikeButtons = false);
|
|
||||||
~CHighlightableButtonsGroup();
|
|
||||||
void select(int id, bool mode); //mode==0: id is serial; mode==1: id is unique button id
|
|
||||||
void selectionChanged(int to);
|
|
||||||
void show(SDL_Surface * to);
|
|
||||||
void showAll(SDL_Surface * to);
|
|
||||||
void block(ui8 on);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A typical slider which can be orientated horizontally/vertically.
|
|
||||||
class CSlider : public CIntObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CAdventureMapButton *left, *right, *slider; //if vertical then left=up
|
|
||||||
int capacity;//how many elements can be active at same time (e.g. hero list = 5)
|
|
||||||
int amount; //total amount of elements (e.g. hero list = 0-8)
|
|
||||||
int positions; //number of highest position (0 if there is only one)
|
|
||||||
int value; //first active element
|
|
||||||
int scrollStep; // how many elements will be scrolled via one click, default = 1
|
|
||||||
bool horizontal;
|
|
||||||
bool wheelScrolling;
|
|
||||||
bool keyScrolling;
|
|
||||||
|
|
||||||
std::function<void(int)> moved;
|
|
||||||
|
|
||||||
void redrawSlider();
|
|
||||||
void sliderClicked();
|
|
||||||
void moveLeft();
|
|
||||||
void moveRight();
|
|
||||||
void moveTo(int to);
|
|
||||||
void block(bool on);
|
|
||||||
void setAmount(int to);
|
|
||||||
|
|
||||||
void keyPressed(const SDL_KeyboardEvent & key);
|
|
||||||
void wheelScrolled(bool down, bool in);
|
|
||||||
void clickLeft(tribool down, bool previousState);
|
|
||||||
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
|
|
||||||
void showAll(SDL_Surface * to);
|
|
||||||
|
|
||||||
CSlider(int x, int y, int totalw, std::function<void(int)> Moved, int Capacity, int Amount,
|
|
||||||
int Value=0, bool Horizontal=true, int style = 0); //style 0 - brown, 1 - blue
|
|
||||||
~CSlider();
|
|
||||||
void moveToMax();
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Used as base for Tabs and List classes
|
|
||||||
class CObjectList : public CIntObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::function<CIntObject* (size_t)> CreateFunc;
|
|
||||||
typedef std::function<void(CIntObject *)> DestroyFunc;
|
|
||||||
|
|
||||||
private:
|
|
||||||
CreateFunc createObject;
|
|
||||||
DestroyFunc destroyObject;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//Internal methods for safe creation of items (Children capturing and activation/deactivation if needed)
|
|
||||||
void deleteItem(CIntObject* item);
|
|
||||||
CIntObject* createItem(size_t index);
|
|
||||||
|
|
||||||
CObjectList(CreateFunc create, DestroyFunc destroy = DestroyFunc());//Protected constructor
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Window element with multiple tabs
|
|
||||||
class CTabbedInt : public CObjectList
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
CIntObject * activeTab;
|
|
||||||
size_t activeID;
|
|
||||||
|
|
||||||
public:
|
|
||||||
//CreateFunc, DestroyFunc - see CObjectList
|
|
||||||
//Pos - position of object, all tabs will be moved to this position
|
|
||||||
//ActiveID - ID of initially active tab
|
|
||||||
CTabbedInt(CreateFunc create, DestroyFunc destroy = DestroyFunc(), Point position=Point(), size_t ActiveID=0);
|
|
||||||
|
|
||||||
void setActive(size_t which);
|
|
||||||
//recreate active tab
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
//return currently active item
|
|
||||||
CIntObject * getItem();
|
|
||||||
};
|
|
||||||
|
|
||||||
/// List of IntObjects with optional slider
|
|
||||||
class CListBox : public CObjectList
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::list< CIntObject* > items;
|
|
||||||
size_t first;
|
|
||||||
size_t totalSize;
|
|
||||||
|
|
||||||
Point itemOffset;
|
|
||||||
CSlider * slider;
|
|
||||||
|
|
||||||
void updatePositions();
|
|
||||||
public:
|
|
||||||
//CreateFunc, DestroyFunc - see CObjectList
|
|
||||||
//Pos - position of first item
|
|
||||||
//ItemOffset - distance between items in the list
|
|
||||||
//VisibleSize - maximal number of displayable at once items
|
|
||||||
//TotalSize
|
|
||||||
//Slider - slider style, bit field: 1 = present(disabled), 2=horisontal(vertical), 4=blue(brown)
|
|
||||||
//SliderPos - position of slider, if present
|
|
||||||
CListBox(CreateFunc create, DestroyFunc destroy, Point Pos, Point ItemOffset, size_t VisibleSize,
|
|
||||||
size_t TotalSize, size_t InitialPos=0, int Slider=0, Rect SliderPos=Rect() );
|
|
||||||
|
|
||||||
//recreate all visible items
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
//change or get total amount of items in the list
|
|
||||||
void resize(size_t newSize);
|
|
||||||
size_t size();
|
|
||||||
|
|
||||||
//return item with index which or null if not present
|
|
||||||
CIntObject * getItem(size_t which);
|
|
||||||
|
|
||||||
//return currently active items
|
|
||||||
const std::list< CIntObject * > & getItems();
|
|
||||||
|
|
||||||
//get index of this item. -1 if not found
|
|
||||||
size_t getIndexOf(CIntObject * item);
|
|
||||||
|
|
||||||
//scroll list to make item which visible
|
|
||||||
void scrollTo(size_t which);
|
|
||||||
|
|
||||||
//scroll list to specified position
|
|
||||||
void moveToPos(size_t which);
|
|
||||||
void moveToNext();
|
|
||||||
void moveToPrev();
|
|
||||||
|
|
||||||
size_t getPos();
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Small helper class to manage group of similar labels
|
|
||||||
class CLabelGroup : public CIntObject
|
|
||||||
{
|
|
||||||
std::list<CLabel*> labels;
|
|
||||||
EFonts font;
|
|
||||||
EAlignment align;
|
|
||||||
SDL_Color color;
|
|
||||||
public:
|
|
||||||
CLabelGroup(EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE);
|
|
||||||
void add(int x=0, int y=0, const std::string &text = "");
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Base class for all text-related widgets.
|
|
||||||
/// Controls text blitting-related options
|
|
||||||
class CTextContainer : public virtual CIntObject
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
/// returns size of border, for left- or right-aligned text
|
|
||||||
virtual Point getBorderSize() = 0;
|
|
||||||
/// do actual blitting of line. Text "what" will be placed at "where" and aligned according to alignment
|
|
||||||
void blitLine(SDL_Surface * to, Rect where, std::string what);
|
|
||||||
|
|
||||||
CTextContainer(EAlignment alignment, EFonts font, SDL_Color color);
|
|
||||||
|
|
||||||
public:
|
|
||||||
EAlignment alignment;
|
|
||||||
EFonts font;
|
|
||||||
SDL_Color color; // default font color. Can be overridden by placing "{}" into the string
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Label which shows text
|
|
||||||
class CLabel : public CTextContainer
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
Point getBorderSize() override;
|
|
||||||
virtual std::string visibleText();
|
|
||||||
|
|
||||||
CPicture *bg;
|
|
||||||
public:
|
|
||||||
|
|
||||||
std::string text;
|
|
||||||
bool autoRedraw; //whether control will redraw itself on setTxt
|
|
||||||
|
|
||||||
std::string getText();
|
|
||||||
virtual void setText(const std::string &Txt);
|
|
||||||
|
|
||||||
CLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT,
|
|
||||||
const SDL_Color &Color = Colors::WHITE, const std::string &Text = "");
|
|
||||||
void showAll(SDL_Surface * to); //shows statusbar (with current text)
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Multi-line label that can display multiple lines of text
|
|
||||||
/// If text is too big to fit into requested area remaining part will not be visible
|
|
||||||
class CMultiLineLabel : public CLabel
|
|
||||||
{
|
|
||||||
// text to blit, split into lines that are no longer than widget width
|
|
||||||
std::vector<std::string> lines;
|
|
||||||
|
|
||||||
// area of text that actually will be printed, default is widget size
|
|
||||||
Rect visibleSize;
|
|
||||||
|
|
||||||
void splitText(const std::string &Txt);
|
|
||||||
Rect getTextLocation();
|
|
||||||
public:
|
|
||||||
// total size of text, x = longest line of text, y = total height of lines
|
|
||||||
Point textSize;
|
|
||||||
|
|
||||||
CMultiLineLabel(Rect position, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE, const std::string &Text = "");
|
|
||||||
|
|
||||||
void setText(const std::string &Txt);
|
|
||||||
void showAll(SDL_Surface * to);
|
|
||||||
|
|
||||||
void setVisibleSize(Rect visibleSize);
|
|
||||||
// scrolls text visible in widget. Positive value will move text up
|
|
||||||
void scrollTextTo(int distance);
|
|
||||||
void scrollTextBy(int distance);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// a multi-line label that tries to fit text with given available width and height;
|
|
||||||
/// if not possible, it creates a slider for scrolling text
|
|
||||||
class CTextBox : public CIntObject
|
|
||||||
{
|
|
||||||
int sliderStyle;
|
|
||||||
public:
|
|
||||||
CMultiLineLabel * label;
|
|
||||||
CSlider *slider;
|
|
||||||
|
|
||||||
CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE);
|
|
||||||
|
|
||||||
void resize(Point newSize);
|
|
||||||
void setText(const std::string &Txt);
|
|
||||||
void sliderMoved(int to);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Status bar which is shown at the bottom of the in-game screens
|
|
||||||
class CGStatusBar : public CLabel
|
|
||||||
{
|
|
||||||
bool textLock; //Used for blocking changes to the text
|
|
||||||
void init();
|
|
||||||
|
|
||||||
CGStatusBar *oldStatusBar;
|
|
||||||
protected:
|
|
||||||
Point getBorderSize() override;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void clear();//clears statusbar and refreshes
|
|
||||||
void setText(const std::string & Text) override; //prints text and refreshes statusbar
|
|
||||||
|
|
||||||
void show(SDL_Surface * to); //shows statusbar (with current text)
|
|
||||||
|
|
||||||
CGStatusBar(CPicture *BG, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = Colors::WHITE); //given CPicture will be captured by created sbar and it's pos will be used as pos for sbar
|
|
||||||
CGStatusBar(int x, int y, std::string name, int maxw=-1);
|
|
||||||
~CGStatusBar();
|
|
||||||
|
|
||||||
void lock(bool shouldLock); //If true, current text cannot be changed until lock(false) is called
|
|
||||||
};
|
|
||||||
|
|
||||||
/// UIElement which can get input focus
|
|
||||||
class CFocusable : public virtual CIntObject
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
virtual void focusGot(){};
|
|
||||||
virtual void focusLost(){};
|
|
||||||
public:
|
|
||||||
bool focus; //only one focusable control can have focus at one moment
|
|
||||||
|
|
||||||
void giveFocus(); //captures focus
|
|
||||||
void moveFocus(); //moves focus to next active control (may be used for tab switching)
|
|
||||||
|
|
||||||
static std::list<CFocusable*> focusables; //all existing objs
|
|
||||||
static CFocusable *inputWithFocus; //who has focus now
|
|
||||||
CFocusable();
|
|
||||||
~CFocusable();
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Text input box where players can enter text
|
|
||||||
class CTextInput : public CLabel, public CFocusable
|
|
||||||
{
|
|
||||||
std::string newText;
|
|
||||||
protected:
|
|
||||||
std::string visibleText() override;
|
|
||||||
|
|
||||||
void focusGot() override;
|
|
||||||
void focusLost() override;
|
|
||||||
public:
|
|
||||||
CFunctionList<void(const std::string &)> cb;
|
|
||||||
CFunctionList<void(std::string &, const std::string &)> filters;
|
|
||||||
void setText(const std::string &nText, bool callCb = false);
|
|
||||||
|
|
||||||
CTextInput(const Rect &Pos, EFonts font, const CFunctionList<void(const std::string &)> &CB);
|
|
||||||
CTextInput(const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList<void(const std::string &)> &CB);
|
|
||||||
CTextInput(const Rect &Pos, SDL_Surface *srf = nullptr);
|
|
||||||
|
|
||||||
void clickLeft(tribool down, bool previousState) override;
|
|
||||||
void keyPressed(const SDL_KeyboardEvent & key) override;
|
|
||||||
bool captureThisEvent(const SDL_KeyboardEvent & key) override;
|
|
||||||
|
|
||||||
#ifndef VCMI_SDL1
|
|
||||||
void textInputed(const SDL_TextInputEvent & event) override;
|
|
||||||
void textEdited(const SDL_TextEditingEvent & event) override;
|
|
||||||
|
|
||||||
|
|
||||||
#endif // VCMI_SDL1
|
|
||||||
|
|
||||||
//Filter that will block all characters not allowed in filenames
|
|
||||||
static void filenameFilter(std::string &text, const std::string & oldText);
|
|
||||||
//Filter that will allow only input of numbers in range min-max (min-max are allowed)
|
|
||||||
//min-max should be set via something like std::bind
|
|
||||||
static void numberFilter(std::string &text, const std::string & oldText, int minValue, int maxValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Shows a text by moving the mouse cursor over the object
|
|
||||||
class CHoverableArea: public virtual CIntObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::string hoverText;
|
|
||||||
|
|
||||||
virtual void hover (bool on);
|
|
||||||
|
|
||||||
CHoverableArea();
|
|
||||||
virtual ~CHoverableArea();
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Can interact on left and right mouse clicks, plus it shows a text when by hovering over it
|
|
||||||
class LRClickableAreaWText: public CHoverableArea
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::string text;
|
|
||||||
|
|
||||||
LRClickableAreaWText();
|
|
||||||
LRClickableAreaWText(const Rect &Pos, const std::string &HoverText = "", const std::string &ClickText = "");
|
|
||||||
virtual ~LRClickableAreaWText();
|
|
||||||
void init();
|
|
||||||
|
|
||||||
virtual void clickLeft(tribool down, bool previousState);
|
|
||||||
virtual void clickRight(tribool down, bool previousState);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Basic class for windows
|
|
||||||
class CWindowObject : public CIntObject
|
|
||||||
{
|
|
||||||
CPicture * createBg(std::string imageName, bool playerColored);
|
|
||||||
int getUsedEvents(int options);
|
|
||||||
|
|
||||||
CIntObject *shadow;
|
|
||||||
void setShadow(bool on);
|
|
||||||
|
|
||||||
int options;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
CPicture * background;
|
|
||||||
|
|
||||||
//Simple function with call to GH.popInt
|
|
||||||
void close();
|
|
||||||
//Used only if RCLICK_POPUP was set
|
|
||||||
void clickRight(tribool down, bool previousState);
|
|
||||||
//To display border
|
|
||||||
void showAll(SDL_Surface *to);
|
|
||||||
//change or set background image
|
|
||||||
void setBackground(std::string filename);
|
|
||||||
void updateShadow();
|
|
||||||
public:
|
|
||||||
enum EOptions
|
|
||||||
{
|
|
||||||
PLAYER_COLORED=1, //background will be player-colored
|
|
||||||
RCLICK_POPUP=2, // window will behave as right-click popup
|
|
||||||
BORDERED=4, // window will have border if current resolution is bigger than size of window
|
|
||||||
SHADOW_DISABLED=8 //this window won't display any shadow
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* options - EOpions enum
|
|
||||||
* imageName - name for background image, can be empty
|
|
||||||
* centerAt - position of window center. Default - center of the screen
|
|
||||||
*/
|
|
||||||
CWindowObject(int options, std::string imageName, Point centerAt);
|
|
||||||
CWindowObject(int options, std::string imageName = "");
|
|
||||||
~CWindowObject();
|
|
||||||
};
|
|
@ -1,6 +1,11 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "Geometries.h"
|
#include "Geometries.h"
|
||||||
#include "../CMT.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 )
|
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)
|
Rect Rect::centerIn(const Rect &r)
|
||||||
{
|
{
|
||||||
return Rect(r.x + (r.w - w) / 2, r.y + (r.h - h) / 2, w, h);
|
return Rect(r.x + (r.w - w) / 2, r.y + (r.h - h) / 2, w, h);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
#include <SDL_events.h>
|
|
||||||
#include "../../lib/int3.h"
|
#include "../../lib/int3.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -21,6 +20,7 @@
|
|||||||
#undef min
|
#undef min
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct SDL_MouseMotionEvent;
|
||||||
|
|
||||||
// A point with x/y coordinate, used mostly for graphic rendering
|
// A point with x/y coordinate, used mostly for graphic rendering
|
||||||
struct Point
|
struct Point
|
||||||
@ -38,9 +38,7 @@ struct Point
|
|||||||
Point(const int3 &a)
|
Point(const int3 &a)
|
||||||
:x(a.x),y(a.y)
|
:x(a.x),y(a.y)
|
||||||
{}
|
{}
|
||||||
Point(const SDL_MouseMotionEvent &a)
|
Point(const SDL_MouseMotionEvent &a);
|
||||||
:x(a.x),y(a.y)
|
|
||||||
{}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Point operator+(const T &b) const
|
Point operator+(const T &b) const
|
||||||
@ -265,4 +263,4 @@ struct Rect : public SDL_Rect
|
|||||||
ret.h = y2 -ret.y;
|
ret.h = y2 -ret.y;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "SDL_Extensions.h"
|
#include "SDL_Extensions.h"
|
||||||
#include "SDL_Pixels.h"
|
#include "SDL_Pixels.h"
|
||||||
|
|
||||||
#include <SDL_ttf.h>
|
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../CMessage.h"
|
#include "../CMessage.h"
|
||||||
#include "../CDefHandler.h"
|
#include "../CDefHandler.h"
|
||||||
|
@ -16,10 +16,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
#include <SDL_ttf.h>
|
#include <SDL_events.h>
|
||||||
#include "../../lib/int3.h"
|
#include "../../lib/int3.h"
|
||||||
#include "../Graphics.h"
|
//#include "../Graphics.h"
|
||||||
#include "Geometries.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
|
//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>
|
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);
|
return boost::lexical_cast<std::string>(number);
|
||||||
|
|
||||||
std::string symbols = "kMGTPE";
|
std::string symbols = " kMGTPE";
|
||||||
auto iter = symbols.begin();
|
auto iter = symbols.begin();
|
||||||
|
|
||||||
while (number >= 1000)
|
while (number >= max)
|
||||||
{
|
{
|
||||||
number /= 1000;
|
number /= 1000;
|
||||||
iter++;
|
iter++;
|
||||||
|
@ -1,30 +1,43 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "AdventureMapClasses.h"
|
#include "AdventureMapClasses.h"
|
||||||
|
|
||||||
#include "../CCallback.h"
|
#include <SDL.h>
|
||||||
#include "../lib/JsonNode.h"
|
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "MiscWidgets.h"
|
||||||
#include "../lib/mapping/CMap.h"
|
#include "CComponent.h"
|
||||||
#include "../lib/CModHandler.h"
|
|
||||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../lib/CGameState.h"
|
#include "../CMusicHandler.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../CPlayerInterface.h"
|
||||||
#include "../lib/CTownHandler.h"
|
#include "../CPreGame.h"
|
||||||
#include "../lib/NetPacksBase.h"
|
#include "../Graphics.h"
|
||||||
#include "../lib/CHeroHandler.h"
|
|
||||||
#include "../lib/StringConstants.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
#include "CAdvmapInterface.h"
|
#include "../gui/SDL_Pixels.h"
|
||||||
#include "CAnimation.h"
|
|
||||||
#include "CGameInfo.h"
|
#include "../windows/InfoWindows.h"
|
||||||
#include "CPlayerInterface.h"
|
#include "../windows/CAdvmapInterface.h"
|
||||||
#include "CMusicHandler.h"
|
#include "../windows/GUIClasses.h"
|
||||||
#include "Graphics.h"
|
|
||||||
#include "GUIClasses.h"
|
#include "../battle/CBattleInterfaceClasses.h"
|
||||||
#include "gui/CGuiHandler.h"
|
#include "../battle/CBattleInterface.h"
|
||||||
#include "gui/SDL_Pixels.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
|
* Authors: listed in file AUTHORS in main folder
|
||||||
*
|
*
|
||||||
@ -93,15 +106,23 @@ CList::CList(int Size, Point position, std::string btnUp, std::string btnDown, s
|
|||||||
selected(nullptr)
|
selected(nullptr)
|
||||||
{
|
{
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
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);
|
list = new CListBox(create, destroy, Point(1,scrollUp->pos.h), Point(0, 32), size, listAmount);
|
||||||
|
|
||||||
//assign callback only after list was created
|
//assign callback only after list was created
|
||||||
|
<<<<<<< HEAD:client/AdventureMapClasses.cpp
|
||||||
scrollUp->callback = std::bind(&CListBox::moveToPrev, list);
|
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);
|
scrollDown = new CAdventureMapButton(CGI->generaltexth->zelp[helpDown], std::bind(&CListBox::moveToNext, list), 0, scrollUp->pos.h + 32*size, btnDown);
|
||||||
|
|
||||||
scrollDown->callback += std::bind(&CList::update, this);
|
scrollDown->callback += std::bind(&CList::update, this);
|
||||||
scrollUp->callback += std::bind(&CList::update, this);
|
scrollUp->callback += std::bind(&CList::update, this);
|
||||||
|
=======
|
||||||
|
scrollUp->addCallback(boost::bind(&CListBox::moveToPrev, list));
|
||||||
|
scrollDown = new CButton(Point(0, scrollUp->pos.h + 32*size), btnDown, CGI->generaltexth->zelp[helpDown], boost::bind(&CListBox::moveToNext, list));
|
||||||
|
|
||||||
|
scrollDown->addCallback(boost::bind(&CList::update, this));
|
||||||
|
scrollUp->addCallback(boost::bind(&CList::update, this));
|
||||||
|
>>>>>>> refactoring/guiClasses:client/widgets/AdventureMapClasses.cpp
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@ -950,3 +971,248 @@ void CInfoBar::showGameStatus()
|
|||||||
setTimer(3000);
|
setTimer(3000);
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CInGameConsole::show(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
int number = 0;
|
||||||
|
|
||||||
|
std::vector<std::list< std::pair< std::string, int > >::iterator> toDel;
|
||||||
|
|
||||||
|
boost::unique_lock<boost::mutex> lock(texts_mx);
|
||||||
|
for(auto it = texts.begin(); it != texts.end(); ++it, ++number)
|
||||||
|
{
|
||||||
|
Point leftBottomCorner(0, screen->h);
|
||||||
|
if(LOCPLINT->battleInt)
|
||||||
|
{
|
||||||
|
leftBottomCorner = LOCPLINT->battleInt->pos.bottomLeft();
|
||||||
|
}
|
||||||
|
graphics->fonts[FONT_MEDIUM]->renderTextLeft(to, it->first, Colors::GREEN,
|
||||||
|
Point(leftBottomCorner.x + 50, leftBottomCorner.y - texts.size() * 20 - 80 + number*20));
|
||||||
|
|
||||||
|
if(SDL_GetTicks() - it->second > defaultTimeout)
|
||||||
|
{
|
||||||
|
toDel.push_back(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto & elem : toDel)
|
||||||
|
{
|
||||||
|
texts.erase(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CInGameConsole::print(const std::string &txt)
|
||||||
|
{
|
||||||
|
boost::unique_lock<boost::mutex> lock(texts_mx);
|
||||||
|
int lineLen = conf.go()->ac.outputLineLength;
|
||||||
|
|
||||||
|
if(txt.size() < lineLen)
|
||||||
|
{
|
||||||
|
texts.push_back(std::make_pair(txt, SDL_GetTicks()));
|
||||||
|
if(texts.size() > maxDisplayedTexts)
|
||||||
|
{
|
||||||
|
texts.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(lineLen);
|
||||||
|
for(int g=0; g<txt.size() / lineLen + 1; ++g)
|
||||||
|
{
|
||||||
|
std::string part = txt.substr(g * lineLen, lineLen);
|
||||||
|
if(part.size() == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
texts.push_back(std::make_pair(part, SDL_GetTicks()));
|
||||||
|
if(texts.size() > maxDisplayedTexts)
|
||||||
|
{
|
||||||
|
texts.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
|
||||||
|
{
|
||||||
|
if(key.type != SDL_KEYDOWN) return;
|
||||||
|
|
||||||
|
if(!captureAllKeys && key.keysym.sym != SDLK_TAB) return; //because user is not entering any text
|
||||||
|
|
||||||
|
switch(key.keysym.sym)
|
||||||
|
{
|
||||||
|
case SDLK_TAB:
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
{
|
||||||
|
if(captureAllKeys)
|
||||||
|
{
|
||||||
|
captureAllKeys = false;
|
||||||
|
endEnteringText(false);
|
||||||
|
}
|
||||||
|
else if(SDLK_TAB)
|
||||||
|
{
|
||||||
|
captureAllKeys = true;
|
||||||
|
startEnteringText();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDLK_RETURN: //enter key
|
||||||
|
{
|
||||||
|
if(enteredText.size() > 0 && captureAllKeys)
|
||||||
|
{
|
||||||
|
captureAllKeys = false;
|
||||||
|
endEnteringText(true);
|
||||||
|
CCS->soundh->playSound("CHAT");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDLK_BACKSPACE:
|
||||||
|
{
|
||||||
|
if(enteredText.size() > 1)
|
||||||
|
{
|
||||||
|
Unicode::trimRight(enteredText,2);
|
||||||
|
enteredText += '_';
|
||||||
|
refreshEnteredText();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDLK_UP: //up arrow
|
||||||
|
{
|
||||||
|
if(previouslyEntered.size() == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(prevEntDisp == -1)
|
||||||
|
{
|
||||||
|
prevEntDisp = previouslyEntered.size() - 1;
|
||||||
|
enteredText = previouslyEntered[prevEntDisp] + "_";
|
||||||
|
refreshEnteredText();
|
||||||
|
}
|
||||||
|
else if( prevEntDisp > 0)
|
||||||
|
{
|
||||||
|
--prevEntDisp;
|
||||||
|
enteredText = previouslyEntered[prevEntDisp] + "_";
|
||||||
|
refreshEnteredText();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDLK_DOWN: //down arrow
|
||||||
|
{
|
||||||
|
if(prevEntDisp != -1 && prevEntDisp+1 < previouslyEntered.size())
|
||||||
|
{
|
||||||
|
++prevEntDisp;
|
||||||
|
enteredText = previouslyEntered[prevEntDisp] + "_";
|
||||||
|
refreshEnteredText();
|
||||||
|
}
|
||||||
|
else if(prevEntDisp+1 == previouslyEntered.size()) //useful feature
|
||||||
|
{
|
||||||
|
prevEntDisp = -1;
|
||||||
|
enteredText = "_";
|
||||||
|
refreshEnteredText();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
#ifdef VCMI_SDL1
|
||||||
|
if(enteredText.size() > 0 && enteredText.size() < conf.go()->ac.inputLineLength)
|
||||||
|
{
|
||||||
|
if( key.keysym.unicode < 0x80 && key.keysym.unicode > 0 )
|
||||||
|
{
|
||||||
|
enteredText[enteredText.size()-1] = (char)key.keysym.unicode;
|
||||||
|
enteredText += "_";
|
||||||
|
refreshEnteredText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // VCMI_SDL1
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef VCMI_SDL1
|
||||||
|
|
||||||
|
void CInGameConsole::textInputed(const SDL_TextInputEvent & event)
|
||||||
|
{
|
||||||
|
if(!captureAllKeys || enteredText.size() == 0)
|
||||||
|
return;
|
||||||
|
enteredText.resize(enteredText.size()-1);
|
||||||
|
|
||||||
|
enteredText += event.text;
|
||||||
|
enteredText += "_";
|
||||||
|
|
||||||
|
refreshEnteredText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CInGameConsole::textEdited(const SDL_TextEditingEvent & event)
|
||||||
|
{
|
||||||
|
//do nothing here
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VCMI_SDL1
|
||||||
|
|
||||||
|
void CInGameConsole::startEnteringText()
|
||||||
|
{
|
||||||
|
CSDL_Ext::startTextInput(&pos);
|
||||||
|
|
||||||
|
enteredText = "_";
|
||||||
|
if(GH.topInt() == adventureInt)
|
||||||
|
{
|
||||||
|
GH.statusbar->alignment = TOPLEFT;
|
||||||
|
GH.statusbar->setText(enteredText);
|
||||||
|
|
||||||
|
//Prevent changes to the text from mouse interaction with the adventure map
|
||||||
|
GH.statusbar->lock(true);
|
||||||
|
}
|
||||||
|
else if(LOCPLINT->battleInt)
|
||||||
|
{
|
||||||
|
LOCPLINT->battleInt->console->ingcAlter = enteredText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CInGameConsole::endEnteringText(bool printEnteredText)
|
||||||
|
{
|
||||||
|
CSDL_Ext::stopTextInput();
|
||||||
|
|
||||||
|
prevEntDisp = -1;
|
||||||
|
if(printEnteredText)
|
||||||
|
{
|
||||||
|
std::string txt = enteredText.substr(0, enteredText.size()-1);
|
||||||
|
LOCPLINT->cb->sendMessage(txt);
|
||||||
|
previouslyEntered.push_back(txt);
|
||||||
|
//print(txt);
|
||||||
|
}
|
||||||
|
enteredText = "";
|
||||||
|
if(GH.topInt() == adventureInt)
|
||||||
|
{
|
||||||
|
GH.statusbar->alignment = CENTER;
|
||||||
|
GH.statusbar->lock(false);
|
||||||
|
GH.statusbar->clear();
|
||||||
|
}
|
||||||
|
else if(LOCPLINT->battleInt)
|
||||||
|
{
|
||||||
|
LOCPLINT->battleInt->console->ingcAlter = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CInGameConsole::refreshEnteredText()
|
||||||
|
{
|
||||||
|
if(GH.topInt() == adventureInt)
|
||||||
|
{
|
||||||
|
GH.statusbar->lock(false);
|
||||||
|
GH.statusbar->clear();
|
||||||
|
GH.statusbar->setText(enteredText);
|
||||||
|
GH.statusbar->lock(true);
|
||||||
|
}
|
||||||
|
else if(LOCPLINT->battleInt)
|
||||||
|
{
|
||||||
|
LOCPLINT->battleInt->console->ingcAlter = enteredText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CInGameConsole::CInGameConsole() : prevEntDisp(-1), defaultTimeout(10000), maxDisplayedTexts(10)
|
||||||
|
{
|
||||||
|
#ifdef VCMI_SDL1
|
||||||
|
addUsedEvents(KEYBOARD);
|
||||||
|
#else
|
||||||
|
addUsedEvents(KEYBOARD | TEXTINPUT);
|
||||||
|
#endif
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "gui/CIntObject.h"
|
#include "ObjectLists.h"
|
||||||
#include "gui/CIntObjectClasses.h"
|
#include "../../lib/FunctionList.h"
|
||||||
|
|
||||||
class CArmedInstance;
|
class CArmedInstance;
|
||||||
class CShowableAnim;
|
class CShowableAnim;
|
||||||
@ -9,6 +9,7 @@ class CGGarrison;
|
|||||||
class CGObjectInstance;
|
class CGObjectInstance;
|
||||||
class CGHeroInstance;
|
class CGHeroInstance;
|
||||||
class CGTownInstance;
|
class CGTownInstance;
|
||||||
|
class CButton;
|
||||||
struct Component;
|
struct Component;
|
||||||
struct InfoAboutArmy;
|
struct InfoAboutArmy;
|
||||||
struct InfoAboutHero;
|
struct InfoAboutHero;
|
||||||
@ -82,8 +83,8 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CAdventureMapButton * scrollUp;
|
CButton * scrollUp;
|
||||||
CAdventureMapButton * scrollDown;
|
CButton * scrollDown;
|
||||||
|
|
||||||
/// functions that will be called when selection changes
|
/// functions that will be called when selection changes
|
||||||
CFunctionList<void()> onSelect;
|
CFunctionList<void()> onSelect;
|
||||||
@ -313,3 +314,30 @@ public:
|
|||||||
/// for 3 seconds shows amount of town halls and players status
|
/// for 3 seconds shows amount of town halls and players status
|
||||||
void showGameStatus();
|
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
|
||||||
|
};
|
740
client/widgets/Buttons.cpp
Normal file
@ -0,0 +1,740 @@
|
|||||||
|
#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);
|
||||||
|
|
||||||
|
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(boost::bind(&CSlider::moveLeft,this));
|
||||||
|
right->addCallback(boost::bind(&CSlider::moveRight,this));
|
||||||
|
slider->addCallback(boost::bind(&CSlider::sliderClicked,this));
|
||||||
|
|
||||||
|
if(horizontal)
|
||||||
|
{
|
||||||
|
pos.h = slider->pos.h;
|
||||||
|
pos.w = totalw;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos.w = slider->pos.w;
|
||||||
|
pos.h = totalw;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSliderPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSlider::block( bool on )
|
||||||
|
{
|
||||||
|
left->block(on);
|
||||||
|
right->block(on);
|
||||||
|
slider->block(on);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSlider::setAmount( int to )
|
||||||
|
{
|
||||||
|
amount = to;
|
||||||
|
positions = to - capacity;
|
||||||
|
vstd::amax(positions, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSlider::showAll(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
CSDL_Ext::fillRectBlack(to, &pos);
|
||||||
|
CIntObject::showAll(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSlider::wheelScrolled(bool down, bool in)
|
||||||
|
{
|
||||||
|
moveTo(value + 3 * (down ? +scrollStep : -scrollStep));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSlider::keyPressed(const SDL_KeyboardEvent & key)
|
||||||
|
{
|
||||||
|
if(key.state != SDL_PRESSED) return;
|
||||||
|
|
||||||
|
int moveDest = 0;
|
||||||
|
switch(key.keysym.sym)
|
||||||
|
{
|
||||||
|
case SDLK_UP:
|
||||||
|
case SDLK_LEFT:
|
||||||
|
moveDest = value - scrollStep;
|
||||||
|
break;
|
||||||
|
case SDLK_DOWN:
|
||||||
|
case SDLK_RIGHT:
|
||||||
|
moveDest = value + scrollStep;
|
||||||
|
break;
|
||||||
|
case SDLK_PAGEUP:
|
||||||
|
moveDest = value - capacity + scrollStep;
|
||||||
|
break;
|
||||||
|
case SDLK_PAGEDOWN:
|
||||||
|
moveDest = value + capacity - scrollStep;
|
||||||
|
break;
|
||||||
|
case SDLK_HOME:
|
||||||
|
moveDest = 0;
|
||||||
|
break;
|
||||||
|
case SDLK_END:
|
||||||
|
moveDest = amount - capacity;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
moveTo(moveDest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSlider::moveToMax()
|
||||||
|
{
|
||||||
|
moveTo(amount);
|
||||||
|
}
|
261
client/widgets/Buttons.h
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../gui/CIntObject.h"
|
||||||
|
#include "../gui/SDL_Extensions.h"
|
||||||
|
|
||||||
|
#include "../../lib/FunctionList.h"
|
||||||
|
|
||||||
|
struct SDL_Surface;
|
||||||
|
struct Rect;
|
||||||
|
class CAnimImage;
|
||||||
|
class CLabel;
|
||||||
|
class CAnimation;
|
||||||
|
class CDefHandler;
|
||||||
|
|
||||||
|
namespace config
|
||||||
|
{
|
||||||
|
struct ButtonInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Buttons.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ClickableArea : public CIntObject //TODO: derive from LRCLickableArea? Or somehow use its right-click/hover data?
|
||||||
|
{
|
||||||
|
CFunctionList<void()> callback;
|
||||||
|
|
||||||
|
CIntObject * area;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onClick();
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClickableArea(CIntObject * object, CFunctionList<void()> callback);
|
||||||
|
|
||||||
|
void addCallback(std::function<void()> callback);
|
||||||
|
void setArea(CIntObject * object);
|
||||||
|
|
||||||
|
void clickLeft(tribool down, bool previousState) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Typical Heroes 3 button which can be inactive or active and can
|
||||||
|
/// hold further information if you right-click it
|
||||||
|
class CButton : public CKeyShortcut
|
||||||
|
{
|
||||||
|
CFunctionList<void()> callback;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum ButtonState
|
||||||
|
{
|
||||||
|
NORMAL=0,
|
||||||
|
PRESSED=1,
|
||||||
|
BLOCKED=2,
|
||||||
|
HIGHLIGHTED=3
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
std::vector<std::string> imageNames;//store list of images that can be used by this button
|
||||||
|
size_t currentImage;
|
||||||
|
|
||||||
|
ButtonState state;//current state of button from enum
|
||||||
|
|
||||||
|
std::array<int, 4> stateToIndex; // mapping of button state to index of frame in animation
|
||||||
|
std::array<std::string, 4> hoverTexts; //texts for statusbar, if empty - first entry will be used
|
||||||
|
std::string helpBox; //for right-click help
|
||||||
|
|
||||||
|
CAnimImage * image; //image for this button
|
||||||
|
CIntObject * overlay;//object-overlay, can be null
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onButtonClicked(); // calls callback
|
||||||
|
void update();//to refresh button after image or text change
|
||||||
|
|
||||||
|
// internal method to change state. Public change can be done only via block()
|
||||||
|
void setState(ButtonState newState);
|
||||||
|
ButtonState getState();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool actOnDown,//runs when mouse is pressed down over it, not when up
|
||||||
|
hoverable,//if true, button will be highlighted when hovered (e.g. main menu)
|
||||||
|
soundDisabled;
|
||||||
|
|
||||||
|
// if set, button will have 1-px border around it with this color
|
||||||
|
boost::optional<SDL_Color> borderColor;
|
||||||
|
|
||||||
|
/// adds one more callback to on-click actions
|
||||||
|
void addCallback(std::function<void()> callback);
|
||||||
|
|
||||||
|
/// adds overlay on top of button image. Only one overlay can be active at once
|
||||||
|
void addOverlay(CIntObject * newOverlay);
|
||||||
|
void addTextOverlay(const std::string &Text, EFonts font, SDL_Color color = Colors::WHITE);
|
||||||
|
|
||||||
|
void addImage(std::string filename);
|
||||||
|
void addHoverText(ButtonState state, std::string text);
|
||||||
|
|
||||||
|
void setImageOrder(int state1, int state2, int state3, int state4);
|
||||||
|
void block(bool on);
|
||||||
|
|
||||||
|
/// State modifiers
|
||||||
|
bool isBlocked();
|
||||||
|
bool isHighlighted();
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
CButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
|
||||||
|
CFunctionList<void()> Callback = 0, int key=0, bool playerColoredButton = false );
|
||||||
|
|
||||||
|
/// Appearance modifiers
|
||||||
|
void setIndex(size_t index, bool playerColoredButton=false);
|
||||||
|
void setImage(CAnimation* anim, bool playerColoredButton=false, int animFlags=0);
|
||||||
|
void setPlayerColor(PlayerColor player);
|
||||||
|
|
||||||
|
/// CIntObject overrides
|
||||||
|
void clickRight(tribool down, bool previousState) override;
|
||||||
|
void clickLeft(tribool down, bool previousState) override;
|
||||||
|
void hover (bool on) override;
|
||||||
|
void showAll(SDL_Surface * to) override;
|
||||||
|
|
||||||
|
/// generates tooltip that can be passed into constructor
|
||||||
|
static std::pair<std::string, std::string> tooltip();
|
||||||
|
static std::pair<std::string, std::string> tooltip(const JsonNode & localizedTexts);
|
||||||
|
static std::pair<std::string, std::string> tooltip(const std::string & hover, const std::string & help = "");
|
||||||
|
};
|
||||||
|
|
||||||
|
class CToggleBase
|
||||||
|
{
|
||||||
|
CFunctionList<void(bool)> callback;
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool selected;
|
||||||
|
|
||||||
|
// internal method for overrides
|
||||||
|
virtual void doSelect(bool on);
|
||||||
|
|
||||||
|
// returns true if toggle can change its state
|
||||||
|
bool canActivate();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// if set to false - button can not be deselected normally
|
||||||
|
bool allowDeselection;
|
||||||
|
|
||||||
|
CToggleBase(CFunctionList<void(bool)> callback);
|
||||||
|
virtual ~CToggleBase();
|
||||||
|
|
||||||
|
/// Changes selection to "on", and calls callback
|
||||||
|
void setSelected(bool on);
|
||||||
|
|
||||||
|
void addCallback(std::function<void(bool)> callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClickableToggle : public ClickableArea, public CToggleBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClickableToggle(CIntObject * object, CFunctionList<void()> selectFun, CFunctionList<void()> deselectFun);
|
||||||
|
void clickLeft(tribool down, bool previousState) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A button which can be selected/deselected, checkbox
|
||||||
|
class CToggleButton : public CButton, public CToggleBase
|
||||||
|
{
|
||||||
|
void doSelect(bool on) override;
|
||||||
|
public:
|
||||||
|
CToggleButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
|
||||||
|
CFunctionList<void(bool)> Callback = 0, int key=0, bool playerColoredButton = false );
|
||||||
|
void clickLeft(tribool down, bool previousState) override;
|
||||||
|
|
||||||
|
// bring overrides into scope
|
||||||
|
using CButton::addCallback;
|
||||||
|
using CToggleBase::addCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CToggleGroup : public CIntObject
|
||||||
|
{
|
||||||
|
CFunctionList<void(int)> onChange; //called when changing selected button with new button's id
|
||||||
|
|
||||||
|
int selectedID;
|
||||||
|
bool musicLike; //determines the behaviour of this group
|
||||||
|
void selectionChanged(int to);
|
||||||
|
public:
|
||||||
|
std::map<int, CToggleBase*> buttons;
|
||||||
|
|
||||||
|
CToggleGroup(const CFunctionList<void(int)> & OnChange, bool musicLikeButtons = false);
|
||||||
|
|
||||||
|
void addCallback(std::function<void(int)> callback);
|
||||||
|
|
||||||
|
/// add one toggle/button into group
|
||||||
|
void addToggle(int index, CToggleBase * button);
|
||||||
|
/// Changes selection to specific value. Will select toggle with this ID, if present
|
||||||
|
void setSelected(int id);
|
||||||
|
|
||||||
|
void show(SDL_Surface * to);
|
||||||
|
void showAll(SDL_Surface * to);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A typical slider which can be orientated horizontally/vertically.
|
||||||
|
class CSlider : public CIntObject
|
||||||
|
{
|
||||||
|
CButton *left, *right, *slider; //if vertical then left=up
|
||||||
|
int capacity;//how many elements can be active at same time (e.g. hero list = 5)
|
||||||
|
int positions; //number of highest position (0 if there is only one)
|
||||||
|
bool horizontal;
|
||||||
|
bool wheelScrolling;
|
||||||
|
bool keyScrolling;
|
||||||
|
|
||||||
|
int amount; //total amount of elements (e.g. hero list = 0-8)
|
||||||
|
int value; //first active element
|
||||||
|
int scrollStep; // how many elements will be scrolled via one click, default = 1
|
||||||
|
CFunctionList<void(int)> moved;
|
||||||
|
|
||||||
|
void updateSliderPos();
|
||||||
|
void sliderClicked();
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum EStyle {
|
||||||
|
BROWN,
|
||||||
|
BLUE
|
||||||
|
};
|
||||||
|
|
||||||
|
void block(bool on);
|
||||||
|
|
||||||
|
/// Controls how many items wil be scrolled via one click
|
||||||
|
void setScrollStep(int to);
|
||||||
|
|
||||||
|
/// Value modifiers
|
||||||
|
void moveLeft();
|
||||||
|
void moveRight();
|
||||||
|
void moveTo(int value);
|
||||||
|
void moveBy(int amount);
|
||||||
|
void moveToMax();
|
||||||
|
|
||||||
|
/// Amount modifier
|
||||||
|
void setAmount(int to);
|
||||||
|
|
||||||
|
/// Accessors
|
||||||
|
int getAmount();
|
||||||
|
int getValue();
|
||||||
|
|
||||||
|
void addCallback(std::function<void(int)> callback);
|
||||||
|
|
||||||
|
void keyPressed(const SDL_KeyboardEvent & key);
|
||||||
|
void wheelScrolled(bool down, bool in);
|
||||||
|
void clickLeft(tribool down, bool previousState);
|
||||||
|
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
|
||||||
|
void showAll(SDL_Surface * to);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param position, coordinates of slider
|
||||||
|
* @param length, length of slider ribbon, including left/right buttons
|
||||||
|
* @param Moved, function that will be called whenever slider moves
|
||||||
|
* @param Capacity, maximal number of visible at once elements
|
||||||
|
* @param Amount, total amount of elements, including not visible
|
||||||
|
* @param Value, starting position
|
||||||
|
*/
|
||||||
|
CSlider(Point position, int length, std::function<void(int)> Moved, int Capacity, int Amount,
|
||||||
|
int Value=0, bool Horizontal=true, EStyle style = BROWN);
|
||||||
|
~CSlider();
|
||||||
|
};
|
1017
client/widgets/CArtifactHolder.cpp
Normal file
145
client/widgets/CArtifactHolder.h
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
//#include "CComponent.h"
|
||||||
|
#include "MiscWidgets.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CArtifactHolder.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CArtifactsOfHero;
|
||||||
|
class CAnimImage;
|
||||||
|
class CButton;
|
||||||
|
|
||||||
|
struct ArtifactLocation;
|
||||||
|
|
||||||
|
class CArtifactHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CArtifactHolder();
|
||||||
|
|
||||||
|
virtual void artifactRemoved(const ArtifactLocation &artLoc)=0;
|
||||||
|
virtual void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc)=0;
|
||||||
|
virtual void artifactDisassembled(const ArtifactLocation &artLoc)=0;
|
||||||
|
virtual void artifactAssembled(const ArtifactLocation &artLoc)=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CWindowWithArtifacts : public CArtifactHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<CArtifactsOfHero *> artSets;
|
||||||
|
|
||||||
|
void artifactRemoved(const ArtifactLocation &artLoc);
|
||||||
|
void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc);
|
||||||
|
void artifactDisassembled(const ArtifactLocation &artLoc);
|
||||||
|
void artifactAssembled(const ArtifactLocation &artLoc);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Artifacts can be placed there. Gets shown at the hero window
|
||||||
|
class CArtPlace: public LRClickableAreaWTextComp
|
||||||
|
{
|
||||||
|
CAnimImage *image;
|
||||||
|
CAnimImage *selection;
|
||||||
|
|
||||||
|
void createImage();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// consider these members as const - change them only with appropriate methods e.g. lockSlot()
|
||||||
|
bool locked;
|
||||||
|
bool picked;
|
||||||
|
bool marked;
|
||||||
|
|
||||||
|
ArtifactPosition slotID; //Arts::EPOS enum + backpack starting from Arts::BACKPACK_START
|
||||||
|
|
||||||
|
void lockSlot(bool on);
|
||||||
|
void pickSlot(bool on);
|
||||||
|
void selectSlot(bool on);
|
||||||
|
|
||||||
|
CArtifactsOfHero * ourOwner;
|
||||||
|
const CArtifactInstance * ourArt; // should be changed only with setArtifact()
|
||||||
|
|
||||||
|
CArtPlace(Point position, const CArtifactInstance * Art = nullptr); //c-tor
|
||||||
|
void clickLeft(tribool down, bool previousState);
|
||||||
|
void clickRight(tribool down, bool previousState);
|
||||||
|
void select ();
|
||||||
|
void deselect ();
|
||||||
|
void showAll(SDL_Surface * to);
|
||||||
|
bool fitsHere (const CArtifactInstance * art) const; //returns true if given artifact can be placed here
|
||||||
|
|
||||||
|
void setMeAsDest(bool backpackAsVoid = true);
|
||||||
|
void setArtifact(const CArtifactInstance *art);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Contains artifacts of hero. Distincts which artifacts are worn or backpacked
|
||||||
|
class CArtifactsOfHero : public CIntObject
|
||||||
|
{
|
||||||
|
const CGHeroInstance * curHero;
|
||||||
|
|
||||||
|
std::vector<CArtPlace *> artWorn; // 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
|
||||||
|
std::vector<CArtPlace *> backpack; //hero's visible backpack (only 5 elements!)
|
||||||
|
int backpackPos; //number of first art visible in backpack (in hero's vector)
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct SCommonPart
|
||||||
|
{
|
||||||
|
struct Artpos
|
||||||
|
{
|
||||||
|
ArtifactPosition slotID;
|
||||||
|
const CArtifactsOfHero *AOH;
|
||||||
|
const CArtifactInstance *art;
|
||||||
|
|
||||||
|
Artpos();
|
||||||
|
void clear();
|
||||||
|
void setTo(const CArtPlace *place, bool dontTakeBackpack);
|
||||||
|
bool valid();
|
||||||
|
bool operator==(const ArtifactLocation &al) const;
|
||||||
|
} src, dst;
|
||||||
|
|
||||||
|
std::set<CArtifactsOfHero *> participants; // Needed to mark slots.
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
} * commonInfo; //when we have more than one CArtifactsOfHero in one window with exchange possibility, we use this (eg. in exchange window); to be provided externally
|
||||||
|
|
||||||
|
bool updateState; // Whether the commonInfo should be updated on setHero or not.
|
||||||
|
|
||||||
|
CButton * leftArtRoll, * rightArtRoll;
|
||||||
|
bool allowedAssembling;
|
||||||
|
std::multiset<const CArtifactInstance*> artifactsOnAltar; //artifacts id that are technically present in backpack but in GUI are moved to the altar - they'll be omitted in backpack slots
|
||||||
|
std::function<void(CArtPlace*)> highlightModeCallback; //if set, clicking on art place doesn't pick artifact but highlights the slot and calls this function
|
||||||
|
|
||||||
|
void realizeCurrentTransaction(); //calls callback with parameters stored in commonInfo
|
||||||
|
void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst);
|
||||||
|
void artifactRemoved(const ArtifactLocation &al);
|
||||||
|
void artifactAssembled(const ArtifactLocation &al);
|
||||||
|
void artifactDisassembled(const ArtifactLocation &al);
|
||||||
|
CArtPlace *getArtPlace(int slot);
|
||||||
|
|
||||||
|
void setHero(const CGHeroInstance * hero);
|
||||||
|
const CGHeroInstance *getHero() const;
|
||||||
|
void dispose(); //free resources not needed after closing windows and reset state
|
||||||
|
void scrollBackpack(int dir); //dir==-1 => to left; dir==1 => to right
|
||||||
|
|
||||||
|
void safeRedraw();
|
||||||
|
void markPossibleSlots(const CArtifactInstance* art);
|
||||||
|
void unmarkSlots(bool withRedraw = true); //unmarks slots in all visible AOHs
|
||||||
|
void unmarkLocalSlots(bool withRedraw = true); //unmarks slots in that particular AOH
|
||||||
|
void setSlotData (CArtPlace* artPlace, ArtifactPosition slotID);
|
||||||
|
void updateWornSlots (bool redrawParent = true);
|
||||||
|
|
||||||
|
void updateSlot(ArtifactPosition i);
|
||||||
|
void eraseSlotData (CArtPlace* artPlace, ArtifactPosition slotID);
|
||||||
|
|
||||||
|
CArtifactsOfHero(const Point& position, bool createCommonPart = false);
|
||||||
|
//Alternative constructor, used if custom artifacts positioning required (Kingdom interface)
|
||||||
|
CArtifactsOfHero(std::vector<CArtPlace *> ArtWorn, std::vector<CArtPlace *> Backpack,
|
||||||
|
CButton *leftScroll, CButton *rightScroll, bool createCommonPart = false);
|
||||||
|
~CArtifactsOfHero(); //d-tor
|
||||||
|
void updateParentWindow();
|
||||||
|
friend class CArtPlace;
|
||||||
|
};
|
453
client/widgets/CComponent.cpp
Normal file
@ -0,0 +1,453 @@
|
|||||||
|
#include "StdInc.h"
|
||||||
|
#include "CComponent.h"
|
||||||
|
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
#include "../gui/CCursorHandler.h"
|
||||||
|
|
||||||
|
#include "../CMessage.h"
|
||||||
|
#include "../CGameInfo.h"
|
||||||
|
#include "../widgets/Images.h"
|
||||||
|
#include "../windows/CAdvmapInterface.h"
|
||||||
|
|
||||||
|
#include "../../lib/CArtHandler.h"
|
||||||
|
#include "../../lib/CTownHandler.h"
|
||||||
|
#include "../../lib/CCreatureHandler.h"
|
||||||
|
#include "../../lib/CSpellHandler.h"
|
||||||
|
#include "../../lib/CGeneralTextHandler.h"
|
||||||
|
#include "../../lib/NetPacksBase.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CComponent.cpp, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
CComponent::CComponent(Etype Type, int Subtype, int Val, ESize imageSize):
|
||||||
|
image(nullptr),
|
||||||
|
perDay(false)
|
||||||
|
{
|
||||||
|
addUsedEvents(RCLICK);
|
||||||
|
init(Type, Subtype, Val, imageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
CComponent::CComponent(const Component &c):
|
||||||
|
image(nullptr),
|
||||||
|
perDay(false)
|
||||||
|
{
|
||||||
|
addUsedEvents(RCLICK);
|
||||||
|
|
||||||
|
if(c.id == Component::RESOURCE && c.when==-1)
|
||||||
|
perDay = true;
|
||||||
|
|
||||||
|
init((Etype)c.id,c.subtype,c.val, large);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CComponent::init(Etype Type, int Subtype, int Val, ESize imageSize)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
|
||||||
|
compType = Type;
|
||||||
|
subtype = Subtype;
|
||||||
|
val = Val;
|
||||||
|
size = imageSize;
|
||||||
|
|
||||||
|
assert(compType < typeInvalid);
|
||||||
|
assert(size < sizeInvalid);
|
||||||
|
|
||||||
|
setSurface(getFileName()[size], getIndex());
|
||||||
|
|
||||||
|
pos.w = image->pos.w;
|
||||||
|
pos.h = image->pos.h;
|
||||||
|
|
||||||
|
EFonts font = FONT_SMALL;
|
||||||
|
if (imageSize < small)
|
||||||
|
font = FONT_TINY; //other sizes?
|
||||||
|
|
||||||
|
pos.h += 4; //distance between text and image
|
||||||
|
|
||||||
|
std::vector<std::string> textLines = CMessage::breakText(getSubtitle(), std::max<int>(80, pos.w), font);
|
||||||
|
for(auto & line : textLines)
|
||||||
|
{
|
||||||
|
int height = graphics->fonts[font]->getLineHeight();
|
||||||
|
auto label = new CLabel(pos.w/2, pos.h + height/2, font, CENTER, Colors::WHITE, line);
|
||||||
|
|
||||||
|
pos.h += height;
|
||||||
|
if (label->pos.w > pos.w)
|
||||||
|
{
|
||||||
|
pos.x -= (label->pos.w - pos.w)/2;
|
||||||
|
pos.w = label->pos.w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> CComponent::getFileName()
|
||||||
|
{
|
||||||
|
static const std::string primSkillsArr [] = {"PSKIL32", "PSKIL32", "PSKIL42", "PSKILL"};
|
||||||
|
static const std::string secSkillsArr [] = {"SECSK32", "SECSK32", "SECSKILL", "SECSK82"};
|
||||||
|
static const std::string resourceArr [] = {"SMALRES", "RESOURCE", "RESOUR82", "RESOUR82"};
|
||||||
|
static const std::string creatureArr [] = {"CPRSMALL", "CPRSMALL", "TWCRPORT", "TWCRPORT"};
|
||||||
|
static const std::string artifactArr[] = {"Artifact", "Artifact", "Artifact", "Artifact"};
|
||||||
|
static const std::string spellsArr [] = {"SpellInt", "SpellInt", "SPELLSCR", "SPELLSCR"};
|
||||||
|
static const std::string moraleArr [] = {"IMRL22", "IMRL30", "IMRL42", "imrl82"};
|
||||||
|
static const std::string luckArr [] = {"ILCK22", "ILCK30", "ILCK42", "ilck82"};
|
||||||
|
static const std::string heroArr [] = {"PortraitsSmall", "PortraitsSmall", "PortraitsLarge", "PortraitsLarge"};
|
||||||
|
static const std::string flagArr [] = {"CREST58", "CREST58", "CREST58", "CREST58"};
|
||||||
|
|
||||||
|
auto gen = [](const std::string * arr)
|
||||||
|
{
|
||||||
|
return std::vector<std::string>(arr, arr + 4);
|
||||||
|
};
|
||||||
|
|
||||||
|
switch(compType)
|
||||||
|
{
|
||||||
|
case primskill: return gen(primSkillsArr);
|
||||||
|
case secskill: return gen(secSkillsArr);
|
||||||
|
case resource: return gen(resourceArr);
|
||||||
|
case creature: return gen(creatureArr);
|
||||||
|
case artifact: return gen(artifactArr);
|
||||||
|
case experience: return gen(primSkillsArr);
|
||||||
|
case spell: return gen(spellsArr);
|
||||||
|
case morale: return gen(moraleArr);
|
||||||
|
case luck: return gen(luckArr);
|
||||||
|
case building: return std::vector<std::string>(4, CGI->townh->factions[subtype]->town->clientInfo.buildingsIcons);
|
||||||
|
case hero: return gen(heroArr);
|
||||||
|
case flag: return gen(flagArr);
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return std::vector<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CComponent::getIndex()
|
||||||
|
{
|
||||||
|
switch(compType)
|
||||||
|
{
|
||||||
|
case primskill: return subtype;
|
||||||
|
case secskill: return subtype*3 + 3 + val - 1;
|
||||||
|
case resource: return subtype;
|
||||||
|
case creature: return CGI->creh->creatures[subtype]->iconIndex;
|
||||||
|
case artifact: return CGI->arth->artifacts[subtype]->iconIndex;
|
||||||
|
case experience: return 4;
|
||||||
|
case spell: return subtype;
|
||||||
|
case morale: return val+3;
|
||||||
|
case luck: return val+3;
|
||||||
|
case building: return val;
|
||||||
|
case hero: return subtype;
|
||||||
|
case flag: return subtype;
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CComponent::getDescription()
|
||||||
|
{
|
||||||
|
switch (compType)
|
||||||
|
{
|
||||||
|
case primskill: return (subtype < 4)? CGI->generaltexth->arraytxt[2+subtype] //Primary skill
|
||||||
|
: CGI->generaltexth->allTexts[149]; //mana
|
||||||
|
case secskill: return CGI->generaltexth->skillInfoTexts[subtype][val-1];
|
||||||
|
case resource: return CGI->generaltexth->allTexts[242];
|
||||||
|
case creature: return "";
|
||||||
|
case artifact: return CGI->arth->artifacts[subtype]->Description();
|
||||||
|
case experience: return CGI->generaltexth->allTexts[241];
|
||||||
|
case spell: return CGI->spellh->objects[subtype]->getLevelInfo(val).description;
|
||||||
|
case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
|
||||||
|
case luck: return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)];
|
||||||
|
case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Description();
|
||||||
|
case hero: return "";
|
||||||
|
case flag: return "";
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CComponent::getSubtitle()
|
||||||
|
{
|
||||||
|
if (!perDay)
|
||||||
|
return getSubtitleInternal();
|
||||||
|
|
||||||
|
std::string ret = CGI->generaltexth->allTexts[3];
|
||||||
|
boost::replace_first(ret, "%d", getSubtitleInternal());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CComponent::getSubtitleInternal()
|
||||||
|
{
|
||||||
|
//FIXME: some of these are horrible (e.g creature)
|
||||||
|
switch(compType)
|
||||||
|
{
|
||||||
|
case primskill: return boost::str(boost::format("%+d %s") % val % (subtype < 4 ? CGI->generaltexth->primarySkillNames[subtype] : CGI->generaltexth->allTexts[387]));
|
||||||
|
case secskill: return CGI->generaltexth->levels[val-1] + "\n" + CGI->generaltexth->skillName[subtype];
|
||||||
|
case resource: return boost::lexical_cast<std::string>(val);
|
||||||
|
case creature: return (val? boost::lexical_cast<std::string>(val) + " " : "") + CGI->creh->creatures[subtype]->*(val != 1 ? &CCreature::namePl : &CCreature::nameSing);
|
||||||
|
case artifact: return CGI->arth->artifacts[subtype]->Name();
|
||||||
|
case experience:
|
||||||
|
{
|
||||||
|
if (subtype == 1) //+1 level - tree of knowledge
|
||||||
|
{
|
||||||
|
std::string level = CGI->generaltexth->allTexts[442];
|
||||||
|
boost::replace_first(level, "1", boost::lexical_cast<std::string>(val));
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return boost::lexical_cast<std::string>(val); //amount of experience OR level required for seer hut;
|
||||||
|
}
|
||||||
|
case spell: return CGI->spellh->objects[subtype]->name;
|
||||||
|
case morale: return "";
|
||||||
|
case luck: return "";
|
||||||
|
case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Name();
|
||||||
|
case hero: return "";
|
||||||
|
case flag: return CGI->generaltexth->capColors[subtype];
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CComponent::setSurface(std::string defName, int imgPos)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
vstd::clear_pointer(image);
|
||||||
|
image = new CAnimImage(defName, imgPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CComponent::clickRight(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if(!getDescription().empty())
|
||||||
|
adventureInt->handleRightClick(getDescription(), down);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSelectableComponent::clickLeft(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if (down)
|
||||||
|
{
|
||||||
|
if(onSelect)
|
||||||
|
onSelect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSelectableComponent::init()
|
||||||
|
{
|
||||||
|
selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSelectableComponent::CSelectableComponent(const Component &c, std::function<void()> OnSelect):
|
||||||
|
CComponent(c),onSelect(OnSelect)
|
||||||
|
{
|
||||||
|
type |= REDRAW_PARENT;
|
||||||
|
addUsedEvents(LCLICK | KEYBOARD);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CSelectableComponent::CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize, std::function<void()> OnSelect):
|
||||||
|
CComponent(Type,Sub,Val, imageSize),onSelect(OnSelect)
|
||||||
|
{
|
||||||
|
type |= REDRAW_PARENT;
|
||||||
|
addUsedEvents(LCLICK | KEYBOARD);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSelectableComponent::select(bool on)
|
||||||
|
{
|
||||||
|
if(on != selected)
|
||||||
|
{
|
||||||
|
selected = on;
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSelectableComponent::showAll(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
CComponent::showAll(to);
|
||||||
|
if(selected)
|
||||||
|
{
|
||||||
|
CSDL_Ext::drawBorder(to, Rect::around(image->pos), int3(239,215,123));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CComponentBox::selectionChanged(CSelectableComponent * newSelection)
|
||||||
|
{
|
||||||
|
if (newSelection == selected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (selected)
|
||||||
|
selected->select(false);
|
||||||
|
|
||||||
|
selected = newSelection;
|
||||||
|
if (onSelect)
|
||||||
|
onSelect(selectedIndex());
|
||||||
|
|
||||||
|
if (selected)
|
||||||
|
selected->select(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CComponentBox::selectedIndex()
|
||||||
|
{
|
||||||
|
if (selected)
|
||||||
|
return std::find(components.begin(), components.end(), selected) - components.begin();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point CComponentBox::getOrTextPos(CComponent *left, CComponent *right)
|
||||||
|
{
|
||||||
|
int leftSubtitle = ( left->pos.w - left->image->pos.w) / 2;
|
||||||
|
int rightSubtitle = (right->pos.w - right->image->pos.w) / 2;
|
||||||
|
int fullDistance = getDistance(left, right) + leftSubtitle + rightSubtitle;
|
||||||
|
|
||||||
|
return Point(fullDistance/2 - leftSubtitle, (left->image->pos.h + right->image->pos.h) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CComponentBox::getDistance(CComponent *left, CComponent *right)
|
||||||
|
{
|
||||||
|
static const int betweenImagesMin = 20;
|
||||||
|
static const int betweenSubtitlesMin = 10;
|
||||||
|
|
||||||
|
int leftSubtitle = ( left->pos.w - left->image->pos.w) / 2;
|
||||||
|
int rightSubtitle = (right->pos.w - right->image->pos.w) / 2;
|
||||||
|
int subtitlesOffset = leftSubtitle + rightSubtitle;
|
||||||
|
|
||||||
|
return std::max(betweenSubtitlesMin, betweenImagesMin - subtitlesOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CComponentBox::placeComponents(bool selectable)
|
||||||
|
{
|
||||||
|
static const int betweenRows = 22;
|
||||||
|
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
if (components.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
//prepare components
|
||||||
|
for(auto & comp : components)
|
||||||
|
{
|
||||||
|
addChild(comp);
|
||||||
|
comp->moveTo(Point(pos.x, pos.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RowData
|
||||||
|
{
|
||||||
|
size_t comps;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
RowData (size_t Comps, int Width, int Height):
|
||||||
|
comps(Comps), width (Width), height (Height){};
|
||||||
|
};
|
||||||
|
std::vector<RowData> rows;
|
||||||
|
rows.push_back (RowData (0,0,0));
|
||||||
|
|
||||||
|
//split components in rows
|
||||||
|
CComponent * prevComp = nullptr;
|
||||||
|
|
||||||
|
for(CComponent * comp : components)
|
||||||
|
{
|
||||||
|
//make sure that components are smaller than our width
|
||||||
|
//assert(pos.w == 0 || pos.w < comp->pos.w);
|
||||||
|
|
||||||
|
const int distance = prevComp ? getDistance(prevComp, comp) : 0;
|
||||||
|
|
||||||
|
//start next row
|
||||||
|
if ((pos.w != 0 && rows.back().width + comp->pos.w + distance > pos.w) // row is full
|
||||||
|
|| rows.back().comps >= 4) // no more than 4 comps per row
|
||||||
|
{
|
||||||
|
prevComp = nullptr;
|
||||||
|
rows.push_back (RowData (0,0,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevComp)
|
||||||
|
rows.back().width += distance;
|
||||||
|
|
||||||
|
rows.back().comps++;
|
||||||
|
rows.back().width += comp->pos.w;
|
||||||
|
|
||||||
|
vstd::amax(rows.back().height, comp->pos.h);
|
||||||
|
prevComp = comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos.w == 0)
|
||||||
|
{
|
||||||
|
for(auto & row : rows)
|
||||||
|
vstd::amax(pos.w, row.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
int height = (rows.size() - 1) * betweenRows;
|
||||||
|
for(auto & row : rows)
|
||||||
|
height += row.height;
|
||||||
|
|
||||||
|
//assert(pos.h == 0 || pos.h < height);
|
||||||
|
if (pos.h == 0)
|
||||||
|
pos.h = height;
|
||||||
|
|
||||||
|
auto iter = components.begin();
|
||||||
|
int currentY = (pos.h - height) / 2;
|
||||||
|
|
||||||
|
//move components to their positions
|
||||||
|
for (auto & rows_row : rows)
|
||||||
|
{
|
||||||
|
// amount of free space we may add on each side of every component
|
||||||
|
int freeSpace = (pos.w - rows_row.width) / (rows_row.comps * 2);
|
||||||
|
prevComp = nullptr;
|
||||||
|
|
||||||
|
int currentX = 0;
|
||||||
|
for (size_t col = 0; col < rows_row.comps; col++)
|
||||||
|
{
|
||||||
|
currentX += freeSpace;
|
||||||
|
if (prevComp)
|
||||||
|
{
|
||||||
|
if (selectable)
|
||||||
|
{
|
||||||
|
Point orPos = Point(currentX - freeSpace, currentY) + getOrTextPos(prevComp, *iter);
|
||||||
|
|
||||||
|
new CLabel(orPos.x, orPos.y, FONT_MEDIUM, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[4]);
|
||||||
|
}
|
||||||
|
currentX += getDistance(prevComp, *iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*iter)->moveBy(Point(currentX, currentY));
|
||||||
|
currentX += (*iter)->pos.w;
|
||||||
|
currentX += freeSpace;
|
||||||
|
|
||||||
|
prevComp = *(iter++);
|
||||||
|
}
|
||||||
|
currentY += rows_row.height + betweenRows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CComponentBox::CComponentBox(CComponent * _components, Rect position):
|
||||||
|
components(1, _components),
|
||||||
|
selected(nullptr)
|
||||||
|
{
|
||||||
|
type |= REDRAW_PARENT;
|
||||||
|
pos = position + pos;
|
||||||
|
placeComponents(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CComponentBox::CComponentBox(std::vector<CComponent *> _components, Rect position):
|
||||||
|
components(_components),
|
||||||
|
selected(nullptr)
|
||||||
|
{
|
||||||
|
type |= REDRAW_PARENT;
|
||||||
|
pos = position + pos;
|
||||||
|
placeComponents(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CComponentBox::CComponentBox(std::vector<CSelectableComponent *> _components, Rect position, std::function<void(int newID)> _onSelect):
|
||||||
|
components(_components.begin(), _components.end()),
|
||||||
|
selected(nullptr),
|
||||||
|
onSelect(_onSelect)
|
||||||
|
{
|
||||||
|
type |= REDRAW_PARENT;
|
||||||
|
pos = position + pos;
|
||||||
|
placeComponents(true);
|
||||||
|
|
||||||
|
assert(!components.empty());
|
||||||
|
|
||||||
|
int key = SDLK_1;
|
||||||
|
for(auto & comp : _components)
|
||||||
|
{
|
||||||
|
comp->onSelect = boost::bind(&CComponentBox::selectionChanged, this, comp);
|
||||||
|
comp->assignedKeys.insert(key++);
|
||||||
|
}
|
||||||
|
selectionChanged(_components.front());
|
||||||
|
}
|
112
client/widgets/CComponent.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../gui/CIntObject.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CComponent.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Component;
|
||||||
|
class CAnimImage;
|
||||||
|
|
||||||
|
/// common popup window component
|
||||||
|
class CComponent : public virtual CIntObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Etype
|
||||||
|
{
|
||||||
|
primskill, secskill, resource, creature, artifact, experience, spell, morale, luck, building, hero, flag, typeInvalid
|
||||||
|
};
|
||||||
|
|
||||||
|
//NOTE: not all types have exact these sizes or have less than 4 of them. In such cases closest one will be used
|
||||||
|
enum ESize
|
||||||
|
{
|
||||||
|
tiny, // ~22-24px
|
||||||
|
small, // ~30px
|
||||||
|
medium,// ~42px
|
||||||
|
large, // ~82px
|
||||||
|
sizeInvalid
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t getIndex();
|
||||||
|
const std::vector<std::string> getFileName();
|
||||||
|
void setSurface(std::string defName, int imgPos);
|
||||||
|
std::string getSubtitleInternal();
|
||||||
|
|
||||||
|
void init(Etype Type, int Subtype, int Val, ESize imageSize);
|
||||||
|
|
||||||
|
public:
|
||||||
|
CAnimImage *image; //our image
|
||||||
|
|
||||||
|
Etype compType; //component type
|
||||||
|
ESize size; //component size.
|
||||||
|
int subtype; //type-dependant subtype. See getSomething methods for details
|
||||||
|
int val; // value \ strength \ amount of component. See getSomething methods for details
|
||||||
|
bool perDay; // add "per day" text to subtitle
|
||||||
|
|
||||||
|
std::string getDescription();
|
||||||
|
std::string getSubtitle();
|
||||||
|
|
||||||
|
CComponent(Etype Type, int Subtype, int Val = 0, ESize imageSize=large);//c-tor
|
||||||
|
CComponent(const Component &c); //c-tor
|
||||||
|
|
||||||
|
void clickRight(tribool down, bool previousState); //call-in
|
||||||
|
};
|
||||||
|
|
||||||
|
/// component that can be selected or deselected
|
||||||
|
class CSelectableComponent : public CComponent, public CKeyShortcut
|
||||||
|
{
|
||||||
|
void init();
|
||||||
|
public:
|
||||||
|
bool selected; //if true, this component is selected
|
||||||
|
std::function<void()> onSelect; //function called on selection change
|
||||||
|
|
||||||
|
void showAll(SDL_Surface * to);
|
||||||
|
void select(bool on);
|
||||||
|
|
||||||
|
void clickLeft(tribool down, bool previousState); //call-in
|
||||||
|
CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize=large, std::function<void()> OnSelect = nullptr); //c-tor
|
||||||
|
CSelectableComponent(const Component &c, std::function<void()> OnSelect = nullptr); //c-tor
|
||||||
|
};
|
||||||
|
|
||||||
|
/// box with multiple components (up to 8?)
|
||||||
|
/// will take ownership on components and delete them afterwards
|
||||||
|
class CComponentBox : public CIntObject
|
||||||
|
{
|
||||||
|
std::vector<CComponent *> components;
|
||||||
|
|
||||||
|
CSelectableComponent * selected;
|
||||||
|
std::function<void(int newID)> onSelect;
|
||||||
|
|
||||||
|
void selectionChanged(CSelectableComponent * newSelection);
|
||||||
|
|
||||||
|
//get position of "or" text between these comps
|
||||||
|
//it will place "or" equidistant to both images
|
||||||
|
Point getOrTextPos(CComponent *left, CComponent * right);
|
||||||
|
|
||||||
|
//get distance between these copmonents
|
||||||
|
int getDistance(CComponent *left, CComponent * right);
|
||||||
|
void placeComponents(bool selectable);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// return index of selected item
|
||||||
|
int selectedIndex();
|
||||||
|
|
||||||
|
/// constructor for quite common 1-components popups
|
||||||
|
/// if position width or height are 0 then it will be determined automatically
|
||||||
|
CComponentBox(CComponent * components, Rect position);
|
||||||
|
/// constructor for non-selectable components
|
||||||
|
CComponentBox(std::vector<CComponent *> components, Rect position);
|
||||||
|
|
||||||
|
/// constructor for selectable components
|
||||||
|
/// will also create "or" labels between components
|
||||||
|
/// onSelect - optional function that will be called every time on selection change
|
||||||
|
CComponentBox(std::vector<CSelectableComponent *> components, Rect position, std::function<void(int newID)> onSelect = nullptr);
|
||||||
|
};
|
512
client/widgets/CGarrisonInt.cpp
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
#include "StdInc.h"
|
||||||
|
#include "CGarrisonInt.h"
|
||||||
|
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
|
||||||
|
#include "../CGameInfo.h"
|
||||||
|
#include "../CPlayerInterface.h"
|
||||||
|
#include "../widgets/Buttons.h"
|
||||||
|
#include "../widgets/TextControls.h"
|
||||||
|
#include "../windows/CCreatureWindow.h"
|
||||||
|
#include "../windows/GUIClasses.h"
|
||||||
|
|
||||||
|
#include "../../CCallback.h"
|
||||||
|
|
||||||
|
#include "../../lib/CGeneralTextHandler.h"
|
||||||
|
#include "../../lib/CCreatureHandler.h"
|
||||||
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
|
||||||
|
#include "../../lib/CGameState.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CGarrisonInt.cpp, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void CGarrisonSlot::setHighlight(bool on)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
selectionImage->enable(); //show
|
||||||
|
else
|
||||||
|
selectionImage->disable(); //hide
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonSlot::hover (bool on)
|
||||||
|
{
|
||||||
|
////Hoverable::hover(on);
|
||||||
|
if(on)
|
||||||
|
{
|
||||||
|
std::string temp;
|
||||||
|
if(creature)
|
||||||
|
{
|
||||||
|
if(owner->getSelection())
|
||||||
|
{
|
||||||
|
if(owner->getSelection() == this)
|
||||||
|
{
|
||||||
|
temp = CGI->generaltexth->tcommands[4]; //View %s
|
||||||
|
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
|
||||||
|
}
|
||||||
|
else if (owner->getSelection()->creature == creature)
|
||||||
|
{
|
||||||
|
temp = CGI->generaltexth->tcommands[2]; //Combine %s armies
|
||||||
|
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
|
||||||
|
}
|
||||||
|
else if (owner->getSelection()->creature)
|
||||||
|
{
|
||||||
|
temp = CGI->generaltexth->tcommands[7]; //Exchange %s with %s
|
||||||
|
boost::algorithm::replace_first(temp,"%s",owner->getSelection()->creature->nameSing);
|
||||||
|
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logGlobal->warnStream() << "Warning - shouldn't be - highlighted void slot "<<owner->getSelection();
|
||||||
|
logGlobal->warnStream() << "Highlighted set to nullptr";
|
||||||
|
owner->selectSlot(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(upg)
|
||||||
|
{
|
||||||
|
temp = CGI->generaltexth->tcommands[32]; //Select %s (visiting)
|
||||||
|
}
|
||||||
|
else if(owner->armedObjs[0] && owner->armedObjs[0]->ID == Obj::TOWN)
|
||||||
|
{
|
||||||
|
temp = CGI->generaltexth->tcommands[12]; //Select %s (in garrison)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
temp = CGI->generaltexth->allTexts[481]; //Select %s
|
||||||
|
}
|
||||||
|
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(owner->getSelection())
|
||||||
|
{
|
||||||
|
const CArmedInstance *highl = owner->getSelection()->getObj();
|
||||||
|
if( highl->needsLastStack() //we are moving stack from hero's
|
||||||
|
&& highl->stacksCount() == 1 //it's only stack
|
||||||
|
&& owner->getSelection()->upg != upg //we're moving it to the other garrison
|
||||||
|
)
|
||||||
|
{
|
||||||
|
temp = CGI->generaltexth->tcommands[5]; //Cannot move last army to garrison
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
temp = CGI->generaltexth->tcommands[6]; //Move %s
|
||||||
|
boost::algorithm::replace_first(temp,"%s",owner->getSelection()->creature->nameSing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
temp = CGI->generaltexth->tcommands[11]; //Empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GH.statusbar->setText(temp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GH.statusbar->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CArmedInstance * CGarrisonSlot::getObj() const
|
||||||
|
{
|
||||||
|
return (!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CGarrisonSlot::our() const
|
||||||
|
{
|
||||||
|
return upg?(owner->owned[1]):(owner->owned[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonSlot::clickRight(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if(down && creature)
|
||||||
|
{
|
||||||
|
GH.pushInt(new CStackWindow(myStack, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void CGarrisonSlot::clickLeft(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if(down)
|
||||||
|
{
|
||||||
|
bool refr = false;
|
||||||
|
if(owner->getSelection())
|
||||||
|
{
|
||||||
|
if(owner->getSelection() == this) //view info
|
||||||
|
{
|
||||||
|
UpgradeInfo pom;
|
||||||
|
LOCPLINT->cb->getUpgradeInfo(getObj(), ID, pom);
|
||||||
|
|
||||||
|
bool canUpgrade = getObj()->tempOwner == LOCPLINT->playerID && pom.oldID>=0; //upgrade is possible
|
||||||
|
bool canDismiss = getObj()->tempOwner == LOCPLINT->playerID && (getObj()->stacksCount()>1 || !getObj()->needsLastStack());
|
||||||
|
std::function<void(CreatureID)> upgr = nullptr;
|
||||||
|
std::function<void()> dism = nullptr;
|
||||||
|
if(canUpgrade) upgr = [=] (CreatureID newID) { LOCPLINT->cb->upgradeCreature(getObj(), ID, newID); };
|
||||||
|
if(canDismiss) dism = [=] { LOCPLINT->cb->dismissCreature(getObj(), ID); };
|
||||||
|
|
||||||
|
owner->selectSlot(nullptr);
|
||||||
|
owner->setSplittingMode(false);
|
||||||
|
|
||||||
|
for(auto & elem : owner->splitButtons)
|
||||||
|
elem->block(true);
|
||||||
|
|
||||||
|
redraw();
|
||||||
|
refr = true;
|
||||||
|
GH.pushInt(new CStackWindow(myStack, dism, pom, upgr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Only allow certain moves if troops aren't removable or not ours.
|
||||||
|
if ( ( owner->getSelection()->our()//our creature is selected
|
||||||
|
|| owner->getSelection()->creature == creature )//or we are rebalancing army
|
||||||
|
&& ( owner->removableUnits
|
||||||
|
|| (upg == 0 && ( owner->getSelection()->upg == 1 && !creature ) )
|
||||||
|
|| (upg == 1 && owner->getSelection()->upg == 1 ) ) )
|
||||||
|
{
|
||||||
|
//we want to split
|
||||||
|
if((owner->getSplittingMode() || LOCPLINT->shiftPressed())
|
||||||
|
&& (!creature
|
||||||
|
|| (creature == owner->getSelection()->creature)))
|
||||||
|
{
|
||||||
|
owner->p2 = ID; //store the second stack pos
|
||||||
|
owner->pb = upg;//store the second stack owner (up or down army)
|
||||||
|
owner->setSplittingMode(false);
|
||||||
|
|
||||||
|
int minLeft=0, minRight=0;
|
||||||
|
|
||||||
|
if(upg != owner->getSelection()->upg) //not splitting within same army
|
||||||
|
{
|
||||||
|
if(owner->getSelection()->getObj()->stacksCount() == 1 //we're splitting away the last stack
|
||||||
|
&& owner->getSelection()->getObj()->needsLastStack() )
|
||||||
|
{
|
||||||
|
minLeft = 1;
|
||||||
|
}
|
||||||
|
if(getObj()->stacksCount() == 1 //destination army can't be emptied, unless we're rebalancing two stacks of same creature
|
||||||
|
&& owner->getSelection()->creature == creature
|
||||||
|
&& getObj()->needsLastStack() )
|
||||||
|
{
|
||||||
|
minRight = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int countLeft = owner->getSelection()->myStack ? owner->getSelection()->myStack->count : 0;
|
||||||
|
int countRight = myStack ? myStack->count : 0;
|
||||||
|
|
||||||
|
GH.pushInt(new CSplitWindow(owner->getSelection()->creature, boost::bind(&CGarrisonInt::splitStacks, owner, _1, _2),
|
||||||
|
minLeft, minRight, countLeft, countRight));
|
||||||
|
refr = true;
|
||||||
|
}
|
||||||
|
else if(creature != owner->getSelection()->creature) //swap
|
||||||
|
{
|
||||||
|
LOCPLINT->cb->swapCreatures(
|
||||||
|
(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
|
||||||
|
(!owner->getSelection()->upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
|
||||||
|
ID,owner->getSelection()->ID);
|
||||||
|
}
|
||||||
|
else //merge
|
||||||
|
{
|
||||||
|
LOCPLINT->cb->mergeStacks(
|
||||||
|
(!owner->getSelection()->upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
|
||||||
|
(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
|
||||||
|
owner->getSelection()->ID,ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Highlight
|
||||||
|
{
|
||||||
|
if(creature)
|
||||||
|
owner->selectSlot(this);
|
||||||
|
redraw();
|
||||||
|
refr = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //highlight or drop artifact
|
||||||
|
{
|
||||||
|
bool artSelected = false;
|
||||||
|
if (CWindowWithArtifacts* chw = dynamic_cast<CWindowWithArtifacts*>(GH.topInt())) //dirty solution
|
||||||
|
{
|
||||||
|
const CArtifactsOfHero::SCommonPart *commonInfo = chw->artSets.front()->commonInfo;
|
||||||
|
if (const CArtifactInstance *art = commonInfo->src.art)
|
||||||
|
{
|
||||||
|
const CGHeroInstance *srcHero = commonInfo->src.AOH->getHero();
|
||||||
|
artSelected = true;
|
||||||
|
ArtifactLocation src(srcHero, commonInfo->src.slotID);
|
||||||
|
ArtifactLocation dst(myStack, ArtifactPosition::CREATURE_SLOT);
|
||||||
|
if (art->canBePutAt(dst, true))
|
||||||
|
{ //equip clicked stack
|
||||||
|
if(dst.getArt())
|
||||||
|
{
|
||||||
|
//creature can wear only one active artifact
|
||||||
|
//if we are placing a new one, the old one will be returned to the hero's backpack
|
||||||
|
LOCPLINT->cb->swapArtifacts(dst, ArtifactLocation(srcHero, dst.getArt()->firstBackpackSlot(srcHero)));
|
||||||
|
}
|
||||||
|
LOCPLINT->cb->swapArtifacts(src, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!artSelected && creature)
|
||||||
|
{
|
||||||
|
owner->selectSlot(this);
|
||||||
|
if(creature)
|
||||||
|
{
|
||||||
|
for(auto & elem : owner->splitButtons)
|
||||||
|
elem->block(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
redraw();
|
||||||
|
refr = true;
|
||||||
|
}
|
||||||
|
if(refr) {hover(false); hover(true); } //to refresh statusbar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonSlot::update()
|
||||||
|
{
|
||||||
|
if (getObj() != nullptr)
|
||||||
|
{
|
||||||
|
addUsedEvents(LCLICK | RCLICK | HOVER);
|
||||||
|
myStack = getObj()->getStackPtr(ID);
|
||||||
|
creature = myStack ? myStack->type : nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
removeUsedEvents(LCLICK | RCLICK | HOVER);
|
||||||
|
myStack = nullptr;
|
||||||
|
creature = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature)
|
||||||
|
{
|
||||||
|
creatureImage->enable();
|
||||||
|
creatureImage->setFrame(creature->iconIndex);
|
||||||
|
|
||||||
|
stackCount->enable();
|
||||||
|
stackCount->setText(boost::lexical_cast<std::string>(myStack->count));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
creatureImage->disable();
|
||||||
|
stackCount->disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, int Upg, const CStackInstance * Creature):
|
||||||
|
ID(IID),
|
||||||
|
owner(Owner),
|
||||||
|
myStack(Creature),
|
||||||
|
creature(Creature ? Creature->type : nullptr),
|
||||||
|
upg(Upg)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
if (getObj())
|
||||||
|
addUsedEvents(LCLICK | RCLICK | HOVER);
|
||||||
|
pos.x += x;
|
||||||
|
pos.y += y;
|
||||||
|
|
||||||
|
std::string imgName = owner->smallIcons ? "cprsmall" : "TWCRPORT";
|
||||||
|
|
||||||
|
creatureImage = new CAnimImage(imgName, creature ? creature->iconIndex : 0);
|
||||||
|
if (!creature)
|
||||||
|
creatureImage->disable();
|
||||||
|
|
||||||
|
selectionImage = new CAnimImage(imgName, 1);
|
||||||
|
selectionImage->disable();
|
||||||
|
|
||||||
|
if(Owner->smallIcons)
|
||||||
|
{
|
||||||
|
pos.w = 32;
|
||||||
|
pos.h = 32;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos.w = 58;
|
||||||
|
pos.h = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
stackCount = new CLabel(pos.w, pos.h, owner->smallIcons ? FONT_TINY : FONT_MEDIUM, BOTTOMRIGHT, Colors::WHITE);
|
||||||
|
if (!creature)
|
||||||
|
stackCount->disable();
|
||||||
|
else
|
||||||
|
stackCount->setText(boost::lexical_cast<std::string>(myStack->count));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonInt::addSplitBtn(CButton * button)
|
||||||
|
{
|
||||||
|
addChild(button);
|
||||||
|
button->recActions = defActions;
|
||||||
|
splitButtons.push_back(button);
|
||||||
|
button->block(getSelection() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonInt::createSet(std::vector<CGarrisonSlot*> &ret, const CCreatureSet * set, int posX, int posY, int distance, int Upg )
|
||||||
|
{
|
||||||
|
ret.resize(7);
|
||||||
|
|
||||||
|
if (set)
|
||||||
|
{
|
||||||
|
for(auto & elem : set->Slots())
|
||||||
|
{
|
||||||
|
ret[elem.first.getNum()] = new CGarrisonSlot(this, posX + (elem.first.getNum()*distance), posY, elem.first, Upg, elem.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0; i<ret.size(); i++)
|
||||||
|
if(!ret[i])
|
||||||
|
ret[i] = new CGarrisonSlot(this, posX + (i*distance), posY, SlotID(i), Upg, nullptr);
|
||||||
|
|
||||||
|
if (twoRows)
|
||||||
|
for (int i=4; i<ret.size(); i++)
|
||||||
|
{
|
||||||
|
ret[i]->pos.x -= 126;
|
||||||
|
ret[i]->pos.y += 37;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonInt::createSlots()
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
|
||||||
|
int width = smallIcons? 32 : 58;
|
||||||
|
|
||||||
|
createSet(slotsUp, armedObjs[0], 0, 0, width+interx, 0);
|
||||||
|
createSet(slotsDown, armedObjs[1], garOffset.x, garOffset.y, width+interx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonInt::recreateSlots()
|
||||||
|
{
|
||||||
|
selectSlot(nullptr);
|
||||||
|
setSplittingMode(false);
|
||||||
|
|
||||||
|
for(auto & elem : splitButtons)
|
||||||
|
elem->block(true);
|
||||||
|
|
||||||
|
|
||||||
|
for(CGarrisonSlot * slot : slotsUp)
|
||||||
|
slot->update();
|
||||||
|
|
||||||
|
for(CGarrisonSlot * slot : slotsDown)
|
||||||
|
slot->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonInt::splitClick()
|
||||||
|
{
|
||||||
|
if(!getSelection())
|
||||||
|
return;
|
||||||
|
setSplittingMode(!getSplittingMode());
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
void CGarrisonInt::splitStacks(int, int amountRight)
|
||||||
|
{
|
||||||
|
LOCPLINT->cb->splitStack(armedObjs[getSelection()->upg], armedObjs[pb], getSelection()->ID, p2, amountRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point &garsOffset,
|
||||||
|
SDL_Surface *pomsur, const Point& SurOffset,
|
||||||
|
const CArmedInstance *s1, const CArmedInstance *s2,
|
||||||
|
bool _removableUnits, bool smallImgs, bool _twoRows ) :
|
||||||
|
highlighted(nullptr),
|
||||||
|
inSplittingMode(false),
|
||||||
|
interx(inx),
|
||||||
|
garOffset(garsOffset),
|
||||||
|
smallIcons(smallImgs),
|
||||||
|
removableUnits(_removableUnits),
|
||||||
|
twoRows(_twoRows)
|
||||||
|
{
|
||||||
|
setArmy(s1, false);
|
||||||
|
setArmy(s2, true);
|
||||||
|
pos.x += x;
|
||||||
|
pos.y += y;
|
||||||
|
createSlots();
|
||||||
|
}
|
||||||
|
|
||||||
|
const CGarrisonSlot * CGarrisonInt::getSelection()
|
||||||
|
{
|
||||||
|
return highlighted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonInt::selectSlot(CGarrisonSlot *slot)
|
||||||
|
{
|
||||||
|
if (slot != highlighted)
|
||||||
|
{
|
||||||
|
if (highlighted)
|
||||||
|
highlighted->setHighlight(false);
|
||||||
|
|
||||||
|
highlighted = slot;
|
||||||
|
for (auto button : splitButtons)
|
||||||
|
button->block(highlighted == nullptr);
|
||||||
|
|
||||||
|
if (highlighted)
|
||||||
|
highlighted->setHighlight(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonInt::setSplittingMode(bool on)
|
||||||
|
{
|
||||||
|
assert(on == false || highlighted != nullptr); //can't be in splitting mode without selection
|
||||||
|
|
||||||
|
if (inSplittingMode || on)
|
||||||
|
{
|
||||||
|
for(CGarrisonSlot * slot : slotsUp)
|
||||||
|
slot->setHighlight( ( on && (slot->creature == nullptr || slot->creature == getSelection()->creature)));
|
||||||
|
|
||||||
|
for(CGarrisonSlot * slot : slotsDown)
|
||||||
|
slot->setHighlight( ( on && (slot->creature == nullptr || slot->creature == getSelection()->creature)));
|
||||||
|
inSplittingMode = on;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CGarrisonInt::getSplittingMode()
|
||||||
|
{
|
||||||
|
return inSplittingMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGarrisonInt::setArmy(const CArmedInstance *army, bool bottomGarrison)
|
||||||
|
{
|
||||||
|
owned[bottomGarrison] = army ? (army->tempOwner == LOCPLINT->playerID || army->tempOwner == PlayerColor::UNFLAGGABLE) : false;
|
||||||
|
armedObjs[bottomGarrison] = army;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits ):
|
||||||
|
CWindowObject(PLAYER_COLORED, "GARRISON")
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
|
||||||
|
garr = new CGarrisonInt(92, 127, 4, Point(0,96), background->bg, Point(93,127), up, down, removableUnits);
|
||||||
|
{
|
||||||
|
CButton *split = new CButton(Point(88, 314), "IDV6432.DEF", CButton::tooltip(CGI->generaltexth->tcommands[3], ""), [&]{ garr->splitClick(); } );
|
||||||
|
removeChild(split);
|
||||||
|
garr->addSplitBtn(split);
|
||||||
|
}
|
||||||
|
quit = new CButton(Point(399, 314), "IOK6432.DEF", CButton::tooltip(CGI->generaltexth->tcommands[8], ""), [&]{ close(); }, SDLK_RETURN);
|
||||||
|
|
||||||
|
std::string titleText;
|
||||||
|
if (garr->armedObjs[1]->tempOwner == garr->armedObjs[0]->tempOwner)
|
||||||
|
titleText = CGI->generaltexth->allTexts[709];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
titleText = CGI->generaltexth->allTexts[35];
|
||||||
|
boost::algorithm::replace_first(titleText, "%s", garr->armedObjs[0]->Slots().begin()->second->type->namePl);
|
||||||
|
}
|
||||||
|
new CLabel(275, 30, FONT_BIG, CENTER, Colors::YELLOW, titleText);
|
||||||
|
|
||||||
|
new CAnimImage("CREST58", garr->armedObjs[0]->getOwner().getNum(), 0, 28, 124);
|
||||||
|
new CAnimImage("PortraitsLarge", dynamic_cast<const CGHeroInstance*>(garr->armedObjs[1])->portrait, 0, 29, 222);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGarrisonHolder::CGarrisonHolder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWindowWithGarrison::updateGarrisons()
|
||||||
|
{
|
||||||
|
garr->recreateSlots();
|
||||||
|
}
|
122
client/widgets/CGarrisonInt.h
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../windows/CWindowObject.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CGarrisonInt.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CGarrisonInt;
|
||||||
|
class CButton;
|
||||||
|
class CArmedInstance;
|
||||||
|
class CAnimImage;
|
||||||
|
class CCreatureSet;
|
||||||
|
class CGarrisonSlot;
|
||||||
|
class CStackInstance;
|
||||||
|
class CLabel;
|
||||||
|
|
||||||
|
/// A single garrison slot which holds one creature of a specific amount
|
||||||
|
class CGarrisonSlot : public CIntObject
|
||||||
|
{
|
||||||
|
SlotID ID; //for identification
|
||||||
|
CGarrisonInt *owner;
|
||||||
|
const CStackInstance *myStack; //nullptr if slot is empty
|
||||||
|
const CCreature *creature;
|
||||||
|
int upg; //0 - up garrison, 1 - down garrison
|
||||||
|
|
||||||
|
CAnimImage * creatureImage;
|
||||||
|
CAnimImage * selectionImage; // image for selection, not always visible
|
||||||
|
CLabel * stackCount;
|
||||||
|
|
||||||
|
void setHighlight(bool on);
|
||||||
|
public:
|
||||||
|
virtual void hover (bool on); //call-in
|
||||||
|
const CArmedInstance * getObj() const;
|
||||||
|
bool our() const;
|
||||||
|
void clickRight(tribool down, bool previousState);
|
||||||
|
void clickLeft(tribool down, bool previousState);
|
||||||
|
void update();
|
||||||
|
CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, int Upg=0, const CStackInstance * Creature=nullptr);
|
||||||
|
|
||||||
|
friend class CGarrisonInt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Class which manages slots of upper and lower garrison, splitting of units
|
||||||
|
class CGarrisonInt :public CIntObject
|
||||||
|
{
|
||||||
|
CGarrisonSlot *highlighted; //chosen slot. Should be changed only via selectSlot
|
||||||
|
bool inSplittingMode;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void selectSlot(CGarrisonSlot * slot); //null = deselect
|
||||||
|
const CGarrisonSlot * getSelection();
|
||||||
|
|
||||||
|
void setSplittingMode(bool on);
|
||||||
|
bool getSplittingMode();
|
||||||
|
|
||||||
|
int interx; //space between slots
|
||||||
|
Point garOffset; //offset between garrisons (not used if only one hero)
|
||||||
|
std::vector<CButton *> splitButtons; //may be empty if no buttons
|
||||||
|
|
||||||
|
SlotID p2; //TODO: comment me
|
||||||
|
int shiftPos;//1st slot of the second row, set shiftPoint for effect
|
||||||
|
bool pb,
|
||||||
|
smallIcons, //true - 32x32 imgs, false - 58x64
|
||||||
|
removableUnits,//player can remove units from up
|
||||||
|
twoRows,//slots will be placed in 2 rows
|
||||||
|
owned[2];//player owns up or down army [0] upper, [1] lower
|
||||||
|
|
||||||
|
// const CCreatureSet *set1; //top set of creatures
|
||||||
|
// const CCreatureSet *set2; //bottom set of creatures
|
||||||
|
|
||||||
|
std::vector<CGarrisonSlot*> slotsUp, slotsDown; //slots of upper and lower garrison
|
||||||
|
const CArmedInstance *armedObjs[2]; //[0] is upper, [1] is down
|
||||||
|
//const CArmedInstance *oup, *odown; //upper and lower garrisons (heroes or towns)
|
||||||
|
|
||||||
|
void setArmy(const CArmedInstance *army, bool bottomGarrison);
|
||||||
|
void addSplitBtn(CButton * button);
|
||||||
|
void createSet(std::vector<CGarrisonSlot*> &ret, const CCreatureSet * set, int posX, int distance, int posY, int Upg );
|
||||||
|
|
||||||
|
void createSlots();
|
||||||
|
void recreateSlots();
|
||||||
|
|
||||||
|
void splitClick(); //handles click on split button
|
||||||
|
void splitStacks(int amountLeft, int amountRight); //TODO: comment me
|
||||||
|
//x, y - position;
|
||||||
|
//inx - distance between slots;
|
||||||
|
//pomsur, SurOffset - UNUSED
|
||||||
|
//s1, s2 - top and bottom armies;
|
||||||
|
//removableUnits - you can take units from top;
|
||||||
|
//smallImgs - units images size 64x58 or 32x32;
|
||||||
|
//twoRows - display slots in 2 row (1st row = 4 slots, 2nd = 3 slots)
|
||||||
|
CGarrisonInt(int x, int y, int inx, const Point &garsOffset, SDL_Surface *pomsur, const Point &SurOffset, const CArmedInstance *s1, const CArmedInstance *s2=nullptr, bool _removableUnits = true, bool smallImgs = false, bool _twoRows=false); //c-tor
|
||||||
|
};
|
||||||
|
|
||||||
|
class CGarrisonHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CGarrisonHolder();
|
||||||
|
virtual void updateGarrisons()=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CWindowWithGarrison : public virtual CGarrisonHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CGarrisonInt *garr;
|
||||||
|
virtual void updateGarrisons();
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Garrison window where you can take creatures out of the hero to place it on the garrison
|
||||||
|
class CGarrisonWindow : public CWindowObject, public CWindowWithGarrison
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CButton * quit;
|
||||||
|
|
||||||
|
CGarrisonWindow(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits); //c-tor
|
||||||
|
};
|
533
client/widgets/Images.cpp
Normal file
@ -0,0 +1,533 @@
|
|||||||
|
#include "StdInc.h"
|
||||||
|
#include "Images.h"
|
||||||
|
|
||||||
|
#include "MiscWidgets.h"
|
||||||
|
|
||||||
|
#include "../gui/CAnimation.h"
|
||||||
|
#include "../gui/SDL_Pixels.h"
|
||||||
|
#include "../gui/SDL_Extensions.h"
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
#include "../gui/CCursorHandler.h"
|
||||||
|
|
||||||
|
#include "../battle/CBattleInterface.h"
|
||||||
|
#include "../battle/CBattleInterfaceClasses.h"
|
||||||
|
|
||||||
|
#include "../CBitmapHandler.h"
|
||||||
|
#include "../Graphics.h"
|
||||||
|
#include "../CGameInfo.h"
|
||||||
|
#include "../CPlayerInterface.h"
|
||||||
|
#include "../CMessage.h"
|
||||||
|
#include "../CMusicHandler.h"
|
||||||
|
#include "../windows/CAdvmapInterface.h"
|
||||||
|
|
||||||
|
#include "../../CCallback.h"
|
||||||
|
|
||||||
|
#include "../../lib/CConfigHandler.h"
|
||||||
|
#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
|
||||||
|
#include "../../lib/CRandomGenerator.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Images.cpp, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free )
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
bg = BG;
|
||||||
|
freeSurf = Free;
|
||||||
|
pos.x += x;
|
||||||
|
pos.y += y;
|
||||||
|
pos.w = BG->w;
|
||||||
|
pos.h = BG->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPicture::CPicture( const std::string &bmpname, int x, int y )
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
bg = BitmapHandler::loadBitmap(bmpname);
|
||||||
|
freeSurf = true;;
|
||||||
|
pos.x += x;
|
||||||
|
pos.y += y;
|
||||||
|
if(bg)
|
||||||
|
{
|
||||||
|
pos.w = bg->w;
|
||||||
|
pos.h = bg->h;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos.w = pos.h = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CPicture::CPicture(const Rect &r, const SDL_Color &color, bool screenFormat /*= false*/)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
createSimpleRect(r, screenFormat, SDL_MapRGB(bg->format, color.r, color.g,color.b));
|
||||||
|
}
|
||||||
|
|
||||||
|
CPicture::CPicture(const Rect &r, ui32 color, bool screenFormat /*= false*/)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
createSimpleRect(r, screenFormat, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
CPicture::CPicture(SDL_Surface *BG, const Rect &SrcRect, int x /*= 0*/, int y /*= 0*/, bool free /*= false*/)
|
||||||
|
{
|
||||||
|
needRefresh = false;
|
||||||
|
srcRect = new Rect(SrcRect);
|
||||||
|
pos.x += x;
|
||||||
|
pos.y += y;
|
||||||
|
pos.w = srcRect->w;
|
||||||
|
pos.h = srcRect->h;
|
||||||
|
bg = BG;
|
||||||
|
freeSurf = free;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPicture::setSurface(SDL_Surface *to)
|
||||||
|
{
|
||||||
|
bg = to;
|
||||||
|
if (srcRect)
|
||||||
|
{
|
||||||
|
pos.w = srcRect->w;
|
||||||
|
pos.h = srcRect->h;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos.w = bg->w;
|
||||||
|
pos.h = bg->h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CPicture::~CPicture()
|
||||||
|
{
|
||||||
|
if(freeSurf)
|
||||||
|
SDL_FreeSurface(bg);
|
||||||
|
delete srcRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPicture::init()
|
||||||
|
{
|
||||||
|
needRefresh = false;
|
||||||
|
srcRect = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPicture::show(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
if (needRefresh)
|
||||||
|
showAll(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPicture::showAll(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
if(bg)
|
||||||
|
{
|
||||||
|
if(srcRect)
|
||||||
|
{
|
||||||
|
SDL_Rect srcRectCpy = *srcRect;
|
||||||
|
SDL_Rect dstRect = srcRectCpy;
|
||||||
|
dstRect.x = pos.x;
|
||||||
|
dstRect.y = pos.y;
|
||||||
|
|
||||||
|
CSDL_Ext::blitSurface(bg, &srcRectCpy, to, &dstRect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
blitAt(bg, pos, to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPicture::convertToScreenBPP()
|
||||||
|
{
|
||||||
|
SDL_Surface *hlp = bg;
|
||||||
|
bg = SDL_ConvertSurface(hlp,screen->format,0);
|
||||||
|
CSDL_Ext::setDefaultColorKey(bg);
|
||||||
|
SDL_FreeSurface(hlp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPicture::setAlpha(int value)
|
||||||
|
{
|
||||||
|
#ifdef VCMI_SDL1
|
||||||
|
SDL_SetAlpha(bg, SDL_SRCALPHA, value);
|
||||||
|
#else
|
||||||
|
SDL_SetSurfaceAlphaMod(bg,value);
|
||||||
|
#endif // 0
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPicture::scaleTo(Point size)
|
||||||
|
{
|
||||||
|
SDL_Surface * scaled = CSDL_Ext::scaleSurface(bg, size.x, size.y);
|
||||||
|
|
||||||
|
if(freeSurf)
|
||||||
|
SDL_FreeSurface(bg);
|
||||||
|
|
||||||
|
setSurface(scaled);
|
||||||
|
freeSurf = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPicture::createSimpleRect(const Rect &r, bool screenFormat, ui32 color)
|
||||||
|
{
|
||||||
|
pos += r;
|
||||||
|
pos.w = r.w;
|
||||||
|
pos.h = r.h;
|
||||||
|
if(screenFormat)
|
||||||
|
bg = CSDL_Ext::newSurface(r.w, r.h);
|
||||||
|
else
|
||||||
|
bg = SDL_CreateRGBSurface(SDL_SWSURFACE, r.w, r.h, 8, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
SDL_FillRect(bg, nullptr, color);
|
||||||
|
freeSurf = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPicture::colorizeAndConvert(PlayerColor player)
|
||||||
|
{
|
||||||
|
assert(bg);
|
||||||
|
colorize(player);
|
||||||
|
convertToScreenBPP();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPicture::colorize(PlayerColor player)
|
||||||
|
{
|
||||||
|
assert(bg);
|
||||||
|
graphics->blueToPlayersAdv(bg, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFilledTexture::CFilledTexture(std::string imageName, Rect position):
|
||||||
|
CIntObject(0, position.topLeft()),
|
||||||
|
texture(BitmapHandler::loadBitmap(imageName))
|
||||||
|
{
|
||||||
|
pos.w = position.w;
|
||||||
|
pos.h = position.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFilledTexture::~CFilledTexture()
|
||||||
|
{
|
||||||
|
SDL_FreeSurface(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFilledTexture::showAll(SDL_Surface *to)
|
||||||
|
{
|
||||||
|
CSDL_Ext::CClipRectGuard guard(to, pos);
|
||||||
|
CSDL_Ext::fillTexture(to, texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
|
||||||
|
frame(Frame),
|
||||||
|
group(Group),
|
||||||
|
player(-1),
|
||||||
|
flags(Flags)
|
||||||
|
{
|
||||||
|
pos.x += x;
|
||||||
|
pos.y += y;
|
||||||
|
anim = new CAnimation(name);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimImage::CAnimImage(CAnimation *Anim, size_t Frame, size_t Group, int x, int y, ui8 Flags):
|
||||||
|
anim(Anim),
|
||||||
|
frame(Frame),
|
||||||
|
group(Group),
|
||||||
|
player(-1),
|
||||||
|
flags(Flags)
|
||||||
|
{
|
||||||
|
pos.x += x;
|
||||||
|
pos.y += y;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CAnimImage::size()
|
||||||
|
{
|
||||||
|
return anim->size(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimImage::init()
|
||||||
|
{
|
||||||
|
anim->load(frame, group);
|
||||||
|
if (flags & CShowableAnim::BASE)
|
||||||
|
anim->load(0,group);
|
||||||
|
|
||||||
|
IImage *img = anim->getImage(frame, group);
|
||||||
|
if (img)
|
||||||
|
{
|
||||||
|
pos.w = img->width();
|
||||||
|
pos.h = img->height();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimImage::~CAnimImage()
|
||||||
|
{
|
||||||
|
anim->unload(frame, group);
|
||||||
|
if (flags & CShowableAnim::BASE)
|
||||||
|
anim->unload(0,group);
|
||||||
|
delete anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimImage::showAll(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
IImage *img;
|
||||||
|
|
||||||
|
if ( flags & CShowableAnim::BASE && frame != 0)
|
||||||
|
if ((img = anim->getImage(0, group)))
|
||||||
|
img->draw(to, pos.x, pos.y);
|
||||||
|
|
||||||
|
if ((img = anim->getImage(frame, group)))
|
||||||
|
img->draw(to, pos.x, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimImage::setFrame(size_t Frame, size_t Group)
|
||||||
|
{
|
||||||
|
if (frame == Frame && group==Group)
|
||||||
|
return;
|
||||||
|
if (anim->size(Group) > Frame)
|
||||||
|
{
|
||||||
|
anim->load(Frame, Group);
|
||||||
|
anim->unload(frame, group);
|
||||||
|
frame = Frame;
|
||||||
|
group = Group;
|
||||||
|
IImage *img = anim->getImage(frame, group);
|
||||||
|
if (img)
|
||||||
|
{
|
||||||
|
if (flags & CShowableAnim::PLAYER_COLORED)
|
||||||
|
img->playerColored(player);
|
||||||
|
pos.w = img->width();
|
||||||
|
pos.h = img->height();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logGlobal->errorStream() << "Error: accessing unavailable frame " << Group << ":" << Frame << " in CAnimation!";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimImage::playerColored(PlayerColor currPlayer)
|
||||||
|
{
|
||||||
|
player = currPlayer;
|
||||||
|
flags |= CShowableAnim::PLAYER_COLORED;
|
||||||
|
anim->getImage(frame, group)->playerColored(player);
|
||||||
|
if (flags & CShowableAnim::BASE)
|
||||||
|
anim->getImage(0, group)->playerColored(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
CShowableAnim::CShowableAnim(int x, int y, std::string name, ui8 Flags, ui32 Delay, size_t Group):
|
||||||
|
anim(new CAnimation(name, Flags & USE_RLE)),
|
||||||
|
group(Group),
|
||||||
|
frame(0),
|
||||||
|
first(0),
|
||||||
|
frameDelay(Delay),
|
||||||
|
value(0),
|
||||||
|
flags(Flags),
|
||||||
|
xOffset(0),
|
||||||
|
yOffset(0),
|
||||||
|
alpha(255)
|
||||||
|
{
|
||||||
|
anim->loadGroup(group);
|
||||||
|
last = anim->size(group);
|
||||||
|
|
||||||
|
pos.w = anim->getImage(0, group)->width();
|
||||||
|
pos.h = anim->getImage(0, group)->height();
|
||||||
|
pos.x+= x;
|
||||||
|
pos.y+= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
CShowableAnim::~CShowableAnim()
|
||||||
|
{
|
||||||
|
anim->unloadGroup(group);
|
||||||
|
delete anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CShowableAnim::setAlpha(ui32 alphaValue)
|
||||||
|
{
|
||||||
|
alpha = std::min<ui32>(alphaValue, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CShowableAnim::set(size_t Group, size_t from, size_t to)
|
||||||
|
{
|
||||||
|
size_t max = anim->size(Group);
|
||||||
|
|
||||||
|
if (to < max)
|
||||||
|
max = to;
|
||||||
|
|
||||||
|
if (max < from || max == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
anim->load(Group);
|
||||||
|
anim->unload(group);
|
||||||
|
group = Group;
|
||||||
|
frame = first = from;
|
||||||
|
last = max;
|
||||||
|
value = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CShowableAnim::set(size_t Group)
|
||||||
|
{
|
||||||
|
if (anim->size(Group)== 0)
|
||||||
|
return false;
|
||||||
|
if (group != Group)
|
||||||
|
{
|
||||||
|
anim->loadGroup(Group);
|
||||||
|
anim->unloadGroup(group);
|
||||||
|
first = 0;
|
||||||
|
group = Group;
|
||||||
|
last = anim->size(Group);
|
||||||
|
}
|
||||||
|
frame = value = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CShowableAnim::reset()
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
frame = first;
|
||||||
|
|
||||||
|
if (callback)
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CShowableAnim::clipRect(int posX, int posY, int width, int height)
|
||||||
|
{
|
||||||
|
xOffset = posX;
|
||||||
|
yOffset = posY;
|
||||||
|
pos.w = width;
|
||||||
|
pos.h = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CShowableAnim::show(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
if ( flags & BASE )// && frame != first) // FIXME: results in graphical glytch in Fortress, upgraded hydra's dwelling
|
||||||
|
blitImage(first, group, to);
|
||||||
|
blitImage(frame, group, to);
|
||||||
|
|
||||||
|
if ((flags & PLAY_ONCE) && frame + 1 == last)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( ++value == frameDelay )
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
if ( ++frame >= last)
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CShowableAnim::showAll(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
if ( flags & BASE )// && frame != first)
|
||||||
|
blitImage(first, group, to);
|
||||||
|
blitImage(frame, group, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CShowableAnim::blitImage(size_t frame, size_t group, SDL_Surface *to)
|
||||||
|
{
|
||||||
|
assert(to);
|
||||||
|
Rect src( xOffset, yOffset, pos.w, pos.h);
|
||||||
|
IImage * img = anim->getImage(frame, group);
|
||||||
|
if (img)
|
||||||
|
img->draw(to, pos.x-xOffset, pos.y-yOffset, &src, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CShowableAnim::rotate(bool on, bool vertical)
|
||||||
|
{
|
||||||
|
ui8 flag = vertical? VERTICAL_FLIP:HORIZONTAL_FLIP;
|
||||||
|
if (on)
|
||||||
|
flags |= flag;
|
||||||
|
else
|
||||||
|
flags &= ~flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCreatureAnim::CCreatureAnim(int x, int y, std::string name, Rect picPos, ui8 flags, EAnimType type):
|
||||||
|
CShowableAnim(x,y,name,flags,4,type)
|
||||||
|
{
|
||||||
|
xOffset = picPos.x;
|
||||||
|
yOffset = picPos.y;
|
||||||
|
if (picPos.w)
|
||||||
|
pos.w = picPos.w;
|
||||||
|
if (picPos.h)
|
||||||
|
pos.h = picPos.h;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CCreatureAnim::loopPreview(bool warMachine)
|
||||||
|
{
|
||||||
|
std::vector<EAnimType> available;
|
||||||
|
|
||||||
|
static const EAnimType creaPreviewList[] = {HOLDING, HITTED, DEFENCE, ATTACK_FRONT, CAST_FRONT};
|
||||||
|
static const EAnimType machPreviewList[] = {HOLDING, MOVING, SHOOT_UP, SHOOT_FRONT, SHOOT_DOWN};
|
||||||
|
auto & previewList = warMachine ? machPreviewList : creaPreviewList;
|
||||||
|
|
||||||
|
for (auto & elem : previewList)
|
||||||
|
if (anim->size(elem))
|
||||||
|
available.push_back(elem);
|
||||||
|
|
||||||
|
size_t rnd = CRandomGenerator::getDefault().nextInt(available.size() * 2 - 1);
|
||||||
|
|
||||||
|
if (rnd >= available.size())
|
||||||
|
{
|
||||||
|
EAnimType type;
|
||||||
|
if ( anim->size(MOVING) == 0 )//no moving animation present
|
||||||
|
type = HOLDING;
|
||||||
|
else
|
||||||
|
type = MOVING;
|
||||||
|
|
||||||
|
//display this anim for ~1 second (time is random, but it looks good)
|
||||||
|
for (size_t i=0; i< 12/anim->size(type) + 1; i++)
|
||||||
|
addLast(type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
addLast(available[rnd]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCreatureAnim::addLast(EAnimType newType)
|
||||||
|
{
|
||||||
|
if (type != MOVING && newType == MOVING)//starting moving - play init sequence
|
||||||
|
{
|
||||||
|
queue.push( MOVE_START );
|
||||||
|
}
|
||||||
|
else if (type == MOVING && newType != MOVING )//previous anim was moving - finish it
|
||||||
|
{
|
||||||
|
queue.push( MOVE_END );
|
||||||
|
}
|
||||||
|
if (newType == TURN_L || newType == TURN_R)
|
||||||
|
queue.push(newType);
|
||||||
|
|
||||||
|
queue.push(newType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCreatureAnim::reset()
|
||||||
|
{
|
||||||
|
//if we are in the middle of rotation - set flag
|
||||||
|
if (type == TURN_L && !queue.empty() && queue.front() == TURN_L)
|
||||||
|
rotate(true);
|
||||||
|
if (type == TURN_R && !queue.empty() && queue.front() == TURN_R)
|
||||||
|
rotate(false);
|
||||||
|
|
||||||
|
while (!queue.empty())
|
||||||
|
{
|
||||||
|
EAnimType at = queue.front();
|
||||||
|
queue.pop();
|
||||||
|
if (set(at))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (callback)
|
||||||
|
callback();
|
||||||
|
while (!queue.empty())
|
||||||
|
{
|
||||||
|
EAnimType at = queue.front();
|
||||||
|
queue.pop();
|
||||||
|
if (set(at))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
set(HOLDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCreatureAnim::startPreview(bool warMachine)
|
||||||
|
{
|
||||||
|
callback = boost::bind(&CCreatureAnim::loopPreview, this, warMachine);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCreatureAnim::clearAndSet(EAnimType type)
|
||||||
|
{
|
||||||
|
while (!queue.empty())
|
||||||
|
queue.pop();
|
||||||
|
set(type);
|
||||||
|
}
|
226
client/widgets/Images.h
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../gui/CIntObject.h"
|
||||||
|
#include "../gui/SDL_Extensions.h"
|
||||||
|
|
||||||
|
struct SDL_Surface;
|
||||||
|
struct Rect;
|
||||||
|
class CAnimImage;
|
||||||
|
class CLabel;
|
||||||
|
class CAnimation;
|
||||||
|
class CDefHandler;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Images.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Image class
|
||||||
|
class CPicture : public CIntObject
|
||||||
|
{
|
||||||
|
void setSurface(SDL_Surface *to);
|
||||||
|
public:
|
||||||
|
SDL_Surface * bg;
|
||||||
|
Rect * srcRect; //if nullptr then whole surface will be used
|
||||||
|
bool freeSurf; //whether surface will be freed upon CPicture destruction
|
||||||
|
bool needRefresh;//Surface needs to be displayed each frame
|
||||||
|
|
||||||
|
operator SDL_Surface*()
|
||||||
|
{
|
||||||
|
return bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPicture(const Rect & r, const SDL_Color & color, bool screenFormat = false); //rect filled with given color
|
||||||
|
CPicture(const Rect & r, ui32 color, bool screenFormat = false); //rect filled with given color
|
||||||
|
CPicture(SDL_Surface * BG, int x = 0, int y=0, bool Free = true); //wrap existing SDL_Surface
|
||||||
|
CPicture(const std::string &bmpname, int x=0, int y=0);
|
||||||
|
CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0, bool free = false); //wrap subrect of given surface
|
||||||
|
~CPicture();
|
||||||
|
void init();
|
||||||
|
|
||||||
|
//set alpha value for whole surface. Note: may be messed up if surface is shared
|
||||||
|
// 0=transparent, 255=opaque
|
||||||
|
void setAlpha(int value);
|
||||||
|
|
||||||
|
void scaleTo(Point size);
|
||||||
|
void createSimpleRect(const Rect &r, bool screenFormat, ui32 color);
|
||||||
|
void show(SDL_Surface * to);
|
||||||
|
void showAll(SDL_Surface * to);
|
||||||
|
void convertToScreenBPP();
|
||||||
|
void colorizeAndConvert(PlayerColor player);
|
||||||
|
void colorize(PlayerColor player);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// area filled with specific texture
|
||||||
|
class CFilledTexture : CIntObject
|
||||||
|
{
|
||||||
|
SDL_Surface * texture;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CFilledTexture(std::string imageName, Rect position);
|
||||||
|
~CFilledTexture();
|
||||||
|
void showAll(SDL_Surface *to);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Class for displaying one image from animation
|
||||||
|
class CAnimImage: public CIntObject
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CAnimation* anim;
|
||||||
|
//displayed frame/group
|
||||||
|
size_t frame;
|
||||||
|
size_t group;
|
||||||
|
PlayerColor player;
|
||||||
|
ui8 flags;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
public:
|
||||||
|
CAnimImage(std::string name, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
|
||||||
|
CAnimImage(CAnimation* anim, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
|
||||||
|
~CAnimImage();//d-tor
|
||||||
|
|
||||||
|
//size of animation
|
||||||
|
size_t size();
|
||||||
|
|
||||||
|
//change displayed frame on this one
|
||||||
|
void setFrame(size_t Frame, size_t Group=0);
|
||||||
|
|
||||||
|
//makes image player-colored
|
||||||
|
void playerColored(PlayerColor player);
|
||||||
|
|
||||||
|
void showAll(SDL_Surface * to);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Base class for displaying animation, used as superclass for different animations
|
||||||
|
class CShowableAnim: public CIntObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum EFlags
|
||||||
|
{
|
||||||
|
BASE=1, //base frame will be blitted before current one
|
||||||
|
HORIZONTAL_FLIP=2, //TODO: will be displayed rotated
|
||||||
|
VERTICAL_FLIP=4, //TODO: will be displayed rotated
|
||||||
|
USE_RLE=8, //RLE-d version, support full alpha-channel for 8-bit images
|
||||||
|
PLAYER_COLORED=16, //TODO: all loaded images will be player-colored
|
||||||
|
PLAY_ONCE=32 //play animation only once and stop at last frame
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
CAnimation * anim;
|
||||||
|
|
||||||
|
size_t group, frame;//current frame
|
||||||
|
|
||||||
|
size_t first, last; //animation range
|
||||||
|
|
||||||
|
//TODO: replace with time delay(needed for battles)
|
||||||
|
ui32 frameDelay;//delay in frames of each image
|
||||||
|
ui32 value;//how many times current frame was showed
|
||||||
|
|
||||||
|
ui8 flags;//Flags from EFlags enum
|
||||||
|
|
||||||
|
//blit image with optional rotation, fitting into rect, etc
|
||||||
|
void blitImage(size_t frame, size_t group, SDL_Surface *to);
|
||||||
|
|
||||||
|
//For clipping in rect, offsets of picture coordinates
|
||||||
|
int xOffset, yOffset;
|
||||||
|
|
||||||
|
ui8 alpha;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//called when next animation sequence is required
|
||||||
|
std::function<void()> callback;
|
||||||
|
|
||||||
|
//Set per-surface alpha, 0 = transparent, 255 = opaque
|
||||||
|
void setAlpha(ui32 alphaValue);
|
||||||
|
|
||||||
|
CShowableAnim(int x, int y, std::string name, ui8 flags=0, ui32 Delay=4, size_t Group=0);
|
||||||
|
~CShowableAnim();
|
||||||
|
|
||||||
|
//set animation to group or part of group
|
||||||
|
bool set(size_t Group);
|
||||||
|
bool set(size_t Group, size_t from, size_t to=-1);
|
||||||
|
|
||||||
|
//set rotation flags
|
||||||
|
void rotate(bool on, bool vertical=false);
|
||||||
|
|
||||||
|
//move displayed part of picture (if picture is clipped to rect)
|
||||||
|
void clipRect(int posX, int posY, int width, int height);
|
||||||
|
|
||||||
|
//set frame to first, call callback
|
||||||
|
virtual void reset();
|
||||||
|
|
||||||
|
//show current frame and increase counter
|
||||||
|
void show(SDL_Surface * to);
|
||||||
|
void showAll(SDL_Surface * to);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Creature-dependend animations like attacking, moving,...
|
||||||
|
class CCreatureAnim: public CShowableAnim
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum EHeroAnimType
|
||||||
|
{
|
||||||
|
HERO_HOLDING = 0,
|
||||||
|
HERO_IDLE = 1, // idling movement that happens from time to time
|
||||||
|
HERO_DEFEAT = 2, // played when army loses stack or on friendly fire
|
||||||
|
HERO_VICTORY = 3, // when enemy stack killed or huge damage is dealt
|
||||||
|
HERO_CAST_SPELL = 4 // spellcasting
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EAnimType // list of creature animations, numbers were taken from def files
|
||||||
|
{
|
||||||
|
MOVING=0,
|
||||||
|
MOUSEON=1,
|
||||||
|
HOLDING=2,
|
||||||
|
HITTED=3,
|
||||||
|
DEFENCE=4,
|
||||||
|
DEATH=5,
|
||||||
|
//DEATH2=6, //unused?
|
||||||
|
TURN_L=7,
|
||||||
|
TURN_R=8, //same
|
||||||
|
//TURN_L2=9, //identical to previous?
|
||||||
|
//TURN_R2=10,
|
||||||
|
ATTACK_UP=11,
|
||||||
|
ATTACK_FRONT=12,
|
||||||
|
ATTACK_DOWN=13,
|
||||||
|
SHOOT_UP=14,
|
||||||
|
SHOOT_FRONT=15,
|
||||||
|
SHOOT_DOWN=16,
|
||||||
|
CAST_UP=17,
|
||||||
|
CAST_FRONT=18,
|
||||||
|
CAST_DOWN=19,
|
||||||
|
MOVE_START=20,
|
||||||
|
MOVE_END=21,
|
||||||
|
DEAD = 22 // new group, used to show dead stacks. If empty - last frame from "DEATH" will be copied here
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
//queue of animations waiting to be displayed
|
||||||
|
std::queue<EAnimType> queue;
|
||||||
|
|
||||||
|
//this function is used as callback if preview flag was set during construction
|
||||||
|
void loopPreview(bool warMachine);
|
||||||
|
|
||||||
|
public:
|
||||||
|
//change anim to next if queue is not empty, call callback othervice
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
//add sequence to the end of queue
|
||||||
|
void addLast(EAnimType newType);
|
||||||
|
|
||||||
|
void startPreview(bool warMachine);
|
||||||
|
|
||||||
|
//clear queue and set animation to this sequence
|
||||||
|
void clearAndSet(EAnimType type);
|
||||||
|
|
||||||
|
CCreatureAnim(int x, int y, std::string name, Rect picPos,
|
||||||
|
ui8 flags= USE_RLE, EAnimType = HOLDING );
|
||||||
|
|
||||||
|
};
|
442
client/widgets/MiscWidgets.cpp
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
#include "StdInc.h"
|
||||||
|
#include "MiscWidgets.h"
|
||||||
|
|
||||||
|
#include "CComponent.h"
|
||||||
|
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
#include "../gui/CCursorHandler.h"
|
||||||
|
|
||||||
|
#include "../CBitmapHandler.h"
|
||||||
|
#include "../CPlayerInterface.h"
|
||||||
|
#include "../CMessage.h"
|
||||||
|
#include "../CGameInfo.h"
|
||||||
|
#include "../windows/CAdvmapInterface.h"
|
||||||
|
#include "../windows/CCastleInterface.h"
|
||||||
|
#include "../windows/InfoWindows.h"
|
||||||
|
|
||||||
|
#include "../../CCallback.h"
|
||||||
|
|
||||||
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||||
|
#include "../../lib/CGeneralTextHandler.h"
|
||||||
|
#include "../../lib/CModHandler.h"
|
||||||
|
#include "../../lib/CGameState.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MiscWidgets.cpp, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void CHoverableArea::hover (bool on)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
GH.statusbar->setText(hoverText);
|
||||||
|
else if (GH.statusbar->getText()==hoverText)
|
||||||
|
GH.statusbar->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
CHoverableArea::CHoverableArea()
|
||||||
|
{
|
||||||
|
addUsedEvents(HOVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHoverableArea::~CHoverableArea()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LRClickableAreaWText::clickLeft(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if(!down && previousState && !text.empty())
|
||||||
|
{
|
||||||
|
LOCPLINT->showInfoDialog(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void LRClickableAreaWText::clickRight(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if (!text.empty())
|
||||||
|
adventureInt->handleRightClick(text, down);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRClickableAreaWText::LRClickableAreaWText()
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
LRClickableAreaWText::LRClickableAreaWText(const Rect &Pos, const std::string &HoverText /*= ""*/, const std::string &ClickText /*= ""*/)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
pos = Pos + pos;
|
||||||
|
hoverText = HoverText;
|
||||||
|
text = ClickText;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRClickableAreaWText::~LRClickableAreaWText()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LRClickableAreaWText::init()
|
||||||
|
{
|
||||||
|
addUsedEvents(LCLICK | RCLICK | HOVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LRClickableAreaWTextComp::clickLeft(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if((!down) && previousState)
|
||||||
|
{
|
||||||
|
std::vector<CComponent*> comp(1, createComponent());
|
||||||
|
LOCPLINT->showInfoDialog(text, comp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LRClickableAreaWTextComp::LRClickableAreaWTextComp(const Rect &Pos, int BaseType)
|
||||||
|
: LRClickableAreaWText(Pos), baseType(BaseType), bonusValue(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CComponent * LRClickableAreaWTextComp::createComponent() const
|
||||||
|
{
|
||||||
|
if(baseType >= 0)
|
||||||
|
return new CComponent(CComponent::Etype(baseType), type, bonusValue);
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LRClickableAreaWTextComp::clickRight(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if(down)
|
||||||
|
{
|
||||||
|
if(CComponent *comp = createComponent())
|
||||||
|
{
|
||||||
|
CRClickPopup::createAndPush(text, CInfoWindow::TCompsInfo(1, comp));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LRClickableAreaWText::clickRight(down, previousState); //only if with-component variant not occurred
|
||||||
|
}
|
||||||
|
|
||||||
|
CHeroArea::CHeroArea(int x, int y, const CGHeroInstance * _hero):hero(_hero)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
|
||||||
|
addUsedEvents(LCLICK | RCLICK | HOVER);
|
||||||
|
pos.x += x; pos.w = 58;
|
||||||
|
pos.y += y; pos.h = 64;
|
||||||
|
|
||||||
|
if (hero)
|
||||||
|
new CAnimImage("PortraitsLarge", hero->portrait);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHeroArea::clickLeft(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if((!down) && previousState && hero)
|
||||||
|
LOCPLINT->openHeroWindow(hero);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHeroArea::clickRight(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if((!down) && previousState && hero)
|
||||||
|
LOCPLINT->openHeroWindow(hero);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHeroArea::hover(bool on)
|
||||||
|
{
|
||||||
|
if (on && hero)
|
||||||
|
GH.statusbar->setText(hero->getObjectName());
|
||||||
|
else
|
||||||
|
GH.statusbar->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LRClickableAreaOpenTown::clickLeft(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if((!down) && previousState && town)
|
||||||
|
{
|
||||||
|
LOCPLINT->openTownWindow(town);
|
||||||
|
if ( type == 2 )
|
||||||
|
LOCPLINT->castleInt->builds->buildingClicked(BuildingID::VILLAGE_HALL);
|
||||||
|
else if ( type == 3 && town->fortLevel() )
|
||||||
|
LOCPLINT->castleInt->builds->buildingClicked(BuildingID::FORT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LRClickableAreaOpenTown::clickRight(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if((!down) && previousState && town)
|
||||||
|
LOCPLINT->openTownWindow(town);//TODO: popup?
|
||||||
|
}
|
||||||
|
|
||||||
|
LRClickableAreaOpenTown::LRClickableAreaOpenTown()
|
||||||
|
: LRClickableAreaWTextComp(Rect(0,0,0,0), -1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMinorResDataBar::show(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMinorResDataBar::showAll(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
blitAt(bg,pos.x,pos.y,to);
|
||||||
|
for (Res::ERes i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1))
|
||||||
|
{
|
||||||
|
std::string text = boost::lexical_cast<std::string>(LOCPLINT->cb->getResourceAmount(i));
|
||||||
|
|
||||||
|
graphics->fonts[FONT_SMALL]->renderTextCenter(to, text, Colors::WHITE, Point(pos.x + 50 + 76 * i, pos.y + pos.h/2));
|
||||||
|
}
|
||||||
|
std::vector<std::string> temp;
|
||||||
|
|
||||||
|
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::MONTH)));
|
||||||
|
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::WEEK)));
|
||||||
|
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK)));
|
||||||
|
|
||||||
|
std::string datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63]
|
||||||
|
+ ": %s, " + CGI->generaltexth->allTexts[64] + ": %s";
|
||||||
|
|
||||||
|
graphics->fonts[FONT_SMALL]->renderTextCenter(to, CSDL_Ext::processStr(datetext,temp), Colors::WHITE, Point(pos.x+545+(pos.w-545)/2,pos.y+pos.h/2));
|
||||||
|
}
|
||||||
|
|
||||||
|
CMinorResDataBar::CMinorResDataBar()
|
||||||
|
{
|
||||||
|
bg = BitmapHandler::loadBitmap("KRESBAR.bmp");
|
||||||
|
CSDL_Ext::setDefaultColorKey(bg);
|
||||||
|
graphics->blueToPlayersAdv(bg,LOCPLINT->playerID);
|
||||||
|
pos.x = 7;
|
||||||
|
pos.y = 575;
|
||||||
|
pos.w = bg->w;
|
||||||
|
pos.h = bg->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMinorResDataBar::~CMinorResDataBar()
|
||||||
|
{
|
||||||
|
SDL_FreeSurface(bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CArmyTooltip::init(const InfoAboutArmy &army)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
|
||||||
|
new CLabel(66, 2, FONT_SMALL, TOPLEFT, Colors::WHITE, army.name);
|
||||||
|
|
||||||
|
std::vector<Point> slotsPos;
|
||||||
|
slotsPos.push_back(Point(36,73));
|
||||||
|
slotsPos.push_back(Point(72,73));
|
||||||
|
slotsPos.push_back(Point(108,73));
|
||||||
|
slotsPos.push_back(Point(18,122));
|
||||||
|
slotsPos.push_back(Point(54,122));
|
||||||
|
slotsPos.push_back(Point(90,122));
|
||||||
|
slotsPos.push_back(Point(126,122));
|
||||||
|
|
||||||
|
for(auto & slot : army.army)
|
||||||
|
{
|
||||||
|
if(slot.first.getNum() >= GameConstants::ARMY_SIZE)
|
||||||
|
{
|
||||||
|
logGlobal->warnStream() << "Warning: " << army.name << " has stack in slot " << slot.first;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
new CAnimImage("CPRSMALL", slot.second.type->iconIndex, 0, slotsPos[slot.first.getNum()].x, slotsPos[slot.first.getNum()].y);
|
||||||
|
|
||||||
|
std::string subtitle;
|
||||||
|
if(army.army.isDetailed)
|
||||||
|
subtitle = boost::lexical_cast<std::string>(slot.second.count);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//if =0 - we have no information about stack size at all
|
||||||
|
if (slot.second.count)
|
||||||
|
subtitle = CGI->generaltexth->arraytxt[171 + 3*(slot.second.count)];
|
||||||
|
}
|
||||||
|
|
||||||
|
new CLabel(slotsPos[slot.first.getNum()].x + 17, slotsPos[slot.first.getNum()].y + 41, FONT_TINY, CENTER, Colors::WHITE, subtitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CArmyTooltip::CArmyTooltip(Point pos, const InfoAboutArmy &army):
|
||||||
|
CIntObject(0, pos)
|
||||||
|
{
|
||||||
|
init(army);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArmyTooltip::CArmyTooltip(Point pos, const CArmedInstance * army):
|
||||||
|
CIntObject(0, pos)
|
||||||
|
{
|
||||||
|
init(InfoAboutArmy(army, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHeroTooltip::init(const InfoAboutHero &hero)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
new CAnimImage("PortraitsLarge", hero.portrait, 0, 3, 2);
|
||||||
|
|
||||||
|
if(hero.details)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < hero.details->primskills.size(); i++)
|
||||||
|
new CLabel(75 + 28 * i, 58, FONT_SMALL, CENTER, Colors::WHITE,
|
||||||
|
boost::lexical_cast<std::string>(hero.details->primskills[i]));
|
||||||
|
|
||||||
|
new CLabel(158, 98, FONT_TINY, CENTER, Colors::WHITE,
|
||||||
|
boost::lexical_cast<std::string>(hero.details->mana));
|
||||||
|
|
||||||
|
new CAnimImage("IMRL22", hero.details->morale + 3, 0, 5, 74);
|
||||||
|
new CAnimImage("ILCK22", hero.details->luck + 3, 0, 5, 91);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CHeroTooltip::CHeroTooltip(Point pos, const InfoAboutHero &hero):
|
||||||
|
CArmyTooltip(pos, hero)
|
||||||
|
{
|
||||||
|
init(hero);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHeroTooltip::CHeroTooltip(Point pos, const CGHeroInstance * hero):
|
||||||
|
CArmyTooltip(pos, InfoAboutHero(hero, true))
|
||||||
|
{
|
||||||
|
init(InfoAboutHero(hero, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTownTooltip::init(const InfoAboutTown &town)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
|
||||||
|
//order of icons in def: fort, citadel, castle, no fort
|
||||||
|
size_t fortIndex = town.fortLevel ? town.fortLevel - 1 : 3;
|
||||||
|
|
||||||
|
new CAnimImage("ITMCLS", fortIndex, 0, 105, 31);
|
||||||
|
|
||||||
|
assert(town.tType);
|
||||||
|
|
||||||
|
size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
|
||||||
|
|
||||||
|
new CAnimImage("itpt", iconIndex, 0, 3, 2);
|
||||||
|
|
||||||
|
if(town.details)
|
||||||
|
{
|
||||||
|
new CAnimImage("ITMTLS", town.details->hallLevel, 0, 67, 31);
|
||||||
|
|
||||||
|
if (town.details->goldIncome)
|
||||||
|
new CLabel(157, 58, FONT_TINY, CENTER, Colors::WHITE,
|
||||||
|
boost::lexical_cast<std::string>(town.details->goldIncome));
|
||||||
|
|
||||||
|
if(town.details->garrisonedHero) //garrisoned hero icon
|
||||||
|
new CPicture("TOWNQKGH", 149, 76);
|
||||||
|
|
||||||
|
if(town.details->customRes)//silo is built
|
||||||
|
{
|
||||||
|
if (town.tType->primaryRes == Res::WOOD_AND_ORE )// wood & ore
|
||||||
|
{
|
||||||
|
new CAnimImage("SMALRES", Res::WOOD, 0, 7, 75);
|
||||||
|
new CAnimImage("SMALRES", Res::ORE , 0, 7, 88);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
new CAnimImage("SMALRES", town.tType->primaryRes, 0, 7, 81);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CTownTooltip::CTownTooltip(Point pos, const InfoAboutTown &town):
|
||||||
|
CArmyTooltip(pos, town)
|
||||||
|
{
|
||||||
|
init(town);
|
||||||
|
}
|
||||||
|
|
||||||
|
CTownTooltip::CTownTooltip(Point pos, const CGTownInstance * town):
|
||||||
|
CArmyTooltip(pos, InfoAboutTown(town, true))
|
||||||
|
{
|
||||||
|
init(InfoAboutTown(town, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MoraleLuckBox::set(const IBonusBearer *node)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
const int textId[] = {62, 88}; //eg %s \n\n\n {Current Luck Modifiers:}
|
||||||
|
const int noneTxtId = 108; //Russian version uses same text for neutral morale\luck
|
||||||
|
const int neutralDescr[] = {60, 86}; //eg {Neutral Morale} \n\n Neutral morale means your armies will neither be blessed with extra attacks or freeze in combat.
|
||||||
|
const int componentType[] = {CComponent::luck, CComponent::morale};
|
||||||
|
const int hoverTextBase[] = {7, 4};
|
||||||
|
const Bonus::BonusType bonusType[] = {Bonus::LUCK, Bonus::MORALE};
|
||||||
|
int (IBonusBearer::*getValue[])() const = {&IBonusBearer::LuckVal, &IBonusBearer::MoraleVal};
|
||||||
|
|
||||||
|
int mrlt = -9;
|
||||||
|
TModDescr mrl;
|
||||||
|
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
node->getModifiersWDescr(mrl, bonusType[morale]);
|
||||||
|
bonusValue = (node->*getValue[morale])();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bonusValue = 0;
|
||||||
|
|
||||||
|
mrlt = (bonusValue>0)-(bonusValue<0); //signum: -1 - bad luck / morale, 0 - neutral, 1 - good
|
||||||
|
hoverText = CGI->generaltexth->heroscrn[hoverTextBase[morale] - mrlt];
|
||||||
|
baseType = componentType[morale];
|
||||||
|
text = CGI->generaltexth->arraytxt[textId[morale]];
|
||||||
|
boost::algorithm::replace_first(text,"%s",CGI->generaltexth->arraytxt[neutralDescr[morale]-mrlt]);
|
||||||
|
if (!mrl.size())
|
||||||
|
text += CGI->generaltexth->arraytxt[noneTxtId];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//it's a creature window
|
||||||
|
if ((morale && node->hasBonusOfType(Bonus::UNDEAD)) ||
|
||||||
|
node->hasBonusOfType(Bonus::BLOCK_MORALE) || node->hasBonusOfType(Bonus::NON_LIVING))
|
||||||
|
{
|
||||||
|
text += CGI->generaltexth->arraytxt[113]; //unaffected by morale
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(auto & elem : mrl)
|
||||||
|
{
|
||||||
|
if (elem.first) //no bonuses with value 0
|
||||||
|
text += "\n" + elem.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string imageName;
|
||||||
|
if (small)
|
||||||
|
imageName = morale ? "IMRL30": "ILCK30";
|
||||||
|
else
|
||||||
|
imageName = morale ? "IMRL42" : "ILCK42";
|
||||||
|
|
||||||
|
delete image;
|
||||||
|
image = new CAnimImage(imageName, bonusValue + 3);
|
||||||
|
image->moveBy(Point(pos.w/2 - image->pos.w/2, pos.h/2 - image->pos.h/2));//center icon
|
||||||
|
}
|
||||||
|
|
||||||
|
MoraleLuckBox::MoraleLuckBox(bool Morale, const Rect &r, bool Small):
|
||||||
|
image(nullptr),
|
||||||
|
morale(Morale),
|
||||||
|
small(Small)
|
||||||
|
{
|
||||||
|
bonusValue = 0;
|
||||||
|
pos = r + pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCreaturePic::CCreaturePic(int x, int y, const CCreature *cre, bool Big, bool Animated)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
pos.x+=x;
|
||||||
|
pos.y+=y;
|
||||||
|
|
||||||
|
TFaction faction = cre->faction;
|
||||||
|
|
||||||
|
assert(CGI->townh->factions.size() > faction);
|
||||||
|
|
||||||
|
if(Big)
|
||||||
|
bg = new CPicture(CGI->townh->factions[faction]->creatureBg130);
|
||||||
|
else
|
||||||
|
bg = new CPicture(CGI->townh->factions[faction]->creatureBg120);
|
||||||
|
bg->needRefresh = true;
|
||||||
|
anim = new CCreatureAnim(0, 0, cre->animDefName, Rect());
|
||||||
|
anim->clipRect(cre->isDoubleWide()?170:150, 155, bg->pos.w, bg->pos.h);
|
||||||
|
anim->startPreview(cre->hasBonusOfType(Bonus::SIEGE_WEAPON));
|
||||||
|
|
||||||
|
pos.w = bg->pos.w;
|
||||||
|
pos.h = bg->pos.h;
|
||||||
|
}
|
150
client/widgets/MiscWidgets.h
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../gui/CIntObject.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MiscWidgets.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CCreatureAnim;
|
||||||
|
class CComponent;
|
||||||
|
class CGGarrison;
|
||||||
|
class CSelectableComponent;
|
||||||
|
class InfoAboutArmy;
|
||||||
|
class CArmedInstance;
|
||||||
|
class IBonusBearer;
|
||||||
|
class CAnimImage;
|
||||||
|
|
||||||
|
/// Shows a text by moving the mouse cursor over the object
|
||||||
|
class CHoverableArea: public virtual CIntObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string hoverText;
|
||||||
|
|
||||||
|
virtual void hover (bool on);
|
||||||
|
|
||||||
|
CHoverableArea();
|
||||||
|
virtual ~CHoverableArea();
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Can interact on left and right mouse clicks, plus it shows a text when by hovering over it
|
||||||
|
class LRClickableAreaWText: public CHoverableArea
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string text;
|
||||||
|
|
||||||
|
LRClickableAreaWText();
|
||||||
|
LRClickableAreaWText(const Rect &Pos, const std::string &HoverText = "", const std::string &ClickText = "");
|
||||||
|
virtual ~LRClickableAreaWText();
|
||||||
|
void init();
|
||||||
|
|
||||||
|
virtual void clickLeft(tribool down, bool previousState);
|
||||||
|
virtual void clickRight(tribool down, bool previousState);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// base class for hero/town/garrison tooltips
|
||||||
|
class CArmyTooltip : public CIntObject
|
||||||
|
{
|
||||||
|
void init(const InfoAboutArmy &army);
|
||||||
|
public:
|
||||||
|
CArmyTooltip(Point pos, const InfoAboutArmy &army);
|
||||||
|
CArmyTooltip(Point pos, const CArmedInstance * army);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Class for hero tooltip. Does not have any background!
|
||||||
|
/// background for infoBox: ADSTATHR
|
||||||
|
/// background for tooltip: HEROQVBK
|
||||||
|
class CHeroTooltip : public CArmyTooltip
|
||||||
|
{
|
||||||
|
void init(const InfoAboutHero &hero);
|
||||||
|
public:
|
||||||
|
CHeroTooltip(Point pos, const InfoAboutHero &hero);
|
||||||
|
CHeroTooltip(Point pos, const CGHeroInstance * hero);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Class for town tooltip. Does not have any background!
|
||||||
|
/// background for infoBox: ADSTATCS
|
||||||
|
/// background for tooltip: TOWNQVBK
|
||||||
|
class CTownTooltip : public CArmyTooltip
|
||||||
|
{
|
||||||
|
void init(const InfoAboutTown &town);
|
||||||
|
public:
|
||||||
|
CTownTooltip(Point pos, const InfoAboutTown &town);
|
||||||
|
CTownTooltip(Point pos, const CGTownInstance * town);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// draws picture with creature on background, use Animated=true to get animation
|
||||||
|
class CCreaturePic : public CIntObject
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CPicture *bg;
|
||||||
|
CCreatureAnim *anim; //displayed animation
|
||||||
|
|
||||||
|
public:
|
||||||
|
CCreaturePic(int x, int y, const CCreature *cre, bool Big=true, bool Animated=true); //c-tor
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Resource bar like that at the bottom of the adventure map screen
|
||||||
|
class CMinorResDataBar : public CIntObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SDL_Surface *bg; //background bitmap
|
||||||
|
void show(SDL_Surface * to);
|
||||||
|
void showAll(SDL_Surface * to);
|
||||||
|
CMinorResDataBar(); //c-tor
|
||||||
|
~CMinorResDataBar(); //d-tor
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Opens hero window by left-clicking on it
|
||||||
|
class CHeroArea: public CIntObject
|
||||||
|
{
|
||||||
|
const CGHeroInstance * hero;
|
||||||
|
public:
|
||||||
|
|
||||||
|
CHeroArea(int x, int y, const CGHeroInstance * _hero);
|
||||||
|
|
||||||
|
void clickLeft(tribool down, bool previousState);
|
||||||
|
void clickRight(tribool down, bool previousState);
|
||||||
|
void hover(bool on);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Can interact on left and right mouse clicks
|
||||||
|
class LRClickableAreaWTextComp: public LRClickableAreaWText
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int baseType;
|
||||||
|
int bonusValue, type;
|
||||||
|
virtual void clickLeft(tribool down, bool previousState);
|
||||||
|
virtual void clickRight(tribool down, bool previousState);
|
||||||
|
|
||||||
|
LRClickableAreaWTextComp(const Rect &Pos = Rect(0,0,0,0), int BaseType = -1);
|
||||||
|
CComponent * createComponent() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Opens town screen by left-clicking on it
|
||||||
|
class LRClickableAreaOpenTown: public LRClickableAreaWTextComp
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const CGTownInstance * town;
|
||||||
|
void clickLeft(tribool down, bool previousState);
|
||||||
|
void clickRight(tribool down, bool previousState);
|
||||||
|
LRClickableAreaOpenTown();
|
||||||
|
};
|
||||||
|
|
||||||
|
class MoraleLuckBox : public LRClickableAreaWTextComp
|
||||||
|
{
|
||||||
|
CAnimImage *image;
|
||||||
|
public:
|
||||||
|
bool morale; //true if morale, false if luck
|
||||||
|
bool small;
|
||||||
|
|
||||||
|
void set(const IBonusBearer *node);
|
||||||
|
|
||||||
|
MoraleLuckBox(bool Morale, const Rect &r, bool Small=false);
|
||||||
|
};
|
234
client/widgets/ObjectLists.cpp
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
#include "StdInc.h"
|
||||||
|
#include "ObjectLists.h"
|
||||||
|
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
#include "Buttons.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ObjectLists.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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static void intDeleter(CIntObject* object)
|
||||||
|
{
|
||||||
|
delete object;
|
||||||
|
}
|
||||||
|
|
||||||
|
CObjectList::CObjectList(CreateFunc create, DestroyFunc destroy):
|
||||||
|
createObject(create),
|
||||||
|
destroyObject(destroy)
|
||||||
|
{
|
||||||
|
if (!destroyObject)
|
||||||
|
destroyObject = intDeleter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CObjectList::deleteItem(CIntObject* item)
|
||||||
|
{
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
removeChild(item);
|
||||||
|
destroyObject(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
CIntObject* CObjectList::createItem(size_t index)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
CIntObject * item = createObject(index);
|
||||||
|
if (item == nullptr)
|
||||||
|
item = new CIntObject();
|
||||||
|
|
||||||
|
item->recActions = defActions;
|
||||||
|
|
||||||
|
addChild(item);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
CTabbedInt::CTabbedInt(CreateFunc create, DestroyFunc destroy, Point position, size_t ActiveID):
|
||||||
|
CObjectList(create, destroy),
|
||||||
|
activeTab(nullptr),
|
||||||
|
activeID(ActiveID)
|
||||||
|
{
|
||||||
|
pos += position;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTabbedInt::setActive(size_t which)
|
||||||
|
{
|
||||||
|
if (which != activeID)
|
||||||
|
{
|
||||||
|
activeID = which;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTabbedInt::reset()
|
||||||
|
{
|
||||||
|
deleteItem(activeTab);
|
||||||
|
activeTab = createItem(activeID);
|
||||||
|
activeTab->moveTo(pos.topLeft());
|
||||||
|
|
||||||
|
if (active)
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
CIntObject * CTabbedInt::getItem()
|
||||||
|
{
|
||||||
|
return activeTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
CListBox::CListBox(CreateFunc create, DestroyFunc destroy, Point Pos, Point ItemOffset, size_t VisibleSize,
|
||||||
|
size_t TotalSize, size_t InitialPos, int Slider, Rect SliderPos):
|
||||||
|
CObjectList(create, destroy),
|
||||||
|
first(InitialPos),
|
||||||
|
totalSize(TotalSize),
|
||||||
|
itemOffset(ItemOffset),
|
||||||
|
slider(nullptr)
|
||||||
|
{
|
||||||
|
pos += Pos;
|
||||||
|
items.resize(VisibleSize, nullptr);
|
||||||
|
|
||||||
|
if (Slider & 1)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
slider = new CSlider(SliderPos.topLeft(), SliderPos.w, boost::bind(&CListBox::moveToPos, this, _1),
|
||||||
|
VisibleSize, TotalSize, InitialPos, Slider & 2, Slider & 4 ? CSlider::BLUE : CSlider::BROWN);
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to move active items after changing list position
|
||||||
|
void CListBox::updatePositions()
|
||||||
|
{
|
||||||
|
Point itemPos = pos.topLeft();
|
||||||
|
for (auto & elem : items)
|
||||||
|
{
|
||||||
|
(elem)->moveTo(itemPos);
|
||||||
|
itemPos += itemOffset;
|
||||||
|
}
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
redraw();
|
||||||
|
if (slider)
|
||||||
|
slider->moveTo(first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::reset()
|
||||||
|
{
|
||||||
|
size_t current = first;
|
||||||
|
for (auto & elem : items)
|
||||||
|
{
|
||||||
|
deleteItem(elem);
|
||||||
|
elem = createItem(current++);
|
||||||
|
}
|
||||||
|
updatePositions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::resize(size_t newSize)
|
||||||
|
{
|
||||||
|
totalSize = newSize;
|
||||||
|
if (slider)
|
||||||
|
slider->setAmount(totalSize);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CListBox::size()
|
||||||
|
{
|
||||||
|
return totalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
CIntObject * CListBox::getItem(size_t which)
|
||||||
|
{
|
||||||
|
if (which < first || which > first + items.size() || which > totalSize)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
size_t i=first;
|
||||||
|
for (auto iter = items.begin(); iter != items.end(); iter++, i++)
|
||||||
|
if( i == which)
|
||||||
|
return *iter;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CListBox::getIndexOf(CIntObject *item)
|
||||||
|
{
|
||||||
|
size_t i=first;
|
||||||
|
for (auto iter = items.begin(); iter != items.end(); iter++, i++)
|
||||||
|
if(*iter == item)
|
||||||
|
return i;
|
||||||
|
return size_t(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::scrollTo(size_t which)
|
||||||
|
{
|
||||||
|
//scroll up
|
||||||
|
if (first > which)
|
||||||
|
moveToPos(which);
|
||||||
|
//scroll down
|
||||||
|
else if (first + items.size() <= which && which < totalSize)
|
||||||
|
moveToPos(which - items.size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::moveToPos(size_t which)
|
||||||
|
{
|
||||||
|
//Calculate new position
|
||||||
|
size_t maxPossible;
|
||||||
|
if (totalSize > items.size())
|
||||||
|
maxPossible = totalSize - items.size();
|
||||||
|
else
|
||||||
|
maxPossible = 0;
|
||||||
|
|
||||||
|
size_t newPos = std::min(which, maxPossible);
|
||||||
|
|
||||||
|
//If move distance is 1 (most of calls from Slider) - use faster shifts instead of resetting all items
|
||||||
|
if (first - newPos == 1)
|
||||||
|
moveToPrev();
|
||||||
|
else if (newPos - first == 1)
|
||||||
|
moveToNext();
|
||||||
|
else if (newPos != first)
|
||||||
|
{
|
||||||
|
first = newPos;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::moveToNext()
|
||||||
|
{
|
||||||
|
//Remove front item and insert new one to end
|
||||||
|
if (first + items.size() < totalSize)
|
||||||
|
{
|
||||||
|
first++;
|
||||||
|
deleteItem(items.front());
|
||||||
|
items.pop_front();
|
||||||
|
items.push_back(createItem(first+items.size()));
|
||||||
|
updatePositions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::moveToPrev()
|
||||||
|
{
|
||||||
|
//Remove last item and insert new one at start
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
first--;
|
||||||
|
deleteItem(items.back());
|
||||||
|
items.pop_back();
|
||||||
|
items.push_front(createItem(first));
|
||||||
|
updatePositions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CListBox::getPos()
|
||||||
|
{
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::list<CIntObject *> &CListBox::getItems()
|
||||||
|
{
|
||||||
|
return items;
|
||||||
|
}
|
111
client/widgets/ObjectLists.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../gui/CIntObject.h"
|
||||||
|
|
||||||
|
struct SDL_Surface;
|
||||||
|
struct Rect;
|
||||||
|
class CAnimImage;
|
||||||
|
class CSlider;
|
||||||
|
class CLabel;
|
||||||
|
class CAnimation;
|
||||||
|
class CDefHandler;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ObjectLists.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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// 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();
|
||||||
|
};
|
642
client/widgets/TextControls.cpp
Normal file
@ -0,0 +1,642 @@
|
|||||||
|
#include "StdInc.h"
|
||||||
|
#include "TextControls.h"
|
||||||
|
|
||||||
|
#include "Buttons.h"
|
||||||
|
#include "Images.h"
|
||||||
|
|
||||||
|
#include "../CMessage.h"
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
|
||||||
|
#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TextControls.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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::string CLabel::visibleText()
|
||||||
|
{
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLabel::showAll(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
CIntObject::showAll(to);
|
||||||
|
|
||||||
|
if(!visibleText().empty())
|
||||||
|
blitLine(to, pos, visibleText());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CLabel::CLabel(int x, int y, EFonts Font /*= FONT_SMALL*/, EAlignment Align, const SDL_Color &Color /*= Colors::WHITE*/, const std::string &Text /*= ""*/)
|
||||||
|
:CTextContainer(Align, Font, Color), text(Text)
|
||||||
|
{
|
||||||
|
type |= REDRAW_PARENT;
|
||||||
|
autoRedraw = true;
|
||||||
|
pos.x += x;
|
||||||
|
pos.y += y;
|
||||||
|
pos.w = pos.h = 0;
|
||||||
|
bg = nullptr;
|
||||||
|
|
||||||
|
if (alignment == TOPLEFT) // causes issues for MIDDLE
|
||||||
|
{
|
||||||
|
pos.w = graphics->fonts[font]->getStringWidth(visibleText().c_str());
|
||||||
|
pos.h = graphics->fonts[font]->getLineHeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Point CLabel::getBorderSize()
|
||||||
|
{
|
||||||
|
return Point(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CLabel::getText()
|
||||||
|
{
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLabel::setText(const std::string &Txt)
|
||||||
|
{
|
||||||
|
text = Txt;
|
||||||
|
if(autoRedraw)
|
||||||
|
{
|
||||||
|
if(bg || !parent)
|
||||||
|
redraw();
|
||||||
|
else
|
||||||
|
parent->redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CMultiLineLabel::CMultiLineLabel(Rect position, EFonts Font, EAlignment Align, const SDL_Color &Color, const std::string &Text):
|
||||||
|
CLabel(position.x, position.y, Font, Align, Color, Text),
|
||||||
|
visibleSize(0, 0, position.w, position.h)
|
||||||
|
{
|
||||||
|
pos.w = position.w;
|
||||||
|
pos.h = position.h;
|
||||||
|
splitText(Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMultiLineLabel::setVisibleSize(Rect visibleSize)
|
||||||
|
{
|
||||||
|
this->visibleSize = visibleSize;
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMultiLineLabel::scrollTextBy(int distance)
|
||||||
|
{
|
||||||
|
scrollTextTo(visibleSize.y + distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMultiLineLabel::scrollTextTo(int distance)
|
||||||
|
{
|
||||||
|
Rect size = visibleSize;
|
||||||
|
size.y = distance;
|
||||||
|
setVisibleSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMultiLineLabel::setText(const std::string &Txt)
|
||||||
|
{
|
||||||
|
splitText(Txt);
|
||||||
|
CLabel::setText(Txt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextContainer::blitLine(SDL_Surface *to, Rect destRect, std::string what)
|
||||||
|
{
|
||||||
|
const IFont * f = graphics->fonts[font];
|
||||||
|
Point where = destRect.topLeft();
|
||||||
|
|
||||||
|
// input is rect in which given text should be placed
|
||||||
|
// calculate proper position for top-left corner of the text
|
||||||
|
if (alignment == TOPLEFT)
|
||||||
|
{
|
||||||
|
where.x += getBorderSize().x;
|
||||||
|
where.y += getBorderSize().y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alignment == CENTER)
|
||||||
|
{
|
||||||
|
where.x += (int(destRect.w) - int(f->getStringWidth(what))) / 2;
|
||||||
|
where.y += (int(destRect.h) - int(f->getLineHeight())) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alignment == BOTTOMRIGHT)
|
||||||
|
{
|
||||||
|
where.x += getBorderSize().x + destRect.w - f->getStringWidth(what);
|
||||||
|
where.y += getBorderSize().y + destRect.h - f->getLineHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t begin = 0;
|
||||||
|
std::string delimeters = "{}";
|
||||||
|
size_t currDelimeter = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
size_t end = what.find_first_of(delimeters[currDelimeter % 2], begin);
|
||||||
|
if (begin != end)
|
||||||
|
{
|
||||||
|
std::string toPrint = what.substr(begin, end - begin);
|
||||||
|
|
||||||
|
if (currDelimeter % 2) // Enclosed in {} text - set to yellow
|
||||||
|
f->renderTextLeft(to, toPrint, Colors::YELLOW, where);
|
||||||
|
else // Non-enclosed text, use default color
|
||||||
|
f->renderTextLeft(to, toPrint, color, where);
|
||||||
|
begin = end;
|
||||||
|
|
||||||
|
where.x += f->getStringWidth(toPrint);
|
||||||
|
}
|
||||||
|
currDelimeter++;
|
||||||
|
}
|
||||||
|
while (begin++ != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
CTextContainer::CTextContainer(EAlignment alignment, EFonts font, SDL_Color color):
|
||||||
|
alignment(alignment),
|
||||||
|
font(font),
|
||||||
|
color(color)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void CMultiLineLabel::showAll(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
CIntObject::showAll(to);
|
||||||
|
|
||||||
|
const IFont * f = graphics->fonts[font];
|
||||||
|
|
||||||
|
// calculate which lines should be visible
|
||||||
|
int totalLines = lines.size();
|
||||||
|
int beginLine = visibleSize.y;
|
||||||
|
int endLine = getTextLocation().h + visibleSize.y;
|
||||||
|
|
||||||
|
if (beginLine < 0)
|
||||||
|
beginLine = 0;
|
||||||
|
else
|
||||||
|
beginLine /= f->getLineHeight();
|
||||||
|
|
||||||
|
if (endLine < 0)
|
||||||
|
endLine = 0;
|
||||||
|
else
|
||||||
|
endLine /= f->getLineHeight();
|
||||||
|
endLine++;
|
||||||
|
|
||||||
|
// and where they should be displayed
|
||||||
|
Point lineStart = getTextLocation().topLeft() - visibleSize + Point(0, beginLine * f->getLineHeight());
|
||||||
|
Point lineSize = Point(getTextLocation().w, f->getLineHeight());
|
||||||
|
|
||||||
|
CSDL_Ext::CClipRectGuard guard(to, getTextLocation()); // to properly trim text that is too big to fit
|
||||||
|
|
||||||
|
for (int i = beginLine; i < std::min(totalLines, endLine); i++)
|
||||||
|
{
|
||||||
|
if (!lines[i].empty()) //non-empty line
|
||||||
|
blitLine(to, Rect(lineStart, lineSize), lines[i]);
|
||||||
|
|
||||||
|
lineStart.y += f->getLineHeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMultiLineLabel::splitText(const std::string &Txt)
|
||||||
|
{
|
||||||
|
lines.clear();
|
||||||
|
|
||||||
|
const IFont * f = graphics->fonts[font];
|
||||||
|
int lineHeight = f->getLineHeight();
|
||||||
|
|
||||||
|
lines = CMessage::breakText(Txt, pos.w, font);
|
||||||
|
|
||||||
|
textSize.y = lineHeight * lines.size();
|
||||||
|
textSize.x = 0;
|
||||||
|
for(const std::string &line : lines)
|
||||||
|
vstd::amax( textSize.x, f->getStringWidth(line.c_str()));
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect CMultiLineLabel::getTextLocation()
|
||||||
|
{
|
||||||
|
// this method is needed for vertical alignment alignment of text
|
||||||
|
// when height of available text is smaller than height of widget
|
||||||
|
// in this case - we should add proper offset to display text at required position
|
||||||
|
if (pos.h <= textSize.y)
|
||||||
|
return pos;
|
||||||
|
|
||||||
|
Point textSize(pos.w, graphics->fonts[font]->getLineHeight() * lines.size());
|
||||||
|
Point textOffset(pos.w - textSize.x, pos.h - textSize.y);
|
||||||
|
|
||||||
|
switch(alignment)
|
||||||
|
{
|
||||||
|
case TOPLEFT: return Rect(pos.topLeft(), textSize);
|
||||||
|
case CENTER: return Rect(pos.topLeft() + textOffset / 2, textSize);
|
||||||
|
case BOTTOMRIGHT: return Rect(pos.topLeft() + textOffset, textSize);
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return Rect();
|
||||||
|
}
|
||||||
|
|
||||||
|
CLabelGroup::CLabelGroup(EFonts Font, EAlignment Align, const SDL_Color &Color):
|
||||||
|
font(Font), align(Align), color(Color)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void CLabelGroup::add(int x, int y, const std::string &text)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
new CLabel(x, y, font, align, color, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
CTextBox::CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font /*= FONT_SMALL*/, EAlignment Align /*= TOPLEFT*/, const SDL_Color &Color /*= Colors::WHITE*/):
|
||||||
|
sliderStyle(SliderStyle),
|
||||||
|
slider(nullptr)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
label = new CMultiLineLabel(rect, Font, Align, Color);
|
||||||
|
|
||||||
|
type |= REDRAW_PARENT;
|
||||||
|
pos.x += rect.x;
|
||||||
|
pos.y += rect.y;
|
||||||
|
pos.h = rect.h;
|
||||||
|
pos.w = rect.w;
|
||||||
|
|
||||||
|
assert(pos.w >= 40); //we need some space
|
||||||
|
setText(Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextBox::sliderMoved(int to)
|
||||||
|
{
|
||||||
|
label->scrollTextTo(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextBox::resize(Point newSize)
|
||||||
|
{
|
||||||
|
pos.w = newSize.x;
|
||||||
|
pos.h = newSize.y;
|
||||||
|
label->pos.w = pos.w;
|
||||||
|
label->pos.h = pos.h;
|
||||||
|
if (slider)
|
||||||
|
vstd::clear_pointer(slider); // will be recreated if needed later
|
||||||
|
|
||||||
|
setText(label->getText()); // force refresh
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextBox::setText(const std::string &text)
|
||||||
|
{
|
||||||
|
label->setText(text);
|
||||||
|
if (label->textSize.y <= label->pos.h && slider)
|
||||||
|
{
|
||||||
|
// slider is no longer needed
|
||||||
|
vstd::clear_pointer(slider);
|
||||||
|
label->pos.w = pos.w;
|
||||||
|
label->setText(text);
|
||||||
|
}
|
||||||
|
else if (label->textSize.y > label->pos.h && !slider)
|
||||||
|
{
|
||||||
|
// create slider and update widget
|
||||||
|
label->pos.w = pos.w - 32;
|
||||||
|
label->setText(text);
|
||||||
|
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
slider = new CSlider(Point(pos.w - 32, 0), pos.h, boost::bind(&CTextBox::sliderMoved, this, _1),
|
||||||
|
label->pos.h, label->textSize.y, 0, false, CSlider::EStyle(sliderStyle));
|
||||||
|
slider->setScrollStep(graphics->fonts[label->font]->getLineHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGStatusBar::setText(const std::string & Text)
|
||||||
|
{
|
||||||
|
if(!textLock)
|
||||||
|
CLabel::setText(Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGStatusBar::clear()
|
||||||
|
{
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
CGStatusBar::CGStatusBar(CPicture *BG, EFonts Font /*= FONT_SMALL*/, EAlignment Align /*= CENTER*/, const SDL_Color &Color /*= Colors::WHITE*/)
|
||||||
|
: CLabel(BG->pos.x, BG->pos.y, Font, Align, Color, "")
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
bg = BG;
|
||||||
|
addChild(bg);
|
||||||
|
pos = bg->pos;
|
||||||
|
getBorderSize();
|
||||||
|
textLock = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGStatusBar::CGStatusBar(int x, int y, std::string name/*="ADROLLVR.bmp"*/, int maxw/*=-1*/)
|
||||||
|
: CLabel(x, y, FONT_SMALL, CENTER)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
init();
|
||||||
|
bg = new CPicture(name);
|
||||||
|
pos = bg->pos;
|
||||||
|
if((unsigned int)maxw < pos.w)
|
||||||
|
{
|
||||||
|
vstd::amin(pos.w, maxw);
|
||||||
|
bg->srcRect = new Rect(0, 0, maxw, pos.h);
|
||||||
|
}
|
||||||
|
textLock = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGStatusBar::~CGStatusBar()
|
||||||
|
{
|
||||||
|
GH.statusbar = oldStatusBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGStatusBar::show(SDL_Surface * to)
|
||||||
|
{
|
||||||
|
showAll(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGStatusBar::init()
|
||||||
|
{
|
||||||
|
oldStatusBar = GH.statusbar;
|
||||||
|
GH.statusbar = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point CGStatusBar::getBorderSize()
|
||||||
|
{
|
||||||
|
//Width of borders where text should not be printed
|
||||||
|
static const Point borderSize(5,1);
|
||||||
|
|
||||||
|
switch(alignment)
|
||||||
|
{
|
||||||
|
case TOPLEFT: return Point(borderSize.x, borderSize.y);
|
||||||
|
case CENTER: return Point(pos.w/2, pos.h/2);
|
||||||
|
case BOTTOMRIGHT: return Point(pos.w - borderSize.x, pos.h - borderSize.y);
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return Point();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGStatusBar::lock(bool shouldLock)
|
||||||
|
{
|
||||||
|
textLock = shouldLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
CTextInput::CTextInput(const Rect &Pos, EFonts font, const CFunctionList<void(const std::string &)> &CB):
|
||||||
|
CLabel(Pos.x, Pos.y, font, CENTER),
|
||||||
|
cb(CB)
|
||||||
|
{
|
||||||
|
type |= REDRAW_PARENT;
|
||||||
|
focus = false;
|
||||||
|
pos.h = Pos.h;
|
||||||
|
pos.w = Pos.w;
|
||||||
|
captureAllKeys = true;
|
||||||
|
bg = nullptr;
|
||||||
|
addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
|
||||||
|
giveFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
CTextInput::CTextInput( const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList<void(const std::string &)> &CB )
|
||||||
|
:cb(CB)
|
||||||
|
{
|
||||||
|
focus = false;
|
||||||
|
pos += Pos;
|
||||||
|
captureAllKeys = true;
|
||||||
|
OBJ_CONSTRUCTION;
|
||||||
|
bg = new CPicture(bgName, bgOffset.x, bgOffset.y);
|
||||||
|
addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
|
||||||
|
giveFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
CTextInput::CTextInput(const Rect &Pos, SDL_Surface *srf)
|
||||||
|
{
|
||||||
|
focus = false;
|
||||||
|
pos += Pos;
|
||||||
|
captureAllKeys = true;
|
||||||
|
OBJ_CONSTRUCTION;
|
||||||
|
bg = new CPicture(Pos, 0, true);
|
||||||
|
Rect hlp = Pos;
|
||||||
|
if(srf)
|
||||||
|
CSDL_Ext::blitSurface(srf, &hlp, *bg, nullptr);
|
||||||
|
else
|
||||||
|
SDL_FillRect(*bg, nullptr, 0);
|
||||||
|
pos.w = bg->pos.w;
|
||||||
|
pos.h = bg->pos.h;
|
||||||
|
bg->pos = pos;
|
||||||
|
addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
|
||||||
|
giveFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInput::focusGot()
|
||||||
|
{
|
||||||
|
CSDL_Ext::startTextInput(&pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInput::focusLost()
|
||||||
|
{
|
||||||
|
CSDL_Ext::stopTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string CTextInput::visibleText()
|
||||||
|
{
|
||||||
|
return focus ? text + newText + "_" : text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInput::clickLeft( tribool down, bool previousState )
|
||||||
|
{
|
||||||
|
if(down && !focus)
|
||||||
|
giveFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInput::keyPressed( const SDL_KeyboardEvent & key )
|
||||||
|
{
|
||||||
|
|
||||||
|
if(!focus || key.state != SDL_PRESSED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(key.keysym.sym == SDLK_TAB)
|
||||||
|
{
|
||||||
|
moveFocus();
|
||||||
|
GH.breakEventHandling();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool redrawNeeded = false;
|
||||||
|
#ifdef VCMI_SDL1
|
||||||
|
std::string oldText = text;
|
||||||
|
#endif // 0
|
||||||
|
switch(key.keysym.sym)
|
||||||
|
{
|
||||||
|
case SDLK_DELETE: // have index > ' ' so it won't be filtered out by default section
|
||||||
|
return;
|
||||||
|
case SDLK_BACKSPACE:
|
||||||
|
if(!newText.empty())
|
||||||
|
{
|
||||||
|
Unicode::trimRight(newText);
|
||||||
|
redrawNeeded = true;
|
||||||
|
}
|
||||||
|
else if(!text.empty())
|
||||||
|
{
|
||||||
|
Unicode::trimRight(text);
|
||||||
|
redrawNeeded = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#ifdef VCMI_SDL1
|
||||||
|
if (key.keysym.unicode < ' ')
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text += key.keysym.unicode; //TODO 16-/>8
|
||||||
|
redrawNeeded = true;
|
||||||
|
}
|
||||||
|
#endif // 0
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#ifdef VCMI_SDL1
|
||||||
|
filters(text, oldText);
|
||||||
|
#endif // 0
|
||||||
|
if (redrawNeeded)
|
||||||
|
{
|
||||||
|
redraw();
|
||||||
|
cb(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInput::setText( const std::string &nText, bool callCb )
|
||||||
|
{
|
||||||
|
CLabel::setText(nText);
|
||||||
|
if(callCb)
|
||||||
|
cb(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key)
|
||||||
|
{
|
||||||
|
if(key.keysym.sym == SDLK_RETURN || key.keysym.sym == SDLK_KP_ENTER)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#ifdef VCMI_SDL1
|
||||||
|
//this should allow all non-printable keys to go through (for example arrows)
|
||||||
|
if (key.keysym.unicode < ' ')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef VCMI_SDL1
|
||||||
|
void CTextInput::textInputed(const SDL_TextInputEvent & event)
|
||||||
|
{
|
||||||
|
if(!focus)
|
||||||
|
return;
|
||||||
|
std::string oldText = text;
|
||||||
|
|
||||||
|
text += event.text;
|
||||||
|
|
||||||
|
filters(text,oldText);
|
||||||
|
if (text != oldText)
|
||||||
|
{
|
||||||
|
redraw();
|
||||||
|
cb(text);
|
||||||
|
}
|
||||||
|
newText = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInput::textEdited(const SDL_TextEditingEvent & event)
|
||||||
|
{
|
||||||
|
if(!focus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
newText = event.text;
|
||||||
|
redraw();
|
||||||
|
cb(text+newText);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void CTextInput::filenameFilter(std::string & text, const std::string &)
|
||||||
|
{
|
||||||
|
static const std::string forbiddenChars = "<>:\"/\\|?*\r\n"; //if we are entering a filename, some special characters won't be allowed
|
||||||
|
size_t pos;
|
||||||
|
while ((pos = text.find_first_of(forbiddenChars)) != std::string::npos)
|
||||||
|
text.erase(pos, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInput::numberFilter(std::string & text, const std::string & oldText, int minValue, int maxValue)
|
||||||
|
{
|
||||||
|
assert(minValue < maxValue);
|
||||||
|
|
||||||
|
if (text.empty())
|
||||||
|
text = "0";
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
if (text[0] == '-') //allow '-' sign as first symbol only
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
while (pos < text.size())
|
||||||
|
{
|
||||||
|
if (text[pos] < '0' || text[pos] > '9')
|
||||||
|
{
|
||||||
|
text = oldText;
|
||||||
|
return; //new text is not number.
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int value = boost::lexical_cast<int>(text);
|
||||||
|
if (value < minValue)
|
||||||
|
text = boost::lexical_cast<std::string>(minValue);
|
||||||
|
else if (value > maxValue)
|
||||||
|
text = boost::lexical_cast<std::string>(maxValue);
|
||||||
|
}
|
||||||
|
catch(boost::bad_lexical_cast &)
|
||||||
|
{
|
||||||
|
//Should never happen. Unless I missed some cases
|
||||||
|
logGlobal->warnStream() << "Warning: failed to convert "<< text << " to number!";
|
||||||
|
text = oldText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFocusable::CFocusable()
|
||||||
|
{
|
||||||
|
focusables.push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFocusable::~CFocusable()
|
||||||
|
{
|
||||||
|
if(inputWithFocus == this)
|
||||||
|
{
|
||||||
|
focusLost();
|
||||||
|
inputWithFocus = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
focusables -= this;
|
||||||
|
}
|
||||||
|
void CFocusable::giveFocus()
|
||||||
|
{
|
||||||
|
if(inputWithFocus)
|
||||||
|
{
|
||||||
|
inputWithFocus->focus = false;
|
||||||
|
inputWithFocus->focusLost();
|
||||||
|
inputWithFocus->redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
focus = true;
|
||||||
|
inputWithFocus = this;
|
||||||
|
focusGot();
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFocusable::moveFocus()
|
||||||
|
{
|
||||||
|
auto i = vstd::find(focusables, this),
|
||||||
|
ourIt = i;
|
||||||
|
for(i++; i != ourIt; i++)
|
||||||
|
{
|
||||||
|
if(i == focusables.end())
|
||||||
|
i = focusables.begin();
|
||||||
|
|
||||||
|
if((*i)->active)
|
||||||
|
{
|
||||||
|
(*i)->giveFocus();
|
||||||
|
break;;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
189
client/widgets/TextControls.h
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../gui/CIntObject.h"
|
||||||
|
#include "../gui/SDL_Extensions.h"
|
||||||
|
#include "../../lib/FunctionList.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TextControls.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 CSlider;
|
||||||
|
|
||||||
|
/// 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)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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 = "");
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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 boost::bind
|
||||||
|
static void numberFilter(std::string &text, const std::string & oldText, int minValue, int maxValue);
|
||||||
|
};
|
@ -1,36 +1,43 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CAdvmapInterface.h"
|
#include "CAdvmapInterface.h"
|
||||||
|
|
||||||
#include "../CCallback.h"
|
|
||||||
#include "CCastleInterface.h"
|
#include "CCastleInterface.h"
|
||||||
#include "gui/CCursorHandler.h"
|
|
||||||
#include "CGameInfo.h"
|
|
||||||
#include "CHeroWindow.h"
|
#include "CHeroWindow.h"
|
||||||
#include "CKingdomInterface.h"
|
#include "CKingdomInterface.h"
|
||||||
#include "CMessage.h"
|
|
||||||
#include "CPlayerInterface.h"
|
|
||||||
#include "gui/SDL_Extensions.h"
|
|
||||||
#include "CBitmapHandler.h"
|
|
||||||
#include "../lib/CConfigHandler.h"
|
|
||||||
#include "CSpellWindow.h"
|
#include "CSpellWindow.h"
|
||||||
#include "Graphics.h"
|
#include "GUIClasses.h"
|
||||||
#include "CDefHandler.h"
|
#include "CTradeWindow.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
|
||||||
#include "../lib/CHeroHandler.h"
|
#include "../CBitmapHandler.h"
|
||||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
#include "../CDefHandler.h"
|
||||||
#include "../lib/CTownHandler.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../lib/mapping/CMap.h"
|
#include "../CMessage.h"
|
||||||
#include "../lib/JsonNode.h"
|
#include "../CMusicHandler.h"
|
||||||
#include "mapHandler.h"
|
#include "../CPlayerInterface.h"
|
||||||
#include "CPreGame.h"
|
#include "../CPreGame.h"
|
||||||
#include "../lib/VCMI_Lib.h"
|
#include "../Graphics.h"
|
||||||
#include "../lib/CSpellHandler.h"
|
#include "../mapHandler.h"
|
||||||
#include "../lib/CSoundBase.h"
|
|
||||||
#include "../lib/CGameState.h"
|
#include "../gui/CCursorHandler.h"
|
||||||
#include "CMusicHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
#include "gui/CGuiHandler.h"
|
#include "../gui/SDL_Extensions.h"
|
||||||
#include "gui/CIntObjectClasses.h"
|
#include "../widgets/MiscWidgets.h"
|
||||||
#include "../lib/UnlockGuard.h"
|
#include "../windows/InfoWindows.h"
|
||||||
|
|
||||||
|
#include "../../CCallback.h"
|
||||||
|
|
||||||
|
#include "../../lib/CConfigHandler.h"
|
||||||
|
#include "../../lib/CGameState.h"
|
||||||
|
#include "../../lib/CGeneralTextHandler.h"
|
||||||
|
#include "../../lib/CHeroHandler.h"
|
||||||
|
#include "../../lib/CSoundBase.h"
|
||||||
|
#include "../../lib/CSpellHandler.h"
|
||||||
|
#include "../../lib/CTownHandler.h"
|
||||||
|
#include "../../lib/JsonNode.h"
|
||||||
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
#include "../../lib/mapping/CMap.h"
|
||||||
|
#include "../../lib/UnlockGuard.h"
|
||||||
|
#include "../../lib/VCMI_Lib.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning (disable : 4355)
|
#pragma warning (disable : 4355)
|
||||||
@ -363,6 +370,7 @@ void CResDataBar::showAll(SDL_Surface * to)
|
|||||||
CAdvMapInt::CAdvMapInt():
|
CAdvMapInt::CAdvMapInt():
|
||||||
minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)),
|
minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)),
|
||||||
statusbar(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG),
|
statusbar(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG),
|
||||||
|
<<<<<<< HEAD:client/CAdvmapInterface.cpp
|
||||||
kingOverview(CGI->generaltexth->zelp[293].first,CGI->generaltexth->zelp[293].second,
|
kingOverview(CGI->generaltexth->zelp[293].first,CGI->generaltexth->zelp[293].second,
|
||||||
std::bind(&CAdvMapInt::fshowOverview,this),&ADVOPT.kingOverview, SDLK_k),
|
std::bind(&CAdvMapInt::fshowOverview,this),&ADVOPT.kingOverview, SDLK_k),
|
||||||
|
|
||||||
@ -392,6 +400,8 @@ nextHero(CGI->generaltexth->zelp[301].first,CGI->generaltexth->zelp[301].second,
|
|||||||
|
|
||||||
endTurn(CGI->generaltexth->zelp[302].first,CGI->generaltexth->zelp[302].second,
|
endTurn(CGI->generaltexth->zelp[302].first,CGI->generaltexth->zelp[302].second,
|
||||||
std::bind(&CAdvMapInt::fendTurn,this), &ADVOPT.endTurn, SDLK_e),
|
std::bind(&CAdvMapInt::fendTurn,this), &ADVOPT.endTurn, SDLK_e),
|
||||||
|
=======
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CAdvmapInterface.cpp
|
||||||
|
|
||||||
heroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD),
|
heroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD),
|
||||||
townList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD),
|
townList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD),
|
||||||
@ -420,9 +430,28 @@ infoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192) )
|
|||||||
gems.push_back(CDefHandler::giveDef(ADVOPT.gemG[g]));
|
gems.push_back(CDefHandler::giveDef(ADVOPT.gemG[g]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto makeButton = [&] (int textID, std::function<void()> callback, config::ButtonInfo info, int key) -> CButton *
|
||||||
|
{
|
||||||
|
auto button = new CButton(Point(info.x, info.y), info.defName, CGI->generaltexth->zelp[textID], callback, key, info.playerColoured);
|
||||||
|
|
||||||
|
for (auto image : info.additionalDefs)
|
||||||
|
button->addImage(image);
|
||||||
|
return button;
|
||||||
|
};
|
||||||
|
|
||||||
|
kingOverview = makeButton(293, boost::bind(&CAdvMapInt::fshowOverview,this), ADVOPT.kingOverview, SDLK_k);
|
||||||
|
underground = makeButton(294, boost::bind(&CAdvMapInt::fswitchLevel,this), ADVOPT.underground, SDLK_u);
|
||||||
|
questlog = makeButton(295, boost::bind(&CAdvMapInt::fshowQuestlog,this), ADVOPT.questlog, SDLK_q);
|
||||||
|
sleepWake = makeButton(296, boost::bind(&CAdvMapInt::fsleepWake,this), ADVOPT.sleepWake, SDLK_w);
|
||||||
|
moveHero = makeButton(297, boost::bind(&CAdvMapInt::fmoveHero,this), ADVOPT.moveHero, SDLK_m);
|
||||||
|
spellbook = makeButton(298, boost::bind(&CAdvMapInt::fshowSpellbok,this), ADVOPT.spellbook, SDLK_c);
|
||||||
|
advOptions = makeButton(299, boost::bind(&CAdvMapInt::fadventureOPtions,this), ADVOPT.advOptions, SDLK_a);
|
||||||
|
sysOptions = makeButton(300, boost::bind(&CAdvMapInt::fsystemOptions,this), ADVOPT.sysOptions, SDLK_o);
|
||||||
|
nextHero = makeButton(301, boost::bind(&CAdvMapInt::fnextHero,this), ADVOPT.nextHero, SDLK_h);
|
||||||
|
endTurn = makeButton(302, boost::bind(&CAdvMapInt::fendTurn,this), ADVOPT.endTurn, SDLK_e);
|
||||||
|
|
||||||
setPlayer(LOCPLINT->playerID);
|
setPlayer(LOCPLINT->playerID);
|
||||||
underground.block(!CGI->mh->map->twoLevel);
|
underground->block(!CGI->mh->map->twoLevel);
|
||||||
addUsedEvents(MOVE);
|
addUsedEvents(MOVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,14 +474,14 @@ void CAdvMapInt::fswitchLevel()
|
|||||||
if (position.z)
|
if (position.z)
|
||||||
{
|
{
|
||||||
position.z--;
|
position.z--;
|
||||||
underground.setIndex(0,true);
|
underground->setIndex(0,true);
|
||||||
underground.showAll(screenBuf);
|
underground->showAll(screenBuf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
underground.setIndex(1,true);
|
underground->setIndex(1,true);
|
||||||
position.z++;
|
position.z++;
|
||||||
underground.showAll(screenBuf);
|
underground->showAll(screenBuf);
|
||||||
}
|
}
|
||||||
updateScreen = true;
|
updateScreen = true;
|
||||||
minimap.setLevel(position.z);
|
minimap.setLevel(position.z);
|
||||||
@ -537,14 +566,13 @@ void CAdvMapInt::fendTurn()
|
|||||||
|
|
||||||
void CAdvMapInt::updateSleepWake(const CGHeroInstance *h)
|
void CAdvMapInt::updateSleepWake(const CGHeroInstance *h)
|
||||||
{
|
{
|
||||||
sleepWake.block(!h);
|
sleepWake->block(!h);
|
||||||
if (!h)
|
if (!h)
|
||||||
return;
|
return;
|
||||||
bool state = isHeroSleeping(h);
|
bool state = isHeroSleeping(h);
|
||||||
sleepWake.setIndex(state ? 1 : 0, true);
|
sleepWake->setIndex(state ? 1 : 0, true);
|
||||||
sleepWake.assignedKeys.clear();
|
sleepWake->assignedKeys.clear();
|
||||||
sleepWake.assignedKeys.insert(state ? SDLK_w : SDLK_z);
|
sleepWake->assignedKeys.insert(state ? SDLK_w : SDLK_z);
|
||||||
sleepWake.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath)
|
void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath)
|
||||||
@ -554,10 +582,10 @@ void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath)
|
|||||||
hasPath = LOCPLINT->paths[h].nodes.size() ? true : false;
|
hasPath = LOCPLINT->paths[h].nodes.size() ? true : false;
|
||||||
if (!h)
|
if (!h)
|
||||||
{
|
{
|
||||||
moveHero.block(true);
|
moveHero->block(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
moveHero.block(!hasPath || (h->movement == 0));
|
moveHero->block(!hasPath || (h->movement == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
int CAdvMapInt::getNextHeroIndex(int startIndex)
|
int CAdvMapInt::getNextHeroIndex(int startIndex)
|
||||||
@ -587,12 +615,12 @@ void CAdvMapInt::updateNextHero(const CGHeroInstance *h)
|
|||||||
int next = getNextHeroIndex(start);
|
int next = getNextHeroIndex(start);
|
||||||
if (next < 0)
|
if (next < 0)
|
||||||
{
|
{
|
||||||
nextHero.block(true);
|
nextHero->block(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next];
|
const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next];
|
||||||
bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH));
|
bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH));
|
||||||
nextHero.block(noActiveHeroes);
|
nextHero->block(noActiveHeroes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAdvMapInt::activate()
|
void CAdvMapInt::activate()
|
||||||
@ -605,16 +633,16 @@ void CAdvMapInt::activate()
|
|||||||
GH.statusbar = &statusbar;
|
GH.statusbar = &statusbar;
|
||||||
if(!duringAITurn)
|
if(!duringAITurn)
|
||||||
{
|
{
|
||||||
kingOverview.activate();
|
kingOverview->activate();
|
||||||
underground.activate();
|
underground->activate();
|
||||||
questlog.activate();
|
questlog->activate();
|
||||||
sleepWake.activate();
|
sleepWake->activate();
|
||||||
moveHero.activate();
|
moveHero->activate();
|
||||||
spellbook.activate();
|
spellbook->activate();
|
||||||
sysOptions.activate();
|
sysOptions->activate();
|
||||||
advOptions.activate();
|
advOptions->activate();
|
||||||
nextHero.activate();
|
nextHero->activate();
|
||||||
endTurn.activate();
|
endTurn->activate();
|
||||||
|
|
||||||
minimap.activate();
|
minimap.activate();
|
||||||
heroList.activate();
|
heroList.activate();
|
||||||
@ -635,16 +663,16 @@ void CAdvMapInt::deactivate()
|
|||||||
scrollingDir = 0;
|
scrollingDir = 0;
|
||||||
|
|
||||||
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
|
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
|
||||||
kingOverview.deactivate();
|
kingOverview->deactivate();
|
||||||
underground.deactivate();
|
underground->deactivate();
|
||||||
questlog.deactivate();
|
questlog->deactivate();
|
||||||
sleepWake.deactivate();
|
sleepWake->deactivate();
|
||||||
moveHero.deactivate();
|
moveHero->deactivate();
|
||||||
spellbook.deactivate();
|
spellbook->deactivate();
|
||||||
advOptions.deactivate();
|
advOptions->deactivate();
|
||||||
sysOptions.deactivate();
|
sysOptions->deactivate();
|
||||||
nextHero.deactivate();
|
nextHero->deactivate();
|
||||||
endTurn.deactivate();
|
endTurn->deactivate();
|
||||||
minimap.deactivate();
|
minimap.deactivate();
|
||||||
heroList.deactivate();
|
heroList.deactivate();
|
||||||
townList.deactivate();
|
townList.deactivate();
|
||||||
@ -661,16 +689,16 @@ void CAdvMapInt::showAll(SDL_Surface * to)
|
|||||||
if(state != INGAME)
|
if(state != INGAME)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
kingOverview.showAll(to);
|
kingOverview->showAll(to);
|
||||||
underground.showAll(to);
|
underground->showAll(to);
|
||||||
questlog.showAll(to);
|
questlog->showAll(to);
|
||||||
sleepWake.showAll(to);
|
sleepWake->showAll(to);
|
||||||
moveHero.showAll(to);
|
moveHero->showAll(to);
|
||||||
spellbook.showAll(to);
|
spellbook->showAll(to);
|
||||||
advOptions.showAll(to);
|
advOptions->showAll(to);
|
||||||
sysOptions.showAll(to);
|
sysOptions->showAll(to);
|
||||||
nextHero.showAll(to);
|
nextHero->showAll(to);
|
||||||
endTurn.showAll(to);
|
endTurn->showAll(to);
|
||||||
|
|
||||||
minimap.showAll(to);
|
minimap.showAll(to);
|
||||||
heroList.showAll(to);
|
heroList.showAll(to);
|
||||||
@ -781,8 +809,8 @@ void CAdvMapInt::centerOn(int3 on)
|
|||||||
|
|
||||||
position = on;
|
position = on;
|
||||||
updateScreen=true;
|
updateScreen=true;
|
||||||
underground.setIndex(on.z,true); //change underground switch button image
|
underground->setIndex(on.z,true); //change underground switch button image
|
||||||
underground.redraw();
|
underground->redraw();
|
||||||
if (switchedLevels)
|
if (switchedLevels)
|
||||||
minimap.setLevel(position.z);
|
minimap.setLevel(position.z);
|
||||||
}
|
}
|
||||||
@ -1096,16 +1124,16 @@ void CAdvMapInt::setPlayer(PlayerColor Player)
|
|||||||
player = Player;
|
player = Player;
|
||||||
graphics->blueToPlayersAdv(bg,player);
|
graphics->blueToPlayersAdv(bg,player);
|
||||||
|
|
||||||
kingOverview.setPlayerColor(player);
|
kingOverview->setPlayerColor(player);
|
||||||
underground.setPlayerColor(player);
|
underground->setPlayerColor(player);
|
||||||
questlog.setPlayerColor(player);
|
questlog->setPlayerColor(player);
|
||||||
sleepWake.setPlayerColor(player);
|
sleepWake->setPlayerColor(player);
|
||||||
moveHero.setPlayerColor(player);
|
moveHero->setPlayerColor(player);
|
||||||
spellbook.setPlayerColor(player);
|
spellbook->setPlayerColor(player);
|
||||||
sysOptions.setPlayerColor(player);
|
sysOptions->setPlayerColor(player);
|
||||||
advOptions.setPlayerColor(player);
|
advOptions->setPlayerColor(player);
|
||||||
nextHero.setPlayerColor(player);
|
nextHero->setPlayerColor(player);
|
||||||
endTurn.setPlayerColor(player);
|
endTurn->setPlayerColor(player);
|
||||||
graphics->blueToPlayersAdv(resdatabar.bg,player);
|
graphics->blueToPlayersAdv(resdatabar.bg,player);
|
||||||
|
|
||||||
//heroList.updateHList();
|
//heroList.updateHList();
|
||||||
@ -1525,10 +1553,11 @@ void CAdvMapInt::adjustActiveness(bool aiTurnStart)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CAdventureOptions::CAdventureOptions():
|
CAdventureOptions::CAdventureOptions():
|
||||||
CWindowObject(PLAYER_COLORED, "ADVOPTS")
|
CWindowObject(PLAYER_COLORED, "ADVOPTS")
|
||||||
{
|
{
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
|
||||||
|
<<<<<<< HEAD:client/CAdvmapInterface.cpp
|
||||||
exit = new CAdventureMapButton("","",std::bind(&CAdventureOptions::close, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
|
exit = new CAdventureMapButton("","",std::bind(&CAdventureOptions::close, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
|
||||||
exit->assignedKeys.insert(SDLK_ESCAPE);
|
exit->assignedKeys.insert(SDLK_ESCAPE);
|
||||||
|
|
||||||
@ -1542,6 +1571,22 @@ CAdventureOptions::CAdventureOptions():
|
|||||||
dig = new CAdventureMapButton("","", std::bind(&CAdventureOptions::close, this), 24, 139, "ADVDIG.DEF");
|
dig = new CAdventureMapButton("","", std::bind(&CAdventureOptions::close, this), 24, 139, "ADVDIG.DEF");
|
||||||
if(const CGHeroInstance *h = adventureInt->curHero())
|
if(const CGHeroInstance *h = adventureInt->curHero())
|
||||||
dig->callback += std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h);
|
dig->callback += std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h);
|
||||||
|
=======
|
||||||
|
exit = new CButton(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), boost::bind(&CAdventureOptions::close, this), SDLK_RETURN);
|
||||||
|
exit->assignedKeys.insert(SDLK_ESCAPE);
|
||||||
|
|
||||||
|
scenInfo = new CButton(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&]{ close(); }, SDLK_i);
|
||||||
|
scenInfo->addCallback(CAdventureOptions::showScenarioInfo);
|
||||||
|
|
||||||
|
//viewWorld = new CButton("","",boost::bind(&CGuiHandler::popIntTotally, &GH, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
|
||||||
|
|
||||||
|
puzzle = new CButton(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&]{ close(); }, SDLK_p);
|
||||||
|
puzzle->addCallback(boost::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT));
|
||||||
|
|
||||||
|
dig = new CButton(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&]{ close(); }, SDLK_d);
|
||||||
|
if(const CGHeroInstance *h = adventureInt->curHero())
|
||||||
|
dig->addCallback(boost::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h));
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CAdvmapInterface.cpp
|
||||||
else
|
else
|
||||||
dig->block(true);
|
dig->block(true);
|
||||||
}
|
}
|
@ -1,11 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <typeinfo>
|
#include "../widgets/AdventureMapClasses.h"
|
||||||
|
#include "CWindowObject.h"
|
||||||
|
|
||||||
#include "SDL.h"
|
#include "../widgets/TextControls.h"
|
||||||
#include "gui/CIntObjectClasses.h"
|
#include "../widgets/Buttons.h"
|
||||||
#include "GUIClasses.h"
|
|
||||||
#include "AdventureMapClasses.h"
|
|
||||||
|
|
||||||
class CDefHandler;
|
class CDefHandler;
|
||||||
class CCallback;
|
class CCallback;
|
||||||
@ -33,7 +32,7 @@ class IShipyard;
|
|||||||
class CAdventureOptions : public CWindowObject
|
class CAdventureOptions : public CWindowObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CAdventureMapButton *exit, *viewWorld, *puzzle, *dig, *scenInfo, *replay;
|
CButton *exit, *viewWorld, *puzzle, *dig, *scenInfo, *replay;
|
||||||
|
|
||||||
CAdventureOptions();
|
CAdventureOptions();
|
||||||
static void showScenarioInfo();
|
static void showScenarioInfo();
|
||||||
@ -111,16 +110,16 @@ public:
|
|||||||
CMinimap minimap;
|
CMinimap minimap;
|
||||||
CGStatusBar statusbar;
|
CGStatusBar statusbar;
|
||||||
|
|
||||||
CAdventureMapButton kingOverview,//- kingdom overview
|
CButton * kingOverview;
|
||||||
underground,//- underground switch
|
CButton * underground;
|
||||||
questlog,//- questlog
|
CButton * questlog;
|
||||||
sleepWake, //- sleep/wake hero
|
CButton * sleepWake;
|
||||||
moveHero, //- move hero
|
CButton * moveHero;
|
||||||
spellbook,//- spellbook
|
CButton * spellbook;
|
||||||
advOptions, //- adventure options
|
CButton * advOptions;
|
||||||
sysOptions,//- system options
|
CButton * sysOptions;
|
||||||
nextHero, //- next hero
|
CButton * nextHero;
|
||||||
endTurn;//- end turn
|
CButton * endTurn;
|
||||||
|
|
||||||
CTerrainRect terrain; //visible terrain
|
CTerrainRect terrain; //visible terrain
|
||||||
CResDataBar resdatabar;
|
CResDataBar resdatabar;
|
@ -1,29 +1,36 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CCastleInterface.h"
|
#include "CCastleInterface.h"
|
||||||
|
|
||||||
#include "../CCallback.h"
|
|
||||||
#include "../lib/CArtHandler.h"
|
|
||||||
#include "../lib/CBuildingHandler.h"
|
|
||||||
#include "../lib/CCreatureHandler.h"
|
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
|
||||||
#include "../lib/CModHandler.h"
|
|
||||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
|
||||||
#include "../lib/CSpellHandler.h"
|
|
||||||
#include "../lib/CTownHandler.h"
|
|
||||||
#include "CAdvmapInterface.h"
|
#include "CAdvmapInterface.h"
|
||||||
#include "CAnimation.h"
|
|
||||||
#include "CBitmapHandler.h"
|
|
||||||
#include "CDefHandler.h"
|
|
||||||
#include "CGameInfo.h"
|
|
||||||
#include "CHeroWindow.h"
|
#include "CHeroWindow.h"
|
||||||
#include "CMessage.h"
|
#include "CTradeWindow.h"
|
||||||
#include "CMusicHandler.h"
|
#include "GUIClasses.h"
|
||||||
#include "CPlayerInterface.h"
|
|
||||||
#include "Graphics.h"
|
#include "../CBitmapHandler.h"
|
||||||
#include "gui/SDL_Extensions.h"
|
#include "../CDefHandler.h"
|
||||||
#include "../lib/GameConstants.h"
|
#include "../CGameInfo.h"
|
||||||
#include "gui/CGuiHandler.h"
|
#include "../CMessage.h"
|
||||||
#include "gui/CIntObjectClasses.h"
|
#include "../CMusicHandler.h"
|
||||||
|
#include "../CPlayerInterface.h"
|
||||||
|
#include "../Graphics.h"
|
||||||
|
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
#include "../gui/SDL_Extensions.h"
|
||||||
|
#include "../windows/InfoWindows.h"
|
||||||
|
#include "../widgets/MiscWidgets.h"
|
||||||
|
#include "../widgets/CComponent.h"
|
||||||
|
|
||||||
|
#include "../../CCallback.h"
|
||||||
|
#include "../../lib/CArtHandler.h"
|
||||||
|
#include "../../lib/CBuildingHandler.h"
|
||||||
|
#include "../../lib/CCreatureHandler.h"
|
||||||
|
#include "../../lib/CGeneralTextHandler.h"
|
||||||
|
#include "../../lib/CModHandler.h"
|
||||||
|
#include "../../lib/CSpellHandler.h"
|
||||||
|
#include "../../lib/CTownHandler.h"
|
||||||
|
#include "../../lib/GameConstants.h"
|
||||||
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||||
|
|
||||||
using namespace boost::assign;
|
using namespace boost::assign;
|
||||||
|
|
||||||
@ -836,7 +843,11 @@ void CCastleBuildings::enterTownHall()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[673]);
|
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[673]);
|
||||||
|
<<<<<<< HEAD:client/CCastleInterface.cpp
|
||||||
(dynamic_cast<CInfoWindow*>(GH.topInt()))->buttons[0]->callback += std::bind(&CCastleBuildings::openTownHall, this);
|
(dynamic_cast<CInfoWindow*>(GH.topInt()))->buttons[0]->callback += std::bind(&CCastleBuildings::openTownHall, this);
|
||||||
|
=======
|
||||||
|
dynamic_cast<CInfoWindow*>(GH.topInt())->buttons[0]->addCallback(boost::bind(&CCastleBuildings::openTownHall, this));
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -881,12 +892,21 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
|
|||||||
income = new CLabel(195, 443, FONT_SMALL, CENTER);
|
income = new CLabel(195, 443, FONT_SMALL, CENTER);
|
||||||
icon = new CAnimImage("ITPT", 0, 0, 15, 387);
|
icon = new CAnimImage("ITPT", 0, 0, 15, 387);
|
||||||
|
|
||||||
|
<<<<<<< HEAD:client/CCastleInterface.cpp
|
||||||
exit = new CAdventureMapButton(CGI->generaltexth->tcommands[8], "", std::bind(&CCastleInterface::close,this), 744, 544, "TSBTNS", SDLK_RETURN);
|
exit = new CAdventureMapButton(CGI->generaltexth->tcommands[8], "", std::bind(&CCastleInterface::close,this), 744, 544, "TSBTNS", SDLK_RETURN);
|
||||||
|
=======
|
||||||
|
exit = new CButton(Point(744, 544), "TSBTNS", CButton::tooltip(CGI->generaltexth->tcommands[8]), [&]{close();}, SDLK_RETURN);
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||||
exit->assignedKeys.insert(SDLK_ESCAPE);
|
exit->assignedKeys.insert(SDLK_ESCAPE);
|
||||||
exit->setOffset(4);
|
exit->setImageOrder(4, 5, 6, 7);
|
||||||
|
|
||||||
|
<<<<<<< HEAD:client/CCastleInterface.cpp
|
||||||
split = new CAdventureMapButton(CGI->generaltexth->tcommands[3], "", std::bind(&CGarrisonInt::splitClick,garr), 744, 382, "TSBTNS.DEF");
|
split = new CAdventureMapButton(CGI->generaltexth->tcommands[3], "", std::bind(&CGarrisonInt::splitClick,garr), 744, 382, "TSBTNS.DEF");
|
||||||
split->callback += std::bind(&HeroSlots::splitClicked, heroes);
|
split->callback += std::bind(&HeroSlots::splitClicked, heroes);
|
||||||
|
=======
|
||||||
|
split = new CButton(Point(744, 382), "TSBTNS.DEF", CButton::tooltip(CGI->generaltexth->tcommands[3]), [&]{garr->splitClick();});
|
||||||
|
split->addCallback(boost::bind(&HeroSlots::splitClicked, heroes));
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||||
garr->addSplitBtn(split);
|
garr->addSplitBtn(split);
|
||||||
|
|
||||||
Rect barRect(9, 182, 732, 18);
|
Rect barRect(9, 182, 732, 18);
|
||||||
@ -1304,8 +1324,12 @@ CHallInterface::CHallInterface(const CGTownInstance *Town):
|
|||||||
statusBar = new CGStatusBar(new CPicture(*background, barRect, 5, 556, false));
|
statusBar = new CGStatusBar(new CPicture(*background, barRect, 5, 556, false));
|
||||||
|
|
||||||
title = new CLabel(399, 12, FONT_MEDIUM, CENTER, Colors::WHITE, town->town->buildings.at(BuildingID(town->hallLevel()+BuildingID::VILLAGE_HALL))->Name());
|
title = new CLabel(399, 12, FONT_MEDIUM, CENTER, Colors::WHITE, town->town->buildings.at(BuildingID(town->hallLevel()+BuildingID::VILLAGE_HALL))->Name());
|
||||||
|
<<<<<<< HEAD:client/CCastleInterface.cpp
|
||||||
exit = new CAdventureMapButton(CGI->generaltexth->hcommands[8], "",
|
exit = new CAdventureMapButton(CGI->generaltexth->hcommands[8], "",
|
||||||
std::bind(&CHallInterface::close,this), 748, 556, "TPMAGE1.DEF", SDLK_RETURN);
|
std::bind(&CHallInterface::close,this), 748, 556, "TPMAGE1.DEF", SDLK_RETURN);
|
||||||
|
=======
|
||||||
|
exit = new CButton(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->hcommands[8]), [&]{close();}, SDLK_RETURN);
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||||
exit->assignedKeys.insert(SDLK_ESCAPE);
|
exit->assignedKeys.insert(SDLK_ESCAPE);
|
||||||
|
|
||||||
auto & boxList = town->town->clientInfo.hallSlots;
|
auto & boxList = town->town->clientInfo.hallSlots;
|
||||||
@ -1403,15 +1427,24 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
|
|||||||
|
|
||||||
if(!rightClick)
|
if(!rightClick)
|
||||||
{ //normal window
|
{ //normal window
|
||||||
|
<<<<<<< HEAD:client/CCastleInterface.cpp
|
||||||
buy = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[595]) % building->Name()),
|
buy = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[595]) % building->Name()),
|
||||||
"", std::bind(&CBuildWindow::buyFunc,this), 45, 446,"IBUY30", SDLK_RETURN);
|
"", std::bind(&CBuildWindow::buyFunc,this), 45, 446,"IBUY30", SDLK_RETURN);
|
||||||
buy->borderColor = Colors::METALLIC_GOLD;
|
=======
|
||||||
buy->borderEnabled = true;
|
std::string tooltipYes = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % building->Name());
|
||||||
|
std::string tooltipNo = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % building->Name());
|
||||||
|
|
||||||
|
buy = new CButton(Point(45, 446), "IBUY30", CButton::tooltip(tooltipYes), [&]{ buyFunc(); }, SDLK_RETURN);
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||||
|
buy->borderColor = Colors::METALLIC_GOLD;
|
||||||
|
|
||||||
|
<<<<<<< HEAD:client/CCastleInterface.cpp
|
||||||
cancel = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[596]) % building->Name()),
|
cancel = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[596]) % building->Name()),
|
||||||
"", std::bind(&CBuildWindow::close,this), 290, 445, "ICANCEL", SDLK_ESCAPE);
|
"", std::bind(&CBuildWindow::close,this), 290, 445, "ICANCEL", SDLK_ESCAPE);
|
||||||
|
=======
|
||||||
|
cancel = new CButton(Point(290, 445), "ICANCEL", CButton::tooltip(tooltipNo), [&] { close();}, SDLK_ESCAPE);
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||||
cancel->borderColor = Colors::METALLIC_GOLD;
|
cancel->borderColor = Colors::METALLIC_GOLD;
|
||||||
cancel->borderEnabled = true;
|
|
||||||
buy->block(state!=7 || LOCPLINT->playerID != town->tempOwner);
|
buy->block(state!=7 || LOCPLINT->playerID != town->tempOwner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1441,7 +1474,11 @@ CFortScreen::CFortScreen(const CGTownInstance * town):
|
|||||||
title = new CLabel(400, 12, FONT_BIG, CENTER, Colors::WHITE, fortBuilding->Name());
|
title = new CLabel(400, 12, FONT_BIG, CENTER, Colors::WHITE, fortBuilding->Name());
|
||||||
|
|
||||||
std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->Name());
|
std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->Name());
|
||||||
|
<<<<<<< HEAD:client/CCastleInterface.cpp
|
||||||
exit = new CAdventureMapButton(text, "", std::bind(&CFortScreen::close,this) ,748, 556, "TPMAGE1", SDLK_RETURN);
|
exit = new CAdventureMapButton(text, "", std::bind(&CFortScreen::close,this) ,748, 556, "TPMAGE1", SDLK_RETURN);
|
||||||
|
=======
|
||||||
|
exit = new CButton(Point(748, 556), "TPMAGE1", CButton::tooltip(text), [&]{ close(); }, SDLK_RETURN);
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||||
exit->assignedKeys.insert(SDLK_ESCAPE);
|
exit->assignedKeys.insert(SDLK_ESCAPE);
|
||||||
|
|
||||||
std::vector<Point> positions;
|
std::vector<Point> positions;
|
||||||
@ -1640,7 +1677,6 @@ void CFortScreen::RecruitArea::clickRight(tribool down, bool previousState)
|
|||||||
|
|
||||||
CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem) :CWindowObject(BORDERED,imagem)
|
CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem) :CWindowObject(BORDERED,imagem)
|
||||||
{
|
{
|
||||||
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
|
||||||
window = new CPicture(owner->town->town->clientInfo.guildWindow , 332, 76);
|
window = new CPicture(owner->town->town->clientInfo.guildWindow , 332, 76);
|
||||||
@ -1651,7 +1687,11 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem)
|
|||||||
Rect barRect(7, 556, 737, 18);
|
Rect barRect(7, 556, 737, 18);
|
||||||
statusBar = new CGStatusBar(new CPicture(*background, barRect, 7, 556, false));
|
statusBar = new CGStatusBar(new CPicture(*background, barRect, 7, 556, false));
|
||||||
|
|
||||||
|
<<<<<<< HEAD:client/CCastleInterface.cpp
|
||||||
exit = new CAdventureMapButton(CGI->generaltexth->allTexts[593],"",std::bind(&CMageGuildScreen::close,this), 748, 556,"TPMAGE1.DEF",SDLK_RETURN);
|
exit = new CAdventureMapButton(CGI->generaltexth->allTexts[593],"",std::bind(&CMageGuildScreen::close,this), 748, 556,"TPMAGE1.DEF",SDLK_RETURN);
|
||||||
|
=======
|
||||||
|
exit = new CButton(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->allTexts[593]), [&]{ close(); }, SDLK_RETURN);
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||||
exit->assignedKeys.insert(SDLK_ESCAPE);
|
exit->assignedKeys.insert(SDLK_ESCAPE);
|
||||||
|
|
||||||
std::vector<std::vector<Point> > positions;
|
std::vector<std::vector<Point> > positions;
|
||||||
@ -1728,13 +1768,20 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art
|
|||||||
boost::lexical_cast<std::string>(CGI->arth->artifacts[aid]->price));
|
boost::lexical_cast<std::string>(CGI->arth->artifacts[aid]->price));
|
||||||
|
|
||||||
std::string text = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % creature->nameSing);
|
std::string text = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % creature->nameSing);
|
||||||
|
<<<<<<< HEAD:client/CCastleInterface.cpp
|
||||||
buy = new CAdventureMapButton(text,"",std::bind(&CBlacksmithDialog::close, this), 42, 312,"IBUY30.DEF",SDLK_RETURN);
|
buy = new CAdventureMapButton(text,"",std::bind(&CBlacksmithDialog::close, this), 42, 312,"IBUY30.DEF",SDLK_RETURN);
|
||||||
|
|
||||||
text = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % creature->nameSing);
|
text = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % creature->nameSing);
|
||||||
cancel = new CAdventureMapButton(text,"",std::bind(&CBlacksmithDialog::close, this), 224, 312,"ICANCEL.DEF",SDLK_ESCAPE);
|
cancel = new CAdventureMapButton(text,"",std::bind(&CBlacksmithDialog::close, this), 224, 312,"ICANCEL.DEF",SDLK_ESCAPE);
|
||||||
|
=======
|
||||||
|
buy = new CButton(Point(42, 312), "IBUY30.DEF", CButton::tooltip(text), [&]{ close(); }, SDLK_RETURN);
|
||||||
|
|
||||||
|
text = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % creature->nameSing);
|
||||||
|
cancel = new CButton(Point(224, 312), "ICANCEL.DEF", CButton::tooltip(text), [&]{ close(); }, SDLK_ESCAPE);
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||||
|
|
||||||
if(possible)
|
if(possible)
|
||||||
buy->callback += [=]{ LOCPLINT->cb->buyArtifact(LOCPLINT->cb->getHero(hid),aid); };
|
buy->addCallback([=]{ LOCPLINT->cb->buyArtifact(LOCPLINT->cb->getHero(hid),aid); });
|
||||||
else
|
else
|
||||||
buy->block(true);
|
buy->block(true);
|
||||||
|
|
@ -1,10 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../widgets/CGarrisonInt.h"
|
||||||
|
#include "../widgets/Images.h"
|
||||||
|
|
||||||
#include "CAnimation.h"
|
class CButton;
|
||||||
#include "GUIClasses.h"
|
|
||||||
|
|
||||||
class CAdventureMapButton;
|
|
||||||
class CBuilding;
|
class CBuilding;
|
||||||
class CCastleBuildings;
|
class CCastleBuildings;
|
||||||
class CCreaturePic;
|
class CCreaturePic;
|
||||||
@ -204,8 +203,8 @@ class CCastleInterface : public CWindowObject, public CWindowWithGarrison
|
|||||||
|
|
||||||
CTownInfo *hall, *fort;
|
CTownInfo *hall, *fort;
|
||||||
|
|
||||||
CAdventureMapButton *exit;
|
CButton *exit;
|
||||||
CAdventureMapButton *split;
|
CButton *split;
|
||||||
|
|
||||||
std::vector<CCreaInfo*> creainfo;//small icons of creatures (bottom-left corner);
|
std::vector<CCreaInfo*> creainfo;//small icons of creatures (bottom-left corner);
|
||||||
|
|
||||||
@ -261,7 +260,7 @@ class CHallInterface : public CWindowObject
|
|||||||
CLabel *title;
|
CLabel *title;
|
||||||
CGStatusBar *statusBar;
|
CGStatusBar *statusBar;
|
||||||
CMinorResDataBar * resdatabar;
|
CMinorResDataBar * resdatabar;
|
||||||
CAdventureMapButton *exit;
|
CButton *exit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CHallInterface(const CGTownInstance * Town); //c-tor
|
CHallInterface(const CGTownInstance * Town); //c-tor
|
||||||
@ -273,8 +272,8 @@ class CBuildWindow: public CWindowObject
|
|||||||
const CGTownInstance *town;
|
const CGTownInstance *town;
|
||||||
const CBuilding *building;
|
const CBuilding *building;
|
||||||
|
|
||||||
CAdventureMapButton *buy;
|
CButton *buy;
|
||||||
CAdventureMapButton *cancel;
|
CButton *cancel;
|
||||||
|
|
||||||
std::string getTextForState(int state);
|
std::string getTextForState(int state);
|
||||||
void buyFunc();
|
void buyFunc();
|
||||||
@ -329,7 +328,7 @@ class CFortScreen : public CWindowObject
|
|||||||
std::vector<RecruitArea*> recAreas;
|
std::vector<RecruitArea*> recAreas;
|
||||||
CMinorResDataBar * resdatabar;
|
CMinorResDataBar * resdatabar;
|
||||||
CGStatusBar *statusBar;
|
CGStatusBar *statusBar;
|
||||||
CAdventureMapButton *exit;
|
CButton *exit;
|
||||||
|
|
||||||
std::string getBgName(const CGTownInstance *town);
|
std::string getBgName(const CGTownInstance *town);
|
||||||
|
|
||||||
@ -354,7 +353,7 @@ class CMageGuildScreen : public CWindowObject
|
|||||||
void hover(bool on);
|
void hover(bool on);
|
||||||
};
|
};
|
||||||
CPicture *window;
|
CPicture *window;
|
||||||
CAdventureMapButton *exit;
|
CButton *exit;
|
||||||
std::vector<Scroll *> spells;
|
std::vector<Scroll *> spells;
|
||||||
CMinorResDataBar * resdatabar;
|
CMinorResDataBar * resdatabar;
|
||||||
CGStatusBar *statusBar;
|
CGStatusBar *statusBar;
|
||||||
@ -366,7 +365,7 @@ public:
|
|||||||
/// The blacksmith window where you can buy available in town war machine
|
/// The blacksmith window where you can buy available in town war machine
|
||||||
class CBlacksmithDialog : public CWindowObject
|
class CBlacksmithDialog : public CWindowObject
|
||||||
{
|
{
|
||||||
CAdventureMapButton *buy, *cancel;
|
CButton *buy, *cancel;
|
||||||
CPicture *animBG;
|
CPicture *animBG;
|
||||||
CCreatureAnim * anim;
|
CCreatureAnim * anim;
|
||||||
CLabel * title;
|
CLabel * title;
|
871
client/windows/CCreatureWindow.cpp
Normal file
@ -0,0 +1,871 @@
|
|||||||
|
#include "StdInc.h"
|
||||||
|
#include "CCreatureWindow.h"
|
||||||
|
|
||||||
|
#include "../CGameInfo.h"
|
||||||
|
#include "../CPlayerInterface.h"
|
||||||
|
#include "../widgets/Buttons.h"
|
||||||
|
#include "../widgets/CComponent.h"
|
||||||
|
#include "../widgets/Images.h"
|
||||||
|
#include "../widgets/TextControls.h"
|
||||||
|
#include "../widgets/ObjectLists.h"
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
|
||||||
|
#include "../../CCallback.h"
|
||||||
|
#include "../../lib/BattleState.h"
|
||||||
|
#include "../../lib/CBonusTypeHandler.h"
|
||||||
|
#include "../../lib/CGeneralTextHandler.h"
|
||||||
|
#include "../../lib/CModHandler.h"
|
||||||
|
#include "../../lib/CHeroHandler.h"
|
||||||
|
#include "../../lib/CSpellHandler.h"
|
||||||
|
#include "../../lib/CGameState.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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct StackWindowInfo
|
||||||
|
{
|
||||||
|
// helper structs
|
||||||
|
struct CommanderLevelInfo
|
||||||
|
{
|
||||||
|
std::vector<ui32> skills;
|
||||||
|
std::function<void(ui32)> callback;
|
||||||
|
};
|
||||||
|
struct StackDismissInfo
|
||||||
|
{
|
||||||
|
std::function<void()> callback;
|
||||||
|
};
|
||||||
|
struct StackUpgradeInfo
|
||||||
|
{
|
||||||
|
UpgradeInfo info;
|
||||||
|
std::function<void(CreatureID)> callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
// pointers to permament objects in game state
|
||||||
|
const CCreature * creature;
|
||||||
|
const CCommanderInstance * commander;
|
||||||
|
const CStackInstance * stackNode;
|
||||||
|
const CGHeroInstance * owner;
|
||||||
|
|
||||||
|
// temporary objects which should be kept as copy if needed
|
||||||
|
boost::optional<CommanderLevelInfo> levelupInfo;
|
||||||
|
boost::optional<StackDismissInfo> dismissInfo;
|
||||||
|
boost::optional<StackUpgradeInfo> upgradeInfo;
|
||||||
|
|
||||||
|
// misc fields
|
||||||
|
unsigned int creatureCount;
|
||||||
|
bool popupWindow;
|
||||||
|
|
||||||
|
StackWindowInfo();
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
namespace EStat
|
||||||
|
{
|
||||||
|
enum EStat
|
||||||
|
{
|
||||||
|
ATTACK,
|
||||||
|
DEFENCE,
|
||||||
|
SHOTS,
|
||||||
|
DAMAGE,
|
||||||
|
HEALTH,
|
||||||
|
HEALTH_LEFT,
|
||||||
|
SPEED,
|
||||||
|
MANA
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StackWindowInfo::StackWindowInfo():
|
||||||
|
creature(nullptr),
|
||||||
|
commander(nullptr),
|
||||||
|
stackNode(nullptr),
|
||||||
|
owner(nullptr),
|
||||||
|
creatureCount(0),
|
||||||
|
popupWindow(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::createBackground(std::string path)
|
||||||
|
{
|
||||||
|
background = new CPicture("stackWindow/" + path);
|
||||||
|
pos = background->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::printStatString(int index, std::string name, std::string value)
|
||||||
|
{
|
||||||
|
new CLabel(145, 32 + index*19, FONT_SMALL, TOPLEFT, Colors::WHITE, name);
|
||||||
|
new CLabel(307, 48 + index*19, FONT_SMALL, BOTTOMRIGHT, Colors::WHITE, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::printStatRange(int index, std::string name, int min, int max)
|
||||||
|
{
|
||||||
|
if(min != max)
|
||||||
|
printStatString(index, name, boost::str(boost::format("%d - %d") % min % max));
|
||||||
|
else
|
||||||
|
printStatString(index, name, boost::str(boost::format("%d") % min));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::printStatBase(int index, std::string name, int base, int current)
|
||||||
|
{
|
||||||
|
if(base != current)
|
||||||
|
printStatString(index, name, boost::str(boost::format("%d (%d)") % base % current));
|
||||||
|
else
|
||||||
|
printStatString(index, name, boost::str(boost::format("%d") % base));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::printStat(int index, std::string name, int value)
|
||||||
|
{
|
||||||
|
printStatBase(index, name, value, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CStackWindow::generateStackExpDescription()
|
||||||
|
{
|
||||||
|
const CStackInstance * stack = info->stackNode;
|
||||||
|
const CCreature * creature = info->creature;
|
||||||
|
|
||||||
|
int tier = stack->type->level;
|
||||||
|
int rank = stack->getExpRank();
|
||||||
|
if (!vstd::iswithin(tier, 1, 7))
|
||||||
|
tier = 0;
|
||||||
|
int number;
|
||||||
|
std::string expText = CGI->generaltexth->zcrexp[325];
|
||||||
|
boost::replace_first (expText, "%s", creature->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
|
||||||
|
|
||||||
|
return expText;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::removeStackArtifact(ArtifactPosition pos)
|
||||||
|
{
|
||||||
|
auto art = info->stackNode->getArt(ArtifactPosition::CREATURE_SLOT);
|
||||||
|
LOCPLINT->cb->swapArtifacts(ArtifactLocation(info->stackNode, pos),
|
||||||
|
ArtifactLocation(info->owner, art->firstBackpackSlot(info->owner)));
|
||||||
|
delete stackArtifactButton;
|
||||||
|
delete stackArtifactHelp;
|
||||||
|
delete stackArtifactIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::setStackArtifact(const CArtifactInstance * art, Point artPos)
|
||||||
|
{
|
||||||
|
if (art)
|
||||||
|
{
|
||||||
|
stackArtifactIcon = new CAnimImage("ARTIFACT", art->artType->iconIndex, 0, pos.x, pos.y);
|
||||||
|
stackArtifactHelp = new LRClickableAreaWTextComp(Rect(artPos, Point(44, 44)), CComponent::artifact);
|
||||||
|
stackArtifactHelp->type = art->artType->id;
|
||||||
|
|
||||||
|
const JsonNode & text = VLC->generaltexth->localizedTexts["creatureWindow"]["returnArtifact"];
|
||||||
|
|
||||||
|
if (info->owner)
|
||||||
|
{
|
||||||
|
stackArtifactButton = new CButton(Point(artPos.x - 2 , artPos.y + 46), "stackWindow/cancelButton",
|
||||||
|
CButton::tooltip(text),
|
||||||
|
[=]{ removeStackArtifact(ArtifactPosition::CREATURE_SLOT); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::createStackInfo(bool showExp, bool showArt)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
if (showExp && showArt)
|
||||||
|
createBackground("info-panel-2");
|
||||||
|
else if (showExp || showArt)
|
||||||
|
createBackground("info-panel-1");
|
||||||
|
else
|
||||||
|
createBackground("info-panel-0");
|
||||||
|
|
||||||
|
new CCreaturePic(5, 41, parent->info->creature);
|
||||||
|
|
||||||
|
std::string visibleName;
|
||||||
|
if (parent->info->commander != nullptr)
|
||||||
|
visibleName = parent->info->commander->type->nameSing;
|
||||||
|
else
|
||||||
|
visibleName = parent->info->creature->namePl;
|
||||||
|
new CLabel(215, 12, FONT_SMALL, CENTER, Colors::YELLOW, visibleName);
|
||||||
|
|
||||||
|
int dmgMultiply = 1;
|
||||||
|
if(parent->info->owner && parent->info->stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
||||||
|
dmgMultiply += parent->info->owner->Attack();
|
||||||
|
|
||||||
|
new CPicture("stackWindow/icons", 117, 32);
|
||||||
|
printStatBase(EStat::ATTACK, CGI->generaltexth->primarySkillNames[0], parent->info->creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), parent->info->stackNode->Attack());
|
||||||
|
printStatBase(EStat::DEFENCE, CGI->generaltexth->primarySkillNames[1], parent->info->creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), parent->info->stackNode->Defense());
|
||||||
|
printStatRange(EStat::DAMAGE, CGI->generaltexth->allTexts[199], parent->info->stackNode->getMinDamage() * dmgMultiply, parent->info->stackNode->getMaxDamage() * dmgMultiply);
|
||||||
|
printStatBase(EStat::HEALTH, CGI->generaltexth->allTexts[388], parent->info->creature->valOfBonuses(Bonus::STACK_HEALTH), parent->info->stackNode->valOfBonuses(Bonus::STACK_HEALTH));
|
||||||
|
printStatBase(EStat::SPEED, CGI->generaltexth->zelp[441].first, parent->info->creature->Speed(), parent->info->stackNode->Speed());
|
||||||
|
|
||||||
|
const CStack * battleStack = dynamic_cast<const CStack*>(parent->info->stackNode);
|
||||||
|
bool shooter = parent->info->stackNode->hasBonusOfType(Bonus::SHOOTER) && parent->info->stackNode->valOfBonuses(Bonus::SHOTS);
|
||||||
|
bool caster = parent->info->stackNode->valOfBonuses(Bonus::CASTS);
|
||||||
|
|
||||||
|
if (battleStack != nullptr) // in battle
|
||||||
|
{
|
||||||
|
if (shooter)
|
||||||
|
printStatBase(EStat::SHOTS, CGI->generaltexth->allTexts[198], battleStack->valOfBonuses(Bonus::SHOTS), battleStack->shots);
|
||||||
|
if (caster)
|
||||||
|
printStatBase(EStat::MANA, CGI->generaltexth->allTexts[399], battleStack->valOfBonuses(Bonus::CASTS), battleStack->casts);
|
||||||
|
printStat(EStat::HEALTH_LEFT, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (shooter)
|
||||||
|
printStat(EStat::SHOTS, CGI->generaltexth->allTexts[198], parent->info->stackNode->valOfBonuses(Bonus::SHOTS));
|
||||||
|
if (caster)
|
||||||
|
printStat(EStat::MANA, CGI->generaltexth->allTexts[399], parent->info->stackNode->valOfBonuses(Bonus::CASTS));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto morale = new MoraleLuckBox(true, genRect(42, 42, 321, 110));
|
||||||
|
morale->set(parent->info->stackNode);
|
||||||
|
auto luck = new MoraleLuckBox(false, genRect(42, 42, 375, 110));
|
||||||
|
luck->set(parent->info->stackNode);
|
||||||
|
|
||||||
|
if (showArt)
|
||||||
|
{
|
||||||
|
Point pos = showExp ? Point(375, 32) : Point(347, 32);
|
||||||
|
parent->setStackArtifact(parent->info->stackNode->getArt(ArtifactPosition::CREATURE_SLOT), pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showExp)
|
||||||
|
{
|
||||||
|
const CStackInstance * stack = parent->info->stackNode;
|
||||||
|
Point pos = showArt ? Point(321, 32) : Point(347, 32);
|
||||||
|
if (parent->info->commander)
|
||||||
|
{
|
||||||
|
const CCommanderInstance * commander = parent->info->commander;
|
||||||
|
new CAnimImage("PSKIL42", 4, 0, pos.x, pos.y); // experience icon
|
||||||
|
|
||||||
|
auto expArea = new LRClickableAreaWTextComp(Rect(pos.x, pos.y, 44, 44), CComponent::experience);
|
||||||
|
expArea->text = CGI->generaltexth->allTexts[2];
|
||||||
|
expArea->bonusValue = commander->getExpRank();
|
||||||
|
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(commander->getExpRank()));
|
||||||
|
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(CGI->heroh->reqExp(commander->getExpRank()+1)));
|
||||||
|
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(commander->experience));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new CAnimImage("stackWindow/levels", stack->getExpRank(), 0, pos.x, pos.y);
|
||||||
|
auto expArea = new LRClickableAreaWText(Rect(pos.x, pos.y, 44, 44));
|
||||||
|
expArea->text = parent->generateStackExpDescription();
|
||||||
|
}
|
||||||
|
new CLabel(pos.x + 21, pos.y + 52, FONT_SMALL, CENTER, Colors::WHITE, makeNumberShort<TExpType>(stack->experience, 6));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::createActiveSpells()
|
||||||
|
{
|
||||||
|
static const Point firstPos(7 ,4); // position of 1st spell box
|
||||||
|
static const Point offset(54, 0); // offset of each spell box from previous
|
||||||
|
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
createBackground("spell-effects");
|
||||||
|
|
||||||
|
const CStack * battleStack = dynamic_cast<const CStack*>(parent->info->stackNode);
|
||||||
|
|
||||||
|
assert(battleStack); // Section should be created only for battles
|
||||||
|
|
||||||
|
//spell effects
|
||||||
|
int printed=0; //how many effect pics have been printed
|
||||||
|
std::vector<si32> spells = battleStack->activeSpells();
|
||||||
|
for(si32 effect : spells)
|
||||||
|
{
|
||||||
|
std::string spellText;
|
||||||
|
if (effect < 77) //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", effect + 1, 0, firstPos.x + offset.x * printed, firstPos.x + offset.y * printed);
|
||||||
|
new LRClickableAreaWText(Rect(firstPos + offset * printed, Point(50, 38)), spellText, spellText);
|
||||||
|
if (++printed >= 8) // interface limit reached
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::createCommanderSection()
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
auto onCreate = [=](size_t index) -> CIntObject *
|
||||||
|
{
|
||||||
|
return parent->switchTab(index);
|
||||||
|
};
|
||||||
|
auto onDestroy = [=](CIntObject * obj)
|
||||||
|
{
|
||||||
|
delete obj;
|
||||||
|
};
|
||||||
|
parent->commanderTab = new CTabbedInt(onCreate, onDestroy, Point(0,0), 0);
|
||||||
|
pos.w = parent->pos.w;
|
||||||
|
pos.h = 177; // height of commander info
|
||||||
|
if (parent->info->levelupInfo)
|
||||||
|
pos.h += 59; // height of abilities selection
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string skillToFile (int skill, int level, bool selected)
|
||||||
|
{
|
||||||
|
// FIXME: is this a correct hadling?
|
||||||
|
// level 0 = skill not present, use image with "no" suffix
|
||||||
|
// level 1-5 = skill available, mapped to images indexed as 0-4
|
||||||
|
// selecting skill means that it will appear one level higher (as if alredy upgraded)
|
||||||
|
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;
|
||||||
|
if (selected)
|
||||||
|
level++; // UI will display resulting level
|
||||||
|
if (level == 0)
|
||||||
|
sufix = "no"; //not avaliable - no number
|
||||||
|
else
|
||||||
|
sufix = boost::lexical_cast<std::string>(level-1);
|
||||||
|
if (selected)
|
||||||
|
sufix += "="; //level-up highlight
|
||||||
|
|
||||||
|
return file + sufix + ".bmp";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::createCommander()
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
createBackground("commander-bg");
|
||||||
|
|
||||||
|
auto getSkillPos = [&](int index)
|
||||||
|
{
|
||||||
|
return Point(10 + 80 * (index%3), 20 + 80 * (index/3));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto getSkillImage = [this](int skillIndex) -> std::string
|
||||||
|
{
|
||||||
|
bool selected = ((parent->selectedSkill == skillIndex) && parent->info->levelupInfo );
|
||||||
|
return skillToFile(skillIndex, parent->info->commander->secondarySkills[skillIndex], selected);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int index = ECommander::ATTACK; index <= ECommander::SPELL_POWER; ++index)
|
||||||
|
{
|
||||||
|
Point skillPos = getSkillPos(index);
|
||||||
|
|
||||||
|
auto icon = new CClickableObject(new CPicture(getSkillImage(index), skillPos.x, skillPos.y), [=]{});
|
||||||
|
|
||||||
|
if (parent->selectedSkill == index)
|
||||||
|
parent->selectedIcon = icon;
|
||||||
|
|
||||||
|
if (parent->info->levelupInfo && vstd::contains(parent->info->levelupInfo->skills, index)) // can be upgraded - enable selection switch
|
||||||
|
{
|
||||||
|
icon->callback = [=]
|
||||||
|
{
|
||||||
|
parent->setSelection(index, icon);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: commander artifacts
|
||||||
|
}
|
||||||
|
|
||||||
|
CIntObject * CStackWindow::createSkillEntry(int index)
|
||||||
|
{
|
||||||
|
for (auto skillID : info->levelupInfo->skills)
|
||||||
|
{
|
||||||
|
if (index == 0 && skillID >= 100)
|
||||||
|
{
|
||||||
|
const Bonus *bonus = CGI->creh->skillRequirements[skillID-100].first;
|
||||||
|
const CStackInstance *stack = info->commander;
|
||||||
|
CClickableObject * icon = new CClickableObject(new CPicture(stack->bonusToGraphics(bonus)), []{});
|
||||||
|
icon->callback = [=]
|
||||||
|
{
|
||||||
|
setSelection(skillID, icon);
|
||||||
|
};
|
||||||
|
icon->text = stack->bonusToString(bonus, true);
|
||||||
|
icon->hoverText = stack->bonusToString(bonus, false);
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
if (skillID >= 100)
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::createCommanderAbilities()
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
|
||||||
|
auto bg2 = new CPicture("stackWindow/commander-abilities.png");
|
||||||
|
bg2->moveBy(Point(0, pos.h));
|
||||||
|
size_t abilitiesCount = boost::range::count_if(parent->info->levelupInfo->skills, [](ui32 skillID)
|
||||||
|
{
|
||||||
|
return skillID >= 100;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto list = new CListBox([=] (int index)
|
||||||
|
{
|
||||||
|
return parent->createSkillEntry(index);
|
||||||
|
},
|
||||||
|
[=] (CIntObject * elem)
|
||||||
|
{
|
||||||
|
delete elem;
|
||||||
|
},
|
||||||
|
Point(38, 3+pos.h), Point(63, 0), 6, abilitiesCount);
|
||||||
|
|
||||||
|
auto leftBtn = new CButton(Point(10, pos.h + 6), "hsbtns3.def", CButton::tooltip(), [=]{ list->moveToPrev(); }, SDLK_LEFT);
|
||||||
|
auto rightBtn = new CButton(Point(411, pos.h + 6), "hsbtns5.def", CButton::tooltip(), [=]{ list->moveToNext(); }, SDLK_RIGHT);
|
||||||
|
|
||||||
|
if (abilitiesCount <= 6)
|
||||||
|
{
|
||||||
|
leftBtn->block(true);
|
||||||
|
rightBtn->block(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::setSelection(si32 newSkill, CClickableObject * newIcon)
|
||||||
|
{
|
||||||
|
auto getSkillImage = [this](int skillIndex) -> std::string
|
||||||
|
{
|
||||||
|
bool selected = ((selectedSkill == skillIndex) && info->levelupInfo );
|
||||||
|
return skillToFile(skillIndex, info->commander->secondarySkills[skillIndex], selected);
|
||||||
|
};
|
||||||
|
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
int oldSelection = selectedSkill; // update selection
|
||||||
|
selectedSkill = newSkill;
|
||||||
|
|
||||||
|
if (selectedIcon && oldSelection < 100) // recreate image on old selection, only for skills
|
||||||
|
selectedIcon->setObject(new CPicture(getSkillImage(oldSelection)));
|
||||||
|
|
||||||
|
selectedIcon = newIcon; // update new selection
|
||||||
|
if (newSkill < 100)
|
||||||
|
newIcon->setObject(new CPicture(getSkillImage(newSkill)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::createBonuses(boost::optional<size_t> preferredSize)
|
||||||
|
{
|
||||||
|
// size of single image for an item
|
||||||
|
static const int itemHeight = 59;
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
size_t totalSize = (parent->activeBonuses.size() + 1) / 2;
|
||||||
|
size_t visibleSize = preferredSize ? preferredSize.get() : std::min<size_t>(3, totalSize);
|
||||||
|
|
||||||
|
pos.w = parent->pos.w;
|
||||||
|
pos.h = itemHeight * visibleSize;
|
||||||
|
|
||||||
|
auto onCreate = [=](size_t index) -> CIntObject *
|
||||||
|
{
|
||||||
|
return parent->createBonusEntry(index);
|
||||||
|
};
|
||||||
|
auto onDestroy = [=](CIntObject * obj)
|
||||||
|
{
|
||||||
|
delete obj;
|
||||||
|
};
|
||||||
|
new CListBox(onCreate, onDestroy, Point(0, 0), Point(0, itemHeight), visibleSize, totalSize, 0, 1, Rect(pos.w - 15, 0, pos.h, pos.h));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::createButtonPanel()
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
createBackground("button-panel");
|
||||||
|
|
||||||
|
if (parent->info->dismissInfo)
|
||||||
|
{
|
||||||
|
auto onDismiss = [=]()
|
||||||
|
{
|
||||||
|
parent->info->dismissInfo->callback();
|
||||||
|
parent->close();
|
||||||
|
};
|
||||||
|
auto onClick = [=] ()
|
||||||
|
{
|
||||||
|
LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[12], onDismiss, 0, false, std::vector<CComponent*>());
|
||||||
|
};
|
||||||
|
new CButton(Point(5, 5),"IVIEWCR2.DEF", CGI->generaltexth->zelp[445], onClick, SDLK_d);
|
||||||
|
}
|
||||||
|
if (parent->info->upgradeInfo)
|
||||||
|
{
|
||||||
|
// used space overlaps with commander switch button
|
||||||
|
// besides - should commander really be upgradeable?
|
||||||
|
assert(!parent->info->commander);
|
||||||
|
|
||||||
|
StackWindowInfo::StackUpgradeInfo & upgradeInfo = parent->info->upgradeInfo.get();
|
||||||
|
size_t buttonsToCreate = std::min<size_t>(upgradeInfo.info.newID.size(), 3); // no more than 3 windows on UI - space limit
|
||||||
|
|
||||||
|
for (size_t i=0; i<buttonsToCreate; i++)
|
||||||
|
{
|
||||||
|
TResources totalCost = upgradeInfo.info.cost[i] * parent->info->creatureCount;
|
||||||
|
|
||||||
|
auto onUpgrade = [=]()
|
||||||
|
{
|
||||||
|
upgradeInfo.callback(upgradeInfo.info.newID[i]);
|
||||||
|
parent->close();
|
||||||
|
};
|
||||||
|
auto onClick = [=]()
|
||||||
|
{
|
||||||
|
std::vector<CComponent*> resComps;
|
||||||
|
for(TResources::nziterator i(totalCost); i.valid(); i++)
|
||||||
|
{
|
||||||
|
resComps.push_back(new CComponent(CComponent::resource, i->resType, i->resVal));
|
||||||
|
}
|
||||||
|
LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[207], onUpgrade, nullptr, true, resComps);
|
||||||
|
};
|
||||||
|
auto upgradeBtn = new CButton(Point(221 + i * 40, 5), "stackWindow/upgradeButton", CGI->generaltexth->zelp[446], onClick, SDLK_1);
|
||||||
|
|
||||||
|
upgradeBtn->addOverlay(new CAnimImage("CPRSMALL", VLC->creh->creatures[upgradeInfo.info.newID[i]]->iconIndex));
|
||||||
|
|
||||||
|
if (!LOCPLINT->cb->getResourceAmount().canAfford(totalCost))
|
||||||
|
upgradeBtn->block(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->info->commander)
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
std::string btnIDs[2] = { "showSkills", "showBonuses" };
|
||||||
|
auto onSwitch = [&, i]()
|
||||||
|
{
|
||||||
|
parent->switchButtons[parent->activeTab]->enable();
|
||||||
|
parent->commanderTab->setActive(i);
|
||||||
|
parent->switchButtons[i]->disable();
|
||||||
|
parent->redraw(); // FIXME: enable/disable don't redraw screen themselves
|
||||||
|
};
|
||||||
|
|
||||||
|
const JsonNode & text = VLC->generaltexth->localizedTexts["creatureWindow"][btnIDs[i]];
|
||||||
|
parent->switchButtons[i] = new CButton(Point(302 + i*40, 5), "stackWindow/upgradeButton", CButton::tooltip(text), onSwitch);
|
||||||
|
parent->switchButtons[i]->addOverlay(new CAnimImage("stackWindow/switchModeIcons", i));
|
||||||
|
}
|
||||||
|
parent->switchButtons[parent->activeTab]->disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto exitBtn = new CButton(Point(382, 5), "hsbtns.def", CGI->generaltexth->zelp[445], [=]{ parent->close(); }, SDLK_RETURN);
|
||||||
|
exitBtn->assignedKeys.insert(SDLK_ESCAPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
CStackWindow::CWindowSection::CWindowSection(CStackWindow * parent):
|
||||||
|
parent(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CClickableObject::CClickableObject(CIntObject *object, std::function<void()> callback):
|
||||||
|
object(nullptr),
|
||||||
|
callback(callback)
|
||||||
|
{
|
||||||
|
pos = object->pos;
|
||||||
|
setObject(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CClickableObject::setObject(CIntObject *newObject)
|
||||||
|
{
|
||||||
|
delete object;
|
||||||
|
object = newObject;
|
||||||
|
addChild(object);
|
||||||
|
object->moveTo(pos.topLeft());
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CClickableObject::clickLeft(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if (down)
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
CIntObject * CStackWindow::createBonusEntry(size_t index)
|
||||||
|
{
|
||||||
|
auto section = new CWindowSection(this);
|
||||||
|
section->createBonusEntry(index);
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::createBonusEntry(size_t index)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
createBackground("bonus-effects");
|
||||||
|
createBonusItem(index * 2, Point(6, 4));
|
||||||
|
createBonusItem(index * 2 + 1, Point(214, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::CWindowSection::createBonusItem(size_t index, Point position)
|
||||||
|
{
|
||||||
|
if (parent->activeBonuses.size() > index)
|
||||||
|
{
|
||||||
|
BonusInfo & bi = parent->activeBonuses[index];
|
||||||
|
new CPicture(bi.imagePath, position.x, position.y);
|
||||||
|
new CLabel(position.x + 60, position.y + 2, FONT_SMALL, TOPLEFT, Colors::WHITE, bi.name);
|
||||||
|
new CLabel(position.x + 60, position.y + 25, FONT_SMALL, TOPLEFT, Colors::WHITE, bi.description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CIntObject * CStackWindow::switchTab(size_t index)
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
activeTab = 0;
|
||||||
|
auto ret = new CWindowSection(this);
|
||||||
|
ret->createCommander();
|
||||||
|
if (info->levelupInfo)
|
||||||
|
ret->createCommanderAbilities();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
activeTab = 1;
|
||||||
|
auto ret = new CWindowSection(this);
|
||||||
|
if (info->levelupInfo)
|
||||||
|
ret->createBonuses(4);
|
||||||
|
else
|
||||||
|
ret->createBonuses(3);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::initSections()
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
|
CWindowSection * currentSection;
|
||||||
|
|
||||||
|
bool showArt = CGI->modh->modules.STACK_ARTIFACT && info->commander == nullptr && info->stackNode;
|
||||||
|
bool showExp = (CGI->modh->modules.STACK_EXP || info->commander != nullptr) && info->stackNode;
|
||||||
|
currentSection = new CWindowSection(this);
|
||||||
|
currentSection->createStackInfo(showExp, showArt);
|
||||||
|
pos.w = currentSection->pos.w;
|
||||||
|
pos.h += currentSection->pos.h;
|
||||||
|
|
||||||
|
if (dynamic_cast<const CStack*>(info->stackNode)) // in battle
|
||||||
|
{
|
||||||
|
currentSection = new CWindowSection(this);
|
||||||
|
currentSection->pos.y += pos.h;
|
||||||
|
currentSection->createActiveSpells();
|
||||||
|
pos.h += currentSection->pos.h;
|
||||||
|
}
|
||||||
|
if (info->commander)
|
||||||
|
{
|
||||||
|
currentSection = new CWindowSection(this);
|
||||||
|
currentSection->pos.y += pos.h;
|
||||||
|
currentSection->createCommanderSection();
|
||||||
|
pos.h += currentSection->pos.h;
|
||||||
|
}
|
||||||
|
if (!info->commander && !activeBonuses.empty())
|
||||||
|
{
|
||||||
|
currentSection = new CWindowSection(this);
|
||||||
|
currentSection->pos.y += pos.h;
|
||||||
|
currentSection->createBonuses();
|
||||||
|
pos.h += currentSection->pos.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info->popupWindow)
|
||||||
|
{
|
||||||
|
currentSection = new CWindowSection(this);
|
||||||
|
currentSection->pos.y += pos.h;
|
||||||
|
currentSection->createButtonPanel();
|
||||||
|
pos.h += currentSection->pos.h;
|
||||||
|
//FIXME: add status bar to image?
|
||||||
|
}
|
||||||
|
updateShadow();
|
||||||
|
pos = center(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::initBonusesList()
|
||||||
|
{
|
||||||
|
BonusList output, input;
|
||||||
|
input = *(info->stackNode->getBonuses(Selector::durationType(Bonus::PERMANENT).And(Selector::anyRange())));
|
||||||
|
|
||||||
|
while (!input.empty())
|
||||||
|
{
|
||||||
|
Bonus * b = input.front();
|
||||||
|
|
||||||
|
output.push_back(new Bonus(*b));
|
||||||
|
output.back()->val = input.valOfBonuses(Selector::typeSubtype(b->type, b->subtype)); //merge multiple bonuses into one
|
||||||
|
input.remove_if (Selector::typeSubtype(b->type, b->subtype)); //remove used bonuses
|
||||||
|
}
|
||||||
|
|
||||||
|
BonusInfo bonusInfo;
|
||||||
|
for(Bonus* b : output)
|
||||||
|
{
|
||||||
|
bonusInfo.name = info->stackNode->bonusToString(b, false);
|
||||||
|
bonusInfo.imagePath = info->stackNode->bonusToGraphics(b);
|
||||||
|
|
||||||
|
//if it's possible to give any description or image for this kind of bonus
|
||||||
|
//TODO: figure out why half of bonuses don't have proper description
|
||||||
|
if (!bonusInfo.name.empty() || !bonusInfo.imagePath.empty())
|
||||||
|
activeBonuses.push_back(bonusInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
//handle Magic resistance separately :/
|
||||||
|
int magicResistance = info->stackNode->magicResistance();
|
||||||
|
|
||||||
|
if (magicResistance)
|
||||||
|
{
|
||||||
|
BonusInfo bonusInfo;
|
||||||
|
Bonus b;
|
||||||
|
b.type = Bonus::MAGIC_RESISTANCE;
|
||||||
|
|
||||||
|
bonusInfo.name = VLC->getBth()->bonusToString(&b, info->stackNode, false);
|
||||||
|
bonusInfo.description = VLC->getBth()->bonusToString(&b, info->stackNode, true);
|
||||||
|
bonusInfo.imagePath = info->stackNode->bonusToGraphics(&b);
|
||||||
|
activeBonuses.push_back(bonusInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStackWindow::init()
|
||||||
|
{
|
||||||
|
stackArtifactHelp = nullptr;
|
||||||
|
stackArtifactIcon = nullptr;
|
||||||
|
stackArtifactButton = nullptr;
|
||||||
|
|
||||||
|
selectedIcon = nullptr;
|
||||||
|
selectedSkill = 0;
|
||||||
|
if (info->levelupInfo)
|
||||||
|
{
|
||||||
|
selectedSkill = info->levelupInfo->skills.front();
|
||||||
|
logGlobal->debugStream() << "Received commander level-up. Possible options are: ";
|
||||||
|
for (auto skill : info->levelupInfo->skills)
|
||||||
|
logGlobal->debugStream() << "Skill #" << skill;
|
||||||
|
}
|
||||||
|
|
||||||
|
commanderTab = nullptr;
|
||||||
|
activeTab = 0;
|
||||||
|
|
||||||
|
initBonusesList();
|
||||||
|
initSections();
|
||||||
|
}
|
||||||
|
|
||||||
|
CStackWindow::CStackWindow(const CStack * stack, bool popup):
|
||||||
|
CWindowObject(BORDERED | (popup ? RCLICK_POPUP : 0))
|
||||||
|
{
|
||||||
|
info->stackNode = stack->base;
|
||||||
|
info->creature = stack->type;
|
||||||
|
info->creatureCount = stack->count;
|
||||||
|
info->popupWindow = popup;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CStackWindow::CStackWindow(const CCreature * creature, bool popup):
|
||||||
|
CWindowObject(BORDERED | (popup ? RCLICK_POPUP : 0)),
|
||||||
|
info(new StackWindowInfo())
|
||||||
|
{
|
||||||
|
info->stackNode = new CStackInstance(creature, 1); // FIXME: free data
|
||||||
|
info->creature = creature;
|
||||||
|
info->popupWindow = popup;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CStackWindow::CStackWindow(const CStackInstance * stack, bool popup):
|
||||||
|
CWindowObject(BORDERED | (popup ? RCLICK_POPUP : 0)),
|
||||||
|
info(new StackWindowInfo())
|
||||||
|
{
|
||||||
|
info->stackNode = stack;
|
||||||
|
info->creature = stack->type;
|
||||||
|
info->creatureCount = stack->count;
|
||||||
|
info->popupWindow = popup;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CStackWindow::CStackWindow(const CStackInstance * stack, std::function<void()> dismiss, const UpgradeInfo & upgradeInfo, std::function<void(CreatureID)> callback):
|
||||||
|
CWindowObject(BORDERED),
|
||||||
|
info(new StackWindowInfo())
|
||||||
|
{
|
||||||
|
info->stackNode = stack;
|
||||||
|
info->creature = stack->type;
|
||||||
|
info->creatureCount = stack->count;
|
||||||
|
|
||||||
|
info->upgradeInfo = StackWindowInfo::StackUpgradeInfo();
|
||||||
|
info->dismissInfo = StackWindowInfo::StackDismissInfo();
|
||||||
|
info->upgradeInfo->info = upgradeInfo;
|
||||||
|
info->upgradeInfo->callback = callback;
|
||||||
|
info->dismissInfo->callback = dismiss;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CStackWindow::CStackWindow(const CCommanderInstance * commander, bool popup):
|
||||||
|
CWindowObject(BORDERED | (popup ? RCLICK_POPUP : 0)),
|
||||||
|
info(new StackWindowInfo())
|
||||||
|
{
|
||||||
|
info->stackNode = commander;
|
||||||
|
info->creature = commander->type;
|
||||||
|
info->commander = commander;
|
||||||
|
info->creatureCount = 1;
|
||||||
|
info->popupWindow = popup;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CStackWindow::CStackWindow(const CCommanderInstance * commander, std::vector<ui32> &skills, std::function<void(ui32)> callback):
|
||||||
|
CWindowObject(BORDERED),
|
||||||
|
info(new StackWindowInfo())
|
||||||
|
{
|
||||||
|
info->stackNode = commander;
|
||||||
|
info->creature = commander->type;
|
||||||
|
info->commander = commander;
|
||||||
|
info->creatureCount = 1;
|
||||||
|
info->levelupInfo = StackWindowInfo::CommanderLevelInfo();
|
||||||
|
info->levelupInfo->skills = skills;
|
||||||
|
info->levelupInfo->callback = callback;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CStackWindow::~CStackWindow()
|
||||||
|
{
|
||||||
|
if (info->levelupInfo)
|
||||||
|
{
|
||||||
|
logGlobal->debugStream() << "Selected skill was " << selectedSkill;
|
||||||
|
info->levelupInfo->callback(vstd::find_pos(info->levelupInfo->skills, selectedSkill));
|
||||||
|
}
|
||||||
|
}
|
120
client/windows/CCreatureWindow.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../lib/HeroBonus.h"
|
||||||
|
#include "../widgets/MiscWidgets.h"
|
||||||
|
#include "CWindowObject.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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class StackWindowInfo;
|
||||||
|
class CCommanderInstance;
|
||||||
|
class CStackInstance;
|
||||||
|
class CStack;
|
||||||
|
struct UpgradeInfo;
|
||||||
|
class CTabbedInt;
|
||||||
|
class CButton;
|
||||||
|
|
||||||
|
class CClickableObject : public LRClickableAreaWText
|
||||||
|
{
|
||||||
|
CIntObject * object; // passive object that will be used to determine clickable area
|
||||||
|
public:
|
||||||
|
CClickableObject(CIntObject * object, std::function<void()> callback);
|
||||||
|
|
||||||
|
std::function<void()> callback; //TODO: create more generic clickable class than AdvMapButton?
|
||||||
|
|
||||||
|
void clickLeft(tribool down, bool previousState) override;
|
||||||
|
//void clickRight(tribool down, bool previousState){};
|
||||||
|
|
||||||
|
void setObject(CIntObject * object);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CStackWindow : public CWindowObject
|
||||||
|
{
|
||||||
|
struct BonusInfo
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::string description;
|
||||||
|
std::string imagePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CWindowSection : public CIntObject
|
||||||
|
{
|
||||||
|
CStackWindow * parent;
|
||||||
|
|
||||||
|
CPicture * background;
|
||||||
|
|
||||||
|
void createBackground(std::string path);
|
||||||
|
void createBonusItem(size_t index, Point position);
|
||||||
|
|
||||||
|
void printStatString(int index, std::string name, std::string value);
|
||||||
|
void printStatRange(int index, std::string name, int min, int max);
|
||||||
|
void printStatBase(int index, std::string name, int base, int current);
|
||||||
|
void printStat(int index, std::string name, int value);
|
||||||
|
public:
|
||||||
|
void createStackInfo(bool showExp, bool showArt);
|
||||||
|
void createActiveSpells();
|
||||||
|
void createCommanderSection();
|
||||||
|
void createCommander();
|
||||||
|
void createCommanderAbilities();
|
||||||
|
void createBonuses(boost::optional<size_t> size = boost::optional<size_t>());
|
||||||
|
void createBonusEntry(size_t index);
|
||||||
|
void createButtonPanel();
|
||||||
|
|
||||||
|
CWindowSection(CStackWindow * parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
CAnimImage * stackArtifactIcon;
|
||||||
|
LRClickableAreaWTextComp * stackArtifactHelp;
|
||||||
|
CButton * stackArtifactButton;
|
||||||
|
|
||||||
|
std::unique_ptr<StackWindowInfo> info;
|
||||||
|
std::vector<BonusInfo> activeBonuses;
|
||||||
|
size_t activeTab;
|
||||||
|
CTabbedInt * commanderTab;
|
||||||
|
|
||||||
|
std::map<int, CButton *> switchButtons;
|
||||||
|
|
||||||
|
void setSelection(si32 newSkill, CClickableObject * newIcon);
|
||||||
|
CClickableObject * selectedIcon;
|
||||||
|
si32 selectedSkill;
|
||||||
|
|
||||||
|
CIntObject * createBonusEntry(size_t index);
|
||||||
|
CIntObject * switchTab(size_t index);
|
||||||
|
|
||||||
|
void removeStackArtifact(ArtifactPosition pos);
|
||||||
|
void setStackArtifact(const CArtifactInstance * art, Point artPos);
|
||||||
|
|
||||||
|
void initSections();
|
||||||
|
void initBonusesList();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
std::string generateStackExpDescription();
|
||||||
|
|
||||||
|
CIntObject * createSkillEntry(int index);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// for battles
|
||||||
|
CStackWindow(const CStack * stack, bool popup);
|
||||||
|
|
||||||
|
// for non-existing stacks, e.g. recruit screen
|
||||||
|
CStackWindow(const CCreature * creature, bool popup);
|
||||||
|
|
||||||
|
// for normal stacks in armies
|
||||||
|
CStackWindow(const CStackInstance * stack, bool popup);
|
||||||
|
CStackWindow(const CStackInstance * stack, std::function<void()> dismiss, const UpgradeInfo & info, std::function<void(CreatureID)> callback);
|
||||||
|
|
||||||
|
// for commanders & commander level-up dialog
|
||||||
|
CStackWindow(const CCommanderInstance * commander, bool popup);
|
||||||
|
CStackWindow(const CCommanderInstance * commander, std::vector<ui32> &skills, std::function<void(ui32)> callback);
|
||||||
|
|
||||||
|
~CStackWindow();
|
||||||
|
};
|
@ -1,34 +1,34 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
|
|
||||||
#include "CAnimation.h"
|
|
||||||
#include "CAdvmapInterface.h"
|
|
||||||
#include "../CCallback.h"
|
|
||||||
#include "CGameInfo.h"
|
|
||||||
#include "CHeroWindow.h"
|
#include "CHeroWindow.h"
|
||||||
#include "CMessage.h"
|
|
||||||
#include "CKingdomInterface.h"
|
#include "CAdvmapInterface.h"
|
||||||
#include "CCreatureWindow.h"
|
#include "CCreatureWindow.h"
|
||||||
#include "SDL.h"
|
#include "CKingdomInterface.h"
|
||||||
#include "gui/SDL_Extensions.h"
|
|
||||||
#include "CBitmapHandler.h"
|
|
||||||
#include "Graphics.h"
|
|
||||||
#include "CSpellWindow.h"
|
#include "CSpellWindow.h"
|
||||||
#include "../lib/CConfigHandler.h"
|
#include "GUIClasses.h"
|
||||||
#include "CPlayerInterface.h"
|
|
||||||
|
#include "../CBitmapHandler.h"
|
||||||
|
#include "../CDefHandler.h"
|
||||||
|
#include "../CGameInfo.h"
|
||||||
|
#include "../CMessage.h"
|
||||||
|
#include "../CMT.h"
|
||||||
|
#include "../CPlayerInterface.h"
|
||||||
|
#include "../Graphics.h"
|
||||||
|
|
||||||
|
#include "../gui/SDL_Extensions.h"
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
#include "../widgets/MiscWidgets.h"
|
||||||
|
#include "../widgets/CComponent.h"
|
||||||
|
|
||||||
|
#include "../../CCallback.h"
|
||||||
|
|
||||||
#include "../lib/CArtHandler.h"
|
#include "../lib/CArtHandler.h"
|
||||||
#include "CDefHandler.h"
|
#include "../lib/CConfigHandler.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../lib/CGeneralTextHandler.h"
|
||||||
#include "../lib/CHeroHandler.h"
|
#include "../lib/CHeroHandler.h"
|
||||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||||
#include "../lib/NetPacksBase.h"
|
#include "../lib/NetPacksBase.h"
|
||||||
|
|
||||||
#include "gui/CGuiHandler.h"
|
|
||||||
#include "gui/CIntObjectClasses.h"
|
|
||||||
#include "CMT.h"
|
|
||||||
|
|
||||||
#undef min
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CHeroWindow.cpp, part of VCMI engine
|
* CHeroWindow.cpp, part of VCMI engine
|
||||||
*
|
*
|
||||||
@ -93,8 +93,11 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
|
|||||||
CWindowObject(PLAYER_COLORED, "HeroScr4"),
|
CWindowObject(PLAYER_COLORED, "HeroScr4"),
|
||||||
heroWArt(this, hero)
|
heroWArt(this, hero)
|
||||||
{
|
{
|
||||||
|
auto & heroscrn = CGI->generaltexth->heroscrn;
|
||||||
|
|
||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
garr = nullptr;
|
garr = nullptr;
|
||||||
|
tacticsButton = nullptr;
|
||||||
curHero = hero;
|
curHero = hero;
|
||||||
listSelection = nullptr;
|
listSelection = nullptr;
|
||||||
|
|
||||||
@ -103,23 +106,32 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
|
|||||||
//artifs = new CArtifactsOfHero(pos.topLeft(), true);
|
//artifs = new CArtifactsOfHero(pos.topLeft(), true);
|
||||||
ourBar = new CGStatusBar(7, 559, "ADROLLVR.bmp", 660); // new CStatusBar(pos.x+72, pos.y+567, "ADROLLVR.bmp", 660);
|
ourBar = new CGStatusBar(7, 559, "ADROLLVR.bmp", 660); // new CStatusBar(pos.x+72, pos.y+567, "ADROLLVR.bmp", 660);
|
||||||
|
|
||||||
|
<<<<<<< HEAD:client/CHeroWindow.cpp
|
||||||
quitButton = new CAdventureMapButton(CGI->generaltexth->heroscrn[17], std::string(),std::bind(&CHeroWindow::close,this), 609, 516, "hsbtns.def", SDLK_RETURN);
|
quitButton = new CAdventureMapButton(CGI->generaltexth->heroscrn[17], std::string(),std::bind(&CHeroWindow::close,this), 609, 516, "hsbtns.def", SDLK_RETURN);
|
||||||
quitButton->assignedKeys.insert(SDLK_ESCAPE);
|
quitButton->assignedKeys.insert(SDLK_ESCAPE);
|
||||||
dismissButton = new CAdventureMapButton(std::string(), CGI->generaltexth->heroscrn[28], std::bind(&CHeroWindow::dismissCurrent,this), 454, 429, "hsbtns2.def", SDLK_d);
|
dismissButton = new CAdventureMapButton(std::string(), CGI->generaltexth->heroscrn[28], std::bind(&CHeroWindow::dismissCurrent,this), 454, 429, "hsbtns2.def", SDLK_d);
|
||||||
questlogButton = new CAdventureMapButton(CGI->generaltexth->heroscrn[0], std::string(), std::bind(&CHeroWindow::questlog,this), 314, 429, "hsbtns4.def", SDLK_q);
|
questlogButton = new CAdventureMapButton(CGI->generaltexth->heroscrn[0], std::string(), std::bind(&CHeroWindow::questlog,this), 314, 429, "hsbtns4.def", SDLK_q);
|
||||||
|
=======
|
||||||
|
quitButton = new CButton(Point(609, 516), "hsbtns.def", CButton::tooltip(heroscrn[17]), [&]{ close(); }, SDLK_RETURN);
|
||||||
|
quitButton->assignedKeys.insert(SDLK_ESCAPE);
|
||||||
|
dismissButton = new CButton(Point(454, 429), "hsbtns2.def", CButton::tooltip(heroscrn[28]), [&]{ dismissCurrent(); }, SDLK_d);
|
||||||
|
questlogButton = new CButton(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [&]{ questlog(); }, SDLK_q);
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CHeroWindow.cpp
|
||||||
|
|
||||||
formations = new CHighlightableButtonsGroup(0);
|
formations = new CToggleGroup(0);
|
||||||
formations->addButton(map_list_of(0,CGI->generaltexth->heroscrn[23]),CGI->generaltexth->heroscrn[29], "hsbtns6.def", 481, 483, 0, 0, SDLK_t);
|
formations->addToggle(0, new CToggleButton(Point(481, 483), "hsbtns6.def", std::make_pair(heroscrn[23], heroscrn[29]), 0, SDLK_t));
|
||||||
formations->addButton(map_list_of(0,CGI->generaltexth->heroscrn[24]),CGI->generaltexth->heroscrn[30], "hsbtns7.def", 481, 519, 1, 0, SDLK_l);
|
formations->addToggle(1, new CToggleButton(Point(481, 519), "hsbtns7.def", std::make_pair(heroscrn[24], heroscrn[30]), 0, SDLK_l));
|
||||||
|
|
||||||
tacticsButton = new CHighlightableButton(0, 0, map_list_of(0,CGI->generaltexth->heroscrn[26])(3,CGI->generaltexth->heroscrn[25]), CGI->generaltexth->heroscrn[31], false, "hsbtns8.def", nullptr, 539, 483, SDLK_b);
|
|
||||||
|
|
||||||
if (hero->commander)
|
if (hero->commander)
|
||||||
{
|
{
|
||||||
|
<<<<<<< HEAD:client/CHeroWindow.cpp
|
||||||
commanderButton = new CAdventureMapButton ("Commander", "Commander info", std::bind(&CHeroWindow::commanderWindow, this), 317, 18, "chftke.def", SDLK_c, nullptr, false);
|
commanderButton = new CAdventureMapButton ("Commander", "Commander info", std::bind(&CHeroWindow::commanderWindow, this), 317, 18, "chftke.def", SDLK_c, nullptr, false);
|
||||||
|
=======
|
||||||
|
auto texts = CGI->generaltexth->localizedTexts["heroWindow"]["openCommander"];
|
||||||
|
commanderButton = new CButton (Point(317, 18), "buttons/commander", CButton::tooltip(texts), [&]{ commanderWindow(); }, SDLK_c);
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CHeroWindow.cpp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//right list of heroes
|
//right list of heroes
|
||||||
for(int i=0; i < std::min(LOCPLINT->cb->howManyHeroes(false), 8); i++)
|
for(int i=0; i < std::min(LOCPLINT->cb->howManyHeroes(false), 8); i++)
|
||||||
heroList.push_back(new CHeroSwitcher(Point(612, 87 + i * 54), LOCPLINT->cb->getHeroBySerial(i, false)));
|
heroList.push_back(new CHeroSwitcher(Point(612, 87 + i * 54), LOCPLINT->cb->getHeroBySerial(i, false)));
|
||||||
@ -180,7 +192,9 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= false*/)
|
void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= false*/)
|
||||||
{
|
{
|
||||||
|
auto & heroscrn = CGI->generaltexth->heroscrn;
|
||||||
|
|
||||||
if(!hero) //something strange... no hero? it shouldn't happen
|
if(!hero) //something strange... no hero? it shouldn't happen
|
||||||
{
|
{
|
||||||
logGlobal->errorStream() << "Set nullptr hero? no way...";
|
logGlobal->errorStream() << "Set nullptr hero? no way...";
|
||||||
@ -192,10 +206,11 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
|
|||||||
specArea->text = curHero->type->specDescr;
|
specArea->text = curHero->type->specDescr;
|
||||||
specImage->setFrame(curHero->type->imageIndex);
|
specImage->setFrame(curHero->type->imageIndex);
|
||||||
|
|
||||||
tacticsButton->callback.clear();
|
delete tacticsButton;
|
||||||
tacticsButton->callback2.clear();
|
tacticsButton = new CToggleButton(Point(539, 483), "hsbtns8.def", std::make_pair(heroscrn[26], heroscrn[31]), 0, SDLK_b);
|
||||||
|
tacticsButton->addHoverText(CButton::HIGHLIGHTED, CGI->generaltexth->heroscrn[25]);
|
||||||
|
|
||||||
dismissButton->hoverTexts[0] = boost::str(boost::format(CGI->generaltexth->heroscrn[16]) % curHero->name % curHero->type->heroClass->name);
|
dismissButton->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->heroscrn[16]) % curHero->name % curHero->type->heroClass->name));
|
||||||
portraitArea->hoverText = boost::str(boost::format(CGI->generaltexth->allTexts[15]) % curHero->name % curHero->type->heroClass->name);
|
portraitArea->hoverText = boost::str(boost::format(CGI->generaltexth->allTexts[15]) % curHero->name % curHero->type->heroClass->name);
|
||||||
portraitArea->text = curHero->getBiography();
|
portraitArea->text = curHero->getBiography();
|
||||||
portraitImage->setFrame(curHero->portrait);
|
portraitImage->setFrame(curHero->portrait);
|
||||||
@ -204,10 +219,17 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
|
|||||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||||
if(!garr)
|
if(!garr)
|
||||||
{
|
{
|
||||||
|
std::string helpBox = heroscrn[32];
|
||||||
|
boost::algorithm::replace_first(helpBox, "%s", CGI->generaltexth->allTexts[43]);
|
||||||
|
|
||||||
garr = new CGarrisonInt(15, 485, 8, Point(), background->bg, Point(15,485), curHero);
|
garr = new CGarrisonInt(15, 485, 8, Point(), background->bg, Point(15,485), curHero);
|
||||||
|
<<<<<<< HEAD:client/CHeroWindow.cpp
|
||||||
auto split = new CAdventureMapButton(CGI->generaltexth->allTexts[256], CGI->generaltexth->heroscrn[32],
|
auto split = new CAdventureMapButton(CGI->generaltexth->allTexts[256], CGI->generaltexth->heroscrn[32],
|
||||||
std::bind(&CGarrisonInt::splitClick,garr), 539, 519, "hsbtns9.def", false, nullptr, false); //deleted by garrison destructor
|
std::bind(&CGarrisonInt::splitClick,garr), 539, 519, "hsbtns9.def", false, nullptr, false); //deleted by garrison destructor
|
||||||
boost::algorithm::replace_first(split->hoverTexts[0],"%s",CGI->generaltexth->allTexts[43]);
|
boost::algorithm::replace_first(split->hoverTexts[0],"%s",CGI->generaltexth->allTexts[43]);
|
||||||
|
=======
|
||||||
|
auto split = new CButton(Point(539, 519), "hsbtns9.def", CButton::tooltip(CGI->generaltexth->allTexts[256], helpBox), [&]{ garr->splitClick(); });
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CHeroWindow.cpp
|
||||||
|
|
||||||
garr->addSplitBtn(split);
|
garr->addSplitBtn(split);
|
||||||
}
|
}
|
||||||
@ -239,7 +261,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
|
|||||||
secSkillAreas[g]->type = skill;
|
secSkillAreas[g]->type = skill;
|
||||||
secSkillAreas[g]->bonusValue = level;
|
secSkillAreas[g]->bonusValue = level;
|
||||||
secSkillAreas[g]->text = CGI->generaltexth->skillInfoTexts[skill][level-1];
|
secSkillAreas[g]->text = CGI->generaltexth->skillInfoTexts[skill][level-1];
|
||||||
secSkillAreas[g]->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[21]) % CGI->generaltexth->levels[level-1] % CGI->generaltexth->skillName[skill]);
|
secSkillAreas[g]->hoverText = boost::str(boost::format(heroscrn[21]) % CGI->generaltexth->levels[level-1] % CGI->generaltexth->skillName[skill]);
|
||||||
secSkillImages[g]->setFrame(skill*3 + level + 2);
|
secSkillImages[g]->setFrame(skill*3 + level + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,14 +296,19 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
tacticsButton->block(false);
|
tacticsButton->block(false);
|
||||||
tacticsButton->callback = vstd::assigno(curHero->tacticFormationEnabled,true);
|
tacticsButton->addCallback( [&](bool on) {curHero->tacticFormationEnabled = on;});
|
||||||
tacticsButton->callback2 = vstd::assigno(curHero->tacticFormationEnabled,false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//setting formations
|
//setting formations
|
||||||
|
<<<<<<< HEAD:client/CHeroWindow.cpp
|
||||||
formations->onChange = 0;
|
formations->onChange = 0;
|
||||||
formations->select(curHero->formation,true);
|
formations->select(curHero->formation,true);
|
||||||
formations->onChange = std::bind(&CCallback::setFormation, LOCPLINT->cb.get(), curHero, _1);
|
formations->onChange = std::bind(&CCallback::setFormation, LOCPLINT->cb.get(), curHero, _1);
|
||||||
|
=======
|
||||||
|
formations->setSelected(curHero->formation);
|
||||||
|
formations->addCallback([&] (int value) { LOCPLINT->cb->setFormation(curHero, value); });
|
||||||
|
>>>>>>> refactoring/guiClasses:client/windows/CHeroWindow.cpp
|
||||||
|
|
||||||
morale->set(&heroWArt);
|
morale->set(&heroWArt);
|
||||||
luck->set(&heroWArt);
|
luck->set(&heroWArt);
|
||||||
@ -328,7 +355,7 @@ void CHeroWindow::commanderWindow()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
GH.pushInt(new CCreatureWindow (curHero->commander));
|
GH.pushInt(new CStackWindow(curHero->commander, false));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|