1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-02 00:10:22 +02:00

vcmi: allow showing more than one components in infobar

Up to 8, AFAIK. So, we can show multi-reward in infobox now.
One issue remain - cannot dynamically choose components size
based on text size.
This commit is contained in:
Konstantin 2023-03-06 02:30:21 +03:00
parent 2fb2a79ca4
commit 4617ce10e5
24 changed files with 105 additions and 87 deletions

View File

@ -390,7 +390,7 @@ void AIGateway::advmapSpellCast(const CGHeroInstance * caster, int spellID)
NET_EVENT_HANDLER;
}
void AIGateway::showInfoDialog(const std::string & text, const std::vector<Component> & components, int soundID)
void AIGateway::showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID)
{
LOG_TRACE_PARAMS(logAi, "soundID '%i'", soundID);
NET_EVENT_HANDLER;

View File

@ -153,7 +153,7 @@ public:
void playerBonusChanged(const Bonus & bonus, bool gain) override;
void heroCreated(const CGHeroInstance *) override;
void advmapSpellCast(const CGHeroInstance * caster, int spellID) override;
void showInfoDialog(const std::string & text, const std::vector<Component> & components, int soundID) override;
void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override;
void requestRealized(PackageApplied * pa) override;
void receivedResource() override;
void objectRemoved(const CGObjectInstance * obj) override;

View File

@ -20,6 +20,7 @@
#include "../../lib/CHeroHandler.h"
#include "../../lib/CModHandler.h"
#include "../../lib/CGameState.h"
#include "../../lib/NetPacksBase.h"
#include "../../lib/NetPacks.h"
#include "../../lib/serializer/CTypeList.h"
#include "../../lib/serializer/BinarySerializer.h"
@ -475,7 +476,7 @@ void VCAI::advmapSpellCast(const CGHeroInstance * caster, int spellID)
NET_EVENT_HANDLER;
}
void VCAI::showInfoDialog(const std::string & text, const std::vector<Component> & components, int soundID)
void VCAI::showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID)
{
LOG_TRACE_PARAMS(logAi, "soundID '%i'", soundID);
NET_EVENT_HANDLER;

View File

@ -186,7 +186,7 @@ public:
void playerBonusChanged(const Bonus & bonus, bool gain) override;
void heroCreated(const CGHeroInstance *) override;
void advmapSpellCast(const CGHeroInstance * caster, int spellID) override;
void showInfoDialog(const std::string & text, const std::vector<Component> & components, int soundID) override;
void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override;
void requestRealized(PackageApplied * pa) override;
void receivedResource() override;
void objectRemoved(const CGObjectInstance * obj) override;

View File

@ -1031,18 +1031,16 @@ void CPlayerInterface::yourTacticPhase(int distance)
boost::this_thread::sleep(boost::posix_time::millisec(1));
}
void CPlayerInterface::showComp(const Component &comp, std::string message)
void CPlayerInterface::showInfoDialog(EInfoWindowMode type, const std::string &text, const std::vector<Component> & components, int soundID)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
waitWhileDialog(); //Fix for mantis #98
CCS->soundh->playSoundFromSet(CCS->soundh->pickupSounds);
adventureInt->infoBar->showComponent(comp, message);
if(type == InfoWindow::INFO) {
adventureInt->infoBar->showComponents(components, text);
if (makingTurn && GH.listInt.size() && LOCPLINT == this)
CCS->soundh->playSound(static_cast<soundBase::soundID>(soundID));
return;
}
void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<Component> & components, int soundID)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
if (settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown())
{
return;
@ -1093,7 +1091,7 @@ void CPlayerInterface::showInfoDialogAndWait(std::vector<Component> & components
std::string str;
text.toString(str);
showInfoDialog(str, components, 0);
showInfoDialog(EInfoWindowMode::MODAL, str, components, 0);
waitWhileDialog();
}

View File

@ -168,7 +168,7 @@ public:
void heroMovePointsChanged(const CGHeroInstance * hero) override;
void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town) override;
void receivedResource() override;
void showInfoDialog(const std::string & text, const std::vector<Component> & components, int soundID) override;
void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override;
void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) override;
void showShipyardDialog(const IShipyard *obj) override; //obj may be town or shipyard;
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
@ -201,7 +201,6 @@ public:
void playerBlocked(int reason, bool start) override;
void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) override;
void playerStartsTurn(PlayerColor player) override; //called before yourTurn on active itnerface
void showComp(const Component &comp, std::string message) override; //display component in the advmapint infobox
void saveGame(BinarySerializer & h, const int version) override; //saving
void loadGame(BinaryDeserializer & h, const int version) override; //loading
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;

