mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Many fixes around bonus system. Some basic propagation mechanism (not clever but works).
This commit is contained in:
parent
519a4186de
commit
4c9edd3f06
@ -1922,7 +1922,7 @@ void CAdvMapInt::tileHovered(const int3 &tile)
|
||||
const CGTownInstance* townObj = dynamic_cast<const CGTownInstance*>(objAtTile);
|
||||
|
||||
// Show movement cursor for unguarded enemy towns, otherwise attack cursor.
|
||||
if (townObj && !townObj->stacksCount())
|
||||
if (townObj && !townObj->armedGarrison())
|
||||
CCS->curh->changeGraphic(0, 9 + turns*6);
|
||||
else
|
||||
CCS->curh->changeGraphic(0, 5 + turns*6);
|
||||
@ -1955,7 +1955,7 @@ void CAdvMapInt::tileHovered(const int3 &tile)
|
||||
const CGGarrison* garrObj = dynamic_cast<const CGGarrison*>(objAtTile); //TODO evil evil cast!
|
||||
|
||||
// Show battle cursor for guarded enemy garrisons, otherwise movement cursor.
|
||||
if (garrObj&& garrObj->stacksCount()
|
||||
if (garrObj && garrObj->stacksCount()
|
||||
&& !LOCPLINT->cb->getPlayerRelations( LOCPLINT->playerID, garrObj->tempOwner) )
|
||||
CCS->curh->changeGraphic(0, 5 + turns*6);
|
||||
else
|
||||
|
@ -89,9 +89,7 @@
|
||||
+ 66 SPELL_AFTER_ATTACK 0 42 20 //black knights
|
||||
+ 67 DOUBLE_DAMAGE_CHANCE 20 0 0 //vampire lords
|
||||
+ 67 SPELL_AFTER_ATTACK 0 42 20 //dread knights
|
||||
+ 68 ENEMY_MORALE_DECREASING -1 0 0 //bone dragon
|
||||
+ 68 DRAGON_NATURE 0 0 0 //bone dragon is a dragon
|
||||
+ 69 ENEMY_MORALE_DECREASING -1 0 0 //ghost dragon
|
||||
+ 69 SPELL_AFTER_ATTACK 0 75 20 //ghost dragon
|
||||
+ 69 DRAGON_NATURE 0 0 0 //ghost dragon is a dragon
|
||||
+ 70 SPELL_IMMUNITY 0 62 0 //troglodytes are immune to blind
|
||||
@ -190,4 +188,4 @@
|
||||
- 47 FLYING //cerberus doesn't fly
|
||||
- 120 DOUBLE_WIDE //psychic elemental
|
||||
- 121 DOUBLE_WIDE //magic elemental
|
||||
0
|
||||
0
|
@ -1100,27 +1100,6 @@ si8 BattleInfo::canTeleportTo(const CStack * stack, THex destHex, int telportLev
|
||||
|
||||
}
|
||||
|
||||
// void BattleInfo::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
|
||||
// {
|
||||
// CBonusSystemNode::getBonuses(out, selector, root);
|
||||
//
|
||||
// const CStack *dest = dynamic_cast<const CStack*>(root);
|
||||
// if (!dest)
|
||||
// return;
|
||||
//
|
||||
// //TODO: make it in clean way
|
||||
// if(Selector::matchesType(selector, Bonus::MORALE) || Selector::matchesType(selector, Bonus::LUCK))
|
||||
// {
|
||||
// BOOST_FOREACH(const CStack *s, stacks)
|
||||
// {
|
||||
// if(s->owner == dest->owner)
|
||||
// s->getBonuses(out, selector, Selector::effectRange(Bonus::ONLY_ALLIED_ARMY), this);
|
||||
// else
|
||||
// s->getBonuses(out, selector, Selector::effectRange(Bonus::ONLY_ENEMY_ARMY), this);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
bool BattleInfo::battleCanShoot(const CStack * stack, THex dest) const
|
||||
{
|
||||
const CStack *dst = getStackT(dest);
|
||||
@ -1223,7 +1202,9 @@ si8 BattleInfo::battleMaxSpellLevel() const
|
||||
void BattleInfo::localInit()
|
||||
{
|
||||
belligerents[0]->battle = belligerents[1]->battle = this;
|
||||
//TODO: attach battle to belligerents
|
||||
|
||||
BOOST_FOREACH(CArmedInstance *b, belligerents)
|
||||
b->attachTo(this);
|
||||
|
||||
BOOST_FOREACH(CStack *s, stacks)
|
||||
{
|
||||
@ -1492,39 +1473,6 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
||||
}
|
||||
}
|
||||
|
||||
// //giving building bonuses, if siege and we have harrisoned hero
|
||||
// if (town)
|
||||
// {
|
||||
// if (heroes[1])
|
||||
// {
|
||||
// for (int i=0; i<4; i++)
|
||||
// {
|
||||
// int val = town->defenceBonus(i);
|
||||
// if (val)
|
||||
// {
|
||||
// GiveBonus gs;
|
||||
// gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::PRIMARY_SKILL, Bonus::OBJECT, val, -1, "", i);
|
||||
// gs.id = heroes[1]->id;
|
||||
// sendAndApply(&gs);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else//if we don't have hero - apply separately, if hero present - will be taken from hero bonuses
|
||||
// {
|
||||
// if(town->subID == 0 && vstd::contains(town->builtBuildings,22)) //castle, brotherhood of sword built
|
||||
// for(int g=0; g<stacks.size(); ++g)
|
||||
// stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 2, Bonus::TOWN_STRUCTURE));
|
||||
//
|
||||
// else if(vstd::contains(town->builtBuildings,5)) //tavern is built
|
||||
// for(int g=0; g<stacks.size(); ++g)
|
||||
// stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TOWN_STRUCTURE));
|
||||
//
|
||||
// if(town->subID == 1 && vstd::contains(town->builtBuildings,21)) //rampart, fountain of fortune is present
|
||||
// for(int g=0; g<stacks.size(); ++g)
|
||||
// stacks[g]->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, 2, Bonus::TOWN_STRUCTURE));
|
||||
// }
|
||||
// }
|
||||
|
||||
//giving terrain overalay premies
|
||||
int bonusSubtype = -1;
|
||||
switch(terType)
|
||||
@ -1586,12 +1534,13 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
||||
if(town) //during siege always take premies for native terrain of faction
|
||||
terrain = VLC->heroh->nativeTerrains[town->town->typeID];
|
||||
|
||||
ILimiter *nativeTerrain = new CreatureNativeTerrainLimiter(terrain);
|
||||
boost::shared_ptr<ILimiter> nativeTerrain(new CreatureNativeTerrainLimiter(terrain));
|
||||
curB->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
||||
curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
||||
curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//tactics
|
||||
int tacticLvls[2] = {0};
|
||||
for(int i = 0; i < ARRAY_COUNT(tacticLvls); i++)
|
||||
{
|
||||
@ -1607,6 +1556,28 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
||||
else
|
||||
curB->tacticDistance = 0;
|
||||
|
||||
|
||||
// workaround — bonuses affecting only enemy
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
TNodes nodes;
|
||||
curB->belligerents[i]->getRedAncestors(nodes);
|
||||
BOOST_FOREACH(CBonusSystemNode *n, nodes)
|
||||
{
|
||||
BOOST_FOREACH(Bonus *b, n->exportedBonuses)
|
||||
{
|
||||
if(b->effectRange == Bonus::ONLY_ENEMY_ARMY/* && b->propagator && b->propagator->shouldBeAttached(curB)*/)
|
||||
{
|
||||
Bonus *bCopy = new Bonus(*b);
|
||||
bCopy->effectRange = Bonus::NO_LIMIT;
|
||||
bCopy->propagator.reset();
|
||||
bCopy->limiter.reset(new StackOwnerLimiter(curB->sides[!i]));
|
||||
curB->addNewBonus(bCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return curB;
|
||||
}
|
||||
|
||||
|
@ -496,7 +496,7 @@ void CArtHandler::giveArtBonus( int aid, Bonus::BonusType type, int val, int sub
|
||||
added->valType = valType;
|
||||
added->limiter.reset(limiter);
|
||||
if(type == Bonus::MORALE || Bonus::LUCK)
|
||||
added->description = "\n" + artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
|
||||
added->description = artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
|
||||
artifacts[aid]->addNewBonus(added);
|
||||
}
|
||||
|
||||
|
@ -329,7 +329,7 @@ void CCreatureHandler::loadCreatures()
|
||||
if(boost::algorithm::find_first(ncre.abilityRefs, "const_raises_morale"))
|
||||
{
|
||||
ncre.addBonus(+1, Bonus::MORALE);;
|
||||
ncre.bonuses.back()->effectRange = Bonus::ONLY_ALLIED_ARMY;
|
||||
ncre.bonuses.back()->addPropagator(new CPropagatorNodeType(CBonusSystemNode::HERO));
|
||||
}
|
||||
if(boost::algorithm::find_first(ncre.abilityRefs, "const_lowers_morale"))
|
||||
{
|
||||
|
@ -3010,7 +3010,7 @@ PlayerState::PlayerState()
|
||||
: color(-1), currentSelection(0xffffffff), enteredWinningCheatCode(0),
|
||||
enteredLosingCheatCode(0), status(INGAME), daysWithoutCastle(0)
|
||||
{
|
||||
|
||||
nodeType = PLAYER;
|
||||
}
|
||||
|
||||
std::string PlayerState::nodeName() const
|
||||
@ -3129,3 +3129,8 @@ DuelParameters::DuelParameters()
|
||||
terType = TerrainTile::dirt;
|
||||
bfieldType = 15;
|
||||
}
|
||||
|
||||
TeamState::TeamState()
|
||||
{
|
||||
nodeType = TEAM;
|
||||
}
|
@ -167,7 +167,7 @@ public:
|
||||
std::set<ui8> players; // members of this team
|
||||
std::vector<std::vector<std::vector<ui8> > > fogOfWarMap; //true - visible, false - hidden
|
||||
|
||||
//TeamState();
|
||||
TeamState();
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@ -977,10 +977,12 @@ void CGHeroInstance::initObj()
|
||||
bonus->subtype = PrimarySkill::ATTACK;
|
||||
speciality.addNewBonus(bonus);
|
||||
|
||||
bonus = new Bonus(*bonus);
|
||||
bonus->subtype = PrimarySkill::DEFENSE;
|
||||
speciality.addNewBonus(bonus);
|
||||
//values will be calculated later
|
||||
|
||||
bonus = new Bonus(*bonus);
|
||||
bonus->type = Bonus::STACKS_SPEED;
|
||||
bonus->val = 1; //+1 speed
|
||||
speciality.addNewBonus(bonus);
|
||||
@ -993,6 +995,8 @@ void CGHeroInstance::initObj()
|
||||
bonus->subtype = it->subtype; //skill id
|
||||
bonus->val = it->val; //value per level, in percent
|
||||
speciality.addNewBonus(bonus);
|
||||
bonus = new Bonus(*bonus);
|
||||
|
||||
switch (it->additionalinfo)
|
||||
{
|
||||
case 0: //normal
|
||||
@ -1068,13 +1072,16 @@ void CGHeroInstance::initObj()
|
||||
bonus->subtype = it->subtype; //base id
|
||||
bonus->additionalInfo = it->additionalinfo; //target id
|
||||
speciality.addNewBonus(bonus);
|
||||
bonus = new Bonus(*bonus);
|
||||
|
||||
for (std::set<ui32>::iterator i = (*creatures)[it->subtype]->upgrades.begin();
|
||||
i != (*creatures)[it->subtype]->upgrades.end(); i++)
|
||||
{
|
||||
bonus->subtype = *i; //propagate for regular upgrades of base creature
|
||||
speciality.addNewBonus(bonus);
|
||||
bonus = new Bonus(*bonus);
|
||||
}
|
||||
delNull(bonus);
|
||||
break;
|
||||
}
|
||||
case 10://resource generation
|
||||
@ -1162,7 +1169,7 @@ void CGHeroInstance::UpdateSpeciality()
|
||||
void CGHeroInstance::updateSkill(int which, int val)
|
||||
{
|
||||
if(which == LEADERSHIP || which == LUCK)
|
||||
{
|
||||
{ //luck-> VLC->generaltexth->arraytxt[73+luckSkill]; VLC->generaltexth->arraytxt[104+moraleSkill]
|
||||
bool luck = which == LUCK;
|
||||
Bonus::BonusType type[] = {Bonus::MORALE, Bonus::LUCK};
|
||||
|
||||
@ -1445,60 +1452,6 @@ void CGHeroInstance::pushPrimSkill(int which, int val)
|
||||
addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::HERO_BASE_SKILL, val, id, which));
|
||||
}
|
||||
|
||||
// void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
|
||||
// {
|
||||
// #define FOREACH_OWNER_TOWN(town) if(const PlayerState *p = cb->getPlayerState(tempOwner)) BOOST_FOREACH(const CGTownInstance *town, p->towns)
|
||||
//
|
||||
// CArmedInstance::getBonuses(out, selector, root); ///that's not part of macro!
|
||||
//
|
||||
// //TODO eliminate by moving secondary skills effects to bonus system
|
||||
// if(Selector::matchesType(selector, Bonus::LUCK))
|
||||
// {
|
||||
// //luck skill
|
||||
// if(int luckSkill = getSecSkillLevel(9))
|
||||
// out.push_back(Bonus(Bonus::PERMANENT, Bonus::LUCK, Bonus::SECONDARY_SKILL, luckSkill, 9, VLC->generaltexth->arraytxt[73+luckSkill]));
|
||||
//
|
||||
// //guardian spirit
|
||||
// FOREACH_OWNER_TOWN(t)
|
||||
// if(t->subID ==1 && vstd::contains(t->builtBuildings,26)) //rampart with grail
|
||||
// out.push_back(Bonus(Bonus::PERMANENT, Bonus::LUCK, Bonus::TOWN_STRUCTURE, +2, 26, VLC->generaltexth->buildings[1][26].first + " +2"));
|
||||
// }
|
||||
//
|
||||
// if(Selector::matchesType(selector, Bonus::SEA_MOVEMENT))
|
||||
// {
|
||||
// //lighthouses
|
||||
// FOREACH_OWNER_TOWN(t)
|
||||
// if(t->subID == 0 && vstd::contains(t->builtBuildings,17)) //castle
|
||||
// out.push_back(Bonus(Bonus::PERMANENT, Bonus::SEA_MOVEMENT, Bonus::TOWN_STRUCTURE, +500, 17, VLC->generaltexth->buildings[0][17].first + " +500"));
|
||||
// }
|
||||
//
|
||||
// if(Selector::matchesType(selector, Bonus::MORALE))
|
||||
// {
|
||||
// //leadership
|
||||
// if(int moraleSkill = getSecSkillLevel(6))
|
||||
// out.push_back(Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::SECONDARY_SKILL, moraleSkill, 6, VLC->generaltexth->arraytxt[104+moraleSkill]));
|
||||
//
|
||||
// //colossus
|
||||
// FOREACH_OWNER_TOWN(t)
|
||||
// if(t->subID == 0 && vstd::contains(t->builtBuildings,26)) //castle
|
||||
// out.push_back(Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::TOWN_STRUCTURE, +2, 26, VLC->generaltexth->buildings[0][26].first + " +2"));
|
||||
// }
|
||||
//
|
||||
// if(Selector::matchesTypeSubtype(selector, Bonus::SECONDARY_SKILL_PREMY, 12)) //necromancy
|
||||
// {
|
||||
// FOREACH_OWNER_TOWN(t)
|
||||
// {
|
||||
// if(t->subID == 4) //necropolis
|
||||
// {
|
||||
// if(vstd::contains(t->builtBuildings,21)) //necromancy amplifier
|
||||
// out.push_back(Bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, Bonus::TOWN_STRUCTURE, +10, 21, VLC->generaltexth->buildings[4][21].first + " +10%", 12));
|
||||
// if(vstd::contains(t->builtBuildings,26)) //grail - Soul prison
|
||||
// out.push_back(Bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, Bonus::TOWN_STRUCTURE, +20, 26, VLC->generaltexth->buildings[4][26].first + " +20%", 12));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
EAlignment CGHeroInstance::getAlignment() const
|
||||
{
|
||||
return type->heroClass->getAlignment();
|
||||
@ -1984,39 +1937,6 @@ int CGTownInstance::spellsAtLevel(int level, bool checkGuild) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CGTownInstance::defenceBonus(int type) const
|
||||
{
|
||||
int ret=0;
|
||||
switch (type)
|
||||
{
|
||||
/*attack*/ case 0:
|
||||
if (subID == 6 && vstd::contains(builtBuildings,26))//Stronghold, grail
|
||||
ret += 12;
|
||||
if (subID == 7 && vstd::contains(builtBuildings,26))//Fortress, grail
|
||||
ret += 10;
|
||||
if (subID == 7 && vstd::contains(builtBuildings,22))//Fortress, Blood Obelisk
|
||||
ret += 2;
|
||||
return ret;
|
||||
/*defence*/ case 1:
|
||||
if (subID == 7 && vstd::contains(builtBuildings,21))//Fortress, Glyphs of Fear
|
||||
ret += 2;
|
||||
if (subID == 7 && vstd::contains(builtBuildings,26))//Fortress, Grail
|
||||
ret += 10;
|
||||
return ret;
|
||||
/*spellpower*/ case 2:
|
||||
if (subID == 3 && vstd::contains(builtBuildings,21))//Inferno, Brimstone Clouds
|
||||
ret += 2;
|
||||
if (subID == 5 && vstd::contains(builtBuildings,26))//Dungeon, Grail
|
||||
ret += 12;
|
||||
return ret;
|
||||
/*knowledge*/ case 3:
|
||||
if (subID == 2 && vstd::contains(builtBuildings,26))//Tower, Grail
|
||||
ret += 15;
|
||||
return ret;
|
||||
}
|
||||
return 0;//Why we are here? wrong type?
|
||||
}
|
||||
|
||||
bool CGTownInstance::needsLastStack() const
|
||||
{
|
||||
if(garrisonHero)
|
||||
@ -2028,25 +1948,30 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
|
||||
{
|
||||
if( !cb->gameState()->getPlayerRelations( getOwner(), h->getOwner() ))//if this is enemy
|
||||
{
|
||||
if(stacksCount() > 0 || visitingHero)
|
||||
if(armedGarrison() || visitingHero)
|
||||
{
|
||||
const CGHeroInstance *defendingHero = NULL;
|
||||
const CArmedInstance *defendingArmy = this;
|
||||
|
||||
if(visitingHero)
|
||||
defendingHero = visitingHero;
|
||||
else if(garrisonHero)
|
||||
defendingHero = garrisonHero;
|
||||
|
||||
const CArmedInstance *defendingArmy = this;
|
||||
if(defendingHero)
|
||||
defendingArmy = defendingHero;
|
||||
|
||||
bool outsideTown = (defendingHero == visitingHero && garrisonHero);
|
||||
|
||||
//TODO
|
||||
//"borrowing" army from garrison to visiting hero
|
||||
|
||||
cb->startBattleI(h, defendingArmy, getSightCenter(), h, defendingHero, false, boost::bind(&CGTownInstance::fightOver, this, h, _1), (outsideTown ? NULL : this));
|
||||
}
|
||||
else
|
||||
{
|
||||
cb->setOwner(id, h->tempOwner);
|
||||
removeCapitols (h->getOwner());
|
||||
removeCapitols(h->getOwner());
|
||||
cb->heroVisitCastle(id, h->id);
|
||||
}
|
||||
}
|
||||
@ -2172,7 +2097,7 @@ int3 CGTownInstance::getSightCenter() const
|
||||
|
||||
ui8 CGTownInstance::getPassableness() const
|
||||
{
|
||||
if ( !stacksCount() )//empty castle - anyone can visit
|
||||
if (!armedGarrison())//empty castle - anyone can visit
|
||||
return ALL_PLAYERS;
|
||||
if ( tempOwner == 255 )//neutral guarded - noone can visit
|
||||
return 0;
|
||||
@ -2309,18 +2234,85 @@ void CGTownInstance::deserializationFix()
|
||||
|
||||
void CGTownInstance::recreateBuildingsBonuses()
|
||||
{
|
||||
bonuses.remove_if(Selector::sourceType(Bonus::TOWN_STRUCTURE)); //TODO memory leak
|
||||
BonusList bl;
|
||||
exportedBonuses.getBonuses(bl, Selector::sourceType(Bonus::TOWN_STRUCTURE));
|
||||
BOOST_FOREACH(Bonus *b, bl)
|
||||
removeBonus(b);
|
||||
|
||||
if(subID == 4 && vstd::contains(builtBuildings, 17))
|
||||
addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::DARKNESS, Bonus::TOWN_STRUCTURE, 20, 17));
|
||||
|
||||
if(subID == 1 && vstd::contains(builtBuildings,21)) //rampart, fountain of fortune
|
||||
addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::LUCK, Bonus::TOWN_STRUCTURE, +2, 21, VLC->generaltexth->buildings[1][21].first + " +2"));
|
||||
if(subID != 0 || !addBonusIfBuilt(22, Bonus::MORALE, +2)) //tricky! -> checks tavern only if no bratherhood of sword or not a castle
|
||||
addBonusIfBuilt(5, Bonus::MORALE, +1);
|
||||
|
||||
if(subID == 0) //castle
|
||||
{
|
||||
addBonusIfBuilt(17, Bonus::SEA_MOVEMENT, +500, new CPropagatorNodeType(PLAYER)); //lighthouses
|
||||
addBonusIfBuilt(26, Bonus::MORALE, +2, new CPropagatorNodeType(PLAYER)); //colossus
|
||||
}
|
||||
else if(subID == 1) //rampart
|
||||
{
|
||||
addBonusIfBuilt(21, Bonus::LUCK, +2); //fountain of fortune
|
||||
addBonusIfBuilt(21, Bonus::LUCK, +2, new CPropagatorNodeType(PLAYER)); //guardian spirit
|
||||
}
|
||||
else if(subID == 2) //tower
|
||||
{
|
||||
addBonusIfBuilt(26, Bonus::PRIMARY_SKILL, +15, PrimarySkill::KNOWLEDGE); //grail
|
||||
}
|
||||
else if(subID == 3) //Inferno
|
||||
{
|
||||
addBonusIfBuilt(21, Bonus::PRIMARY_SKILL, +2, PrimarySkill::SPELL_POWER); //Brimstone Clouds
|
||||
}
|
||||
else if(subID == 4) //necropolis
|
||||
{
|
||||
addBonusIfBuilt(17, Bonus::DARKNESS, +20);
|
||||
addBonusIfBuilt(21, Bonus::SECONDARY_SKILL_PREMY, +10, new CPropagatorNodeType(PLAYER), CGHeroInstance::NECROMANCY); //necromancy amplifier
|
||||
addBonusIfBuilt(26, Bonus::SECONDARY_SKILL_PREMY, +20, new CPropagatorNodeType(PLAYER), CGHeroInstance::NECROMANCY); //Soul prison
|
||||
}
|
||||
else if(subID == 5) //Dungeon
|
||||
{
|
||||
addBonusIfBuilt(26, Bonus::PRIMARY_SKILL, +12, PrimarySkill::SPELL_POWER); //grail
|
||||
}
|
||||
else if(subID == 6) //Stronghold
|
||||
{
|
||||
addBonusIfBuilt(26, Bonus::PRIMARY_SKILL, +20, PrimarySkill::ATTACK); //grail
|
||||
}
|
||||
else if(subID == 7) //Fortress
|
||||
{
|
||||
addBonusIfBuilt(21, Bonus::PRIMARY_SKILL, +2, PrimarySkill::DEFENSE); //Glyphs of Fear
|
||||
addBonusIfBuilt(22, Bonus::PRIMARY_SKILL, +2, PrimarySkill::ATTACK); //Blood Obelisk
|
||||
addBonusIfBuilt(26, Bonus::PRIMARY_SKILL, +10, PrimarySkill::ATTACK); //grail
|
||||
addBonusIfBuilt(26, Bonus::PRIMARY_SKILL, +10, PrimarySkill::DEFENSE); //grail
|
||||
}
|
||||
else if(subID == 8)
|
||||
{
|
||||
|
||||
if(subID == 0 && vstd::contains(builtBuildings,22)) //castle, brotherhood of sword built
|
||||
addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::TOWN_STRUCTURE, +2, 22, VLC->generaltexth->buildings[0][22].first + " +2"));
|
||||
else if(vstd::contains(builtBuildings,5)) //tavern is built
|
||||
addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::TOWN_STRUCTURE, +1, 5, VLC->generaltexth->buildings[0][5].first + " +1"));
|
||||
}
|
||||
}
|
||||
|
||||
bool CGTownInstance::addBonusIfBuilt(int building, int type, int val, int subtype /*= -1*/)
|
||||
{
|
||||
return addBonusIfBuilt(building, type, val, NULL, subtype);
|
||||
}
|
||||
|
||||
bool CGTownInstance::addBonusIfBuilt(int building, int type, int val, IPropagator *prop, int subtype /*= -1*/)
|
||||
{
|
||||
if(vstd::contains(builtBuildings, building))
|
||||
{
|
||||
std::ostringstream descr;
|
||||
descr << VLC->generaltexth->buildings[subID][building].first << " ";
|
||||
if(val > 0)
|
||||
descr << "+";
|
||||
else if(val < 0)
|
||||
descr << "-";
|
||||
descr << val;
|
||||
|
||||
Bonus *b = new Bonus(Bonus::PERMANENT, type, Bonus::TOWN_STRUCTURE, val, building, descr.str(), subtype);
|
||||
if(prop)
|
||||
b->addPropagator(prop);
|
||||
addNewBonus(b);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CGTownInstance::setVisitingHero(CGHeroInstance *h)
|
||||
@ -2370,6 +2362,11 @@ void CGTownInstance::setGarrisonedHero(CGHeroInstance *h)
|
||||
}
|
||||
}
|
||||
|
||||
bool CGTownInstance::armedGarrison() const
|
||||
{
|
||||
return stacksCount() || garrisonHero;
|
||||
}
|
||||
|
||||
void CGVisitableOPH::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
if(visitors.find(h->id)==visitors.end())
|
||||
@ -3099,20 +3096,6 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co
|
||||
cb->giveResource(h->tempOwner,6,-cost);
|
||||
|
||||
cb->tryJoiningArmy(this, h, true, false);
|
||||
// int slot = h->getSlotFor(subID);
|
||||
// if(slot >= 0) //there is place
|
||||
// {
|
||||
// //add creatures
|
||||
// SetGarrisons sg;
|
||||
// sg.garrs[h->id] = h->getArmy();
|
||||
// sg.garrs[h->id].addToSlot(slot, subID, getStackCount(0));
|
||||
// cb->sendAndApply(&sg);
|
||||
// cb->removeObject(id);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// cb->showGarrisonDialog(id,h->id,true,boost::bind(&IGameCallback::removeObject,cb,id)); //show garrison window and remove ourselves from map when player ends
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -4764,6 +4747,7 @@ void CGMagicSpring::onHeroVisit(const CGHeroInstance * h) const
|
||||
iw.text << std::pair<ui8,ui32>(11,messageID);
|
||||
cb->showInfoDialog(&iw);
|
||||
}
|
||||
|
||||
const std::string & CGMagicSpring::getHoverText() const
|
||||
{
|
||||
hoverName = VLC->generaltexth->names[ID];
|
||||
@ -6530,13 +6514,6 @@ void CGLighthouse::giveBonusTo( ui8 player ) const
|
||||
cb->sendAndApply(&gb);
|
||||
}
|
||||
|
||||
CCreatureSet& CArmedInstance::getArmy() const
|
||||
{ //do not return itself by value, or it will xplode
|
||||
// CCreatureSet set = *this; return set;
|
||||
//WARNING! A DIRTY CONST_CAST! TO BE INVESTIGATED AND PROBABLY REMOVED!
|
||||
return *(const_cast<CArmedInstance*>(this));
|
||||
}
|
||||
|
||||
void CArmedInstance::randomizeArmy(int type)
|
||||
{
|
||||
int max = VLC->creh->creatures.size();
|
||||
@ -6558,41 +6535,11 @@ void CArmedInstance::randomizeArmy(int type)
|
||||
return;
|
||||
}
|
||||
|
||||
// void CArmedInstance::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const
|
||||
// {
|
||||
// /* //already given via PlayerState->getBonuses();
|
||||
// const PlayerState *p = cb->getPlayerState(tempOwner);
|
||||
// if (p && p != root)
|
||||
// out.insert(p);
|
||||
// */
|
||||
// out.insert(&cb->gameState()->globalEffects); //global effects are always active I believe
|
||||
//
|
||||
// if(battle)
|
||||
// out.insert(battle);
|
||||
// }
|
||||
|
||||
CArmedInstance::CArmedInstance()
|
||||
{
|
||||
battle = NULL;
|
||||
}
|
||||
|
||||
// void CArmedInstance::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
|
||||
// {
|
||||
// CBonusSystemNode::getBonuses(out, selector, root);
|
||||
//
|
||||
// if(!battle)
|
||||
// {
|
||||
// //TODO do it clean, unify with BattleInfo version
|
||||
// if(Selector::matchesType(selector, Bonus::MORALE) || Selector::matchesType(selector, Bonus::LUCK))
|
||||
// {
|
||||
// for(TSlots::const_iterator i=Slots().begin(); i!=Slots().end(); i++)
|
||||
// i->second.getBonuses(out, selector, Selector::effectRange(Bonus::ONLY_ALLIED_ARMY), this);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
||||
// }
|
||||
|
||||
int CArmedInstance::valOfGlobalBonuses(CSelector selector) const
|
||||
{
|
||||
//if (tempOwner != NEUTRAL_PLAYER)
|
||||
@ -6640,8 +6587,17 @@ void CArmedInstance::updateMoraleBonusFromArmy()
|
||||
b->description = boost::str(boost::format(VLC->generaltexth->arraytxt[114]) % factions.size() % b->val); //Troops of %d alignments %d
|
||||
}
|
||||
|
||||
// if(vstd::contains(factions,4))
|
||||
// out.push_back(Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, -1, id, VLC->generaltexth->arraytxt[116]));//Undead in group -1
|
||||
//-1 modifier for any Necropolis unit in army
|
||||
const ui8 UNDEAD_MODIFIER_ID = -2;
|
||||
Bonus *undeadModifier = bonuses.getFirst(Selector::source(Bonus::ARMY, UNDEAD_MODIFIER_ID));
|
||||
if(vstd::contains(factions,4))
|
||||
{
|
||||
if(!undeadModifier)
|
||||
addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, -1, UNDEAD_MODIFIER_ID, VLC->generaltexth->arraytxt[116]));
|
||||
}
|
||||
else if(undeadModifier)
|
||||
removeBonus(undeadModifier);
|
||||
|
||||
}
|
||||
|
||||
void CArmedInstance::armyChanged()
|
||||
@ -6963,16 +6919,6 @@ CArtifactInstance* CArtifactSet::getArt(ui16 pos)
|
||||
{
|
||||
return const_cast<CArtifactInstance*>((const_cast<const CArtifactSet*>(this))->getArt(pos));
|
||||
}
|
||||
// if(pos<19)
|
||||
// if(vstd::contains(artifWorn,pos))
|
||||
// return artifWorn.find(pos)->second;
|
||||
// else
|
||||
// return NULL;
|
||||
// else
|
||||
// if(pos-19 < artifacts.size())
|
||||
// return artifacts[pos-19];
|
||||
// else
|
||||
// return NULL;
|
||||
|
||||
si32 CArtifactSet::getArtPos(int aid, bool onlyWorn /*= true*/) const
|
||||
{
|
||||
|
@ -225,7 +225,6 @@ class DLL_EXPORT CArmedInstance: public CGObjectInstance, public CBonusSystemNod
|
||||
public:
|
||||
BattleInfo *battle; //set to the current battle, if engaged
|
||||
|
||||
CCreatureSet& getArmy() const;
|
||||
void randomizeArmy(int type);
|
||||
void updateMoraleBonusFromArmy();
|
||||
|
||||
@ -604,6 +603,8 @@ public:
|
||||
std::string nodeName() const OVERRIDE;
|
||||
void deserializationFix();
|
||||
void recreateBuildingsBonuses();
|
||||
bool addBonusIfBuilt(int building, int type, int val, IPropagator *prop, int subtype = -1); //returns true if building is built and bonus has been added
|
||||
bool addBonusIfBuilt(int building, int type, int val, int subtype = -1); //convienence version of above
|
||||
void setVisitingHero(CGHeroInstance *h);
|
||||
void setGarrisonedHero(CGHeroInstance *h);
|
||||
// void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const;
|
||||
@ -635,7 +636,7 @@ public:
|
||||
int dailyIncome() const; //calculates daily income of this town
|
||||
int spellsAtLevel(int level, bool checkGuild) const; //levels are counted from 1 (1 - 5)
|
||||
void removeCapitols (ui8 owner) const;
|
||||
int defenceBonus(int type) const;//primary skills bonuses for defending hero
|
||||
bool armedGarrison() const; //true if town has creatures in garrison or garrisoned hero
|
||||
|
||||
CGTownInstance();
|
||||
virtual ~CGTownInstance();
|
||||
|
@ -13,8 +13,10 @@
|
||||
#include "CGeneralTextHandler.h"
|
||||
#include "BattleState.h"
|
||||
|
||||
#define FOREACH_CONST_PARENT(pname) TCNodes parents; getParents(parents); BOOST_FOREACH(const CBonusSystemNode *pname, parents)
|
||||
#define FOREACH_PARENT(pname) TNodes parents; getParents(parents); BOOST_FOREACH(CBonusSystemNode *pname, parents)
|
||||
#define FOREACH_CONST_PARENT(pname) TCNodes lparents; getParents(lparents); BOOST_FOREACH(const CBonusSystemNode *pname, lparents)
|
||||
#define FOREACH_PARENT(pname) TNodes lparents; getParents(lparents); BOOST_FOREACH(CBonusSystemNode *pname, lparents)
|
||||
#define FOREACH_RED_CHILD(pname) TNodes lchildren; getRedChildren(lchildren); BOOST_FOREACH(CBonusSystemNode *pname, lchildren)
|
||||
#define FOREACH_RED_PARENT(pname) TNodes lparents; getRedParents(lparents); BOOST_FOREACH(CBonusSystemNode *pname, lparents)
|
||||
|
||||
#define BONUS_NAME(x) ( #x, Bonus::x )
|
||||
DLL_EXPORT const std::map<std::string, int> bonusNameMap = boost::assign::map_list_of BONUS_LIST;
|
||||
@ -124,12 +126,6 @@ void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector,
|
||||
out.push_back(i);
|
||||
}
|
||||
|
||||
|
||||
void DLL_EXPORT BonusList::removeSpells(Bonus::BonusSource sourceType)
|
||||
{
|
||||
remove_if(Selector::sourceType(sourceType));
|
||||
}
|
||||
|
||||
void BonusList::limit(const CBonusSystemNode &node)
|
||||
{
|
||||
remove_if(boost::bind(&CBonusSystemNode::isLimitedOnUs, boost::ref(node), _1));
|
||||
@ -338,19 +334,20 @@ CBonusSystemNode::~CBonusSystemNode()
|
||||
while(children.size())
|
||||
children.front()->detachFrom(this);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(Bonus *b, exportedBonuses)
|
||||
delete b;
|
||||
}
|
||||
|
||||
void CBonusSystemNode::attachTo(CBonusSystemNode *parent)
|
||||
{
|
||||
assert(!vstd::contains(parents, parent));
|
||||
parents.push_back(parent);
|
||||
// BOOST_FOREACH(Bonus *b, exportedBonuses)
|
||||
// propagateBonus(b);
|
||||
//
|
||||
// if(parent->weActAsBonusSourceOnly())
|
||||
// {
|
||||
//
|
||||
// }
|
||||
|
||||
if(parent->actsAsBonusSourceOnly())
|
||||
parent->newRedDescendant(this);
|
||||
else
|
||||
newRedDescendant(parent);
|
||||
|
||||
parent->newChildAttached(this);
|
||||
}
|
||||
@ -358,16 +355,18 @@ void CBonusSystemNode::attachTo(CBonusSystemNode *parent)
|
||||
void CBonusSystemNode::detachFrom(CBonusSystemNode *parent)
|
||||
{
|
||||
assert(vstd::contains(parents, parent));
|
||||
parents -= parent;
|
||||
//unpropagate bonus
|
||||
|
||||
if(parent->actsAsBonusSourceOnly())
|
||||
parent->removedRedDescendant(this);
|
||||
else
|
||||
removedRedDescendant(parent);
|
||||
|
||||
parents -= parent;
|
||||
parent->childDetached(this);
|
||||
}
|
||||
|
||||
void CBonusSystemNode::popBonuses(const CSelector &s)
|
||||
{
|
||||
//TODO
|
||||
//prop
|
||||
BonusList bl;
|
||||
exportedBonuses.getBonuses(bl, s);
|
||||
BOOST_FOREACH(Bonus *b, bl)
|
||||
@ -384,24 +383,22 @@ void CBonusSystemNode::popBonuses(const CSelector &s)
|
||||
|
||||
void CBonusSystemNode::addNewBonus(Bonus *b)
|
||||
{
|
||||
assert(!vstd::contains(exportedBonuses,b));
|
||||
exportedBonuses.push_back(b);
|
||||
propagateBonus(b);
|
||||
if(b->propagator)
|
||||
propagateBonus(b);
|
||||
else
|
||||
bonuses.push_back(b);
|
||||
}
|
||||
|
||||
void CBonusSystemNode::removeBonus(Bonus *b)
|
||||
{
|
||||
exportedBonuses -= b;
|
||||
CBonusSystemNode *whereIsOurBonus = whereToPropagate(b);
|
||||
whereIsOurBonus->bonuses -= b;
|
||||
delNull(b);
|
||||
}
|
||||
|
||||
CBonusSystemNode * CBonusSystemNode::whereToPropagate(Bonus *b)
|
||||
{
|
||||
if(b->propagator)
|
||||
return b->propagator->getDestNode(this);
|
||||
unpropagateBonus(b);
|
||||
else
|
||||
return this;
|
||||
bonuses -= b;
|
||||
delNull(b);
|
||||
}
|
||||
|
||||
bool CBonusSystemNode::isLimitedOnUs(Bonus *b) const
|
||||
@ -409,7 +406,7 @@ bool CBonusSystemNode::isLimitedOnUs(Bonus *b) const
|
||||
return b->limiter && b->limiter->limit(b, *this);
|
||||
}
|
||||
|
||||
bool CBonusSystemNode::weActAsBonusSourceOnly() const
|
||||
bool CBonusSystemNode::actsAsBonusSourceOnly() const
|
||||
{
|
||||
switch(nodeType)
|
||||
{
|
||||
@ -422,14 +419,28 @@ bool CBonusSystemNode::weActAsBonusSourceOnly() const
|
||||
}
|
||||
}
|
||||
|
||||
TNodesVector & CBonusSystemNode::nodesOnWhichWePropagate()
|
||||
{
|
||||
return weActAsBonusSourceOnly() ? children : parents;
|
||||
}
|
||||
|
||||
void CBonusSystemNode::propagateBonus(Bonus * b)
|
||||
{
|
||||
whereToPropagate(b)->bonuses.push_back(b);
|
||||
if(b->propagator->shouldBeAttached(this))
|
||||
{
|
||||
bonuses.push_back(b);
|
||||
BONUS_LOG_LINE("#$# " << b->Description() << " #propagated to# " << nodeName());
|
||||
}
|
||||
|
||||
FOREACH_RED_CHILD(child)
|
||||
child->propagateBonus(b);
|
||||
}
|
||||
|
||||
void CBonusSystemNode::unpropagateBonus(Bonus * b)
|
||||
{
|
||||
if(b->propagator->shouldBeAttached(this))
|
||||
{
|
||||
bonuses -= b;
|
||||
BONUS_LOG_LINE("#$#" << b->Description() << " #is no longer propagated to# " << nodeName());
|
||||
}
|
||||
|
||||
FOREACH_RED_CHILD(child)
|
||||
child->unpropagateBonus(b);
|
||||
}
|
||||
|
||||
void CBonusSystemNode::newChildAttached(CBonusSystemNode *child)
|
||||
@ -469,6 +480,92 @@ void CBonusSystemNode::deserializationFix()
|
||||
tlog2 << "Deserialization fix called on bare CBSN? Shouldn't be...\n";
|
||||
}
|
||||
|
||||
void CBonusSystemNode::getRedParents(TNodes &out)
|
||||
{
|
||||
FOREACH_PARENT(pname)
|
||||
{
|
||||
if(pname->actsAsBonusSourceOnly())
|
||||
{
|
||||
out.insert(pname);
|
||||
}
|
||||
}
|
||||
|
||||
if(!actsAsBonusSourceOnly())
|
||||
{
|
||||
BOOST_FOREACH(CBonusSystemNode *child, children)
|
||||
{
|
||||
out.insert(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBonusSystemNode::getRedChildren(TNodes &out)
|
||||
{
|
||||
FOREACH_PARENT(pname)
|
||||
{
|
||||
if(!pname->actsAsBonusSourceOnly())
|
||||
{
|
||||
out.insert(pname);
|
||||
}
|
||||
}
|
||||
|
||||
if(actsAsBonusSourceOnly())
|
||||
{
|
||||
BOOST_FOREACH(CBonusSystemNode *child, children)
|
||||
{
|
||||
out.insert(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBonusSystemNode::newRedDescendant(CBonusSystemNode *descendant)
|
||||
{
|
||||
BOOST_FOREACH(Bonus *b, exportedBonuses)
|
||||
if(b->propagator)
|
||||
descendant->propagateBonus(b);
|
||||
|
||||
FOREACH_RED_PARENT(parent)
|
||||
parent->newRedDescendant(descendant);
|
||||
}
|
||||
|
||||
void CBonusSystemNode::removedRedDescendant(CBonusSystemNode *descendant)
|
||||
{
|
||||
BOOST_FOREACH(Bonus *b, exportedBonuses)
|
||||
if(b->propagator)
|
||||
descendant->unpropagateBonus(b);
|
||||
|
||||
FOREACH_RED_PARENT(parent)
|
||||
parent->removedRedDescendant(descendant);
|
||||
}
|
||||
|
||||
void CBonusSystemNode::getRedAncestors(TNodes &out)
|
||||
{
|
||||
getRedParents(out);
|
||||
FOREACH_RED_PARENT(p)
|
||||
p->getRedAncestors(out);
|
||||
}
|
||||
|
||||
void CBonusSystemNode::getRedDescendants(TNodes &out)
|
||||
{
|
||||
getRedChildren(out);
|
||||
FOREACH_RED_CHILD(c)
|
||||
c->getRedChildren(out);
|
||||
}
|
||||
|
||||
void CBonusSystemNode::battleTurnPassed()
|
||||
{
|
||||
BonusList bonusesCpy = exportedBonuses; //copy, because removing bonuses invalidates iters
|
||||
BOOST_FOREACH(Bonus *b, bonusesCpy)
|
||||
{
|
||||
if(b->duration & Bonus::N_TURNS)
|
||||
{
|
||||
b->turnsRemain--;
|
||||
if(b->turnsRemain <= 0)
|
||||
removeBonus(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/)
|
||||
{
|
||||
if(obj)
|
||||
@ -562,7 +659,23 @@ Bonus::~Bonus()
|
||||
|
||||
Bonus * Bonus::addLimiter(ILimiter *Limiter)
|
||||
{
|
||||
limiter.reset(Limiter);
|
||||
return addLimiter(boost::shared_ptr<ILimiter>(Limiter));
|
||||
}
|
||||
|
||||
Bonus * Bonus::addLimiter(boost::shared_ptr<ILimiter> Limiter)
|
||||
{
|
||||
limiter = Limiter;
|
||||
return this;
|
||||
}
|
||||
|
||||
Bonus * Bonus::addPropagator(IPropagator *Propagator)
|
||||
{
|
||||
return addPropagator(boost::shared_ptr<IPropagator>(Propagator));
|
||||
}
|
||||
|
||||
Bonus * Bonus::addPropagator(boost::shared_ptr<IPropagator> Propagator)
|
||||
{
|
||||
propagator = Propagator;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -618,6 +731,27 @@ namespace Selector
|
||||
dummy.subtype = subtype;
|
||||
return sel(&dummy);
|
||||
}
|
||||
|
||||
bool DLL_EXPORT positiveSpellEffects(const Bonus *b)
|
||||
{
|
||||
if(b->source == Bonus::SPELL_EFFECT)
|
||||
{
|
||||
CSpell *sp = VLC->spellh->spells[b->sid];
|
||||
return sp->positiveness == 1;
|
||||
}
|
||||
return false; //not a spell effect
|
||||
}
|
||||
}
|
||||
|
||||
const CStack * retreiveStackBattle(const CBonusSystemNode *node)
|
||||
{
|
||||
switch(node->nodeType)
|
||||
{
|
||||
case CBonusSystemNode::STACK_BATTLE:
|
||||
return static_cast<const CStack*>(node);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const CStackInstance * retreiveStackInstance(const CBonusSystemNode *node)
|
||||
@ -732,9 +866,35 @@ IPropagator::~IPropagator()
|
||||
|
||||
}
|
||||
|
||||
CBonusSystemNode * IPropagator::getDestNode(CBonusSystemNode *source)
|
||||
// CBonusSystemNode * IPropagator::getDestNode(CBonusSystemNode *source, CBonusSystemNode *redParent, CBonusSystemNode *redChild)
|
||||
// {
|
||||
// tlog1 << "IPropagator::getDestNode called!\n";
|
||||
// return source;
|
||||
// }
|
||||
|
||||
bool IPropagator::shouldBeAttached(CBonusSystemNode *dest)
|
||||
{
|
||||
return source;
|
||||
return false;
|
||||
}
|
||||
|
||||
// CBonusSystemNode * CPropagatorNodeType::getDestNode(CBonusSystemNode *source, CBonusSystemNode *redParent, CBonusSystemNode *redChild)
|
||||
// {
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
CPropagatorNodeType::CPropagatorNodeType()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CPropagatorNodeType::CPropagatorNodeType(ui8 NodeType)
|
||||
: nodeType(NodeType)
|
||||
{
|
||||
}
|
||||
|
||||
bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
|
||||
{
|
||||
return nodeType == dest->nodeType;
|
||||
}
|
||||
|
||||
CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter(int TerrainType)
|
||||
@ -749,7 +909,8 @@ CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter()
|
||||
bool CreatureNativeTerrainLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const
|
||||
{
|
||||
const CCreature *c = retrieveCreature(&node);
|
||||
return !c || VLC->heroh->nativeTerrains[c->faction] != terrainType; //drop bonus for non-creatures or non-native residents
|
||||
return !c || !iswith(c->faction, 0, 9) || VLC->heroh->nativeTerrains[c->faction] != terrainType; //drop bonus for non-creatures or non-native residents
|
||||
//TODO neutral creatues
|
||||
}
|
||||
|
||||
CreatureFactionLimiter::CreatureFactionLimiter(int Faction)
|
||||
@ -799,10 +960,37 @@ RankRangeLimiter::RankRangeLimiter(ui8 Min, ui8 Max)
|
||||
{
|
||||
}
|
||||
|
||||
RankRangeLimiter::RankRangeLimiter()
|
||||
{
|
||||
minRank = maxRank = -1;
|
||||
}
|
||||
|
||||
bool RankRangeLimiter::limit( const Bonus *b, const CBonusSystemNode &node ) const
|
||||
{
|
||||
const CStackInstance *csi = retreiveStackInstance(&node);
|
||||
if(csi)
|
||||
return csi->getExpRank() < minRank || csi->getExpRank() > maxRank;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StackOwnerLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const
|
||||
{
|
||||
const CStack *s = retreiveStackBattle(&node);
|
||||
if(s)
|
||||
return s->owner != owner;
|
||||
|
||||
const CStackInstance *csi = retreiveStackInstance(&node);
|
||||
if(csi && csi->armyObj)
|
||||
return csi->armyObj->tempOwner != owner;
|
||||
return true;
|
||||
}
|
||||
|
||||
StackOwnerLimiter::StackOwnerLimiter()
|
||||
: owner(-1)
|
||||
{
|
||||
}
|
||||
|
||||
StackOwnerLimiter::StackOwnerLimiter(ui8 Owner)
|
||||
: owner(Owner)
|
||||
{
|
||||
}
|
@ -202,9 +202,7 @@ struct DLL_EXPORT Bonus
|
||||
{
|
||||
NO_LIMIT = 0,
|
||||
ONLY_DISTANCE_FIGHT=1, ONLY_MELEE_FIGHT, //used to mark bonuses for attack/defense primary skills from spells like Precision (distance only)
|
||||
ONLY_ALLIED_ARMY, ONLY_ENEMY_ARMY,
|
||||
PLAYR_HEROES,
|
||||
GLOBAL //Statue of Legion etc.
|
||||
ONLY_ENEMY_ARMY
|
||||
};
|
||||
|
||||
enum ValueType
|
||||
@ -303,6 +301,9 @@ struct DLL_EXPORT Bonus
|
||||
std::string Description() const;
|
||||
|
||||
Bonus *addLimiter(ILimiter *Limiter); //returns this for convenient chain-calls
|
||||
Bonus *addPropagator(IPropagator *Propagator); //returns this for convenient chain-calls
|
||||
Bonus *addLimiter(boost::shared_ptr<ILimiter> Limiter); //returns this for convenient chain-calls
|
||||
Bonus *addPropagator(boost::shared_ptr<IPropagator> Propagator); //returns this for convenient chain-calls
|
||||
};
|
||||
|
||||
DLL_EXPORT std::ostream & operator<<(std::ostream &out, const Bonus &bonus);
|
||||
@ -314,7 +315,6 @@ public:
|
||||
void DLL_EXPORT getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *source = NULL) const;
|
||||
void DLL_EXPORT getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *source = NULL) const;
|
||||
void DLL_EXPORT getModifiersWDescr(TModDescr &out) const;
|
||||
void DLL_EXPORT removeSpells(Bonus::BonusSource sourceType);
|
||||
|
||||
//special find functions
|
||||
DLL_EXPORT Bonus * getFirst(const CSelector &select);
|
||||
@ -334,7 +334,26 @@ class DLL_EXPORT IPropagator
|
||||
{
|
||||
public:
|
||||
virtual ~IPropagator();
|
||||
virtual CBonusSystemNode *getDestNode(CBonusSystemNode *source);
|
||||
virtual bool shouldBeAttached(CBonusSystemNode *dest);
|
||||
//virtual CBonusSystemNode *getDestNode(CBonusSystemNode *source, CBonusSystemNode *redParent, CBonusSystemNode *redChild); //called when red relation between parent-childrem is established / removed
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{}
|
||||
};
|
||||
|
||||
class DLL_EXPORT CPropagatorNodeType : public IPropagator
|
||||
{
|
||||
ui8 nodeType;
|
||||
public:
|
||||
CPropagatorNodeType();
|
||||
CPropagatorNodeType(ui8 NodeType);
|
||||
bool shouldBeAttached(CBonusSystemNode *dest);
|
||||
//CBonusSystemNode *getDestNode(CBonusSystemNode *source, CBonusSystemNode *redParent, CBonusSystemNode *redChild) OVERRIDE;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & nodeType;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_EXPORT ILimiter
|
||||
@ -400,7 +419,11 @@ public:
|
||||
|
||||
const Bonus *getBonus(const CSelector &selector) const;
|
||||
//non-const interface
|
||||
void getParents(TNodes &out); //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker
|
||||
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)
|
||||
void getRedAncestors(TNodes &out);
|
||||
void getRedChildren(TNodes &out);
|
||||
void getRedDescendants(TNodes &out);
|
||||
Bonus *getBonus(const CSelector &selector);
|
||||
|
||||
void attachTo(CBonusSystemNode *parent);
|
||||
@ -411,15 +434,17 @@ public:
|
||||
void newChildAttached(CBonusSystemNode *child);
|
||||
void childDetached(CBonusSystemNode *child);
|
||||
void propagateBonus(Bonus * b);
|
||||
void unpropagateBonus(Bonus * b);
|
||||
//void addNewBonus(const Bonus &b); //b will copied
|
||||
void removeBonus(Bonus *b);
|
||||
void newRedDescendant(CBonusSystemNode *descendant); //propagation needed
|
||||
void removedRedDescendant(CBonusSystemNode *descendant); //de-propagation needed
|
||||
|
||||
TNodesVector &nodesOnWhichWePropagate();
|
||||
bool isIndependentNode() const; //node is independent when it has no parents nor children
|
||||
bool weActAsBonusSourceOnly() const;
|
||||
bool actsAsBonusSourceOnly() const;
|
||||
bool isLimitedOnUs(Bonus *b) const; //if bonus should be removed from list acquired from this node
|
||||
CBonusSystemNode *whereToPropagate(Bonus *b);
|
||||
|
||||
void battleTurnPassed(); //updates count of remaining turns and removed outdated bonuses
|
||||
void popBonuses(const CSelector &s);
|
||||
virtual std::string nodeName() const;
|
||||
void deserializationFix();
|
||||
@ -434,7 +459,7 @@ public:
|
||||
|
||||
enum ENodeTypes
|
||||
{
|
||||
UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALITY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO
|
||||
UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALITY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO, PLAYER, TEAM
|
||||
};
|
||||
};
|
||||
|
||||
@ -619,11 +644,27 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_EXPORT StackOwnerLimiter : public ILimiter //applies only to creatures of given alignment
|
||||
{
|
||||
public:
|
||||
ui8 owner;
|
||||
StackOwnerLimiter();
|
||||
StackOwnerLimiter(ui8 Owner);
|
||||
|
||||
bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & owner;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_EXPORT RankRangeLimiter : public ILimiter //applies to creatures with min <= Rank <= max
|
||||
{
|
||||
public:
|
||||
ui8 minRank, maxRank;
|
||||
|
||||
RankRangeLimiter();
|
||||
RankRangeLimiter(ui8 Min, ui8 Max = 255);
|
||||
bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE;
|
||||
|
||||
@ -651,6 +692,7 @@ namespace Selector
|
||||
|
||||
bool DLL_EXPORT matchesType(const CSelector &sel, TBonusType type);
|
||||
bool DLL_EXPORT matchesTypeSubtype(const CSelector &sel, TBonusType type, TBonusSubtype subtype);
|
||||
bool DLL_EXPORT positiveSpellEffects(const Bonus *b);
|
||||
}
|
||||
|
||||
extern DLL_EXPORT const std::map<std::string, int> bonusNameMap;
|
@ -800,15 +800,33 @@ DLL_EXPORT void SetObjectProperty::applyGs( CGameState *gs )
|
||||
|
||||
if(what == ObjProperty::OWNER)
|
||||
{
|
||||
CBonusSystemNode *nodeToMove = NULL;
|
||||
if(obj->ID == TOWNI_TYPE)
|
||||
{
|
||||
CGTownInstance *t = static_cast<CGTownInstance*>(obj);
|
||||
nodeToMove = &t->townAndVis;
|
||||
if(t->tempOwner < PLAYER_LIMIT)
|
||||
gs->getPlayer(t->tempOwner)->towns -= t;
|
||||
|
||||
if(val < PLAYER_LIMIT)
|
||||
gs->getPlayer(val)->towns.push_back(t);
|
||||
}
|
||||
if(CArmedInstance *cai = dynamic_cast<CArmedInstance *>(obj))
|
||||
{
|
||||
if(!nodeToMove)
|
||||
nodeToMove = cai;
|
||||
|
||||
if(obj->tempOwner < PLAYER_LIMIT)
|
||||
nodeToMove->detachFrom(gs->getPlayer(obj->tempOwner));
|
||||
else
|
||||
nodeToMove->detachFrom(&gs->globalEffects);
|
||||
|
||||
if(val < PLAYER_LIMIT)
|
||||
nodeToMove->attachTo(gs->getPlayer(val));
|
||||
else
|
||||
nodeToMove->attachTo(&gs->globalEffects);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
obj->setProperty(what,val);
|
||||
@ -852,34 +870,7 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
|
||||
if( s->hasBonusOfType(Bonus::FULL_HP_REGENERATION) && s->alive() )
|
||||
s->firstHPleft = s->MaxHealth();
|
||||
|
||||
//remove effects and restore only those with remaining turns in duration
|
||||
BonusList tmpEffects = s->bonuses;
|
||||
s->bonuses.removeSpells(Bonus::SPELL_EFFECT);
|
||||
|
||||
BOOST_FOREACH(Bonus *it, tmpEffects)
|
||||
{
|
||||
it->turnsRemain--;
|
||||
if(it->turnsRemain > 0)
|
||||
s->addNewBonus(it);
|
||||
}
|
||||
|
||||
//the same as above for features
|
||||
BonusList tmpFeatures = s->bonuses;
|
||||
s->bonuses.clear();
|
||||
|
||||
BOOST_FOREACH(Bonus *b, tmpFeatures)
|
||||
{
|
||||
if((b->duration & Bonus::N_TURNS) != 0)
|
||||
{
|
||||
b->turnsRemain--;
|
||||
if(b->turnsRemain > 0)
|
||||
s->addNewBonus(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
s->addNewBonus(b);
|
||||
}
|
||||
}
|
||||
s->battleTurnPassed();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1048,28 +1039,10 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
|
||||
CStack *s = gs->curB->getStack(*it);
|
||||
if(s && !vstd::contains(resisted, s->ID)) //if stack exists and it didn't resist
|
||||
{
|
||||
BonusList remainingEff;
|
||||
//WTF?
|
||||
for (BonusList::iterator it = remainingEff.begin(); it != remainingEff.end(); it++)
|
||||
{
|
||||
if (onlyHelpful && VLC->spellh->spells[ (*it)->sid ]->positiveness != 1)
|
||||
{
|
||||
remainingEff.push_back(*it);
|
||||
}
|
||||
|
||||
}
|
||||
s->bonuses.removeSpells(Bonus::SPELL_EFFECT); //removing all effects
|
||||
s->bonuses = remainingEff; //assigning effects that should remain
|
||||
|
||||
//removing all features from spells
|
||||
BonusList tmpFeatures = s->bonuses;
|
||||
s->bonuses.clear();
|
||||
BOOST_FOREACH(Bonus *b, tmpFeatures)
|
||||
{
|
||||
const CSpell *sp = b->sourceSpell();
|
||||
if(sp && sp->positiveness != 1) //if(b->source != HeroBonus::SPELL_EFFECT || b.positiveness != 1)
|
||||
s->addNewBonus(b);
|
||||
}
|
||||
if(onlyHelpful)
|
||||
s->popBonuses(Selector::positiveSpellEffects);
|
||||
else
|
||||
s->popBonuses(Selector::sourceType(Bonus::SPELL_EFFECT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,12 +75,17 @@ void registerTypes1(Serializer &s)
|
||||
s.template registerType<CGBlackMarket>();
|
||||
s.template registerType<CGUniversity>();
|
||||
//end of objects
|
||||
s.template registerType<IPropagator>();
|
||||
s.template registerType<CPropagatorNodeType>();
|
||||
|
||||
s.template registerType<ILimiter>();
|
||||
s.template registerType<CCreatureTypeLimiter>();
|
||||
s.template registerType<HasAnotherBonusLimiter>();
|
||||
s.template registerType<CreatureNativeTerrainLimiter>();
|
||||
s.template registerType<CreatureFactionLimiter>();
|
||||
s.template registerType<CreatureAlignmentLimiter>();
|
||||
s.template registerType<RankRangeLimiter>();
|
||||
s.template registerType<StackOwnerLimiter>();
|
||||
|
||||
s.template registerType<CBonusSystemNode>();
|
||||
s.template registerType<CArtifact>();
|
||||
|
@ -2064,8 +2064,8 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2,
|
||||
}
|
||||
else if(what==3) //split
|
||||
{
|
||||
if ( (s1->tempOwner != player && S1.stacks[p1]->count < s1->getArmy().getStackCount(p1) )
|
||||
|| (s2->tempOwner != player && S2.stacks[p2]->count < s2->getArmy().getStackCount(p2) ) )
|
||||
if ( (s1->tempOwner != player && S1.stacks[p1]->count < s1->getStackCount(p1) )
|
||||
|| (s2->tempOwner != player && S2.stacks[p2]->count < s2->getStackCount(p2) ) )
|
||||
{
|
||||
complain("Can't move troops of another player!");
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user