1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

Version set to 0.83c, to be released as development build.

Code reorganizations in bonus system, allowing defining bonusNode-like classes.
Fixed some issues with artifact handling (proper updating of GUI when moving, minor fixes). 
Restoring battle AI for neutrals after loading game.
This commit is contained in:
Michał W. Urbańczyk
2011-02-27 19:58:14 +00:00
parent d7b586f1fd
commit 03fdd22b1a
13 changed files with 319 additions and 250 deletions

View File

@ -1,14 +1,26 @@
0.83 -> 0.84 (Mar 01 2011)
GENERAL:
* Bonus system has been rewritten
* Support for new artifacts (spell scrolls, angelic alliance)
* Preliminary support for stack experience (no UI yet)
* Partial support for running VCMI in duel mode (no adventure map, only one battle)
* Partial support for running VCMI in duel mode (no adventure map, only one battle, ATM only AI-AI battles)
* New artifacts supported:
- Angellic Alliance
- Bird of Perception
- Emblem of Cognizance
- Spell Scroll
- Stoic Watchman
BATTLES:
* Support for eagle eye, tactics and artillery secondary skills (together with corresponding artifacts)
* Better animations handling
* Defensive stance is supported
* New, improved AI for neutral player
HERO:
* New secondary skills supported:
- Artillery
- Eagle Eye
- Tactics
AI PLAYER:
* new AI leading neutral creatures in combat, slightly better then previous
0.82 -> 0.83 (Nov 01 2010)

View File