View File

@ -217,7 +217,6 @@ public:
void removeArtifact(const ArtifactLocation & al) override {};
bool moveArtifact(const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;};
void showCompInfo(ShowInInfobox * comp) override {};
void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override {};
void visitCastleObjects(const CGTownInstance * obj, const CGHeroInstance * hero) override {};
void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override {};

View File

@ -96,7 +96,6 @@ public:
void visitYourTurn(YourTurn & pack) override;
void visitSaveGameClient(SaveGameClient & pack) override;
void visitPlayerMessageClient(PlayerMessageClient & pack) override;
void visitShowInInfobox(ShowInInfobox & pack) override;
void visitAdvmapSpellCast(AdvmapSpellCast & pack) override;
void visitShowWorldViewEx(ShowWorldViewEx & pack) override;
void visitOpenWindow(OpenWindow & pack) override;

View File

@ -592,7 +592,7 @@ void ApplyClientNetPackVisitor::visitInfoWindow(InfoWindow & pack)
std::string str;
pack.text.toString(str);
if(!callInterfaceIfPresent(cl, pack.player, &CGameInterface::showInfoDialog, str, pack.components,(soundBase::soundID)pack.soundID))
if(!callInterfaceIfPresent(cl, pack.player, &CGameInterface::showInfoDialog, pack.type, str, pack.components,(soundBase::soundID)pack.soundID))
logNetwork->warn("We received InfoWindow for not our player...");
}
@ -855,11 +855,6 @@ void ApplyClientNetPackVisitor::visitPlayerMessageClient(PlayerMessageClient & p
LOCPLINT->cingconsole->print(str.str());
}
void ApplyClientNetPackVisitor::visitShowInInfobox(ShowInInfobox & pack)
{
callInterfaceIfPresent(cl, pack.player, &IGameEventsReceiver::showComp, pack.c, pack.text.toString());
}
void ApplyClientNetPackVisitor::visitAdvmapSpellCast(AdvmapSpellCast & pack)
{
cl.invalidatePaths();

View File

@ -163,16 +163,39 @@ CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo()
}
}
CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const Component & compToDisplay, std::string message)
CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const std::vector<Component> & compsToDisplay, std::string message)
{
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
background = std::make_shared<CPicture>("ADSTATOT", 1, 0);
auto fullRect = Rect(4, 4, 171, 171);
auto textRect = fullRect;
auto imageRect = fullRect;
comp = std::make_shared<CComponent>(compToDisplay);
comp->moveTo(Point(pos.x+47, pos.y+50));
if(!compsToDisplay.empty())
{
auto size = CComponent::large;
if(compsToDisplay.size() > 2)
size = CComponent::small;
if(message != "")
{
textRect = Rect(4, 4, 171, 42);
imageRect = Rect(4, 42, 171, 121);
if(compsToDisplay.size() > 4)
size = CComponent::tiny;
}
else if(compsToDisplay.size() > 4)
size = CComponent::small;
text = std::make_shared<CTextBox>(message, Rect(10, 4, 160, 50), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
std::vector<std::shared_ptr<CComponent>> vect;
for(const auto & c : compsToDisplay)
vect.emplace_back(std::make_shared<CComponent>(c, size));
comps = std::make_shared<CComponentBox>(vect, imageRect, 4, 4, 1);
}
text = std::make_shared<CTextBox>(message, textRect, 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
}
void CInfoBar::playNewDaySound()
@ -266,11 +289,12 @@ void CInfoBar::showDate()
redraw();
}
void CInfoBar::showComponent(const Component & comp, std::string message)
void CInfoBar::showComponents(const std::vector<Component> & comps, std::string message)
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
state = COMPONENT;
visibleInfo = std::make_shared<VisibleComponentInfo>(comp, message);
visibleInfo = std::make_shared<VisibleComponentInfo>(comps, message);
setTimer(3000);
redraw();
}

