1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-10-31 00:07:39 +02:00

Merge pull request #6211 from Laserlicht/text_edit

Allowing editing town name
This commit is contained in:
Ivan Savenko
2025-10-28 15:33:50 +02:00
committed by GitHub
28 changed files with 265 additions and 58 deletions

View File

@@ -104,6 +104,7 @@ public:
void visitSetAvailableArtifacts(SetAvailableArtifacts & pack) override;
void visitEntitiesChanged(EntitiesChanged & pack) override;
void visitPlayerCheated(PlayerCheated & pack) override;
void visitChangeTownName(ChangeTownName & pack) override;
};
class ApplyFirstClientNetPackVisitor : public VCMI_LIB_WRAP_NAMESPACE(ICPackVisitor)

View File

@@ -1071,3 +1071,16 @@ void ApplyClientNetPackVisitor::visitPlayerCheated(PlayerCheated & pack)
if(pack.colorScheme != ColorScheme::KEEP && vstd::contains(cl.playerint, pack.player))
cl.playerint[pack.player]->setColorScheme(pack.colorScheme);
}
void ApplyClientNetPackVisitor::visitChangeTownName(ChangeTownName & pack)
{
if(!adventureInt)
return;
const CGTownInstance *town = gs.getTown(pack.tid);
if(town)
{
adventureInt->onTownChanged(town);
ENGINE->windows().totalRedraw();
}
}

View File

@@ -1035,10 +1035,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
if(s->isControlledByAI() || GAME->server().isGuest())
labelPlayerName = std::make_shared<CLabel>(55, 10, EFonts::FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, name, 95);
else
{
labelPlayerNameEdit = std::make_shared<CTextInput>(Rect(6, 3, 95, 15), EFonts::FONT_SMALL, ETextAlignment::CENTER, false);
labelPlayerNameEdit->setText(name);
}
labelPlayerNameEdit = std::make_shared<CTextInputWithConfirm>(Rect(6, 3, 95, 15), EFonts::FONT_SMALL, ETextAlignment::CENTER, name, false, [this](){ updateName(); });
labelWhoCanPlay = std::make_shared<CMultiLineLabel>(Rect(6, 21, 45, 26), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, LIBRARY->generaltexth->arraytxt[206 + whoCanPlay]);
@@ -1114,28 +1111,6 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
bonus = std::make_shared<SelectedBox>(Point(271, 2), *s, BONUS);
}
bool OptionsTab::PlayerOptionsEntry::captureThisKey(EShortcut key)
{
return labelPlayerNameEdit && labelPlayerNameEdit->hasFocus() && key == EShortcut::GLOBAL_ACCEPT;
}
void OptionsTab::PlayerOptionsEntry::keyPressed(EShortcut key)
{
if(labelPlayerNameEdit && key == EShortcut::GLOBAL_ACCEPT)
updateName();
}
bool OptionsTab::PlayerOptionsEntry::receiveEvent(const Point & position, int eventType) const
{
return eventType == AEventsReceiver::LCLICK; // capture all left clicks (not only within control)
}
void OptionsTab::PlayerOptionsEntry::clickReleased(const Point & cursorPosition)
{
if(labelPlayerNameEdit && !labelPlayerNameEdit->pos.isInside(cursorPosition))
updateName();
}
void OptionsTab::PlayerOptionsEntry::updateName() {
if(labelPlayerNameEdit->getText() != name)
{
@@ -1146,8 +1121,6 @@ void OptionsTab::PlayerOptionsEntry::updateName() {
set->String() = labelPlayerNameEdit->getText();
}
}
labelPlayerNameEdit->removeFocus();
name = labelPlayerNameEdit->getText();
}

View File

@@ -28,6 +28,7 @@ class CTextBox;
class CButton;
class CSlider;
class LRClickableArea;
class CTextInputWithConfirm;
class FilledTexturePlayerColored;
class TransparentFilledRectangle;
@@ -196,7 +197,7 @@ private:
std::unique_ptr<PlayerInfo> pi;
std::unique_ptr<PlayerSettings> s;
std::shared_ptr<CLabel> labelPlayerName;
std::shared_ptr<CTextInput> labelPlayerNameEdit;
std::shared_ptr<CTextInputWithConfirm> labelPlayerNameEdit;
std::shared_ptr<CMultiLineLabel> labelWhoCanPlay;
std::shared_ptr<CPicture> background;
std::shared_ptr<CButton> buttonTownLeft;
@@ -215,10 +216,6 @@ private:
PlayerOptionsEntry(const PlayerSettings & S, const OptionsTab & parentTab);
void hideUnavailableButtons();
bool captureThisKey(EShortcut key) override;
void keyPressed(EShortcut key) override;
void clickReleased(const Point & cursorPosition) override;
bool receiveEvent(const Point & position, int eventType) const override;
private:
const OptionsTab & parentTab;

