mirror of
https://github.com/vcmi/vcmi.git
synced 2025-05-31 22:59:54 +02:00
Merge commit '3c844002626f48007a888d4dd8b0b45ec867fc9a' into feature/VCMIMapFormat1
Conflicts: lib/mapObjects/CGHeroInstance.cpp
This commit is contained in:
commit
1bc41b3ba3
@ -1933,7 +1933,7 @@ void CBattleInterface::bTacticNextStack(const CStack *current /*= nullptr*/)
|
|||||||
waitForAnims();
|
waitForAnims();
|
||||||
|
|
||||||
TStacks stacksOfMine = tacticianInterface->cb->battleGetStacks(CBattleCallback::ONLY_MINE);
|
TStacks stacksOfMine = tacticianInterface->cb->battleGetStacks(CBattleCallback::ONLY_MINE);
|
||||||
stacksOfMine.erase(std::remove_if(stacksOfMine.begin(), stacksOfMine.end(), &immobile), stacksOfMine.end());
|
vstd::erase_if(stacksOfMine, &immobile);
|
||||||
auto it = vstd::find(stacksOfMine, current);
|
auto it = vstd::find(stacksOfMine, current);
|
||||||
if(it != stacksOfMine.end() && ++it != stacksOfMine.end())
|
if(it != stacksOfMine.end() && ++it != stacksOfMine.end())
|
||||||
stackActivated(*it);
|
stackActivated(*it);
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
CArtPlace::CArtPlace(Point position, const CArtifactInstance * Art):
|
CArtPlace::CArtPlace(Point position, const CArtifactInstance * Art):
|
||||||
locked(false), picked(false), marked(false), ourArt(Art)
|
locked(false), picked(false), marked(false), ourArt(Art)
|
||||||
{
|
{
|
||||||
pos += position;
|
pos += position;
|
||||||
pos.w = pos.h = 44;
|
pos.w = pos.h = 44;
|
||||||
@ -180,7 +180,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
|
|||||||
if(srcInBackpack && srcInSameHero)
|
if(srcInBackpack && srcInSameHero)
|
||||||
{
|
{
|
||||||
if(!ourArt //cannot move from backpack to AFTER backpack -> combined with vstd::amin above it will guarantee that dest is at most the last artifact
|
if(!ourArt //cannot move from backpack to AFTER backpack -> combined with vstd::amin above it will guarantee that dest is at most the last artifact
|
||||||
|| ourOwner->commonInfo->src.slotID < ourOwner->commonInfo->dst.slotID) //rearranging arts in backpack after taking src artifact, the dest id will be shifted
|
|| ourOwner->commonInfo->src.slotID < ourOwner->commonInfo->dst.slotID) //rearranging arts in backpack after taking src artifact, the dest id will be shifted
|
||||||
vstd::advance(ourOwner->commonInfo->dst.slotID, -1);
|
vstd::advance(ourOwner->commonInfo->dst.slotID, -1);
|
||||||
}
|
}
|
||||||
if(srcInSameHero && ourOwner->commonInfo->dst.slotID == ourOwner->commonInfo->src.slotID) //we came to src == dst
|
if(srcInSameHero && ourOwner->commonInfo->dst.slotID == ourOwner->commonInfo->src.slotID) //we came to src == dst
|
||||||
@ -386,70 +386,36 @@ void CArtPlace::setArtifact(const CArtifactInstance *art)
|
|||||||
image->disable();
|
image->disable();
|
||||||
text = std::string();
|
text = std::string();
|
||||||
hoverText = CGI->generaltexth->allTexts[507];
|
hoverText = CGI->generaltexth->allTexts[507];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
image->enable();
|
||||||
|
image->setFrame(locked ? ArtifactID::ART_LOCK : art->artType->iconIndex);
|
||||||
|
|
||||||
|
text = art->getEffectiveDescription(ourOwner->curHero);
|
||||||
|
|
||||||
|
if(art->artType->id == ArtifactID::SPELL_SCROLL)
|
||||||
|
{
|
||||||
|
int spellID = art->getGivenSpellID();
|
||||||
|
if(spellID >= 0)
|
||||||
|
{
|
||||||
|
//add spell component info (used to provide a pic in r-click popup)
|
||||||
|
baseType = CComponent::spell;
|
||||||
|
type = spellID;
|
||||||
|
bonusValue = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
image->enable();
|
baseType = CComponent::artifact;
|
||||||
image->setFrame(locked ? ArtifactID::ART_LOCK : art->artType->iconIndex);
|
type = art->artType->id;
|
||||||
|
bonusValue = 0;
|
||||||
std::string artDesc = ourArt->artType->Description();
|
|
||||||
if (vstd::contains (artDesc, '{'))
|
|
||||||
text = artDesc;
|
|
||||||
else
|
|
||||||
text = '{' + ourArt->artType->Name() + "}\n\n" + artDesc; //workaround for new artifacts with single name, turns it to H3-style
|
|
||||||
|
|
||||||
if(art->artType->id == ArtifactID::SPELL_SCROLL)
|
|
||||||
{
|
|
||||||
// we expect scroll description to be like this: This scroll contains the [spell name] spell which is added into your spell book for as long as you carry the scroll.
|
|
||||||
// so we want to replace text in [...] with a spell name
|
|
||||||
// however other language versions don't have name placeholder at all, so we have to be careful
|
|
||||||
int spellID = art->getGivenSpellID();
|
|
||||||
size_t nameStart = text.find_first_of('[');
|
|
||||||
size_t nameEnd = text.find_first_of(']', nameStart);
|
|
||||||
if(spellID >= 0)
|
|
||||||
{
|
|
||||||
if(nameStart != std::string::npos && nameEnd != std::string::npos)
|
|
||||||
text = text.replace(nameStart, nameEnd - nameStart + 1, CGI->spellh->objects[spellID]->name);
|
|
||||||
|
|
||||||
//add spell component info (used to provide a pic in r-click popup)
|
|
||||||
baseType = CComponent::spell;
|
|
||||||
type = spellID;
|
|
||||||
bonusValue = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
baseType = CComponent::artifact;
|
|
||||||
type = art->artType->id;
|
|
||||||
bonusValue = 0;
|
|
||||||
}
|
|
||||||
if (art->artType->constituents) //display info about components of combined artifact
|
|
||||||
{
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
else if (art->artType->constituentOf.size()) //display info about set
|
|
||||||
{
|
|
||||||
std::string artList;
|
|
||||||
auto combinedArt = art->artType->constituentOf[0];
|
|
||||||
text += "\n\n";
|
|
||||||
text += "{" + combinedArt->Name() + "}";
|
|
||||||
int wornArtifacts = 0;
|
|
||||||
for (auto a : *combinedArt->constituents) //TODO: can the artifact be a part of more than one set?
|
|
||||||
{
|
|
||||||
artList += "\n" + a->Name();
|
|
||||||
if (ourOwner->curHero->hasArt(a->id, true))
|
|
||||||
wornArtifacts++;
|
|
||||||
}
|
|
||||||
text += " (" + boost::str(boost::format("%d") % wornArtifacts) + " / " +
|
|
||||||
boost::str(boost::format("%d") % combinedArt->constituents->size()) + ")" + artList;
|
|
||||||
//TODO: fancy colors and fonts for this text
|
|
||||||
}
|
|
||||||
|
|
||||||
if (locked) // Locks should appear as empty.
|
|
||||||
hoverText = CGI->generaltexth->allTexts[507];
|
|
||||||
else
|
|
||||||
hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1]) % ourArt->artType->Name());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (locked) // Locks should appear as empty.
|
||||||
|
hoverText = CGI->generaltexth->allTexts[507];
|
||||||
|
else
|
||||||
|
hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1]) % ourArt->artType->Name());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CArtifactsOfHero::SCommonPart::reset()
|
void CArtifactsOfHero::SCommonPart::reset()
|
||||||
@ -811,7 +777,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
|
|||||||
}
|
}
|
||||||
else if(src.slot >= GameConstants::BACKPACK_START &&
|
else if(src.slot >= GameConstants::BACKPACK_START &&
|
||||||
src.slot < commonInfo->src.slotID &&
|
src.slot < commonInfo->src.slotID &&
|
||||||
src.isHolder(commonInfo->src.AOH->curHero)) //artifact taken from before currently picked one
|
src.isHolder(commonInfo->src.AOH->curHero)) //artifact taken from before currently picked one
|
||||||
{
|
{
|
||||||
//int fixedSlot = src.hero->getArtPos(commonInfo->src.art);
|
//int fixedSlot = src.hero->getArtPos(commonInfo->src.art);
|
||||||
vstd::advance(commonInfo->src.slotID, -1);
|
vstd::advance(commonInfo->src.slotID, -1);
|
||||||
@ -825,14 +791,14 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateParentWindow();
|
updateParentWindow();
|
||||||
int shift = 0;
|
int shift = 0;
|
||||||
// if(dst.slot >= Arts::BACKPACK_START && dst.slot - Arts::BACKPACK_START < backpackPos)
|
// if(dst.slot >= Arts::BACKPACK_START && dst.slot - Arts::BACKPACK_START < backpackPos)
|
||||||
// shift++;
|
// shift++;
|
||||||
//
|
//
|
||||||
if(src.slot < GameConstants::BACKPACK_START && dst.slot - GameConstants::BACKPACK_START < backpackPos)
|
if(src.slot < GameConstants::BACKPACK_START && dst.slot - GameConstants::BACKPACK_START < backpackPos)
|
||||||
shift++;
|
shift++;
|
||||||
if(dst.slot < GameConstants::BACKPACK_START && src.slot - GameConstants::BACKPACK_START < backpackPos)
|
if(dst.slot < GameConstants::BACKPACK_START && src.slot - GameConstants::BACKPACK_START < backpackPos)
|
||||||
shift--;
|
shift--;
|
||||||
|
|
||||||
if( (isCurHeroSrc && src.slot >= GameConstants::BACKPACK_START)
|
if( (isCurHeroSrc && src.slot >= GameConstants::BACKPACK_START)
|
||||||
|| (isCurHeroDst && dst.slot >= GameConstants::BACKPACK_START) )
|
|| (isCurHeroDst && dst.slot >= GameConstants::BACKPACK_START) )
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "../CMessage.h"
|
#include "../CMessage.h"
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../widgets/Images.h"
|
#include "../widgets/Images.h"
|
||||||
|
#include "../widgets/CArtifactHolder.h"
|
||||||
#include "../windows/CAdvmapInterface.h"
|
#include "../windows/CAdvmapInterface.h"
|
||||||
|
|
||||||
#include "../../lib/CArtHandler.h"
|
#include "../../lib/CArtHandler.h"
|
||||||
@ -144,14 +145,26 @@ size_t CComponent::getIndex()
|
|||||||
|
|
||||||
std::string CComponent::getDescription()
|
std::string CComponent::getDescription()
|
||||||
{
|
{
|
||||||
switch (compType)
|
switch(compType)
|
||||||
{
|
{
|
||||||
case primskill: return (subtype < 4)? CGI->generaltexth->arraytxt[2+subtype] //Primary skill
|
case primskill: return (subtype < 4)? CGI->generaltexth->arraytxt[2+subtype] //Primary skill
|
||||||
: CGI->generaltexth->allTexts[149]; //mana
|
: CGI->generaltexth->allTexts[149]; //mana
|
||||||
case secskill: return CGI->generaltexth->skillInfoTexts[subtype][val-1];
|
case secskill: return CGI->generaltexth->skillInfoTexts[subtype][val-1];
|
||||||
case resource: return CGI->generaltexth->allTexts[242];
|
case resource: return CGI->generaltexth->allTexts[242];
|
||||||
case creature: return "";
|
case creature: return "";
|
||||||
case artifact: return CGI->arth->artifacts[subtype]->Description();
|
case artifact:
|
||||||
|
{
|
||||||
|
std::unique_ptr<CArtifactInstance> art;
|
||||||
|
if (subtype != ArtifactID::SPELL_SCROLL)
|
||||||
|
{
|
||||||
|
art.reset(CArtifactInstance::createNewArtifactInstance(subtype));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
art.reset(CArtifactInstance::createScroll(static_cast<SpellID>(val)));
|
||||||
|
}
|
||||||
|
return art->getEffectiveDescription();
|
||||||
|
}
|
||||||
case experience: return CGI->generaltexth->allTexts[241];
|
case experience: return CGI->generaltexth->allTexts[241];
|
||||||
case spell: return CGI->spellh->objects[subtype]->getLevelInfo(val).description;
|
case spell: return CGI->spellh->objects[subtype]->getLevelInfo(val).description;
|
||||||
case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
|
case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
|
||||||
@ -166,7 +179,7 @@ std::string CComponent::getDescription()
|
|||||||
|
|
||||||
std::string CComponent::getSubtitle()
|
std::string CComponent::getSubtitle()
|
||||||
{
|
{
|
||||||
if (!perDay)
|
if(!perDay)
|
||||||
return getSubtitleInternal();
|
return getSubtitleInternal();
|
||||||
|
|
||||||
std::string ret = CGI->generaltexth->allTexts[3];
|
std::string ret = CGI->generaltexth->allTexts[3];
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "../lib/CHeroHandler.h"
|
#include "../lib/CHeroHandler.h"
|
||||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||||
#include "../lib/NetPacksBase.h"
|
#include "../lib/NetPacksBase.h"
|
||||||
|
#include "../mapHandler.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CHeroWindow.cpp, part of VCMI engine
|
* CHeroWindow.cpp, part of VCMI engine
|
||||||
@ -275,6 +276,9 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
|
|||||||
if(!LOCPLINT->cb->howManyTowns() && LOCPLINT->cb->howManyHeroes() == 1)
|
if(!LOCPLINT->cb->howManyTowns() && LOCPLINT->cb->howManyHeroes() == 1)
|
||||||
noDismiss = true;
|
noDismiss = true;
|
||||||
|
|
||||||
|
if(curHero->isMissionCritical())
|
||||||
|
noDismiss = true;
|
||||||
|
|
||||||
dismissButton->block(!!curHero->visitedTown || noDismiss);
|
dismissButton->block(!!curHero->visitedTown || noDismiss);
|
||||||
|
|
||||||
if(curHero->getSecSkillLevel(SecondarySkill::TACTICS) == 0)
|
if(curHero->getSecSkillLevel(SecondarySkill::TACTICS) == 0)
|
||||||
|
@ -269,7 +269,7 @@ void CTradeWindow::CTradeableItem::clickRight(tribool down, bool previousState)
|
|||||||
case ARTIFACT_TYPE:
|
case ARTIFACT_TYPE:
|
||||||
case ARTIFACT_PLACEHOLDER:
|
case ARTIFACT_PLACEHOLDER:
|
||||||
if(id >= 0)
|
if(id >= 0)
|
||||||
adventureInt->handleRightClick(CGI->arth->artifacts[id]->Description(), down);
|
adventureInt->handleRightClick(hlp->getEffectiveDescription(), down);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
"ALL_CREATURES_GET_DOUBLE_MONTHS" : false,
|
"ALL_CREATURES_GET_DOUBLE_MONTHS" : false,
|
||||||
"NEGATIVE_LUCK" : false,
|
"NEGATIVE_LUCK" : false,
|
||||||
"MAX_HEROES_AVAILABLE_PER_PLAYER" : 16,
|
"MAX_HEROES_AVAILABLE_PER_PLAYER" : 16,
|
||||||
"MAX_HEROES_ON_MAP_PER_PLAYER" : 8
|
"MAX_HEROES_ON_MAP_PER_PLAYER" : 8,
|
||||||
|
"WINNING_HERO_WITH_NO_TROOPS_RETREATS": true
|
||||||
|
|
||||||
},
|
},
|
||||||
"modules":
|
"modules":
|
||||||
|
@ -764,9 +764,14 @@ std::string CArtifactInstance::nodeName() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
CArtifactInstance * CArtifactInstance::createScroll( const CSpell *s)
|
CArtifactInstance * CArtifactInstance::createScroll( const CSpell *s)
|
||||||
|
{
|
||||||
|
return createScroll(s->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArtifactInstance *CArtifactInstance::createScroll(SpellID sid)
|
||||||
{
|
{
|
||||||
auto ret = new CArtifactInstance(VLC->arth->artifacts[ArtifactID::SPELL_SCROLL]);
|
auto ret = new CArtifactInstance(VLC->arth->artifacts[ArtifactID::SPELL_SCROLL]);
|
||||||
auto b = new Bonus(Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT_INSTANCE, -1, ArtifactID::SPELL_SCROLL, s->id);
|
auto b = new Bonus(Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT_INSTANCE, -1, ArtifactID::SPELL_SCROLL, sid);
|
||||||
ret->addNewBonus(b);
|
ret->addNewBonus(b);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -778,6 +783,48 @@ void CArtifactInstance::init()
|
|||||||
setNodeType(ARTIFACT_INSTANCE);
|
setNodeType(ARTIFACT_INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CArtifactInstance::getEffectiveDescription(
|
||||||
|
const CGHeroInstance *hero) const
|
||||||
|
{
|
||||||
|
std::string text = artType->Description();
|
||||||
|
if (!vstd::contains(text, '{'))
|
||||||
|
text = '{' + artType->Name() + "}\n\n" + text; //workaround for new artifacts with single name, turns it to H3-style
|
||||||
|
|
||||||
|
if(artType->id == ArtifactID::SPELL_SCROLL)
|
||||||
|
{
|
||||||
|
// we expect scroll description to be like this: This scroll contains the [spell name] spell which is added into your spell book for as long as you carry the scroll.
|
||||||
|
// so we want to replace text in [...] with a spell name
|
||||||
|
// however other language versions don't have name placeholder at all, so we have to be careful
|
||||||
|
int spellID = getGivenSpellID();
|
||||||
|
size_t nameStart = text.find_first_of('[');
|
||||||
|
size_t nameEnd = text.find_first_of(']', nameStart);
|
||||||
|
if(spellID >= 0)
|
||||||
|
{
|
||||||
|
if(nameStart != std::string::npos && nameEnd != std::string::npos)
|
||||||
|
text = text.replace(nameStart, nameEnd - nameStart + 1, VLC->spellh->objects[spellID]->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (hero && artType->constituentOf.size()) //display info about set
|
||||||
|
{
|
||||||
|
std::string artList;
|
||||||
|
auto combinedArt = artType->constituentOf[0];
|
||||||
|
text += "\n\n";
|
||||||
|
text += "{" + combinedArt->Name() + "}";
|
||||||
|
int wornArtifacts = 0;
|
||||||
|
for (auto a : *combinedArt->constituents) //TODO: can the artifact be a part of more than one set?
|
||||||
|
{
|
||||||
|
artList += "\n" + a->Name();
|
||||||
|
if (hero->hasArt(a->id, true))
|
||||||
|
wornArtifacts++;
|
||||||
|
}
|
||||||
|
text += " (" + boost::str(boost::format("%d") % wornArtifacts) + " / " +
|
||||||
|
boost::str(boost::format("%d") % combinedArt->constituents->size()) + ")" + artList;
|
||||||
|
//TODO: fancy colors and fonts for this text
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
ArtifactPosition CArtifactInstance::firstAvailableSlot(const CArtifactSet *h) const
|
ArtifactPosition CArtifactInstance::firstAvailableSlot(const CArtifactSet *h) const
|
||||||
{
|
{
|
||||||
for(auto slot : artType->possibleSlots.at(h->bearerType()))
|
for(auto slot : artType->possibleSlots.at(h->bearerType()))
|
||||||
@ -926,7 +973,7 @@ SpellID CArtifactInstance::getGivenSpellID() const
|
|||||||
const Bonus * b = getBonusLocalFirst(Selector::type(Bonus::SPELL));
|
const Bonus * b = getBonusLocalFirst(Selector::type(Bonus::SPELL));
|
||||||
if(!b)
|
if(!b)
|
||||||
{
|
{
|
||||||
logGlobal->warnStream() << "Warning: " << nodeName() << " doesn't bear any spell!";
|
logGlobal->warnStream() << "Warning: " << nodeName() << " doesn't bear any spell!";
|
||||||
return SpellID::NONE;
|
return SpellID::NONE;
|
||||||
}
|
}
|
||||||
return SpellID(b->subtype);
|
return SpellID(b->subtype);
|
||||||
|
@ -124,6 +124,7 @@ public:
|
|||||||
void deserializationFix();
|
void deserializationFix();
|
||||||
void setType(CArtifact *Art);
|
void setType(CArtifact *Art);
|
||||||
|
|
||||||
|
std::string getEffectiveDescription(const CGHeroInstance *hero = nullptr) const;
|
||||||
ArtifactPosition firstAvailableSlot(const CArtifactSet *h) const;
|
ArtifactPosition firstAvailableSlot(const CArtifactSet *h) const;
|
||||||
ArtifactPosition firstBackpackSlot(const CArtifactSet *h) const;
|
ArtifactPosition firstBackpackSlot(const CArtifactSet *h) const;
|
||||||
SpellID getGivenSpellID() const; //to be used with scrolls (and similar arts), -1 if none
|
SpellID getGivenSpellID() const; //to be used with scrolls (and similar arts), -1 if none
|
||||||
@ -148,6 +149,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static CArtifactInstance *createScroll(const CSpell *s);
|
static CArtifactInstance *createScroll(const CSpell *s);
|
||||||
|
static CArtifactInstance *createScroll(SpellID sid);
|
||||||
static CArtifactInstance *createNewArtifactInstance(CArtifact *Art);
|
static CArtifactInstance *createNewArtifactInstance(CArtifact *Art);
|
||||||
static CArtifactInstance *createNewArtifactInstance(int aid);
|
static CArtifactInstance *createNewArtifactInstance(int aid);
|
||||||
};
|
};
|
||||||
|
@ -66,6 +66,10 @@ const PlayerState * CGameInfoCallback::getPlayer(PlayerColor color, bool verbose
|
|||||||
{
|
{
|
||||||
//funtion written from scratch since it's accessed A LOT by AI
|
//funtion written from scratch since it's accessed A LOT by AI
|
||||||
|
|
||||||
|
if(!color.isValidPlayer())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
auto player = gs->players.find(color);
|
auto player = gs->players.find(color);
|
||||||
if (player != gs->players.end())
|
if (player != gs->players.end())
|
||||||
{
|
{
|
||||||
@ -964,4 +968,3 @@ void IGameEventRealizer::setObjProperty(ObjectInstanceID objid, int prop, si64 v
|
|||||||
sob.val = static_cast<ui32>(val);
|
sob.val = static_cast<ui32>(val);
|
||||||
commitPackage(&sob);
|
commitPackage(&sob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,8 +1219,8 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar
|
|||||||
// remove heroes which didn't reached the end of the scenario, but were available at the start
|
// remove heroes which didn't reached the end of the scenario, but were available at the start
|
||||||
for(auto hero : lostCrossoverHeroes)
|
for(auto hero : lostCrossoverHeroes)
|
||||||
{
|
{
|
||||||
crossoverHeroes.heroesFromAnyPreviousScenarios.erase(range::remove_if(crossoverHeroes.heroesFromAnyPreviousScenarios,
|
vstd::erase_if(crossoverHeroes.heroesFromAnyPreviousScenarios,
|
||||||
CGObjectInstanceBySubIdFinder(hero)), crossoverHeroes.heroesFromAnyPreviousScenarios.end());
|
CGObjectInstanceBySubIdFinder(hero));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now add heroes which completed the scenario
|
// now add heroes which completed the scenario
|
||||||
@ -2268,7 +2268,7 @@ EVictoryLossCheckResult CGameState::checkForVictoryAndLoss(PlayerColor player) c
|
|||||||
|
|
||||||
for (const TriggeredEvent & event : map->triggeredEvents)
|
for (const TriggeredEvent & event : map->triggeredEvents)
|
||||||
{
|
{
|
||||||
if ((event.trigger.test(evaluateEvent)))
|
if (event.trigger.test(evaluateEvent))
|
||||||
{
|
{
|
||||||
if (event.effect.type == EventEffect::VICTORY)
|
if (event.effect.type == EventEffect::VICTORY)
|
||||||
return EVictoryLossCheckResult::victory(event.onFulfill, event.effect.toOtherMessage);
|
return EVictoryLossCheckResult::victory(event.onFulfill, event.effect.toOtherMessage);
|
||||||
@ -2285,7 +2285,7 @@ EVictoryLossCheckResult CGameState::checkForVictoryAndLoss(PlayerColor player) c
|
|||||||
return EVictoryLossCheckResult();
|
return EVictoryLossCheckResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameState::checkForVictory( PlayerColor player, const EventCondition & condition ) const
|
bool CGameState::checkForVictory(PlayerColor player, const EventCondition & condition) const
|
||||||
{
|
{
|
||||||
const PlayerState *p = CGameInfoCallback::getPlayer(player);
|
const PlayerState *p = CGameInfoCallback::getPlayer(player);
|
||||||
switch (condition.condition)
|
switch (condition.condition)
|
||||||
|
@ -551,21 +551,42 @@ CModHandler::CModHandler()
|
|||||||
|
|
||||||
void CModHandler::loadConfigFromFile (std::string name)
|
void CModHandler::loadConfigFromFile (std::string name)
|
||||||
{
|
{
|
||||||
|
std::string paths;
|
||||||
|
for(auto& p : CResourceHandler::get()->getResourceNames(ResourceID("config/" + name)))
|
||||||
|
{
|
||||||
|
paths += p + ", ";
|
||||||
|
}
|
||||||
|
paths = paths.substr(0, paths.size() - 2);
|
||||||
|
logGlobal->debugStream() << "Loading hardcoded features settings from [" << paths << "], result:";
|
||||||
settings.data = JsonUtils::assembleFromFiles("config/" + name);
|
settings.data = JsonUtils::assembleFromFiles("config/" + name);
|
||||||
const JsonNode & hardcodedFeatures = settings.data["hardcodedFeatures"];
|
const JsonNode & hardcodedFeatures = settings.data["hardcodedFeatures"];
|
||||||
settings.MAX_HEROES_AVAILABLE_PER_PLAYER = hardcodedFeatures["MAX_HEROES_AVAILABLE_PER_PLAYER"].Float();
|
settings.MAX_HEROES_AVAILABLE_PER_PLAYER = hardcodedFeatures["MAX_HEROES_AVAILABLE_PER_PLAYER"].Float();
|
||||||
|
logGlobal->debugStream() << "\tMAX_HEROES_AVAILABLE_PER_PLAYER\t" << settings.MAX_HEROES_AVAILABLE_PER_PLAYER;
|
||||||
settings.MAX_HEROES_ON_MAP_PER_PLAYER = hardcodedFeatures["MAX_HEROES_ON_MAP_PER_PLAYER"].Float();
|
settings.MAX_HEROES_ON_MAP_PER_PLAYER = hardcodedFeatures["MAX_HEROES_ON_MAP_PER_PLAYER"].Float();
|
||||||
|
logGlobal->debugStream() << "\tMAX_HEROES_ON_MAP_PER_PLAYER\t" << settings.MAX_HEROES_ON_MAP_PER_PLAYER;
|
||||||
settings.CREEP_SIZE = hardcodedFeatures["CREEP_SIZE"].Float();
|
settings.CREEP_SIZE = hardcodedFeatures["CREEP_SIZE"].Float();
|
||||||
|
logGlobal->debugStream() << "\tCREEP_SIZE\t" << settings.CREEP_SIZE;
|
||||||
settings.WEEKLY_GROWTH = hardcodedFeatures["WEEKLY_GROWTH_PERCENT"].Float();
|
settings.WEEKLY_GROWTH = hardcodedFeatures["WEEKLY_GROWTH_PERCENT"].Float();
|
||||||
|
logGlobal->debugStream() << "\tWEEKLY_GROWTH\t" << settings.WEEKLY_GROWTH;
|
||||||
settings.NEUTRAL_STACK_EXP = hardcodedFeatures["NEUTRAL_STACK_EXP_DAILY"].Float();
|
settings.NEUTRAL_STACK_EXP = hardcodedFeatures["NEUTRAL_STACK_EXP_DAILY"].Float();
|
||||||
|
logGlobal->debugStream() << "\tNEUTRAL_STACK_EXP\t" << settings.NEUTRAL_STACK_EXP;
|
||||||
settings.MAX_BUILDING_PER_TURN = hardcodedFeatures["MAX_BUILDING_PER_TURN"].Float();
|
settings.MAX_BUILDING_PER_TURN = hardcodedFeatures["MAX_BUILDING_PER_TURN"].Float();
|
||||||
|
logGlobal->debugStream() << "\tMAX_BUILDING_PER_TURN\t" << settings.MAX_BUILDING_PER_TURN;
|
||||||
settings.DWELLINGS_ACCUMULATE_CREATURES = hardcodedFeatures["DWELLINGS_ACCUMULATE_CREATURES"].Bool();
|
settings.DWELLINGS_ACCUMULATE_CREATURES = hardcodedFeatures["DWELLINGS_ACCUMULATE_CREATURES"].Bool();
|
||||||
|
logGlobal->debugStream() << "\tDWELLINGS_ACCUMULATE_CREATURES\t" << settings.DWELLINGS_ACCUMULATE_CREATURES;
|
||||||
settings.ALL_CREATURES_GET_DOUBLE_MONTHS = hardcodedFeatures["ALL_CREATURES_GET_DOUBLE_MONTHS"].Bool();
|
settings.ALL_CREATURES_GET_DOUBLE_MONTHS = hardcodedFeatures["ALL_CREATURES_GET_DOUBLE_MONTHS"].Bool();
|
||||||
|
logGlobal->debugStream() << "\tALL_CREATURES_GET_DOUBLE_MONTHS\t" << settings.ALL_CREATURES_GET_DOUBLE_MONTHS;
|
||||||
|
settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS = hardcodedFeatures["WINNING_HERO_WITH_NO_TROOPS_RETREATS"].Bool();
|
||||||
|
logGlobal->debugStream() << "\tWINNING_HERO_WITH_NO_TROOPS_RETREATS\t" << settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS;
|
||||||
const JsonNode & gameModules = settings.data["modules"];
|
const JsonNode & gameModules = settings.data["modules"];
|
||||||
modules.STACK_EXP = gameModules["STACK_EXPERIENCE"].Bool();
|
modules.STACK_EXP = gameModules["STACK_EXPERIENCE"].Bool();
|
||||||
|
logGlobal->debugStream() << "\tSTACK_EXP\t" << modules.STACK_EXP;
|
||||||
modules.STACK_ARTIFACT = gameModules["STACK_ARTIFACTS"].Bool();
|
modules.STACK_ARTIFACT = gameModules["STACK_ARTIFACTS"].Bool();
|
||||||
|
logGlobal->debugStream() << "\tSTACK_ARTIFACT\t" << modules.STACK_ARTIFACT;
|
||||||
modules.COMMANDERS = gameModules["COMMANDERS"].Bool();
|
modules.COMMANDERS = gameModules["COMMANDERS"].Bool();
|
||||||
|
logGlobal->debugStream() << "\tCOMMANDERS\t" << modules.COMMANDERS;
|
||||||
modules.MITHRIL = gameModules["MITHRIL"].Bool();
|
modules.MITHRIL = gameModules["MITHRIL"].Bool();
|
||||||
|
logGlobal->debugStream() << "\tMITHRIL\t" << modules.MITHRIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// currentList is passed by value to get current list of depending mods
|
// currentList is passed by value to get current list of depending mods
|
||||||
|
@ -259,11 +259,21 @@ public:
|
|||||||
bool ALL_CREATURES_GET_DOUBLE_MONTHS;
|
bool ALL_CREATURES_GET_DOUBLE_MONTHS;
|
||||||
int MAX_HEROES_AVAILABLE_PER_PLAYER;
|
int MAX_HEROES_AVAILABLE_PER_PLAYER;
|
||||||
int MAX_HEROES_ON_MAP_PER_PLAYER;
|
int MAX_HEROES_ON_MAP_PER_PLAYER;
|
||||||
|
bool WINNING_HERO_WITH_NO_TROOPS_RETREATS;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & data & CREEP_SIZE & WEEKLY_GROWTH & NEUTRAL_STACK_EXP & MAX_BUILDING_PER_TURN;
|
h & data & CREEP_SIZE & WEEKLY_GROWTH & NEUTRAL_STACK_EXP & MAX_BUILDING_PER_TURN;
|
||||||
h & DWELLINGS_ACCUMULATE_CREATURES & ALL_CREATURES_GET_DOUBLE_MONTHS & MAX_HEROES_AVAILABLE_PER_PLAYER & MAX_HEROES_ON_MAP_PER_PLAYER;
|
h & DWELLINGS_ACCUMULATE_CREATURES & ALL_CREATURES_GET_DOUBLE_MONTHS &
|
||||||
|
MAX_HEROES_AVAILABLE_PER_PLAYER & MAX_HEROES_ON_MAP_PER_PLAYER;
|
||||||
|
if(version >= 756)
|
||||||
|
{
|
||||||
|
h & WINNING_HERO_WITH_NO_TROOPS_RETREATS;
|
||||||
|
}
|
||||||
|
else if(!h.saving)
|
||||||
|
{
|
||||||
|
WINNING_HERO_WITH_NO_TROOPS_RETREATS = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
|
@ -56,6 +56,15 @@ JsonNode::JsonNode(ResourceID && fileURI):
|
|||||||
*this = parser.parse(fileURI.getName());
|
*this = parser.parse(fileURI.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JsonNode::JsonNode(const ResourceID & fileURI):
|
||||||
|
type(DATA_NULL)
|
||||||
|
{
|
||||||
|
auto file = CResourceHandler::get()->load(fileURI)->readAll();
|
||||||
|
|
||||||
|
JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second);
|
||||||
|
*this = parser.parse(fileURI.getName());
|
||||||
|
}
|
||||||
|
|
||||||
JsonNode::JsonNode(ResourceID && fileURI, bool &isValidSyntax):
|
JsonNode::JsonNode(ResourceID && fileURI, bool &isValidSyntax):
|
||||||
type(DATA_NULL)
|
type(DATA_NULL)
|
||||||
{
|
{
|
||||||
|
@ -55,6 +55,7 @@ public:
|
|||||||
explicit JsonNode(const char * data, size_t datasize);
|
explicit JsonNode(const char * data, size_t datasize);
|
||||||
//Create tree from JSON file
|
//Create tree from JSON file
|
||||||
explicit JsonNode(ResourceID && fileURI);
|
explicit JsonNode(ResourceID && fileURI);
|
||||||
|
explicit JsonNode(const ResourceID & fileURI);
|
||||||
explicit JsonNode(ResourceID && fileURI, bool & isValidSyntax);
|
explicit JsonNode(ResourceID && fileURI, bool & isValidSyntax);
|
||||||
//Copy c-tor
|
//Copy c-tor
|
||||||
JsonNode(const JsonNode ©);
|
JsonNode(const JsonNode ©);
|
||||||
|
@ -362,6 +362,10 @@ DLL_LINKAGE void RemoveObject::applyGs( CGameState *gs )
|
|||||||
p->heroes -= h;
|
p->heroes -= h;
|
||||||
h->detachFrom(h->whereShouldBeAttached(gs));
|
h->detachFrom(h->whereShouldBeAttached(gs));
|
||||||
h->tempOwner = PlayerColor::NEUTRAL; //no one owns beaten hero
|
h->tempOwner = PlayerColor::NEUTRAL; //no one owns beaten hero
|
||||||
|
vstd::erase_if(h->artifactsInBackpack, [](const ArtSlotInfo& asi)
|
||||||
|
{
|
||||||
|
return asi.artifact->artType->id == ArtifactID::GRAIL;
|
||||||
|
});
|
||||||
|
|
||||||
if(h->visitedTown)
|
if(h->visitedTown)
|
||||||
{
|
{
|
||||||
@ -590,7 +594,11 @@ DLL_LINKAGE void HeroRecruited::applyGs( CGameState *gs )
|
|||||||
|
|
||||||
h->setOwner(player);
|
h->setOwner(player);
|
||||||
h->pos = tile;
|
h->pos = tile;
|
||||||
h->movement = h->maxMovePoints(true);
|
bool fresh = !h->isInitialized();
|
||||||
|
if(fresh)
|
||||||
|
{ // this is a fresh hero who hasn't appeared yet
|
||||||
|
h->movement = h->maxMovePoints(true);
|
||||||
|
}
|
||||||
|
|
||||||
gs->hpool.heroesPool.erase(hid);
|
gs->hpool.heroesPool.erase(hid);
|
||||||
if(h->id == ObjectInstanceID())
|
if(h->id == ObjectInstanceID())
|
||||||
@ -604,7 +612,10 @@ DLL_LINKAGE void HeroRecruited::applyGs( CGameState *gs )
|
|||||||
gs->map->heroesOnMap.push_back(h);
|
gs->map->heroesOnMap.push_back(h);
|
||||||
p->heroes.push_back(h);
|
p->heroes.push_back(h);
|
||||||
h->attachTo(p);
|
h->attachTo(p);
|
||||||
h->initObj();
|
if(fresh)
|
||||||
|
{
|
||||||
|
h->initObj();
|
||||||
|
}
|
||||||
gs->map->addBlockVisTiles(h);
|
gs->map->addBlockVisTiles(h);
|
||||||
|
|
||||||
if(t)
|
if(t)
|
||||||
|
@ -87,6 +87,20 @@ boost::optional<std::string> CFilesystemList::getResourceName(const ResourceID &
|
|||||||
return boost::optional<std::string>();
|
return boost::optional<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<std::string> CFilesystemList::getResourceNames(const ResourceID & resourceName) const
|
||||||
|
{
|
||||||
|
std::set<std::string> paths;
|
||||||
|
for(auto& loader : getResourcesWithName(resourceName))
|
||||||
|
{
|
||||||
|
auto rn = loader->getResourceName(resourceName);
|
||||||
|
if(rn)
|
||||||
|
{
|
||||||
|
paths.insert(*rn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::move(paths);
|
||||||
|
}
|
||||||
|
|
||||||
std::unordered_set<ResourceID> CFilesystemList::getFilteredFiles(std::function<bool(const ResourceID &)> filter) const
|
std::unordered_set<ResourceID> CFilesystemList::getFilteredFiles(std::function<bool(const ResourceID &)> filter) const
|
||||||
{
|
{
|
||||||
std::unordered_set<ResourceID> ret;
|
std::unordered_set<ResourceID> ret;
|
||||||
|
@ -59,15 +59,8 @@ class DLL_LINKAGE CFilesystemList : public ISimpleResourceLoader
|
|||||||
std::set<ISimpleResourceLoader *> writeableLoaders;
|
std::set<ISimpleResourceLoader *> writeableLoaders;
|
||||||
|
|
||||||
//FIXME: this is only compile fix, should be removed in the end
|
//FIXME: this is only compile fix, should be removed in the end
|
||||||
CFilesystemList(CFilesystemList &)
|
CFilesystemList(CFilesystemList &) = delete;
|
||||||
{
|
CFilesystemList &operator=(CFilesystemList &) = delete;
|
||||||
//class is not copyable
|
|
||||||
}
|
|
||||||
CFilesystemList &operator=(CFilesystemList &)
|
|
||||||
{
|
|
||||||
//class is not copyable
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CFilesystemList();
|
CFilesystemList();
|
||||||
@ -78,6 +71,7 @@ public:
|
|||||||
bool existsResource(const ResourceID & resourceName) const override;
|
bool existsResource(const ResourceID & resourceName) const override;
|
||||||
std::string getMountPoint() const override;
|
std::string getMountPoint() const override;
|
||||||
boost::optional<std::string> getResourceName(const ResourceID & resourceName) const override;
|
boost::optional<std::string> getResourceName(const ResourceID & resourceName) const override;
|
||||||
|
std::set<std::string> getResourceNames(const ResourceID & resourceName) const override;
|
||||||
std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const override;
|
std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const override;
|
||||||
bool createResource(std::string filename, bool update = false) override;
|
bool createResource(std::string filename, bool update = false) override;
|
||||||
std::vector<const ISimpleResourceLoader *> getResourcesWithName(const ResourceID & resourceName) const override;
|
std::vector<const ISimpleResourceLoader *> getResourcesWithName(const ResourceID & resourceName) const override;
|
||||||
|
@ -53,6 +53,22 @@ public:
|
|||||||
return boost::optional<std::string>();
|
return boost::optional<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all full names of matching resources, e.g. names of files in filesystem.
|
||||||
|
*
|
||||||
|
* @return std::set with names.
|
||||||
|
*/
|
||||||
|
virtual std::set<std::string> getResourceNames(const ResourceID & resourceName) const
|
||||||
|
{
|
||||||
|
std::set<std::string> result;
|
||||||
|
auto rn = getResourceName(resourceName);
|
||||||
|
if(rn)
|
||||||
|
{
|
||||||
|
result.insert(*rn);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get list of files that matches filter function
|
* Get list of files that matches filter function
|
||||||
*
|
*
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "../CCreatureHandler.h"
|
#include "../CCreatureHandler.h"
|
||||||
#include "../BattleState.h"
|
#include "../BattleState.h"
|
||||||
#include "../CTownHandler.h"
|
#include "../CTownHandler.h"
|
||||||
|
#include "../mapping/CMap.h"
|
||||||
#include "CGTownInstance.h"
|
#include "CGTownInstance.h"
|
||||||
|
|
||||||
///helpers
|
///helpers
|
||||||
@ -220,7 +221,9 @@ CGHeroInstance::CGHeroInstance()
|
|||||||
setNodeType(HERO);
|
setNodeType(HERO);
|
||||||
ID = Obj::HERO;
|
ID = Obj::HERO;
|
||||||
tacticFormationEnabled = inTownGarrison = false;
|
tacticFormationEnabled = inTownGarrison = false;
|
||||||
mana = movement = portrait = -1;
|
mana = UNINITIALIZED_MANA;
|
||||||
|
movement = UNINITIALIZED_MOVEMENT;
|
||||||
|
portrait = UNINITIALIZED_PORTRAIT;
|
||||||
isStanding = true;
|
isStanding = true;
|
||||||
moveDir = 4;
|
moveDir = 4;
|
||||||
level = 1;
|
level = 1;
|
||||||
@ -1466,3 +1469,26 @@ void CGHeroInstance::readJsonOptions(const JsonNode& json)
|
|||||||
CGObjectInstance::readOwner(json);
|
CGObjectInstance::readOwner(json);
|
||||||
CArtifactSet::readJson(json["artifacts"]);
|
CArtifactSet::readJson(json["artifacts"]);
|
||||||
}
|
}
|
||||||
|
bool CGHeroInstance::isMissionCritical() const
|
||||||
|
{
|
||||||
|
for(const TriggeredEvent & event : IObjectInterface::cb->getMapHeader()->triggeredEvents)
|
||||||
|
{
|
||||||
|
if(event.trigger.test([&](const EventCondition & condition)
|
||||||
|
{
|
||||||
|
if (condition.condition == EventCondition::CONTROL && condition.object)
|
||||||
|
{
|
||||||
|
auto hero = dynamic_cast<const CGHeroInstance*>(condition.object);
|
||||||
|
return (hero != this);
|
||||||
|
}
|
||||||
|
else if(condition.condition == EventCondition::IS_HUMAN)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
class CHero;
|
class CHero;
|
||||||
class CGBoat;
|
class CGBoat;
|
||||||
class CGTownInstance;
|
class CGTownInstance;
|
||||||
|
class CMap;
|
||||||
struct TerrainTile;
|
struct TerrainTile;
|
||||||
struct TurnInfo;
|
struct TurnInfo;
|
||||||
|
|
||||||
@ -64,6 +65,9 @@ public:
|
|||||||
ConstTransitivePtr<CCommanderInstance> commander;
|
ConstTransitivePtr<CCommanderInstance> commander;
|
||||||
const CGBoat *boat; //set to CGBoat when sailing
|
const CGBoat *boat; //set to CGBoat when sailing
|
||||||
|
|
||||||
|
static const ui32 UNINITIALIZED_PORTRAIT = -1;
|
||||||
|
static const ui32 UNINITIALIZED_MANA = -1;
|
||||||
|
static const ui32 UNINITIALIZED_MOVEMENT = -1;
|
||||||
|
|
||||||
//std::vector<const CArtifact*> artifacts; //hero's artifacts from bag
|
//std::vector<const CArtifact*> artifacts; //hero's artifacts from bag
|
||||||
//std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
|
//std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
|
||||||
@ -124,6 +128,11 @@ public:
|
|||||||
}
|
}
|
||||||
} skillsInfo;
|
} skillsInfo;
|
||||||
|
|
||||||
|
inline bool isInitialized() const
|
||||||
|
{ // has this hero been on the map at least once?
|
||||||
|
return movement != UNINITIALIZED_MOVEMENT && mana != UNINITIALIZED_MANA;
|
||||||
|
}
|
||||||
|
|
||||||
//int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
|
//int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
|
||||||
int getSightRadious() const override; //sight distance (should be used if player-owned structure)
|
int getSightRadious() const override; //sight distance (should be used if player-owned structure)
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -203,6 +212,8 @@ public:
|
|||||||
void updateSkill(SecondarySkill which, int val);
|
void updateSkill(SecondarySkill which, int val);
|
||||||
|
|
||||||
bool hasVisions(const CGObjectInstance * target, const int subtype) const;
|
bool hasVisions(const CGObjectInstance * target, const int subtype) const;
|
||||||
|
/// If this hero perishes, the scenario is failed
|
||||||
|
bool isMissionCritical() const;
|
||||||
|
|
||||||
CGHeroInstance();
|
CGHeroInstance();
|
||||||
virtual ~CGHeroInstance();
|
virtual ~CGHeroInstance();
|
||||||
|
@ -295,10 +295,10 @@ void CGPandoraBox::getText( InfoWindow &iw, bool &afterBattle, int val, int nega
|
|||||||
|
|
||||||
void CGPandoraBox::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
void CGPandoraBox::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||||
{
|
{
|
||||||
if(result.winner)
|
if(result.winner == 0)
|
||||||
return;
|
{
|
||||||
|
giveContentsUpToExp(hero);
|
||||||
giveContentsUpToExp(hero);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||||
|
@ -133,10 +133,10 @@ namespace JsonRandom
|
|||||||
if (value["type"].getType() == JsonNode::DATA_STRING)
|
if (value["type"].getType() == JsonNode::DATA_STRING)
|
||||||
return SpellID(VLC->modh->identifiers.getIdentifier("spell", value["type"]).get());
|
return SpellID(VLC->modh->identifiers.getIdentifier("spell", value["type"]).get());
|
||||||
|
|
||||||
spells.erase(std::remove_if(spells.begin(), spells.end(), [=](SpellID spell)
|
vstd::erase_if(spells, [=](SpellID spell)
|
||||||
{
|
{
|
||||||
return VLC->spellh->objects[spell]->level != si32(value["level"].Float());
|
return VLC->spellh->objects[spell]->level != si32(value["level"].Float());
|
||||||
}), spells.end());
|
});
|
||||||
|
|
||||||
return SpellID(*RandomGeneratorUtil::nextItem(spells, rng));
|
return SpellID(*RandomGeneratorUtil::nextItem(spells, rng));
|
||||||
}
|
}
|
||||||
|
@ -454,22 +454,26 @@ void CGCreature::flee( const CGHeroInstance * h ) const
|
|||||||
|
|
||||||
void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||||
{
|
{
|
||||||
|
if(result.winner == 0)
|
||||||
if(result.winner==0)
|
|
||||||
{
|
{
|
||||||
giveReward(hero);
|
giveReward(hero);
|
||||||
cb->removeObject(this);
|
cb->removeObject(this);
|
||||||
}
|
}
|
||||||
|
else if(result.winner > 1) // draw
|
||||||
|
{
|
||||||
|
// guarded reward is lost forever on draw
|
||||||
|
cb->removeObject(this);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//merge stacks into one
|
//merge stacks into one
|
||||||
TSlots::const_iterator i;
|
TSlots::const_iterator i;
|
||||||
CCreature * cre = VLC->creh->creatures[formation.basicType];
|
CCreature * cre = VLC->creh->creatures[formation.basicType];
|
||||||
for (i = stacks.begin(); i != stacks.end(); i++)
|
for(i = stacks.begin(); i != stacks.end(); i++)
|
||||||
{
|
{
|
||||||
if (cre->isMyUpgrade(i->second->type))
|
if(cre->isMyUpgrade(i->second->type))
|
||||||
{
|
{
|
||||||
cb->changeStackType (StackLocation(this, i->first), cre); //un-upgrade creatures
|
cb->changeStackType(StackLocation(this, i->first), cre); //un-upgrade creatures
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,16 +481,16 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &
|
|||||||
if(!hasStackAtSlot(SlotID(0)))
|
if(!hasStackAtSlot(SlotID(0)))
|
||||||
cb->moveStack(StackLocation(this, stacks.begin()->first), StackLocation(this, SlotID(0)), stacks.begin()->second->count);
|
cb->moveStack(StackLocation(this, stacks.begin()->first), StackLocation(this, SlotID(0)), stacks.begin()->second->count);
|
||||||
|
|
||||||
while (stacks.size() > 1) //hopefully that's enough
|
while(stacks.size() > 1) //hopefully that's enough
|
||||||
{
|
{
|
||||||
// TODO it's either overcomplicated (if we assume there'll be only one stack) or buggy (if we allow multiple stacks... but that'll also cause troubles elsewhere)
|
// TODO it's either overcomplicated (if we assume there'll be only one stack) or buggy (if we allow multiple stacks... but that'll also cause troubles elsewhere)
|
||||||
i = stacks.end();
|
i = stacks.end();
|
||||||
i--;
|
i--;
|
||||||
SlotID slot = getSlotFor(i->second->type);
|
SlotID slot = getSlotFor(i->second->type);
|
||||||
if (slot == i->first) //no reason to move stack to its own slot
|
if(slot == i->first) //no reason to move stack to its own slot
|
||||||
break;
|
break;
|
||||||
else
|
else
|
||||||
cb->moveStack (StackLocation(this, i->first), StackLocation(this, slot), i->second->count);
|
cb->moveStack(StackLocation(this, i->first), StackLocation(this, slot), i->second->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
cb->setObjProperty(id, ObjProperty::MONSTER_POWER, stacks.begin()->second->count * 1000); //remember casualties
|
cb->setObjProperty(id, ObjProperty::MONSTER_POWER, stacks.begin()->second->count * 1000); //remember casualties
|
||||||
|
@ -124,6 +124,11 @@ static inline double distance(int3 a, int3 b)
|
|||||||
}
|
}
|
||||||
static void giveExp(BattleResult &r)
|
static void giveExp(BattleResult &r)
|
||||||
{
|
{
|
||||||
|
if(r.winner > 1)
|
||||||
|
{
|
||||||
|
// draw
|
||||||
|
return;
|
||||||
|
}
|
||||||
r.exp[0] = 0;
|
r.exp[0] = 0;
|
||||||
r.exp[1] = 0;
|
r.exp[1] = 0;
|
||||||
for(auto i = r.casualties[!r.winner].begin(); i!=r.casualties[!r.winner].end(); i++)
|
for(auto i = r.casualties[!r.winner].begin(); i!=r.casualties[!r.winner].end(); i++)
|
||||||
@ -471,7 +476,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
|||||||
const CArmedInstance *bEndArmy2 = gs->curB->sides.at(1).armyObject;
|
const CArmedInstance *bEndArmy2 = gs->curB->sides.at(1).armyObject;
|
||||||
const BattleResult::EResult result = battleResult.get()->result;
|
const BattleResult::EResult result = battleResult.get()->result;
|
||||||
|
|
||||||
auto findBattleQuery = [this] () -> std::shared_ptr<CBattleQuery>
|
auto findBattleQuery = [this]() -> std::shared_ptr<CBattleQuery>
|
||||||
{
|
{
|
||||||
for(auto &q : queries.allQueries())
|
for(auto &q : queries.allQueries())
|
||||||
{
|
{
|
||||||
@ -526,66 +531,70 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<ui32> arts; //display them in window
|
std::vector<const CArtifactInstance *> arts; //display them in window
|
||||||
|
|
||||||
if (result == BattleResult::NORMAL && finishingBattle->winnerHero)
|
if(result == BattleResult::NORMAL && finishingBattle->winnerHero)
|
||||||
{
|
{
|
||||||
if (finishingBattle->loserHero)
|
auto sendMoveArtifact = [&](const CArtifactInstance *art, MoveArtifact *ma)
|
||||||
{
|
{
|
||||||
auto artifactsWorn = finishingBattle->loserHero->artifactsWorn; //TODO: wrap it into a function, somehow (boost::variant -_-)
|
arts.push_back(art);
|
||||||
|
ma->dst = ArtifactLocation(finishingBattle->winnerHero, art->firstAvailableSlot(finishingBattle->winnerHero));
|
||||||
|
sendAndApply(ma);
|
||||||
|
};
|
||||||
|
if(finishingBattle->loserHero)
|
||||||
|
{
|
||||||
|
//TODO: wrap it into a function, somehow (boost::variant -_-)
|
||||||
|
auto artifactsWorn = finishingBattle->loserHero->artifactsWorn;
|
||||||
for (auto artSlot : artifactsWorn)
|
for (auto artSlot : artifactsWorn)
|
||||||
{
|
{
|
||||||
MoveArtifact ma;
|
MoveArtifact ma;
|
||||||
ma.src = ArtifactLocation (finishingBattle->loserHero, artSlot.first);
|
ma.src = ArtifactLocation(finishingBattle->loserHero, artSlot.first);
|
||||||
const CArtifactInstance * art = ma.src.getArt();
|
const CArtifactInstance * art = ma.src.getArt();
|
||||||
if (art && !art->artType->isBig() && art->artType->id != ArtifactID::SPELLBOOK) // don't move war machines or locked arts (spellbook)
|
if(art && !art->artType->isBig() &&
|
||||||
|
art->artType->id != ArtifactID::SPELLBOOK)
|
||||||
|
// don't move war machines or locked arts (spellbook)
|
||||||
{
|
{
|
||||||
arts.push_back (art->artType->id);
|
sendMoveArtifact(art, &ma);
|
||||||
ma.dst = ArtifactLocation (finishingBattle->winnerHero, art->firstAvailableSlot(finishingBattle->winnerHero));
|
|
||||||
sendAndApply(&ma);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (!finishingBattle->loserHero->artifactsInBackpack.empty())
|
while(!finishingBattle->loserHero->artifactsInBackpack.empty())
|
||||||
{
|
{
|
||||||
//we assume that no big artifacts can be found
|
//we assume that no big artifacts can be found
|
||||||
MoveArtifact ma;
|
MoveArtifact ma;
|
||||||
ma.src = ArtifactLocation (finishingBattle->loserHero,
|
ma.src = ArtifactLocation(finishingBattle->loserHero,
|
||||||
ArtifactPosition(GameConstants::BACKPACK_START)); //backpack automatically shifts arts to beginning
|
ArtifactPosition(GameConstants::BACKPACK_START)); //backpack automatically shifts arts to beginning
|
||||||
const CArtifactInstance * art = ma.src.getArt();
|
const CArtifactInstance * art = ma.src.getArt();
|
||||||
arts.push_back (art->artType->id);
|
if(art->artType->id != ArtifactID::GRAIL) //grail may not be won
|
||||||
ma.dst = ArtifactLocation (finishingBattle->winnerHero, art->firstAvailableSlot(finishingBattle->winnerHero));
|
{
|
||||||
sendAndApply(&ma);
|
sendMoveArtifact(art, &ma);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (finishingBattle->loserHero->commander) //TODO: what if commanders belong to no hero?
|
if(finishingBattle->loserHero->commander) //TODO: what if commanders belong to no hero?
|
||||||
{
|
{
|
||||||
artifactsWorn = finishingBattle->loserHero->commander->artifactsWorn;
|
artifactsWorn = finishingBattle->loserHero->commander->artifactsWorn;
|
||||||
for (auto artSlot : artifactsWorn)
|
for(auto artSlot : artifactsWorn)
|
||||||
{
|
{
|
||||||
MoveArtifact ma;
|
MoveArtifact ma;
|
||||||
ma.src = ArtifactLocation (finishingBattle->loserHero->commander.get(), artSlot.first);
|
ma.src = ArtifactLocation(finishingBattle->loserHero->commander.get(), artSlot.first);
|
||||||
const CArtifactInstance * art = ma.src.getArt();
|
const CArtifactInstance * art = ma.src.getArt();
|
||||||
if (art && !art->artType->isBig())
|
if (art && !art->artType->isBig())
|
||||||
{
|
{
|
||||||
arts.push_back (art->artType->id);
|
sendMoveArtifact(art, &ma);
|
||||||
ma.dst = ArtifactLocation (finishingBattle->winnerHero, art->firstAvailableSlot(finishingBattle->winnerHero));
|
|
||||||
sendAndApply(&ma);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto armySlot : gs->curB->battleGetArmyObject(!battleResult.data->winner)->stacks)
|
for(auto armySlot : gs->curB->battleGetArmyObject(!battleResult.data->winner)->stacks)
|
||||||
{
|
{
|
||||||
auto artifactsWorn = armySlot.second->artifactsWorn;
|
auto artifactsWorn = armySlot.second->artifactsWorn;
|
||||||
for (auto artSlot : artifactsWorn)
|
for (auto artSlot : artifactsWorn)
|
||||||
{
|
{
|
||||||
MoveArtifact ma;
|
MoveArtifact ma;
|
||||||
ma.src = ArtifactLocation (armySlot.second, artSlot.first);
|
ma.src = ArtifactLocation(armySlot.second, artSlot.first);
|
||||||
const CArtifactInstance * art = ma.src.getArt();
|
const CArtifactInstance * art = ma.src.getArt();
|
||||||
if (art && !art->artType->isBig())
|
if (art && !art->artType->isBig())
|
||||||
{
|
{
|
||||||
arts.push_back (art->artType->id);
|
sendMoveArtifact(art, &ma);
|
||||||
ma.dst = ArtifactLocation (finishingBattle->winnerHero, art->firstAvailableSlot(finishingBattle->winnerHero));
|
|
||||||
sendAndApply(&ma);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -593,23 +602,25 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
|||||||
|
|
||||||
sendAndApply(battleResult.data); //after this point casualties objects are destroyed
|
sendAndApply(battleResult.data); //after this point casualties objects are destroyed
|
||||||
|
|
||||||
if (arts.size()) //display loot
|
if(arts.size()) //display loot
|
||||||
{
|
{
|
||||||
InfoWindow iw;
|
InfoWindow iw;
|
||||||
iw.player = finishingBattle->winnerHero->tempOwner;
|
iw.player = finishingBattle->winnerHero->tempOwner;
|
||||||
|
|
||||||
iw.text.addTxt (MetaString::GENERAL_TXT, 30); //You have captured enemy artifact
|
iw.text.addTxt (MetaString::GENERAL_TXT, 30); //You have captured enemy artifact
|
||||||
|
|
||||||
for (auto id : arts) //TODO; separate function to display loot for various ojects?
|
for(auto art : arts) //TODO; separate function to display loot for various ojects?
|
||||||
{
|
{
|
||||||
iw.components.push_back (Component (Component::ARTIFACT, id, 0, 0));
|
iw.components.push_back(Component(
|
||||||
|
Component::ARTIFACT, art->artType->id,
|
||||||
|
art->artType->id == ArtifactID::SPELL_SCROLL? art->getGivenSpellID() : 0, 0));
|
||||||
if(iw.components.size() >= 14)
|
if(iw.components.size() >= 14)
|
||||||
{
|
{
|
||||||
sendAndApply(&iw);
|
sendAndApply(&iw);
|
||||||
iw.components.clear();
|
iw.components.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (iw.components.size())
|
if(iw.components.size())
|
||||||
{
|
{
|
||||||
sendAndApply(&iw);
|
sendAndApply(&iw);
|
||||||
}
|
}
|
||||||
@ -712,7 +723,7 @@ void CGameHandler::battleAfterLevelUp( const BattleResult &result )
|
|||||||
|
|
||||||
setBattle(nullptr);
|
setBattle(nullptr);
|
||||||
|
|
||||||
if(visitObjectAfterVictory && result.winner==0)
|
if(visitObjectAfterVictory && result.winner==0 && !finishingBattle->winnerHero->stacks.empty())
|
||||||
{
|
{
|
||||||
logGlobal->traceStream() << "post-victory visit";
|
logGlobal->traceStream() << "post-victory visit";
|
||||||
visitObjectOnTile(*getTile(finishingBattle->winnerHero->getPosition()), finishingBattle->winnerHero);
|
visitObjectOnTile(*getTile(finishingBattle->winnerHero->getPosition()), finishingBattle->winnerHero);
|
||||||
@ -734,13 +745,34 @@ void CGameHandler::battleAfterLevelUp( const BattleResult &result )
|
|||||||
sah.army[0].setCreature(SlotID(0), finishingBattle->loserHero->type->initialArmy.at(0).creature, 1);
|
sah.army[0].setCreature(SlotID(0), finishingBattle->loserHero->type->initialArmy.at(0).creature, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(const CGHeroInstance *another = getPlayer(finishingBattle->loser)->availableHeroes.at(1))
|
if(const CGHeroInstance *another = getPlayer(finishingBattle->loser)->availableHeroes.at(0))
|
||||||
sah.hid[1] = another->subID;
|
sah.hid[1] = another->subID;
|
||||||
else
|
else
|
||||||
sah.hid[1] = -1;
|
sah.hid[1] = -1;
|
||||||
|
|
||||||
sendAndApply(&sah);
|
sendAndApply(&sah);
|
||||||
}
|
}
|
||||||
|
if(result.winner != 2 && finishingBattle->winnerHero && finishingBattle->winnerHero->stacks.empty())
|
||||||
|
{
|
||||||
|
RemoveObject ro(finishingBattle->winnerHero->id);
|
||||||
|
sendAndApply(&ro);
|
||||||
|
|
||||||
|
if (VLC->modh->settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS)
|
||||||
|
{
|
||||||
|
SetAvailableHeroes sah;
|
||||||
|
sah.player = finishingBattle->victor;
|
||||||
|
sah.hid[0] = finishingBattle->winnerHero->subID;
|
||||||
|
sah.army[0].clear();
|
||||||
|
sah.army[0].setCreature(SlotID(0), finishingBattle->winnerHero->type->initialArmy.at(0).creature, 1);
|
||||||
|
|
||||||
|
if(const CGHeroInstance *another = getPlayer(finishingBattle->victor)->availableHeroes.at(0))
|
||||||
|
sah.hid[1] = another->subID;
|
||||||
|
else
|
||||||
|
sah.hid[1] = -1;
|
||||||
|
|
||||||
|
sendAndApply(&sah);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CStack *def, int distance, int targetHex)
|
void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CStack *def, int distance, int targetHex)
|
||||||
@ -3322,23 +3354,27 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
|
|||||||
// || (getHeroCount(player, false) >= GameConstants::MAX_HEROES_PER_PLAYER && complain("Cannot hire hero, only 8 wandering heroes are allowed!")))
|
// || (getHeroCount(player, false) >= GameConstants::MAX_HEROES_PER_PLAYER && complain("Cannot hire hero, only 8 wandering heroes are allowed!")))
|
||||||
if((p->resources.at(Res::GOLD) < GameConstants::HERO_GOLD_COST && complain("Not enough gold for buying hero!"))
|
if((p->resources.at(Res::GOLD) < GameConstants::HERO_GOLD_COST && complain("Not enough gold for buying hero!"))
|
||||||
|| ((!t) && (getHeroCount(player, false) >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER && complain("Cannot hire hero, too many wandering heroes already!")))
|
|| ((!t) && (getHeroCount(player, false) >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER && complain("Cannot hire hero, too many wandering heroes already!")))
|
||||||
|| ((t) && (getHeroCount(player, true) >= VLC->modh->settings.MAX_HEROES_AVAILABLE_PER_PLAYER && complain("Cannot hire hero, too many heroes garrizoned and wandering already!"))) )
|
|| ((t) && (getHeroCount(player, true) >= VLC->modh->settings.MAX_HEROES_AVAILABLE_PER_PLAYER && complain("Cannot hire hero, too many heroes garrizoned and wandering already!"))) )
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(t) //tavern in town
|
if(t) //tavern in town
|
||||||
{
|
{
|
||||||
if( (!t->hasBuilt(BuildingID::TAVERN) && complain("No tavern!"))
|
if((!t->hasBuilt(BuildingID::TAVERN) && complain("No tavern!"))
|
||||||
|| (t->visitingHero && complain("There is visiting hero - no place!")))
|
|| (t->visitingHero && complain("There is visiting hero - no place!")))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(obj->ID == Obj::TAVERN)
|
else if(obj->ID == Obj::TAVERN)
|
||||||
{
|
{
|
||||||
if(getTile(obj->visitablePos())->visitableObjects.back() != obj && complain("Tavern entry must be unoccupied!"))
|
if(getTile(obj->visitablePos())->visitableObjects.back() != obj && complain("Tavern entry must be unoccupied!"))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const CGHeroInstance *nh = p->availableHeroes.at(hid);
|
const CGHeroInstance *nh = p->availableHeroes.at(hid);
|
||||||
if (!nh)
|
if (!nh)
|
||||||
{
|
{
|
||||||
@ -3353,13 +3389,14 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
|
|||||||
hr.tile = obj->visitablePos() + nh->getVisitableOffset();
|
hr.tile = obj->visitablePos() + nh->getVisitableOffset();
|
||||||
sendAndApply(&hr);
|
sendAndApply(&hr);
|
||||||
|
|
||||||
|
|
||||||
std::map<ui32, ConstTransitivePtr<CGHeroInstance> > pool = gs->unusedHeroesFromPool();
|
std::map<ui32, ConstTransitivePtr<CGHeroInstance> > pool = gs->unusedHeroesFromPool();
|
||||||
|
|
||||||
const CGHeroInstance *theOtherHero = p->availableHeroes.at(!hid);
|
const CGHeroInstance *theOtherHero = p->availableHeroes.at(!hid);
|
||||||
const CGHeroInstance *newHero = nullptr;
|
const CGHeroInstance *newHero = nullptr;
|
||||||
if (theOtherHero) //on XXL maps all heroes can be imprisoned :(
|
if (theOtherHero) //on XXL maps all heroes can be imprisoned :(
|
||||||
|
{
|
||||||
newHero = gs->hpool.pickHeroFor(false, player, getNativeTown(player), pool, gs->getRandomGenerator(), theOtherHero->type->heroClass);
|
newHero = gs->hpool.pickHeroFor(false, player, getNativeTown(player), pool, gs->getRandomGenerator(), theOtherHero->type->heroClass);
|
||||||
|
}
|
||||||
|
|
||||||
SetAvailableHeroes sah;
|
SetAvailableHeroes sah;
|
||||||
sah.player = player;
|
sah.player = player;
|
||||||
@ -3371,7 +3408,9 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
|
|||||||
sah.army[hid].setCreature(SlotID(0), newHero->type->initialArmy[0].creature, 1);
|
sah.army[hid].setCreature(SlotID(0), newHero->type->initialArmy[0].creature, 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
sah.hid[hid] = -1;
|
sah.hid[hid] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
sah.hid[!hid] = theOtherHero ? theOtherHero->subID : -1;
|
sah.hid[!hid] = theOtherHero ? theOtherHero->subID : -1;
|
||||||
sendAndApply(&sah);
|
sendAndApply(&sah);
|
||||||
@ -5663,16 +5702,18 @@ void CGameHandler::giveHeroNewArtifact(const CGHeroInstance *h, const CArtifact
|
|||||||
|
|
||||||
void CGameHandler::setBattleResult(BattleResult::EResult resultType, int victoriusSide)
|
void CGameHandler::setBattleResult(BattleResult::EResult resultType, int victoriusSide)
|
||||||
{
|
{
|
||||||
if(battleResult.get())
|
boost::unique_lock<boost::mutex> guard(battleResult.mx);
|
||||||
|
if(battleResult.data)
|
||||||
{
|
{
|
||||||
complain("There is already set result?");
|
complain((boost::format("The battle result has been already set (to %d, asked to %d)")
|
||||||
|
% battleResult.data->result % resultType).str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto br = new BattleResult;
|
auto br = new BattleResult;
|
||||||
br->result = resultType;
|
br->result = resultType;
|
||||||
br->winner = victoriusSide; //surrendering side loses
|
br->winner = victoriusSide; //surrendering side loses
|
||||||
gs->curB->calculateCasualties(br->casualties);
|
gs->curB->calculateCasualties(br->casualties);
|
||||||
battleResult.set(br);
|
battleResult.data = br;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::commitPackage( CPackForClient *pack )
|
void CGameHandler::commitPackage( CPackForClient *pack )
|
||||||
|
Loading…
x
Reference in New Issue
Block a user