View File

@ -23,6 +23,7 @@ VCMI_LIB_NAMESPACE_END
class CAnimImage;
class CShowableAnim;
class CComponent;
class CComponentBox;
class CHeroTooltip;
class CTownTooltip;
class CLabel;
@ -97,10 +98,10 @@ class CInfoBar : public CIntObject
class VisibleComponentInfo : public CVisibleInfo
{
std::shared_ptr<CComponent> comp;
std::shared_ptr<CComponentBox> comps;
std::shared_ptr<CTextBox> text;
public:
VisibleComponentInfo(const Component & compToDisplay, std::string message);
VisibleComponentInfo(const std::vector<Component> & compsToDisplay, std::string message);
};
enum EState
@ -127,8 +128,8 @@ public:
/// show new day/week animation
void showDate();
/// show component for 3 seconds. Used to display picked up resources
void showComponent(const Component & comp, std::string message);
/// show components for 3 seconds. Used to display picked up resources. Can display up to 8 components
void showComponents(const std::vector<Component> & comps, std::string message);
/// print enemy turn progress
void startEnemyTurn(PlayerColor color);

View File

@ -336,9 +336,6 @@ Point CComponentBox::getOrTextPos(CComponent *left, CComponent *right)
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;
@ -348,8 +345,6 @@ int CComponentBox::getDistance(CComponent *left, CComponent *right)
void CComponentBox::placeComponents(bool selectable)
{
static const int betweenRows = 22;
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
if (components.empty())
return;
@ -450,7 +445,15 @@ void CComponentBox::placeComponents(bool selectable)
}
CComponentBox::CComponentBox(std::vector<std::shared_ptr<CComponent>> _components, Rect position):
components(_components)
CComponentBox(_components, position, defaultBetweenImagesMin, defaultBetweenSubtitlesMin, defaultBetweenRows)
{
}
CComponentBox::CComponentBox(std::vector<std::shared_ptr<CComponent>> _components, Rect position, int betweenImagesMin, int betweenSubtitlesMin, int betweenRows):
components(_components),
betweenImagesMin(betweenImagesMin),
betweenSubtitlesMin(betweenSubtitlesMin),
betweenRows(betweenRows)
{
type |= REDRAW_PARENT;
pos = position + pos.topLeft();
@ -458,8 +461,16 @@ CComponentBox::CComponentBox(std::vector<std::shared_ptr<CComponent>> _component
}
CComponentBox::CComponentBox(std::vector<std::shared_ptr<CSelectableComponent>> _components, Rect position, std::function<void(int newID)> _onSelect):
CComponentBox(_components, position, _onSelect, defaultBetweenImagesMin, defaultBetweenSubtitlesMin, defaultBetweenRows)
{
}
CComponentBox::CComponentBox(std::vector<std::shared_ptr<CSelectableComponent>> _components, Rect position, std::function<void(int newID)> _onSelect, int betweenImagesMin, int betweenSubtitlesMin, int betweenRows):
components(_components.begin(), _components.end()),
onSelect(_onSelect)
onSelect(_onSelect),
betweenImagesMin(betweenImagesMin),
betweenSubtitlesMin(betweenSubtitlesMin),
betweenRows(betweenRows)
{
type |= REDRAW_PARENT;
pos = position + pos.topLeft();

View File

@ -94,6 +94,14 @@ class CComponentBox : public CIntObject
std::shared_ptr<CSelectableComponent> selected;
std::function<void(int newID)> onSelect;
static constexpr int defaultBetweenImagesMin = 20;
static constexpr int defaultBetweenSubtitlesMin = 10;
static constexpr int defaultBetweenRows = 22;
int betweenImagesMin;
int betweenSubtitlesMin;
int betweenRows;
void selectionChanged(std::shared_ptr<CSelectableComponent> newSelection);
//get position of "or" text between these comps
@ -108,11 +116,13 @@ public:
/// return index of selected item
int selectedIndex();
/// constructor for non-selectable components
/// constructors for non-selectable components
CComponentBox(std::vector<std::shared_ptr<CComponent>> components, Rect position);
CComponentBox(std::vector<std::shared_ptr<CComponent>> components, Rect position, int betweenImagesMin, int betweenSubtitlesMin, int betweenRows);
/// 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<std::shared_ptr<CSelectableComponent>> components, Rect position, std::function<void(int newID)> onSelect = nullptr);
CComponentBox(std::vector<std::shared_ptr<CSelectableComponent>> components, Rect position, std::function<void(int newID)> onSelect, int betweenImagesMin, int betweenSubtitlesMin, int betweenRows);
};

View File

@ -21,7 +21,6 @@ struct GiveBonus;
struct BlockingDialog;
struct TeleportDialog;
struct MetaString;
struct ShowInInfobox;
struct StackLocation;
struct ArtifactLocation;
class CCreatureSet;
@ -113,7 +112,6 @@ public:
virtual void removeArtifact(const ArtifactLocation &al) = 0;
virtual bool moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) = 0;
virtual void showCompInfo(ShowInInfobox * comp)=0;
virtual void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)=0;
virtual void visitCastleObjects(const CGTownInstance * obj, const CGHeroInstance * hero)=0;
virtual void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)=0;