@ -44,6 +44,28 @@
extern SDL_Surface * screen;
using namespace boost::assign;
void CHeroWithMaybePickedArtifact::getAllBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
{
BonusList heroBonuses, bonusesFromPickedUpArtifact;
hero->getAllBonuses(heroBonuses, selector, limit, hero);
CArtifactsOfHero::SCommonPart *cp = cww->artSets.size() ? cww->artSets.front()->commonInfo : NULL;
if(cp && cp->src.art && cp->src.AOH && cp->src.AOH->getHero() == hero)
{
cp->src.art->getAllBonuses(bonusesFromPickedUpArtifact, selector, limit, hero);
}
BOOST_FOREACH(Bonus *b, bonusesFromPickedUpArtifact)
heroBonuses -= b;
BOOST_FOREACH(Bonus *b, heroBonuses)
out.push_back(b);
}
CHeroWithMaybePickedArtifact::CHeroWithMaybePickedArtifact(CWindowWithArtifacts *Cww, const CGHeroInstance *Hero)
: cww(Cww), hero(Hero)
{
}
void CHeroSwitcher::clickLeft(tribool down, bool previousState)
{
if(!down)
@ -69,6 +91,7 @@ CHeroSwitcher::CHeroSwitcher(int serial)
}
CHeroWindow::CHeroWindow(const CGHeroInstance *hero)
: heroWArt(this, hero)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
garr = NULL;
@ -98,8 +121,6 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero)
for(int g=0; g<8; ++g)
heroListMi.push_back(new CHeroSwitcher(g));
flags = CDefHandler::giveDefEss("CREST58.DEF");
//areas
@ -162,15 +183,14 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
assert(hero == curHero);
//assert(hero->tempOwner == LOCPLINT->playerID || hero->tempOwner == NEUTRAL_PLAYER); //for now we won't show hero windows for non-our heroes
specArea->text = CGI->generaltexth->hTxts[hero->subID].longBonus;
specArea->text = CGI->generaltexth->hTxts[curHero->subID].longBonus;
tacticsButton->callback.clear();
tacticsButton->callback2.clear();
dismissButton->hoverTexts[0] = boost::str(boost::format(CGI->generaltexth->heroscrn[16]) % curHero->name % curHero->type->heroClass->name);
portraitArea->hoverText = boost::str(boost::format(CGI->generaltexth->allTexts[15]) % curHero->name % curHero->type->heroClass->name);
portraitArea->text = hero->getBiography();
portraitArea->text = curHero->getBiography();
{
AdventureMapButton * split = NULL;
@ -189,7 +209,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
if(!artSets.size())
{
CArtifactsOfHero *arts = new CArtifactsOfHero(Point(-65, -8), true);
arts->setHero(hero);
arts->setHero(curHero);
artSets.push_back(arts);
}
}
@ -198,14 +218,14 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
//primary skills support
for(size_t g=0; g<primSkillAreas.size(); ++g)
{
primSkillAreas[g]->bonusValue = hero->getPrimSkillLevel(g);
primSkillAreas[g]->bonusValue = heroWArt.getPrimSkillLevel(g);
}
//secondary skills support
for(size_t g=0; g< secSkillAreas.size(); ++g)
{
int skill = hero->secSkills[g].first,
level = hero->getSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(hero->secSkills[g].first));
int skill = curHero->secSkills[g].first,
level = curHero->getSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(curHero->secSkills[g].first));
secSkillAreas[g]->type = skill;
secSkillAreas[g]->bonusValue = level;
secSkillAreas[g]->text = CGI->generaltexth->skillInfoTexts[skill][level-1];
@ -214,43 +234,43 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
//printing experience - original format does not support ui64
expArea->text = CGI->generaltexth->allTexts[2];
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(hero->level));
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(CGI->heroh->reqExp(hero->level+1)));
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(hero->exp));
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(curHero->level));
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(CGI->heroh->reqExp(curHero->level+1)));
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(curHero->exp));
//printing spell points
spellPointsArea->text = boost::str(boost::format(CGI->generaltexth->allTexts[205]) % hero->name % hero->mana % hero->manaLimit());
spellPointsArea->text = boost::str(boost::format(CGI->generaltexth->allTexts[205]) % curHero->name % curHero->mana % heroWArt.manaLimit());
//if we have exchange window with this hero open
//if we have exchange window with this curHero open
bool noDismiss=false;
BOOST_FOREACH(IShowActivable *isa, GH.listInt)
{
if(CExchangeWindow * cew = dynamic_cast<CExchangeWindow*>(isa))
for(int g=0; g < ARRAY_COUNT(cew->heroInst); ++g)
if(cew->heroInst[g] == hero)
if(cew->heroInst[g] == curHero)
noDismiss = true;
if (dynamic_cast<CKingdomInterface*>(isa))
noDismiss = true;
}
dismissButton->block(!!hero->visitedTown || noDismiss);
dismissButton->block(!!curHero->visitedTown || noDismiss);
if(hero->getSecSkillLevel(CGHeroInstance::TACTICS) == 0)
if(curHero->getSecSkillLevel(CGHeroInstance::TACTICS) == 0)
tacticsButton->block(true);
else
{
tacticsButton->block(false);
tacticsButton->callback = vstd::assigno(hero->tacticFormationEnabled,true);
tacticsButton->callback2 = vstd::assigno(hero->tacticFormationEnabled,false);
tacticsButton->callback = vstd::assigno(curHero->tacticFormationEnabled,true);
tacticsButton->callback2 = vstd::assigno(curHero->tacticFormationEnabled,false);
}
//setting formations
formations->onChange = 0;
formations->select(hero->formation,true);
formations->onChange = boost::bind(&CCallback::setFormation, LOCPLINT->cb, hero, _1);
formations->select(curHero->formation,true);
formations->onChange = boost::bind(&CCallback::setFormation, LOCPLINT->cb, curHero, _1);
morale->set(hero);
luck->set(hero);
morale->set(&heroWArt);
luck->set(&heroWArt);
if(redrawNeeded)
redraw();
@ -271,6 +291,7 @@ void CHeroWindow::dismissCurrent()
void CHeroWindow::questlog()
{
}
void CHeroWindow::showAll(SDL_Surface * to)
{
CIntObject::showAll(to);
@ -319,7 +340,7 @@ void CHeroWindow::showAll(SDL_Surface * to)
for(int m=0; m<4; ++m)
{
std::ostringstream primarySkill;
primarySkill<<curHero->getPrimSkillLevel(m);
primarySkill << primSkillAreas[m]->bonusValue;
printAtMiddleLoc(primarySkill.str(), 53 + 70 * m, 166, FONT_SMALL, zwykly, to);
}
@ -365,10 +386,10 @@ void CHeroWindow::showAll(SDL_Surface * to)
//printing necessery texts
printAtLoc(CGI->generaltexth->jktexts[6].substr(1, CGI->generaltexth->jktexts[6].size()-2), 69, 232, FONT_SMALL, tytulowy, to);
std::ostringstream expstr;
expstr<<curHero->exp;
expstr << curHero->exp;
printAtLoc(expstr.str(), 68, 252, FONT_SMALL, zwykly, to);
printAtLoc(CGI->generaltexth->jktexts[7].substr(1, CGI->generaltexth->jktexts[7].size()-2), 213, 232, FONT_SMALL, tytulowy, to);
std::ostringstream manastr;
manastr << curHero->mana << '/' << curHero->manaLimit();
manastr << curHero->mana << '/' << heroWArt.manaLimit();
printAtLoc(manastr.str(), 211, 252, FONT_SMALL, zwykly, to);
}

View File

