From d831c087d9411fa029da9bf6b1956f9b783b2dea Mon Sep 17 00:00:00 2001 From: dydzio Date: Tue, 27 Sep 2016 13:48:04 +0200 Subject: [PATCH 1/4] Extending hero info callback Allow to check battle enemy hero details + adding max spell points to available data --- lib/CGameInfoCallback.cpp | 10 ++++++++++ lib/CGameState.cpp | 1 + lib/CGameStateFwd.h | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index c0d6b4fbf..54effd756 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -273,6 +273,16 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero bool accessFlag = hasAccess(h->tempOwner); + if (!accessFlag && gs->curB) //if it's battle we can get enemy hero full data + { + ui8 playerSide = gs->curB->playerToSide(*player); + if (playerSide >= 0) + { + if (gs->curB->sides[!playerSide].hero == h) + accessFlag = true; + } + } + if(!accessFlag && nullptr != selectedObject) { const CGHeroInstance * selectedHero = dynamic_cast(selectedObject); diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index f2df3c8ed..003334b35 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -3044,6 +3044,7 @@ void InfoAboutHero::initFromHero(const CGHeroInstance *h, bool detailed) details->luck = h->LuckVal(); details->morale = h->MoraleVal(); details->mana = h->mana; + details->manaLimit = h->manaLimit(); details->primskills.resize(GameConstants::PRIMARY_SKILLS); for (int i = 0; i < GameConstants::PRIMARY_SKILLS ; i++) diff --git a/lib/CGameStateFwd.h b/lib/CGameStateFwd.h index 268300e02..be633e8f8 100644 --- a/lib/CGameStateFwd.h +++ b/lib/CGameStateFwd.h @@ -48,7 +48,7 @@ public: struct DLL_LINKAGE Details { std::vector primskills; - si32 mana, luck, morale; + si32 mana, manaLimit, luck, morale; } *details; const CHeroClass *hclass; From f621ef4ce80f2521d9a13afe0ad3bb3e00c4dcc4 Mon Sep 17 00:00:00 2001 From: dydzio Date: Tue, 27 Sep 2016 14:13:20 +0200 Subject: [PATCH 2/4] Implementing hero battle information window --- client/battle/CBattleInterfaceClasses.cpp | 71 ++++++++++++++++++++++- client/battle/CBattleInterfaceClasses.h | 19 ++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/client/battle/CBattleInterfaceClasses.cpp b/client/battle/CBattleInterfaceClasses.cpp index f14f0a8c6..afc8e3588 100644 --- a/client/battle/CBattleInterfaceClasses.cpp +++ b/client/battle/CBattleInterfaceClasses.cpp @@ -177,6 +177,15 @@ void CBattleHero::setPhase(int newPhase) nextPhase = 0; } +void CBattleHero::hover(bool on) +{ + //TODO: Make lines below work properly + if (on) + CCS->curh->changeGraphic(ECursor::COMBAT, 5); + else + CCS->curh->changeGraphic(ECursor::COMBAT, 0); +} + void CBattleHero::clickLeft(tribool down, bool previousState) { if(myOwner->spellDestSelectMode) //we are casting a spell @@ -196,6 +205,25 @@ void CBattleHero::clickLeft(tribool down, bool previousState) } } +void CBattleHero::clickRight(tribool down, bool previousState) +{ + Point windowPosition; + windowPosition.x = (!flip) ? myOwner->pos.topLeft().x + 1 : myOwner->pos.topRight().x - 79; + windowPosition.y = myOwner->pos.y + 135; + + InfoAboutHero targetHero; + + if (down && myOwner->myTurn) + { + if (myHero != nullptr) + targetHero.initFromHero(myHero, true); + else + targetHero = myOwner->enemyHero(); + + GH.pushInt(new CHeroInfoWindow(targetHero, &windowPosition)); + } +} + void CBattleHero::switchToNextPhase() { if (phase != nextPhase) @@ -247,7 +275,7 @@ CBattleHero::CBattleHero(const std::string & defName, bool flipG, PlayerColor pl CSDL_Ext::alphaTransform(elem.bitmap); graphics->blueToPlayersAdv(elem.bitmap, player); } - addUsedEvents(LCLICK); + addUsedEvents(LCLICK | RCLICK | HOVER); switchToNextPhase(); } @@ -614,6 +642,47 @@ void CClickableHex::clickRight(tribool down, bool previousState) } } +CHeroInfoWindow::CHeroInfoWindow(const InfoAboutHero &hero, Point *position) : CWindowObject(RCLICK_POPUP | SHADOW_DISABLED, "CHRPOP") +{ + OBJ_CONSTRUCTION_CAPTURING_ALL; + if (position != nullptr) + moveTo(*position); + background->colorize(hero.owner); //maybe add this functionality to base class? + + attack = hero.details->primskills[0]; + defense = hero.details->primskills[1]; + power = hero.details->primskills[2]; + knowledge = hero.details->primskills[3]; + morale = hero.details->morale; + luck = hero.details->luck; + currentSpellPoints = hero.details->mana; + maxSpellPoints = hero.details->manaLimit; + + new CAnimImage("PortraitsLarge", hero.portrait, 0, 10, 6); + + //primary stats + new CLabel(9, 75, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[380] + ":"); + new CLabel(9, 87, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[381] + ":"); + new CLabel(9, 99, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[382] + ":"); + new CLabel(9, 111, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[383] + ":"); + + new CLabel(69, 87, EFonts::FONT_TINY, EAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(attack)); + new CLabel(69, 99, EFonts::FONT_TINY, EAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(defense)); + new CLabel(69, 111, EFonts::FONT_TINY, EAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(power)); + new CLabel(69, 123, EFonts::FONT_TINY, EAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(knowledge)); + + //morale+luck + new CLabel(9, 131, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[384] + ":"); + new CLabel(9, 143, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[385] + ":"); + + new CAnimImage("IMRL22", morale + 3, 0, 47, 131); + new CAnimImage("ILCK22", luck + 3, 0, 47, 143); + + //spell points + new CLabel(39, 174, EFonts::FONT_TINY, EAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[387]); + new CLabel(39, 186, EFonts::FONT_TINY, EAlignment::CENTER, Colors::WHITE, std::to_string(currentSpellPoints) + "/" + std::to_string(maxSpellPoints)); +} + void CStackQueue::update() { stacksSorted.clear(); diff --git a/client/battle/CBattleInterfaceClasses.h b/client/battle/CBattleInterfaceClasses.h index dee453509..40e354caa 100644 --- a/client/battle/CBattleInterfaceClasses.h +++ b/client/battle/CBattleInterfaceClasses.h @@ -2,6 +2,7 @@ #include "../gui/CIntObject.h" #include "../../lib/BattleHex.h" +#include "../windows/CWindowObject.h" struct SDL_Surface; class CDefHandler; @@ -62,11 +63,29 @@ public: ui8 flagAnim, animCount; //for flag animation void show(SDL_Surface * to) override; //prints next frame of animation to to void setPhase(int newPhase); //sets phase of hero animation + void hover(bool on) override; void clickLeft(tribool down, bool previousState) override; //call-in + void clickRight(tribool down, bool previousState) override; //call-in CBattleHero(const std::string &defName, bool filpG, PlayerColor player, const CGHeroInstance *hero, const CBattleInterface *owner); //c-tor ~CBattleHero(); //d-tor }; +class CHeroInfoWindow : public CWindowObject +{ +public: + CHeroInfoWindow(const InfoAboutHero &hero, Point *position); + +private: + int attack; + int defense; + int power; + int knowledge; + int morale; + int luck; + int currentSpellPoints; + int maxSpellPoints; +}; + /// Class which manages the battle options window class CBattleOptionsWindow : public CIntObject { From f9b5ca33747e23c2dd01224bb39e4160e3bbeb9f Mon Sep 17 00:00:00 2001 From: dydzio Date: Wed, 28 Sep 2016 00:20:45 +0200 Subject: [PATCH 3/4] Remove max mana info leak + tiny refactor --- client/battle/CBattleInterfaceClasses.cpp | 16 ++++++++-------- client/battle/CBattleInterfaceClasses.h | 10 ---------- lib/CGameInfoCallback.cpp | 3 +++ 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/client/battle/CBattleInterfaceClasses.cpp b/client/battle/CBattleInterfaceClasses.cpp index afc8e3588..3bfd26527 100644 --- a/client/battle/CBattleInterfaceClasses.cpp +++ b/client/battle/CBattleInterfaceClasses.cpp @@ -649,14 +649,14 @@ CHeroInfoWindow::CHeroInfoWindow(const InfoAboutHero &hero, Point *position) : C moveTo(*position); background->colorize(hero.owner); //maybe add this functionality to base class? - attack = hero.details->primskills[0]; - defense = hero.details->primskills[1]; - power = hero.details->primskills[2]; - knowledge = hero.details->primskills[3]; - morale = hero.details->morale; - luck = hero.details->luck; - currentSpellPoints = hero.details->mana; - maxSpellPoints = hero.details->manaLimit; + int attack = hero.details->primskills[0]; + int defense = hero.details->primskills[1]; + int power = hero.details->primskills[2]; + int knowledge = hero.details->primskills[3]; + int morale = hero.details->morale; + int luck = hero.details->luck; + int currentSpellPoints = hero.details->mana; + int maxSpellPoints = hero.details->manaLimit; new CAnimImage("PortraitsLarge", hero.portrait, 0, 10, 6); diff --git a/client/battle/CBattleInterfaceClasses.h b/client/battle/CBattleInterfaceClasses.h index 40e354caa..2a1c0a1ec 100644 --- a/client/battle/CBattleInterfaceClasses.h +++ b/client/battle/CBattleInterfaceClasses.h @@ -74,16 +74,6 @@ class CHeroInfoWindow : public CWindowObject { public: CHeroInfoWindow(const InfoAboutHero &hero, Point *position); - -private: - int attack; - int defense; - int power; - int knowledge; - int morale; - int luck; - int currentSpellPoints; - int maxSpellPoints; }; /// Class which manages the battle options window diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index 54effd756..dc2a12a10 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -292,6 +292,9 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero dest.initFromHero(h, accessFlag); + if (accessFlag && !gs->curB) + dest.details->manaLimit = -1; //we do not want to leak max mana info outside battle so set to meaningless value + //DISGUISED bonus implementation if(getPlayerRelations(getLocalPlayer(), hero->tempOwner) == PlayerRelations::ENEMIES) From 68af6a0c197f2c1a61882d7ff081ddfa339e5de2 Mon Sep 17 00:00:00 2001 From: dydzio Date: Wed, 28 Sep 2016 13:22:33 +0200 Subject: [PATCH 4/4] Refactoring InfoAboutHero + GetHeroInfo --- client/battle/CBattleInterfaceClasses.cpp | 2 +- client/widgets/MiscWidgets.cpp | 4 ++-- lib/CBattleCallback.cpp | 15 +++++++++++- lib/CBattleCallback.h | 1 + lib/CGameInfoCallback.cpp | 29 +++++++++++------------ lib/CGameState.cpp | 15 ++++++++---- lib/CGameStateFwd.h | 12 ++++++++-- 7 files changed, 52 insertions(+), 26 deletions(-) diff --git a/client/battle/CBattleInterfaceClasses.cpp b/client/battle/CBattleInterfaceClasses.cpp index 3bfd26527..2246ce545 100644 --- a/client/battle/CBattleInterfaceClasses.cpp +++ b/client/battle/CBattleInterfaceClasses.cpp @@ -216,7 +216,7 @@ void CBattleHero::clickRight(tribool down, bool previousState) if (down && myOwner->myTurn) { if (myHero != nullptr) - targetHero.initFromHero(myHero, true); + targetHero.initFromHero(myHero, InfoAboutHero::EInfoLevel::INBATTLE); else targetHero = myOwner->enemyHero(); diff --git a/client/widgets/MiscWidgets.cpp b/client/widgets/MiscWidgets.cpp index 83ba3bacf..e609dc481 100644 --- a/client/widgets/MiscWidgets.cpp +++ b/client/widgets/MiscWidgets.cpp @@ -294,9 +294,9 @@ CHeroTooltip::CHeroTooltip(Point pos, const InfoAboutHero &hero): } CHeroTooltip::CHeroTooltip(Point pos, const CGHeroInstance * hero): - CArmyTooltip(pos, InfoAboutHero(hero, true)) + CArmyTooltip(pos, InfoAboutHero(hero, InfoAboutHero::EInfoLevel::DETAILED)) { - init(InfoAboutHero(hero, true)); + init(InfoAboutHero(hero, InfoAboutHero::EInfoLevel::DETAILED)); } void CTownTooltip::init(const InfoAboutTown &town) diff --git a/lib/CBattleCallback.cpp b/lib/CBattleCallback.cpp index 454f17d7d..53351c786 100644 --- a/lib/CBattleCallback.cpp +++ b/lib/CBattleCallback.cpp @@ -332,7 +332,8 @@ InfoAboutHero CBattleInfoEssentials::battleGetHeroInfo( ui8 side ) const return InfoAboutHero(); } - return InfoAboutHero(hero, battleDoWeKnowAbout(side)); + InfoAboutHero::EInfoLevel infoLevel = battleDoWeKnowAbout(side) ? InfoAboutHero::EInfoLevel::DETAILED : InfoAboutHero::EInfoLevel::BASIC; + return InfoAboutHero(hero, infoLevel); } int CBattleInfoEssentials::battleCastSpells(ui8 side) const @@ -424,6 +425,18 @@ ui8 CBattleInfoEssentials::playerToSide(PlayerColor player) const return ret; } +bool CBattleInfoEssentials::playerHasAccessToHeroInfo(PlayerColor player, const CGHeroInstance * h) const +{ + RETURN_IF_NOT_BATTLE(false); + ui8 playerSide = playerToSide(player); + if (playerSide >= 0) + { + if (getBattle()->sides[!playerSide].hero == h) + return true; + } + return false; +} + ui8 CBattleInfoEssentials::battleGetSiegeLevel() const { RETURN_IF_NOT_BATTLE(0); diff --git a/lib/CBattleCallback.h b/lib/CBattleCallback.h index ca2677ed7..0ddcedc42 100644 --- a/lib/CBattleCallback.h +++ b/lib/CBattleCallback.h @@ -190,6 +190,7 @@ public: bool battleCanFlee(PlayerColor player) const; bool battleCanSurrender(PlayerColor player) const; ui8 playerToSide(PlayerColor player) const; + bool playerHasAccessToHeroInfo(PlayerColor player, const CGHeroInstance * h) const; ui8 battleGetSiegeLevel() const; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle bool battleHasHero(ui8 side) const; int battleCastSpells(ui8 side) const; //how many spells has given side cast diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index dc2a12a10..12c43fbf7 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -271,32 +271,31 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero ERROR_RET_VAL_IF(!h, "That's not a hero!", false); ERROR_RET_VAL_IF(!isVisible(h->getPosition(false)), "That hero is not visible!", false); - bool accessFlag = hasAccess(h->tempOwner); + InfoAboutHero::EInfoLevel infoLevel = InfoAboutHero::EInfoLevel::BASIC; - if (!accessFlag && gs->curB) //if it's battle we can get enemy hero full data + if(hasAccess(h->tempOwner)) + infoLevel = InfoAboutHero::EInfoLevel::DETAILED; + + if ( (infoLevel == InfoAboutHero::EInfoLevel::BASIC) && gs->curB) //if it's battle we can get enemy hero full data { - ui8 playerSide = gs->curB->playerToSide(*player); - if (playerSide >= 0) - { - if (gs->curB->sides[!playerSide].hero == h) - accessFlag = true; - } + if(gs->curB->playerHasAccessToHeroInfo(*player, h)) + infoLevel = InfoAboutHero::EInfoLevel::INBATTLE; } - if(!accessFlag && nullptr != selectedObject) + if( (infoLevel == InfoAboutHero::EInfoLevel::BASIC) && nullptr != selectedObject) { const CGHeroInstance * selectedHero = dynamic_cast(selectedObject); if(nullptr != selectedHero) - accessFlag = selectedHero->hasVisions(hero, 1); + if(selectedHero->hasVisions(hero, 1)) + infoLevel = InfoAboutHero::EInfoLevel::DETAILED; } - dest.initFromHero(h, accessFlag); - - if (accessFlag && !gs->curB) - dest.details->manaLimit = -1; //we do not want to leak max mana info outside battle so set to meaningless value + dest.initFromHero(h, infoLevel); //DISGUISED bonus implementation + bool disguiseFlag = (infoLevel == InfoAboutHero::EInfoLevel::DETAILED); + if(getPlayerRelations(getLocalPlayer(), hero->tempOwner) == PlayerRelations::ENEMIES) { //todo: bonus cashing @@ -325,7 +324,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero } }; - auto doAdvancedDisguise = [accessFlag, &doBasicDisguise](InfoAboutHero & info) + auto doAdvancedDisguise = [disguiseFlag, &doBasicDisguise](InfoAboutHero & info) { doBasicDisguise(info); diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 003334b35..685586d7b 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -2619,7 +2619,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) continue; const CGHeroInstance * best = statsHLP::findBestHero(this, g->second.color); InfoAboutHero iah; - iah.initFromHero(best, level >= 2); + iah.initFromHero(best, (level >= 2) ? InfoAboutHero::EInfoLevel::DETAILED : InfoAboutHero::EInfoLevel::BASIC); iah.army.clear(); tgi.colorToBestHero[g->second.color] = iah; } @@ -3007,12 +3007,12 @@ InfoAboutHero::InfoAboutHero(const InfoAboutHero & iah): assign(iah); } -InfoAboutHero::InfoAboutHero(const CGHeroInstance *h, bool detailed) +InfoAboutHero::InfoAboutHero(const CGHeroInstance *h, InfoAboutHero::EInfoLevel infoLevel) : details(nullptr), hclass(nullptr), portrait(-1) { - initFromHero(h, detailed); + initFromHero(h, infoLevel); } InfoAboutHero::~InfoAboutHero() @@ -3026,11 +3026,13 @@ InfoAboutHero & InfoAboutHero::operator=(const InfoAboutHero & iah) return *this; } -void InfoAboutHero::initFromHero(const CGHeroInstance *h, bool detailed) +void InfoAboutHero::initFromHero(const CGHeroInstance *h, InfoAboutHero::EInfoLevel infoLevel) { if(!h) return; + bool detailed = ( (infoLevel == EInfoLevel::DETAILED) || (infoLevel == EInfoLevel::INBATTLE) ); + initFromArmy(h, detailed); hclass = h->type->heroClass; @@ -3044,13 +3046,16 @@ void InfoAboutHero::initFromHero(const CGHeroInstance *h, bool detailed) details->luck = h->LuckVal(); details->morale = h->MoraleVal(); details->mana = h->mana; - details->manaLimit = h->manaLimit(); details->primskills.resize(GameConstants::PRIMARY_SKILLS); for (int i = 0; i < GameConstants::PRIMARY_SKILLS ; i++) { details->primskills[i] = h->getPrimSkillLevel(static_cast(i)); } + if (infoLevel == EInfoLevel::INBATTLE) + details->manaLimit = h->manaLimit(); + else + details->manaLimit = -1; //we do not want to leak max mana info outside battle so set to meaningless value } } diff --git a/lib/CGameStateFwd.h b/lib/CGameStateFwd.h index be633e8f8..b2c4a249d 100644 --- a/lib/CGameStateFwd.h +++ b/lib/CGameStateFwd.h @@ -44,6 +44,7 @@ struct DLL_LINKAGE InfoAboutHero : public InfoAboutArmy { private: void assign(const InfoAboutHero & iah); + public: struct DLL_LINKAGE Details { @@ -54,14 +55,21 @@ public: const CHeroClass *hclass; int portrait; + enum EInfoLevel + { + BASIC, + DETAILED, + INBATTLE + }; + InfoAboutHero(); InfoAboutHero(const InfoAboutHero & iah); - InfoAboutHero(const CGHeroInstance *h, bool detailed); + InfoAboutHero(const CGHeroInstance *h, EInfoLevel infoLevel); ~InfoAboutHero(); InfoAboutHero & operator=(const InfoAboutHero & iah); - void initFromHero(const CGHeroInstance *h, bool detailed); + void initFromHero(const CGHeroInstance *h, EInfoLevel infoLevel); }; /// Struct which holds a int information about a town