mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-22 22:13:35 +02:00
commit
4d0c0f10a9
@ -261,12 +261,12 @@ void CCallback::setFormation(const CGHeroInstance * hero, EArmyFormation mode)
|
|||||||
sendRequest(&pack);
|
sendRequest(&pack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCallback::recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero)
|
void CCallback::recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero, const HeroTypeID & nextHero)
|
||||||
{
|
{
|
||||||
assert(townOrTavern);
|
assert(townOrTavern);
|
||||||
assert(hero);
|
assert(hero);
|
||||||
|
|
||||||
HireHero pack(hero->getHeroType(), townOrTavern->id);
|
HireHero pack(hero->getHeroType(), townOrTavern->id, nextHero);
|
||||||
pack.player = *player;
|
pack.player = *player;
|
||||||
sendRequest(&pack);
|
sendRequest(&pack);
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ public:
|
|||||||
virtual void castSpell(const CGHeroInstance *hero, SpellID spellID, const int3 &pos = int3(-1, -1, -1))=0; //cast adventure map spell
|
virtual void castSpell(const CGHeroInstance *hero, SpellID spellID, const int3 &pos = int3(-1, -1, -1))=0; //cast adventure map spell
|
||||||
|
|
||||||
//town
|
//town
|
||||||
virtual void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero)=0;
|
virtual void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero, const HeroTypeID & nextHero=HeroTypeID::NONE)=0;
|
||||||
virtual bool buildBuilding(const CGTownInstance *town, BuildingID buildingID)=0;
|
virtual bool buildBuilding(const CGTownInstance *town, BuildingID buildingID)=0;
|
||||||
virtual void recruitCreatures(const CGDwelling *obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1)=0;
|
virtual void recruitCreatures(const CGDwelling *obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1)=0;
|
||||||
virtual bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE)=0; //if newID==-1 then best possible upgrade will be made
|
virtual bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE)=0; //if newID==-1 then best possible upgrade will be made
|
||||||
@ -185,7 +185,7 @@ public:
|
|||||||
void trade(const IMarket * market, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero = nullptr) override;
|
void trade(const IMarket * market, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero = nullptr) override;
|
||||||
void trade(const IMarket * market, EMarketMode mode, const std::vector<TradeItemSell> & id1, const std::vector<TradeItemBuy> & id2, const std::vector<ui32> & val1, const CGHeroInstance * hero = nullptr) override;
|
void trade(const IMarket * market, EMarketMode mode, const std::vector<TradeItemSell> & id1, const std::vector<TradeItemBuy> & id2, const std::vector<ui32> & val1, const CGHeroInstance * hero = nullptr) override;
|
||||||
void setFormation(const CGHeroInstance * hero, EArmyFormation mode) override;
|
void setFormation(const CGHeroInstance * hero, EArmyFormation mode) override;
|
||||||
void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero) override;
|
void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero, const HeroTypeID & nextHero=HeroTypeID::NONE) override;
|
||||||
void save(const std::string &fname) override;
|
void save(const std::string &fname) override;
|
||||||
void sendMessage(const std::string &mess, const CGObjectInstance * currentObject = nullptr) override;
|
void sendMessage(const std::string &mess, const CGObjectInstance * currentObject = nullptr) override;
|
||||||
void gamePause(bool pause) override;
|
void gamePause(bool pause) override;
|
||||||
|
@ -233,6 +233,8 @@
|
|||||||
"vcmi.heroWindow.openBackpack.hover" : "Open artifact backpack window",
|
"vcmi.heroWindow.openBackpack.hover" : "Open artifact backpack window",
|
||||||
"vcmi.heroWindow.openBackpack.help" : "Opens window that allows easier artifact backpack management.",
|
"vcmi.heroWindow.openBackpack.help" : "Opens window that allows easier artifact backpack management.",
|
||||||
|
|
||||||
|
"vcmi.tavernWindow.inviteHero" : "Invite hero",
|
||||||
|
|
||||||
"vcmi.commanderWindow.artifactMessage" : "Do you want to return this artifact to the hero?",
|
"vcmi.commanderWindow.artifactMessage" : "Do you want to return this artifact to the hero?",
|
||||||
|
|
||||||
"vcmi.creatureWindow.showBonuses.hover" : "Switch to bonuses view",
|
"vcmi.creatureWindow.showBonuses.hover" : "Switch to bonuses view",
|
||||||
|
@ -232,6 +232,8 @@
|
|||||||
"vcmi.heroWindow.openBackpack.hover" : "Artefakt-Rucksack-Fenster öffnen",
|
"vcmi.heroWindow.openBackpack.hover" : "Artefakt-Rucksack-Fenster öffnen",
|
||||||
"vcmi.heroWindow.openBackpack.help" : "Öffnet ein Fenster, das die Verwaltung des Artefakt-Rucksacks erleichtert",
|
"vcmi.heroWindow.openBackpack.help" : "Öffnet ein Fenster, das die Verwaltung des Artefakt-Rucksacks erleichtert",
|
||||||
|
|
||||||
|
"vcmi.tavernWindow.inviteHero" : "Helden einladen",
|
||||||
|
|
||||||
"vcmi.commanderWindow.artifactMessage" : "Möchtet Ihr diesen Artefakt dem Helden zurückgeben?",
|
"vcmi.commanderWindow.artifactMessage" : "Möchtet Ihr diesen Artefakt dem Helden zurückgeben?",
|
||||||
|
|
||||||
"vcmi.creatureWindow.showBonuses.hover" : "Wechsle zur Bonus-Ansicht",
|
"vcmi.creatureWindow.showBonuses.hover" : "Wechsle zur Bonus-Ansicht",
|
||||||
|
@ -407,8 +407,14 @@ void OptionsTabBase::recreate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(auto buttonCheatAllowed = widget<CToggleButton>("buttonCheatAllowed"))
|
if(auto buttonCheatAllowed = widget<CToggleButton>("buttonCheatAllowed"))
|
||||||
|
{
|
||||||
buttonCheatAllowed->setSelectedSilent(SEL->getStartInfo()->extraOptionsInfo.cheatsAllowed);
|
buttonCheatAllowed->setSelectedSilent(SEL->getStartInfo()->extraOptionsInfo.cheatsAllowed);
|
||||||
|
buttonCheatAllowed->block(SEL->screenType == ESelectionScreen::loadGame);
|
||||||
|
}
|
||||||
|
|
||||||
if(auto buttonUnlimitedReplay = widget<CToggleButton>("buttonUnlimitedReplay"))
|
if(auto buttonUnlimitedReplay = widget<CToggleButton>("buttonUnlimitedReplay"))
|
||||||
|
{
|
||||||
buttonUnlimitedReplay->setSelectedSilent(SEL->getStartInfo()->extraOptionsInfo.unlimitedReplay);
|
buttonUnlimitedReplay->setSelectedSilent(SEL->getStartInfo()->extraOptionsInfo.unlimitedReplay);
|
||||||
|
buttonUnlimitedReplay->block(SEL->screenType == ESelectionScreen::loadGame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
#include "InfoWindows.h"
|
#include "InfoWindows.h"
|
||||||
|
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
|
#include "../CServerHandler.h"
|
||||||
|
#include "../Client.h"
|
||||||
#include "../CMusicHandler.h"
|
#include "../CMusicHandler.h"
|
||||||
#include "../CPlayerInterface.h"
|
#include "../CPlayerInterface.h"
|
||||||
#include "../CVideoHandler.h"
|
#include "../CVideoHandler.h"
|
||||||
@ -48,6 +50,7 @@
|
|||||||
#include "../lib/mapObjects/ObjectTemplate.h"
|
#include "../lib/mapObjects/ObjectTemplate.h"
|
||||||
#include "../lib/gameState/CGameState.h"
|
#include "../lib/gameState/CGameState.h"
|
||||||
#include "../lib/gameState/SThievesGuildInfo.h"
|
#include "../lib/gameState/SThievesGuildInfo.h"
|
||||||
|
#include "../lib/gameState/TavernHeroesPool.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../lib/CGeneralTextHandler.h"
|
||||||
#include "../lib/CHeroHandler.h"
|
#include "../lib/CHeroHandler.h"
|
||||||
#include "../lib/GameSettings.h"
|
#include "../lib/GameSettings.h"
|
||||||
@ -443,7 +446,8 @@ CLevelWindow::~CLevelWindow()
|
|||||||
CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::function<void()> & onWindowClosed)
|
CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::function<void()> & onWindowClosed)
|
||||||
: CStatusbarWindow(PLAYER_COLORED, ImagePath::builtin("TPTAVERN")),
|
: CStatusbarWindow(PLAYER_COLORED, ImagePath::builtin("TPTAVERN")),
|
||||||
onWindowClosed(onWindowClosed),
|
onWindowClosed(onWindowClosed),
|
||||||
tavernObj(TavernObj)
|
tavernObj(TavernObj),
|
||||||
|
heroToInvite(nullptr)
|
||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
||||||
|
|
||||||
@ -459,8 +463,8 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::func
|
|||||||
|
|
||||||
oldSelected = -1;
|
oldSelected = -1;
|
||||||
|
|
||||||
h1 = std::make_shared<HeroPortrait>(selected, 0, 72, 299, h[0]);
|
h1 = std::make_shared<HeroPortrait>(selected, 0, 72, 299, h[0], [this]() { if(!recruit->isBlocked()) recruitb(); });
|
||||||
h2 = std::make_shared<HeroPortrait>(selected, 1, 162, 299, h[1]);
|
h2 = std::make_shared<HeroPortrait>(selected, 1, 162, 299, h[1], [this]() { if(!recruit->isBlocked()) recruitb(); });
|
||||||
|
|
||||||
title = std::make_shared<CLabel>(197, 32, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->jktexts[37]);
|
title = std::make_shared<CLabel>(197, 32, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->jktexts[37]);
|
||||||
cost = std::make_shared<CLabel>(320, 328, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(GameConstants::HERO_GOLD_COST));
|
cost = std::make_shared<CLabel>(320, 328, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(GameConstants::HERO_GOLD_COST));
|
||||||
@ -507,6 +511,34 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::func
|
|||||||
CCS->videoh->open(townObj->town->clientInfo.tavernVideo);
|
CCS->videoh->open(townObj->town->clientInfo.tavernVideo);
|
||||||
else
|
else
|
||||||
CCS->videoh->open(VideoPath::builtin("TAVERN.BIK"));
|
CCS->videoh->open(VideoPath::builtin("TAVERN.BIK"));
|
||||||
|
|
||||||
|
addInvite();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTavernWindow::addInvite()
|
||||||
|
{
|
||||||
|
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
||||||
|
|
||||||
|
if(!VLC->settings()->getBoolean(EGameSettings::HEROES_TAVERN_INVITE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto & heroesPool = CSH->client->gameState()->heroesPool;
|
||||||
|
for(auto & elem : heroesPool->unusedHeroesFromPool())
|
||||||
|
{
|
||||||
|
bool heroAvailable = heroesPool->isHeroAvailableFor(elem.first, tavernObj->getOwner());
|
||||||
|
if(heroAvailable)
|
||||||
|
inviteableHeroes[elem.first] = elem.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!inviteableHeroes.empty())
|
||||||
|
{
|
||||||
|
if(!heroToInvite)
|
||||||
|
heroToInvite = (*RandomGeneratorUtil::nextItem(inviteableHeroes, CRandomGenerator::getDefault())).second;
|
||||||
|
|
||||||
|
inviteHero = std::make_shared<CLabel>(170, 444, EFonts::FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->translate("vcmi.tavernWindow.inviteHero"));
|
||||||
|
inviteHeroImage = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsSmall"), (*CGI->heroh)[heroToInvite->getHeroType()]->imageIndex, 0, 245, 428);
|
||||||
|
inviteHeroImageArea = std::make_shared<LRClickableArea>(Rect(245, 428, 48, 32), [this](){ GH.windows().createAndPushWindow<HeroSelector>(inviteableHeroes, [this](CGHeroInstance* h){ heroToInvite = h; addInvite(); }); }, [this](){ GH.windows().createAndPushWindow<CRClickPopupInt>(std::make_shared<CHeroWindow>(heroToInvite)); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTavernWindow::recruitb()
|
void CTavernWindow::recruitb()
|
||||||
@ -514,7 +546,7 @@ void CTavernWindow::recruitb()
|
|||||||
const CGHeroInstance *toBuy = (selected ? h2 : h1)->h;
|
const CGHeroInstance *toBuy = (selected ? h2 : h1)->h;
|
||||||
const CGObjectInstance *obj = tavernObj;
|
const CGObjectInstance *obj = tavernObj;
|
||||||
|
|
||||||
LOCPLINT->cb->recruitHero(obj, toBuy);
|
LOCPLINT->cb->recruitHero(obj, toBuy, heroToInvite ? heroToInvite->getHeroType() : HeroTypeID::NONE);
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,15 +601,23 @@ void CTavernWindow::HeroPortrait::clickPressed(const Point & cursorPosition)
|
|||||||
*_sel = _id;
|
*_sel = _id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CTavernWindow::HeroPortrait::clickDouble(const Point & cursorPosition)
|
||||||
|
{
|
||||||
|
clickPressed(cursorPosition);
|
||||||
|
|
||||||
|
if(onChoose)
|
||||||
|
onChoose();
|
||||||
|
}
|
||||||
|
|
||||||
void CTavernWindow::HeroPortrait::showPopupWindow(const Point & cursorPosition)
|
void CTavernWindow::HeroPortrait::showPopupWindow(const Point & cursorPosition)
|
||||||
{
|
{
|
||||||
if(h)
|
if(h)
|
||||||
GH.windows().createAndPushWindow<CRClickPopupInt>(std::make_shared<CHeroWindow>(h));
|
GH.windows().createAndPushWindow<CRClickPopupInt>(std::make_shared<CHeroWindow>(h));
|
||||||
}
|
}
|
||||||
|
|
||||||
CTavernWindow::HeroPortrait::HeroPortrait(int & sel, int id, int x, int y, const CGHeroInstance * H)
|
CTavernWindow::HeroPortrait::HeroPortrait(int & sel, int id, int x, int y, const CGHeroInstance * H, std::function<void()> OnChoose)
|
||||||
: CIntObject(LCLICK | SHOW_POPUP | HOVER),
|
: CIntObject(LCLICK | DOUBLECLICK | SHOW_POPUP | HOVER),
|
||||||
h(H), _sel(&sel), _id(id)
|
h(H), _sel(&sel), _id(id), onChoose(OnChoose)
|
||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
||||||
h = H;
|
h = H;
|
||||||
@ -615,6 +655,33 @@ void CTavernWindow::HeroPortrait::hover(bool on)
|
|||||||
GH.statusbar()->clear();
|
GH.statusbar()->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CTavernWindow::HeroSelector::HeroSelector(std::map<HeroTypeID, CGHeroInstance*> InviteableHeroes, std::function<void(CGHeroInstance*)> OnChoose)
|
||||||
|
: CWindowObject(BORDERED), inviteableHeroes(InviteableHeroes), onChoose(OnChoose)
|
||||||
|
{
|
||||||
|
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
||||||
|
|
||||||
|
pos = Rect(0, 0, 16 * 48, (inviteableHeroes.size() / 16 + (inviteableHeroes.size() % 16 != 0)) * 32);
|
||||||
|
background = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), Rect(0, 0, pos.w, pos.h));
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
for(auto & h : inviteableHeroes)
|
||||||
|
{
|
||||||
|
portraits.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsSmall"), (*CGI->heroh)[h.first]->imageIndex, 0, x * 48, y * 32));
|
||||||
|
portraitAreas.push_back(std::make_shared<LRClickableArea>(Rect(x * 48, y * 32, 48, 32), [this, h](){ close(); onChoose(inviteableHeroes[h.first]); }, [this, h](){ GH.windows().createAndPushWindow<CRClickPopupInt>(std::make_shared<CHeroWindow>(inviteableHeroes[h.first])); }));
|
||||||
|
|
||||||
|
if(x > 0 && x % 15 == 0)
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
center();
|
||||||
|
}
|
||||||
|
|
||||||
static const std::string QUICK_EXCHANGE_MOD_PREFIX = "quick-exchange";
|
static const std::string QUICK_EXCHANGE_MOD_PREFIX = "quick-exchange";
|
||||||
static const std::string QUICK_EXCHANGE_BG = QUICK_EXCHANGE_MOD_PREFIX + "/TRADEQE";
|
static const std::string QUICK_EXCHANGE_BG = QUICK_EXCHANGE_MOD_PREFIX + "/TRADEQE";
|
||||||
|
|
||||||
|
@ -36,6 +36,8 @@ class CTextBox;
|
|||||||
class CGarrisonInt;
|
class CGarrisonInt;
|
||||||
class CGarrisonSlot;
|
class CGarrisonSlot;
|
||||||
class CHeroArea;
|
class CHeroArea;
|
||||||
|
class CAnimImage;
|
||||||
|
class CFilledTexture;
|
||||||
|
|
||||||
enum class EUserEvent;
|
enum class EUserEvent;
|
||||||
|
|
||||||
@ -206,10 +208,13 @@ public:
|
|||||||
std::string description; // "XXX is a level Y ZZZ with N artifacts"
|
std::string description; // "XXX is a level Y ZZZ with N artifacts"
|
||||||
const CGHeroInstance * h;
|
const CGHeroInstance * h;
|
||||||
|
|
||||||
|
std::function<void()> onChoose;
|
||||||
|
|
||||||
void clickPressed(const Point & cursorPosition) override;
|
void clickPressed(const Point & cursorPosition) override;
|
||||||
|
void clickDouble(const Point & cursorPosition) override;
|
||||||
void showPopupWindow(const Point & cursorPosition) override;
|
void showPopupWindow(const Point & cursorPosition) override;
|
||||||
void hover (bool on) override;
|
void hover (bool on) override;
|
||||||
HeroPortrait(int & sel, int id, int x, int y, const CGHeroInstance * H);
|
HeroPortrait(int & sel, int id, int x, int y, const CGHeroInstance * H, std::function<void()> OnChoose = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int *_sel;
|
int *_sel;
|
||||||
@ -218,6 +223,21 @@ public:
|
|||||||
std::shared_ptr<CAnimImage> portrait;
|
std::shared_ptr<CAnimImage> portrait;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class HeroSelector : public CWindowObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::shared_ptr<CFilledTexture> background;
|
||||||
|
|
||||||
|
HeroSelector(std::map<HeroTypeID, CGHeroInstance*> InviteableHeroes, std::function<void(CGHeroInstance*)> OnChoose);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<HeroTypeID, CGHeroInstance*> inviteableHeroes;
|
||||||
|
std::function<void(CGHeroInstance*)> onChoose;
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<CAnimImage>> portraits;
|
||||||
|
std::vector<std::shared_ptr<LRClickableArea>> portraitAreas;
|
||||||
|
};
|
||||||
|
|
||||||
//recruitable heroes
|
//recruitable heroes
|
||||||
std::shared_ptr<HeroPortrait> h1;
|
std::shared_ptr<HeroPortrait> h1;
|
||||||
std::shared_ptr<HeroPortrait> h2; //recruitable heroes
|
std::shared_ptr<HeroPortrait> h2; //recruitable heroes
|
||||||
@ -238,6 +258,13 @@ public:
|
|||||||
|
|
||||||
std::shared_ptr<CTextBox> rumor;
|
std::shared_ptr<CTextBox> rumor;
|
||||||
|
|
||||||
|
std::shared_ptr<CLabel> inviteHero;
|
||||||
|
std::shared_ptr<CAnimImage> inviteHeroImage;
|
||||||
|
std::shared_ptr<LRClickableArea> inviteHeroImageArea;
|
||||||
|
std::map<HeroTypeID, CGHeroInstance*> inviteableHeroes;
|
||||||
|
CGHeroInstance* heroToInvite;
|
||||||
|
void addInvite();
|
||||||
|
|
||||||
CTavernWindow(const CGObjectInstance * TavernObj, const std::function<void()> & onWindowClosed);
|
CTavernWindow(const CGObjectInstance * TavernObj, const std::function<void()> & onWindowClosed);
|
||||||
~CTavernWindow();
|
~CTavernWindow();
|
||||||
|
|
||||||
|
@ -289,7 +289,9 @@
|
|||||||
// Chances for a hero with default army to receive corresponding stack out of his predefined starting troops
|
// Chances for a hero with default army to receive corresponding stack out of his predefined starting troops
|
||||||
"startingStackChances": [ 100, 88, 25],
|
"startingStackChances": [ 100, 88, 25],
|
||||||
// number of artifacts that can fit in a backpack. -1 is unlimited.
|
// number of artifacts that can fit in a backpack. -1 is unlimited.
|
||||||
"backpackSize" : -1
|
"backpackSize" : -1,
|
||||||
|
// if heroes are invitable in tavern
|
||||||
|
"tavernInvite" : false
|
||||||
},
|
},
|
||||||
|
|
||||||
"towns":
|
"towns":
|
||||||
|
@ -64,12 +64,14 @@
|
|||||||
"name": "buttonCheatAllowed",
|
"name": "buttonCheatAllowed",
|
||||||
"image": "lobby/checkbox",
|
"image": "lobby/checkbox",
|
||||||
"callback" : "setCheatAllowed",
|
"callback" : "setCheatAllowed",
|
||||||
|
"help" : "vcmi.optionsTab.cheatAllowed",
|
||||||
"selected" : true
|
"selected" : true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "buttonUnlimitedReplay",
|
"name": "buttonUnlimitedReplay",
|
||||||
"image": "lobby/checkbox",
|
"image": "lobby/checkbox",
|
||||||
"callback" : "setUnlimitedReplay",
|
"callback" : "setUnlimitedReplay",
|
||||||
|
"help" : "vcmi.optionsTab.unlimitedReplay",
|
||||||
"selected" : true
|
"selected" : true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -74,6 +74,7 @@ void GameSettings::load(const JsonNode & input)
|
|||||||
{EGameSettings::HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS, "heroes", "retreatOnWinWithoutTroops" },
|
{EGameSettings::HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS, "heroes", "retreatOnWinWithoutTroops" },
|
||||||
{EGameSettings::HEROES_STARTING_STACKS_CHANCES, "heroes", "startingStackChances" },
|
{EGameSettings::HEROES_STARTING_STACKS_CHANCES, "heroes", "startingStackChances" },
|
||||||
{EGameSettings::HEROES_BACKPACK_CAP, "heroes", "backpackSize" },
|
{EGameSettings::HEROES_BACKPACK_CAP, "heroes", "backpackSize" },
|
||||||
|
{EGameSettings::HEROES_TAVERN_INVITE, "heroes", "tavernInvite" },
|
||||||
{EGameSettings::MAP_FORMAT_RESTORATION_OF_ERATHIA, "mapFormat", "restorationOfErathia" },
|
{EGameSettings::MAP_FORMAT_RESTORATION_OF_ERATHIA, "mapFormat", "restorationOfErathia" },
|
||||||
{EGameSettings::MAP_FORMAT_ARMAGEDDONS_BLADE, "mapFormat", "armageddonsBlade" },
|
{EGameSettings::MAP_FORMAT_ARMAGEDDONS_BLADE, "mapFormat", "armageddonsBlade" },
|
||||||
{EGameSettings::MAP_FORMAT_SHADOW_OF_DEATH, "mapFormat", "shadowOfDeath" },
|
{EGameSettings::MAP_FORMAT_SHADOW_OF_DEATH, "mapFormat", "shadowOfDeath" },
|
||||||
|
@ -38,6 +38,7 @@ enum class EGameSettings
|
|||||||
HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS,
|
HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS,
|
||||||
HEROES_STARTING_STACKS_CHANCES,
|
HEROES_STARTING_STACKS_CHANCES,
|
||||||
HEROES_BACKPACK_CAP,
|
HEROES_BACKPACK_CAP,
|
||||||
|
HEROES_TAVERN_INVITE,
|
||||||
MARKETS_BLACK_MARKET_RESTOCK_PERIOD,
|
MARKETS_BLACK_MARKET_RESTOCK_PERIOD,
|
||||||
BANKS_SHOW_GUARDS_COMPOSITION,
|
BANKS_SHOW_GUARDS_COMPOSITION,
|
||||||
MODULE_COMMANDERS,
|
MODULE_COMMANDERS,
|
||||||
|
@ -516,12 +516,14 @@ struct DLL_LINKAGE SetFormation : public CPackForServer
|
|||||||
struct DLL_LINKAGE HireHero : public CPackForServer
|
struct DLL_LINKAGE HireHero : public CPackForServer
|
||||||
{
|
{
|
||||||
HireHero() = default;
|
HireHero() = default;
|
||||||
HireHero(HeroTypeID HID, const ObjectInstanceID & TID)
|
HireHero(HeroTypeID HID, const ObjectInstanceID & TID, const HeroTypeID & NHID)
|
||||||
: hid(HID)
|
: hid(HID)
|
||||||
, tid(TID)
|
, tid(TID)
|
||||||
|
, nhid(NHID)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
HeroTypeID hid; //available hero serial
|
HeroTypeID hid; //available hero serial
|
||||||
|
HeroTypeID nhid; //next hero
|
||||||
ObjectInstanceID tid; //town (tavern) id
|
ObjectInstanceID tid; //town (tavern) id
|
||||||
PlayerColor player;
|
PlayerColor player;
|
||||||
|
|
||||||
@ -531,6 +533,7 @@ struct DLL_LINKAGE HireHero : public CPackForServer
|
|||||||
{
|
{
|
||||||
h & static_cast<CPackForServer &>(*this);
|
h & static_cast<CPackForServer &>(*this);
|
||||||
h & hid;
|
h & hid;
|
||||||
|
h & nhid;
|
||||||
h & tid;
|
h & tid;
|
||||||
h & player;
|
h & player;
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ void ApplyGhNetPackVisitor::visitHireHero(HireHero & pack)
|
|||||||
{
|
{
|
||||||
gh.throwIfWrongPlayer(&pack);
|
gh.throwIfWrongPlayer(&pack);
|
||||||
|
|
||||||
result = gh.heroPool->hireHero(pack.tid, pack.hid, pack.player);
|
result = gh.heroPool->hireHero(pack.tid, pack.hid, pack.player, pack.nhid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyGhNetPackVisitor::visitBuildBoat(BuildBoat & pack)
|
void ApplyGhNetPackVisitor::visitBuildBoat(BuildBoat & pack)
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "../../lib/gameState/CGameState.h"
|
#include "../../lib/gameState/CGameState.h"
|
||||||
#include "../../lib/gameState/TavernHeroesPool.h"
|
#include "../../lib/gameState/TavernHeroesPool.h"
|
||||||
#include "../../lib/gameState/TavernSlot.h"
|
#include "../../lib/gameState/TavernSlot.h"
|
||||||
|
#include "../../lib/GameSettings.h"
|
||||||
|
|
||||||
HeroPoolProcessor::HeroPoolProcessor()
|
HeroPoolProcessor::HeroPoolProcessor()
|
||||||
: gameHandler(nullptr)
|
: gameHandler(nullptr)
|
||||||
@ -104,14 +105,14 @@ void HeroPoolProcessor::clearHeroFromSlot(const PlayerColor & color, TavernHeroS
|
|||||||
gameHandler->sendAndApply(&sah);
|
gameHandler->sendAndApply(&sah);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeroPoolProcessor::selectNewHeroForSlot(const PlayerColor & color, TavernHeroSlot slot, bool needNativeHero, bool giveArmy)
|
void HeroPoolProcessor::selectNewHeroForSlot(const PlayerColor & color, TavernHeroSlot slot, bool needNativeHero, bool giveArmy, const HeroTypeID & nextHero)
|
||||||
{
|
{
|
||||||
SetAvailableHero sah;
|
SetAvailableHero sah;
|
||||||
sah.player = color;
|
sah.player = color;
|
||||||
sah.slotID = slot;
|
sah.slotID = slot;
|
||||||
sah.replenishPoints = true;
|
sah.replenishPoints = true;
|
||||||
|
|
||||||
CGHeroInstance *newHero = pickHeroFor(needNativeHero, color);
|
CGHeroInstance *newHero = (nextHero == HeroTypeID::NONE) ? pickHeroFor(needNativeHero, color) : gameHandler->gameState()->heroesPool->unusedHeroesFromPool()[nextHero];
|
||||||
|
|
||||||
if (newHero)
|
if (newHero)
|
||||||
{
|
{
|
||||||
@ -145,11 +146,12 @@ void HeroPoolProcessor::onNewWeek(const PlayerColor & color)
|
|||||||
selectNewHeroForSlot(color, TavernHeroSlot::RANDOM, false, true);
|
selectNewHeroForSlot(color, TavernHeroSlot::RANDOM, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTypeID & heroToRecruit, const PlayerColor & player)
|
bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTypeID & heroToRecruit, const PlayerColor & player, const HeroTypeID & nextHero)
|
||||||
{
|
{
|
||||||
const PlayerState * playerState = gameHandler->getPlayerState(player);
|
const PlayerState * playerState = gameHandler->getPlayerState(player);
|
||||||
const CGObjectInstance * mapObject = gameHandler->getObj(objectID);
|
const CGObjectInstance * mapObject = gameHandler->getObj(objectID);
|
||||||
const CGTownInstance * town = gameHandler->getTown(objectID);
|
const CGTownInstance * town = gameHandler->getTown(objectID);
|
||||||
|
const auto & heroesPool = gameHandler->gameState()->heroesPool;
|
||||||
|
|
||||||
if (!mapObject && gameHandler->complain("Invalid map object!"))
|
if (!mapObject && gameHandler->complain("Invalid map object!"))
|
||||||
return false;
|
return false;
|
||||||
@ -166,6 +168,18 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
|
|||||||
if (gameHandler->getHeroCount(player, true) >= VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP) && gameHandler->complain("Cannot hire hero, too many heroes garrizoned and wandering already!"))
|
if (gameHandler->getHeroCount(player, true) >= VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP) && gameHandler->complain("Cannot hire hero, too many heroes garrizoned and wandering already!"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (nextHero != HeroTypeID::NONE) // player attempts to invite next hero
|
||||||
|
{
|
||||||
|
if(!VLC->settings()->getBoolean(EGameSettings::HEROES_TAVERN_INVITE) && gameHandler->complain("Inviting heroes not allowed!"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!heroesPool->unusedHeroesFromPool().count(nextHero) && gameHandler->complain("Cannot invite specified hero!"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!heroesPool->isHeroAvailableFor(nextHero, player) && gameHandler->complain("Cannot invite specified hero!"))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(town) //tavern in town
|
if(town) //tavern in town
|
||||||
{
|
{
|
||||||
if(gameHandler->getPlayerRelations(mapObject->tempOwner, player) == PlayerRelations::ENEMIES && gameHandler->complain("Can't buy hero in enemy town!"))
|
if(gameHandler->getPlayerRelations(mapObject->tempOwner, player) == PlayerRelations::ENEMIES && gameHandler->complain("Can't buy hero in enemy town!"))
|
||||||
@ -192,7 +206,7 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto recruitableHeroes = gameHandler->gameState()->heroesPool->getHeroesFor(player);
|
auto recruitableHeroes = heroesPool->getHeroesFor(player);
|
||||||
|
|
||||||
const CGHeroInstance * recruitedHero = nullptr;
|
const CGHeroInstance * recruitedHero = nullptr;
|
||||||
|
|
||||||
@ -226,9 +240,9 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
|
|||||||
gameHandler->sendAndApply(&hr);
|
gameHandler->sendAndApply(&hr);
|
||||||
|
|
||||||
if(recruitableHeroes[0] == recruitedHero)
|
if(recruitableHeroes[0] == recruitedHero)
|
||||||
selectNewHeroForSlot(player, TavernHeroSlot::NATIVE, false, false);
|
selectNewHeroForSlot(player, TavernHeroSlot::NATIVE, false, false, nextHero);
|
||||||
else
|
else
|
||||||
selectNewHeroForSlot(player, TavernHeroSlot::RANDOM, false, false);
|
selectNewHeroForSlot(player, TavernHeroSlot::RANDOM, false, false, nextHero);
|
||||||
|
|
||||||
gameHandler->giveResource(player, EGameResID::GOLD, -GameConstants::HERO_GOLD_COST);
|
gameHandler->giveResource(player, EGameResID::GOLD, -GameConstants::HERO_GOLD_COST);
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../lib/constants/EntityIdentifiers.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
enum class TavernHeroSlot : int8_t;
|
enum class TavernHeroSlot : int8_t;
|
||||||
@ -33,7 +35,7 @@ class HeroPoolProcessor : boost::noncopyable
|
|||||||
std::map<HeroTypeID, std::unique_ptr<CRandomGenerator>> heroSeed;
|
std::map<HeroTypeID, std::unique_ptr<CRandomGenerator>> heroSeed;
|
||||||
|
|
||||||
void clearHeroFromSlot(const PlayerColor & color, TavernHeroSlot slot);
|
void clearHeroFromSlot(const PlayerColor & color, TavernHeroSlot slot);
|
||||||
void selectNewHeroForSlot(const PlayerColor & color, TavernHeroSlot slot, bool needNativeHero, bool giveStartingArmy);
|
void selectNewHeroForSlot(const PlayerColor & color, TavernHeroSlot slot, bool needNativeHero, bool giveStartingArmy, const HeroTypeID & nextHero = HeroTypeID::NONE);
|
||||||
|
|
||||||
std::vector<const CHeroClass *> findAvailableClassesFor(const PlayerColor & player) const;
|
std::vector<const CHeroClass *> findAvailableClassesFor(const PlayerColor & player) const;
|
||||||
std::vector<CGHeroInstance *> findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const;
|
std::vector<CGHeroInstance *> findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const;
|
||||||
@ -60,7 +62,7 @@ public:
|
|||||||
CRandomGenerator & getHeroSkillsRandomGenerator(const HeroTypeID & hero);
|
CRandomGenerator & getHeroSkillsRandomGenerator(const HeroTypeID & hero);
|
||||||
|
|
||||||
/// Incoming net pack handling
|
/// Incoming net pack handling
|
||||||
bool hireHero(const ObjectInstanceID & objectID, const HeroTypeID & hid, const PlayerColor & player);
|
bool hireHero(const ObjectInstanceID & objectID, const HeroTypeID & hid, const PlayerColor & player, const HeroTypeID & nextHero);
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h)
|
template <typename Handler> void serialize(Handler &h)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user