View File

@ -10,6 +10,7 @@
#pragma once
#include "NetPacksBase.h"
#include "battle/BattleHex.h"
#include "GameConstants.h"
#include "int3.h"
@ -103,7 +104,7 @@ public:
virtual void heroMovePointsChanged(const CGHeroInstance * hero){} //not called at the beginning of turn and after movement
virtual void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town){};
virtual void receivedResource(){};
virtual void showInfoDialog(const std::string & text, const std::vector<Component> & components, int soundID){};
virtual void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID){};
virtual void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level){}
virtual void showShipyardDialog(const IShipyard *obj){} //obj may be town or shipyard; state: 0 - can buid, 1 - lack of resources, 2 - dest tile is blocked, 3 - no water
@ -132,7 +133,6 @@ public:
virtual void playerBlocked(int reason, bool start){}; //reason: 0 - upcoming battle
virtual void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) {}; //player lost or won the game
virtual void playerStartsTurn(PlayerColor player){};
virtual void showComp(const Component &comp, std::string message) {}; //display component in the advmapint infobox
//TODO shouldn't be moved down the tree?
virtual void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID){};

View File

@ -106,7 +106,6 @@ public:
virtual void visitBattleSetStackProperty(BattleSetStackProperty & pack) {}
virtual void visitBattleTriggerEffect(BattleTriggerEffect & pack) {}
virtual void visitBattleUpdateGateState(BattleUpdateGateState & pack) {}
virtual void visitShowInInfobox(ShowInInfobox & pack) {}
virtual void visitAdvmapSpellCast(AdvmapSpellCast & pack) {}
virtual void visitShowWorldViewEx(ShowWorldViewEx & pack) {}
virtual void visitEndTurn(EndTurn & pack) {}

View File