View File

@@ -85,6 +85,7 @@ private:
//void visitSetCommanderProperty(SetCommanderProperty & pack) override;
//void visitAddQuest(AddQuest & pack) override;
//void visitChangeFormation(ChangeFormation & pack) override;
//void visitChangeTownName(ChangeTownName & pack) override;
//void visitChangeSpells(ChangeSpells & pack) override;
//void visitSetAvailableHero(SetAvailableHero & pack) override;
//void visitChangeObjectVisitors(ChangeObjectVisitors & pack) override;

View File

@@ -27,6 +27,85 @@
std::list<CFocusable *> CFocusable::focusables;
CFocusable * CFocusable::inputWithFocus;
CTextInputWithConfirm::CTextInputWithConfirm(const Rect & Pos, EFonts font, ETextAlignment alignment, std::string text, bool limitToRect, std::function<void()> confirmCallback)
: CTextInput(Pos, font, alignment, false), confirmCb(confirmCallback), limitToRect(limitToRect), initialText(text)
{
setText(text);
}
bool CTextInputWithConfirm::captureThisKey(EShortcut key)
{
return hasFocus() && (key == EShortcut::GLOBAL_ACCEPT || key == EShortcut::GLOBAL_CANCEL || key == EShortcut::GLOBAL_BACKSPACE);
}
void CTextInputWithConfirm::keyPressed(EShortcut key)
{
if(!hasFocus())
return;
if(key == EShortcut::GLOBAL_ACCEPT)
confirm();
else if(key == EShortcut::GLOBAL_CANCEL)
{
setText(initialText);
removeFocus();
}
CTextInput::keyPressed(key);
}
bool CTextInputWithConfirm::receiveEvent(const Point & position, int eventType) const
{
return eventType == AEventsReceiver::LCLICK; // capture all left clicks (not only within control)
}
void CTextInputWithConfirm::clickReleased(const Point & cursorPosition)
{
if(!pos.isInside(cursorPosition)) // clicked outside
confirm();
}
void CTextInputWithConfirm::clickPressed(const Point & cursorPosition)
{
if(pos.isInside(cursorPosition)) // clickPressed should respect control area (receiveEvent also affects this)
CTextInput::clickPressed(cursorPosition);
}
void CTextInputWithConfirm::onFocusGot()
{
initialText = getText();
CTextInput::onFocusGot();
}
void CTextInputWithConfirm::textInputted(const std::string & enteredText)
{
if(!hasFocus())
return;
std::string visibleText = getVisibleText() + enteredText;
const auto & font = ENGINE->renderHandler().loadFont(label->font);
if(!limitToRect || (font->getStringWidth(visibleText) - CLabel::getDelimitersWidth(label->font, visibleText)) < pos.w)
CTextInput::textInputted(enteredText);
}
void CTextInputWithConfirm::deactivate()
{
removeUsedEvents(LCLICK);
CTextInput::deactivate();
}
void CTextInputWithConfirm::confirm()
{
if(getText().empty())
setText(initialText);
if(confirmCb && initialText != getText())
confirmCb();
removeFocus();
}
CTextInput::CTextInput(const Rect & Pos)
:originalAlignment(ETextAlignment::CENTERLEFT)
{
@@ -196,7 +275,7 @@ void CTextInput::updateLabel()
label->alignment = originalAlignment;
const auto & font = ENGINE->renderHandler().loadFont(label->font);
while (font->getStringWidth(visibleText) > pos.w)
while ((font->getStringWidth(visibleText) - CLabel::getDelimitersWidth(label->font, visibleText)) > pos.w)
{
label->alignment = ETextAlignment::CENTERRIGHT;
visibleText = visibleText.substr(TextOperations::getUnicodeCharacterSize(visibleText[0]));

View File

@@ -45,8 +45,9 @@ public:
};
/// Text input box where players can enter text
class CTextInput final : public CFocusable
class CTextInput : public CFocusable
{
protected:
using TextEditedCallback = std::function<void(const std::string &)>;
using TextFilterCallback = std::function<void(std::string &, const std::string &)>;
@@ -71,12 +72,12 @@ class CTextInput final : public CFocusable
void createLabel(bool giveFocusToInput);
void updateLabel();
void clickPressed(const Point & cursorPosition) final;
void textInputted(const std::string & enteredText) final;
void textEdited(const std::string & enteredText) final;
void onFocusGot() final;
void onFocusLost() final;
void showPopupWindow(const Point & cursorPosition) final;
void clickPressed(const Point & cursorPosition) override;
void textInputted(const std::string & enteredText) override;
void textEdited(const std::string & enteredText) override;
void onFocusGot() override;
void onFocusLost() override;
void showPopupWindow(const Point & cursorPosition) override;
CTextInput(const Rect & Pos);
public:
@@ -105,7 +106,27 @@ public:
void setAlignment(ETextAlignment alignment);
// CIntObject interface impl
void keyPressed(EShortcut key) final;
void activate() final;
void deactivate() final;
void keyPressed(EShortcut key) override;
void activate() override;
void deactivate() override;
};
class CTextInputWithConfirm final : public CTextInput
{
std::string initialText;
std::function<void()> confirmCb;
bool limitToRect;
void confirm();
public:
CTextInputWithConfirm(const Rect & Pos, EFonts font, ETextAlignment alignment, std::string text, bool limitToRect, std::function<void()> confirmCallback);
bool captureThisKey(EShortcut key) override;
void keyPressed(EShortcut key) override;
void clickReleased(const Point & cursorPosition) override;
void clickPressed(const Point & cursorPosition) override;
bool receiveEvent(const Point & position, int eventType) const override;
void onFocusGot() override;
void textInputted(const std::string & enteredText) override;
void deactivate() override;
};

View File

@@ -182,29 +182,39 @@ std::vector<std::string> CMultiLineLabel::getLines()
return lines;
}
void CTextContainer::blitLine(Canvas & to, Rect destRect, std::string what)
const std::string delimiters = "{}";
int CTextContainer::getDelimitersWidth(EFonts font, std::string text)
{
const auto f = ENGINE->renderHandler().loadFont(font);
Point where = destRect.topLeft();
const std::string delimiters = "{}";
auto delimitersCount = std::count_if(what.cbegin(), what.cend(), [&delimiters](char c)
auto delimitersWidth = std::count_if(text.cbegin(), text.cend(), [](char c)
{
return delimiters.find(c) != std::string::npos;
});
//We should count delimiters length from string to correct centering later.
delimitersCount *= f->getStringWidth(delimiters)/2;
delimitersWidth *= f->getStringWidth(delimiters)/2;
std::smatch match;
std::regex expr("\\{(.*?)\\|");
std::string::const_iterator searchStart( what.cbegin() );
while(std::regex_search(searchStart, what.cend(), match, expr))
std::string::const_iterator searchStart( text.cbegin() );
while(std::regex_search(searchStart, text.cend(), match, expr))
{
std::string colorText = match[1].str();
if(auto c = Colors::parseColor(colorText))
delimitersCount += f->getStringWidth(colorText + "|");
delimitersWidth += f->getStringWidth(colorText + "|");
searchStart = match.suffix().first;
}
return delimitersWidth;
}
void CTextContainer::blitLine(Canvas & to, Rect destRect, std::string what)
{
const auto f = ENGINE->renderHandler().loadFont(font);
Point where = destRect.topLeft();
int delimitersWidth = getDelimitersWidth(font, what);
// input is rect in which given text should be placed
// calculate proper position for top-left corner of the text
@@ -212,10 +222,10 @@ void CTextContainer::blitLine(Canvas & to, Rect destRect, std::string what)
where.x += getBorderSize().x;
if(alignment == ETextAlignment::CENTER || alignment == ETextAlignment::TOPCENTER || alignment == ETextAlignment::BOTTOMCENTER)
where.x += (destRect.w - (static_cast<int>(f->getStringWidth(what)) - delimitersCount)) / 2;
where.x += (destRect.w - (static_cast<int>(f->getStringWidth(what)) - delimitersWidth)) / 2;
if(alignment == ETextAlignment::TOPRIGHT || alignment == ETextAlignment::BOTTOMRIGHT || alignment == ETextAlignment::CENTERRIGHT)
where.x += getBorderSize().x + destRect.w - (static_cast<int>(f->getStringWidth(what)) - delimitersCount);
where.x += getBorderSize().x + destRect.w - (static_cast<int>(f->getStringWidth(what)) - delimitersWidth);
if(alignment == ETextAlignment::TOPLEFT || alignment == ETextAlignment::TOPCENTER || alignment == ETextAlignment::TOPRIGHT)
where.y += getBorderSize().y;

View File

@@ -31,6 +31,8 @@ protected:
CTextContainer(ETextAlignment alignment, EFonts font, ColorRGBA color);
public:
static int getDelimitersWidth(EFonts font, std::string text);
ETextAlignment alignment;
EFonts font;
ColorRGBA color; // default font color. Can be overridden by placing "{}" into the string

View File

@@ -30,6 +30,7 @@
#include "../widgets/MiscWidgets.h"
#include "../widgets/CComponent.h"
#include "../widgets/CGarrisonInt.h"
#include "../widgets/CTextInput.h"
#include "../widgets/Buttons.h"
#include "../widgets/TextControls.h"
#include "../widgets/RadialMenu.h"
@@ -1435,7 +1436,15 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
garr->setRedrawParent(true);
heroes = std::make_shared<HeroSlots>(town, Point(241, 387), Point(241, 483), garr, true);
title = std::make_shared<CLabel>(85, 387, FONT_MEDIUM, ETextAlignment::TOPLEFT, Colors::WHITE, town->getNameTranslated());
title = std::make_shared<CTextInputWithConfirm>(Rect(83, 386, 140, 20), FONT_MEDIUM, ETextAlignment::TOPLEFT, town->getNameTranslated(), true, [this](){
std::string name = title->getText();
std::string originalName = LIBRARY->generaltexth->translate(town->getNameTextID());
if(name == originalName)
name = ""; // use textID again
GAME->interface()->cb->setTownName(town, name);
});
if(town->tempOwner != GAME->interface()->playerID) // disable changing for allied towns
title->deactivate();
income = std::make_shared<CLabel>(195, 443, FONT_SMALL, ETextAlignment::CENTER);
icon = std::make_shared<CAnimImage>(AnimationPath::builtin("ITPT"), 0, 0, 15, 387);

View File

@@ -37,6 +37,7 @@ class CGarrisonInt;
class CComponent;
class CComponentBox;
class LRClickableArea;
class CTextInputWithConfirm;
/// Building "button"
class CBuildingRect : public CShowableAnim
@@ -225,7 +226,7 @@ public:
/// Class which manages the castle window
class CCastleInterface final : public CStatusbarWindow, public IGarrisonHolder, public IArtifactsHolder
{
std::shared_ptr<CLabel> title;
std::shared_ptr<CTextInputWithConfirm> title;
std::shared_ptr<CLabel> income;
std::shared_ptr<CAnimImage> icon;

View File

@@ -286,6 +286,12 @@ void CCallback::setFormation(const CGHeroInstance * hero, EArmyFormation mode)
sendRequest(pack);
}
void CCallback::setTownName(const CGTownInstance * town, std::string & name)
{
SetTownName pack(town->id, name);
sendRequest(pack);
}
void CCallback::recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero, const HeroTypeID & nextHero)
{
assert(townOrTavern);

View File

@@ -76,6 +76,7 @@ public:
void trade(const ObjectInstanceID marketId, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero = nullptr) override;
void trade(const ObjectInstanceID marketId, 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 setTownName(const CGTownInstance * town, std::string & name) override;
void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero, const HeroTypeID & nextHero=HeroTypeID::NONE) override;
void save(const std::string &fname) override;
void sendMessage(const std::string &mess, const CGObjectInstance * currentObject = nullptr) override;

View File

@@ -70,6 +70,7 @@ public:
virtual void endTurn()=0;
virtual void buyArtifact(const CGHeroInstance *hero, ArtifactID aid)=0; //used to buy artifacts in towns (including spell book in the guild and war machines in blacksmith)
virtual void setFormation(const CGHeroInstance * hero, EArmyFormation mode)=0;
virtual void setTownName(const CGTownInstance * town, std::string & name)=0;
virtual void save(const std::string &fname) = 0;
virtual void sendMessage(const std::string &mess, const CGObjectInstance * currentObject = nullptr) = 0;

View File

@@ -123,6 +123,11 @@ void GameStatePackVisitor::visitChangeFormation(ChangeFormation & pack)
gs.getHero(pack.hid)->setFormation(pack.formation);
}
void GameStatePackVisitor::visitChangeTownName(ChangeTownName & pack)
{
gs.getTown(pack.tid)->setCustomName(pack.name);
}
void GameStatePackVisitor::visitHeroVisitCastle(HeroVisitCastle & pack)
{
CGHeroInstance *h = gs.getHero(pack.hid);

View File

@@ -87,6 +87,7 @@ public:
void visitSetCommanderProperty(SetCommanderProperty & pack) override;
void visitAddQuest(AddQuest & pack) override;
void visitChangeFormation(ChangeFormation & pack) override;
void visitChangeTownName(ChangeTownName & pack) override;
void visitChangeSpells(ChangeSpells & pack) override;
void visitSetAvailableHero(SetAvailableHero & pack) override;
void visitChangeObjectVisitors(ChangeObjectVisitors & pack) override;

View File

@@ -860,7 +860,7 @@ CBonusSystemNode & CGTownInstance::whatShouldBeAttached()
std::string CGTownInstance::getNameTranslated() const
{
return LIBRARY->generaltexth->translate(nameTextId);
return customName.empty() ? LIBRARY->generaltexth->translate(nameTextId) : customName;
}
std::string CGTownInstance::getNameTextID() const
@@ -873,6 +873,11 @@ void CGTownInstance::setNameTextId( const std::string & newName )
nameTextId = newName;
}
void CGTownInstance::setCustomName( const std::string & newName )
{
customName = newName;
}
const CArmedInstance * CGTownInstance::getUpperArmy() const
{
if(getGarrisonHero())

View File

@@ -46,6 +46,7 @@ class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public I
{
friend class CTownInstanceConstructor;
std::string nameTextId; // name of town
std::string customName;
std::map<BuildingID, TownRewardableBuildingInstance*> convertOldBuildings(std::vector<TownRewardableBuildingInstance*> oldVector);
std::set<BuildingID> builtBuildings;
@@ -75,6 +76,8 @@ public:
{
h & static_cast<CGDwelling&>(*this);
h & nameTextId;
if (h.version >= Handler::Version::CUSTOM_NAMES)
h & customName;
h & built;
h & destroyed;
h & identifier;
@@ -128,6 +131,7 @@ public:
std::string getNameTranslated() const;
std::string getNameTextID() const;
void setNameTextId(const std::string & newName);
void setCustomName(const std::string & newName);
//////////////////////////////////////////////////////////////////////////

View File

@@ -58,6 +58,7 @@ public:
virtual void visitSetCommanderProperty(SetCommanderProperty & pack) {}
virtual void visitAddQuest(AddQuest & pack) {}
virtual void visitChangeFormation(ChangeFormation & pack) {}
virtual void visitChangeTownName(ChangeTownName & pack) {}
virtual void visitRemoveObject(RemoveObject & pack) {}
virtual void visitTryMoveHero(TryMoveHero & pack) {}
virtual void visitNewStructures(NewStructures & pack) {}
@@ -144,6 +145,7 @@ public:
virtual void visitBuyArtifact(BuyArtifact & pack) {}
virtual void visitTradeOnMarketplace(TradeOnMarketplace & pack) {}
virtual void visitSetFormation(SetFormation & pack) {}
virtual void visitSetTownName(SetTownName & pack) {}
virtual void visitHireHero(HireHero & pack) {}
virtual void visitBuildBoat(BuildBoat & pack) {}
virtual void visitQueryReply(QueryReply & pack) {}

View File

@@ -213,6 +213,11 @@ void ChangeFormation::visitTyped(ICPackVisitor & visitor)
visitor.visitChangeFormation(*this);
}
void ChangeTownName::visitTyped(ICPackVisitor & visitor)
{
visitor.visitChangeTownName(*this);
}
void RemoveObject::visitTyped(ICPackVisitor & visitor)
{
visitor.visitRemoveObject(*this);
@@ -643,6 +648,11 @@ void SetFormation::visitTyped(ICPackVisitor & visitor)
visitor.visitSetFormation(*this);
}
void SetTownName::visitTyped(ICPackVisitor & visitor)
{
visitor.visitSetTownName(*this);
}
void HireHero::visitTyped(ICPackVisitor & visitor)
{
visitor.visitHireHero(*this);

View File

@@ -614,6 +614,20 @@ struct DLL_LINKAGE ChangeFormation : public CPackForClient
}
};
struct DLL_LINKAGE ChangeTownName : public CPackForClient
{
ObjectInstanceID tid;
std::string name;
void visitTyped(ICPackVisitor & visitor) override;
template <typename Handler> void serialize(Handler & h)
{
h & tid;
h & name;
}
};
struct DLL_LINKAGE RemoveObject : public CPackForClient
{
RemoveObject() = default;

View File

@@ -609,6 +609,28 @@ struct DLL_LINKAGE SetFormation : public CPackForServer
}
};
struct DLL_LINKAGE SetTownName : public CPackForServer
{
SetTownName() = default;
;
SetTownName(const ObjectInstanceID & TID, std::string Name)
: tid(TID)
, name(Name)
{
}
ObjectInstanceID tid;
std::string name;
void visitTyped(ICPackVisitor & visitor) override;
template <typename Handler> void serialize(Handler & h)
{
h & static_cast<CPackForServer &>(*this);
h & tid;
h & name;
}
};
struct DLL_LINKAGE HireHero : public CPackForServer
{
HireHero() = default;

View File

@@ -50,8 +50,9 @@ enum class ESerializationVersion : int32_t
BONUS_HIDDEN, // hidden bonus
MORE_MAP_LAYERS, // more map layers
CONFIGURABLE_RESOURCES, // configurable resources
CUSTOM_NAMES, // custom names
CURRENT = CONFIGURABLE_RESOURCES,
CURRENT = CUSTOM_NAMES,
};
static_assert(ESerializationVersion::MINIMAL <= ESerializationVersion::CURRENT, "Invalid serialization version definition!");

View File

@@ -291,6 +291,8 @@ void registerTypes(Serializer &s)
s.template registerType<TimesStackSizeUpdater>(249);
s.template registerType<TimesArmySizeUpdater>(250);
s.template registerType<PackageReceived>(251);
s.template registerType<ChangeTownName>(252);
s.template registerType<SetTownName>(253);
}
VCMI_LIB_NAMESPACE_END