@ -37,7 +37,16 @@ public:
CHeroSwitcher(int serial);
};
//helper class for calculating values of hero bonuses without bonuses from picked up artifact
class CHeroWithMaybePickedArtifact : public IBonusBearer
{
public:
const CGHeroInstance *hero;
CWindowWithArtifacts *cww;
CHeroWithMaybePickedArtifact(CWindowWithArtifacts *Cww, const CGHeroInstance *Hero);
void getAllBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const OVERRIDE;
};
class CHeroWindow: public CWindowWithGarrison, public CWindowWithArtifacts
{
@ -61,6 +70,8 @@ class CHeroWindow: public CWindowWithGarrison, public CWindowWithArtifacts
LRClickableAreaWText * specArea;//speciality
MoraleLuckBox * morale, * luck;
std::vector<LRClickableAreaWTextComp *> secSkillAreas;
CHeroWithMaybePickedArtifact heroWArt;
public:
const CGHeroInstance * curHero;
AdventureMapButton * quitButton, * dismissButton, * questlogButton; //general

View File

@ -430,10 +430,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
}
else
{
battleints[255] = CAIHandler::getNewBattleAI(conf.cc.defaultBattleAI);
battleints[255]->init(new CBattleCallback(gs, 255, this));
// playerint[255]->init(new CCallback(gs,255,this));
// battleints[255] = playerint[255];
loadNeutralBattleAI();
}
serv->addStdVecItems(const_cast<CGameInfo*>(CGI)->state);
@ -493,6 +490,9 @@ void CClient::serialize( Handler &h, const int version )
nInt->init(callback);
nInt->serialize(h, version);
}
if(!vstd::contains(battleints, NEUTRAL_PLAYER))
loadNeutralBattleAI();
}
}
@ -588,6 +588,12 @@ void CClient::battleStarted(const BattleInfo * info)
battleints[254]->battleStart(info->belligerents[0], info->belligerents[1], info->tile, info->heroes[0], info->heroes[1], 1);
}
void CClient::loadNeutralBattleAI()
{
battleints[255] = CAIHandler::getNewBattleAI(conf.cc.defaultBattleAI);
battleints[255]->init(new CBattleCallback(gs, 255, this));
}
template void CClient::serialize( CISer<CLoadFile> &h, const int version );
template void CClient::serialize( COSer<CSaveFile> &h, const int version );

View File

@ -82,6 +82,8 @@ public:
void init();
void newGame(CConnection *con, StartInfo *si); //con - connection to server
void loadNeutralBattleAI();
void endGame(bool closeConnection = true);
void stopConnection();
void save(const std::string & fname);

View File