@ -1150,6 +1150,7 @@ struct DLL_LINKAGE NewTurn : public CPackForClient
struct DLL_LINKAGE InfoWindow : public CPackForClient //103 - displays simple info window
{
EInfoWindowMode type = EInfoWindowMode::MODAL;
MetaString text;
std::vector<Component> components;
PlayerColor player;
@ -1159,6 +1160,7 @@ struct DLL_LINKAGE InfoWindow : public CPackForClient //103 - displays simple i
template <typename Handler> void serialize(Handler & h, const int version)
{
h & type;
h & text;
h & components;
h & player;
@ -1873,22 +1875,6 @@ protected:
virtual void visitTyped(ICPackVisitor & visitor) override;
};
struct DLL_LINKAGE ShowInInfobox : public CPackForClient
{
PlayerColor player;
Component c;
MetaString text;
template <typename Handler> void serialize(Handler & h, const int version)
{
h & player;
h & c;
h & text;
}
protected:
virtual void visitTyped(ICPackVisitor & visitor) override;
};
struct DLL_LINKAGE AdvmapSpellCast : public CPackForClient
{
ObjectInstanceID casterID;

View File

@ -35,6 +35,13 @@ struct ArtSlotInfo;
class ICPackVisitor;
enum class EInfoWindowMode : uint8_t
{
AUTO,
MODAL,
INFO
};
struct DLL_LINKAGE CPack
{
std::shared_ptr<CConnection> c; // Pointer to connection that pack received from

View File

@ -492,11 +492,6 @@ void BattleUpdateGateState::visitTyped(ICPackVisitor & visitor)
visitor.visitBattleUpdateGateState(*this);
}
void ShowInInfobox::visitTyped(ICPackVisitor & visitor)
{
visitor.visitShowInInfobox(*this);
}
void AdvmapSpellCast::visitTyped(ICPackVisitor & visitor)
{
visitor.visitAdvmapSpellCast(*this);

View File

@ -881,27 +881,30 @@ void CGResource::onHeroVisit( const CGHeroInstance * h ) const
}
}
else
{
if(message.length())
{
InfoWindow iw;
iw.player = h->tempOwner;
iw.text << message;
cb->showInfoDialog(&iw);
}
collectRes(h->getOwner());
}
}
void CGResource::collectRes(const PlayerColor & player) const
{
cb->giveResource(player, static_cast<Res::ERes>(subID), amount);
ShowInInfobox sii;
InfoWindow sii;
sii.player = player;
sii.c = Component(Component::RESOURCE,subID,amount,0);
if(!message.empty())
{
sii.type = EInfoWindowMode::AUTO;
sii.text << message;
}
else
{
sii.type = EInfoWindowMode::INFO;
sii.text.addTxt(MetaString::ADVOB_TXT,113);
sii.text.addReplacement(MetaString::RES_NAMES, subID);
cb->showCompInfo(&sii);
}
sii.components.emplace_back(Component::RESOURCE,subID,amount,0);
sii.text.addTxt(MetaString::ADVOB_TXT,113);
sii.text.addReplacement(MetaString::RES_NAMES, subID);
sii.soundID = soundBase::pickup01 + CRandomGenerator::getDefault().nextInt(6);
cb->showInfoDialog(&sii);
cb->removeObject(this);
}

View File

@ -243,7 +243,6 @@ void registerTypesClientPacks1(Serializer &s)
s.template registerType<CPackForClient, NewTurn>();
s.template registerType<CPackForClient, InfoWindow>();
s.template registerType<CPackForClient, SetObjectProperty>();
s.template registerType<CPackForClient, ShowInInfobox>();
s.template registerType<CPackForClient, AdvmapSpellCast>();
s.template registerType<CPackForClient, OpenWindow>();
s.template registerType<CPackForClient, NewObject>();

View File

@ -2657,10 +2657,6 @@ void CGameHandler::takeCreatures(ObjectInstanceID objid, const std::vector<CStac
}
}
void CGameHandler::showCompInfo(ShowInInfobox * comp)
{
sendToAllClients(comp);
}
void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)
{
HeroVisitCastle vc;

View File

@ -184,7 +184,6 @@ public:
bool bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap);
void synchronizeArtifactHandlerLists();
void showCompInfo(ShowInInfobox * comp) override;
void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override;
void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override;
void startBattlePrimary(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, const CGTownInstance *town = nullptr) override; //use hero=nullptr for no hero

View File

@ -70,7 +70,6 @@ public:
void removeArtifact(const ArtifactLocation &al) override {}
bool moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) override {return false;}
void showCompInfo(ShowInInfobox * comp) override {}
void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override {}
void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override {}
void visitCastleObjects(const CGTownInstance * obj, const CGHeroInstance * hero) override {}