View File

@@ -3219,6 +3219,23 @@ bool CGameHandler::setFormation(ObjectInstanceID hid, EArmyFormation formation)
return true;
}
bool CGameHandler::setTownName(ObjectInstanceID tid, std::string & name)
{
const CGTownInstance *t = gameInfo().getTown(tid);
if (!t)
{
logGlobal->error("Town doesn't exist!");
return false;
}
ChangeTownName ctn;
ctn.tid = tid;
ctn.name = name;
sendAndApply(ctn);
return true;
}
bool CGameHandler::queryReply(QueryID qid, std::optional<int32_t> answer, PlayerColor player)
{
logGlobal->trace("Player %s attempts answering query %d with answer:", player, qid);

View File

@@ -212,6 +212,7 @@ public:
bool queryReply( QueryID qid, std::optional<int32_t> reply, PlayerColor player );
bool buildBoat( ObjectInstanceID objid, PlayerColor player );
bool setFormation( ObjectInstanceID hid, EArmyFormation formation );
bool setTownName( ObjectInstanceID tid, std::string & name );
bool tradeResources(const IMarket *market, ui32 amountToSell, PlayerColor player, GameResID toSell, GameResID toBuy);
bool sacrificeCreatures(const IMarket * market, const CGHeroInstance * hero, const std::vector<SlotID> & slot, const std::vector<ui32> & count);
bool sendResources(ui32 val, PlayerColor player, GameResID r1, PlayerColor r2);

View File

@@ -362,6 +362,13 @@ void ApplyGhNetPackVisitor::visitSetFormation(SetFormation & pack)
result = gh.setFormation(pack.hid, pack.formation);
}
void ApplyGhNetPackVisitor::visitSetTownName(SetTownName & pack)
{
gh.throwIfWrongOwner(connection, &pack, pack.tid);
result = gh.setTownName(pack.tid, pack.name);
}
void ApplyGhNetPackVisitor::visitHireHero(HireHero & pack)
{
gh.throwIfWrongPlayer(connection, &pack);

View File

@@ -58,6 +58,7 @@ public:
void visitBuyArtifact(BuyArtifact & pack) override;
void visitTradeOnMarketplace(TradeOnMarketplace & pack) override;
void visitSetFormation(SetFormation & pack) override;
void visitSetTownName(SetTownName & pack) override;
void visitHireHero(HireHero & pack) override;
void visitBuildBoat(BuildBoat & pack) override;
void visitQueryReply(QueryReply & pack) override;