@ -74,6 +74,7 @@ CFocusable * CFocusable::inputWithFocus;
#undef min
#undef max
void CGarrisonSlot::hover (bool on)
{
////Hoverable::hover(on);
@ -4663,7 +4664,6 @@ void CArtPlace::select ()
if(slotID >= Arts::BACKPACK_START)
ourOwner->scrollBackpack(0); //will update slots
// Update the hero bonuses.
ourOwner->updateParentWindow();
ourOwner->safeRedraw();
}
@ -4695,7 +4695,7 @@ void CArtPlace::deactivate()
void CArtPlace::showAll(SDL_Surface *to)
{
if (ourArt && !picked)
if (ourArt && !picked && ourArt == ourOwner->curHero->getArt(slotID)) //last condition is needed for disassembling -> artifact may be gone, but we don't know yet TODO: real, nice solution
{
int graphic = locked ? 145 : ourArt->artType->id;
blitAt(graphics->artDefs->ourImages[graphic].bitmap, pos.x, pos.y, to);
@ -5161,16 +5161,17 @@ void CArtifactsOfHero::updateParentWindow()
if(!updateState)
{
cew->deactivate();
for(int g=0; g<ARRAY_COUNT(cew->heroInst); ++g)
{
if(cew->heroInst[g] == curHero)
{
cew->artifs[g]->setHero(curHero);
}
}
// for(int g=0; g<ARRAY_COUNT(cew->heroInst); ++g)
// {
// if(cew->heroInst[g] == curHero)
// {
// cew->artifs[g]->setHero(curHero);
// }
// }
cew->prepareBackground();
cew->redraw();
cew->activate();
}
}
@ -5199,13 +5200,14 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
if(dst.hero == curHero && dst.slot >= Arts::BACKPACK_START)
setSlotData(getArtPlace(dst.slot), dst.slot);
if(src.hero == curHero || dst.hero == curHero) //we need to update all slots, artifact might be combined and affect more slots
updateWornSlots();
updateWornSlots(false);
if(commonInfo->src == src) //artifact was taken from us
{
assert(commonInfo->dst == dst || dst.slot == dst.hero->artifactsInBackpack.size() + Arts::BACKPACK_START);
commonInfo->reset();
unmarkSlots();
updateParentWindow();
}
else if(commonInfo->dst == src) //the dest artifact was moved -> we are picking it
{
@ -5289,12 +5291,18 @@ void CArtifactsOfHero::artifactDisassembled(const ArtifactLocation &al)
updateWornSlots();
}
void CArtifactsOfHero::updateWornSlots()
void CArtifactsOfHero::updateWornSlots(bool redrawParent /*= true*/)
{
for(int i = 0; i < Arts::BACKPACK_START; i++)
setSlotData(getArtPlace(i), i);
updateParentWindow();
if(redrawParent)
updateParentWindow();
}
const CGHeroInstance * CArtifactsOfHero::getHero() const
{
return curHero;
}
void CExchangeWindow::close()
@ -5307,9 +5315,9 @@ void CExchangeWindow::activate()
quit->activate();
garr->activate();
artifs[0]->setHero(heroInst[0]);
//artifs[0]->setHero(heroInst[0]);
artifs[0]->activate();
artifs[1]->setHero(heroInst[1]);
//artifs[1]->setHero(heroInst[1]);
artifs[1]->activate();
for(int g=0; g<ARRAY_COUNT(secSkillAreas); g++)
@ -5446,11 +5454,12 @@ void CExchangeWindow::prepareBackground()
//heroes related thing
for(int b=0; b<ARRAY_COUNT(heroInst); b++)
{
CHeroWithMaybePickedArtifact heroWArt = CHeroWithMaybePickedArtifact(this, heroInst[b]);
//printing primary skills' amounts
for(int m=0; m<4; ++m)
{
std::ostringstream primarySkill;
primarySkill<<heroInst[b]->getPrimSkillLevel(m);
primarySkill << heroWArt.getPrimSkillLevel(m);
CSDL_Ext::printAtMiddle(primarySkill.str(), 352 + 93 * b, 35 + 36 * m, FONT_SMALL, zwykly, bg);
}
@ -5472,10 +5481,10 @@ void CExchangeWindow::prepareBackground()
printAtMiddle( makeNumberShort(heroInst[b]->mana), 155 + 490*b, 71, FONT_SMALL, zwykly, bg );
//setting morale
blitAt(graphics->morale30->ourImages[heroInst[b]->MoraleVal()+3].bitmap, 177 + 490*b, 45, bg);
blitAt(graphics->morale30->ourImages[heroWArt.MoraleVal()+3].bitmap, 177 + 490*b, 45, bg);
//setting luck
blitAt(graphics->luck30->ourImages[heroInst[b]->LuckVal()+3].bitmap, 213 + 490*b, 45, bg);
blitAt(graphics->luck30->ourImages[heroWArt.LuckVal()+3].bitmap, 213 + 490*b, 45, bg);
}
//printing portraits
@ -6453,7 +6462,7 @@ CThievesGuildWindow::~CThievesGuildWindow()
// delete resdatabar;
}
void MoraleLuckBox::set(const CBonusSystemNode *node)
void MoraleLuckBox::set(const IBonusBearer *node)
{
const int textId[] = {62, 88}; //eg %s \n\n\n {Current Luck Modifiers:}
const int noneTxtId = 108; //Russian version uses same text for neutral morale\luck
@ -6461,7 +6470,7 @@ void MoraleLuckBox::set(const CBonusSystemNode *node)
const int componentType[] = {SComponent::luck, SComponent::morale};
const int hoverTextBase[] = {7, 4};
const Bonus::BonusType bonusType[] = {Bonus::LUCK, Bonus::MORALE};
int (CBonusSystemNode::*getValue[])() const = {&CBonusSystemNode::LuckVal, &CBonusSystemNode::MoraleVal};
int (IBonusBearer::*getValue[])() const = {&IBonusBearer::LuckVal, &IBonusBearer::MoraleVal};
int mrlt = -9;
TModDescr mrl;
@ -6484,8 +6493,7 @@ void MoraleLuckBox::set(const CBonusSystemNode *node)
text += CGI->generaltexth->arraytxt[noneTxtId];
else
{
if (node->nodeType == CBonusSystemNode::STACK_INSTANCE &&
(node->hasBonusOfType (Bonus::UNDEAD) || node->hasBonusOfType(Bonus::BLOCK_MORALE) || node->hasBonusOfType(Bonus::NON_LIVING))) //it's a creature window
if (node->hasBonusOfType (Bonus::UNDEAD) || node->hasBonusOfType(Bonus::BLOCK_MORALE) || node->hasBonusOfType(Bonus::NON_LIVING)) //it's a creature window
{
text += CGI->generaltexth->arraytxt[113]; //unaffected by morale
}

View File

@ -70,6 +70,7 @@ class CStackInstance;
class IMarket;
class CTextBox;
class CArtifactInstance;
class IBonusBearer;
extern SDL_Color tytulowy, tlo, zwykly ;
@ -878,7 +879,7 @@ class MoraleLuckBox : public LRClickableAreaWTextComp
public:
bool morale; //true if morale, false if luck
void set(const CBonusSystemNode *node);
void set(const IBonusBearer *node);
void showAll(SDL_Surface * to);
MoraleLuckBox(bool Morale, const Rect &r);
@ -972,7 +973,7 @@ public:
/// Contains artifacts of hero. Distincts which artifacts are worn or backpacked
class CArtifactsOfHero : public CIntObject
{
const CGHeroInstance * curHero; //local copy of hero on which we operate
const CGHeroInstance * curHero;
std::vector<CArtPlace *> artWorn; // 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::vector<CArtPlace *> backpack; //hero's visible backpack (only 5 elements!)
@ -1012,6 +1013,7 @@ public:
CArtPlace *getArtPlace(int slot);
void setHero(const CGHeroInstance * hero);
const CGHeroInstance *getHero() const;
void dispose(); //free resources not needed after closing windows and reset state
void scrollBackpack(int dir); //dir==-1 => to left; dir==1 => to right
@ -1019,7 +1021,7 @@ public:
void markPossibleSlots(const CArtifactInstance* art);
void unmarkSlots(bool withRedraw = true);
void setSlotData (CArtPlace* artPlace, int slotID);
void updateWornSlots ();
void updateWornSlots (bool redrawParent = true);
void eraseSlotData (CArtPlace* artPlace, int slotID);
CArtifactsOfHero(const Point& position, bool createCommonPart = false); //c-tor

View File

@ -33,7 +33,7 @@ typedef si32 TBonusSubtype;
#define THC
#endif
#define NAME_VER ("VCMI 0.83b")
#define NAME_VER ("VCMI 0.83c")
extern std::string NAME; //full name
extern std::string NAME_AFFIX; //client / server
#define CONSOLE_LOGGING_LEVEL 5

View File

@ -622,30 +622,11 @@ int3 CGHeroInstance::getPosition(bool h3m) const //h3m=true - returns position o
}
}
si32 CGHeroInstance::manaLimit() const
{
return si32(getPrimSkillLevel(3) * (100.0f + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, 24)) / 10.0f);
}
//void CGHeroInstance::setPosition(int3 Pos, bool h3m) //as above, but sets position
//{
// if (h3m)
// pos = Pos;
// else
// pos = convertPosition(Pos,true);
//}
bool CGHeroInstance::canWalkOnSea() const
{
return hasBonusOfType(Bonus::FLYING_MOVEMENT) || hasBonusOfType(Bonus::WATER_WALKING);
}
int CGHeroInstance::getPrimSkillLevel(int id) const
{
int ret = valOfBonuses(Bonus::PRIMARY_SKILL, id);
amax(ret, id/2); //minimal value is 0 for attack and defense and 1 for spell power and knowledge
return ret;
}
ui8 CGHeroInstance::getSecSkillLevel(SecondarySkill skill) const
{
for(size_t i=0; i < secSkills.size(); ++i)

View File

@ -386,16 +386,11 @@ public:
unsigned int getTileCost(const TerrainTile &dest, const TerrainTile &from) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
unsigned int getLowestCreatureSpeed() const;
int3 getPosition(bool h3m = false) const; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
si32 manaLimit() const; //maximum mana value for this hero (basically 10*knowledge)
si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day
bool canWalkOnSea() const;
int getCurrentLuck(int stack=-1, bool town=false) const;
int getSpellCost(const CSpell *sp) const; //do not use during battles -> bonuses from army would be ignored
TModDescr getCurrentLuckModifiers(int stack=-1, bool town=false) const; //args as above
int getCurrentMorale(int stack=-1, bool town=false) const; //if stack - position of creature, if -1 then morale for hero is calculated; town - if bonuses from town (tavern) should be considered
TModDescr getCurrentMoraleModifiers(int stack=-1, bool town=false) const; //args as above
int getPrimSkillLevel(int id) const; //0-attack, 1-defence, 2-spell power, 3-knowledge
ui8 getSecSkillLevel(SecondarySkill skill) const; //0 - no skill
void setSecSkillLevel(SecondarySkill which, int val, bool abs);// abs == 0 - changes by value; 1 - sets to value

View File

@ -140,12 +140,12 @@ void DLL_EXPORT BonusList::eliminateDuplicates()
unique();
}
int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
int IBonusBearer::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
{
return valOfBonuses(Selector::type(type) && selector);
}
int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/) const
int IBonusBearer::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/) const
{
CSelector s = Selector::type(type);
if(subtype != -1)
@ -154,18 +154,18 @@ int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/)
return valOfBonuses(s);
}
int CBonusSystemNode::valOfBonuses(const CSelector &selector) const
int IBonusBearer::valOfBonuses(const CSelector &selector) const
{
BonusList hlp;
getBonuses(hlp, selector);
return hlp.totalValue();
}
bool CBonusSystemNode::hasBonus(const CSelector &selector) const
bool IBonusBearer::hasBonus(const CSelector &selector) const
{
return getBonuses(selector).size() > 0;
}
bool CBonusSystemNode::hasBonusOfType(Bonus::BonusType type, int subtype /*= -1*/) const
bool IBonusBearer::hasBonusOfType(Bonus::BonusType type, int subtype /*= -1*/) const
{
CSelector s = Selector::type(type);
if(subtype != -1)
@ -174,6 +174,150 @@ bool CBonusSystemNode::hasBonusOfType(Bonus::BonusType type, int subtype /*= -1*
return hasBonus(s);
}
void IBonusBearer::getModifiersWDescr(TModDescr &out, Bonus::BonusType type, int subtype /*= -1 */) const
{
getModifiersWDescr(out, subtype != -1 ? Selector::typeSybtype(type, subtype) : Selector::type(type));
}
void IBonusBearer::getModifiersWDescr(TModDescr &out, const CSelector &selector) const
{
getBonuses(selector).getModifiersWDescr(out);
}
int IBonusBearer::getBonusesCount(int from, int id) const
{
return getBonusesCount(Selector::source(from, id));
}
int IBonusBearer::getBonusesCount(const CSelector &selector) const
{
return getBonuses(selector).size();
}
void IBonusBearer::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
{
getBonuses(out, selector, 0, root);
// FOREACH_CONST_PARENT(p)
// p->getBonuses(out, selector, root ? root : this);
//
// bonuses.getBonuses(out, selector);
//
// if(!root)
// out.limit(*this);
}
BonusList IBonusBearer::getBonuses(const CSelector &selector) const
{
BonusList ret;
getBonuses(ret, selector);
return ret;
}
void IBonusBearer::getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
{
getAllBonuses(out, selector, limit, root);
out.eliminateDuplicates();
//
// getBonuses(out, selector); //first get all the bonuses
// out.remove_if(std::not1(limit)); //now remove the ones we don't like
// out.limit(*this); //apply bonuses' limiters
}
BonusList IBonusBearer::getBonuses(const CSelector &selector, const CSelector &limit) const
{
BonusList ret;
getBonuses(ret, selector, limit);
return ret;
}
bool IBonusBearer::hasBonusFrom(ui8 source, ui32 sourceID) const
{
return hasBonus(Selector::source(source,sourceID));
}
int IBonusBearer::MoraleVal() const
{
if(hasBonusOfType(Bonus::NON_LIVING) || hasBonusOfType(Bonus::UNDEAD) ||
hasBonusOfType(Bonus::NO_MORALE) || hasBonusOfType(Bonus::SIEGE_WEAPON))
return 0;
int ret = valOfBonuses(Selector::type(Bonus::MORALE));
if(hasBonusOfType(Bonus::SELF_MORALE)) //eg. minotaur
amax(ret, +1);
return abetw(ret, -3, +3);
}
int IBonusBearer::LuckVal() const
{
if(hasBonusOfType(Bonus::NO_LUCK))
return 0;
int ret = valOfBonuses(Selector::type(Bonus::LUCK));
if(hasBonusOfType(Bonus::SELF_LUCK)) //eg. halfling
amax(ret, +1);
return abetw(ret, -3, +3);
}
si32 IBonusBearer::Attack() const
{
si32 ret = valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
if(int frenzyPower = valOfBonuses(Bonus::IN_FRENZY)) //frenzy for attacker
{
ret += frenzyPower * Defense(false);
}
return ret;
}
si32 IBonusBearer::Defense(bool withFrenzy /*= true*/) const
{
si32 ret = valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
if(withFrenzy && hasBonusOfType(Bonus::IN_FRENZY)) //frenzy for defender
{
return 0;
}
return ret;
}
ui16 IBonusBearer::MaxHealth() const
{
return valOfBonuses(Bonus::STACK_HEALTH);
}
ui32 IBonusBearer::getMinDamage() const
{
return valOfBonuses(Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 0) || Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 1));
}
ui32 IBonusBearer::getMaxDamage() const
{
return valOfBonuses(Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 0) || Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 2));
}
si32 IBonusBearer::manaLimit() const
{
return si32(getPrimSkillLevel(3) * (100.0f + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, 24)) / 10.0f);
}
int IBonusBearer::getPrimSkillLevel(int id) const
{
int ret = 0;
if(id == PrimarySkill::ATTACK)
ret = Attack();
else if(id == PrimarySkill::DEFENSE)
ret = Defense();
else
ret = valOfBonuses(Bonus::PRIMARY_SKILL, id);
amax(ret, id/2); //minimal value is 0 for attack and defense and 1 for spell power and knowledge
return ret;
}
Bonus * CBonusSystemNode::getBonus(const CSelector &selector)
{
Bonus *ret = bonuses.getFirst(selector);
@ -195,25 +339,6 @@ const Bonus * CBonusSystemNode::getBonus( const CSelector &selector ) const
return (const_cast<CBonusSystemNode*>(this))->getBonus(selector);
}
void CBonusSystemNode::getModifiersWDescr(TModDescr &out, Bonus::BonusType type, int subtype /*= -1 */) const
{
getModifiersWDescr(out, subtype != -1 ? Selector::typeSybtype(type, subtype) : Selector::type(type));
}
void CBonusSystemNode::getModifiersWDescr(TModDescr &out, const CSelector &selector) const
{
getBonuses(selector).getModifiersWDescr(out);
}
int CBonusSystemNode::getBonusesCount(int from, int id) const
{
return getBonusesCount(Selector::source(from, id));
}
int CBonusSystemNode::getBonusesCount(const CSelector &selector) const
{
return getBonuses(selector).size();
}
void CBonusSystemNode::getParents(TCNodes &out) const /*retreives list of parent nodes (nodes to inherit bonuses from) */
{
BOOST_FOREACH(const CBonusSystemNode *parent, parents)
@ -226,42 +351,6 @@ void CBonusSystemNode::getParents(TNodes &out)
out.insert(const_cast<CBonusSystemNode*>(parent));
}
void CBonusSystemNode::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
{
getBonuses(out, selector, 0, root);
// FOREACH_CONST_PARENT(p)
// p->getBonuses(out, selector, root ? root : this);
//
// bonuses.getBonuses(out, selector);
//
// if(!root)
// out.limit(*this);
}
BonusList CBonusSystemNode::getBonuses(const CSelector &selector) const
{
BonusList ret;
getBonuses(ret, selector);
return ret;
}
void CBonusSystemNode::getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
{
getAllBonuses(out, selector, limit, root);
out.eliminateDuplicates();
//
// getBonuses(out, selector); //first get all the bonuses
// out.remove_if(std::not1(limit)); //now remove the ones we don't like
// out.limit(*this); //apply bonuses' limiters
}
BonusList CBonusSystemNode::getBonuses(const CSelector &selector, const CSelector &limit) const
{
BonusList ret;
getBonuses(ret, selector, limit);
return ret;
}
void CBonusSystemNode::getAllBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
{
FOREACH_CONST_PARENT(p)
@ -273,76 +362,6 @@ void CBonusSystemNode::getAllBonuses(BonusList &out, const CSelector &selector,
out.limit(*this);
}
bool CBonusSystemNode::hasBonusFrom(ui8 source, ui32 sourceID) const
{
return hasBonus(Selector::source(source,sourceID));
}
int CBonusSystemNode::MoraleVal() const
{
if(hasBonusOfType(Bonus::NON_LIVING) || hasBonusOfType(Bonus::UNDEAD) ||
hasBonusOfType(Bonus::NO_MORALE) || hasBonusOfType(Bonus::SIEGE_WEAPON))
return 0;
int ret = valOfBonuses(Selector::type(Bonus::MORALE));
if(hasBonusOfType(Bonus::SELF_MORALE)) //eg. minotaur
amax(ret, +1);
return abetw(ret, -3, +3);
}
int CBonusSystemNode::LuckVal() const
{
if(hasBonusOfType(Bonus::NO_LUCK))
return 0;
int ret = valOfBonuses(Selector::type(Bonus::LUCK));
if(hasBonusOfType(Bonus::SELF_LUCK)) //eg. halfling
amax(ret, +1);
return abetw(ret, -3, +3);
}
si32 CBonusSystemNode::Attack() const
{
si32 ret = valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
if(int frenzyPower = valOfBonuses(Bonus::IN_FRENZY)) //frenzy for attacker
{
ret += frenzyPower * Defense(false);
}
return ret;
}
si32 CBonusSystemNode::Defense(bool withFrenzy /*= true*/) const
{
si32 ret = valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
if(withFrenzy && hasBonusOfType(Bonus::IN_FRENZY)) //frenzy for defender
{
return 0;
}
return ret;
}
ui16 CBonusSystemNode::MaxHealth() const
{
return valOfBonuses(Bonus::STACK_HEALTH);
}
ui32 CBonusSystemNode::getMinDamage() const
{
return valOfBonuses(Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 0) || Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 1));
}
ui32 CBonusSystemNode::getMaxDamage() const
{
return valOfBonuses(Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 0) || Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 2));
}
CBonusSystemNode::CBonusSystemNode()
{
nodeType = UNKNOWN;

View File

@ -369,7 +369,47 @@ public:
{}
};
class DLL_EXPORT CBonusSystemNode
class DLL_EXPORT IBonusBearer
{
public:
virtual void getAllBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const = 0;
//new bonusing node interface
// * selector is predicate that tests if HeroBonus matches our criteria
// * root is node on which call was made (NULL will be replaced with this)
//interface
void getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const; //as above but without duplicates
void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
void getModifiersWDescr(TModDescr &out, const CSelector &selector) const; //out: pairs<modifier value, modifier description>
int getBonusesCount(const CSelector &selector) const;
int valOfBonuses(const CSelector &selector) const;
bool hasBonus(const CSelector &selector) const;
BonusList getBonuses(const CSelector &selector, const CSelector &limit) const;
BonusList getBonuses(const CSelector &selector) const;
//legacy interface
int valOfBonuses(Bonus::BonusType type, const CSelector &selector) const;
int valOfBonuses(Bonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then anyt;
bool hasBonusOfType(Bonus::BonusType type, int subtype = -1) const;//determines if hero has a bonus of given type (and optionally subtype)
bool hasBonusFrom(ui8 source, ui32 sourceID) const;
void getModifiersWDescr( TModDescr &out, Bonus::BonusType type, int subtype = -1 ) const; //out: pairs<modifier value, modifier description>
int getBonusesCount(int from, int id) const;
//various hlp functions for non-trivial values
ui32 getMinDamage() const; //used for stacks and creatures only
ui32 getMaxDamage() const;
int MoraleVal() const; //range [-3, +3]
int LuckVal() const; //range [-3, +3]
si32 Attack() const; //get attack of stack with all modificators
si32 Defense(bool withFrenzy = true) const; //get defense of stack with all modificators
ui16 MaxHealth() const; //get max HP of stack with all modifiers
si32 manaLimit() const; //maximum mana value for this hero (basically 10*knowledge)
int getPrimSkillLevel(int id) const; //0-attack, 1-defence, 2-spell power, 3-knowledge
};
class DLL_EXPORT CBonusSystemNode : public IBonusBearer
{
public:
BonusList bonuses; //wielded bonuses (local or up-propagated here)
@ -384,39 +424,11 @@ public:
CBonusSystemNode();
virtual ~CBonusSystemNode();
//new bonusing node interface
// * selector is predicate that tests if HeroBonus matches our criteria
// * root is node on which call was made (NULL will be replaced with this)
//interface
void getAllBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const;
void getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const; //as above but without duplicates
void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
void getModifiersWDescr(TModDescr &out, const CSelector &selector) const; //out: pairs<modifier value, modifier description>
int getBonusesCount(const CSelector &selector) const;
int valOfBonuses(const CSelector &selector) const;
bool hasBonus(const CSelector &selector) const;
BonusList getBonuses(const CSelector &selector, const CSelector &limit) const;
BonusList getBonuses(const CSelector &selector) const;
void getParents(TCNodes &out) const; //retrieves list of parent nodes (nodes to inherit bonuses from),
//legacy interface
int valOfBonuses(Bonus::BonusType type, const CSelector &selector) const;
int valOfBonuses(Bonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then anyt;
bool hasBonusOfType(Bonus::BonusType type, int subtype = -1) const;//determines if hero has a bonus of given type (and optionally subtype)
bool hasBonusFrom(ui8 source, ui32 sourceID) const;
void getModifiersWDescr( TModDescr &out, Bonus::BonusType type, int subtype = -1 ) const; //out: pairs<modifier value, modifier description>
int getBonusesCount(int from, int id) const;
ui32 getMinDamage() const; //used for stacks and creatures only
ui32 getMaxDamage() const;
int MoraleVal() const; //range [-3, +3]
int LuckVal() const; //range [-3, +3]
si32 Attack() const; //get attack of stack with all modificators
si32 Defense(bool withFrenzy = true) const; //get defense of stack with all modificators
ui16 MaxHealth() const; //get max HP of stack with all modifiers
const Bonus *getBonus(const CSelector &selector) const;
//non-const interface
void getParents(TNodes &out); //retrieves list of parent nodes (nodes to inherit bonuses from)
void getRedParents(TNodes &out); //retrieves list of red parent nodes (nodes bonuses propagate from)

View File

@ -2578,7 +2578,7 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u
// if (src.slot >= 19 && dst.slot >= 19 && src.slot < dst.slot)
// dst.slot--;
if (src.slot == dst.slot)
if (src.slot == dst.slot && src.hero == dst.hero)
COMPLAIN_RET("Won't move artifact: Dest same as source!");
//moving art to backpack is always allowed (we've ruled out exceptions)