1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-10-31 00:07:39 +02:00

New bonus system. Unified HeroBonus and StackFeature. Still early version, will need improvements and development.

If you encounter any new crashes / bugs / unacceptable slowdowns, please PM me.
This commit is contained in:
Michał W. Urbańczyk
2010-05-02 18:20:26 +00:00
parent e3af43fb48
commit a14606f32d
44 changed files with 2345 additions and 2020 deletions

View File

@@ -41,7 +41,7 @@ ui8 side; //who made this action: false - left, true - right player
/**
* Implementation of CBattleLogic class.
*/
CBattleLogic::CBattleLogic(ICallback *cb, CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) :
CBattleLogic::CBattleLogic(ICallback *cb, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) :
m_iCurrentTurn(-2),
m_bIsAttacker(!side),
m_cb(cb),
@@ -121,23 +121,24 @@ void CBattleLogic::MakeStatistics(int currentCreatureId)
for (map_stacks::const_iterator it = allStacks.begin(); it != allStacks.end(); ++it)
{
const CStack *st = &it->second;
const int stackHP = st->valOfBonuses(Bonus::STACK_HEALTH);
if ((it->second.attackerOwned != 0) != m_bIsAttacker)
{
int id = it->first;
if (st->amount < 1)
if (st->count < 1)
{
continue;
}
// make stats
int hitPoints = st->amount * st->creature->hitPoints - (st->creature->hitPoints - st->firstHPleft);
int hitPoints = st->count * stackHP - (stackHP - st->firstHPleft);
m_statMaxDamage.push_back(std::pair<int, int>(id, st->creature->damageMax * st->amount));
m_statMinDamage.push_back(std::pair<int, int>(id, st->creature->damageMin * st->amount));
m_statMaxDamage.push_back(std::pair<int, int>(id, st->type->damageMax * st->count));
m_statMinDamage.push_back(std::pair<int, int>(id, st->type->damageMin * st->count));
m_statHitPoints.push_back(std::pair<int, int>(id, hitPoints));
m_statMaxSpeed.push_back(std::pair<int, int>(id, st->creature->speed));
m_statMaxSpeed.push_back(std::pair<int, int>(id, stackHP));
totalEnemyDamage += (st->creature->damageMax + st->creature->damageMin) * st->amount / 2;
totalEnemyDamage += (st->type->damageMax + st->type->damageMin) * st->count / 2;
totalEnemyHitPoints += hitPoints;
// calculate casualties
@@ -174,32 +175,32 @@ void CBattleLogic::MakeStatistics(int currentCreatureId)
}
}
cs.damage_max = (int)(currentStack->creature->damageMax * currentStack->amount * damageFactor);
cs.damage_max = (int)(currentStack->type->damageMax * currentStack->count * damageFactor);
if (cs.damage_max > hitPoints)
{
cs.damage_max = hitPoints;
}
cs.damage_min = (int)(currentStack->creature->damageMin * currentStack->amount * damageFactor);
cs.damage_min = (int)(currentStack->type->damageMin * currentStack->count * damageFactor);
if (cs.damage_min > hitPoints)
{
cs.damage_min = hitPoints;
}
cs.amount_max = cs.damage_max / st->creature->hitPoints;
cs.amount_min = cs.damage_min / st->creature->hitPoints;
cs.amount_max = cs.damage_max / stackHP;
cs.amount_min = cs.damage_min / stackHP;
cs.leftHitPoints_for_max = (hitPoints - cs.damage_max) % st->creature->hitPoints;
cs.leftHitPoint_for_min = (hitPoints - cs.damage_min) % st->creature->hitPoints;
cs.leftHitPoints_for_max = (hitPoints - cs.damage_max) % stackHP;
cs.leftHitPoint_for_min = (hitPoints - cs.damage_min) % stackHP;
m_statCasualties.push_back(std::pair<int, SCreatureCasualties>(id, cs));
if (st->creature->isShooting() && st->shots > 0)
if (st->type->isShooting() && st->shots > 0)
{
m_statDistanceFromShooters.push_back(std::pair<int, int>(id, m_battleHelper.GetShortestDistance(currentStack->position, st->position)));
}
if (currentStack->hasFeatureOfType(StackFeature::FLYING) || (currentStack->creature->isShooting() && currentStack->shots > 0))
if (currentStack->hasBonusOfType(Bonus::FLYING) || (currentStack->type->isShooting() && currentStack->shots > 0))
{
m_statDistance.push_back(std::pair<int, int>(id, m_battleHelper.GetShortestDistance(currentStack->position, st->position)));
}
@@ -210,13 +211,13 @@ void CBattleLogic::MakeStatistics(int currentCreatureId)
}
else
{
if (st->amount < 1)
if (st->count < 1)
{
continue;
}
int hitPoints = st->amount * st->creature->hitPoints - (st->creature->hitPoints - st->firstHPleft);
int hitPoints = st->count * stackHP - (stackHP - st->firstHPleft);
totalDamage += (st->creature->damageMax + st->creature->damageMin) * st->amount / 2;
totalDamage += (st->type->damageMax + st->type->damageMin) * st->count / 2;
totalHitPoints += hitPoints;
}
}
@@ -258,7 +259,7 @@ void CBattleLogic::MakeStatistics(int currentCreatureId)
BattleAction CBattleLogic::MakeDecision(int stackID)
{
const CStack *currentStack = m_cb->battleGetStackByID(stackID);
if(currentStack->position < 0 || currentStack->creature->idNumber == 147) //turret or first aid kit
if(currentStack->position < 0 || currentStack->type->idNumber == 147) //turret or first aid kit
{
return MakeDefend(stackID);
}
@@ -318,8 +319,8 @@ std::vector<int> CBattleLogic::GetAvailableHexesForAttacker(const CStack *defend
{
int x = m_battleHelper.DecodeXPosition(defender->position);
int y = m_battleHelper.DecodeYPosition(defender->position);
bool defenderIsDW = defender->hasFeatureOfType(StackFeature::DOUBLE_WIDE);
bool attackerIsDW = attacker->hasFeatureOfType(StackFeature::DOUBLE_WIDE);
bool defenderIsDW = defender->doubleWide();
bool attackerIsDW = attacker->doubleWide();
// TOTO: should be std::vector<int> but for debug purpose std::pair is used
typedef std::pair<int, int> hexPoint;
std::list<hexPoint> candidates;
@@ -424,7 +425,7 @@ std::vector<int> CBattleLogic::GetAvailableHexesForAttacker(const CStack *defend
int new_pos = m_battleHelper.GetBattleFieldPosition(it->first, it->second);
const CStack *st = m_cb->battleGetStackByPos(new_pos);
if (st == NULL || st->amount < 1)
if (st == NULL || st->count < 1)
{
if (attackerIsDW)
{
@@ -449,7 +450,7 @@ std::vector<int> CBattleLogic::GetAvailableHexesForAttacker(const CStack *defend
}
assert(tail_pos >= 0 && "Error during calculation position of double wide creature");
//CStack *tailStack = m_cb->battleGetStackByPos(tail_pos);
if (st != NULL && st->amount >= 1)
if (st != NULL && st->count >= 1)
{
continue;
}
@@ -572,7 +573,7 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
// if double wide calculate tail
int tail_pos = -1;
if (attackerStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
if (attackerStack->doubleWide())
{
int x_pos = m_battleHelper.DecodeXPosition(attackerStack->position);
int y_pos = m_battleHelper.DecodeYPosition(attackerStack->position);
@@ -657,7 +658,7 @@ list<int> CBattleLogic::PerformBerserkAttack(int stackID, int &additionalInfo)
}
for (creature_stat::const_iterator it2 = m_statDistance.begin(); it2 != m_statDistance.end(); ++it2)
{
if (it2->first == it->first && it2->second - 1 <= c.speed)
if (it2->first == it->first && it2->second - 1 <= c.valOfBonuses(Bonus::STACKS_SPEED))
{
creatures.push_front(it->first);
}
@@ -761,9 +762,9 @@ void CBattleLogic::PrintBattleAction(const BattleAction &action) // for debug pu
message += ", " + boost::lexical_cast<std::string>(m_battleHelper.DecodeYPosition(action.additionalInfo));
message += ", creature - ";
const CStack *c = m_cb->battleGetStackByPos(action.additionalInfo);
if (c && c->creature)
if (c && c->type)
{
message += c->creature->nameRef;
message += c->type->nameRef;
}
else
{

View File

@@ -63,7 +63,7 @@ private:
int leftHitPoint_for_min; // scenario
};
public:
CBattleLogic(ICallback *cb, CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side);
CBattleLogic(ICallback *cb, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side);
~CBattleLogic();
void SetCurrentTurn(int turn);
@@ -77,8 +77,8 @@ private:
int m_iCurrentTurn;
bool m_bIsAttacker;
ICallback *m_cb;
CCreatureSet *m_army1;
CCreatureSet *m_army2;
const CCreatureSet *m_army1;
const CCreatureSet *m_army2;
int3 m_tile;
CGHeroInstance *m_hero1;
CGHeroInstance *m_hero2;

View File

@@ -61,7 +61,7 @@ CGeniusAI::HypotheticalGameState::TownModel::TownModel(
{
hasBuilt = static_cast<bool>(t->builded);
creaturesToRecruit = t->creatures;
creaturesInGarrison = t->army;
creaturesInGarrison = t->getArmy();
}
CGeniusAI::HypotheticalGameState::HypotheticalGameState(CGeniusAI& ai)
@@ -295,7 +295,7 @@ float CGeniusAI::TownObjective::getValue() const
case recruitCreatures:
// Buy upgraded if possible.
ID = whichTown->creaturesToRecruit[which].second.back();
creature = &VLC->creh->creatures[ID];
creature = VLC->creh->creatures[ID];
howMany = whichTown->creaturesToRecruit[which].first;
creatures_max = 0; // Max creatures you can recruit of this type.
@@ -316,8 +316,8 @@ float CGeniusAI::TownObjective::getValue() const
case upgradeCreatures:
UpgradeInfo ui = AI->m_cb->getUpgradeInfo(whichTown->t,which);
ID = whichTown->creaturesInGarrison.slots[which].type->idNumber;
howMany = whichTown->creaturesInGarrison.slots[which].count;
ID = whichTown->creaturesInGarrison.getCreature(which)->idNumber;
howMany = whichTown->creaturesInGarrison.getAmount(which);
newID = ui.newID.back();
int upgrade_serial = ui.newID.size() - 1;
@@ -388,7 +388,7 @@ void CGeniusAI::TownObjective::print() const
case recruitCreatures:
// Buy upgraded if possible.
ID = whichTown->creaturesToRecruit[which].second.back();
creature = &VLC->creh->creatures[ID];
creature = VLC->creh->creatures[ID];
howMany = whichTown->creaturesToRecruit[which].first;
creatures_max = 0;
@@ -424,8 +424,8 @@ void CGeniusAI::TownObjective::print() const
case upgradeCreatures:
UpgradeInfo ui = AI->m_cb->getUpgradeInfo(whichTown->t,which);
ID = whichTown->creaturesInGarrison.slots[which].type->idNumber;
cout << "upgrade " << VLC->creh->creatures[ID].namePl;
ID = whichTown->creaturesInGarrison.getCreature(which)->idNumber;
cout << "upgrade " << VLC->creh->creatures[ID]->namePl;
//ui.cost
break;
} // switch(type)
@@ -734,10 +734,10 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg,
if (town && object->getOwner() == cg.m_cb->getMyColor()) {
//upgrade hero's units
cout << "visiting town" << endl;
CCreatureSet hcreatures = h->h->army;
CCreatureSet hcreatures = h->h->getArmy();
for (TSlots::const_iterator
i = hcreatures.slots.begin();
i != hcreatures.slots.end();
i = hcreatures.Slots().begin();
i != hcreatures.Slots().end();
i++) { // For each hero slot.
UpgradeInfo ui = cg.m_cb->getUpgradeInfo(h->h,i->first);
@@ -763,13 +763,13 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg,
}
// Give town's units to hero.
CCreatureSet tcreatures = town->army;
CCreatureSet tcreatures = town->getArmy();
int weakestCreatureStack;
int weakestCreatureAIValue = 99999; // TODO: Wtf??
for (TSlots::const_iterator
i = tcreatures.slots.begin();
i != tcreatures.slots.end();
i = tcreatures.Slots().begin();
i != tcreatures.Slots().end();
i++) {
if (i->second.type->AIValue <
weakestCreatureAIValue) {
@@ -778,10 +778,10 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg,
}
}
for (TSlots::const_iterator
i = tcreatures.slots.begin();
i != tcreatures.slots.end();
i = tcreatures.Slots().begin();
i != tcreatures.Slots().end();
i++) { // For each town slot.
hcreatures = h->h->army;
hcreatures = h->h->getArmy();
int hSlot = hcreatures.getSlotFor(i->second.type->idNumber);
if (hSlot == -1)
@@ -789,7 +789,7 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg,
cout << "giving hero "
<< i->second.type->namePl
<< endl;
if (hcreatures.slots.find(hSlot) != hcreatures.slots.end()) {
if (!hcreatures.slotEmpty(hSlot)) {
// Can't take garrisonHero's last unit.
if ( (i->first == weakestCreatureStack)
&& (town->garrisonHero != NULL) )
@@ -855,22 +855,22 @@ void CGeniusAI::addTownObjectives(HypotheticalGameState::TownModel& t,
int ID = t.creaturesToRecruit[i].second.back();
// m_cb->getCCreatureByID(ID);
const CCreature *creature = &VLC->creh->creatures[ID];
const CCreature *creature = VLC->creh->creatures[ID];
bool canAfford = true;
for (int ii = 0; ii < creature->cost.size(); ii++)
if (creature->cost[ii] > hgs.resourceAmounts[ii])
canAfford = false; // Can we afford at least one creature?
if (!canAfford) continue;
//cout << "town has " << t.t->creatures[i].first << " "<< creature->namePl << " (AI Strength " << creature->AIValue << ")." << endl;
//cout << "town has " << t.t->creatures[i]->first << " "<< creature->namePl << " (AI Strength " << creature->AIValue << ")." << endl;
TownObjective to(hgs, AIObjective::recruitCreatures, &t, i, this);
currentTownObjectives.insert(to);
}
// Upgrade creatures.
for (TSlots::iterator
i = t.creaturesInGarrison.slots.begin();
i != t.creaturesInGarrison.slots.end();
for (TSlots::const_iterator
i = t.creaturesInGarrison.Slots().begin();
i != t.creaturesInGarrison.Slots().end();
i++) {
UpgradeInfo ui = m_cb->getUpgradeInfo(t.t, i->first);
if (ui.newID.size() != 0) {
@@ -927,7 +927,7 @@ void CGeniusAI::TownObjective::fulfill(CGeniusAI& cg,
case recruitCreatures:
// Buy upgraded if possible.
ID = whichTown->creaturesToRecruit[which].second.back();
creature = &VLC->creh->creatures[ID];
creature = VLC->creh->creatures[ID];
howMany = whichTown->creaturesToRecruit[which].first;
for (int i = 0; i < creature->cost.size(); i++)
// TODO: rewrite.
@@ -942,11 +942,11 @@ void CGeniusAI::TownObjective::fulfill(CGeniusAI& cg,
case upgradeCreatures:
UpgradeInfo ui = cg.m_cb->getUpgradeInfo(whichTown->t, which);
ID = whichTown->creaturesInGarrison.slots[which].type->idNumber;
ID = whichTown->creaturesInGarrison.getCreature(which)->idNumber;
newID = ui.newID.back();
// TODO: reduce resources in hgs
cg.m_cb->upgradeCreature(whichTown->t, which, newID);
cout << "upgrading " << VLC->creh->creatures[ID].namePl << endl;
cout << "upgrading " << VLC->creh->creatures[ID]->namePl << endl;
break;
}
}
@@ -1077,7 +1077,7 @@ void CGeniusAI::startFirstTurn()
if (hgs.townModels.front().creaturesToRecruit[i].first == 0)
continue;
int ID = hgs.townModels.front().creaturesToRecruit[i].second.back();
const CCreature *creature = &VLC->creh->creatures[ID];
const CCreature *creature = VLC->creh->creatures[ID];
bool canAfford = true;
for (int ii = 0; ii < creature->cost.size(); ii++) {
if (creature->cost[ii] > hgs.resourceAmounts[ii])
@@ -1246,7 +1246,7 @@ void CGeniusAI::battleStacksAttacked(std::set<BattleStackAttacked>& bsa)
/**
* called by engine when battle starts; side=0 - left, side=1 - right
*/
void CGeniusAI::battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side)
void CGeniusAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side)
{
// TODO: Battle logic what...
assert(!m_battleLogic);
@@ -1275,7 +1275,7 @@ void CGeniusAI::battleEnd(BattleResult* br)
for (std::map<ui32,si32>::iterator i = br->casualties[0].begin();\
i != br->casualties[0].end();
i++)
cout << i->second << " " << VLC->creh->creatures[i->first].namePl << endl;
cout << i->second << " " << VLC->creh->creatures[i->first]->namePl << endl;
delete m_battleLogic;
m_battleLogic = NULL;

View File

@@ -208,7 +208,7 @@ public:
virtual void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
virtual void battleStackMoved(int ID, int dest, int distance, bool end);
virtual void battleSpellCast(SpellCast *sc);
virtual void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
//
virtual void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving);

View File

@@ -68,7 +68,7 @@ void CCallback::recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amou
bool CCallback::dismissCreature(const CArmedInstance *obj, int stackPos)
{
if(((player>=0) && obj->tempOwner != player) || (obj->army.slots.size()<2 && obj->needsLastStack()))
if(((player>=0) && obj->tempOwner != player) || (obj->stacksCount()<2 && obj->needsLastStack()))
return false;
DisbandCreature pack(stackPos,obj->id);
@@ -379,7 +379,7 @@ const CCreatureSet* CCallback::getGarrison(const CGObjectInstance *obj) const
if(!armi)
return NULL;
else
return &armi->army;
return armi;
}
int CCallback::swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)
@@ -560,7 +560,7 @@ CCreature CCallback::battleGetCreature(int number)
for(size_t h=0; h<gs->curB->stacks.size(); ++h)
{
if(gs->curB->stacks[h]->ID == number) //creature found
return *(gs->curB->stacks[h]->creature);
return *(gs->curB->stacks[h]->type);
}
#ifndef __GNUC__
throw new std::exception("Cannot find the creature");
@@ -776,7 +776,7 @@ void CCallback::trade( int mode, int id1, int id2, int val1 )
void CCallback::setFormation(const CGHeroInstance * hero, bool tight)
{
const_cast<CGHeroInstance*>(hero)->army.formation = tight;
const_cast<CGHeroInstance*>(hero)-> formation = tight;
SetFormation pack(hero->id,tight);
sendRequest(&pack);
}
@@ -939,12 +939,12 @@ void CCallback::dig( const CGObjectInstance *hero )
si8 CCallback::battleGetStackMorale( int stackID )
{
return gs->curB->Morale( gs->curB->getStack(stackID) );
return gs->curB->getStack(stackID)->MoraleVal();
}
si8 CCallback::battleGetStackLuck( int stackID )
{
return gs->curB->Luck( gs->curB->getStack(stackID) );
return gs->curB->getStack(stackID)->LuckVal();
}
void CCallback::castSpell(const CGHeroInstance *hero, int spellID, const int3 &pos)
@@ -987,7 +987,7 @@ InfoAboutTown::~InfoAboutTown()
void InfoAboutTown::initFromTown( const CGTownInstance *t, bool detailed )
{
obj = t;
army = t->army;
army = t->getArmy();
built = t->builded;
fortLevel = t->fortLevel();
name = t->name;
@@ -1006,7 +1006,7 @@ void InfoAboutTown::initFromTown( const CGTownInstance *t, bool detailed )
/*else
{
//hide info about hero stacks counts
for(std::map<si32,std::pair<ui32,si32> >::iterator i = army.slots.begin(); i != army.slots.end(); ++i)
for(std::map<si32,std::pair<ui32,si32> >::iterator i = slots.begin(); i != slots.end(); ++i)
{
i->second.second = 0;
}
@@ -1017,7 +1017,7 @@ void InfoAboutTown::initFromGarrison(const CGGarrison *garr, bool detailed)
{
obj = garr;
fortLevel = 0;
army = garr->army;
army = garr->getArmy();
name = CGI->generaltexth->names[33]; // "Garrison"
owner = garr->tempOwner;
built = false;

View File

@@ -36,7 +36,7 @@ struct BattleAttack;
struct BattleStackAttacked;
struct SpellCast;
struct SetStackEffect;
struct HeroBonus;
struct Bonus;
struct PackageApplied;
struct SetObjectProperty;
struct CatapultAttack;
@@ -53,17 +53,6 @@ class CObstacle
//TODO: add some kind of the blockmap
};
struct StackState
{
StackState(){attackBonus=defenseBonus=healthBonus=speedBonus=morale=luck=shotsLeft=currentHealth=0;};
int attackBonus, defenseBonus, healthBonus, speedBonus;
int currentHealth;
int shotsLeft;
std::set<int> effects; //IDs of spells affecting stack
int morale, luck;
int dmgMultiplier; //for ballista dmg bonus handling
};
class CGameInterface
{
public:
@@ -98,8 +87,8 @@ public:
virtual void yourTurn(){};
virtual void centerView (int3 pos, int focusTime){};
virtual void availableCreaturesChanged(const CGDwelling *town){};
virtual void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
virtual void playerBonusChanged(const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
virtual void heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
virtual void playerBonusChanged(const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
virtual void requestRealized(PackageApplied *pa){};
virtual void heroExchangeStarted(si32 hero1, si32 hero2){};
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
@@ -121,7 +110,7 @@ public:
virtual void battleStackMoved(int ID, int dest, int distance, bool end){};
virtual void battleSpellCast(SpellCast *sc){};
virtual void battleStacksEffectsSet(SetStackEffect & sse){};//called when a specific effect is set to stacks
virtual void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
virtual void battleNewStackAppeared(int stackID){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned

View File

@@ -1898,7 +1898,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->army.slots.empty())
if (townObj && !townObj->stacksCount())
CGI->curh->changeGraphic(0, 9 + turns*6);
else
CGI->curh->changeGraphic(0, 5 + turns*6);
@@ -1938,7 +1938,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->tempOwner != LOCPLINT->playerID && !garrObj->army.slots.empty())
if (garrObj && garrObj->tempOwner != LOCPLINT->playerID && garrObj->stacksCount())
CGI->curh->changeGraphic(0, 5 + turns*6);
else
CGI->curh->changeGraphic(0, 9 + turns*6);

View File

@@ -216,7 +216,7 @@ bool CSpellEffectAnim::init()
}
// Correction for 2-hex creatures.
if (destStack != NULL && destStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
if (destStack != NULL && destStack->doubleWide())
be.x += (destStack->attackerOwned ? -1 : 1)*tilePos.w/2;
owner->battleEffects.push_back(be);
@@ -376,7 +376,7 @@ void CReverseAnim::nextFrame()
owner->creAnims[stackID]->pos.x = coords.x;
//creAnims[stackID]->pos.y = coords.second;
if(curs->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
if(curs->doubleWide())
{
if(curs->attackerOwned)
{
@@ -445,7 +445,7 @@ bool CDefenceAnim::init()
if(IDby != -1)
{
int attackerAnimType = owner->creAnims[IDby]->getType();
if( attackerAnimType == 11 && attackerAnimType == 12 && attackerAnimType == 13 && owner->creAnims[IDby]->getFrame() < attacker->creature->attackClimaxFrame )
if( attackerAnimType == 11 && attackerAnimType == 12 && attackerAnimType == 13 && owner->creAnims[IDby]->getFrame() < attacker->type->attackClimaxFrame )
return false;
}
@@ -465,7 +465,7 @@ bool CDefenceAnim::init()
const CStack * attacked = owner->curInt->cb->battleGetStackByID(stackID, false);
//reverse unit if necessary
if(attacker && isToReverse(attacked->position, attacker->position, owner->creDir[stackID], attacker->hasFeatureOfType(StackFeature::DOUBLE_WIDE), owner->creDir[IDby]))
if(attacker && isToReverse(attacked->position, attacker->position, owner->creDir[stackID], attacker->doubleWide(), owner->creDir[IDby]))
{
owner->addNewAnim(new CReverseAnim(owner, stackID, attacked->position, true));
return false;
@@ -476,7 +476,7 @@ bool CDefenceAnim::init()
{
for(std::list<SProjectileInfo>::const_iterator it = owner->projectiles.begin(); it != owner->projectiles.end(); ++it)
{
if(it->creID == attacker->creature->idNumber)
if(it->creID == attacker->type->idNumber)
{
return false;
}
@@ -488,13 +488,13 @@ bool CDefenceAnim::init()
if(killed)
{
CGI->soundh->playSound(battle_sound(attacked->creature, killed));
CGI->soundh->playSound(battle_sound(attacked->type, killed));
owner->creAnims[stackID]->setType(5); //death
}
else
{
// TODO: this block doesn't seems correct if the unit is defending.
CGI->soundh->playSound(battle_sound(attacked->creature, wince));
CGI->soundh->playSound(battle_sound(attacked->type, wince));
owner->creAnims[stackID]->setType(3); //getting hit
}
@@ -572,7 +572,7 @@ bool CBattleStackMoved::init()
endAnim();
return false;
}
bool twoTiles = movedStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE);
bool twoTiles = movedStack->doubleWide();
Point begPosition = CBattleHex::getXYUnitAnim(curStackPos, movedStack->attackerOwned, movedStack, owner);
Point endPosition = CBattleHex::getXYUnitAnim(destHex, movedStack->attackerOwned, movedStack, owner);
@@ -598,11 +598,11 @@ bool CBattleStackMoved::init()
//unit reversed
if(owner->moveSh <= 0)
owner->moveSh = CGI->soundh->playSound(battle_sound(movedStack->creature, move), -1);
owner->moveSh = CGI->soundh->playSound(battle_sound(movedStack->type, move), -1);
//step shift calculation
posX = owner->creAnims[stackID]->pos.x, posY = owner->creAnims[stackID]->pos.y; // for precise calculations ;]
if(mutPos == -1 && movedStack->hasFeatureOfType(StackFeature::FLYING))
if(mutPos == -1 && movedStack->hasBonusOfType(Bonus::FLYING))
{
steps *= distance;
steps /= 2; //to make animation faster
@@ -668,7 +668,7 @@ void CBattleStackMoved::endAnim()
if(movedStack)
{
bool twoTiles = movedStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE);
bool twoTiles = movedStack->doubleWide();
if(endMoving)
{
@@ -714,7 +714,7 @@ bool CBattleMoveStart::init()
return false;
}
CGI->soundh->playSound(battle_sound(movedStack->creature, startMoving));
CGI->soundh->playSound(battle_sound(movedStack->type, startMoving));
return true;
}
@@ -759,7 +759,7 @@ bool CBattleMoveEnd::init()
return false;
}
CGI->soundh->playSound(battle_sound(movedStack->creature, endMoving));
CGI->soundh->playSound(battle_sound(movedStack->type, endMoving));
owner->creAnims[stackID]->setType(21);
@@ -800,9 +800,9 @@ void CBattleAttack::nextFrame()
if(owner->creAnims[stackID]->onFirstFrameInGroup())
{
if(shooting)
CGI->soundh->playSound(battle_sound(attackingStack->creature, shoot));
CGI->soundh->playSound(battle_sound(attackingStack->type, shoot));
else
CGI->soundh->playSound(battle_sound(attackingStack->creature, attack));
CGI->soundh->playSound(battle_sound(attackingStack->type, attack));
}
else if(owner->creAnims[stackID]->onLastFrameInGroup())
{
@@ -824,7 +824,7 @@ CBattleAttack::CBattleAttack(CBattleInterface * _owner, int _stackID, int _dest,
attackingStack = owner->curInt->cb->battleGetStackByID(_stackID, false);
assert(attackingStack && "attackingStack is NULL in CBattleAttack::CBattleAttack !\n");
if(attackingStack->creature->idNumber != 145) //catapult is allowed to attack not-creature
if(attackingStack->type->idNumber != 145) //catapult is allowed to attack not-creature
{
assert(attackedStack && "attackedStack is NULL in CBattleAttack::CBattleAttack !\n");
}
@@ -857,7 +857,7 @@ bool CMeleeAttack::init()
int reversedShift = 0; //shift of attacking stack's position due to reversing
if(attackingStack->attackerOwned)
{
if(attackingStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && BattleInfo::mutualPosition(attackingStackPosBeforeReturn, dest) == -1)
if(attackingStack->doubleWide() && BattleInfo::mutualPosition(attackingStackPosBeforeReturn, dest) == -1)
{
if(BattleInfo::mutualPosition(attackingStackPosBeforeReturn + (attackingStack->attackerOwned ? -1 : 1), dest) >= 0) //if reversing stack will make its position adjacent to dest
{
@@ -867,7 +867,7 @@ bool CMeleeAttack::init()
}
else //if(astack->attackerOwned)
{
if(attackingStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && BattleInfo::mutualPosition(attackingStackPosBeforeReturn, dest) == -1)
if(attackingStack->doubleWide() && BattleInfo::mutualPosition(attackingStackPosBeforeReturn, dest) == -1)
{
if(BattleInfo::mutualPosition(attackingStackPosBeforeReturn + (attackingStack->attackerOwned ? -1 : 1), dest) >= 0) //if reversing stack will make its position adjacent to dest
{
@@ -878,7 +878,7 @@ bool CMeleeAttack::init()
}
//reversing stack if necessary
if(isToReverse(attackingStackPosBeforeReturn, dest, owner->creDir[stackID], attackedStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE), owner->creDir[attackedStack->ID]))
if(isToReverse(attackingStackPosBeforeReturn, dest, owner->creDir[stackID], attackedStack->doubleWide(), owner->creDir[attackedStack->ID]))
{
owner->addNewAnim(new CReverseAnim(owner, stackID, attackingStackPosBeforeReturn, true));
return false;
@@ -953,7 +953,7 @@ bool CShootingAnim::init()
projectileAngle = -projectileAngle;
SProjectileInfo spi;
spi.creID = shooter->creature->idNumber;
spi.creID = shooter->type->idNumber;
spi.reverse = !shooter->attackerOwned;
spi.step = 0;
@@ -975,18 +975,18 @@ bool CShootingAnim::init()
if(projectileAngle > straightAngle) //upper shot
{
spi.x = xycoord.x + 200 + shooter->creature->upperRightMissleOffsetX;
spi.y = xycoord.y + 100 - shooter->creature->upperRightMissleOffsetY;
spi.x = xycoord.x + 200 + shooter->type->upperRightMissleOffsetX;
spi.y = xycoord.y + 100 - shooter->type->upperRightMissleOffsetY;
}
else if(projectileAngle < -straightAngle) //lower shot
{
spi.x = xycoord.x + 200 + shooter->creature->lowerRightMissleOffsetX;
spi.y = xycoord.y + 150 - shooter->creature->lowerRightMissleOffsetY;
spi.x = xycoord.x + 200 + shooter->type->lowerRightMissleOffsetX;
spi.y = xycoord.y + 150 - shooter->type->lowerRightMissleOffsetY;
}
else //straight shot
{
spi.x = xycoord.x + 200 + shooter->creature->rightMissleOffsetX;
spi.y = xycoord.y + 125 - shooter->creature->rightMissleOffsetY;
spi.x = xycoord.x + 200 + shooter->type->rightMissleOffsetX;
spi.y = xycoord.y + 125 - shooter->type->rightMissleOffsetY;
}
spi.lastStep = sqrt((float)((destcoord.x - spi.x)*(destcoord.x - spi.x) + (destcoord.y - spi.y) * (destcoord.y - spi.y))) / 40;
if(spi.lastStep == 0)
@@ -1003,7 +1003,7 @@ bool CShootingAnim::init()
spi.frameNum = ((M_PI/2.0f - projectileAngle) / (2.0f *M_PI) + 1/((float)(2*(owner->idToProjectile[spi.creID]->ourImages.size()-1)))) * (owner->idToProjectile[spi.creID]->ourImages.size()-1);
}
//set delay
spi.animStartDelay = CGI->creh->creatures[spi.creID].attackClimaxFrame;
spi.animStartDelay = CGI->creh->creatures[spi.creID]->attackClimaxFrame;
owner->projectiles.push_back(spi);
//attack aniamtion
@@ -1064,7 +1064,7 @@ void CBattleInterface::addNewAnim(CBattleAnimation * anim)
animsAreDisplayed.setn(true);
}
CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen)
CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen)
: attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0), activeStack(-1), stackToActivate(-1),
mouseHoveredStack(-1), previouslyHoveredHex(-1), currentlyHoveredHex(-1), spellDestSelectMode(false),
spellToCast(NULL), givenCommand(NULL), myTurn(false), resWindow(NULL), animIDhelper(0),
@@ -1228,25 +1228,25 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
//loading projectiles for units
for(std::map<int, CStack>::iterator g = stacks.begin(); g != stacks.end(); ++g)
{
int creID = (g->second.creature->idNumber == 149) ? CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] : g->second.creature->idNumber; //id of creature whose shots should be loaded
if(g->second.creature->isShooting() && CGI->creh->idToProjectile[creID] != std::string())
int creID = (g->second.type->idNumber == 149) ? CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] : g->second.type->idNumber; //id of creature whose shots should be loaded
if(g->second.type->isShooting() && CGI->creh->idToProjectile[creID] != std::string())
{
idToProjectile[g->second.creature->idNumber] = CDefHandler::giveDef(CGI->creh->idToProjectile[creID]);
idToProjectile[g->second.type->idNumber] = CDefHandler::giveDef(CGI->creh->idToProjectile[creID]);
if(idToProjectile[g->second.creature->idNumber]->ourImages.size() > 2) //add symmetric images
if(idToProjectile[g->second.type->idNumber]->ourImages.size() > 2) //add symmetric images
{
for(int k = idToProjectile[g->second.creature->idNumber]->ourImages.size()-2; k > 1; --k)
for(int k = idToProjectile[g->second.type->idNumber]->ourImages.size()-2; k > 1; --k)
{
Cimage ci;
ci.bitmap = CSDL_Ext::rotate01(idToProjectile[g->second.creature->idNumber]->ourImages[k].bitmap);
ci.bitmap = CSDL_Ext::rotate01(idToProjectile[g->second.type->idNumber]->ourImages[k].bitmap);
ci.groupNumber = 0;
ci.imName = std::string();
idToProjectile[g->second.creature->idNumber]->ourImages.push_back(ci);
idToProjectile[g->second.type->idNumber]->ourImages.push_back(ci);
}
}
for(int s=0; s<idToProjectile[g->second.creature->idNumber]->ourImages.size(); ++s) //alpha transforming
for(int s=0; s<idToProjectile[g->second.type->idNumber]->ourImages.size(); ++s) //alpha transforming
{
CSDL_Ext::alphaTransform(idToProjectile[g->second.creature->idNumber]->ourImages[s].bitmap);
CSDL_Ext::alphaTransform(idToProjectile[g->second.type->idNumber]->ourImages[s].bitmap);
}
}
}
@@ -1589,7 +1589,7 @@ void CBattleInterface::show(SDL_Surface * to)
{
int curStackID = stackAliveByHex[b][v];
if(!stacks[curStackID].hasFeatureOfType(StackFeature::FLYING) || creAnims[curStackID]->getType() != 0)
if(!stacks[curStackID].hasBonusOfType(Bonus::FLYING) || creAnims[curStackID]->getType() != 0)
showAliveStack(curStackID, stacks, to);
else
flyingStacks.push_back(curStackID);
@@ -1733,7 +1733,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
{
if(shere->owner == curInt->playerID) //our stack
{
if(sactive->hasFeatureOfType(StackFeature::HEALER))
if(sactive->hasBonusOfType(Bonus::HEALER))
{
//display the possibility to heal this creature
CGI->curh->changeGraphic(1,17);
@@ -1745,7 +1745,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
}
//setting console text
char buf[500];
sprintf(buf, CGI->generaltexth->allTexts[297].c_str(), shere->amount == 1 ? shere->creature->nameSing.c_str() : shere->creature->namePl.c_str());
sprintf(buf, CGI->generaltexth->allTexts[297].c_str(), shere->count == 1 ? shere->type->nameSing.c_str() : shere->type->namePl.c_str());
console->alterTxt = buf;
console->whoSetAlter = 0;
mouseHoveredStack = shere->ID;
@@ -1773,7 +1773,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
std::ostringstream estDmg;
estDmg << estimatedDmg.first << " - " << estimatedDmg.second;
//printing
sprintf(buf, CGI->generaltexth->allTexts[296].c_str(), shere->amount == 1 ? shere->creature->nameSing.c_str() : shere->creature->namePl.c_str(), sactive->shots, estDmg.str().c_str());
sprintf(buf, CGI->generaltexth->allTexts[296].c_str(), shere->count == 1 ? shere->type->nameSing.c_str() : shere->type->namePl.c_str(), sactive->shots, estDmg.str().c_str());
console->alterTxt = buf;
console->whoSetAlter = 0;
}
@@ -1797,7 +1797,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
sectorCursor.push_back(12);
sectorCursor.push_back(7);
const bool doubleWide = curInt->cb->battleGetStackByID(activeStack)->hasFeatureOfType(StackFeature::DOUBLE_WIDE);
const bool doubleWide = curInt->cb->battleGetStackByID(activeStack)->doubleWide();
bool aboveAttackable = true, belowAttackable = true;
// Exclude directions which cannot be attacked from.
@@ -1923,7 +1923,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
std::ostringstream estDmg;
estDmg << estimatedDmg.first << " - " << estimatedDmg.second;
//printing
sprintf(buf, CGI->generaltexth->allTexts[36].c_str(), shere->amount == 1 ? shere->creature->nameSing.c_str() : shere->creature->namePl.c_str(), estDmg.str().c_str());
sprintf(buf, CGI->generaltexth->allTexts[36].c_str(), shere->count == 1 ? shere->type->nameSing.c_str() : shere->type->namePl.c_str(), estDmg.str().c_str());
console->alterTxt = buf;
console->whoSetAlter = 0;
}
@@ -1934,7 +1934,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
console->whoSetAlter = 0;
}
}
else if( sactive && sactive->hasFeatureOfType(StackFeature::CATAPULT) && isCatapultAttackable(myNumber) ) //catapulting
else if( sactive && sactive->hasBonusOfType(Bonus::CATAPULT) && isCatapultAttackable(myNumber) ) //catapulting
{
CGI->curh->changeGraphic(1,16);
console->alterTxt = "";
@@ -1954,15 +1954,15 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
if(sactive) //there can be a moment when stack is dead ut next is not yet activated
{
char buf[500];
if(sactive->hasFeatureOfType(StackFeature::FLYING))
if(sactive->hasBonusOfType(Bonus::FLYING))
{
CGI->curh->changeGraphic(1,2);
sprintf(buf, CGI->generaltexth->allTexts[295].c_str(), sactive->amount == 1 ? sactive->creature->nameSing.c_str() : sactive->creature->namePl.c_str());
sprintf(buf, CGI->generaltexth->allTexts[295].c_str(), sactive->count == 1 ? sactive->type->nameSing.c_str() : sactive->type->namePl.c_str());
}
else
{
CGI->curh->changeGraphic(1,1);
sprintf(buf, CGI->generaltexth->allTexts[294].c_str(), sactive->amount == 1 ? sactive->creature->nameSing.c_str() : sactive->creature->namePl.c_str());
sprintf(buf, CGI->generaltexth->allTexts[294].c_str(), sactive->count == 1 ? sactive->type->nameSing.c_str() : sactive->type->namePl.c_str());
}
console->alterTxt = buf;
@@ -1994,7 +1994,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
//get dead stack if we cast resurrection or animate dead
const CStack * stackUnder = curInt->cb->battleGetStackByPos(myNumber, spellToCast->additionalInfo != 38 && spellToCast->additionalInfo != 39);
if(stackUnder && spellToCast->additionalInfo == 39 && !stackUnder->hasFeatureOfType(StackFeature::UNDEAD)) //animate dead can be cast only on undead creatures
if(stackUnder && spellToCast->additionalInfo == 39 && !stackUnder->hasBonusOfType(Bonus::UNDEAD)) //animate dead can be cast only on undead creatures
stackUnder = NULL;
bool whichCase; //for cases 1, 2 and 3
@@ -2027,7 +2027,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
CGI->curh->changeGraphic(3, 0);
//setting console text
char buf[500];
std::string creName = stackUnder->amount > 1 ? stackUnder->creature->namePl : stackUnder->creature->nameSing;
std::string creName = stackUnder->count > 1 ? stackUnder->type->namePl : stackUnder->type->nameSing;
sprintf(buf, CGI->generaltexth->allTexts[27].c_str(), CGI->spellh->spells[spellToCast->additionalInfo].name.c_str(), creName.c_str());
console->alterTxt = buf;
console->whoSetAlter = 0;
@@ -2182,12 +2182,12 @@ void CBattleInterface::newStack(int stackID)
if(newStack->position < 0) //turret
{
const CCreature & turretCreature = CGI->creh->creatures[ CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] ];
const CCreature & turretCreature = *CGI->creh->creatures[ CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] ];
creAnims[stackID] = new CCreatureAnimation(turretCreature.animDefName);
}
else
{
creAnims[stackID] = new CCreatureAnimation(newStack->creature->animDefName);
creAnims[stackID] = new CCreatureAnimation(newStack->type->animDefName);
}
creAnims[stackID]->setType(2);
creAnims[stackID]->pos = Rect(coords.x, coords.y, creAnims[newStack->ID]->fullWidth, creAnims[newStack->ID]->fullHeight);
@@ -2239,13 +2239,13 @@ void CBattleInterface::newRound(int number)
std::map<int, CStack> stacks = curInt->cb->battleGetStacks();
for(std::map<int, CStack>::const_iterator it = stacks.begin(); it != stacks.end(); ++it)
{
if( it->second.hasFeatureOfType(StackFeature::HP_REGENERATION) && it->second.alive() )
if( it->second.hasBonusOfType(Bonus::HP_REGENERATION) && it->second.alive() )
displayEffect(74, it->second.position);
if( it->second.hasFeatureOfType(StackFeature::FULL_HP_REGENERATION, 0) && it->second.alive() )
if( it->second.hasBonusOfType(Bonus::FULL_HP_REGENERATION, 0) && it->second.alive() )
displayEffect(4, it->second.position);
if( it->second.hasFeatureOfType(StackFeature::FULL_HP_REGENERATION, 1) && it->second.alive() )
if( it->second.hasBonusOfType(Bonus::FULL_HP_REGENERATION, 1) && it->second.alive() )
displayEffect(74, it->second.position);
}
}
@@ -2317,7 +2317,7 @@ void CBattleInterface::hexLclicked(int whichOne)
{
const CStack * actSt = curInt->cb->battleGetStackByID(activeStack);
if( ((whichOne%BFIELD_WIDTH)!=0 && (whichOne%BFIELD_WIDTH)!=(BFIELD_WIDTH-1)) //if player is trying to attack enemey unit or move creature stack
|| (actSt->hasFeatureOfType(StackFeature::CATAPULT) && !spellDestSelectMode )
|| (actSt->hasBonusOfType(Bonus::CATAPULT) && !spellDestSelectMode )
)
{
if(!myTurn)
@@ -2362,7 +2362,7 @@ void CBattleInterface::hexLclicked(int whichOne)
if(std::find(shadedHexes.begin(),shadedHexes.end(),whichOne)!=shadedHexes.end())// and it's in our range
{
CGI->curh->changeGraphic(1, 6); //cursor should be changed
if(curInt->cb->battleGetStackByID(activeStack)->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
if(curInt->cb->battleGetStackByID(activeStack)->doubleWide())
{
std::vector<int> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
int shiftedDest = whichOne + (curInt->cb->battleGetStackByID(activeStack)->attackerOwned ? 1 : -1);
@@ -2376,7 +2376,7 @@ void CBattleInterface::hexLclicked(int whichOne)
giveCommand(2,whichOne,activeStack);
}
}
else if(actSt->hasFeatureOfType(StackFeature::CATAPULT) && isCatapultAttackable(whichOne)) //attacking (catapult)
else if(actSt->hasBonusOfType(Bonus::CATAPULT) && isCatapultAttackable(whichOne)) //attacking (catapult)
{
giveCommand(9,whichOne,activeStack);
}
@@ -2395,7 +2395,7 @@ void CBattleInterface::hexLclicked(int whichOne)
{
case 12: //from bottom right
{
bool doubleWide = actStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE);
bool doubleWide = actStack->doubleWide();
int destHex = whichOne + ( (whichOne/BFIELD_WIDTH)%2 ? BFIELD_WIDTH : BFIELD_WIDTH+1 ) +
(actStack->attackerOwned && doubleWide ? 1 : 0);
if(vstd::contains(shadedHexes, destHex))
@@ -2431,7 +2431,7 @@ void CBattleInterface::hexLclicked(int whichOne)
}
case 8: //from left
{
if(actStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && !actStack->attackerOwned)
if(actStack->doubleWide() && !actStack->attackerOwned)
{
std::vector<int> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
if(vstd::contains(acc, whichOne))
@@ -2464,7 +2464,7 @@ void CBattleInterface::hexLclicked(int whichOne)
}
case 10: //from top right
{
bool doubleWide = actStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE);
bool doubleWide = actStack->doubleWide();
int destHex = whichOne - ( (whichOne/BFIELD_WIDTH)%2 ? BFIELD_WIDTH : BFIELD_WIDTH-1 ) +
(actStack->attackerOwned && doubleWide ? 1 : 0);
if(vstd::contains(shadedHexes, destHex))
@@ -2483,7 +2483,7 @@ void CBattleInterface::hexLclicked(int whichOne)
}
case 11: //from right
{
if(actStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && actStack->attackerOwned)
if(actStack->doubleWide() && actStack->attackerOwned)
{
std::vector<int> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
if(vstd::contains(acc, whichOne))
@@ -2541,7 +2541,7 @@ void CBattleInterface::hexLclicked(int whichOne)
}
}
else if (actSt->hasFeatureOfType(StackFeature::HEALER) && actSt->owner == dest->owner) //friendly creature we can heal
else if (actSt->hasBonusOfType(Bonus::HEALER) && actSt->owner == dest->owner) //friendly creature we can heal
{
giveCommand(12, whichOne, activeStack); //command healing
@@ -2689,7 +2689,7 @@ void CBattleInterface::spellCast(SpellCast * sc)
boost::algorithm::replace_first(text, "%s", "Creature"); //TODO: better fix
}
boost::algorithm::replace_first(text, "%s", CGI->spellh->spells[sc->id].name);
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->creature->namePl );
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->type->namePl );
console->addText(text);
}
else
@@ -2900,14 +2900,14 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac
creAnims[ID]->nextFrame(to, creAnims[ID]->pos.x, creAnims[ID]->pos.y, creDir[ID], animCount, incrementFrame, ID==activeStack, ID==mouseHoveredStack); //increment always when moving, never if stack died
//printing amount
if(curStack.amount > 0 //don't print if stack is not alive
if(curStack.count > 0 //don't print if stack is not alive
&& (!curInt->curAction
|| (curInt->curAction->stackNumber != ID //don't print if stack is currently taking an action
&& (curInt->curAction->actionType != 6 || curStack.position != curInt->curAction->additionalInfo) //nor if it's an object of attack
&& (curInt->curAction->destinationTile != curStack.position) //nor if it's on destination tile for current action
)
)
&& !curStack.hasFeatureOfType(StackFeature::SIEGE_WEAPON) //and not a war machine...
&& !curStack.hasBonusOfType(Bonus::SIEGE_WEAPON) //and not a war machine...
)
{
int xAdd = curStack.attackerOwned ? 220 : 202;
@@ -2941,7 +2941,7 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac
SDL_BlitSurface(amountBG, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[ID]->pos.x + xAdd, creAnims[ID]->pos.y + 260));
//blitting amount
CSDL_Ext::printAtMiddle(
makeNumberShort(curStack.amount),
makeNumberShort(curStack.count),
creAnims[ID]->pos.x + xAdd + 15,
creAnims[ID]->pos.y + 260 + 5,
FONT_TINY,
@@ -3045,18 +3045,18 @@ void CBattleInterface::printConsoleAttacked(int ID, int dmg, int killed, int IDb
char tabh[200];
const CStack * attacker = curInt->cb->battleGetStackByID(IDby, false);
const CStack * defender = curInt->cb->battleGetStackByID(ID, false);
int end = sprintf(tabh, CGI->generaltexth->allTexts[attacker->amount > 1 ? 377 : 376].c_str(),
(attacker->amount > 1 ? attacker->creature->namePl.c_str() : attacker->creature->nameSing.c_str()),
int end = sprintf(tabh, CGI->generaltexth->allTexts[attacker->count > 1 ? 377 : 376].c_str(),
(attacker->count > 1 ? attacker->type->namePl.c_str() : attacker->type->nameSing.c_str()),
dmg);
if(killed > 0)
{
if(killed > 1)
{
sprintf(tabh + end, CGI->generaltexth->allTexts[379].c_str(), killed, defender->creature->namePl.c_str());
sprintf(tabh + end, CGI->generaltexth->allTexts[379].c_str(), killed, defender->type->namePl.c_str());
}
else //killed == 1
{
sprintf(tabh + end, CGI->generaltexth->allTexts[378].c_str(), defender->creature->nameSing.c_str());
sprintf(tabh + end, CGI->generaltexth->allTexts[378].c_str(), defender->type->nameSing.c_str());
}
}
@@ -3219,14 +3219,14 @@ void CBattleInterface::startAction(const BattleAction* action)
break;
}
if(txtid > 0 && stack->amount != 1)
if(txtid > 0 && stack->count != 1)
txtid++; //move to plural text
else if(txtid < 0)
txtid = -txtid;
if(txtid)
{
sprintf(txt, CGI->generaltexth->allTexts[txtid].c_str(), (stack->amount != 1) ? stack->creature->namePl.c_str() : stack->creature->nameSing.c_str(), 0);
sprintf(txt, CGI->generaltexth->allTexts[txtid].c_str(), (stack->count != 1) ? stack->type->namePl.c_str() : stack->type->nameSing.c_str(), 0);
console->addText(txt);
}
@@ -3386,7 +3386,7 @@ Point CBattleHex::getXYUnitAnim(const int & hexNum, const bool & attacker, const
Point ret(-500, -500); //returned value
if(stack->position < 0) //creatures in turrets
{
const CCreature & turretCreature = CGI->creh->creatures[ CGI->creh->factionToTurretCreature[cbi->siegeH->town->town->typeID] ];
const CCreature & turretCreature = *CGI->creh->creatures[ CGI->creh->factionToTurretCreature[cbi->siegeH->town->town->typeID] ];
int xShift = turretCreature.isDoubleWide() ? 44 : 0;
switch(stack->position)
@@ -3415,7 +3415,7 @@ Point CBattleHex::getXYUnitAnim(const int & hexNum, const bool & attacker, const
ret.x = -219 + 22 * ( ((hexNum/BFIELD_WIDTH) + 1)%2 ) + 44 * (hexNum % BFIELD_WIDTH);
}
//shifting position for double - hex creatures
if(stack && stack->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
if(stack && stack->doubleWide())
{
if(attacker)
{
@@ -3483,7 +3483,7 @@ void CBattleHex::mouseMoved(const SDL_MouseMotionEvent &sEvent)
{
char tabh[160];
const CStack * attackedStack = myInterface->curInt->cb->battleGetStackByPos(myNumber);
const std::string & attackedName = attackedStack->amount == 1 ? attackedStack->creature->nameSing : attackedStack->creature->namePl;
const std::string & attackedName = attackedStack->count == 1 ? attackedStack->type->nameSing : attackedStack->type->namePl;
sprintf(tabh, CGI->generaltexth->allTexts[220].c_str(), attackedName.c_str());
myInterface->console->alterTxt = std::string(tabh);
setAlterText = true;
@@ -3511,32 +3511,10 @@ void CBattleHex::clickRight(tribool down, bool previousState)
{
const CStack & myst = *myInterface->curInt->cb->battleGetStackByID(stID); //stack info
if(!myst.alive()) return;
StackState *pom = NULL;
if(down)
{
pom = new StackState();
const CGHeroInstance *h = myst.owner == myInterface->attackingHeroInstance->tempOwner ? myInterface->attackingHeroInstance : myInterface->defendingHeroInstance;
pom->attackBonus = myst.Attack() - myst.creature->attack;
pom->defenseBonus = myst.Defense() - myst.creature->defence;
pom->luck = myInterface->curInt->cb->battleGetStackLuck(myst.ID);
pom->morale = myInterface->curInt->cb->battleGetStackMorale(myst.ID);
pom->speedBonus = myst.Speed() - myst.creature->speed;
pom->healthBonus = myst.MaxHealth() - myst.creature->hitPoints;
if(myst.hasFeatureOfType(StackFeature::SIEGE_WEAPON))
pom->dmgMultiplier = h->getPrimSkillLevel(0) + 1;
else
pom->dmgMultiplier = 1;
pom->shotsLeft = myst.shots;
for(int vb=0; vb<myst.effects.size(); ++vb)
{
pom->effects.insert(myst.effects[vb].id);
}
pom->currentHealth = myst.firstHPleft;
GH.pushInt(new CCreInfoWindow(myst.creature->idNumber, 0, myst.amount, pom, 0, 0, NULL));
GH.pushInt(new CCreInfoWindow(myst));
}
delete pom;
}
}
@@ -3660,7 +3638,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
{
int bestMonsterID = -1;
int bestPower = 0;
for(TSlots::const_iterator it = owner->army1->slots.begin(); it!=owner->army1->slots.end(); ++it)
for(TSlots::const_iterator it = owner->army1->Slots().begin(); it!=owner->army1->Slots().end(); ++it)
{
if( it->second.type->AIValue > bestPower)
{
@@ -3670,7 +3648,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
}
SDL_BlitSurface(graphics->bigImgs[bestMonsterID], NULL, background, &genRect(64, 58, 21, 38));
//setting attackerName
attackerName = CGI->creh->creatures[bestMonsterID].namePl;
attackerName = CGI->creh->creatures[bestMonsterID]->namePl;
}
if(owner->defendingHeroInstance) //a hero defended
{
@@ -3682,7 +3660,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
{
int bestMonsterID = -1;
int bestPower = 0;
for(TSlots::const_iterator it = owner->army2->slots.begin(); it!=owner->army2->slots.end(); ++it)
for(TSlots::const_iterator it = owner->army2->Slots().begin(); it!=owner->army2->Slots().end(); ++it)
{
if( it->second.type->AIValue > bestPower)
{
@@ -3692,7 +3670,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
}
SDL_BlitSurface(graphics->bigImgs[bestMonsterID], NULL, background, &genRect(64, 58, 391, 38));
//setting defenderName
defenderName = CGI->creh->creatures[bestMonsterID].namePl;
defenderName = CGI->creh->creatures[bestMonsterID]->namePl;
}
//printing attacker and defender's names
@@ -4124,16 +4102,16 @@ void CStackQueue::StackBox::showAll( SDL_Surface *to )
//SDL_UpdateRect(bg, 0, 0, 0, 0);
CSDL_Ext::blit8bppAlphaTo24bpp(bg, NULL, to, &genRect(bg->h, bg->w, pos.x, pos.y));
//blitAt(bg, pos, to);
blitAt(graphics->bigImgs[my->creature->idNumber], pos.x +9, pos.y + 1, to);
printAtMiddleLoc(makeNumberShort(my->amount), pos.w/2, pos.h - 12, FONT_MEDIUM, zwykly, to);
blitAt(graphics->bigImgs[my->type->idNumber], pos.x +9, pos.y + 1, to);
printAtMiddleLoc(makeNumberShort(my->count), pos.w/2, pos.h - 12, FONT_MEDIUM, zwykly, to);
}
else
{
blitAt(graphics->smallImgs[-2], pos, to);
blitAt(graphics->smallImgs[my->creature->idNumber], pos, to);
blitAt(graphics->smallImgs[my->type->idNumber], pos, to);
const SDL_Color &ownerColor = (my->owner == 255 ? *graphics->neutralColor : graphics->playerColors[my->owner]);
CSDL_Ext::drawBorder(to, pos, int3(ownerColor.r, ownerColor.g, ownerColor.b));
printAtMiddleLoc(makeNumberShort(my->amount), pos.w/2, pos.h - 8, FONT_TINY, zwykly, to);
printAtMiddleLoc(makeNumberShort(my->count), pos.w/2, pos.h - 8, FONT_TINY, zwykly, to);
}
}

View File

@@ -382,7 +382,7 @@ private:
CBattleConsole * console;
CBattleHero * attackingHero, * defendingHero; //fighting heroes
CStackQueue *queue;
CCreatureSet * army1, * army2; //fighting armies
const CCreatureSet * army1, * army2; //fighting armies
CGHeroInstance * attackingHeroInstance, * defendingHeroInstance;
std::map< int, CCreatureAnimation * > creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
std::map< int, CDefHandler * > idToProjectile; //projectiles of creatures (creatureID, defhandler)
@@ -445,7 +445,7 @@ public:
unsigned int animIDhelper; //for giving IDs for animations
static CondSh<bool> animsAreDisplayed; //for waiting with the end of battle for end of anims
CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen); //c-tor
CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen); //c-tor
~CBattleInterface(); //d-tor
//std::vector<TimeInterested*> timeinterested; //animation handling

View File

@@ -287,7 +287,7 @@ void CHeroGSlot::clickLeft(tribool down, bool previousState)
LOCPLINT->showInfoDialog(tmp,std::vector<SComponent*>(), soundBase::sound_todo);
allow = false;
}
else if(!other->hero->army.slots.size()) //hero has no creatures - strange, but if we have appropriate error message...
else if(!other->hero->stacksCount()) //hero has no creatures - strange, but if we have appropriate error message...
{
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[19],std::vector<SComponent*>(), soundBase::sound_todo); //This hero has no creatures. A hero must have creatures before he can brave the dangers of the countryside.
allow = false;
@@ -986,7 +986,7 @@ void CCastleInterface::recreateBuildings()
Structure * st = CGI->townh->structures[town->subID][20];
buildings.push_back(new CBuildingRect(st));
s.insert(std::pair<int,int>(st->group,st->ID));
isThereShip = true;
isThereShip = true;
}
}
@@ -1110,7 +1110,7 @@ void CCastleInterface::CCreaInfo::hover(bool on)
if(on)
{
std::string descr=CGI->generaltexth->allTexts[588];
boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid].namePl);
boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->namePl);
GH.statusbar->print(descr);
}
else
@@ -1142,12 +1142,12 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState)
int summ=0, cnt=0;
int level=(bid-30)%CREATURES_PER_TOWN;
std::string descr=CGI->generaltexth->allTexts[589];//Growth of creature is number
boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid].nameSing);
boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->nameSing);
boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>(
ci->town->creatureGrowth(level)));
descr +="\n"+CGI->generaltexth->allTexts[590];
summ = CGI->creh->creatures[crid].growth;
summ = CGI->creh->creatures[crid]->growth;
boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>(summ));
@@ -1159,19 +1159,19 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState)
if(ci->town->town->hordeLvl[0]==level)//horde, x to summ
if((bld.find(18)!=bld.end()) || (bld.find(19)!=bld.end()))
summ+=AddToString(CGI->buildh->buildings[ci->town->subID][18]->Name()+" %+d",descr,
CGI->creh->creatures[crid].hordeGrowth);
CGI->creh->creatures[crid]->hordeGrowth);
if(ci->town->town->hordeLvl[1]==level)//horde, x to summ
if((bld.find(24)!=bld.end()) || (bld.find(25)!=bld.end()))
summ+=AddToString(CGI->buildh->buildings[ci->town->subID][24]->Name()+" %+d",descr,
CGI->creh->creatures[crid].hordeGrowth);
CGI->creh->creatures[crid]->hordeGrowth);
cnt = 0;
int creaLevel = (bid-30)%CREATURES_PER_TOWN;//dwellings have unupgraded units
for (std::vector<CGDwelling*>::const_iterator it = CGI->state->players[ci->town->tempOwner].dwellings.begin();
it !=CGI->state->players[ci->town->tempOwner].dwellings.end(); ++it)
if (CGI->creh->creatures[ci->town->town->basicCreatures[level]].idNumber == (*it)->creatures[0].second[0])
if (CGI->creh->creatures[ci->town->town->basicCreatures[level]]->idNumber == (*it)->creatures[0].second[0])
cnt++;//external dwellings count to summ
summ+=AddToString(CGI->generaltexth->allTexts[591],descr,cnt);
@@ -1180,9 +1180,9 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState)
{
if(ch)
{
for(std::list<HeroBonus>::const_iterator i=ch->bonuses.begin(); i != ch->bonuses.end(); i++)
if(i->type == HeroBonus::CREATURE_GROWTH && i->subtype == level)
if (i->source == HeroBonus::ARTIFACT)
for(std::list<Bonus>::const_iterator i=ch->bonuses.begin(); i != ch->bonuses.end(); i++)
if(i->type == Bonus::CREATURE_GROWTH && i->subtype == level)
if (i->source == Bonus::ARTIFACT)
summ+=AddToString(CGI->arth->artifacts[i->id].Name()+" %+d",descr,i->val);
};
ch = ci->town->visitingHero;
@@ -1810,7 +1810,7 @@ void CFortScreen::draw( CCastleInterface * owner, bool first)
{
bool upgraded = owner->town->creatureDwelling(i,true);
bool present = owner->town->creatureDwelling(i,false);
CCreature *c = &CGI->creh->creatures[upgraded ? owner->town->town->upgradedCreatures[i] : owner->town->town->basicCreatures[i]];
CCreature *c = CGI->creh->creatures[upgraded ? owner->town->town->upgradedCreatures[i] : owner->town->town->basicCreatures[i]];
printAtMiddle(c->namePl,positions[i].x+79,positions[i].y+10,FONT_SMALL,zwykly,bg); //cr. name
blitAt(owner->bicons->ourImages[30+i+upgraded*7].bitmap,positions[i].x+4,positions[i].y+21,bg); //dwelling pic
printAtMiddle(CGI->buildh->buildings[owner->town->subID][30+i+upgraded*7]->Name(),positions[i].x+79,positions[i].y+100,FONT_SMALL,zwykly,bg); //dwelling name
@@ -1823,12 +1823,12 @@ void CFortScreen::draw( CCastleInterface * owner, bool first)
//attack
printAt(CGI->generaltexth->allTexts[190],positions[i].x+288,positions[i].y+5,FONT_SMALL,zwykly,bg);
SDL_itoa(c->attack,buf,10);
SDL_itoa(c->Attack(),buf,10);
printTo(buf,positions[i].x+381,positions[i].y+21,FONT_SMALL,zwykly,bg);
//defense
printAt(CGI->generaltexth->allTexts[191],positions[i].x+288,positions[i].y+25,FONT_SMALL,zwykly,bg);
SDL_itoa(c->defence,buf,10);
SDL_itoa(c->Defense(),buf,10);
printTo(buf,positions[i].x+381,positions[i].y+41,FONT_SMALL,zwykly,bg);
//damage
@@ -1845,12 +1845,12 @@ void CFortScreen::draw( CCastleInterface * owner, bool first)
//health
printAt(CGI->generaltexth->zelp[439].first,positions[i].x+288,positions[i].y+66,FONT_SMALL,zwykly,bg);
SDL_itoa(c->hitPoints,buf,10);
SDL_itoa(c->MaxHealth(),buf,10);
printTo(buf,positions[i].x+381,positions[i].y+82,FONT_SMALL,zwykly,bg);
//speed
printAt(CGI->generaltexth->zelp[441].first,positions[i].x+288,positions[i].y+87,FONT_SMALL,zwykly,bg);
SDL_itoa(c->speed,buf,10);
SDL_itoa(c->valOfBonuses(Bonus::STACKS_SPEED), buf,10);
printTo(buf,positions[i].x+381,positions[i].y+103,FONT_SMALL,zwykly,bg);
if(present)//growth
@@ -2016,10 +2016,10 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, int creMachineID, int aid, i
blitAt(bg2,64,50,bmp);
SDL_FreeSurface(bg2);
CCreatureAnimation cra(CGI->creh->creatures[creMachineID].animDefName);
CCreatureAnimation cra(CGI->creh->creatures[creMachineID]->animDefName);
cra.nextFrameMiddle(bmp,170,120,true,0,false);
char pom[75];
sprintf(pom,CGI->generaltexth->allTexts[274].c_str(),CGI->creh->creatures[creMachineID].nameSing.c_str()); //build a new ...
sprintf(pom,CGI->generaltexth->allTexts[274].c_str(),CGI->creh->creatures[creMachineID]->nameSing.c_str()); //build a new ...
printAtMiddle(pom,165,28,FONT_MEDIUM,tytulowy,bmp);
printAtMiddle(CGI->generaltexth->jktexts[43],165,218,FONT_MEDIUM,zwykly,bmp); //resource cost
SDL_itoa(CGI->arth->artifacts[aid].price,pom,10);

View File

@@ -286,7 +286,7 @@ void CHeroWindow::setHero(const CGHeroInstance *hero)
//setting formations
formations->onChange = 0;
formations->select(hero->army.formation,true);
formations->select(hero->formation,true);
formations->onChange = boost::bind(&CCallback::setFormation, LOCPLINT->cb, hero, _1);
morale->set(true, hero);
@@ -451,8 +451,8 @@ void CHeroWindow::redrawCurBack()
}
//morale and luck printing
blitAt(graphics->luck42->ourImages[curHero->getCurrentLuck()+3].bitmap, 239, 182, curBack);
blitAt(graphics->morale42->ourImages[curHero->getCurrentMorale()+3].bitmap, 181, 182, curBack);
blitAt(graphics->luck42->ourImages[curHero->LuckVal()+3].bitmap, 239, 182, curBack);
blitAt(graphics->morale42->ourImages[curHero->MoraleVal()+3].bitmap, 181, 182, curBack);
blitAt(flags->ourImages[player].bitmap, 606, 8, curBack);

View File

@@ -142,7 +142,7 @@ CKingdomInterface::CKingdomInterface()
if ( obj->ID == 17 )//dwelling, text is a plural name of a creature
{
objList[obj->subID].first += 1;
objList[obj->subID].second = & CGI->creh->creatures[CGI->objh->cregens[obj->subID]].namePl;
objList[obj->subID].second = & CGI->creh->creatures[CGI->objh->cregens[obj->subID]]->namePl;
}
else if (addObjects.find(curElm) != addObjects.end())
{//object from addObjects map, text is name of the object
@@ -552,11 +552,11 @@ void CKingdomInterface::CTownItem::setTown(const CGTownInstance * newTown)
crid = town->town->basicCreatures[i];
std::string descr=CGI->generaltexth->allTexts[588];
boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid].namePl);
boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->namePl);
creaGrowth[i]->hoverText = descr;
descr=CGI->generaltexth->heroscrn[1];
boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid].namePl);
boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->namePl);
creaCount[i]->hoverText = descr;
creaCount[i]->town = town;
}
@@ -910,12 +910,12 @@ void CKingdomInterface::CHeroItem::showAll(SDL_Surface * to)
(i<4)?(pos.y+26):(pos.y+6),to);
if (i>3) continue;//primary skills text
std::ostringstream str;
str << (hero->primSkills[i]);
str << (hero->getPrimSkillLevel(i));
CSDL_Ext::printAtMiddle(str.str(),pos.x+94+36*i,pos.y+66,FONT_SMALL,zwykly,to);
}
{//luck and morale pics, experience and mana text
blitAt(graphics->luck30->ourImages[hero->getCurrentLuck()+3].bitmap,pos.x+222,pos.y+30,to);
blitAt(graphics->morale30->ourImages[hero->getCurrentMorale()+3].bitmap,pos.x+222,pos.y+54,to);
blitAt(graphics->luck30->ourImages[hero->LuckVal()+3].bitmap,pos.x+222,pos.y+30,to);
blitAt(graphics->morale30->ourImages[hero->MoraleVal()+3].bitmap,pos.x+222,pos.y+54,to);
std::ostringstream str;
str << (hero->exp);
CSDL_Ext::printAtMiddle(str.str(),(pos.x+348),(pos.y+31),FONT_TINY,zwykly,to);
@@ -1100,7 +1100,7 @@ void CKingdomInterface::CTownItem::CCreaPlace::clickRight(tribool down, bool pre
crid = town->town->upgradedCreatures[type];
else
crid = town->town->basicCreatures[type];
GH.pushInt(new CCreInfoWindow(crid, 0, town->creatures[type].first, NULL, 0, 0, NULL));
GH.pushInt(new CCreInfoWindow(crid, 0, town->creatures[type].first));
}
}

View File

@@ -436,7 +436,7 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
c->garr->highlighted = NULL;
c->hslotup.hero = town->garrisonHero;
c->garr->odown = c->hslotdown.hero = town->visitingHero;
c->garr->set2 = town->visitingHero ? &town->visitingHero->army : NULL;
c->garr->set2 = town->visitingHero;
c->garr->recreateSlots();
}
GH.totalRedraw();
@@ -499,7 +499,7 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, int buildingID,
}
}
void CPlayerInterface::battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) //called by engine when battle starts; side=0 - left, side=1 - right
void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side)
{
if(LOCPLINT != this)
{ //another local interface should do this
@@ -639,7 +639,7 @@ BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn
if(vstd::contains(stack->state,MOVED)) //this stack has moved and makes second action -> high morale
{
std::string hlp = CGI->generaltexth->allTexts[33];
boost::algorithm::replace_first(hlp,"%s",(stack->amount != 1) ? stack->creature->namePl : stack->creature->nameSing);
boost::algorithm::replace_first(hlp,"%s",(stack->count != 1) ? stack->type->namePl : stack->type->nameSing);
battleInt->displayEffect(20,stack->position);
battleInt->console->addText(hlp);
}
@@ -748,7 +748,7 @@ void CPlayerInterface::battleAttack(BattleAttack *ba)
{
const CStack *stack = cb->battleGetStackByID(ba->stackAttacking);
std::string hlp = CGI->generaltexth->allTexts[45];
boost::algorithm::replace_first(hlp,"%s",(stack->amount != 1) ? stack->creature->namePl.c_str() : stack->creature->nameSing.c_str());
boost::algorithm::replace_first(hlp,"%s",(stack->count != 1) ? stack->type->namePl.c_str() : stack->type->nameSing.c_str());
battleInt->console->addText(hlp);
battleInt->displayEffect(18,stack->position);
}
@@ -926,9 +926,9 @@ void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town )
}
}
void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const HeroBonus &bonus, bool gain )
void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus &bonus, bool gain )
{
if(bonus.type == HeroBonus::NONE) return;
if(bonus.type == Bonus::NONE) return;
boost::unique_lock<boost::recursive_mutex> un(*pim);
updateInfo(hero);
}
@@ -1092,7 +1092,7 @@ void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
{
//redraw minimap if owner changed
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(sop->what == 1)
if(sop->what == ObjProperty::OWNER)
{
const CGObjectInstance * obj = cb->getObjectInfo(sop->id);
std::set<int3> pos = obj->getBlockedPos();
@@ -1725,7 +1725,7 @@ void CPlayerInterface::gameOver(ui8 player, bool victory )
}
}
void CPlayerInterface::playerBonusChanged( const HeroBonus &bonus, bool gain )
void CPlayerInterface::playerBonusChanged( const Bonus &bonus, bool gain )
{
}

View File

@@ -166,8 +166,8 @@ public:
void newObject(const CGObjectInstance * obj);
void yourTurn();
void availableCreaturesChanged(const CGDwelling *town);
void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain);//if gain hero received bonus, else he lost it
void playerBonusChanged(const HeroBonus &bonus, bool gain);
void heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain);//if gain hero received bonus, else he lost it
void playerBonusChanged(const Bonus &bonus, bool gain);
void requestRealized(PackageApplied *pa);
void heroExchangeStarted(si32 hero1, si32 hero2);
void centerView (int3 pos, int focusTime);
@@ -189,7 +189,7 @@ public:
void battleSpellCast(SpellCast *sc);
void battleStacksEffectsSet(SetStackEffect & sse); //called when a specific effect is set to stacks
void battleStacksAttacked(std::vector<BattleStackAttacked> & bsa);
void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks); //called when stacks are healed / resurrected
void battleNewStackAppeared(int stackID); //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned

View File

@@ -1995,7 +1995,7 @@ void OptionsTab::SelectedBox::clickRight( tribool down, bool previousState )
{
int c = t.basicCreatures[i];
blitAt(graphics->smallImgs[c], x, y, bmp);
CSDL_Ext::printAtMiddleWB(CGI->creh->creatures[c].nameSing, x + 16, y + 45, FONT_TINY, 10, zwykly, bmp);
CSDL_Ext::printAtMiddleWB(CGI->creh->creatures[c]->nameSing, x + 16, y + 45, FONT_TINY, 10, zwykly, bmp);
if(i == 2)
{

View File

@@ -157,7 +157,7 @@ void CClient::run()
}
catch (const std::exception& e)
{
tlog3 << "Lost connection to server, ending listening thread!\n";
tlog3 << "Lost connection to server, ending listening thread!\n";
tlog1 << e.what() << std::endl;
if(!terminate) //rethrow (-> boom!) only if closing connection was unexpected
{

View File

@@ -45,6 +45,7 @@
#include "../hch/CVideoHandler.h"
#include "../StartInfo.h"
#include "CPreGame.h"
#include "../lib/HeroBonus.h"
/*
* GUIClasses.cpp, part of VCMI engine
@@ -68,25 +69,6 @@ CFocusable * CFocusable::inputWithFocus;
#undef min
#undef max
static StackState* getStackState(const CGObjectInstance *obj, int pos, bool town)
{
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(obj);
if(!h) return NULL;
StackState *pom = new StackState();
pom->shotsLeft = -1;
pom->healthBonus = h->valOfBonuses(HeroBonus::STACK_HEALTH);
pom->currentHealth = 0;
pom->attackBonus = h->getPrimSkillLevel(0);
pom->defenseBonus = h->getPrimSkillLevel(1);
pom->luck = h->getCurrentLuck();
pom->morale = h->getCurrentMorale(pos,town);
pom->speedBonus = h->valOfBonuses(HeroBonus::STACKS_SPEED);
pom->dmgMultiplier = 1;
return pom;
}
void CGarrisonSlot::hover (bool on)
{
////Hoverable::hover(on);
@@ -143,7 +125,7 @@ void CGarrisonSlot::hover (bool on)
{
const CArmedInstance *highl = owner->highlighted->getObj();
if( highl->needsLastStack() //we are moving stack from hero's
&& highl->army.slots.size() == 1 //it's only stack
&& highl->stacksCount() == 1 //it's only stack
&& owner->highlighted->upg != upg //we're moving it to the other garrison
)
{
@@ -175,12 +157,8 @@ const CArmedInstance * CGarrisonSlot::getObj()
void CGarrisonSlot::clickRight(tribool down, bool previousState)
{
StackState *pom = getStackState(getObj(),ID, GH.topInt() == LOCPLINT->castleInt);
if(down && creature)
{
GH.pushInt(new CCreInfoWindow(creature->idNumber, 0, count, pom, 0, 0, NULL));
}
delete pom;
GH.pushInt(new CCreInfoWindow(*myStack));
}
void CGarrisonSlot::clickLeft(tribool down, bool previousState)
{
@@ -196,7 +174,6 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
{
if(owner->highlighted == this) //view info
{
StackState *pom2 = getStackState(getObj(), ID, GH.topInt() == LOCPLINT->castleInt);
UpgradeInfo pom = LOCPLINT->cb->getUpgradeInfo(getObj(), ID);
CCreInfoWindow *creWindow = NULL;
@@ -204,14 +181,14 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
{
creWindow = new CCreInfoWindow(
creature->idNumber, 1, count, pom2,
*myStack, 1,
boost::bind(&CCallback::upgradeCreature, LOCPLINT->cb, getObj(), ID, pom.newID[0]), //bind upgrade function
boost::bind(&CCallback::dismissCreature, LOCPLINT->cb, getObj(), ID), &pom);
}
else
{
creWindow = new CCreInfoWindow(
creature->idNumber, 1, count, pom2, 0,
*myStack, 1, 0,
boost::bind(&CCallback::dismissCreature, LOCPLINT->cb, getObj(), ID), NULL);
}
@@ -225,7 +202,6 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
show(screen2);
refr = true;
delete pom2;
}
else
{
@@ -250,12 +226,12 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
int last = -1;
if(upg != owner->highlighted->upg) //not splitting within same army
{
if(owner->highlighted->getObj()->army.slots.size() == 1 //we're splitting away the last stack
if(owner->highlighted->getObj()->stacksCount() == 1 //we're splitting away the last stack
&& owner->highlighted->getObj()->needsLastStack() )
{
last = 0;
}
if(getObj()->army.slots.size() == 1 //destination army can't be emptied, unless we're rebalancing two stacks of same creature
if(getObj()->stacksCount() == 1 //destination army can't be emptied, unless we're rebalancing two stacks of same creature
&& owner->highlighted->creature == creature
&& getObj()->needsLastStack() )
{
@@ -323,13 +299,15 @@ void CGarrisonSlot::deactivate()
deactivateRClick();
deactivateHover();
}
CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg, const CCreature * Creature, int Count)
CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg, const CStackInstance * Creature)
{
//assert(Creature == CGI->creh->creatures[Creature->idNumber]);
active = false;
upg = Upg;
count = Count;
ID = IID;
creature = Creature;
myStack = Creature;
creature = Creature ? Creature->type : NULL;
count = Creature ? Creature->count : 0;
pos.x = x;
pos.y = y;
if(Owner->smallIcons)
@@ -487,12 +465,12 @@ void CGarrisonInt::createSlots()
if(set1)
{
sup = new std::vector<CGarrisonSlot*>(7,(CGarrisonSlot *)(NULL));
for(TSlots::const_iterator i=set1->slots.begin(); i!=set1->slots.end(); i++)
(*sup)[i->first] = new CGarrisonSlot(this, pos.x + (i->first*(w+interx)), pos.y, i->first, 0, i->second.type,i->second.count);
for(TSlots::const_iterator i=set1->Slots().begin(); i!=set1->Slots().end(); i++)
(*sup)[i->first] = new CGarrisonSlot(this, pos.x + (i->first*(w+interx)), pos.y, i->first, 0, &i->second);
for(int i=0; i<sup->size(); i++)
if((*sup)[i] == NULL)
(*sup)[i] = new CGarrisonSlot(this, pos.x + (i*(w+interx)), pos.y,i,0,NULL, 0);
(*sup)[i] = new CGarrisonSlot(this, pos.x + (i*(w+interx)), pos.y,i,0,NULL);
if (shiftPos)
for (int i=shiftPos; i<sup->size(); i++)
@@ -504,14 +482,14 @@ void CGarrisonInt::createSlots()
if(set2)
{
sdown = new std::vector<CGarrisonSlot*>(7,(CGarrisonSlot *)(NULL));
for(TSlots::const_iterator i=set2->slots.begin(); i!=set2->slots.end(); i++)
for(TSlots::const_iterator i=set2->Slots().begin(); i!=set2->Slots().end(); i++)
{
(*sdown)[i->first] =
new CGarrisonSlot(this, pos.x + (i->first*(w+interx)) + garOffset.x, pos.y + garOffset.y,i->first,1, i->second.type,i->second.count);
new CGarrisonSlot(this, pos.x + (i->first*(w+interx)) + garOffset.x, pos.y + garOffset.y,i->first,1, &i->second);
}
for(int i=0; i<sdown->size(); i++)
if((*sdown)[i] == NULL)
(*sdown)[i] = new CGarrisonSlot(this, pos.x + (i*(w+interx)) + garOffset.x, pos.y + garOffset.y,i,1, NULL, 0);
(*sdown)[i] = new CGarrisonSlot(this, pos.x + (i*(w+interx)) + garOffset.x, pos.y + garOffset.y,i,1, NULL);
if (shiftPos)
for (int i=shiftPos; i<sup->size(); i++)
{
@@ -906,7 +884,7 @@ void SComponent::init(Etype Type, int Subtype, int Val)
subtitle = CGI->spellh->spells[Subtype].name;
break;
case creature:
subtitle = boost::lexical_cast<std::string>(Val) + " " + CGI->creh->creatures[Subtype].*(Val != 1 ? &CCreature::namePl : &CCreature::nameSing);
subtitle = boost::lexical_cast<std::string>(Val) + " " + CGI->creh->creatures[Subtype]->*(Val != 1 ? &CCreature::namePl : &CCreature::nameSing);
break;
case experience:
description = CGI->generaltexth->allTexts[241];
@@ -1835,7 +1813,7 @@ void CRecruitmentWindow::Max()
void CRecruitmentWindow::Buy()
{
int crid = creatures[which].ID,
dstslot = dst->army.getSlotFor(crid);
dstslot = dst-> getSlotFor(crid);
if(dstslot < 0) //no available slot
{
@@ -1843,7 +1821,7 @@ void CRecruitmentWindow::Buy()
if(dst->ID == HEROI_TYPE)
{
txt = CGI->generaltexth->allTexts[425]; //The %s would join your hero, but there aren't enough provisions to support them.
boost::algorithm::replace_first(txt, "%s", slider->value > 1 ? CGI->creh->creatures[crid].namePl : CGI->creh->creatures[crid].nameSing);
boost::algorithm::replace_first(txt, "%s", slider->value > 1 ? CGI->creh->creatures[crid]->namePl : CGI->creh->creatures[crid]->nameSing);
}
else
{
@@ -1908,7 +1886,7 @@ void CRecruitmentWindow::clickRight(tribool down, bool previousState)
const int sCREATURE_WIDTH = CREATURE_WIDTH; // gcc -O0 workaround
if(isItIn(&genRect(132,sCREATURE_WIDTH,pos.x+curx,pos.y+64),GH.current->motion.x,GH.current->motion.y))
{
CCreInfoWindow *popup = new CCreInfoWindow(creatures[i].ID, 0, 0, NULL, NULL, NULL, NULL);
CCreInfoWindow *popup = new CCreInfoWindow(creatures[i].ID, 0, 0);
GH.pushInt(popup);
break;
}
@@ -1952,7 +1930,7 @@ void CRecruitmentWindow::show(SDL_Surface * to)
printAtMiddle(pom,pos.x+205,pos.y+254,FONT_SMALL,zwykly,to);
SDL_itoa(slider->value,pom,10); //recruit
printAtMiddle(pom,pos.x+279,pos.y+254,FONT_SMALL,zwykly,to);
printAtMiddle(CGI->generaltexth->allTexts[16] + " " + CGI->creh->creatures[creatures[which].ID].namePl,pos.x+243,pos.y+32,FONT_BIG,tytulowy,to); //eg "Recruit Dragon flies"
printAtMiddle(CGI->generaltexth->allTexts[16] + " " + CGI->creh->creatures[creatures[which].ID]->namePl,pos.x+243,pos.y+32,FONT_BIG,tytulowy,to); //eg "Recruit Dragon flies"
int curx = pos.x+115-creatures[which].res.size()*16;
for(int i=0;i<creatures[which].res.size();i++)
@@ -2059,7 +2037,7 @@ void CRecruitmentWindow::initCres()
cur.amount = dwelling->creatures[i].first;
cur.ID = dwelling->creatures[i].second[j];
const CCreature *cre = &CGI->creh->creatures[cur.ID];
const CCreature *cre = CGI->creh->creatures[cur.ID];
cur.pic = new CCreaturePic(cre);
for(int k=0; k<cre->cost.size(); k++)
@@ -2105,11 +2083,11 @@ CSplitWindow::CSplitWindow(int cid, int max, CGarrisonInt *Owner, int Last, int
slider = new CSlider(pos.x+21,pos.y+194,257,boost::bind(&CSplitWindow::sliderMoved,this,_1),0,sliderPositions,val,true);
a1 = max-val;
a2 = val;
anim = new CCreaturePic(&CGI->creh->creatures[cid]);
anim = new CCreaturePic(CGI->creh->creatures[cid]);
anim->anim->setType(1);
std::string title = CGI->generaltexth->allTexts[256];
boost::algorithm::replace_first(title,"%s",CGI->creh->creatures[cid].namePl);
boost::algorithm::replace_first(title,"%s",CGI->creh->creatures[cid]->namePl);
printAtMiddle(title,150,34,FONT_BIG,tytulowy,bitmap);
}
@@ -2226,7 +2204,7 @@ void CSplitWindow::clickLeft(tribool down, bool previousState)
void CCreInfoWindow::show(SDL_Surface * to)
{
char pom[15];
blitAt(bitmap,pos.x,pos.y,to);
blitAt(*bitmap,pos.x,pos.y,to);
anim->blitPic(to,pos.x+21,pos.y+48,(type) && !(anf%4));
if(++anf==4)
anf=0;
@@ -2240,130 +2218,11 @@ void CCreInfoWindow::show(SDL_Surface * to)
ok->show(to);
}
CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState *State, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui)
CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui)
: type(Type), dsm(Dsm), dismiss(0), upgrade(0), ok(0)
{
//active = false;
anf = 0;
c = &CGI->creh->creatures[Cid];
SDL_Surface *hhlp = BitmapHandler::loadBitmap("CRSTKPU.bmp");
graphics->blueToPlayersAdv(hhlp,LOCPLINT->playerID);
bitmap = SDL_ConvertSurface(hhlp,screen->format,0);
SDL_SetColorKey(bitmap,SDL_SRCCOLORKEY,SDL_MapRGB(bitmap->format,0,255,255));
SDL_FreeSurface(hhlp);
pos.x = screen->w/2 - bitmap->w/2;
pos.y = screen->h/2 - bitmap->h/2;
pos.w = bitmap->w;
pos.h = bitmap->h;
anim = new CCreaturePic(c);
if(!type) anim->anim->setType(2);
char pom[75];int hlp=0;
if(creatureCount)
{
SDL_itoa(creatureCount,pom,10);
count = pom;
}
printAtMiddle(c->namePl,149,30,FONT_SMALL,tytulowy,bitmap); //creature name
//atttack
printAt(CGI->generaltexth->primarySkillNames[0],155,48,FONT_SMALL,zwykly,bitmap);
SDL_itoa(c->attack,pom,10);
if(State && State->attackBonus)
{
int hlp;
if(c->attack > 0)
hlp = log10f(c->attack)+2;
else
hlp = 2;
pom[hlp-1] = ' '; pom[hlp] = '(';
SDL_itoa(c->attack+State->attackBonus,pom+hlp+1,10);
hlp += 2+(int)log10f(State->attackBonus+c->attack);
pom[hlp] = ')'; pom[hlp+1] = '\0';
}
printTo(pom,276,61,FONT_SMALL,zwykly,bitmap);
//defense
printAt(CGI->generaltexth->primarySkillNames[1],155,67,FONT_SMALL,zwykly,bitmap);
SDL_itoa(c->defence,pom,10);
if(State && State->defenseBonus)
{
int hlp;
if(c->defence > 0)
hlp = log10f(c->defence)+2;
else
hlp = 2;
pom[hlp-1] = ' '; pom[hlp] = '(';
SDL_itoa(c->defence+State->defenseBonus,pom+hlp+1,10);
hlp += 2+(int)log10f(State->defenseBonus+c->defence);
pom[hlp] = ')'; pom[hlp+1] = '\0';
}
printTo(pom,276,80,FONT_SMALL,zwykly,bitmap);
//shots
if(c->shots)
{
printAt(CGI->generaltexth->allTexts[198], 155, 86, FONT_SMALL, zwykly, bitmap);
if(State && State->shotsLeft >= 0)
sprintf(pom,"%d (%d)", c->shots, State->shotsLeft);
else
SDL_itoa(c->shots, pom, 10);
printTo(pom, 276, 99, FONT_SMALL, zwykly, bitmap);
}
//damage
int dmgMin = c->damageMin * (State ? State->dmgMultiplier : 1);
int dmgMax = c->damageMax * (State ? State->dmgMultiplier : 1);
printAt(CGI->generaltexth->allTexts[199], 155, 105, FONT_SMALL, zwykly, bitmap);
SDL_itoa(dmgMin, pom, 10);
if(dmgMin > 0)
hlp = log10f(dmgMin) + 2;
else
hlp = 2;
pom[hlp-1]=' '; pom[hlp]='-'; pom[hlp+1]=' ';
SDL_itoa(dmgMax, pom+hlp+2, 10);
printTo(pom, 276, 118, FONT_SMALL, zwykly, bitmap);
//health
printAt(CGI->generaltexth->allTexts[388],155,124,FONT_SMALL,zwykly,bitmap);
if(State && State->healthBonus)
sprintf(pom,"%d (%d)",c->hitPoints, c->hitPoints + State->healthBonus);
else
SDL_itoa(c->hitPoints,pom,10);
printTo(pom,276,137,FONT_SMALL,zwykly,bitmap);
//remaining health
if(State && State->currentHealth)
{
printAt(CGI->generaltexth->allTexts[200],155,143,FONT_SMALL,zwykly,bitmap);
SDL_itoa(State->currentHealth,pom,10);
printTo(pom,276,156,FONT_SMALL,zwykly,bitmap);
}
//speed
printAt(CGI->generaltexth->zelp[441].first,155,162,FONT_SMALL,zwykly,bitmap);
SDL_itoa(c->speed,pom,10);
if(State && State->speedBonus)
{
int hlp;
if(c->speed > 0)
hlp = log10f(c->speed)+2;
else
hlp = 2;
pom[hlp-1] = ' '; pom[hlp] = '(';
SDL_itoa(c->speed + State->speedBonus, pom+hlp+1, 10);
hlp += 2+(int)log10f(c->speed + State->speedBonus);
pom[hlp] = ')'; pom[hlp+1] = '\0';
}
printTo(pom,276,175,FONT_SMALL,zwykly,bitmap);
//luck and morale
blitAt(graphics->morale42->ourImages[(State)?(State->morale+3):(3)].bitmap,24,189,bitmap);
blitAt(graphics->luck42->ourImages[(State)?(State->luck+3):(3)].bitmap,77,189,bitmap);
OBJ_CONSTRUCTION_CAPTURING_ALL;
init(st.type, &st, st.count);
//print abilities text - if r-click popup
if(type)
@@ -2373,9 +2232,9 @@ CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState
bool enough = true;
for(std::set<std::pair<int,int> >::iterator i=ui->cost[0].begin(); i!=ui->cost[0].end(); i++) //calculate upgrade cost
{
if(LOCPLINT->cb->getResourceAmount(i->first) < i->second*creatureCount)
if(LOCPLINT->cb->getResourceAmount(i->first) < i->second*st.count)
enough = false;
upgResCost.push_back(new SComponent(SComponent::resource,i->first,i->second*creatureCount));
upgResCost.push_back(new SComponent(SComponent::resource,i->first,i->second*st.count));
}
if(enough)
@@ -2385,11 +2244,11 @@ CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState
fs[0] += boost::bind(&CCreInfoWindow::close,this);
CFunctionList<void()> cfl;
cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[207],boost::ref(upgResCost),fs[0],fs[1],false);
upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,pos.x+76,pos.y+237,"IVIEWCR.DEF",SDLK_u);
upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,76,237,"IVIEWCR.DEF",SDLK_u);
}
else
{
upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,boost::function<void()>(),pos.x+76,pos.y+237,"IVIEWCR.DEF");
upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,boost::function<void()>(),76,237,"IVIEWCR.DEF");
upgrade->callback.funcs.clear();
upgrade->bitmapOffset = 2;
}
@@ -2403,53 +2262,124 @@ CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState
fs[0] += boost::bind(&CCreInfoWindow::close,this);//close this window
CFunctionList<void()> cfl;
cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],std::vector<SComponent*>(),fs[0],fs[1],false);
dismiss = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,pos.x+21,pos.y+237,"IVIEWCR2.DEF",SDLK_d);
dismiss = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,21,237,"IVIEWCR2.DEF",SDLK_d);
}
ok = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,boost::bind(&CCreInfoWindow::close,this),pos.x+216,pos.y+237,"IOKAY.DEF",SDLK_RETURN);
ok = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,boost::bind(&CCreInfoWindow::close,this),216,237,"IOKAY.DEF",SDLK_RETURN);
}
else
{
printAtWB(c->abilityText,17,231,FONT_SMALL,35,zwykly,bitmap);
printAtWB(c->abilityText,17,231,FONT_SMALL,35,zwykly,*bitmap);
}
//spell effects
if(State)
//if we are displying window fo r stack in battle, there are several more things that we need to display
if(const CStack *battleStack = dynamic_cast<const CStack*>(&st))
{
//spell effects
int printed=0; //how many effect pics have been printed
for(std::set<int>::const_iterator it = State->effects.begin(); it!=State->effects.end(); ++it)
BOOST_FOREACH(const CStack::StackEffect &effect, battleStack->effects)
{
blitAt(graphics->spellEffectsPics->ourImages[*it + 1].bitmap, 127 + 52 * printed, 186, bitmap);
blitAt(graphics->spellEffectsPics->ourImages[effect.id + 1].bitmap, 127 + 52 * printed, 186, *bitmap);
++printed;
if(printed >= 3)
{
if(printed >= 3) //we can fit only 3 effects
break;
}
}
//print current health
printLine(5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
}
}
void CCreInfoWindow::printLine(int nr, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
{
printAt(text, 155, 48 + nr*19, FONT_SMALL, zwykly, *bitmap);
std::string hlp;
if(range && baseVal != val)
hlp = boost::str(boost::format("%d - %d") % baseVal % val);
else if(baseVal != val && val>=0)
hlp = boost::str(boost::format("%d (%d)") % baseVal % val);
else
hlp = boost::lexical_cast<std::string>(baseVal);
printTo(hlp, 276, 61 + nr*19, FONT_SMALL, zwykly, *bitmap);
}
void CCreInfoWindow::init(const CCreature *cre, const CStackInstance *stack, int creatureCount)
{
const CBonusSystemNode *finalNode = NULL;
if(stack)
finalNode = stack;
else
finalNode = cre;
anf = 0;
c = cre;
bitmap = new CPicture("CRSTKPU.bmp");
graphics->blueToPlayersAdv(*bitmap, LOCPLINT->playerID);
bitmap->convertToScreenBPP();
pos = bitmap->center();
{
BLOCK_CAPTURING;
anim = new CCreaturePic(c);
}
if(!type) anim->anim->setType(2);
count = boost::lexical_cast<std::string>(creatureCount);
printAtMiddle(c->namePl,149,30,FONT_SMALL,tytulowy,*bitmap); //creature name
printLine(0, CGI->generaltexth->primarySkillNames[0], cre->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), finalNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK));
printLine(1, CGI->generaltexth->primarySkillNames[0], cre->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), finalNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE));
if(c->shots)
printLine(2, CGI->generaltexth->allTexts[198], c->shots);
//TODO
int dmgMultiply = 1;
if(stack && stack->hasBonusOfType(Bonus::SIEGE_WEAPON))
dmgMultiply += stack->armyObj->Attack();
printLine(3, CGI->generaltexth->allTexts[199], c->damageMin * dmgMultiply, c->damageMax * dmgMultiply, true);
printLine(4, CGI->generaltexth->allTexts[388], cre->valOfBonuses(Bonus::STACK_HEALTH), finalNode->valOfBonuses(Bonus::STACK_HEALTH));
printLine(6, CGI->generaltexth->zelp[441].first, cre->valOfBonuses(Bonus::STACKS_SPEED), finalNode->valOfBonuses(Bonus::STACKS_SPEED));
//luck and morale
int luck = 3, morale = 3;
if(stack)
{
//add modifiers
luck += stack->LuckVal();
morale += stack->MoraleVal();
}
blitAt(graphics->morale42->ourImages[morale].bitmap, 24, 189, *bitmap);
blitAt(graphics->luck42->ourImages[luck].bitmap, 77, 189, *bitmap);
}
CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
const CCreature *cre = CGI->creh->creatures[Cid];
init(cre, NULL, creatureCount);
}
CCreInfoWindow::~CCreInfoWindow()
{
SDL_FreeSurface(bitmap);
delete anim;
delete upgrade;
delete ok;
delete dismiss;
for(int i=0; i<upgResCost.size();i++)
delete upgResCost[i];
}
void CCreInfoWindow::activate()
{
//if(active) return;
//active = true;
CIntObject::activate();
if(!type)
activateRClick();
if(ok)
ok->activate();
if(dismiss)
dismiss->activate();
if(upgrade)
upgrade->activate();
}
void CCreInfoWindow::close()
@@ -2475,16 +2405,9 @@ void CCreInfoWindow::keyPressed (const SDL_KeyboardEvent & key)
void CCreInfoWindow::deactivate()
{
//if(!active) return;
//active = false;
if(!type)
deactivateRClick();
if(ok)
ok->deactivate();
if(dismiss)
dismiss->deactivate();
if(upgrade)
upgrade->deactivate();
CIntObject::deactivate();
}
void CLevelWindow::close()
@@ -4511,10 +4434,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]->getCurrentMorale()+3].bitmap, 177 + 490*b, 45, bg);
blitAt(graphics->morale30->ourImages[heroInst[b]->MoraleVal()+3].bitmap, 177 + 490*b, 45, bg);
//setting luck
blitAt(graphics->luck30->ourImages[heroInst[b]->getCurrentLuck()+3].bitmap, 213 + 490*b, 45, bg);
blitAt(graphics->luck30->ourImages[heroInst[b]->LuckVal()+3].bitmap, 213 + 490*b, 45, bg);
}
//printing portraits
@@ -5096,16 +5019,16 @@ CThievesGuildWindow::~CThievesGuildWindow()
void MoraleLuckBox::set( bool morale, const CGHeroInstance *hero, int slot /*= -1*/ )
void MoraleLuckBox::set(bool morale, const CGHeroInstance *hero)
{
int mrlv = -9, mrlt = -9;
std::vector<std::pair<int,std::string> > mrl;
TModDescr mrl;
if(morale)
{
//setting morale
mrl = hero->getCurrentMoraleModifiers(slot);
mrlv = hero->getCurrentMorale(slot);
hero->getModifiersWDescr(mrl, Bonus::MORALE);
mrlv = hero->MoraleVal();
mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad morale, 0 - neutral, 1 - good
hoverText = CGI->generaltexth->heroscrn[4 - mrlt];
baseType = SComponent::morale;
@@ -5121,8 +5044,8 @@ void MoraleLuckBox::set( bool morale, const CGHeroInstance *hero, int slot /*= -
else
{
//setting luck
mrl = hero->getCurrentLuckModifiers(slot);
mrlv = hero->getCurrentLuck(slot);
hero->getModifiersWDescr(mrl, Bonus::LUCK);
mrlv = hero->LuckVal();
mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad luck, 0 - neutral, 1 - good
hoverText = CGI->generaltexth->heroscrn[7 - mrlt];
baseType = SComponent::luck;

View File

@@ -64,6 +64,7 @@ class CArtifactsOfHero;
class CResDataBar;
struct SPuzzleInfo;
class CGGarrison;
class CStackInstance;
extern SDL_Color tytulowy, tlo, zwykly ;
@@ -199,7 +200,8 @@ class CGarrisonSlot : public CIntObject
{
public:
CGarrisonInt *owner;
const CCreature * creature; //creature in slot
const CStackInstance *myStack; //NULL if slot is empty
const CCreature *creature;
int count; //number of creatures
int upg; //0 - up garrison, 1 - down garrison
bool active; //TODO: comment me
@@ -211,7 +213,7 @@ public:
void activate();
void deactivate();
void show(SDL_Surface * to);
CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg=0, const CCreature * Creature=NULL, int Count=0);
CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg=0, const CStackInstance * Creature=NULL);
~CGarrisonSlot(); //d-tor
};
@@ -700,7 +702,7 @@ class MoraleLuckBox : public LRClickableAreaWTextComp
{
public:
void set(bool morale, const CGHeroInstance *hero, int slot = -1); //slot -1 means only hero modifiers
void set(bool morale, const CGHeroInstance *hero);
};
class LRClickableAreaOpenHero: public LRClickableAreaWTextComp
@@ -725,19 +727,22 @@ class CCreInfoWindow : public CIntObject
public:
//bool active; //TODO: comment me
int type;//0 - rclick popup; 1 - normal window
SDL_Surface *bitmap; //background
CPicture *bitmap; //background
char anf; //animation counter
std::string count; //creature count in text format
boost::function<void()> dsm; //dismiss button callback
CCreaturePic *anim; //related creature's animation
CCreature *c; //related creature
const CCreature *c; //related creature
std::vector<SComponent*> upgResCost; //cost of upgrade (if not possible then empty)
//MoraleLuckBox *luck, *morale;
AdventureMapButton *dismiss, *upgrade, *ok;
CCreInfoWindow(int Cid, int Type, int creatureCount, StackState *State, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui); //c-tor
CCreInfoWindow(const CStackInstance &st, int Type = 0, boost::function<void()> Upg = 0, boost::function<void()> Dsm = 0, UpgradeInfo *ui = NULL); //c-tor
CCreInfoWindow(int Cid, int Type, int creatureCount); //c-tor
void init(const CCreature *cre, const CStackInstance *stack, int creatureCount);
void printLine(int nr, const std::string &text, int baseVal, int val=-1, bool range=false);
~CCreInfoWindow(); //d-tor
void activate();
void close();

View File

@@ -51,7 +51,7 @@ SDL_Surface * Graphics::drawHeroInfoWin(const InfoAboutHero &curh)
blitAt(graphics->portraitLarge[curh.portrait],11,12,ret); //portrait
//army
for (TSlots::const_iterator i = curh.army.slots.begin(); i!=curh.army.slots.end();i++)
for (TSlots::const_iterator i = curh.army.Slots().begin(); i!=curh.army.Slots().end();i++)
{
blitAt(graphics->smallImgs[(*i).second.type->idNumber],slotsPos[(*i).first].first+1,slotsPos[(*i).first].second+1,ret);
if(curh.details)
@@ -108,7 +108,7 @@ SDL_Surface * Graphics::drawTownInfoWin( const InfoAboutTown & curh )
int pom = curh.fortLevel - 1; if(pom<0) pom = 3; //fort pic id
blitAt(forts->ourImages[pom].bitmap,115,42,ret); //fort
for (TSlots::const_iterator i=curh.army.slots.begin(); i!=curh.army.slots.end();i++)
for (TSlots::const_iterator i=curh.army.Slots().begin(); i!=curh.army.Slots().end();i++)
{
//if(!i->second.second)
// continue;

View File

@@ -314,11 +314,11 @@ void SetHeroArtifacts::applyCl( CClient *cl )
player->heroArtifactSetChanged(h);
BOOST_FOREACH(HeroBonus *bonus, gained)
BOOST_FOREACH(Bonus *bonus, gained)
{
player->heroBonusChanged(h,*bonus,true);
}
BOOST_FOREACH(HeroBonus *bonus, lost)
BOOST_FOREACH(Bonus *bonus, lost)
{
player->heroBonusChanged(h,*bonus,false);
}
@@ -427,13 +427,13 @@ void BattleStart::applyCl( CClient *cl )
def = NULL;
new CBattleInterface(&info->army1, &info->army2, info->heroes[0], info->heroes[1], genRect(600, 800, (conf.cc.resx - 800)/2, (conf.cc.resy - 600)/2), att, def);
new CBattleInterface(info->belligerents[0], info->belligerents[1], info->heroes[0], info->heroes[1], genRect(600, 800, (conf.cc.resx - 800)/2, (conf.cc.resy - 600)/2), att, def);
if(vstd::contains(cl->playerint,info->side1))
cl->playerint[info->side1]->battleStart(&info->army1, &info->army2, info->tile, info->heroes[0], info->heroes[1], 0);
cl->playerint[info->side1]->battleStart(info->belligerents[0], info->belligerents[1], info->tile, info->heroes[0], info->heroes[1], 0);
if(vstd::contains(cl->playerint,info->side2))
cl->playerint[info->side2]->battleStart(&info->army1, &info->army2, info->tile, info->heroes[0], info->heroes[1], 1);
cl->playerint[info->side2]->battleStart(info->belligerents[0], info->belligerents[1], info->tile, info->heroes[0], info->heroes[1], 1);
}
void BattleNextRound::applyCl( CClient *cl )
@@ -448,7 +448,7 @@ void BattleSetActiveStack::applyCl( CClient *cl )
{
CStack * activated = GS(cl)->curB->getStack(stack);
int playerToCall = -1; //player that will move activated stack
if( activated->hasFeatureOfType(StackFeature::HYPNOTIZED) )
if( activated->hasBonusOfType(Bonus::HYPNOTIZED) )
{
playerToCall = ( GS(cl)->curB->side1 == activated->owner ? GS(cl)->curB->side2 : GS(cl)->curB->side1 );
}

View File

@@ -297,7 +297,6 @@ void delNull(T* &ptr) //deleted pointer and sets it to NULL
ptr = NULL;
}
#include "lib/CCreatureSet.h"
#include "CConsoleHandler.h"
extern DLL_EXPORT std::ostream *logfile;
extern DLL_EXPORT CConsoleHandler *console;

View File

@@ -318,21 +318,21 @@ void CArtHandler::sortArts()
}
}
void CArtHandler::giveArtBonus( int aid, HeroBonus::BonusType type, int val, int subtype )
void CArtHandler::giveArtBonus( int aid, Bonus::BonusType type, int val, int subtype, int valType )
{
artifacts[aid].bonuses.push_back(HeroBonus(HeroBonus::PERMANENT,type,HeroBonus::ARTIFACT,val,aid,subtype));
if(type == HeroBonus::MORALE || HeroBonus::LUCK || HeroBonus::MORALE_AND_LUCK)
artifacts[aid].bonuses.back().description = "\n" + artifacts[aid].Name() + (val > 0 ? " +" : " ")
+ boost::lexical_cast<std::string>(val);
Bonus added(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);
added.valType = valType;
if(type == Bonus::MORALE || Bonus::LUCK)
added.description = "\n" + artifacts[aid].Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
artifacts[aid].bonuses.push_back(added);
}
void CArtHandler::addBonuses()
{
#define ART_PRIM_SKILL(ID, whichSkill, val) giveArtBonus(ID,HeroBonus::PRIMARY_SKILL,val,whichSkill)
#define ART_MORALE(ID, val) giveArtBonus(ID,HeroBonus::MORALE,val)
#define ART_LUCK(ID, val) giveArtBonus(ID,HeroBonus::LUCK,val)
#define ART_MORALE_AND_LUCK(ID, val) giveArtBonus(ID,HeroBonus::MORALE_AND_LUCK,val)
#define ART_PRIM_SKILL(ID, whichSkill, val) giveArtBonus(ID,Bonus::PRIMARY_SKILL,val,whichSkill)
#define ART_MORALE(ID, val) giveArtBonus(ID,Bonus::MORALE,val)
#define ART_LUCK(ID, val) giveArtBonus(ID,Bonus::LUCK,val)
#define ART_MORALE_AND_LUCK(ID, val) giveArtBonus(ID,Bonus::MORALE_AND_LUCK,val)
#define ART_ALL_PRIM_SKILLS(ID, val) ART_PRIM_SKILL(ID,0,val); ART_PRIM_SKILL(ID,1,val); ART_PRIM_SKILL(ID,2,val); ART_PRIM_SKILL(ID,3,val)
#define ART_ATTACK_AND_DEFENSE(ID, val) ART_PRIM_SKILL(ID,0,val); ART_PRIM_SKILL(ID,1,val)
#define ART_POWER_AND_KNOWLEDGE(ID, val) ART_PRIM_SKILL(ID,2,val); ART_PRIM_SKILL(ID,3,val)
@@ -400,185 +400,187 @@ void CArtHandler::addBonuses()
ART_LUCK(47,+1); //Cards of Prophecy
ART_LUCK(48,+1); //Ladybird of Luck
ART_MORALE(49,+1); //Badge of Courage -> +1 morale and immunity to hostile mind spells:
giveArtBonus(49,HeroBonus::SPELL_IMMUNITY,50);//sorrow
giveArtBonus(49,HeroBonus::SPELL_IMMUNITY,59);//berserk
giveArtBonus(49,HeroBonus::SPELL_IMMUNITY,60);//hypnotize
giveArtBonus(49,HeroBonus::SPELL_IMMUNITY,61);//forgetfulness
giveArtBonus(49,HeroBonus::SPELL_IMMUNITY,62);//blind
giveArtBonus(49,Bonus::SPELL_IMMUNITY,50);//sorrow
giveArtBonus(49,Bonus::SPELL_IMMUNITY,59);//berserk
giveArtBonus(49,Bonus::SPELL_IMMUNITY,60);//hypnotize
giveArtBonus(49,Bonus::SPELL_IMMUNITY,61);//forgetfulness
giveArtBonus(49,Bonus::SPELL_IMMUNITY,62);//blind
ART_MORALE(50,+1); //Crest of Valor
ART_MORALE(51,+1); //Glyph of Gallantry
giveArtBonus(52,HeroBonus::SIGHT_RADIOUS,+1);//Speculum
giveArtBonus(53,HeroBonus::SIGHT_RADIOUS,+1);//Spyglass
giveArtBonus(52,Bonus::SIGHT_RADIOUS,+1);//Speculum
giveArtBonus(53,Bonus::SIGHT_RADIOUS,+1);//Spyglass
//necromancy bonus
giveArtBonus(54,HeroBonus::SECONDARY_SKILL_PREMY,+5,12);//Amulet of the Undertaker
giveArtBonus(55,HeroBonus::SECONDARY_SKILL_PREMY,+10,12);//Vampire's Cowl
giveArtBonus(56,HeroBonus::SECONDARY_SKILL_PREMY,+15,12);//Dead Man's Boots
giveArtBonus(54,Bonus::SECONDARY_SKILL_PREMY,+5,12);//Amulet of the Undertaker
giveArtBonus(55,Bonus::SECONDARY_SKILL_PREMY,+10,12);//Vampire's Cowl
giveArtBonus(56,Bonus::SECONDARY_SKILL_PREMY,+15,12);//Dead Man's Boots
giveArtBonus(57,HeroBonus::MAGIC_RESISTANCE,+5);//Garniture of Interference
giveArtBonus(58,HeroBonus::MAGIC_RESISTANCE,+10);//Surcoat of Counterpoise
giveArtBonus(59,HeroBonus::MAGIC_RESISTANCE,+15);//Boots of Polarity
giveArtBonus(57,Bonus::MAGIC_RESISTANCE,+5);//Garniture of Interference
giveArtBonus(58,Bonus::MAGIC_RESISTANCE,+10);//Surcoat of Counterpoise
giveArtBonus(59,Bonus::MAGIC_RESISTANCE,+15);//Boots of Polarity
//archery bonus
giveArtBonus(60,HeroBonus::SECONDARY_SKILL_PREMY,+5,1);//Bow of Elven Cherrywood
giveArtBonus(61,HeroBonus::SECONDARY_SKILL_PREMY,+10,1);//Bowstring of the Unicorn's Mane
giveArtBonus(62,HeroBonus::SECONDARY_SKILL_PREMY,+15,1);//Angel Feather Arrows
giveArtBonus(60,Bonus::SECONDARY_SKILL_PREMY,+5,1);//Bow of Elven Cherrywood
giveArtBonus(61,Bonus::SECONDARY_SKILL_PREMY,+10,1);//Bowstring of the Unicorn's Mane
giveArtBonus(62,Bonus::SECONDARY_SKILL_PREMY,+15,1);//Angel Feather Arrows
//eagle eye bonus
giveArtBonus(63,HeroBonus::SECONDARY_SKILL_PREMY,+5,11);//Bird of Perception
giveArtBonus(64,HeroBonus::SECONDARY_SKILL_PREMY,+10,11);//Stoic Watchman
giveArtBonus(65,HeroBonus::SECONDARY_SKILL_PREMY,+15,11);//Emblem of Cognizance
giveArtBonus(63,Bonus::SECONDARY_SKILL_PREMY,+5,11);//Bird of Perception
giveArtBonus(64,Bonus::SECONDARY_SKILL_PREMY,+10,11);//Stoic Watchman
giveArtBonus(65,Bonus::SECONDARY_SKILL_PREMY,+15,11);//Emblem of Cognizance
//reducing cost of surrendering
giveArtBonus(66,HeroBonus::SURRENDER_DISCOUNT,+10);//Statesman's Medal
giveArtBonus(67,HeroBonus::SURRENDER_DISCOUNT,+10);//Diplomat's Ring
giveArtBonus(68,HeroBonus::SURRENDER_DISCOUNT,+10);//Ambassador's Sash
giveArtBonus(66,Bonus::SURRENDER_DISCOUNT,+10);//Statesman's Medal
giveArtBonus(67,Bonus::SURRENDER_DISCOUNT,+10);//Diplomat's Ring
giveArtBonus(68,Bonus::SURRENDER_DISCOUNT,+10);//Ambassador's Sash
giveArtBonus(69,HeroBonus::STACKS_SPEED,+1);//Ring of the Wayfarer
giveArtBonus(69,Bonus::STACKS_SPEED,+1);//Ring of the Wayfarer
giveArtBonus(70,HeroBonus::LAND_MOVEMENT,+300);//Equestrian's Gloves
giveArtBonus(71,HeroBonus::SEA_MOVEMENT,+1000);//Necklace of Ocean Guidance
giveArtBonus(72,HeroBonus::FLYING_MOVEMENT,+1);//Angel Wings
giveArtBonus(70,Bonus::LAND_MOVEMENT,+300);//Equestrian's Gloves
giveArtBonus(71,Bonus::SEA_MOVEMENT,+1000);//Necklace of Ocean Guidance
giveArtBonus(72,Bonus::FLYING_MOVEMENT,+1);//Angel Wings
giveArtBonus(73,HeroBonus::MANA_REGENERATION,+1);//Charm of Mana
giveArtBonus(74,HeroBonus::MANA_REGENERATION,+2);//Talisman of Mana
giveArtBonus(75,HeroBonus::MANA_REGENERATION,+3);//Mystic Orb of Mana
giveArtBonus(73,Bonus::MANA_REGENERATION,+1);//Charm of Mana
giveArtBonus(74,Bonus::MANA_REGENERATION,+2);//Talisman of Mana
giveArtBonus(75,Bonus::MANA_REGENERATION,+3);//Mystic Orb of Mana
giveArtBonus(76,HeroBonus::SPELL_DURATION,+1);//Collar of Conjuring
giveArtBonus(77,HeroBonus::SPELL_DURATION,+2);//Ring of Conjuring
giveArtBonus(78,HeroBonus::SPELL_DURATION,+3);//Cape of Conjuring
giveArtBonus(76,Bonus::SPELL_DURATION,+1);//Collar of Conjuring
giveArtBonus(77,Bonus::SPELL_DURATION,+2);//Ring of Conjuring
giveArtBonus(78,Bonus::SPELL_DURATION,+3);//Cape of Conjuring
giveArtBonus(79,HeroBonus::AIR_SPELL_DMG_PREMY,+50);//Orb of the Firmament
giveArtBonus(80,HeroBonus::EARTH_SPELL_DMG_PREMY,+50);//Orb of Silt
giveArtBonus(81,HeroBonus::FIRE_SPELL_DMG_PREMY,+50);//Orb of Tempestuous Fire
giveArtBonus(82,HeroBonus::WATER_SPELL_DMG_PREMY,+50);//Orb of Driving Rain
giveArtBonus(79,Bonus::AIR_SPELL_DMG_PREMY,+50);//Orb of the Firmament
giveArtBonus(80,Bonus::EARTH_SPELL_DMG_PREMY,+50);//Orb of Silt
giveArtBonus(81,Bonus::FIRE_SPELL_DMG_PREMY,+50);//Orb of Tempestuous Fire
giveArtBonus(82,Bonus::WATER_SPELL_DMG_PREMY,+50);//Orb of Driving Rain
giveArtBonus(83,HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL,3);//Recanter's Cloak
giveArtBonus(84,HeroBonus::BLOCK_MORALE,0);//Spirit of Oppression
giveArtBonus(85,HeroBonus::BLOCK_LUCK,0);//Hourglass of the Evil Hour
giveArtBonus(83,Bonus::BLOCK_SPELLS_ABOVE_LEVEL,3);//Recanter's Cloak
giveArtBonus(84,Bonus::BLOCK_MORALE,0);//Spirit of Oppression
giveArtBonus(85,Bonus::BLOCK_LUCK,0);//Hourglass of the Evil Hour
giveArtBonus(86,HeroBonus::FIRE_SPELLS,0);//Tome of Fire Magic
giveArtBonus(87,HeroBonus::AIR_SPELLS,0);//Tome of Air Magic
giveArtBonus(88,HeroBonus::WATER_SPELLS,0);//Tome of Water Magic
giveArtBonus(89,HeroBonus::EARTH_SPELLS,0);//Tome of Earth Magic
giveArtBonus(86,Bonus::FIRE_SPELLS,0);//Tome of Fire Magic
giveArtBonus(87,Bonus::AIR_SPELLS,0);//Tome of Air Magic
giveArtBonus(88,Bonus::WATER_SPELLS,0);//Tome of Water Magic
giveArtBonus(89,Bonus::EARTH_SPELLS,0);//Tome of Earth Magic
giveArtBonus(90,HeroBonus::WATER_WALKING,0);//Boots of Levitation
giveArtBonus(91,HeroBonus::NO_SHOTING_PENALTY,0);//Golden Bow
giveArtBonus(92,HeroBonus::SPELL_IMMUNITY,35);//Sphere of Permanence
giveArtBonus(93,HeroBonus::NEGATE_ALL_NATURAL_IMMUNITIES,0);//Orb of Vulnerability
giveArtBonus(90,Bonus::WATER_WALKING,0);//Boots of Levitation
giveArtBonus(91,Bonus::NO_SHOTING_PENALTY,0);//Golden Bow
giveArtBonus(92,Bonus::SPELL_IMMUNITY,35);//Sphere of Permanence
giveArtBonus(93,Bonus::NEGATE_ALL_NATURAL_IMMUNITIES,0);//Orb of Vulnerability
giveArtBonus(94,HeroBonus::STACK_HEALTH,+1);//Ring of Vitality
giveArtBonus(95,HeroBonus::STACK_HEALTH,+1);//Ring of Life
giveArtBonus(96,HeroBonus::STACK_HEALTH,+2);//Vial of Lifeblood
giveArtBonus(94,Bonus::STACK_HEALTH,+1);//Ring of Vitality
giveArtBonus(95,Bonus::STACK_HEALTH,+1);//Ring of Life
giveArtBonus(96,Bonus::STACK_HEALTH,+2);//Vial of Lifeblood
giveArtBonus(97,HeroBonus::STACKS_SPEED,+1);//Necklace of Swiftness
giveArtBonus(98,HeroBonus::LAND_MOVEMENT,+600);//Boots of Speed
giveArtBonus(99,HeroBonus::STACKS_SPEED,+2);//Cape of Velocity
giveArtBonus(97,Bonus::STACKS_SPEED,+1);//Necklace of Swiftness
giveArtBonus(98,Bonus::LAND_MOVEMENT,+600);//Boots of Speed
giveArtBonus(99,Bonus::STACKS_SPEED,+2);//Cape of Velocity
giveArtBonus(100,HeroBonus::SPELL_IMMUNITY,59);//Pendant of Dispassion
giveArtBonus(101,HeroBonus::SPELL_IMMUNITY,62);//Pendant of Second Sight
giveArtBonus(102,HeroBonus::SPELL_IMMUNITY,42);//Pendant of Holiness
giveArtBonus(103,HeroBonus::SPELL_IMMUNITY,24);//Pendant of Life
giveArtBonus(104,HeroBonus::SPELL_IMMUNITY,25);//Pendant of Death
giveArtBonus(105,HeroBonus::SPELL_IMMUNITY,60);//Pendant of Free Will
giveArtBonus(106,HeroBonus::SPELL_IMMUNITY,17);//Pendant of Negativity
giveArtBonus(107,HeroBonus::SPELL_IMMUNITY,61);//Pendant of Total Recall
giveArtBonus(108,HeroBonus::MORALE_AND_LUCK,+3);//Pendant of Courage
giveArtBonus(100,Bonus::SPELL_IMMUNITY,59);//Pendant of Dispassion
giveArtBonus(101,Bonus::SPELL_IMMUNITY,62);//Pendant of Second Sight
giveArtBonus(102,Bonus::SPELL_IMMUNITY,42);//Pendant of Holiness
giveArtBonus(103,Bonus::SPELL_IMMUNITY,24);//Pendant of Life
giveArtBonus(104,Bonus::SPELL_IMMUNITY,25);//Pendant of Death
giveArtBonus(105,Bonus::SPELL_IMMUNITY,60);//Pendant of Free Will
giveArtBonus(106,Bonus::SPELL_IMMUNITY,17);//Pendant of Negativity
giveArtBonus(107,Bonus::SPELL_IMMUNITY,61);//Pendant of Total Recall
giveArtBonus(108,Bonus::MORALE,+3);//Pendant of Courage
giveArtBonus(108,Bonus::LUCK,+3);//Pendant of Courage
giveArtBonus(109,HeroBonus::GENERATE_RESOURCE,+1,4); //Everflowing Crystal Cloak
giveArtBonus(110,HeroBonus::GENERATE_RESOURCE,+1,5); //Ring of Infinite Gems
giveArtBonus(111,HeroBonus::GENERATE_RESOURCE,+1,1); //Everpouring Vial of Mercury
giveArtBonus(112,HeroBonus::GENERATE_RESOURCE,+1,2); //Inexhaustible Cart of Ore
giveArtBonus(113,HeroBonus::GENERATE_RESOURCE,+1,3); //Eversmoking Ring of Sulfur
giveArtBonus(114,HeroBonus::GENERATE_RESOURCE,+1,0); //Inexhaustible Cart of Lumber
giveArtBonus(115,HeroBonus::GENERATE_RESOURCE,+1000,6); //Endless Sack of Gold
giveArtBonus(116,HeroBonus::GENERATE_RESOURCE,+750,6); //Endless Bag of Gold
giveArtBonus(117,HeroBonus::GENERATE_RESOURCE,+500,6); //Endless Purse of Gold
giveArtBonus(109,Bonus::GENERATE_RESOURCE,+1,4); //Everflowing Crystal Cloak
giveArtBonus(110,Bonus::GENERATE_RESOURCE,+1,5); //Ring of Infinite Gems
giveArtBonus(111,Bonus::GENERATE_RESOURCE,+1,1); //Everpouring Vial of Mercury
giveArtBonus(112,Bonus::GENERATE_RESOURCE,+1,2); //Inexhaustible Cart of Ore
giveArtBonus(113,Bonus::GENERATE_RESOURCE,+1,3); //Eversmoking Ring of Sulfur
giveArtBonus(114,Bonus::GENERATE_RESOURCE,+1,0); //Inexhaustible Cart of Lumber
giveArtBonus(115,Bonus::GENERATE_RESOURCE,+1000,6); //Endless Sack of Gold
giveArtBonus(116,Bonus::GENERATE_RESOURCE,+750,6); //Endless Bag of Gold
giveArtBonus(117,Bonus::GENERATE_RESOURCE,+500,6); //Endless Purse of Gold
giveArtBonus(118,HeroBonus::CREATURE_GROWTH,+5,1); //Legs of Legion
giveArtBonus(119,HeroBonus::CREATURE_GROWTH,+4,2); //Loins of Legion
giveArtBonus(120,HeroBonus::CREATURE_GROWTH,+3,3); //Torso of Legion
giveArtBonus(121,HeroBonus::CREATURE_GROWTH,+2,4); //Arms of Legion
giveArtBonus(122,HeroBonus::CREATURE_GROWTH,+1,5); //Head of Legion
giveArtBonus(118,Bonus::CREATURE_GROWTH,+5,1); //Legs of Legion
giveArtBonus(119,Bonus::CREATURE_GROWTH,+4,2); //Loins of Legion
giveArtBonus(120,Bonus::CREATURE_GROWTH,+3,3); //Torso of Legion
giveArtBonus(121,Bonus::CREATURE_GROWTH,+2,4); //Arms of Legion
giveArtBonus(122,Bonus::CREATURE_GROWTH,+1,5); //Head of Legion
//Sea Captain's Hat
giveArtBonus(123,HeroBonus::WHIRLPOOL_PROTECTION,0);
giveArtBonus(123,HeroBonus::SEA_MOVEMENT,+500);
giveArtBonus(123,HeroBonus::SPELL,3,0);
giveArtBonus(123,HeroBonus::SPELL,3,1);
giveArtBonus(123,Bonus::WHIRLPOOL_PROTECTION,0);
giveArtBonus(123,Bonus::SEA_MOVEMENT,+500);
giveArtBonus(123,Bonus::SPELL,3,0);
giveArtBonus(123,Bonus::SPELL,3,1);
giveArtBonus(124,HeroBonus::SPELLS_OF_LEVEL,3,1); //Spellbinder's Hat
giveArtBonus(125,HeroBonus::ENEMY_CANT_ESCAPE,0); //Shackles of War
giveArtBonus(126,HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL,0);//Orb of Inhibition
giveArtBonus(124,Bonus::SPELLS_OF_LEVEL,3,1); //Spellbinder's Hat
giveArtBonus(125,Bonus::ENEMY_CANT_ESCAPE,0); //Shackles of War
giveArtBonus(126,Bonus::BLOCK_SPELLS_ABOVE_LEVEL,0);//Orb of Inhibition
//Armageddon's Blade
giveArtBonus(128, HeroBonus::SPELL, 3, 26);
giveArtBonus(128, HeroBonus::SPELL_IMMUNITY, 26);
giveArtBonus(128, Bonus::SPELL, 3, 26);
giveArtBonus(128, Bonus::SPELL_IMMUNITY, 26);
ART_ATTACK_AND_DEFENSE(128, +3);
ART_PRIM_SKILL(128, 2, +3);
ART_PRIM_SKILL(128, 3, +6);
//Angelic Alliance
ART_ALL_PRIM_SKILLS(129, +21);
giveArtBonus(129, HeroBonus::NONEVIL_ALIGNMENT_MIX, 0);
giveArtBonus(129, HeroBonus::OPENING_BATTLE_SPELL, 10, 29); // Prayer
giveArtBonus(129, Bonus::NONEVIL_ALIGNMENT_MIX, 0);
giveArtBonus(129, Bonus::OPENING_BATTLE_SPELL, 10, 29); // Prayer
//Cloak of the Undead King
giveArtBonus(130, HeroBonus::SECONDARY_SKILL_PREMY, +30, 12);
giveArtBonus(130, HeroBonus::SECONDARY_SKILL_PREMY, +30, 12);
giveArtBonus(130, HeroBonus::IMPROVED_NECROMANCY, 0);
giveArtBonus(130, Bonus::SECONDARY_SKILL_PREMY, +30, 12);
giveArtBonus(130, Bonus::SECONDARY_SKILL_PREMY, +30, 12);
giveArtBonus(130, Bonus::IMPROVED_NECROMANCY, 0);
//Elixir of Life
giveArtBonus(131, HeroBonus::STACK_HEALTH, +4);
giveArtBonus(131, HeroBonus::STACK_HEALTH_PERCENT, +25);
giveArtBonus(131, HeroBonus::HP_REGENERATION, +50);
giveArtBonus(131, Bonus::STACK_HEALTH, +4);
giveArtBonus(131, Bonus::STACK_HEALTH, +25, -1, Bonus::PERCENT_TO_BASE);
giveArtBonus(131, Bonus::HP_REGENERATION, +50);
//Armor of the Damned
ART_ATTACK_AND_DEFENSE(132, +3);
ART_POWER_AND_KNOWLEDGE(132, +2);
giveArtBonus(132, HeroBonus::OPENING_BATTLE_SPELL, 50, 54); // Slow
giveArtBonus(132, HeroBonus::OPENING_BATTLE_SPELL, 50, 47); // Disrupting Ray
giveArtBonus(132, HeroBonus::OPENING_BATTLE_SPELL, 50, 45); // Weakness
giveArtBonus(132, HeroBonus::OPENING_BATTLE_SPELL, 50, 52); // Misfortune
giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 54); // Slow
giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 47); // Disrupting Ray
giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 45); // Weakness
giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 52); // Misfortune
// Statue of Legion - gives only 50% growth
giveArtBonus(133, HeroBonus::CREATURE_GROWTH_PERCENT, 50);
giveArtBonus(133, Bonus::CREATURE_GROWTH_PERCENT, 50);
//Power of the Dragon Father
ART_ALL_PRIM_SKILLS(134, +16);
giveArtBonus(134, HeroBonus::MORALE_AND_LUCK, +1);
giveArtBonus(134, HeroBonus::LEVEL_SPELL_IMMUNITY, 4);
giveArtBonus(134, Bonus::MORALE, +1);
giveArtBonus(134, Bonus::LUCK, +1);
giveArtBonus(134, Bonus::LEVEL_SPELL_IMMUNITY, 4);
//Titan's Thunder
// should also add a permanent spell book, somehow.
ART_ATTACK_AND_DEFENSE(135, +9);
ART_POWER_AND_KNOWLEDGE(135, +8);
giveArtBonus(135, HeroBonus::SPELL, 3, 57);
giveArtBonus(135, Bonus::SPELL, 3, 57);
//Admiral's Hat
giveArtBonus(136, HeroBonus::SEA_MOVEMENT, +1500);
giveArtBonus(136, HeroBonus::WHIRLPOOL_PROTECTION, 0);
giveArtBonus(136, HeroBonus::SPELL, 3, 0);
giveArtBonus(136, HeroBonus::SPELL, 3, 1);
giveArtBonus(136, HeroBonus::FREE_SHIP_BOARDING, 0);
giveArtBonus(136, Bonus::SEA_MOVEMENT, +1500);
giveArtBonus(136, Bonus::WHIRLPOOL_PROTECTION, 0);
giveArtBonus(136, Bonus::SPELL, 3, 0);
giveArtBonus(136, Bonus::SPELL, 3, 1);
giveArtBonus(136, Bonus::FREE_SHIP_BOARDING, 0);
//Bow of the Sharpshooter
giveArtBonus(137, HeroBonus::SECONDARY_SKILL_PREMY, +30, 1);
giveArtBonus(137, HeroBonus::NO_SHOTING_PENALTY, 0);
giveArtBonus(137, HeroBonus::FREE_SHOOTING, 0);
giveArtBonus(137, Bonus::SECONDARY_SKILL_PREMY, +30, 1);
giveArtBonus(137, Bonus::NO_SHOTING_PENALTY, 0);
giveArtBonus(137, Bonus::FREE_SHOOTING, 0);
//Wizard's Well
giveArtBonus(138, HeroBonus::FULL_MANA_REGENERATION, 0);
giveArtBonus(138, Bonus::FULL_MANA_REGENERATION, 0);
//Ring of the Magi
giveArtBonus(139, HeroBonus::SPELL_DURATION, +56);
giveArtBonus(139, Bonus::SPELL_DURATION, +56);
//Cornucopia
giveArtBonus(140, HeroBonus::GENERATE_RESOURCE, +5, 1);
giveArtBonus(140, HeroBonus::GENERATE_RESOURCE, +5, 3);
giveArtBonus(140, HeroBonus::GENERATE_RESOURCE, +5, 4);
giveArtBonus(140, HeroBonus::GENERATE_RESOURCE, +5, 5);
giveArtBonus(140, Bonus::GENERATE_RESOURCE, +5, 1);
giveArtBonus(140, Bonus::GENERATE_RESOURCE, +5, 3);
giveArtBonus(140, Bonus::GENERATE_RESOURCE, +5, 4);
giveArtBonus(140, Bonus::GENERATE_RESOURCE, +5, 5);
}
void CArtHandler::clear()

View File

@@ -35,7 +35,7 @@ public:
std::vector<ui32> * constituentOf; // Reverse map of constituents.
EartClass aClass;
ui32 id;
std::list<HeroBonus> bonuses; //bonuses given by artifact
std::list<Bonus> bonuses; //bonuses given by artifact
template <typename Handler> void serialize(Handler &h, const int version)
{
@@ -45,7 +45,7 @@ public:
class DLL_EXPORT CArtHandler //handles artifacts
{
void giveArtBonus(int aid, HeroBonus::BonusType type, int val, int subtype = -1);
void giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype = -1, int valType = Bonus::BASE_NUMBER);
public:
std::vector<CArtifact*> treasures, minors, majors, relics;
std::vector<CArtifact> artifacts;

View File

@@ -5,6 +5,7 @@
#include <sstream>
#include <boost/assign/std/set.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/assign/std/list.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/find.hpp>
@@ -70,22 +71,22 @@ int CCreature::getQuantityID(const int & quantity)
bool CCreature::isDoubleWide() const
{
return vstd::contains(abilities, StackFeature::DOUBLE_WIDE);
return doubleWide;
}
bool CCreature::isFlying() const
{
return vstd::contains(abilities, StackFeature::FLYING);
return vstd::contains(bonuses, Bonus::FLYING);
}
bool CCreature::isShooting() const
{
return vstd::contains(abilities, StackFeature::SHOOTER);
return vstd::contains(bonuses, Bonus::SHOOTER);
}
bool CCreature::isUndead() const
{
return vstd::contains(abilities, StackFeature::UNDEAD);
return vstd::contains(bonuses, Bonus::UNDEAD);
}
/**
@@ -116,6 +117,17 @@ si32 CCreature::maxAmount(const std::vector<si32> &res) const //how many creatur
return ret;
}
CCreature::CCreature()
{
doubleWide = false;
}
void CCreature::addBonus(int val, int type, int subtype /*= -1*/)
{
Bonus added(Bonus::PERMANENT, type, Bonus::CREATURE_ABILITY, val, idNumber, subtype, Bonus::BASE_NUMBER);
bonuses.push_back(added);
}
int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo()
{
befi=i;
@@ -199,7 +211,8 @@ void CCreatureHandler::loadCreatures()
while(i<buf.size())
{
CCreature ncre;
CCreature &ncre = *new CCreature;
ncre.idNumber = creatures.size();
ncre.cost.resize(RESOURCE_QUANTITY);
ncre.level=0;
@@ -229,12 +242,18 @@ void CCreatureHandler::loadCreatures()
ncre.AIValue = readNumber(befi, i, andame, buf);
ncre.growth = readNumber(befi, i, andame, buf);
ncre.hordeGrowth = readNumber(befi, i, andame, buf);
ncre.hitPoints = readNumber(befi, i, andame, buf);
ncre.addBonus(ncre.hitPoints, Bonus::STACK_HEALTH);
ncre.speed = readNumber(befi, i, andame, buf);
ncre.addBonus(ncre.speed, Bonus::STACKS_SPEED);
ncre.attack = readNumber(befi, i, andame, buf);
ncre.addBonus(ncre.attack, Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
ncre.defence = readNumber(befi, i, andame, buf);
ncre.addBonus(ncre.defence, Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
ncre.damageMin = readNumber(befi, i, andame, buf);
ncre.damageMax = readNumber(befi, i, andame, buf);
ncre.shots = readNumber(befi, i, andame, buf);
ncre.spells = readNumber(befi, i, andame, buf);
ncre.ammMin = readNumber(befi, i, andame, buf);
@@ -260,64 +279,69 @@ void CCreatureHandler::loadCreatures()
if(useCreAbilsFromZCRTRAIT)
{ //adding abilities from ZCRTRAIT.TXT
if(boost::algorithm::find_first(ncre.abilityRefs, "DOUBLE_WIDE"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::DOUBLE_WIDE, 0));
ncre.doubleWide = true;
if(boost::algorithm::find_first(ncre.abilityRefs, "FLYING_ARMY"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::FLYING, 0));
ncre.addBonus(0, Bonus::FLYING);
if(boost::algorithm::find_first(ncre.abilityRefs, "SHOOTING_ARMY"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::SHOOTER, 0));
ncre.addBonus(0, Bonus::SHOOTER);
if(boost::algorithm::find_first(ncre.abilityRefs, "SIEGE_WEAPON"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::SIEGE_WEAPON, 0));
ncre.addBonus(0, Bonus::SIEGE_WEAPON);
if(boost::algorithm::find_first(ncre.abilityRefs, "const_two_attacks"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::ADDITIONAL_ATTACK, 1));
ncre.addBonus(1, Bonus::ADDITIONAL_ATTACK);
if(boost::algorithm::find_first(ncre.abilityRefs, "const_free_attack"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::BLOCKS_RETALIATION, 0));
ncre.addBonus(0, Bonus::BLOCKS_RETALIATION);
if(boost::algorithm::find_first(ncre.abilityRefs, "IS_UNDEAD"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::UNDEAD, 0));
ncre.addBonus(0, Bonus::UNDEAD);
if(boost::algorithm::find_first(ncre.abilityRefs, "const_no_melee_penalty"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::NO_MELEE_PENALTY, 0));
ncre.addBonus(0, Bonus::NO_MELEE_PENALTY);
if(boost::algorithm::find_first(ncre.abilityRefs, "const_jousting"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::JOUSTING, 0));
ncre.addBonus(0, Bonus::JOUSTING);
if(boost::algorithm::find_first(ncre.abilityRefs, "const_raises_morale"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::RAISING_MORALE, 1));
{
ncre.addBonus(+1, Bonus::MORALE);;
ncre.bonuses.back().effectRange = Bonus::ONLY_ALLIED_ARMY;
}
if(boost::algorithm::find_first(ncre.abilityRefs, "const_lowers_morale"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::ENEMY_MORALE_DECREASING, 1));
{
ncre.addBonus(-1, Bonus::MORALE);;
ncre.bonuses.back().effectRange = Bonus::ONLY_ENEMY_ARMY;
}
if(boost::algorithm::find_first(ncre.abilityRefs, "KING_1"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::KING1, 0));
ncre.addBonus(0, Bonus::KING1);
if(boost::algorithm::find_first(ncre.abilityRefs, "KING_2"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::KING2, 0));
ncre.addBonus(0, Bonus::KING2);
if(boost::algorithm::find_first(ncre.abilityRefs, "KING_3"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::KING3, 0));
ncre.addBonus(0, Bonus::KING3);
if(boost::algorithm::find_first(ncre.abilityRefs, "const_no_wall_penalty"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::NO_WALL_PENALTY, 0));
ncre.addBonus(0, Bonus::NO_WALL_PENALTY);
if(boost::algorithm::find_first(ncre.abilityRefs, "CATAPULT"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::CATAPULT, 0));
ncre.addBonus(0, Bonus::CATAPULT);
if(boost::algorithm::find_first(ncre.abilityRefs, "MULTI_HEADED"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::ATTACKS_ALL_ADJACENT, 0));
ncre.addBonus(0, Bonus::ATTACKS_ALL_ADJACENT);
if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_MIND_SPELLS"))
{
std::vector<int> mindSpells = getMindSpells();
for(int g=0; g<mindSpells.size(); ++g)
{
creatures[40].abilities += makeCreatureAbility(StackFeature::SPELL_IMMUNITY, 0, mindSpells[g]); //giants are immune to mind spells
}
ncre.addBonus(0, Bonus::SPELL_IMMUNITY, mindSpells[g]); //giants are immune to mind spells
}
if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_FIRE_SPELLS"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::FIRE_IMMUNITY, 0));
ncre.addBonus(0, Bonus::FIRE_IMMUNITY);
if(boost::algorithm::find_first(ncre.abilityRefs, "HAS_EXTENDED_ATTACK"))
ncre.abilities.push_back(makeCreatureAbility(StackFeature::TWO_HEX_ATTACK_BREATH, 0));
ncre.addBonus(0, Bonus::TWO_HEX_ATTACK_BREATH);;
}
if(ncre.nameSing!=std::string("") && ncre.namePl!=std::string(""))
{
ncre.idNumber = creatures.size();
creatures.push_back(ncre);
creatures.push_back(&ncre);
}
}
// Map types names
#define VCMI_CREATURE_ABILITY_NAME(x) ( #x, StackFeature::x )
static const std::map<std::string, int> type_list = map_list_of VCMI_CREATURE_ABILITY_LIST;
#undef VCMI_CREATURE_ABILITY_NAME
#define BONUS_NAME(x) ( #x, Bonus::x )
static const std::map<std::string, int> type_list = map_list_of BONUS_LIST;
#undef BONUS_NAME
////second part of reading cr_abils.txt////
bool contReading = true;
@@ -332,28 +356,45 @@ void CCreatureHandler::loadCreatures()
case '+': //add new ability
{
int creatureID;
StackFeature nsf;
Bonus nsf;
si32 buf;
std::string type;
reader >> creatureID;
reader >> type;
std::map<std::string, int>::const_iterator it = type_list.find(type);
if (it == type_list.end()) {
tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl;
CCreature *cre = creatures[creatureID];
if (it == type_list.end())
{
if(type == "DOUBLE_WIDE")
cre->doubleWide = true;
else if(type == "ENEMY_MORALE_DECREASING")
{
cre->addBonus(-1, Bonus::MORALE);;
cre->bonuses.back().effectRange = Bonus::ONLY_ENEMY_ARMY;
}
else if(type == "ENEMY_LUCK_DECREASING")
{
cre->addBonus(-1, Bonus::LUCK);;
cre->bonuses.back().effectRange = Bonus::ONLY_ENEMY_ARMY;
}
else
tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl;
break;
}
nsf.type = it->second;
reader >> buf; nsf.value = buf;
reader >> buf; nsf.val = buf;
reader >> buf; nsf.subtype = buf;
reader >> buf; nsf.additionalInfo = buf;
nsf.source = StackFeature::CREATURE_ABILITY;
nsf.duration = StackFeature::WHOLE_BATTLE;
nsf.source = Bonus::CREATURE_ABILITY;
nsf.id = cre->idNumber;
nsf.duration = Bonus::ONE_BATTLE;
nsf.turnsRemain = 0;
creatures[creatureID].abilities += nsf;
cre->bonuses += nsf;
break;
}
case '-': //remove ability
@@ -365,14 +406,17 @@ void CCreatureHandler::loadCreatures()
std::map<std::string, int>::const_iterator it = type_list.find(type);
if (it == type_list.end())
{
tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl;
if(type == "DOUBLE_WIDE")
creatures[creatureID]->doubleWide = false;
else
tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl;
break;
}
int typeNo = it->second;
StackFeature::ECombatFeatures ecf = static_cast<StackFeature::ECombatFeatures>(typeNo);
Bonus::BonusType ecf = static_cast<Bonus::BonusType>(typeNo);
creatures[creatureID].abilities -= ecf;
creatures[creatureID]->bonuses -= ecf;
break;
}
case '0': //end reading
@@ -401,7 +445,7 @@ void CCreatureHandler::loadCreatures()
if (tempi>=creatures.size())
break;
boost::assign::insert(nameToID)(temps,tempi);
creatures[tempi].nameRef=temps;
creatures[tempi]->nameRef=temps;
}
ifs.close();
ifs.clear();
@@ -417,8 +461,8 @@ void CCreatureHandler::loadCreatures()
ifs >> id >> lvl;
if(lvl>0)
{
creatures[id].level = lvl;
levelCreatures[lvl].push_back(&(creatures[id]));
creatures[id]->level = lvl;
levelCreatures[lvl].push_back(creatures[id]);
}
}
}
@@ -431,7 +475,7 @@ void CCreatureHandler::loadCreatures()
{
int id, fact;
ifs >> id >> fact;
creatures[id].faction = fact;
creatures[id]->faction = fact;
}
ifs.close();
ifs.clear();
@@ -442,7 +486,7 @@ void CCreatureHandler::loadCreatures()
{
int id, up;
ifs >> id >> up;
creatures[id].upgrades.insert(up);
creatures[id]->upgrades.insert(up);
}
ifs.close();
ifs.clear();
@@ -489,7 +533,7 @@ void CCreatureHandler::loadCreatures()
break;
}
std::string defName = buf.substr(befi, i-befi);
creatures[s].animDefName = defName;
creatures[s]->animDefName = defName;
}
tlog5 << "\t\tReading CRANIM.TXT.txt" << std::endl;
loadAnimationInfo();
@@ -546,7 +590,7 @@ void CCreatureHandler::loadAnimationInfo()
for(int dd=0; dd<creatures.size(); ++dd)
{
//tlog5 << "\t\t\tReading animation info for creature " << dd << std::endl;
loadUnitAnimInfo(creatures[dd], buf, i);
loadUnitAnimInfo(*creatures[dd], buf, i);
}
return;
}

View File

@@ -7,7 +7,7 @@
#include <set>
#include "CSoundBase.h"
#include "../lib/StackFeature.h"
#include "../lib/HeroBonus.h"
/*
* CCreatureHandler.h, part of VCMI engine
@@ -20,14 +20,16 @@
*/
class CLodHandler;
class CCreatureHandler;
class DLL_EXPORT CCreature
class DLL_EXPORT CCreature : public CBonusSystemNode
{
ui32 hitPoints, speed, attack, defence;
public:
std::string namePl, nameSing, nameRef; //name in singular and plural form; and reference name
std::vector<ui32> cost; //cost[res_id] - amount of that resource
std::set<ui32> upgrades; // IDs of creatures to which this creature can be upgraded
ui32 fightValue, AIValue, growth, hordeGrowth, hitPoints, speed, attack, defence, shots, spells;
ui32 fightValue, AIValue, growth, hordeGrowth, shots, spells;
ui32 damageMin, damageMax;
ui32 ammMin, ammMax;
ui8 level; // 0 - unknown
@@ -35,8 +37,8 @@ public:
std::string abilityRefs; //references to abilities, in textformat
std::string animDefName;
ui32 idNumber;
std::vector<StackFeature> abilities;
si8 faction; //-1 = neutral
ui8 doubleWide;
///animation info
float timeBetweenFidgets, walkAnimationTime, attackAnimationTime, flightAnimationDistance;
@@ -54,6 +56,8 @@ public:
si32 maxAmount(const std::vector<si32> &res) const; //how many creatures can be bought
static int getQuantityID(const int & quantity); //0 - a few, 1 - several, 2 - pack, 3 - lots, 4 - horde, 5 - throng, 6 - swarm, 7 - zounds, 8 - legion
void addBonus(int val, int type, int subtype = -1);
template<typename RanGen>
int getRandomAmount(RanGen &ranGen)
{
@@ -65,12 +69,13 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CBonusSystemNode&>(*this);
h & namePl & nameSing & nameRef
& cost & upgrades
& fightValue & AIValue & growth & hordeGrowth & hitPoints & speed & attack & defence & shots & spells
& damageMin & damageMax & ammMin & ammMax & level
& abilityText & abilityRefs & animDefName
& idNumber & abilities & faction
& idNumber & faction
& timeBetweenFidgets & walkAnimationTime & attackAnimationTime & flightAnimationDistance
& upperRightMissleOffsetX & rightMissleOffsetX & lowerRightMissleOffsetX & upperRightMissleOffsetY & rightMissleOffsetY & lowerRightMissleOffsetY
@@ -82,6 +87,10 @@ public:
h & snd;
}
}
CCreature();
friend CCreatureHandler;
};
@@ -89,7 +98,7 @@ class DLL_EXPORT CCreatureHandler
{
public:
std::set<int> notUsedMonsters;
std::vector<CCreature> creatures; //creature ID -> creature info
std::vector<CCreature*> creatures; //creature ID -> creature info
std::map<int,std::vector<CCreature*> > levelCreatures; //level -> list of creatures
std::map<std::string,int> nameToID;
std::map<int,std::string> idToProjectile;
@@ -111,14 +120,7 @@ public:
{
//TODO: should be optimized, not all these informations needs to be serialized (same for ccreature)
h & notUsedMonsters & creatures & nameToID & idToProjectile & idToProjectileSpin & factionToTurretCreature;
if(!h.saving)
{
for (int i=0; i<creatures.size(); i++) //recreate levelCreatures map
{
levelCreatures[creatures[i].level].push_back(&creatures[i]);
}
}
h & levelCreatures;
}
};

View File

@@ -148,7 +148,7 @@ soundBase::soundID CSoundHandler::getSoundID(std::string &fileName)
return it->second;
}
void CSoundHandler::initCreaturesSounds(std::vector<CCreature> &creatures)
void CSoundHandler::initCreaturesSounds(std::vector<CCreature*> &creatures)
{
tlog5 << "\t\tReading config/cr_sounds.txt" << std::endl;
std::ifstream ifs(DATA_DIR "/config/cr_sounds.txt");

View File

@@ -5,6 +5,7 @@
#include "CSoundBase.h"
#include "CMusicBase.h"
#include "CCreatureHandler.h"
/*
@@ -79,7 +80,7 @@ public:
void init();
void release();
void initCreaturesSounds(std::vector<CCreature> &creatures);
void initCreaturesSounds(std::vector<CCreature*> &creatures);
void initSpellsSounds(std::vector<CSpell> &spells);
void setVolume(unsigned int percent);

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,7 @@
#include "CTownHandler.h"
#include "../lib/VCMI_Lib.h"
#endif
#include "../lib/CCreatureSet.h"
/*
* CObjectHandler.h, part of VCMI engine
@@ -24,6 +25,7 @@
*
*/
class BattleInfo;
class IGameCallback;
struct BattleResult;
class CCPPObjectScript;
@@ -46,6 +48,7 @@ struct Component;
struct BankConfig;
class CGBoat;
class DLL_EXPORT CCastleEvent
{
public:
@@ -141,7 +144,7 @@ class DLL_EXPORT CGObjectInstance : public IObjectInterface
{
protected:
void getNameVis(std::string &hname) const;
void giveDummyBonus(int heroID, ui8 duration = HeroBonus::ONE_DAY) const;
void giveDummyBonus(int heroID, ui8 duration = Bonus::ONE_DAY) const;
public:
mutable std::string hoverName;
int3 pos; //h3m pos
@@ -216,23 +219,31 @@ public:
}
};
class DLL_EXPORT CArmedInstance: public CGObjectInstance
class DLL_EXPORT CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet
{
public:
CCreatureSet army; //army
virtual bool needsLastStack() const; //true if last stack cannot be taken
int getArmyStrength() const; //sum of AI values of creatures
ui64 getPower (TSlot slot) const; //value of specific stack
std::string getRoughAmount (TSlot slot) const; //rought size of specific stack
BattleInfo *battle; //set to the current battle, if engaged
void setArmy(const CCreatureSet &src);
CCreatureSet getArmy() const;
void randomizeArmy(int type);
//////////////////////////////////////////////////////////////////////////
void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const;
void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
//////////////////////////////////////////////////////////////////////////
CArmedInstance();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
h & army;
h & static_cast<CBonusSystemNode&>(*this);
h & static_cast<CCreatureSet&>(*this);
}
};
class DLL_EXPORT CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CBonusSystemNode
class DLL_EXPORT CGHeroInstance : public CArmedInstance, public IBoatGenerator
{
public:
//////////////////////////////////////////////////////////////////////////
@@ -251,7 +262,6 @@ public:
std::string biography; //if custom
si32 portrait; //may be custom
si32 mana; // remaining spell points
std::vector<si32> primSkills; //0-attack, 1-defence, 2-spell power, 3-knowledge
std::vector<std::pair<ui8,ui8> > secSkills; //first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert); if hero has ability (-1, -1) it meansthat it should have default secondary abilities
si32 movement; //remaining movement points
ui8 sex;
@@ -280,7 +290,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this);
h & exp & level & name & biography & portrait & mana & primSkills & secSkills & movement
h & exp & level & name & biography & portrait & mana & secSkills & movement
& sex & inTownGarrison & artifacts & artifWorn & spells & patrol & bonuses
& moveDir;
@@ -288,11 +298,11 @@ public:
//visitied town pointer will be restored by map serialization method
}
//////////////////////////////////////////////////////////////////////////
void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const;
void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
//////////////////////////////////////////////////////////////////////////
int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
int getSightRadious() const; //sight distance (should be used if player-owned structure)
//////////////////////////////////////////////////////////////////////////
int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
@@ -311,12 +321,9 @@ public:
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
void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const;
std::vector<std::pair<int,std::string> > getCurrentLuckModifiers(int stack=-1, bool town=false) const; //args as above
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
std::vector<std::pair<int,std::string> > getCurrentMoraleModifiers(int stack=-1, bool town=false) const; //args as above
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(const int & ID) const; //0 - no skill
int maxMovePoints(bool onLand) const;
@@ -342,6 +349,7 @@ public:
void recreateArtBonuses();
void giveArtifact (ui32 aid);
void initHeroDefInfo();
void pushPrimSkill(int which, int val);
CGHeroInstance();
virtual ~CGHeroInstance();
@@ -472,7 +480,9 @@ public:
h & town;
//garrison/visiting hero pointers will be restored in the map serialization
}
//////////////////////////////////////////////////////////////////////////
void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const;
void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
//////////////////////////////////////////////////////////////////////////
ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used
@@ -541,7 +551,7 @@ public:
{
h & static_cast<CArmedInstance&>(*this);
h & message & gainedExp & manaDiff & moraleDiff & luckDiff & resources & primskills
& abilities & abilityLevels & artifacts & spells & creatures & army;
& abilities & abilityLevels & artifacts & spells & creatures;
}
};
@@ -558,7 +568,7 @@ public:
h & static_cast<CArmedInstance&>(*this);
h & message & gainedExp & manaDiff & moraleDiff & luckDiff & resources & primskills
& abilities & abilityLevels & artifacts & spells & creatures & availableFor
& computerActivate & humanActivate & army;
& computerActivate & humanActivate;
}
void onHeroVisit(const CGHeroInstance * h) const;

View File

@@ -3,6 +3,10 @@
#include "../hch/CCreatureHandler.h"
#include "VCMI_Lib.h"
#include <assert.h>
#include "../hch/CObjectHandler.h"
#include "IGameCallback.h"
#include "CGameState.h"
#include "../hch/CGeneralTextHandler.h"
const CStackInstance CCreatureSet::operator[](TSlot slot) const
{
@@ -28,7 +32,7 @@ bool CCreatureSet::setCreature(TSlot slot, TCreature type, TQuantity quantity) /
if (quantity == 0)
slots.erase(slot);
if (slots.size() > 7)
if (slots.size() > ARMY_SIZE)
return false;
else
return true;
@@ -62,12 +66,12 @@ int CCreatureSet::getAmount(TSlot slot) const
return 0; //TODO? consider issuing a warning
}
bool CCreatureSet::mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable /*= -1*/) /*looks for two same stacks, returns slot positions */
bool CCreatureSet::mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable /*= -1*/) const /*looks for two same stacks, returns slot positions */
{
//try to match creature to our preferred stack
if(preferable >= 0 && vstd::contains(slots, preferable))
{
const CCreature *cr = slots[preferable].type;
const CCreature *cr = slots.find(preferable)->second.type;
for(TSlots::const_iterator j=slots.begin(); j!=slots.end(); ++j)
{
if(cr == j->second.type && j->first != preferable)
@@ -107,18 +111,24 @@ void CCreatureSet::sweep()
}
}
void CCreatureSet::addToSlot(TSlot slot, TCreature cre, TQuantity count)
void CCreatureSet::addToSlot(TSlot slot, TCreature cre, TQuantity count, bool allowMerging/* = true*/)
{
assert(slot >= 0);
const CCreature *c = &VLC->creh->creatures[cre];
assert(!vstd::contains(slots, slot) || slots[slot].type == c); //that slot was empty or contained same type creature
const CCreature *c = VLC->creh->creatures[cre];
assert(!vstd::contains(slots, slot) || slots[slot].type == c && allowMerging); //that slot was empty or contained same type creature
slots[slot].type = c;
slots[slot].count += count;
//TODO
const CArmedInstance *armedObj = dynamic_cast<const CArmedInstance *>(this);
if(armedObj && !slots[slot].armyObj)
slots[slot].armyObj = armedObj;
}
void CCreatureSet::addToSlot(TSlot slot, const CStackInstance &stack)
void CCreatureSet::addToSlot(TSlot slot, const CStackInstance &stack, bool allowMerging/* = true*/)
{
addToSlot(slot, stack.type->idNumber, stack.count);
assert(stack.type == VLC->creh->creatures[stack.type->idNumber]);
addToSlot(slot, stack.type->idNumber, stack.count, allowMerging );
}
bool CCreatureSet::validTypes(bool allowUnrandomized /*= false*/) const
@@ -129,7 +139,7 @@ bool CCreatureSet::validTypes(bool allowUnrandomized /*= false*/) const
if(!isRand)
{
assert(i->second.type);
assert(i->second.type == &VLC->creh->creatures[i->second.type->idNumber]);
assert(i->second.type == VLC->creh->creatures[i->second.type->idNumber]);
}
else
assert(allowUnrandomized);
@@ -137,16 +147,94 @@ bool CCreatureSet::validTypes(bool allowUnrandomized /*= false*/) const
return true;
}
bool CCreatureSet::slotEmpty(TSlot slot) const
{
return !vstd::contains(slots, slot);
}
bool CCreatureSet::needsLastStack() const
{
return false;
}
int CCreatureSet::getArmyStrength() const
{
int ret = 0;
for(TSlots::const_iterator i = slots.begin(); i != slots.end(); i++)
ret += i->second.type->AIValue * i->second.count;
return ret;
}
ui64 CCreatureSet::getPower (TSlot slot) const
{
return getCreature(slot)->AIValue * getAmount(slot);
}
std::string CCreatureSet::getRoughAmount (TSlot slot) const
{
return VLC->generaltexth->arraytxt[174 + 3*CCreature::getQuantityID(getAmount(slot))];
}
int CCreatureSet::stacksCount() const
{
return slots.size();
}
void CCreatureSet::addStack(TSlot slot, const CStackInstance &stack)
{
addToSlot(slot, stack, false);
}
void CCreatureSet::setFormation(bool tight)
{
formation = tight;
}
void CCreatureSet::setStackCount(TSlot slot, TQuantity count)
{
assert(vstd::contains(slots, slot));
slots[slot].count = count;
}
void CCreatureSet::clear()
{
slots.clear();
}
const CStackInstance& CCreatureSet::getStack(TSlot slot) const
{
assert(vstd::contains(slots, slot));
return slots.find(slot)->second;
}
void CCreatureSet::eraseStack(TSlot slot)
{
assert(vstd::contains(slots, slot));
slots.erase(slot);
}
bool CCreatureSet::contains(const CStackInstance *stack) const
{
if(!stack)
return false;
for(TSlots::const_iterator i = slots.begin(); i != slots.end(); ++i)
if(&i->second == stack)
return true;
return false;
}
CStackInstance::CStackInstance()
{
init();
}
CStackInstance::CStackInstance(TCreature id, TQuantity Count)
CStackInstance::CStackInstance(TCreature id, TQuantity Count, const CArmedInstance *ArmyObj)
{
init();
setType(id);
count = Count;
armyObj = ArmyObj;
}
CStackInstance::CStackInstance(const CCreature *cre, TQuantity Count)
@@ -162,6 +250,7 @@ void CStackInstance::init()
count = 0;
type = NULL;
idRand = -1;
armyObj = NULL;
}
int CStackInstance::getQuantityID() const
@@ -171,5 +260,18 @@ int CStackInstance::getQuantityID() const
void CStackInstance::setType(int creID)
{
type = &VLC->creh->creatures[creID];
type = VLC->creh->creatures[creID];
}
void CStackInstance::getParents(TCNodes &out, const CBonusSystemNode *source /*= NULL*/) const
{
out.insert(type);
if(source && source != this) //we should be root, if not - do not inherit anything
return;
if(armyObj)
out.insert(armyObj);
else
out.insert(&IObjectInterface::cb->gameState()->globalEffects);
}

View File

@@ -3,20 +3,26 @@
#include "../global.h"
#include <map>
#include "HeroBonus.h"
class CCreature;
class CGHeroInstance;
class CArmedInstance;
//a few typedefs for CCreatureSet
typedef si32 TSlot;
typedef si32 TQuantity;
typedef ui32 TCreature; //creature id
const int ARMY_SIZE = 7;
class DLL_EXPORT CStackInstance
class DLL_EXPORT CStackInstance : public CBonusSystemNode
{
public:
int idRand; //hlp variable used during loading game -> "id" placeholder for randomization
const CArmedInstance *armyObj; //stack must be part of some army, army must be part of some object
const CCreature *type;
TQuantity count;
ui32 experience; //TODO: handle
@@ -24,13 +30,17 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h/* & owner*/ & type & count & experience;
h & static_cast<CBonusSystemNode&>(*this);
h & armyObj & type & count & experience;
}
//overrides CBonusSystemNode
void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const; //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker
int getQuantityID() const;
void init();
CStackInstance();
CStackInstance(TCreature id, TQuantity count);
CStackInstance(TCreature id, TQuantity count, const CArmedInstance *ArmyObj = NULL);
CStackInstance(const CCreature *cre, TQuantity count);
void setType(int creID);
};
@@ -38,6 +48,8 @@ public:
typedef std::map<TSlot, CStackInstance> TSlots;
class DLL_EXPORT CCreatureSet //seven combined creatures
{
public:
@@ -46,15 +58,31 @@ public:
const CStackInstance operator[](TSlot slot) const;
void addToSlot(TSlot slot, TCreature cre, TQuantity count); //Adds stack to slot. Slot must be empty or with same type creature
void addToSlot(TSlot slot, const CStackInstance &stack); //Adds stack to slot. Slot must be empty or with same type creature
const TSlots &Slots() const {return slots;}
void addToSlot(TSlot slot, TCreature cre, TQuantity count, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature
void addToSlot(TSlot slot, const CStackInstance &stack, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature
void addStack(TSlot slot, const CStackInstance &stack); //adds new stack to the army, slot must be empty
bool setCreature (TSlot slot, TCreature type, TQuantity quantity); //slots 0 to 6, if quantity=0, erases stack
void clear();
void setFormation(bool tight);
void setStackCount(TSlot slot, TQuantity count); //stack must exist!
void eraseStack(TSlot slot);
const CStackInstance& getStack(TSlot slot) const;
const CCreature* getCreature(TSlot slot) const; //workaround of map issue;
int getAmount (TSlot slot) const;
bool setCreature (TSlot slot, TCreature type, TQuantity quantity); //slots 0 to 6
TSlot getSlotFor(TCreature creature, ui32 slotsAmount=7) const; //returns -1 if no slot available
bool mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable = -1); //looks for two same stacks, returns slot positions;
TSlot getSlotFor(TCreature creature, ui32 slotsAmount=ARMY_SIZE) const; //returns -1 if no slot available
bool mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable = -1) const; //looks for two same stacks, returns slot positions;
bool validTypes(bool allowUnrandomized = false) const; //checks if all types of creatures are set properly
bool slotEmpty(TSlot slot) const;
int stacksCount() const;
virtual bool needsLastStack() const; //true if last stack cannot be taken
int getArmyStrength() const; //sum of AI values of creatures
ui64 getPower (TSlot slot) const; //value of specific stack
std::string getRoughAmount (TSlot slot) const; //rought size of specific stack
bool contains(const CStackInstance *stack) const;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@@ -166,7 +166,7 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst
}
else if(type == CRE_PL_NAMES)
{
dst = VLC->creh->creatures[ser].namePl;
dst = VLC->creh->creatures[ser]->namePl;
}
else if(type == MINE_NAMES)
{
@@ -182,7 +182,7 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst
}
else if(type == CRE_SING_NAMES)
{
dst = VLC->creh->creatures[ser].nameSing;
dst = VLC->creh->creatures[ser]->nameSing;
}
else if(type == ART_DESCR)
{
@@ -394,8 +394,8 @@ CStack * BattleInfo::getStackT(int tileID, bool onlyAlive)
for(unsigned int g=0; g<stacks.size(); ++g)
{
if(stacks[g]->position == tileID
|| (stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && stacks[g]->attackerOwned && stacks[g]->position-1 == tileID)
|| (stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && !stacks[g]->attackerOwned && stacks[g]->position+1 == tileID))
|| (stacks[g]->doubleWide() && stacks[g]->attackerOwned && stacks[g]->position-1 == tileID)
|| (stacks[g]->doubleWide() && !stacks[g]->attackerOwned && stacks[g]->position+1 == tileID))
{
if(!onlyAlive || stacks[g]->alive())
{
@@ -428,7 +428,7 @@ void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool atta
continue;
accessibility[stacks[g]->position] = false;
if(stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE)) //if it's a double hex creature
if(stacks[g]->doubleWide()) //if it's a double hex creature
{
if(stacks[g]->attackerOwned)
accessibility[stacks[g]->position-1] = false;
@@ -561,12 +561,12 @@ std::vector<int> BattleInfo::getAccessibility(int stackID, bool addOccupiable) c
std::set<int> occupyable;
getAccessibilityMap(ac, s->hasFeatureOfType(StackFeature::DOUBLE_WIDE), s->attackerOwned, addOccupiable, occupyable, s->hasFeatureOfType(StackFeature::FLYING), stackID);
getAccessibilityMap(ac, s->doubleWide(), s->attackerOwned, addOccupiable, occupyable, s->hasBonusOfType(Bonus::FLYING), stackID);
int pr[BFIELD_SIZE], dist[BFIELD_SIZE];
makeBFS(s->position, ac, pr, dist, s->hasFeatureOfType(StackFeature::DOUBLE_WIDE), s->attackerOwned, s->hasFeatureOfType(StackFeature::FLYING), false);
makeBFS(s->position, ac, pr, dist, s->doubleWide(), s->attackerOwned, s->hasBonusOfType(Bonus::FLYING), false);
if(s->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
if(s->doubleWide())
{
if(!addOccupiable)
{
@@ -597,7 +597,7 @@ std::vector<int> BattleInfo::getAccessibility(int stackID, bool addOccupiable) c
for (int i=0; i < BFIELD_SIZE ; ++i) {
if(
( ( !addOccupiable && dist[i] <= s->Speed() && ac[i] ) || ( addOccupiable && dist[i] <= s->Speed() && isAccessible(i, ac, s->hasFeatureOfType(StackFeature::DOUBLE_WIDE), s->attackerOwned, s->hasFeatureOfType(StackFeature::FLYING), true) ) )//we can reach it
( ( !addOccupiable && dist[i] <= s->Speed() && ac[i] ) || ( addOccupiable && dist[i] <= s->Speed() && isAccessible(i, ac, s->doubleWide(), s->attackerOwned, s->hasBonusOfType(Bonus::FLYING), true) ) )//we can reach it
|| (vstd::contains(occupyable, i) && ( dist[ i + (s->attackerOwned ? 1 : -1 ) ] <= s->Speed() ) &&
ac[i + (s->attackerOwned ? 1 : -1 )] ) //it's occupyable and we can reach adjacent hex
)
@@ -611,7 +611,7 @@ std::vector<int> BattleInfo::getAccessibility(int stackID, bool addOccupiable) c
bool BattleInfo::isStackBlocked(int ID)
{
CStack *our = getStack(ID);
if(our->hasFeatureOfType(StackFeature::SIEGE_WEAPON)) //siege weapons cannot be blocked
if(our->hasBonusOfType(Bonus::SIEGE_WEAPON)) //siege weapons cannot be blocked
return false;
for(unsigned int i=0; i<stacks.size();i++)
@@ -620,7 +620,7 @@ bool BattleInfo::isStackBlocked(int ID)
|| stacks[i]->owner==our->owner
)
continue; //we omit dead and allied stacks
if(stacks[i]->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
if(stacks[i]->doubleWide())
{
if( mutualPosition(stacks[i]->position, our->position) >= 0
|| mutualPosition(stacks[i]->position + (stacks[i]->attackerOwned ? -1 : 1), our->position) >= 0)
@@ -689,72 +689,32 @@ std::pair< std::vector<int>, int > BattleInfo::getPath(int start, int dest, bool
return std::make_pair(path, dist[dest]);
}
int CStack::valOfFeatures(StackFeature::ECombatFeatures type, int subtype, int turn) const
CStack::CStack(const CStackInstance *base, int O, int I, bool AO, int S)
: CStackInstance(*base), ID(I), owner(O), slot(S), attackerOwned(AO), position(-1),
counterAttacks(1)
{
int ret = 0;
if(subtype == -1024) //any subtype
{
for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++)
if(i->type == type && (!turn || i->turnsRemain > turn))
ret += i->value;
}
else //given subtype
{
for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++)
if(i->type == type && i->subtype == subtype && (!turn || i->turnsRemain > turn))
ret += i->value;
}
return ret;
}
baseAmount = base->count;
firstHPleft = valOfBonuses(Bonus::STACK_HEALTH);
shots = type->shots;
counterAttacks += valOfBonuses(Bonus::ADDITIONAL_RETALIATION);
bool CStack::hasFeatureOfType(StackFeature::ECombatFeatures type, int subtype, int turn) const
{
if(subtype == -1024) //any subtype
{
for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++)
if(i->type == type && (!turn || i->turnsRemain > turn))
return true;
}
else //given subtype
{
for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++)
if(i->type == type && i->subtype == subtype && (!turn || i->turnsRemain > turn))
return true;
}
return false;
}
CStack::CStack(CCreature * C, int A, int O, int I, bool AO, int S)
:ID(I), creature(C), amount(A), baseAmount(A), firstHPleft(C->hitPoints), owner(O), slot(S), attackerOwned(AO), position(-1),
counterAttacks(1), shots(C->shots), features(C->abilities)
{
//additional retaliations
for(int h=0; h<C->abilities.size(); ++h)
{
if(C->abilities[h].type == StackFeature::ADDITIONAL_RETALIATION)
{
counterAttacks += C->abilities[h].value;
}
}
//alive state indication
state.insert(ALIVE);
}
ui32 CStack::Speed( int turn /*= 0*/ ) const
{
if(hasFeatureOfType(StackFeature::SIEGE_WEAPON, -1024, turn)) //war machnes cannot move
if(hasBonus(Selector::type(Bonus::SIEGE_WEAPON) && Selector::turns(turn))) //war machines cannot move
return 0;
int speed = creature->speed;
speed += valOfFeatures(StackFeature::SPEED_BONUS, -1024, turn);
int speed = valOfBonuses(Selector::type(Bonus::STACKS_SPEED) && Selector::turns(turn));
int percentBonus = 0;
for(int g=0; g<features.size(); ++g)
BOOST_FOREACH(const Bonus &b, bonuses)
{
if(features[g].type == StackFeature::SPEED_BONUS)
if(b.type == Bonus::STACKS_SPEED)
{
percentBonus += features[g].additionalInfo;
percentBonus += b.additionalInfo;
}
}
@@ -789,39 +749,6 @@ ui8 CStack::howManyEffectsSet(ui16 id) const
return ret;
}
si32 CStack::Attack() const
{
si32 ret = creature->attack; //value to be returned
if(hasFeatureOfType(StackFeature::IN_FRENZY)) //frenzy for attacker
{
ret += si32(VLC->spellh->spells[56].powers[getEffect(56)->level]/100.0) * Defense(false);
}
ret += valOfFeatures(StackFeature::ATTACK_BONUS);
return ret;
}
si32 CStack::Defense(bool withFrenzy /*= true*/) const
{
si32 ret = creature->defence;
if(withFrenzy && getEffect(56)) //frenzy for defender
{
return 0;
}
ret += valOfFeatures(StackFeature::DEFENCE_BONUS);
return ret;
}
ui16 CStack::MaxHealth() const
{
return creature->hitPoints + valOfFeatures(StackFeature::HP_BONUS);
}
bool CStack::willMove(int turn /*= 0*/) const
{
return ( turn ? true : !vstd::contains(state, DEFENDING) )
@@ -832,7 +759,7 @@ bool CStack::willMove(int turn /*= 0*/) const
bool CStack::canMove( int turn /*= 0*/ ) const
{
return alive()
&& !hasFeatureOfType(StackFeature::NOT_ACTIVE, -1024, turn); //eg. Ammo Cart
&& !hasBonus(Selector::type(Bonus::NOT_ACTIVE) && Selector::turns(turn)); //eg. Ammo Cart or blinded creature
}
bool CStack::moved( int turn /*= 0*/ ) const
@@ -843,6 +770,11 @@ bool CStack::moved( int turn /*= 0*/ ) const
return false;
}
bool CStack::doubleWide() const
{
return type->doubleWide;
}
CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, int player, const CTown *town, std::map<ui32,CGHeroInstance *> &available) const
{
CGHeroInstance *ret = NULL;
@@ -1135,24 +1067,6 @@ std::pair<int,int> CGameState::pickObject (CGObjectInstance *obj)
return std::pair<int,int>(-1,-1);
}
void randomizeArmy(CArmedInstance * army, int type)
{
int max = VLC->creh->creatures.size();
for (TSlots::iterator j=army->army.slots.begin(); j!=army->army.slots.end();j++)
{
if(j->second.idRand > max)
{
if(j->second.idRand % 2)
j->second.setType(VLC->townh->towns[type].basicCreatures[(j->second.idRand-197) / 2 -1]);
else
j->second.setType(VLC->townh->towns[type].upgradedCreatures[(j->second.idRand-197) / 2 -1]);
j->second.idRand = -1;
}
}
return;
}
void CGameState::randomizeObject(CGObjectInstance *cur)
{
std::pair<int,int> ran = pickObject(cur);
@@ -1178,7 +1092,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
cur->ID = ran.first;
h->portrait = cur->subID = ran.second;
h->type = VLC->heroh->heroes[ran.second];
randomizeArmy(h, h->type->heroType/2);
h->randomizeArmy(h->type->heroType/2);
map->heroes.push_back(h);
return; //TODO: maybe we should do something with definfo?
}
@@ -1195,7 +1109,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
t->defInfo = forts[t->subID];
else
t->defInfo = villages[t->subID];
randomizeArmy(t, t->subID);
t->randomizeArmy(t->subID);
map->towns.push_back(t);
return;
}
@@ -1655,8 +1569,8 @@ bool CGameState::battleCanFlee(int player)
if(!curB) //there is no battle
return false;
if(curB->heroes[0]->hasBonusOfType(HeroBonus::ENEMY_CANT_ESCAPE) //eg. one of heroes is wearing shakles of war
|| curB->heroes[0]->hasBonusOfType(HeroBonus::ENEMY_CANT_ESCAPE))
if(curB->heroes[0]->hasBonusOfType(Bonus::ENEMY_CANT_ESCAPE) //eg. one of heroes is wearing shakles of war
|| curB->heroes[0]->hasBonusOfType(Bonus::ENEMY_CANT_ESCAPE))
return false;
return true;
@@ -1669,7 +1583,7 @@ int CGameState::battleGetStack(int pos, bool onlyAlive)
for(unsigned int g=0; g<curB->stacks.size(); ++g)
{
if((curB->stacks[g]->position == pos
|| (curB->stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE)
|| (curB->stacks[g]->doubleWide()
&&( (curB->stacks[g]->attackerOwned && curB->stacks[g]->position-1 == pos)
|| (!curB->stacks[g]->attackerOwned && curB->stacks[g]->position+1 == pos) )
))
@@ -1758,7 +1672,7 @@ const CGHeroInstance * CGameState::battleGetOwner(int stackID)
UpgradeInfo CGameState::getUpgradeInfo(const CArmedInstance *obj, int stackPos)
{
UpgradeInfo ret;
const CCreature *base = obj->army.slots.find(stackPos)->second.type;
const CCreature *base = obj->getCreature(stackPos);
if((obj->ID == TOWNI_TYPE) || ((obj->ID == HEROI_TYPE) && static_cast<const CGHeroInstance*>(obj)->visitedTown))
{
const CGTownInstance * t;
@@ -1777,7 +1691,7 @@ UpgradeInfo CGameState::getUpgradeInfo(const CArmedInstance *obj, int stackPos)
ret.cost.push_back(std::set<std::pair<int,int> >());
for(int j=0;j<RESOURCE_QUANTITY;j++)
{
int dif = VLC->creh->creatures[nid].cost[j] - base->cost[j];
int dif = VLC->creh->creatures[nid]->cost[j] - base->cost[j];
if(dif)
ret.cost[ret.cost.size()-1].insert(std::make_pair(j,dif));
}
@@ -2378,10 +2292,10 @@ bool CGameState::checkForVisitableDir( const int3 & src, const TerrainTile *pom,
std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky )
{
float additiveBonus=1.0f, multBonus=1.0f,
minDmg = attacker->creature->damageMin * attacker->amount,
maxDmg = attacker->creature->damageMax * attacker->amount;
minDmg = attacker->type->damageMin * attacker->count,
maxDmg = attacker->type->damageMax * attacker->count;
if(attacker->creature->idNumber == 149) //arrow turret
if(attacker->type->idNumber == 149) //arrow turret
{
switch(attacker->position)
{
@@ -2396,16 +2310,16 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
}
}
if(attacker->hasFeatureOfType(StackFeature::SIEGE_WEAPON) && attacker->creature->idNumber != 149) //any siege weapon, but only ballista can attack (second condition - not arrow turret)
if(attacker->hasBonusOfType(Bonus::SIEGE_WEAPON) && attacker->type->idNumber != 149) //any siege weapon, but only ballista can attack (second condition - not arrow turret)
{ //minDmg and maxDmg are multiplied by hero attack + 1
minDmg *= attackerHero->getPrimSkillLevel(0) + 1;
maxDmg *= attackerHero->getPrimSkillLevel(0) + 1;
}
int attackDefenceDifference = 0;
if(attacker->hasFeatureOfType(StackFeature::GENERAL_ATTACK_REDUCTION))
if(attacker->hasBonusOfType(Bonus::GENERAL_ATTACK_REDUCTION))
{
float multAttackReduction = attacker->valOfFeatures(StackFeature::GENERAL_ATTACK_REDUCTION, -1024) / 100.0f;
float multAttackReduction = attacker->valOfBonuses(Bonus::GENERAL_ATTACK_REDUCTION, -1024) / 100.0f;
attackDefenceDifference = attacker->Attack() * multAttackReduction;
}
else
@@ -2413,9 +2327,9 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
attackDefenceDifference = attacker->Attack();
}
if(attacker->hasFeatureOfType(StackFeature::ENEMY_DEFENCE_REDUCTION))
if(attacker->hasBonusOfType(Bonus::ENEMY_DEFENCE_REDUCTION))
{
float multDefenceReduction = (100.0f - attacker->valOfFeatures(StackFeature::ENEMY_DEFENCE_REDUCTION, -1024)) / 100.0f;
float multDefenceReduction = (100.0f - attacker->valOfBonuses(Bonus::ENEMY_DEFENCE_REDUCTION, -1024)) / 100.0f;
attackDefenceDifference -= defender->Defense() * multDefenceReduction;
}
else
@@ -2425,15 +2339,11 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
//calculating total attack/defense skills modifier
if(!shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 0)) //bloodlust handling (etc.)
{
attackDefenceDifference += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 0);
}
if(shooting) //precision handling (etc.)
attackDefenceDifference += attacker->getBonuses(Selector::typeSybtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), Selector::effectRange(Bonus::ONLY_DISTANCE_FIGHT)).totalValue();
else //bloodlust handling (etc.)
attackDefenceDifference += attacker->getBonuses(Selector::typeSybtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), Selector::effectRange(Bonus::ONLY_MELEE_FIGHT)).totalValue();
if(shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 1)) //precision handling (etc.)
{
attackDefenceDifference += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 1);
}
if(attacker->getEffect(55)) //slayer handling
{
@@ -2442,11 +2352,11 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
for(int g = 0; g < VLC->creh->creatures.size(); ++g)
{
for (int d=0; d<VLC->creh->creatures[g].abilities.size(); ++d)
BOOST_FOREACH(const Bonus &b, VLC->creh->creatures[g]->bonuses)
{
if ( (VLC->creh->creatures[g].abilities[d].type == StackFeature::KING3 && spLevel >= 3) || //expert
(VLC->creh->creatures[g].abilities[d].type == StackFeature::KING2 && spLevel >= 2) || //adv +
(VLC->creh->creatures[g].abilities[d].type == StackFeature::KING1 && spLevel >= 0) ) //none or basic +
if ( (b.type == Bonus::KING3 && spLevel >= 3) || //expert
(b.type == Bonus::KING2 && spLevel >= 2) || //adv +
(b.type == Bonus::KING1 && spLevel >= 0) ) //none or basic +
{
affectedIds.push_back(g);
break;
@@ -2456,7 +2366,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
for(unsigned int g=0; g<affectedIds.size(); ++g)
{
if(defender->creature->idNumber == affectedIds[g])
if(defender->type->idNumber == affectedIds[g])
{
attackDefenceDifference += VLC->spellh->spells[55].powers[attacker->getEffect(55)->level];
break;
@@ -2492,7 +2402,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
//applying jousting bonus
if( attacker->hasFeatureOfType(StackFeature::JOUSTING) && !defender->hasFeatureOfType(StackFeature::CHARGE_IMMUNITY) )
if( attacker->hasBonusOfType(Bonus::JOUSTING) && !defender->hasBonusOfType(Bonus::CHARGE_IMMUNITY) )
additiveBonus += charge * 0.05f;
@@ -2517,7 +2427,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
if(attackerHero->getSecSkillLevel(1) > 0) //non-none level
{
//apply artifact premy to archery
additiveBonus += attackerHero->valOfBonuses(HeroBonus::SECONDARY_SKILL_PREMY, 1) / 100.0f;
additiveBonus += attackerHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, 1) / 100.0f;
}
}
else
@@ -2554,7 +2464,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
}
//handling hate effect
if( attacker->hasFeatureOfType(StackFeature::HATE, defender->creature->idNumber) )
if( attacker->hasBonusOfType(Bonus::HATE, defender->type->idNumber) )
additiveBonus += 0.5f;
//luck bonus
@@ -2564,13 +2474,13 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
}
//handling spell effects
if(!shooting && defender->hasFeatureOfType(StackFeature::GENERAL_DAMAGE_REDUCTION, 0)) //eg. shield
if(!shooting && defender->hasBonusOfType(Bonus::GENERAL_DAMAGE_REDUCTION, 0)) //eg. shield
{
multBonus *= float(defender->valOfFeatures(StackFeature::GENERAL_DAMAGE_REDUCTION, 0)) / 100.0f;
multBonus *= float(defender->valOfBonuses(Bonus::GENERAL_DAMAGE_REDUCTION, 0)) / 100.0f;
}
else if(shooting && defender->hasFeatureOfType(StackFeature::GENERAL_DAMAGE_REDUCTION, 1)) //eg. air shield
else if(shooting && defender->hasBonusOfType(Bonus::GENERAL_DAMAGE_REDUCTION, 1)) //eg. air shield
{
multBonus *= float(defender->valOfFeatures(StackFeature::GENERAL_DAMAGE_REDUCTION, 1)) / 100.0f;
multBonus *= float(defender->valOfBonuses(Bonus::GENERAL_DAMAGE_REDUCTION, 1)) / 100.0f;
}
if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
{
@@ -2636,7 +2546,7 @@ ui32 BattleInfo::calculateDmg( const CStack* attacker, const CStack* defender, c
if(range.first != range.second)
{
int valuesToAverage[10];
int howManyToAv = std::min<ui32>(10, attacker->amount);
int howManyToAv = std::min<ui32>(10, attacker->count);
for (int g=0; g<howManyToAv; ++g)
{
valuesToAverage[g] = range.first + rand() % (range.second - range.first + 1);
@@ -2653,10 +2563,10 @@ void BattleInfo::calculateCasualties( std::map<ui32,si32> *casualties ) const
for(unsigned int i=0; i<stacks.size();i++)//setting casualties
{
const CStack * const st = stacks[i];
si32 killed = (st->alive() ? st->baseAmount - st->amount : st->baseAmount);
si32 killed = (st->alive() ? st->baseAmount - st->count : st->baseAmount);
amax(killed, 0);
if(killed)
casualties[!st->attackerOwned][st->creature->idNumber] += killed;
casualties[!st->attackerOwned][st->type->idNumber] += killed;
}
}
@@ -2673,16 +2583,16 @@ si8 CGameState::battleMaxSpellLevel()
const CGHeroInstance *h1 = curB->heroes[0];
if(h1)
{
for(std::list<HeroBonus>::const_iterator i = h1->bonuses.begin(); i != h1->bonuses.end(); i++)
if(i->type == HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL)
for(std::list<Bonus>::const_iterator i = h1->bonuses.begin(); i != h1->bonuses.end(); i++)
if(i->type == Bonus::BLOCK_SPELLS_ABOVE_LEVEL)
amin(levelLimit, i->val);
}
const CGHeroInstance *h2 = curB->heroes[1];
if(h2)
{
for(std::list<HeroBonus>::const_iterator i = h2->bonuses.begin(); i != h2->bonuses.end(); i++)
if(i->type == HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL)
for(std::list<Bonus>::const_iterator i = h2->bonuses.begin(); i != h2->bonuses.end(); i++)
if(i->type == Bonus::BLOCK_SPELLS_ABOVE_LEVEL)
amin(levelLimit, i->val);
}
@@ -2700,8 +2610,8 @@ std::set<CStack*> BattleInfo::getAttackedCreatures( const CSpell * s, int skillL
{
for(int it=0; it<stacks.size(); ++it)
{
if((s->id == 24 && !stacks[it]->creature->isUndead()) //death ripple
|| (s->id == 25 && stacks[it]->creature->isUndead()) //destroy undead
if((s->id == 24 && !stacks[it]->type->isUndead()) //death ripple
|| (s->id == 25 && stacks[it]->type->isUndead()) //destroy undead
|| (s->id == 26) //Armageddon
)
{
@@ -2761,51 +2671,21 @@ int BattleInfo::calculateSpellDuration(const CSpell * spell, const CGHeroInstanc
case 56: //frenzy
return 1;
default: //other spells
return caster->getPrimSkillLevel(2) + caster->valOfBonuses(HeroBonus::SPELL_DURATION);
return caster->getPrimSkillLevel(2) + caster->valOfBonuses(Bonus::SPELL_DURATION);
}
}
CStack * BattleInfo::generateNewStack(const CGHeroInstance * owner, int creatureID, int amount, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const
CStack * BattleInfo::generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const
{
CStack * ret = new CStack(&VLC->creh->creatures[creatureID], amount, attackerOwned ? side1 : side2, stackID, attackerOwned, slot);
if(owner)
{
ret->features.push_back(makeFeature(StackFeature::SPEED_BONUS, StackFeature::WHOLE_BATTLE, 0, owner->valOfBonuses(HeroBonus::STACKS_SPEED), StackFeature::BONUS_FROM_HERO));
//base luck/morale calculations
ret->morale = owner->getCurrentMorale(slot, false);
ret->luck = owner->getCurrentLuck(slot, false);
//other bonuses
ret->features.push_back(makeFeature(StackFeature::ATTACK_BONUS, StackFeature::WHOLE_BATTLE, 0, owner->getPrimSkillLevel(0), StackFeature::BONUS_FROM_HERO));
ret->features.push_back(makeFeature(StackFeature::DEFENCE_BONUS, StackFeature::WHOLE_BATTLE, 0, owner->getPrimSkillLevel(1), StackFeature::BONUS_FROM_HERO));
if ( owner->hasBonusOfType(HeroBonus::STACK_HEALTH_PERCENT) ) // e.g. Elixir of Life
ret->features.push_back(makeFeature(StackFeature::HP_BONUS, StackFeature::WHOLE_BATTLE, 0,
(ret->creature->hitPoints * owner->valOfBonuses(HeroBonus::STACK_HEALTH_PERCENT)) / 100,
StackFeature::BONUS_FROM_HERO));
if (owner->hasBonusOfType(HeroBonus::HP_REGENERATION)) // e.g. Elixir of Life
ret->features.push_back(makeFeature(StackFeature::HP_REGENERATION, StackFeature::WHOLE_BATTLE, 0,
owner->valOfBonuses(HeroBonus::HP_REGENERATION), StackFeature::BONUS_FROM_HERO));
if (owner->hasBonusOfType(HeroBonus::LEVEL_SPELL_IMMUNITY)) // e.g. Power of the Dragon Father
ret->features.push_back(makeFeature(StackFeature::LEVEL_SPELL_IMMUNITY, StackFeature::WHOLE_BATTLE, 0,
owner->valOfBonuses(HeroBonus::LEVEL_SPELL_IMMUNITY), StackFeature::BONUS_FROM_HERO));
ret->features.push_back(makeFeature(StackFeature::HP_BONUS, StackFeature::WHOLE_BATTLE, 0, owner->valOfBonuses(HeroBonus::STACK_HEALTH), StackFeature::BONUS_FROM_HERO));
ret->firstHPleft = ret->MaxHealth();
}
else
{
ret->morale = 0;
ret->luck = 0;
}
CStack * ret = new CStack(&base, attackerOwned ? side1 : side2, stackID, attackerOwned, slot);
//native terrain bonuses
int faction = ret->creature->faction;
int faction = ret->type->faction;
if(faction >= 0 && VLC->heroh->nativeTerrains[faction] == terrain)
{
ret->features.push_back(makeFeature(StackFeature::SPEED_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE));
ret->features.push_back(makeFeature(StackFeature::ATTACK_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE));
ret->features.push_back(makeFeature(StackFeature::DEFENCE_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE));
ret->bonuses.push_back(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE));
ret->bonuses.push_back(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE));
ret->bonuses.push_back(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE));
}
ret->position = position;
@@ -2823,13 +2703,13 @@ ui32 BattleInfo::getSpellCost(const CSpell * sp, const CGHeroInstance * caster)
si32 manaIncrease = 0;
for(int g=0; g<stacks.size(); ++g)
{
if( stacks[g]->owner == caster->tempOwner && stacks[g]->hasFeatureOfType(StackFeature::CHANGES_SPELL_COST_FOR_ALLY) )
if( stacks[g]->owner == caster->tempOwner && stacks[g]->hasBonusOfType(Bonus::CHANGES_SPELL_COST_FOR_ALLY) )
{
amin(manaReduction, stacks[g]->valOfFeatures(StackFeature::CHANGES_SPELL_COST_FOR_ALLY));
amin(manaReduction, stacks[g]->valOfBonuses(Bonus::CHANGES_SPELL_COST_FOR_ALLY));
}
if( stacks[g]->owner != caster->tempOwner && stacks[g]->hasFeatureOfType(StackFeature::CHANGES_SPELL_COST_FOR_ENEMY) )
if( stacks[g]->owner != caster->tempOwner && stacks[g]->hasBonusOfType(Bonus::CHANGES_SPELL_COST_FOR_ENEMY) )
{
amax(manaIncrease, stacks[g]->valOfFeatures(StackFeature::CHANGES_SPELL_COST_FOR_ENEMY));
amax(manaIncrease, stacks[g]->valOfBonuses(Bonus::CHANGES_SPELL_COST_FOR_ENEMY));
}
}
@@ -2866,10 +2746,10 @@ std::pair<const CStack *, int> BattleInfo::getNearestStack(const CStack * closes
bool ac[BFIELD_SIZE];
std::set<int> occupyable;
getAccessibilityMap(ac, closest->hasFeatureOfType(StackFeature::DOUBLE_WIDE), closest->attackerOwned, false, occupyable, closest->hasFeatureOfType(StackFeature::FLYING), closest->ID);
getAccessibilityMap(ac, closest->doubleWide(), closest->attackerOwned, false, occupyable, closest->hasBonusOfType(Bonus::FLYING), closest->ID);
int predecessor[BFIELD_SIZE], dist[BFIELD_SIZE];
makeBFS(closest->position, ac, predecessor, dist, closest->hasFeatureOfType(StackFeature::DOUBLE_WIDE), closest->attackerOwned, closest->hasFeatureOfType(StackFeature::FLYING), true);
makeBFS(closest->position, ac, predecessor, dist, closest->doubleWide(), closest->attackerOwned, closest->hasBonusOfType(Bonus::FLYING), true);
std::vector< std::pair< std::pair<int, int>, const CStack *> > stackPairs; //pairs <<distance, hex>, stack>
for(int g=0; g<BFIELD_SIZE; ++g)
@@ -2944,59 +2824,59 @@ ui32 BattleInfo::calculateSpellDmg( const CSpell * sp, const CGHeroInstance * ca
}
}
//applying hero bonuses
if(sp->air && caster && caster->valOfBonuses(HeroBonus::AIR_SPELL_DMG_PREMY) != 0)
if(sp->air && caster && caster->valOfBonuses(Bonus::AIR_SPELL_DMG_PREMY) != 0)
{
ret *= (100.0f + caster->valOfBonuses(HeroBonus::AIR_SPELL_DMG_PREMY)) / 100.0f;
ret *= (100.0f + caster->valOfBonuses(Bonus::AIR_SPELL_DMG_PREMY)) / 100.0f;
}
else if(sp->fire && caster && caster->valOfBonuses(HeroBonus::FIRE_SPELL_DMG_PREMY) != 0)
else if(sp->fire && caster && caster->valOfBonuses(Bonus::FIRE_SPELL_DMG_PREMY) != 0)
{
ret *= (100.0f + caster->valOfBonuses(HeroBonus::FIRE_SPELL_DMG_PREMY)) / 100.0f;
ret *= (100.0f + caster->valOfBonuses(Bonus::FIRE_SPELL_DMG_PREMY)) / 100.0f;
}
else if(sp->water && caster && caster->valOfBonuses(HeroBonus::WATER_SPELL_DMG_PREMY) != 0)
else if(sp->water && caster && caster->valOfBonuses(Bonus::WATER_SPELL_DMG_PREMY) != 0)
{
ret *= (100.0f + caster->valOfBonuses(HeroBonus::WATER_SPELL_DMG_PREMY)) / 100.0f;
ret *= (100.0f + caster->valOfBonuses(Bonus::WATER_SPELL_DMG_PREMY)) / 100.0f;
}
else if(sp->earth && caster && caster->valOfBonuses(HeroBonus::EARTH_SPELL_DMG_PREMY) != 0)
else if(sp->earth && caster && caster->valOfBonuses(Bonus::EARTH_SPELL_DMG_PREMY) != 0)
{
ret *= (100.0f + caster->valOfBonuses(HeroBonus::EARTH_SPELL_DMG_PREMY)) / 100.0f;
ret *= (100.0f + caster->valOfBonuses(Bonus::EARTH_SPELL_DMG_PREMY)) / 100.0f;
}
//affected creature-specific part
if(affectedCreature)
{
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
if(sp->air && affectedCreature->hasFeatureOfType(StackFeature::SPELL_DAMAGE_REDUCTION, 0)) //air spell & protection from air
if(sp->air && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 0)) //air spell & protection from air
{
ret *= affectedCreature->valOfFeatures(StackFeature::SPELL_DAMAGE_REDUCTION, 0);
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 0);
ret /= 100;
}
else if(sp->fire && affectedCreature->hasFeatureOfType(StackFeature::SPELL_DAMAGE_REDUCTION, 1)) //fire spell & protection from fire
else if(sp->fire && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 1)) //fire spell & protection from fire
{
ret *= affectedCreature->valOfFeatures(StackFeature::SPELL_DAMAGE_REDUCTION, 1);
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 1);
ret /= 100;
}
else if(sp->water && affectedCreature->hasFeatureOfType(StackFeature::SPELL_DAMAGE_REDUCTION, 2)) //water spell & protection from water
else if(sp->water && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 2)) //water spell & protection from water
{
ret *= affectedCreature->valOfFeatures(StackFeature::SPELL_DAMAGE_REDUCTION, 2);
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 2);
ret /= 100;
}
else if (sp->earth && affectedCreature->hasFeatureOfType(StackFeature::SPELL_DAMAGE_REDUCTION, 3)) //earth spell & protection from earth
else if (sp->earth && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 3)) //earth spell & protection from earth
{
ret *= affectedCreature->valOfFeatures(StackFeature::SPELL_DAMAGE_REDUCTION, 3);
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 3);
ret /= 100;
}
//general spell dmg reduction
if(sp->air && affectedCreature->hasFeatureOfType(StackFeature::SPELL_DAMAGE_REDUCTION, -1)) //air spell & protection from air
if(sp->air && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, -1)) //air spell & protection from air
{
ret *= affectedCreature->valOfFeatures(StackFeature::SPELL_DAMAGE_REDUCTION, -1);
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, -1);
ret /= 100;
}
//dmg increasing
if( affectedCreature->hasFeatureOfType(StackFeature::MORE_DAMAGE_FROM_SPELL, sp->id) )
if( affectedCreature->hasBonusOfType(Bonus::MORE_DAMAGE_FROM_SPELL, sp->id) )
{
ret *= 100 + affectedCreature->valOfFeatures(StackFeature::MORE_DAMAGE_FROM_SPELL, sp->id);
ret *= 100 + affectedCreature->valOfBonuses(Bonus::MORE_DAMAGE_FROM_SPELL, sp->id);
ret /= 100;
}
}
@@ -3016,16 +2896,16 @@ bool CGameState::battleCanShoot(int ID, int dest)
const CGHeroInstance * ourHero = battleGetOwner(our->ID);
if(our->hasFeatureOfType(StackFeature::FORGETFULL)) //forgetfulness
if(our->hasBonusOfType(Bonus::FORGETFULL)) //forgetfulness
return false;
if(our->creature->idNumber == 145 && dst) //catapult cannot attack creatures
if(our->type->idNumber == 145 && dst) //catapult cannot attack creatures
return false;
if(our->hasFeatureOfType(StackFeature::SHOOTER)//it's shooter
if(our->hasBonusOfType(Bonus::SHOOTER)//it's shooter
&& our->owner != dst->owner
&& dst->alive()
&& (!curB->isStackBlocked(ID) || NBonus::hasOfType(ourHero, HeroBonus::FREE_SHOOTING))
&& (!curB->isStackBlocked(ID) || NBonus::hasOfType(ourHero, Bonus::FREE_SHOOTING))
&& our->shots
)
return true;
@@ -3062,7 +2942,7 @@ int CGameState::victoryCheck( ui8 player ) const
&& map->objects[i]->tempOwner == player //object controlled by player
&& (ai = dynamic_cast<const CArmedInstance*>(map->objects[i]))) //contains army
{
for(TSlots::const_iterator i=ai->army.slots.begin(); i!=ai->army.slots.end(); ++i) //iterate through army
for(TSlots::const_iterator i=ai->Slots().begin(); i!=ai->Slots().end(); ++i) //iterate through army
if(i->second.type->idNumber == map->victoryCondition.ID) //it's searched creature
total += i->second.count;
}
@@ -3291,7 +3171,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
const CGHeroInstance * best = statsHLP::findBestHero(this, g->second.color);
InfoAboutHero iah;
iah.initFromHero(best, level >= 8);
iah.army.slots.clear();
iah.army.clear();
tgi.colorToBestHero[g->second.color] = iah;
}
}
@@ -3354,10 +3234,10 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
int bestCre = -1; //best creature's ID
for(int b=0; b<g->second.heroes.size(); ++b)
{
for(TSlots::const_iterator it = g->second.heroes[b]->army.slots.begin(); it != g->second.heroes[b]->army.slots.end(); ++it)
for(TSlots::const_iterator it = g->second.heroes[b]->Slots().begin(); it != g->second.heroes[b]->Slots().end(); ++it)
{
int toCmp = it->second.type->idNumber; //ID of creature we should compare with the best one
if(bestCre == -1 || VLC->creh->creatures[bestCre].AIValue < VLC->creh->creatures[toCmp].AIValue)
if(bestCre == -1 || VLC->creh->creatures[bestCre]->AIValue < VLC->creh->creatures[toCmp]->AIValue)
{
bestCre = toCmp;
}
@@ -3508,7 +3388,7 @@ void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, i
else
p = 3;
}
else if(s->creature->idNumber == 145 || s->creature->idNumber == 149) //catapult and turrets are first
else if(s->type->idNumber == 145 || s->type->idNumber == 149) //catapult and turrets are first
{
p = 0;
}
@@ -3566,77 +3446,6 @@ void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, i
}
}
si8 BattleInfo::Morale( const CStack * st ) const
{
si8 ret = st->morale;
if(st->hasFeatureOfType(StackFeature::NON_LIVING) || st->hasFeatureOfType(StackFeature::UNDEAD) ||
st->hasFeatureOfType(StackFeature::NO_MORALE) || st->hasFeatureOfType(StackFeature::SIEGE_WEAPON))
return 0;
ret += st->valOfFeatures(StackFeature::MORALE_BONUS); //mirth & sorrow & other
//decreasing / increasing morale from other stacks
for (int g=0; g<stacks.size(); ++g)
{
if (stacks[g]->owner == st->owner) //ally
{
if (stacks[g]->hasFeatureOfType(StackFeature::RAISING_MORALE))
{
ret += stacks[g]->valOfFeatures(StackFeature::RAISING_MORALE);
}
}
else //enemy
{
if (stacks[g]->hasFeatureOfType(StackFeature::ENEMY_MORALE_DECREASING))
{
ret -= stacks[g]->valOfFeatures(StackFeature::ENEMY_MORALE_DECREASING);
}
}
}
if(st->hasFeatureOfType(StackFeature::SELF_MORALE)) //eg. minotaur
{
ret = std::max<si8>(ret, +1);
}
if(ret > 3) ret = 3;
if(ret < -3) ret = -3;
return ret;
}
si8 BattleInfo::Luck( const CStack * st ) const
{
si8 ret = st->luck;
if(st->hasFeatureOfType(StackFeature::NO_LUCK))
return 0;
ret += st->valOfFeatures(StackFeature::LUCK_BONUS); //fortune & misfortune & other
//decreasing / increasing morale from other stacks
for (int g=0; g<stacks.size(); ++g)
{
if (stacks[g]->owner == st->owner) //ally
{
//no such feature (yet)
}
else //enemy
{
ret -= stacks[g]->valOfFeatures(StackFeature::ENEMY_LUCK_DECREASING);
}
}
if(st->hasFeatureOfType(StackFeature::SELF_LUCK)) //eg. halfling
{
ret = std::max<si8>(ret, +1);
}
if(ret > 3) ret = 3;
if(ret < -3) ret = -3;
return ret;
}
si8 BattleInfo::hasDistancePenalty( int stackID, int destHex )
{
const CStack * stack = getStack(stackID);
@@ -3644,7 +3453,7 @@ si8 BattleInfo::hasDistancePenalty( int stackID, int destHex )
int distance = std::abs(destHex % BFIELD_WIDTH - stack->position % BFIELD_WIDTH);
//I hope it's approximately correct
return distance > 8 && !stack->hasFeatureOfType(StackFeature::NO_DISTANCE_PENALTY);
return distance > 8 && !stack->hasBonusOfType(Bonus::NO_DISTANCE_PENALTY);
}
si8 BattleInfo::hasWallPenalty( int stackID, int destHex )
@@ -3654,7 +3463,7 @@ si8 BattleInfo::hasWallPenalty( int stackID, int destHex )
return false;
}
const CStack * stack = getStack(stackID);
if (stack->hasFeatureOfType(StackFeature::NO_WALL_PENALTY));
if (stack->hasBonusOfType(Bonus::NO_WALL_PENALTY));
{
return false;
}
@@ -3667,6 +3476,28 @@ si8 BattleInfo::hasWallPenalty( int stackID, int destHex )
return stackLeft != destLeft;
}
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);
}
}
}
int3 CPath::startPos() const
{
return nodes[nodes.size()-1].coord;
@@ -3766,7 +3597,7 @@ bool CMP_stack::operator()( const CStack* a, const CStack* b )
switch(phase)
{
case 0: //catapult moves after turrets
return a->creature->idNumber < b->creature->idNumber; //catapult is 145 and turrets are 149
return a->type->idNumber < b->type->idNumber; //catapult is 145 and turrets are 149
//TODO? turrets order
case 1: //fastest first, upper slot first
{
@@ -3805,6 +3636,11 @@ PlayerState::PlayerState()
}
void PlayerState::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const
{
//TODO: global effects
}
InfoAboutHero::InfoAboutHero()
{
details = NULL;
@@ -3830,14 +3666,14 @@ void InfoAboutHero::initFromHero( const CGHeroInstance *h, bool detailed )
hclass = h->type->heroClass;
name = h->name;
portrait = h->portrait;
army = h->army;
army = h->getArmy();
if(detailed)
{
//include details about hero
details = new Details;
details->luck = h->getCurrentLuck();
details->morale = h->getCurrentMorale();
details->luck = h->LuckVal();
details->morale = h->MoraleVal();
details->mana = h->mana;
details->primskills.resize(PRIMARY_SKILLS);
@@ -3849,9 +3685,9 @@ void InfoAboutHero::initFromHero( const CGHeroInstance *h, bool detailed )
else
{
//hide info about hero stacks counts using descriptives names ids
for(TSlots::iterator i = army.slots.begin(); i != army.slots.end(); ++i)
for(TSlots::const_iterator i = army.Slots().begin(); i != army.Slots().end(); ++i)
{
i->second.count = i->second.getQuantityID();
army.setStackCount(i->first, i->second.getQuantityID());
}
}
}

View File

@@ -2,22 +2,26 @@
#define __CGAMESTATE_H__
#include "../global.h"
#include <cassert>
#ifndef _MSC_VER
#include "../hch/CCreatureHandler.h"
#include "VCMI_Lib.h"
#include "map.h"
#endif
#include <set>
#include <vector>
#include <list>
#include "StackFeature.h"
#include "HeroBonus.h"
#include "CCreatureSet.h"
#ifdef _WIN32
#include <tchar.h>
#else
#include "../tchar_amigaos4.h"
#endif
/*
* CGameState.h, part of VCMI engine
*
@@ -123,11 +127,13 @@ public:
ui8 daysWithoutCastle;
PlayerState();
virtual void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & color & serial & human & currentSelection & fogOfWarMap & resources & status;
h & heroes & towns & availableHeroes & dwellings & bonuses & status & daysWithoutCastle;
h & static_cast<CBonusSystemNode&>(*this);
}
};
@@ -153,7 +159,7 @@ struct DLL_EXPORT SiegeInfo
}
};
struct DLL_EXPORT BattleInfo
struct DLL_EXPORT BattleInfo : public CBonusSystemNode
{
ui8 side1, side2; //side1 - attacker, side2 - defender
si32 round, activeStack;
@@ -161,7 +167,7 @@ struct DLL_EXPORT BattleInfo
si32 tid; //used during town siege - id of attacked town; -1 if not town defence
int3 tile; //for background and bonuses
CGHeroInstance *heroes[2];
CCreatureSet army1, army2;
CArmedInstance *belligerents[2]; //may be same as heroes
std::vector<CStack*> stacks;
std::vector<CObstacleInstance> obstacles;
ui8 castSpells[2]; //[0] - attacker, [1] - defender
@@ -169,10 +175,16 @@ struct DLL_EXPORT BattleInfo
template <typename Handler> void serialize(Handler &h, const int version)
{
h & side1 & side2 & round & activeStack & siege & tid & tile & stacks & army1 & army2 & obstacles
h & side1 & side2 & round & activeStack & siege & tid & tile & stacks & belligerents & obstacles
& castSpells & si;
h & heroes;
h & static_cast<CBonusSystemNode&>(*this);
}
//////////////////////////////////////////////////////////////////////////
void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
//////////////////////////////////////////////////////////////////////////
const CStack * getNextStack() const; //which stack will have turn after current one
void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action
CStack * getStack(int stackID, bool onlyAlive = true);
@@ -185,9 +197,6 @@ struct DLL_EXPORT BattleInfo
std::pair< std::vector<int>, int > getPath(int start, int dest, bool*accessibility, bool flyingCreature, bool twoHex, bool attackerOwned); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes
std::vector<int> getAccessibility(int stackID, bool addOccupiable) const; //returns vector of accessible tiles (taking into account the creature range)
si8 Morale(const CStack * st) const; //get morale of stack with all modificators
si8 Luck(const CStack * st) const; //get luck of stack with all modificators
bool isStackBlocked(int ID); //returns true if there is neighboring enemy stack
static signed char mutualPosition(int hex1, int hex2); //returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left)
static std::vector<int> neighbouringTiles(int hex);
@@ -196,7 +205,7 @@ struct DLL_EXPORT BattleInfo
void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
std::set<CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, int destinationTile); //calculates stack affected by given spell
static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster);
CStack * generateNewStack(const CGHeroInstance * owner, int creatureID, int amount, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
CStack * generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
int hexToWallPart(int hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
int lineToWallHex(int line) const; //returns hex with wall in given line
@@ -206,27 +215,24 @@ struct DLL_EXPORT BattleInfo
si8 hasWallPenalty(int stackID, int destHex); //determines if given stack has wall penalty shooting given pos
};
class DLL_EXPORT CStack
class DLL_EXPORT CStack : public CStackInstance
{
public:
ui32 ID; //unique ID of stack
CCreature * creature;
ui32 amount, baseAmount;
ui32 baseAmount;
ui32 firstHPleft; //HP of first creature in stack
ui8 owner, slot; //owner - player colour (255 for neutrals), slot - position in garrison (may be 255 for neutrals/called creatures)
ui8 attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle)
si16 position; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
ui8 counterAttacks; //how many counter attacks can be performed more in this turn (by default set at the beginning of the round to 1)
si16 shots; //how many shots left
si8 morale, luck; //base stack luck/morale
std::vector<StackFeature> features;
std::set<ECombatInfo> state;
struct StackEffect
{
ui16 id; //spell id
ui8 level; //skill level
ui16 turnsRemain;
si16 turnsRemain;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & id & level & turnsRemain;
@@ -234,39 +240,25 @@ public:
};
std::vector<StackEffect> effects;
int valOfFeatures(StackFeature::ECombatFeatures type, int subtype = -1024, int turn = 0) const;//subtype -> subtype of bonus, if -1024 then any
bool hasFeatureOfType(StackFeature::ECombatFeatures type, int subtype = -1024, int turn = 0) const; //determines if stack has a bonus of given type (and optionally subtype)
//overrides
const CCreature* getCreature() const {return type;}
CStack(CCreature * C, int A, int O, int I, bool AO, int S); //c-tor
CStack() : ID(-1), creature(NULL), amount(-1), baseAmount(-1), firstHPleft(-1), owner(255), slot(255), attackerOwned(true), position(-1), counterAttacks(1) {} //c-tor
CStack(const CStackInstance *base, int O, int I, bool AO, int S); //c-tor
CStack() : ID(-1), baseAmount(-1), firstHPleft(-1), owner(255), slot(255), attackerOwned(true), position(-1), counterAttacks(1) {} //c-tor
const StackEffect * getEffect(ui16 id, int turn = 0) const; //effect id (SP)
ui8 howManyEffectsSet(ui16 id) const; //returns amount of effects with given id set for this stack
bool willMove(int turn = 0) const; //if stack has remaining move this turn
bool moved(int turn = 0) const; //if stack was already moved this turn
bool canMove(int turn = 0) const; //if stack can move
ui32 Speed(int turn = 0) const; //get speed of creature with all modificators
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
template <typename Handler> void save(Handler &h, const int version)
{
h & creature->idNumber;
}
template <typename Handler> void load(Handler &h, const int version)
{
ui32 id;
h & id;
creature = &VLC->creh->creatures[id];
//features = creature->abilities;
}
bool doubleWide() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & ID & amount & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks
& shots & morale & luck & features;
if(h.saving)
save(h,version);
else
load(h,version);
h & static_cast<CStackInstance&>(*this);
h & ID & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks
& shots;
}
bool alive() const //determines if stack is alive
{
@@ -363,6 +355,7 @@ public:
std::map<ui8, PlayerState> players; //ID <-> player state
std::map<int, CGDefInfo*> villages, forts, capitols; //def-info for town graphics
std::vector<ui32> resVals; //default values of resources in gold
CBonusSystemNode globalEffects;
struct DLL_EXPORT HeroesPool
{
@@ -378,7 +371,6 @@ public:
} hpool; //we have here all heroes available on this map that are not hired
boost::shared_mutex *mx;
PlayerState *getPlayer(ui8 color, bool verbose = true);
const PlayerState *getPlayer(ui8 color, bool verbose = true) const;
void init(StartInfo * si, Mapa * map, int Seed);
@@ -424,7 +416,7 @@ public:
int getDate(int mode=0) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
template <typename Handler> void serialize(Handler &h, const int version)
{
h & scenarioOps & seed & currentPlayer & day & map & players & resVals & hpool;
h & scenarioOps & seed & currentPlayer & day & map & players & resVals & hpool & globalEffects;
if(!h.saving)
{
loadTownDInfos();

View File

@@ -14,6 +14,8 @@
#include "CGameState.h"
#include "map.h"
#include "../hch/CObjectHandler.h"
#include "../hch/CCreatureHandler.h"
#include "VCMI_Lib.h"
/*
@@ -202,6 +204,7 @@ void CConnection::close()
}
}
CGObjectInstance *CConnection::loadObject()
{
assert(gs);
@@ -218,6 +221,20 @@ void CConnection::saveObject( const CGObjectInstance *data )
*this << data->id;
}
CCreature * CConnection::loadCreature()
{
si32 id;
*this >> id;
assert(id >= 0 && id < VLC->creh->creatures.size());
return VLC->creh->creatures[id];
}
void CConnection::saveCreature(const CCreature *data)
{
assert(data);
*this << data->idNumber;
}
void CConnection::setGS( CGameState *state )
{
gs = state;

View File

@@ -25,6 +25,7 @@ const ui32 version = 719;
class CConnection;
class CGObjectInstance;
class CGameState;
class CCreature;
namespace mpl = boost::mpl;
/*
@@ -740,6 +741,8 @@ public:
CGObjectInstance *loadObject(); //reads id from net and returns that obj
void saveObject(const CGObjectInstance *data);
CCreature *loadCreature(); //reads id from net and returns that obj
void saveCreature(const CCreature *data);
template<typename T>
@@ -751,6 +754,14 @@ public:
}
};
template<typename T>
struct loadCreatureHelper
{
static void invoke(CConnection &s, T &data, ui16 tid)
{
data = static_cast<T>(s.loadCreature());
}
};
template<typename T>
struct loadRestHelper
{
static void invoke(CConnection &s, T &data, ui16 tid)
@@ -768,6 +779,15 @@ public:
}
};
template<typename T>
struct saveCreatureHelper
{
static void invoke(CConnection &s, const T &data, ui16 tid)
{
//CGObjectInstance *&hlp = const_cast<CGObjectInstance*&>(data); //for loading pointer to const obj we must remove the qualifier
s.saveCreature(data);
}
};
template<typename T>
struct saveRestHelper
{
static void invoke(CConnection &s, const T &data, ui16 tid)
@@ -785,9 +805,12 @@ public:
//if
mpl::eval_if< boost::is_base_of<CGObjectInstance, typename boost::remove_pointer<T>::type>,
mpl::identity<loadObjectHelper<T> >,
//else if
mpl::eval_if< boost::is_base_of<CCreature, typename boost::remove_pointer<T>::type>,
mpl::identity<loadCreatureHelper<T> >,
//else
mpl::identity<loadRestHelper<T> >
>::type typex;
> >::type typex;
typex::invoke(*this, data, tid);
}
@@ -799,9 +822,12 @@ public:
//if
mpl::eval_if< boost::is_base_of<CGObjectInstance, typename boost::remove_pointer<T>::type>,
mpl::identity<saveObjectHelper<T> >,
//else if
mpl::eval_if< boost::is_base_of<CCreature, typename boost::remove_pointer<T>::type>,
mpl::identity<saveCreatureHelper<T> >,
//else
mpl::identity<saveRestHelper<T> >
>::type typex;
> >::type typex;
typex::invoke(*this, data, tid);
}
};

View File

@@ -1,156 +1,265 @@
#define VCMI_DLL
#include "HeroBonus.h"
#include <boost/foreach.hpp>
#include "VCMI_Lib.h"
#include "../hch/CSpellHandler.h"
#include <sstream>
#include "../hch/CCreatureHandler.h"
#define FOREACH_PARENT(pname) TCNodes parents; getParents(parents); BOOST_FOREACH(const CBonusSystemNode *pname, parents)
#define FOREACH_CONST_PARENT(pname, source) TCNodes parents; getParents(parents, source); BOOST_FOREACH(const CBonusSystemNode *pname, parents)
#define FOREACH_PARENT(pname, source) TNodes parents; getParents(parents, source); BOOST_FOREACH(CBonusSystemNode *pname, parents)
int BonusList::valOfBonuses( HeroBonus::BonusType type, int subtype /*= -1*/ ) const /*subtype -> subtype of bonus, if -1 then any */
int DLL_EXPORT BonusList::totalValue() const
{
if(!this) //to avoid null-checking in maany places -> no bonus list means 0 bonus value
return 0;
int base = 0;
int percentToBase = 0;
int percentToAll = 0;
int additive = 0;
int ret = 0;
if(subtype == -1)
for(const_iterator i = begin(); i != end(); i++)
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type)
ret += i->val;
switch(i->valType)
{
case Bonus::BASE_NUMBER:
base += i->val;
break;
case Bonus::PERCENT_TO_ALL:
percentToAll += i->val;
break;
case Bonus::PERCENT_TO_BASE:
percentToBase += i->val;
break;
case Bonus::ADDITIVE_VALUE:
additive += i->val;
break;
}
}
else
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type && i->subtype == subtype)
ret += i->val;
}
return ret;
int modifiedBase = base + (base * percentToBase) / 100;
modifiedBase += additive;
return (modifiedBase * (100 + percentToAll)) / 100;
}
bool BonusList::hasBonusOfType( HeroBonus::BonusType type, int subtype /*= -1*/ ) const
const DLL_EXPORT Bonus * BonusList::getFirst(const CSelector &selector) const
{
if(!this) //to avoid null-checking in maany places -> no bonus list means there is no searched bonus
return 0;
if(subtype == -1) //any subtype
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type)
return true;
}
else //given subtype
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type && i->subtype == subtype)
return true;
}
return false;
}
const HeroBonus * BonusList::getBonus( int from, int id ) const
{
if(!this) //to avoid null-checking in maany places -> no bonus list means bonus cannot be retreived
return NULL;
for (const_iterator i = begin(); i != end(); i++)
if(i->source == from && i->id == id)
if(selector(*i))
return &*i;
return NULL;
}
void BonusList::getModifiersWDescr( std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype /*= -1 */ ) const
DLL_EXPORT Bonus * BonusList::getFirst(const CSelector &select)
{
if(!this) //to avoid null-checking in maany places -> no bonus list means nothing has to be done here
return;
if(subtype == -1)
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type)
out.push_back(std::make_pair(i->val, i->description));
}
else
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type && i->subtype == subtype)
out.push_back(std::make_pair(i->val, i->description));
}
for (iterator i = begin(); i != end(); i++)
if(select(*i))
return &*i;
return NULL;
}
int CBonusSystemNode::valOfBonuses(HeroBonus::BonusType type, int subtype /*= -1*/) const
void DLL_EXPORT BonusList::getModifiersWDescr(TModDescr &out) const
{
int ret = bonuses.valOfBonuses(type, subtype);
FOREACH_PARENT(p)
ret += p->valOfBonuses(type, subtype);
return ret;
for(const_iterator i = begin(); i != end(); i++)
out.push_back(std::make_pair(i->val, i->Description()));
}
bool CBonusSystemNode::hasBonusOfType(HeroBonus::BonusType type, int subtype /*= -1*/) const
void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *source /*= NULL*/) const
{
if(!this) //to allow calls on NULL and avoid checking duplication
return false; //if hero doesn't exist then bonus neither can
if(bonuses.hasBonusOfType(type, subtype))
return true;
FOREACH_PARENT(p)
if(p->hasBonusOfType(type, subtype))
return true;
return false;
for(const_iterator i = begin(); i != end(); i++)
if(selector(*i) && i->effectRange == Bonus::NO_LIMIT)
out.push_back(*i);
}
const HeroBonus * CBonusSystemNode::getBonus(int from, int id) const
void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *source /*= NULL*/) const
{
return bonuses.getBonus(from, id);
for(const_iterator i = begin(); i != end(); i++)
if(selector(*i) && (!limit || limit(*i)))
out.push_back(*i);
}
void CBonusSystemNode::getModifiersWDescr(std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype /*= -1 */) const
int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/) const
{
bonuses.getModifiersWDescr(out, type, subtype);
CSelector s = Selector::type(type);
if(subtype != -1)
s = s && Selector::subtype(subtype);
FOREACH_PARENT(p)
p->getModifiersWDescr(out, type, subtype);
return valOfBonuses(s);
}
int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
{
return valOfBonuses(Selector::type(type) && selector);
}
int CBonusSystemNode::valOfBonuses(const CSelector &selector, const CBonusSystemNode *root/* = NULL*/) const
{
BonusList hlp;
getBonuses(hlp, selector, root);
return hlp.totalValue();
}
bool CBonusSystemNode::hasBonus(const CSelector &selector, const CBonusSystemNode *root/* = NULL*/) const
{
return getBonuses(selector).size() > 0;
}
bool CBonusSystemNode::hasBonusOfType(Bonus::BonusType type, int subtype /*= -1*/) const
{
CSelector s = Selector::type(type);
if(subtype != -1)
s = s && Selector::subtype(subtype);
return hasBonus(s);
}
Bonus * CBonusSystemNode::getBonus(const CSelector &selector)
{
Bonus *ret = bonuses.getFirst(selector);
if(ret)
return ret;
FOREACH_PARENT(p, this)
if(ret = p->getBonus(selector))
return ret;
return NULL;
}
void CBonusSystemNode::getModifiersWDescr(TModDescr &out, Bonus::BonusType type, int subtype /*= -1 */) const
{
getModifiersWDescr(out, Selector::typeSybtype(type, subtype));
}
void CBonusSystemNode::getModifiersWDescr(TModDescr &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
{
getBonuses(selector).getModifiersWDescr(out);
}
int CBonusSystemNode::getBonusesCount(int from, int id) const
{
int ret = 0;
BOOST_FOREACH(const HeroBonus &hb, bonuses)
if(hb.source == from && hb.id == id)
ret++;
return ret;
return getBonusesCount(Selector::source(from, id));
}
void CBonusSystemNode::getParents(TCNodes &out, const CBonusSystemNode *source) const /*retreives list of parent nodes (nodes to inherit bonuses from) */
int CBonusSystemNode::getBonusesCount(const CSelector &selector, const CBonusSystemNode *root/* = NULL*/) const
{
return getBonuses(selector, root).size();
}
void CBonusSystemNode::getParents(TCNodes &out, const CBonusSystemNode *root) const /*retreives list of parent nodes (nodes to inherit bonuses from) */
{
return;
}
int NBonus::valOf(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype /*= -1*/)
void CBonusSystemNode::getParents(TNodes &out, const CBonusSystemNode *root /*= NULL*/)
{
//de-constify above
TCNodes hlp;
getParents(hlp, root);
BOOST_FOREACH(const CBonusSystemNode *pname, hlp)
out.insert(const_cast<CBonusSystemNode*>(pname));
}
void CBonusSystemNode::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
{
bonuses.getBonuses(out, selector);
FOREACH_CONST_PARENT(p, root ? root : this)
p->getBonuses(out, selector, root ? root : this);
}
BonusList CBonusSystemNode::getBonuses(const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
{
BonusList ret;
getBonuses(ret, selector, root);
return ret;
}
void CBonusSystemNode::getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
{
bonuses.getBonuses(out, selector, limit);
FOREACH_CONST_PARENT(p, root ? root : this)
p->getBonuses(out, selector, limit, root ? root : this);
}
BonusList CBonusSystemNode::getBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
{
BonusList ret;
getBonuses(ret, selector, limit, root);
return ret;
}
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);
}
int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/)
{
if(obj)
return obj->valOfBonuses(type, subtype);
return 0;
}
bool NBonus::hasOfType(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype /*= -1*/)
bool NBonus::hasOfType(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/)
{
if(obj)
return obj->hasBonusOfType(type, subtype);
return false;
}
const HeroBonus * NBonus::get(const CBonusSystemNode *obj, int from, int id)
{
if(obj)
return obj->getBonus(from, id);
return NULL;
}
void NBonus::getModifiersWDescr(const CBonusSystemNode *obj, std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype /*= -1 */)
void NBonus::getModifiersWDescr(const CBonusSystemNode *obj, TModDescr &out, Bonus::BonusType type, int subtype /*= -1 */)
{
if(obj)
return obj->getModifiersWDescr(out, type, subtype);
@@ -161,4 +270,72 @@ int NBonus::getCount(const CBonusSystemNode *obj, int from, int id)
if(obj)
return obj->getBonusesCount(from, id);
return 0;
}
const CSpell * Bonus::sourceSpell() const
{
if(source == SPELL_EFFECT)
return &VLC->spellh->spells[id];
return NULL;
}
std::string Bonus::Description() const
{
if(description.size())
return description;
std::ostringstream str;
if(val < 0)
str << '-';
else if(val > 0)
str << '+';
str << val << " ";
switch(source)
{
case CREATURE_ABILITY:
str << VLC->creh->creatures[id]->namePl;
break;
}
return str.str();
}
CSelector DLL_EXPORT operator&&(const CSelector &first, const CSelector &second)
{
return CSelectorsConjunction(first, second);
}
namespace Selector
{
DLL_EXPORT CSelectFieldEqual<TBonusType> type(&Bonus::type, 0);
DLL_EXPORT CSelectFieldEqual<TBonusSubtype> subtype(&Bonus::subtype, 0);
DLL_EXPORT CSelectFieldEqual<si32> info(&Bonus::additionalInfo, 0);
DLL_EXPORT CSelectFieldEqual<ui8> sourceType(&Bonus::source, 0);
DLL_EXPORT CSelectFieldEqual<ui8> effectRange(&Bonus::effectRange, Bonus::NO_LIMIT);
DLL_EXPORT CWillLastTurns turns;;
CSelector DLL_EXPORT typeSybtype(TBonusType Type, TBonusSubtype Subtype)
{
return type(Type) && subtype(Subtype);
}
CSelector DLL_EXPORT typeSybtypeInfo(TBonusType type, TBonusSubtype subtype, si32 info)
{
return CSelectFieldEqual<TBonusType>(&Bonus::type, type) && CSelectFieldEqual<TBonusSubtype>(&Bonus::subtype, subtype) && CSelectFieldEqual<si32>(&Bonus::additionalInfo, info);
}
CSelector DLL_EXPORT source(ui8 source, ui32 sourceID)
{
return CSelectFieldEqual<ui8>(&Bonus::source, source) && CSelectFieldEqual<ui32>(&Bonus::id, sourceID);
}
bool matchesType(const CSelector &sel, TBonusType type)
{
Bonus dummy;
dummy.type = type;
return sel(dummy);
}
}

View File

@@ -2,6 +2,8 @@
#include "../global.h"
#include <string>
#include <list>
#include <set>
#include <boost/function.hpp>
/*
* HeroBonus.h, part of VCMI engine
@@ -13,68 +15,226 @@
*
*/
struct DLL_EXPORT HeroBonus
typedef ui8 TBonusType;
typedef si32 TBonusSubtype;
class CSpell;
struct Bonus;
class CBonusSystemNode;
typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions
typedef std::set<CBonusSystemNode*> TNodes;
typedef std::set<const CBonusSystemNode*> TCNodes;
typedef boost::function<bool(const Bonus&)> CSelector;
namespace PrimarySkill
{
enum { ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE};
}
#define BONUS_LIST \
BONUS_NAME(NONE) \
BONUS_NAME(MOVEMENT) /*both water/land*/ \
BONUS_NAME(LAND_MOVEMENT) \
BONUS_NAME(SEA_MOVEMENT) \
BONUS_NAME(MORALE) \
BONUS_NAME(LUCK) \
BONUS_NAME(PRIMARY_SKILL) /*uses subtype to pick skill; additional info if set: 1 - only melee, 2 - only distance*/ \
BONUS_NAME(SIGHT_RADIOUS) \
BONUS_NAME(MANA_REGENERATION) /*points per turn apart from normal (1 + mysticism)*/ \
BONUS_NAME(FULL_MANA_REGENERATION) /*all mana points are replenished every day*/ \
BONUS_NAME(NONEVIL_ALIGNMENT_MIX) /*good and neutral creatures can be mixed without morale penalty*/ \
BONUS_NAME(SECONDARY_SKILL_PREMY) /*%*/ \
BONUS_NAME(SURRENDER_DISCOUNT) /*%*/ \
BONUS_NAME(STACKS_SPEED) /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - substracted to this part*/ \
BONUS_NAME(FLYING_MOVEMENT) \
BONUS_NAME(SPELL_DURATION) \
BONUS_NAME(AIR_SPELL_DMG_PREMY) \
BONUS_NAME(EARTH_SPELL_DMG_PREMY) \
BONUS_NAME(FIRE_SPELL_DMG_PREMY) \
BONUS_NAME(WATER_SPELL_DMG_PREMY) \
BONUS_NAME(BLOCK_SPELLS_ABOVE_LEVEL) \
BONUS_NAME(WATER_WALKING) \
BONUS_NAME(NO_SHOTING_PENALTY) \
BONUS_NAME(DISPEL_IMMUNITY) \
BONUS_NAME(NEGATE_ALL_NATURAL_IMMUNITIES) \
BONUS_NAME(STACK_HEALTH) \
BONUS_NAME(BLOCK_MORALE) \
BONUS_NAME(BLOCK_LUCK) \
BONUS_NAME(FIRE_SPELLS) \
BONUS_NAME(AIR_SPELLS) \
BONUS_NAME(WATER_SPELLS) \
BONUS_NAME(EARTH_SPELLS) \
BONUS_NAME(GENERATE_RESOURCE) /*daily value, uses subtype (resource type)*/ \
BONUS_NAME(CREATURE_GROWTH) /*for legion artifacts: value - week growth bonus, subtype - monster level*/ \
BONUS_NAME(WHIRLPOOL_PROTECTION) /*hero won't lose army when teleporting through whirlpool*/ \
BONUS_NAME(SPELL) /*hero knows spell, val - skill level (0 - 3), subtype - spell id*/ \
BONUS_NAME(SPELLS_OF_LEVEL) /*hero knows all spells of given level, val - skill level; subtype - level*/ \
BONUS_NAME(ENEMY_CANT_ESCAPE) /*for shackles of war*/ \
BONUS_NAME(MAGIC_SCHOOL_SKILL) /* //eg. for magic plains terrain, subtype: school of magic (0 - all, 1 - fire, 2 - air, 4 - water, 8 - earth), value - level*/ \
BONUS_NAME(FREE_SHOOTING) /*stacks can shoot even if otherwise blocked (sharpshooter's bow effect)*/ \
BONUS_NAME(OPENING_BATTLE_SPELL) /*casts a spell at expert level at beginning of battle, val - spell power, subtype - spell id*/ \
BONUS_NAME(IMPROVED_NECROMANCY) /*allows Necropolis units other than skeletons to be raised by necromancy*/ \
BONUS_NAME(CREATURE_GROWTH_PERCENT) /*increases growth of all units in all towns, val - percentage*/ \
BONUS_NAME(FREE_SHIP_BOARDING) /*movement points preserved with ship boarding and landing*/ \
BONUS_NAME(NO_TYPE) \
BONUS_NAME(FLYING) \
BONUS_NAME(SHOOTER) \
BONUS_NAME(CHARGE_IMMUNITY) \
BONUS_NAME(ADDITIONAL_ATTACK) \
BONUS_NAME(UNLIMITED_RETALIATIONS) \
BONUS_NAME(NO_MELEE_PENALTY) \
BONUS_NAME(JOUSTING) /*for champions*/ \
BONUS_NAME(HATE) /*eg. angels hate devils, subtype - ID of hated creature*/ \
BONUS_NAME(KING1) \
BONUS_NAME(KING2) \
BONUS_NAME(KING3) \
BONUS_NAME(MAGIC_RESISTANCE) /*in % (value)*/ \
BONUS_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \
BONUS_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \
BONUS_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - spell level, (additional info)%1000 - chance in %; eg. dendroids, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
BONUS_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
BONUS_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \
BONUS_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
BONUS_NAME(SPELL_DAMAGE_REDUCTION) /*eg. golems; value - reduction in %, subtype - spell school; -1 - all, 0 - air, 1 - fire, 2 - water, 3 - earth*/ \
BONUS_NAME(NO_WALL_PENALTY) \
BONUS_NAME(NON_LIVING) /*eg. gargoyle*/ \
BONUS_NAME(RANDOM_GENIE_SPELLCASTER) /*eg. master genie*/ \
BONUS_NAME(BLOCKS_RETALIATION) /*eg. naga*/ \
BONUS_NAME(SPELL_IMMUNITY) /*subid - spell id*/ \
BONUS_NAME(MANA_CHANNELING) /*value in %, eg. familiar*/ \
BONUS_NAME(SPELL_LIKE_ATTACK) /*value - spell id; range is taken from spell, but damage from creature; eg. magog*/ \
BONUS_NAME(THREE_HEADED_ATTACK) /*eg. cerberus*/ \
BONUS_NAME(DAEMON_SUMMONING) /*pit lord*/ \
BONUS_NAME(FIRE_IMMUNITY) \
BONUS_NAME(FIRE_SHIELD) \
BONUS_NAME(UNDEAD) \
BONUS_NAME(HP_REGENERATION) /*creature regenerates val HP every new round*/ \
BONUS_NAME(FULL_HP_REGENERATION) /*first creature regenerates all HP every new round; subtype 0 - animation 4 (trolllike), 1 - animation 47 (wightlike)*/ \
BONUS_NAME(MANA_DRAIN) /*value - spell points per turn*/ \
BONUS_NAME(LIFE_DRAIN) \
BONUS_NAME(DOUBLE_DAMAGE_CHANCE) /*value in %, eg. dread knight*/ \
BONUS_NAME(RETURN_AFTER_STRIKE) \
BONUS_NAME(SELF_MORALE) /*eg. minotaur*/ \
BONUS_NAME(SPELLCASTER) /*subtype - spell id, value - level of school, additional info - spell power*/ \
BONUS_NAME(CATAPULT) \
BONUS_NAME(ENEMY_DEFENCE_REDUCTION) /*in % (value) eg. behemots*/ \
BONUS_NAME(GENERAL_DAMAGE_REDUCTION) /* shield / air shield effect */ \
BONUS_NAME(GENERAL_ATTACK_REDUCTION) /*eg. while stoned or blinded - in %, subtype: -1 - any damage, 0 - melee damage, 1 - ranged damage*/ \
BONUS_NAME(ATTACKS_ALL_ADJACENT) /*eg. hydra*/ \
BONUS_NAME(MORE_DAMAGE_FROM_SPELL) /*value - damage increase in %, subtype - spell id*/ \
BONUS_NAME(CASTS_SPELL_WHEN_KILLED) /*similar to spell after attack*/ \
BONUS_NAME(FEAR) \
BONUS_NAME(FEARLESS) \
BONUS_NAME(NO_DISTANCE_PENALTY) \
BONUS_NAME(NO_OBSTACLES_PENALTY) \
BONUS_NAME(SELF_LUCK) /*halfling*/ \
BONUS_NAME(ENCHANTER) \
BONUS_NAME(HEALER) \
BONUS_NAME(SIEGE_WEAPON) \
BONUS_NAME(HYPNOTIZED) \
BONUS_NAME(ADDITIONAL_RETALIATION) /*value - number of additional retaliations*/ \
BONUS_NAME(MAGIC_MIRROR) /* value - chance of redirecting in %*/ \
BONUS_NAME(ALWAYS_MINIMUM_DAMAGE) /*unit does its minimum damage from range; subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative anti-bonus for dmg in % [eg 20 means that creature will inflict 80% of normal dmg]*/ \
BONUS_NAME(ALWAYS_MAXIMUM_DAMAGE) /*eg. bless effect, subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative bonus for dmg in %*/ \
BONUS_NAME(ATTACKS_NEAREST_CREATURE) /*while in berserk*/ \
BONUS_NAME(IN_FRENZY) /*value - level*/ \
BONUS_NAME(SLAYER) /*value - level*/ \
BONUS_NAME(FORGETFULL) /*forgetfulness spell effect, value - level*/ \
BONUS_NAME(NOT_ACTIVE) \
BONUS_NAME(NO_LUCK) /*eg. when fighting on cursed ground*/ \
BONUS_NAME(NO_MORALE) /*eg. when fighting on cursed ground*/
struct DLL_EXPORT Bonus
{
enum BonusType
{
//handled
NONE,
MOVEMENT, //both water/land
LAND_MOVEMENT,
SEA_MOVEMENT,
MORALE,
LUCK,
MORALE_AND_LUCK,
PRIMARY_SKILL, //uses subtype to pick skill
SIGHT_RADIOUS,
MANA_REGENERATION, //points per turn apart from normal (1 + mysticism)
FULL_MANA_REGENERATION, //all mana points are replenished every day
NONEVIL_ALIGNMENT_MIX, //good and neutral creatures can be mixed without morale penalty
HP_REGENERATION, //regenerates a certain amount of hp for the top of each stack every turn, val - hp regained
LEVEL_SPELL_IMMUNITY, //val - spell level creatures become immune to and below
//might not be handled yet:
MAGIC_RESISTANCE, // %
SECONDARY_SKILL_PREMY, //%
SURRENDER_DISCOUNT, //%
STACKS_SPEED,
FLYING_MOVEMENT, SPELL_DURATION, AIR_SPELL_DMG_PREMY, EARTH_SPELL_DMG_PREMY, FIRE_SPELL_DMG_PREMY,
WATER_SPELL_DMG_PREMY, BLOCK_SPELLS_ABOVE_LEVEL, WATER_WALKING, NO_SHOTING_PENALTY, DISPEL_IMMUNITY,
NEGATE_ALL_NATURAL_IMMUNITIES, STACK_HEALTH, STACK_HEALTH_PERCENT, //the second one of stack health - value in % of base HP to be added to overall stack HP
SPELL_IMMUNITY, BLOCK_MORALE, BLOCK_LUCK, FIRE_SPELLS,
AIR_SPELLS, WATER_SPELLS, EARTH_SPELLS,
GENERATE_RESOURCE, //daily value, uses subtype (resource type)
CREATURE_GROWTH, //for legion artifacts: value - week growth bonus, subtype - monster level
WHIRLPOOL_PROTECTION, //hero won't lose army when teleporting through whirlpool
SPELL, //hero knows spell, val - skill level (0 - 3), subtype - spell id
SPELLS_OF_LEVEL, //hero knows all spells of given level, val - skill level; subtype - level
ENEMY_CANT_ESCAPE, //for shackles of war
MAGIC_SCHOOL_SKILL, //eg. for magic plains terrain, subtype: school of magic (0 - all, 1 - fire, 2 - air, 4 - water, 8 - earth), value - level
FREE_SHOOTING, //stacks can shoot even if otherwise blocked (sharpshooter's bow effect)
OPENING_BATTLE_SPELL, //casts a spell at expert level at beginning of battle, val - spell power, subtype - spell id
IMPROVED_NECROMANCY, //allows Necropolis units other than skeletons to be raised by necromancy
CREATURE_GROWTH_PERCENT, //increases growth of all units in all towns, val - percentage
FREE_SHIP_BOARDING //movement points preserved with ship boarding and landing
#define BONUS_NAME(x) x,
BONUS_LIST
#undef BONUS_NAME
};
enum BonusDuration //when bonus is automatically removed
{
PERMANENT = 1,
ONE_BATTLE = 2, //at the end of battle
ONE_DAY = 4, //at the end of day
ONE_WEEK = 8, //at the end of week (bonus lasts till the end of week, thats NOT 7 days
N_TURNS = 16, //used during battles, after battle bonus is always removed
N_DAYS = 32,
UNITL_BEING_ATTACKED = 64,/*removed after attack and counterattacks are performed*/
UNTIL_ATTACK = 128 /*removed after attack and counterattacks are performed*/
};
enum BonusSource
{
ARTIFACT,
OBJECT,
CASTED_SPELL,
CREATURE_ABILITY,
TERRAIN_NATIVE,
TERRAIN_OVERLAY,
SPELL_EFFECT,
TOWN_STRUCTURE,
HERO_BASE_SKILL,
SECONDARY_SKILL,
ARMY
};
enum LimitEffect
{
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
};
enum ValueType
{
ADDITIVE_VALUE,
BASE_NUMBER,
PERCENT_TO_ALL,
PERCENT_TO_BASE
};
enum BonusDuration{PERMANENT, ONE_BATTLE, ONE_DAY, ONE_WEEK};
enum BonusSource{ARTIFACT, OBJECT, CASTED_SPELL};
ui8 duration; //uses BonusDuration values
ui8 type; //uses BonusType values - says to what is this bonus
si32 subtype; //-1 if not applicable
ui8 source;//uses BonusSource values - what gave that bonus
si32 val;//for morale/luck [-3,+3], others any
ui32 id; //id of object/artifact
si16 turnsRemain; //used if duration is N_TURNS or N_DAYS
TBonusType type; //uses BonusType values - says to what is this bonus - 1 byte
TBonusSubtype subtype; //-1 if not applicable - 4 bytes
ui8 source;//source type" uses BonusSource values - what gave that bonus
ui32 id; //source id: id of object/artifact/spell
ui8 valType;
si32 val;
si32 additionalInfo;
ui8 effectRange; //if not NO_LIMIT, bonus will be ommitted by default
std::string description;
HeroBonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1)
Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1)
:duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), id(ID), description(Desc)
{}
HeroBonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype=-1)
:duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), id(ID)
{}
HeroBonus()
{
additionalInfo = -1;
turnsRemain = 0;
valType = ADDITIVE_VALUE;
effectRange = NO_LIMIT;
}
Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype=-1, ui8 ValType = ADDITIVE_VALUE)
:duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), id(ID), valType(ValType)
{
additionalInfo = -1;
turnsRemain = 0;
effectRange = NO_LIMIT;
}
Bonus()
{
subtype = -1;
additionalInfo = -1;
turnsRemain = 0;
valType = ADDITIVE_VALUE;
effectRange = NO_LIMIT;
}
// //comparison
@@ -91,47 +251,57 @@ struct DLL_EXPORT HeroBonus
template <typename Handler> void serialize(Handler &h, const int version)
{
h & duration & type & subtype & source & val & id & description;
h & duration & type & subtype & source & val & id & description & additionalInfo & turnsRemain & valType & effectRange;
}
static bool OneDay(const HeroBonus &hb)
static bool OneDay(const Bonus &hb)
{
return hb.duration==HeroBonus::ONE_DAY;
return hb.duration & Bonus::ONE_DAY;
}
static bool OneWeek(const HeroBonus &hb)
static bool OneWeek(const Bonus &hb)
{
return hb.duration==HeroBonus::ONE_WEEK;
return hb.duration & Bonus::ONE_WEEK;
}
static bool OneBattle(const HeroBonus &hb)
static bool OneBattle(const Bonus &hb)
{
return hb.duration==HeroBonus::ONE_BATTLE;
return hb.duration & Bonus::ONE_BATTLE;
}
static bool IsFrom(const HeroBonus &hb, ui8 source, ui32 id) //if id==0xffffff then id doesn't matter
static bool UntilAttack(const Bonus &hb)
{
return hb.duration & Bonus::UNTIL_ATTACK;
}
static bool UntilBeingAttacked(const Bonus &hb)
{
return hb.duration & Bonus::UNITL_BEING_ATTACKED;
}
static bool IsFrom(const Bonus &hb, ui8 source, ui32 id) //if id==0xffffff then id doesn't matter
{
return hb.source==source && (id==0xffffff || hb.id==id);
}
inline bool operator == (const BonusType & cf) const
{
return type == cf;
}
const CSpell * sourceSpell() const;
std::string Description() const;
};
class CBonusSystemNode;
static const HeroBonus::BonusType MORALE_AFFECTING[] = {HeroBonus::MORALE, HeroBonus::MORALE_AND_LUCK};
static const HeroBonus::BonusType LUCK_AFFECTING[] = {HeroBonus::LUCK, HeroBonus::MORALE_AND_LUCK};
typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions
typedef std::list<CBonusSystemNode*> TNodes;
typedef std::list<const CBonusSystemNode*> TCNodes;
class BonusList : public std::list<HeroBonus>
class BonusList : public std::list<Bonus>
{
public:
int DLL_EXPORT valOfBonuses(HeroBonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any
bool DLL_EXPORT hasBonusOfType(HeroBonus::BonusType type, int subtype = -1) const;
const DLL_EXPORT HeroBonus * getBonus( int from, int id ) const;
void DLL_EXPORT getModifiersWDescr( std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype = -1 ) const;
int DLL_EXPORT totalValue() const; //subtype -> subtype of bonus, if -1 then any
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;
//special find functions
DLL_EXPORT Bonus * getFirst(const CSelector &select);
DLL_EXPORT const Bonus * getFirst(const CSelector &select) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<std::list<HeroBonus>&>(*this);
h & static_cast<std::list<Bonus>&>(*this);
}
};
@@ -140,19 +310,39 @@ class DLL_EXPORT CBonusSystemNode
public:
BonusList bonuses;
virtual void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const; //retreives list of parent nodes (nodes to inherit bonuses from), source is the prinary asker
//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)
virtual void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const; //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker
virtual void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
int valOfBonuses(HeroBonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any
bool hasBonusOfType(HeroBonus::BonusType type, int subtype = -1) const;//determines if hero has a bonus of given type (and optionally subtype)
const HeroBonus * getBonus( int from, int id ) const;
void getModifiersWDescr( std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype = -1 ) const; //out: pairs<modifier value, modifier description>
void getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const;
BonusList getBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const;
BonusList getBonuses(const CSelector &selector, const CBonusSystemNode *root = NULL) const;
int getBonusesCount(const CSelector &selector, const CBonusSystemNode *root = NULL) const;
int valOfBonuses(const CSelector &selector, const CBonusSystemNode *root = NULL) const;
bool hasBonus(const CSelector &selector, const CBonusSystemNode *root = NULL) const;
void getModifiersWDescr(TModDescr &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const; //out: pairs<modifier value, modifier description>
//////////////////////////////////////////////////////////////////////////
//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 any
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;
template<int N> void getModifiersWDescr(std::vector<std::pair<int,std::string> > &out, const HeroBonus::BonusType (&types)[N]) const //retreive array of types
{
for (int i = 0; i < N; i++)
getModifiersWDescr(out, types[i]);
}
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
//non-const interface
void getParents(TNodes &out, const CBonusSystemNode *root = NULL); //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker
Bonus *getBonus(const CSelector &selector);
template <typename Handler> void serialize(Handler &h, const int version)
{
@@ -163,9 +353,94 @@ public:
namespace NBonus
{
//set of methods that may be safely called with NULL objs
DLL_EXPORT int valOf(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype = -1); //subtype -> subtype of bonus, if -1 then any
DLL_EXPORT bool hasOfType(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype = -1);//determines if hero has a bonus of given type (and optionally subtype)
DLL_EXPORT const HeroBonus * get(const CBonusSystemNode *obj, int from, int id );
DLL_EXPORT void getModifiersWDescr(const CBonusSystemNode *obj, std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype = -1 ); //out: pairs<modifier value, modifier description>
DLL_EXPORT int valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype = -1); //subtype -> subtype of bonus, if -1 then any
DLL_EXPORT bool hasOfType(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype = -1);//determines if hero has a bonus of given type (and optionally subtype)
//DLL_EXPORT const HeroBonus * get(const CBonusSystemNode *obj, int from, int id );
DLL_EXPORT void getModifiersWDescr(const CBonusSystemNode *obj, TModDescr &out, Bonus::BonusType type, int subtype = -1 ); //out: pairs<modifier value, modifier description>
DLL_EXPORT int getCount(const CBonusSystemNode *obj, int from, int id);
};
};
//generates HeroBonus from given data
inline Bonus makeFeature(Bonus::BonusType type, ui8 duration, si16 subtype, si32 value, Bonus::BonusSource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
{
Bonus sf;
sf.type = type;
sf.duration = duration;
sf.source = source;
sf.turnsRemain = turnsRemain;
sf.subtype = subtype;
sf.val = value;
sf.additionalInfo = additionalInfo;
return sf;
}
class DLL_EXPORT CSelectorsConjunction
{
const CSelector first, second;
public:
CSelectorsConjunction(const CSelector &First, const CSelector &Second)
:first(First), second(Second)
{
}
bool operator()(const Bonus &bonus) const
{
return first(bonus) && second(bonus);
}
};
CSelector DLL_EXPORT operator&&(const CSelector &first, const CSelector &second);
template<typename T>
class CSelectFieldEqual
{
T Bonus::*ptr;
T val;
public:
CSelectFieldEqual(T Bonus::*Ptr, const T &Val)
: ptr(Ptr), val(Val)
{
}
bool operator()(const Bonus &bonus) const
{
return bonus.*ptr == val;
}
CSelectFieldEqual& operator()(const T &setVal)
{
val = setVal;
return *this;
}
};
class CWillLastTurns
{
public:
int turnsRequested;
bool operator()(const Bonus &bonus) const
{
return !turnsRequested
|| bonus.turnsRemain > turnsRequested && bonus.duration == Bonus::N_TURNS;
}
CWillLastTurns& operator()(const int &setVal)
{
turnsRequested = setVal;
return *this;
}
};
namespace Selector
{
extern DLL_EXPORT CSelectFieldEqual<TBonusType> type;
extern DLL_EXPORT CSelectFieldEqual<TBonusSubtype> subtype;
extern DLL_EXPORT CSelectFieldEqual<si32> info;
extern DLL_EXPORT CSelectFieldEqual<ui8> sourceType;
extern DLL_EXPORT CSelectFieldEqual<ui8> effectRange;
extern DLL_EXPORT CWillLastTurns turns;
CSelector DLL_EXPORT typeSybtype(TBonusType Type, TBonusSubtype Subtype);
CSelector DLL_EXPORT typeSybtypeInfo(TBonusType type, TBonusSubtype subtype, si32 info);
CSelector DLL_EXPORT source(ui8 source, ui32 sourceID);
bool DLL_EXPORT matchesType(const CSelector &sel, TBonusType type);
}

View File

@@ -5,6 +5,7 @@
#include <vector>
#include <set>
#include "../client/FunctionList.h"
#include "CCreatureSet.h"
/*
* IGameCallback.h, part of VCMI engine

View File

@@ -5,6 +5,7 @@
#include "BattleAction.h"
#include "HeroBonus.h"
#include <set>
#include "CCreatureSet.h"
/*
* NetPacks.h, part of VCMI engine
@@ -77,7 +78,7 @@ public:
std::vector<ui8> message; //vector of EMessage
std::vector<std::pair<ui8,ui32> > localStrings; //pairs<text handler type, text number>; types: 1 - generaltexthandler->all; 2 - objh->xtrainfo; 3 - objh->names; 4 - objh->restypes; 5 - arth->artifacts[id].name; 6 - generaltexth->arraytxt; 7 - creh->creatures[os->subID].namePl; 8 - objh->creGens; 9 - objh->mines[ID].first; 10 - objh->mines[ID].second; 11 - objh->advobtxt
std::vector<std::pair<ui8,ui32> > localStrings; //pairs<text handler type, text number>; types: 1 - generaltexthandler->all; 2 - objh->xtrainfo; 3 - objh->names; 4 - objh->restypes; 5 - arth->artifacts[id].name; 6 - generaltexth->arraytxt; 7 - creh->creatures[os->subID].namePl; 8 - objh->creGens; 9 - objh->mines[ID]->first; 10 - objh->mines[ID]->second; 11 - objh->advobtxt
std::vector<std::string> exactStrings;
std::vector<si32> numbers;
@@ -370,7 +371,7 @@ struct GiveBonus : public CPackForClient //115
enum {HERO, PLAYER};
ui8 who; //who receives bonus, uses enum above
ui32 id; //hero or player id
HeroBonus bonus;
Bonus bonus;
MetaString bdescr;
template <typename Handler> void serialize(Handler &h, const int version)
@@ -440,7 +441,7 @@ struct RemoveBonus : public CPackForClient //118
ui32 id; //source id
//used locally: copy of removed bonus
HeroBonus bonus;
Bonus bonus;
template <typename Handler> void serialize(Handler &h, const int version)
{
@@ -573,7 +574,7 @@ struct SetHeroArtifacts : public CPackForClient //509
h & hid & artifacts & artifWorn;
}
std::vector<HeroBonus*> gained, lost; //used locally as hlp when applying
std::vector<Bonus*> gained, lost; //used locally as hlp when applying
};
struct HeroRecruited : public CPackForClient //515
@@ -712,6 +713,12 @@ struct InfoWindow : public CPackForClient //103 - displays simple info window
}
};
namespace ObjProperty
{
//TODO: move non general properties out to the appropriate objs classes
enum {OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6};
}
struct SetObjectProperty : public CPackForClient//1001
{
DLL_EXPORT void applyGs(CGameState *gs);

View File

@@ -52,12 +52,17 @@ DLL_EXPORT void SetResource::applyGs( CGameState *gs )
DLL_EXPORT void SetPrimSkill::applyGs( CGameState *gs )
{
CGHeroInstance *hero = gs->getHero(id);
assert(hero);
if(which <4)
{
Bonus *skill = hero->getBonus(Selector::type(Bonus::PRIMARY_SKILL) && Selector::subtype(which) && Selector::sourceType(Bonus::HERO_BASE_SKILL));
assert(skill);
if(abs)
hero->primSkills[which] = val;
skill->val = val;
else
hero->primSkills[which] += val;
skill->val += val;
}
else if(which == 4) //XP
{
@@ -171,16 +176,16 @@ DLL_EXPORT void SetAvailableHeroes::applyGs( CGameState *gs )
gs->getPlayer(player)->availableHeroes.push_back(h);
if(h && flags & 1)
{
h->army.slots.clear();
h->army.slots[0] = CStackInstance(VLC->creh->nameToID[h->type->refTypeStack[0]],1);
h->clear();
h->addStack(0, CStackInstance(VLC->creh->nameToID[h->type->refTypeStack[0]],1));
}
h = (hid2>=0 ? gs->hpool.heroesPool[hid2] : NULL);
gs->getPlayer(player)->availableHeroes.push_back(h);
if(flags & 2)
{
h->army.slots.clear();
h->army.slots[0] = CStackInstance(VLC->creh->nameToID[h->type->refTypeStack[0]],1);
h->clear();
h->addStack(0, CStackInstance(VLC->creh->nameToID[h->type->refTypeStack[0]],1));
}
}
@@ -209,8 +214,8 @@ DLL_EXPORT void GiveBonus::applyGs( CGameState *gs )
std::string &descr = bonuses->back().description;
if(!bdescr.message.size()
&& bonus.source == HeroBonus::OBJECT
&& (bonus.type == HeroBonus::LUCK || bonus.type == HeroBonus::MORALE || bonus.type == HeroBonus::MORALE_AND_LUCK)
&& bonus.source == Bonus::OBJECT
&& (bonus.type == Bonus::LUCK || bonus.type == Bonus::MORALE)
&& gs->map->objects[bonus.id]->ID == EVENTI_TYPE) //it's morale/luck bonus from an event without description
{
descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle"
@@ -243,9 +248,9 @@ DLL_EXPORT void PlayerEndsGame::applyGs( CGameState *gs )
DLL_EXPORT void RemoveBonus::applyGs( CGameState *gs )
{
std::list<HeroBonus> &bonuses = (who == HERO ? gs->getHero(whoID)->bonuses : gs->getPlayer(whoID)->bonuses);
std::list<Bonus> &bonuses = (who == HERO ? gs->getHero(whoID)->bonuses : gs->getPlayer(whoID)->bonuses);
for(std::list<HeroBonus>::iterator i = bonuses.begin(); i != bonuses.end(); i++)
for(std::list<Bonus>::iterator i = bonuses.begin(); i != bonuses.end(); i++)
{
if(i->source == source && i->id == id)
{
@@ -377,14 +382,14 @@ DLL_EXPORT void SetGarrisons::applyGs( CGameState *gs )
for(std::map<ui32,CCreatureSet>::iterator i = garrs.begin(); i!=garrs.end(); i++)
{
CArmedInstance *ai = static_cast<CArmedInstance*>(gs->map->objects[i->first]);
ai->army = i->second;
ai->setArmy(i->second);
if(ai->ID==TOWNI_TYPE && (static_cast<CGTownInstance*>(ai))->garrisonHero) //if there is a hero in garrison then we must update also his army
const_cast<CGHeroInstance*>((static_cast<CGTownInstance*>(ai))->garrisonHero)->army = i->second;
const_cast<CGHeroInstance*>((static_cast<CGTownInstance*>(ai))->garrisonHero)->setArmy(i->second);
else if(ai->ID==HEROI_TYPE)
{
CGHeroInstance *h = static_cast<CGHeroInstance*>(ai);
if(h->visitedTown && h->inTownGarrison)
h->visitedTown->army = i->second;
h->visitedTown->setArmy(i->second);
}
}
}
@@ -456,7 +461,7 @@ DLL_EXPORT void SetHeroArtifacts::applyGs( CGameState *gs )
continue;
CArtifact &art = VLC->arth->artifacts[id];
for(std::list<HeroBonus>::iterator i = art.bonuses.begin(); i != art.bonuses.end(); i++)
for(std::list<Bonus>::iterator i = art.bonuses.begin(); i != art.bonuses.end(); i++)
{
gained.push_back(&*i);
h->bonuses.push_back(*i);
@@ -476,7 +481,7 @@ DLL_EXPORT void SetHeroArtifacts::applyGs( CGameState *gs )
while(1)
{
std::list<HeroBonus>::iterator hlp = std::find_if(h->bonuses.begin(),h->bonuses.end(),boost::bind(HeroBonus::IsFrom,_1,HeroBonus::ARTIFACT,id));
std::list<Bonus>::iterator hlp = std::find_if(h->bonuses.begin(),h->bonuses.end(),boost::bind(Bonus::IsFrom,_1,Bonus::ARTIFACT,id));
if(hlp != h->bonuses.end())
{
lost.push_back(&*hlp);
@@ -613,11 +618,11 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs )
t->builded = 0;
BOOST_FOREACH(CGHeroInstance *h, gs->map->heroes)
h->bonuses.remove_if(HeroBonus::OneDay);
h->bonuses.remove_if(Bonus::OneDay);
if(gs->getDate(1) == 7) //new week
BOOST_FOREACH(CGHeroInstance *h, gs->map->heroes)
h->bonuses.remove_if(HeroBonus::OneWeek);
h->bonuses.remove_if(Bonus::OneWeek);
//count days without town
for( std::map<ui8, PlayerState>::iterator i=gs->players.begin() ; i!=gs->players.end();i++)
@@ -627,9 +632,9 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs )
else
i->second.daysWithoutCastle++;
i->second.bonuses.remove_if(HeroBonus::OneDay);
i->second.bonuses.remove_if(Bonus::OneDay);
if(gs->getDate(1) == 7) //new week
i->second.bonuses.remove_if(HeroBonus::OneWeek);
i->second.bonuses.remove_if(Bonus::OneWeek);
}
}
@@ -642,7 +647,7 @@ DLL_EXPORT void SetObjectProperty::applyGs( CGameState *gs )
return;
}
if(what == 1)
if(what == ObjProperty::OWNER)
{
if(obj->ID == TOWNI_TYPE)
{
@@ -672,6 +677,7 @@ DLL_EXPORT void HeroLevelUp::applyGs( CGameState *gs )
DLL_EXPORT void BattleStart::applyGs( CGameState *gs )
{
gs->curB = info;
info->belligerents[0]->battle = info->belligerents[1]->battle = info;
}
DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
@@ -685,12 +691,12 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
s->state -= WAITING;
s->state -= MOVED;
s->state -= HAD_MORALE;
s->counterAttacks = 1 + s->valOfFeatures(StackFeature::ADDITIONAL_RETALIATION);
s->counterAttacks = 1 + s->valOfBonuses(Bonus::ADDITIONAL_RETALIATION);
//regeneration
if( s->hasFeatureOfType(StackFeature::HP_REGENERATION) && s->alive() )
s->firstHPleft = std::min<ui32>( s->MaxHealth(), s->valOfFeatures(StackFeature::HP_REGENERATION) );
if( s->hasFeatureOfType(StackFeature::FULL_HP_REGENERATION) && s->alive() )
if( s->hasBonusOfType(Bonus::HP_REGENERATION) && s->alive() )
s->firstHPleft = std::min<ui32>( s->MaxHealth(), s->valOfBonuses(Bonus::HP_REGENERATION) );
if( s->hasBonusOfType(Bonus::FULL_HP_REGENERATION) && s->alive() )
s->firstHPleft = s->MaxHealth();
//remove effects and restore only those with remaining turns in duration
@@ -704,19 +710,20 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
}
//the same as above for features
std::vector<StackFeature> tmpFeatures = s->features;
s->features.clear();
for(int i=0; i < tmpFeatures.size(); i++)
BonusList tmpFeatures = s->bonuses;
s->bonuses.clear();
BOOST_FOREACH(Bonus &b, tmpFeatures)
{
if((tmpFeatures[i].duration & StackFeature::N_TURNS) != 0)
if((b.duration & Bonus::N_TURNS) != 0)
{
tmpFeatures[i].turnsRemain--;
if(tmpFeatures[i].turnsRemain > 0)
s->features.push_back(tmpFeatures[i]);
b.turnsRemain--;
if(b.turnsRemain > 0)
s->bonuses.push_back(b);
}
else
{
s->features.push_back(tmpFeatures[i]);
s->bonuses.push_back(b);
}
}
}
@@ -739,12 +746,13 @@ void BattleResult::applyGs( CGameState *gs )
CGHeroInstance *h;
h = gs->curB->heroes[0];
if(h)
h->bonuses.remove_if(HeroBonus::OneBattle);
h->bonuses.remove_if(Bonus::OneBattle);
h = gs->curB->heroes[1];
if(h)
h->bonuses.remove_if(HeroBonus::OneBattle);
h->bonuses.remove_if(Bonus::OneBattle);
gs->curB->belligerents[0]->battle = gs->curB->belligerents[1]->battle = NULL;
delete gs->curB;
gs->curB = NULL;
}
@@ -757,7 +765,7 @@ void BattleStackMoved::applyGs( CGameState *gs )
DLL_EXPORT void BattleStackAttacked::applyGs( CGameState *gs )
{
CStack * at = gs->curB->getStack(stackAttacked);
at->amount = newAmount;
at->count = newAmount;
at->firstHPleft = newHP;
if(killed())
at->state -= ALIVE;
@@ -773,27 +781,12 @@ DLL_EXPORT void BattleAttack::applyGs( CGameState *gs )
BOOST_FOREACH(BattleStackAttacked stackAttacked, bsa)
stackAttacked.applyGs(gs);
for(int g=0; g<attacker->features.size(); ++g)
{
if((attacker->features[g].duration & StackFeature::UNTIL_ATTACK) != 0)
{
attacker->features.erase(attacker->features.begin() + g);
g = 0;
}
}
attacker->bonuses.remove_if(Bonus::UntilAttack);
for(std::vector<BattleStackAttacked>::const_iterator it = bsa.begin(); it != bsa.end(); ++it)
{
CStack * stack = gs->curB->getStack(it->stackAttacked, false);
for(int g=0; g<stack->features.size(); ++g)
{
if((stack->features[g].duration & StackFeature::UNITL_BEING_ATTACKED) != 0)
{
stack->features.erase(stack->features.begin() + g);
g = 0;
}
}
stack->bonuses.remove_if(Bonus::UntilBeingAttacked);
}
}
@@ -823,6 +816,7 @@ DLL_EXPORT void StartAction::applyGs( CGameState *gs )
DLL_EXPORT void SpellCast::applyGs( CGameState *gs )
{
assert(gs->curB);
CGHeroInstance *h = (side) ? gs->curB->heroes[1] : gs->curB->heroes[0];
if(h)
{
@@ -844,7 +838,7 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs )
}
if(gs->curB && (id == 35 || id == 78)) //dispel and dispel helpful spells
if(id == 35 || id == 78) //dispel and dispel helpful spells
{
bool onlyHelpful = id == 78;
for(std::set<ui32>::const_iterator it = affectedCres.begin(); it != affectedCres.end(); ++it)
@@ -865,14 +859,13 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs )
s->effects = remainingEff; //assigning effects that should remain
//removing all features from spells
std::vector<StackFeature> tmpFeatures = s->features;
s->features.clear();
for(int i=0; i < tmpFeatures.size(); i++)
BonusList tmpFeatures = s->bonuses;
s->bonuses.clear();
BOOST_FOREACH(Bonus &b, tmpFeatures)
{
if(tmpFeatures[i].source != StackFeature::SPELL_EFFECT || tmpFeatures[i].positiveness != 1)
{
s->features.push_back(tmpFeatures[i]);
}
const CSpell *sp = b.sourceSpell();
if(sp && sp->positiveness != 1) //if(b.source != HeroBonus::SPELL_EFFECT || b.positiveness != 1)
s->bonuses.push_back(b);
}
}
}
@@ -904,8 +897,8 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs )
bool ac[BFIELD_SIZE];
std::set<int> occupyable;
bool twoHex = vstd::contains(VLC->creh->creatures[creID].abilities, StackFeature::DOUBLE_WIDE);
bool flying = vstd::contains(VLC->creh->creatures[creID].abilities, StackFeature::FLYING);
bool twoHex = VLC->creh->creatures[creID]->isDoubleWide();
bool flying = vstd::contains(VLC->creh->creatures[creID]->bonuses, Bonus::FLYING);
gs->curB->getAccessibilityMap(ac, twoHex, !side, true, occupyable, flying);
for(int g=0; g<BFIELD_SIZE; ++g)
{
@@ -916,121 +909,126 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs )
}
}
CStack * summonedStack = gs->curB->generateNewStack(h, creID, h->getPrimSkillLevel(2) * VLC->spellh->spells[id].powers[skill], gs->curB->stacks.size(), !side, 255, ter, pos);
summonedStack->features.push_back( makeFeature(StackFeature::SUMMONED, StackFeature::WHOLE_BATTLE, 0, 0, StackFeature::BONUS_FROM_HERO) );
CStack * summonedStack = gs->curB->generateNewStack(CStackInstance(creID, h->getPrimSkillLevel(2) * VLC->spellh->spells[id].powers[skill], h), gs->curB->stacks.size(), !side, 255, ter, pos);
summonedStack->state.insert(SUMMONED);
//summonedStack->bonuses.push_back( makeFeature(HeroBonus::SUMMONED, HeroBonus::ONE_BATTLE, 0, 0, HeroBonus::BONUS_FROM_HERO) );
gs->curB->stacks.push_back(summonedStack);
}
}
static inline StackFeature featureGenerator(StackFeature::ECombatFeatures type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0)
static inline Bonus featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
{
return makeFeature(type, StackFeature::N_TURNS, subtype, value, StackFeature::SPELL_EFFECT, turnsRemain, additionalInfo);
Bonus hb(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo));
hb.effectRange = limit;
return hb;
}
static std::vector<StackFeature> stackEffectToFeature(const CStack::StackEffect & sse)
static inline Bonus featureGeneratorVT(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, ui8 valType)
{
std::vector<StackFeature> sf;
Bonus ret(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain));
ret.valType = valType;
return ret;
}
static BonusList stackEffectToFeature(const CStack::StackEffect & sse)
{
BonusList sf;
si32 power = VLC->spellh->spells[sse.id].powers[sse.level];
switch(sse.id)
{
case 27: //shield
sf.push_back(featureGenerator(StackFeature::GENERAL_DAMAGE_REDUCTION, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
break;
case 28: //air shield
sf.push_back(featureGenerator(StackFeature::GENERAL_DAMAGE_REDUCTION, 1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
break;
case 29: //fire shield
sf.push_back(featureGenerator(StackFeature::FIRE_SHIELD, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain));
break;
case 30: //protection from air
sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
break;
case 31: //protection from fire
sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
break;
case 32: //protection from water
sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 2, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain));
break;
case 33: //protection from earth
sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 3, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain));
break;
case 34: //anti-magic
sf.push_back(featureGenerator(StackFeature::LEVEL_SPELL_IMMUNITY, 0, VLC->spellh->spells[sse.id].powers[sse.level] - 1, sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain));
break;
case 41: //bless
sf.push_back(featureGenerator(StackFeature::ALWAYS_MAXIMUM_DAMAGE, -1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
break;
case 42: //curse
sf.push_back(featureGenerator(StackFeature::ALWAYS_MINIMUM_DAMAGE, -1, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain, sse.level >= 2 ? 20 : 0));
sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.level >= 2 ? 20 : 0));
break;
case 43: //bloodlust
sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT));
break;
case 44: //precision
sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, 1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT));
break;
case 45: //weakness
sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, -1, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain));
break;
case 46: //stone skin
sf.push_back(featureGenerator(StackFeature::DEFENCE_BONUS, -1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
break;
case 47: //disrupting ray
sf.push_back(featureGenerator(StackFeature::DEFENCE_BONUS, -1, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain));
break;
case 48: //prayer
sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(StackFeature::DEFENCE_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(StackFeature::SPEED_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
break;
case 49: //mirth
sf.push_back(featureGenerator(StackFeature::MORALE_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain));
break;
case 50: //sorrow
sf.push_back(featureGenerator(StackFeature::MORALE_BONUS, 0, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain));
break;
case 51: //fortune
sf.push_back(featureGenerator(StackFeature::LUCK_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain));
break;
case 52: //misfortune
sf.push_back(featureGenerator(StackFeature::LUCK_BONUS, 0, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain));
break;
case 53: //haste
sf.push_back(featureGenerator(StackFeature::SPEED_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
break;
case 54: //slow
sf.push_back(featureGenerator(StackFeature::SPEED_BONUS, 0, 0, sse.turnsRemain, -1 * ( 100 - VLC->spellh->spells[sse.id].powers[sse.level] ) ));
sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL));
break;
case 55: //slayer
sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.level, sse.turnsRemain));
break;
case 56: //frenzy
sf.push_back(featureGenerator(StackFeature::IN_FRENZY, 0, sse.level, sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56].powers[sse.level]/100.0, sse.turnsRemain));
break;
case 58: //counterstrike
sf.push_back(featureGenerator(StackFeature::ADDITIONAL_RETALIATION, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain));
break;
case 59: //bersek
sf.push_back(featureGenerator(StackFeature::ATTACKS_NEAREST_CREATURE, 0, sse.level, sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.level, sse.turnsRemain));
break;
case 60: //hypnotize
sf.push_back(featureGenerator(StackFeature::HYPNOTIZED, 0, sse.level, sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.level, sse.turnsRemain));
break;
case 61: //forgetfulness
sf.push_back(featureGenerator(StackFeature::FORGETFULL, 0, sse.level, sse.turnsRemain));
sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.level, sse.turnsRemain));
break;
case 62: //blind
sf.push_back(makeFeature(StackFeature::NOT_ACTIVE, StackFeature::UNITL_BEING_ATTACKED | StackFeature::N_TURNS, 0, 0, StackFeature::SPELL_EFFECT, sse.turnsRemain, 0));
sf.push_back(makeFeature(StackFeature::GENERAL_ATTACK_REDUCTION, StackFeature::UNTIL_ATTACK | StackFeature::N_TURNS, 0, VLC->spellh->spells[sse.id].powers[sse.level], StackFeature::SPELL_EFFECT, sse.turnsRemain, 0));
sf.push_back(makeFeature(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
sf.push_back(makeFeature(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain));
break;
}
//setting positiveness
for(int g=0; g<sf.size(); ++g)
{
sf[g].positiveness = VLC->spellh->spells[sse.id].positiveness;
}
return sf;
}
@@ -1045,14 +1043,15 @@ void actualizeEffect(CStack * s, CStack::StackEffect & ef)
}
}
//actualizing features vector
std::vector<StackFeature> sf = stackEffectToFeature(ef);
for(int b=0; b<sf.size(); ++b)
BonusList sf = stackEffectToFeature(ef);
BOOST_FOREACH(const Bonus &fromEffect, sf)
{
for(int g=0; g<s->features.size(); ++g)
BOOST_FOREACH(Bonus &stackBonus, s->bonuses)
{
if(s->features[g].source == StackFeature::SPELL_EFFECT && s->features[g].type == sf[b].type && s->features[g].subtype == sf[b].subtype)
if(stackBonus.source == Bonus::SPELL_EFFECT && stackBonus.type == fromEffect.type && stackBonus.subtype == fromEffect.subtype)
{
s->features[g].turnsRemain = std::max(s->features[g].turnsRemain, ef.turnsRemain);
stackBonus.turnsRemain = std::max(stackBonus.turnsRemain, ef.turnsRemain);
}
}
}
@@ -1079,10 +1078,10 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
if(effect.id == 42 || !containsEff(s->effects, effect.id))//disrupting ray or not on the list - just add
{
s->effects.push_back(effect);
std::vector<StackFeature> sf = stackEffectToFeature(effect);
for(int n=0; n<sf.size(); ++n)
BonusList sf = stackEffectToFeature(effect);
BOOST_FOREACH(const Bonus &fromEffect, sf)
{
s->features.push_back(sf[n]);
s->bonuses.push_back(fromEffect);
}
}
else //just actualize
@@ -1115,8 +1114,8 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs )
for(int h=0; h<access.size(); ++h)
acc[access[h]] = true;
if(!changedStack->alive() && !gs->curB->isAccessible(changedStack->position, acc,
changedStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE), changedStack->attackerOwned,
changedStack->hasFeatureOfType(StackFeature::FLYING), true))
changedStack->doubleWide(), changedStack->attackerOwned,
changedStack->hasBonusOfType(Bonus::FLYING), true))
return; //position is already occupied
//applying changes
@@ -1125,18 +1124,19 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs )
{
changedStack->state.insert(ALIVE);
if(healedStacks[g].lowLevelResurrection)
changedStack->features.push_back( makeFeature(StackFeature::SUMMONED, StackFeature::WHOLE_BATTLE, 0, 0, StackFeature::BONUS_FROM_HERO) );
changedStack->state.insert(SUMMONED);
//changedStack->bonuses.push_back( makeFeature(HeroBonus::SUMMONED, HeroBonus::ONE_BATTLE, 0, 0, HeroBonus::BONUS_FROM_HERO) );
}
int missingHPfirst = changedStack->MaxHealth() - changedStack->firstHPleft;
int res = std::min( healedStacks[g].healedHP / changedStack->MaxHealth() , changedStack->baseAmount - changedStack->amount );
changedStack->amount += res;
int res = std::min( healedStacks[g].healedHP / changedStack->MaxHealth() , changedStack->baseAmount - changedStack->count );
changedStack->count += res;
changedStack->firstHPleft += healedStacks[g].healedHP - res * changedStack->MaxHealth();
if(changedStack->firstHPleft > changedStack->MaxHealth())
{
changedStack->firstHPleft -= changedStack->MaxHealth();
if(changedStack->baseAmount > changedStack->amount)
if(changedStack->baseAmount > changedStack->count)
{
changedStack->amount += 1;
changedStack->count += 1;
}
}
amin(changedStack->firstHPleft, changedStack->MaxHealth());
@@ -1152,13 +1152,15 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs )
}
//removing all features from negative spells
std::vector<StackFeature> tmpFeatures = changedStack->features;
changedStack->features.clear();
for(int i=0; i < tmpFeatures.size(); i++)
BonusList tmpFeatures = changedStack->bonuses;
changedStack->bonuses.clear();
BOOST_FOREACH(Bonus &b, tmpFeatures)
{
if(tmpFeatures[i].source != StackFeature::SPELL_EFFECT || tmpFeatures[i].positiveness >= 0)
const CSpell *s = b.sourceSpell();
if(s && s->positiveness >= 0)
{
changedStack->features.push_back(tmpFeatures[i]);
changedStack->bonuses.push_back(b);
}
}
}

View File

@@ -1,153 +0,0 @@
#ifndef __STACK_FEATURE_H__
#define __STACK_FEATURE_H__
struct StackFeature
{
#define VCMI_CREATURE_ABILITY_LIST \
VCMI_CREATURE_ABILITY_NAME(NO_TYPE) \
VCMI_CREATURE_ABILITY_NAME(DOUBLE_WIDE) \
VCMI_CREATURE_ABILITY_NAME(FLYING) \
VCMI_CREATURE_ABILITY_NAME(SHOOTER) \
VCMI_CREATURE_ABILITY_NAME(CHARGE_IMMUNITY) \
VCMI_CREATURE_ABILITY_NAME(ADDITIONAL_ATTACK) \
VCMI_CREATURE_ABILITY_NAME(UNLIMITED_RETALIATIONS) \
VCMI_CREATURE_ABILITY_NAME(NO_MELEE_PENALTY) \
VCMI_CREATURE_ABILITY_NAME(JOUSTING) /*for champions*/ \
VCMI_CREATURE_ABILITY_NAME(RAISING_MORALE) /*value - how much raises*/ \
VCMI_CREATURE_ABILITY_NAME(HATE) /*eg. angels hate devils, subtype - ID of hated creature*/ \
VCMI_CREATURE_ABILITY_NAME(KING1) \
VCMI_CREATURE_ABILITY_NAME(KING2) \
VCMI_CREATURE_ABILITY_NAME(KING3) \
VCMI_CREATURE_ABILITY_NAME(MAGIC_RESISTANCE) /*in % (value)*/ \
VCMI_CREATURE_ABILITY_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \
VCMI_CREATURE_ABILITY_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \
VCMI_CREATURE_ABILITY_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - spell level, (additional info)%1000 - chance in %; eg. dendroids, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
VCMI_CREATURE_ABILITY_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
VCMI_CREATURE_ABILITY_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \
VCMI_CREATURE_ABILITY_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
VCMI_CREATURE_ABILITY_NAME(SPELL_DAMAGE_REDUCTION) /*eg. golems; value - reduction in %, subtype - spell school; -1 - all, 0 - air, 1 - fire, 2 - water, 3 - earth*/ \
VCMI_CREATURE_ABILITY_NAME(NO_WALL_PENALTY) \
VCMI_CREATURE_ABILITY_NAME(NON_LIVING) /*eg. gargoyle*/ \
VCMI_CREATURE_ABILITY_NAME(RANDOM_GENIE_SPELLCASTER) /*eg. master genie*/ \
VCMI_CREATURE_ABILITY_NAME(BLOCKS_RETALIATION) /*eg. naga*/ \
VCMI_CREATURE_ABILITY_NAME(SPELL_IMMUNITY) /*subid - spell id*/ \
VCMI_CREATURE_ABILITY_NAME(MANA_CHANNELING) /*value in %, eg. familiar*/ \
VCMI_CREATURE_ABILITY_NAME(SPELL_LIKE_ATTACK) /*value - spell id; range is taken from spell, but damage from creature; eg. magog*/ \
VCMI_CREATURE_ABILITY_NAME(THREE_HEADED_ATTACK) /*eg. cerberus*/ \
VCMI_CREATURE_ABILITY_NAME(DAEMON_SUMMONING) /*pit lord*/ \
VCMI_CREATURE_ABILITY_NAME(FIRE_IMMUNITY) \
VCMI_CREATURE_ABILITY_NAME(FIRE_SHIELD) \
VCMI_CREATURE_ABILITY_NAME(ENEMY_MORALE_DECREASING) /*value - how much it decreases*/ \
VCMI_CREATURE_ABILITY_NAME(ENEMY_LUCK_DECREASING) \
VCMI_CREATURE_ABILITY_NAME(UNDEAD) \
VCMI_CREATURE_ABILITY_NAME(HP_REGENERATION) /*creature regenerates val HP every new round*/ \
VCMI_CREATURE_ABILITY_NAME(FULL_HP_REGENERATION) /*first creature regenerates all HP every new round; subtype 0 - animation 4 (trolllike), 1 - animation 47 (wightlike)*/ \
VCMI_CREATURE_ABILITY_NAME(MANA_DRAIN) /*value - spell points per turn*/ \
VCMI_CREATURE_ABILITY_NAME(LIFE_DRAIN) \
VCMI_CREATURE_ABILITY_NAME(DOUBLE_DAMAGE_CHANCE) /*value in %, eg. dread knight*/ \
VCMI_CREATURE_ABILITY_NAME(RETURN_AFTER_STRIKE) \
VCMI_CREATURE_ABILITY_NAME(SELF_MORALE) /*eg. minotaur*/ \
VCMI_CREATURE_ABILITY_NAME(SPELLCASTER) /*subtype - spell id, value - level of school, additional info - spell power*/ \
VCMI_CREATURE_ABILITY_NAME(CATAPULT) \
VCMI_CREATURE_ABILITY_NAME(ENEMY_DEFENCE_REDUCTION) /*in % (value) eg. behemots*/ \
VCMI_CREATURE_ABILITY_NAME(GENERAL_DAMAGE_REDUCTION) /* shield / air shield effect */ \
VCMI_CREATURE_ABILITY_NAME(GENERAL_ATTACK_REDUCTION) /*eg. while stoned or blinded - in %, subtype: -1 - any damage, 0 - melee damage, 1 - ranged damage*/ \
VCMI_CREATURE_ABILITY_NAME(ATTACKS_ALL_ADJACENT) /*eg. hydra*/ \
VCMI_CREATURE_ABILITY_NAME(MORE_DAMAGE_FROM_SPELL) /*value - damage increase in %, subtype - spell id*/ \
VCMI_CREATURE_ABILITY_NAME(CASTS_SPELL_WHEN_KILLED) /*similar to spell after attack*/ \
VCMI_CREATURE_ABILITY_NAME(FEAR) \
VCMI_CREATURE_ABILITY_NAME(FEARLESS) \
VCMI_CREATURE_ABILITY_NAME(NO_DISTANCE_PENALTY) \
VCMI_CREATURE_ABILITY_NAME(NO_OBSTACLES_PENALTY) \
VCMI_CREATURE_ABILITY_NAME(SELF_LUCK) /*halfling*/ \
VCMI_CREATURE_ABILITY_NAME(ATTACK_BONUS) /*subtype: -1 - any attack, 0 - melee, 1 - ranged*/ \
VCMI_CREATURE_ABILITY_NAME(DEFENCE_BONUS) /*subtype: -1 - any attack, 0 - melee, 1 - ranged*/ \
VCMI_CREATURE_ABILITY_NAME(SPEED_BONUS) /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - substracted to this part*/ \
VCMI_CREATURE_ABILITY_NAME(HP_BONUS) \
VCMI_CREATURE_ABILITY_NAME(ENCHANTER) \
VCMI_CREATURE_ABILITY_NAME(HEALER) \
VCMI_CREATURE_ABILITY_NAME(SIEGE_WEAPON) \
VCMI_CREATURE_ABILITY_NAME(LUCK_BONUS) \
VCMI_CREATURE_ABILITY_NAME(MORALE_BONUS) \
VCMI_CREATURE_ABILITY_NAME(HYPNOTIZED) \
VCMI_CREATURE_ABILITY_NAME(ADDITIONAL_RETALIATION) /*value - number of additional retaliations*/ \
VCMI_CREATURE_ABILITY_NAME(MAGIC_MIRROR) /* value - chance of redirecting in %*/ \
VCMI_CREATURE_ABILITY_NAME(SUMMONED) \
VCMI_CREATURE_ABILITY_NAME(ALWAYS_MINIMUM_DAMAGE) /*unit does its minimum damage from range; subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative anti-bonus for dmg in % [eg 20 means that creature will inflict 80% of normal dmg]*/ \
VCMI_CREATURE_ABILITY_NAME(ALWAYS_MAXIMUM_DAMAGE) /*eg. bless effect, subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative bonus for dmg in %*/ \
VCMI_CREATURE_ABILITY_NAME(ATTACKS_NEAREST_CREATURE) /*while in berserk*/ \
VCMI_CREATURE_ABILITY_NAME(IN_FRENZY) /*value - level*/ \
VCMI_CREATURE_ABILITY_NAME(SLAYER) /*value - level*/ \
VCMI_CREATURE_ABILITY_NAME(FORGETFULL) /*forgetfullnes spell effect, value - level*/ \
VCMI_CREATURE_ABILITY_NAME(CLONED) \
VCMI_CREATURE_ABILITY_NAME(NOT_ACTIVE) \
VCMI_CREATURE_ABILITY_NAME(NO_LUCK) /*eg. when fighting on cursed ground*/ \
VCMI_CREATURE_ABILITY_NAME(NO_MORALE) /*eg. when fighting on cursed ground*/
//general list of stack abilities and effects
enum ECombatFeatures
{
#define VCMI_CREATURE_ABILITY_NAME(x) x,
VCMI_CREATURE_ABILITY_LIST
#undef VCMI_CREATURE_ABILITY_NAME
};
enum EDuration
{
WHOLE_BATTLE = 1,
N_TURNS = 2,
UNITL_BEING_ATTACKED = 4,/*removed after attack and counterattacks are performed*/
UNTIL_ATTACK = 8 /*removed after attack and counterattacks are performed*/
};
enum ESource
{
CREATURE_ABILITY,
BONUS_FROM_HERO,
SPELL_EFFECT,
OTHER_SOURCE /*eg. bonus from terrain if native*/
};
ui8 type;//ECombatFeatures
ui8 duration;//EDuration //bitfield
ui8 source;//ESource
si8 positiveness; //+1 - positive, 0 - neutral, -1 - negative; used mostly for spell features
ui16 turnsRemain; //if duration is N_TURNS it describes how long the effect will last
si16 subtype; //subtype of bonus/feature
si32 value;
si32 additionalInfo;
inline bool operator == (const ECombatFeatures & cf) const
{
return type == cf;
}
StackFeature() : type(NO_TYPE)
{}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & type & duration & source & positiveness & turnsRemain & subtype & value & additionalInfo;
}
};
//generates StackFeature from given data
inline StackFeature makeFeature(StackFeature::ECombatFeatures type, ui8 duration, si16 subtype, si32 value, StackFeature::ESource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
{
StackFeature sf;
sf.type = type;
sf.duration = duration;
sf.source = source;
sf.turnsRemain = turnsRemain;
sf.subtype = subtype;
sf.value = value;
sf.additionalInfo = additionalInfo;
return sf;
}
inline StackFeature makeCreatureAbility(StackFeature::ECombatFeatures type, si32 value, si16 subtype = 0, si32 additionalInfo = 0)
{
return makeFeature(type, StackFeature::WHOLE_BATTLE, subtype, value, StackFeature::CREATURE_ABILITY, 0, additionalInfo);
}
#endif //__STACK_FEATURE_H__

View File

@@ -152,18 +152,21 @@ static CCreatureSet readCreatureSet(const unsigned char * bufor, int &i, int num
{
int creID = readNormalNr(bufor,i+ir*bytesPerCre, idBytes);
int count = readNormalNr(bufor,i+ir*bytesPerCre+idBytes, 2);
if(creID == maxID) //empty slot
continue;
CStackInstance hlp;
hlp.count = count;
if(creID > maxID - 0xf)
{
creID = maxID + 1 - creID + VLC->creh->creatures.size();//this will happen when random object has random army
ret.slots[ir].idRand = creID;
hlp.idRand = creID;
}
else
ret.slots[ir].setType(creID);
hlp.setType(creID);
ret.slots[ir].count = count;
ret.slots[ir] = hlp;
}
i+=number*bytesPerCre;
@@ -704,8 +707,8 @@ void Mapa::loadTown( CGObjectInstance * &nobj, const unsigned char * bufor, int
if(readChar(bufor,i)) //has name
nt->name = readString(bufor,i);
if(readChar(bufor,i))//true if garrison isn't empty
nt->army = readCreatureSet(bufor,i,7,(version>RoE));
nt->army.formation = bufor[i]; ++i;
nt->setArmy(readCreatureSet(bufor, i, 7, version > RoE));
nt->formation = bufor[i]; ++i;
if(readChar(bufor,i)) //custom buildings info
{
//built buildings
@@ -889,9 +892,9 @@ void Mapa::loadHero( CGObjectInstance * &nobj, const unsigned char * bufor, int
}
}
if(readChar(bufor,i))//true if hero has nonstandard garrison
nhi->army = readCreatureSet(bufor,i,7,(version>RoE));
nhi->setArmy(readCreatureSet(bufor, i, 7, version > RoE));
nhi->army.formation =bufor[i]; ++i; //formation
nhi->formation =bufor[i]; ++i; //formation
bool artSet = bufor[i]; ++i; //true if artifact set is not default (hero has some artifacts)
int artmask = version == RoE ? 0xff : 0xffff;
int artidlen = version == RoE ? 1 : 2;
@@ -988,9 +991,8 @@ void Mapa::loadHero( CGObjectInstance * &nobj, const unsigned char * bufor, int
{
if(readChar(bufor,i))//customPrimSkills
{
nhi->primSkills.resize(4);
for(int xx=0;xx<4;xx++)
nhi->primSkills[xx] = bufor[i++];
nhi->pushPrimSkill(xx, bufor[i++]);
}
}
i+=16;
@@ -1197,9 +1199,8 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i)
}
if(readChar(bufor,i))//customPrimSkills
{
cgh->primSkills.resize(4);
for(int xx=0;xx<4;xx++)
cgh->primSkills[xx] = bufor[i++];
cgh->pushPrimSkill(xx, bufor[i++]);
}
predefinedHeroes.push_back(cgh);
}
@@ -1375,7 +1376,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
}
if(bufor[i++])
{
evnt->army = readCreatureSet(bufor,i,7,(version>RoE));
evnt->setArmy(readCreatureSet(bufor, i, 7, version > RoE));
}
i+=4;
}
@@ -1485,7 +1486,12 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
cre->identifier = readNormalNr(bufor,i); i+=4;
monsters[cre->identifier] = cre;
}
cre->army.slots[0].count = readNormalNr(bufor,i, 2); i+=2;
CStackInstance hlp;
hlp.count = readNormalNr(bufor,i, 2); i+=2;
//type will be set during initialization
cre->slots[0] = hlp;
cre->character = bufor[i]; ++i;
bool isMesTre = bufor[i]; ++i; //true if there is message or treasury
if(isMesTre)
@@ -1575,7 +1581,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
nobj = gar;
nobj->setOwner(bufor[i++]);
i+=3;
gar->army = readCreatureSet(bufor,i,7,(version>RoE));
gar->setArmy(readCreatureSet(bufor, i, 7, version > RoE));
if(version > RoE)
{
gar->removableUnits = bufor[i]; ++i;
@@ -1599,7 +1605,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
bool areGuards = bufor[i]; ++i;
if(areGuards)
{
art->army = readCreatureSet(bufor,i,7,(version>RoE));
art->setArmy(readCreatureSet(bufor, i, 7, version > RoE));
}
i+=4;
}
@@ -1621,7 +1627,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
res->message = readString(bufor,i);
if(bufor[i++])
{
res->army = readCreatureSet(bufor,i,7,(version>RoE));
res->setArmy(readCreatureSet(bufor, i, 7, version > RoE));
}
i+=4;
}
@@ -1675,7 +1681,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
box->message = readString(bufor,i);
if(bufor[i++])
{
box->army = readCreatureSet(bufor,i,7,(version>RoE));
box->setArmy(readCreatureSet(bufor, i, 7, version > RoE));
}
i+=4;
}

View File

@@ -101,7 +101,7 @@ static void giveExp(BattleResult &r)
r.exp[1] = 0;
for(std::map<ui32,si32>::iterator i = r.casualties[!r.winner].begin(); i!=r.casualties[!r.winner].end(); i++)
{
r.exp[r.winner] += VLC->creh->creatures[i->first].hitPoints * i->second;
r.exp[r.winner] += VLC->creh->creatures[i->first]->valOfBonuses(Bonus::STACK_HEALTH) * i->second;
}
}
@@ -302,19 +302,20 @@ static CCreatureSet takeCasualties(int color, const CCreatureSet &set, BattleInf
{
if(color == 254)
color = 255;
CCreatureSet ret(set);
for(int i=0; i<bat->stacks.size();i++)
{
if(bat->stacks[i]->hasFeatureOfType(StackFeature::SUMMONED)) //don't take into account sumoned stacks
CStack *st = bat->stacks[i];
if(vstd::contains(st->state, SUMMONED)) //don't take into account sumoned stacks
continue;
CStack *st = bat->stacks[i];
if(st->owner==color && vstd::contains(set.slots,st->slot) && st->amount < set.slots.find(st->slot)->second.count)
if(st->owner==color && !set.slotEmpty(st->slot) && st->count < set.getAmount(st->slot))
{
if(st->alive())
ret.slots[st->slot].count = st->amount;
ret.setStackCount(st->slot, st->count);
else
ret.slots.erase(st->slot);
ret.eraseStack(st->slot);
}
}
return ret;
@@ -331,7 +332,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
curB->side2 = army2->tempOwner;
if(curB->side2 == 254)
curB->side2 = 255;
setupBattle(curB, tile, army1->army, army2->army, hero1, hero2, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
setupBattle(curB, tile, army1, army2, hero1, hero2, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
}
NEW_ROUND;
@@ -360,11 +361,12 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
{
//check for bad morale => freeze
if( curB.Morale(next) < 0 &&
!(NBonus::hasOfType(hero1, HeroBonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, HeroBonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses)
int nextStackMorale = next->MoraleVal();
if( nextStackMorale < 0 &&
!(NBonus::hasOfType(hero1, Bonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, Bonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses)
)
{
if( rand()%24 < (-curB.Morale(next))*2 )
if( rand()%24 < -2 * nextStackMorale)
{
//unit loses its turn - empty freeze action
BattleAction ba;
@@ -379,7 +381,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
}
}
if(next->hasFeatureOfType(StackFeature::ATTACKS_NEAREST_CREATURE)) //while in berserk
if(next->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE)) //while in berserk
{
std::pair<const CStack *, int> attackInfo = curB.getNearestStack(next, boost::logic::indeterminate);
if(attackInfo.first != NULL)
@@ -402,7 +404,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
const CGHeroInstance * curOwner = gs->battleGetOwner(next->ID);
if( (next->position < 0 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //arrow turret, hero has no ballistics
|| (next->creature->idNumber == 146 && curOwner->getSecSkillLevel(20) == 0)) //ballista, hero has no artillery
|| (next->type->idNumber == 146 && curOwner->getSecSkillLevel(20) == 0)) //ballista, hero has no artillery
{
BattleAction attack;
attack.actionType = 7;
@@ -424,7 +426,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
continue;
}
if(next->creature->idNumber == 145 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //catapult, hero has no ballistics
if(next->type->idNumber == 145 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //catapult, hero has no ballistics
{
BattleAction attack;
static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95};
@@ -439,7 +441,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
continue;
}
if(next->creature->idNumber == 147 && (!curOwner || curOwner->getSecSkillLevel(27) == 0)) //first aid tent, hero has no first aid
if(next->type->idNumber == 147 && (!curOwner || curOwner->getSecSkillLevel(27) == 0)) //first aid tent, hero has no first aid
{
BattleAction heal;
@@ -503,14 +505,15 @@ askInterfaceForMove:
checkForBattleEnd(stacks); //check if this action ended the battle
//check for good morale
nextStackMorale = next->MoraleVal();
if(!vstd::contains(next->state,HAD_MORALE) //only one extra move per turn possible
&& !vstd::contains(next->state,DEFENDING)
&& !vstd::contains(next->state,WAITING)
&& next->alive()
&& curB.Morale(next) > 0
&& !(NBonus::hasOfType(hero1, HeroBonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, HeroBonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses
&& nextStackMorale > 0
&& !(NBonus::hasOfType(hero1, Bonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, Bonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses
)
if(rand()%24 < curB.Morale(next)) //this stack hasn't got morale this turn
if(rand()%24 < nextStackMorale) //this stack hasn't got morale this turn
goto askInterfaceForMove; //move this stack once more
}
}
@@ -533,8 +536,8 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
//casualties among heroes armies
SetGarrisons sg;
sg.garrs[bEndArmy1->id] = takeCasualties(bEndArmy1->tempOwner, bEndArmy1->army, gs->curB);
sg.garrs[bEndArmy2->id] = takeCasualties(bEndArmy2->tempOwner, bEndArmy2->army, gs->curB);
sg.garrs[bEndArmy1->id] = takeCasualties(bEndArmy1->tempOwner, *bEndArmy1, gs->curB);
sg.garrs[bEndArmy2->id] = takeCasualties(bEndArmy2->tempOwner, *bEndArmy2, gs->curB);
sendAndApply(&sg);
ui8 sides[2];
@@ -581,17 +584,18 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
// Give raised units to winner and show dialog, if any were raised.
if (raisedStack.type)
{
int slot = winnerHero->army.getSlotFor(raisedStack.type->idNumber);
int slot = winnerHero->getSlotFor(raisedStack.type->idNumber);
if (slot != -1)
{
SetGarrisons sg;
sg.garrs[winnerHero->id] = winnerHero->getArmy();
sg.garrs[winnerHero->id].addToSlot(slot, raisedStack);
sg.garrs[winnerHero->id] = winnerHero->army;
if (vstd::contains(winnerHero->army.slots, slot)) // Add to existing stack.
sg.garrs[winnerHero->id].slots[slot].count += raisedStack.count;
else // Create a new stack.
sg.garrs[winnerHero->id].slots[slot] = raisedStack;
// if (vstd::contains(winnerHero->slots, slot)) // Add to existing stack.
// sg.garrs[winnerHero->id].slots[slot].count += raisedStack.count;
// else // Create a new stack.
// sg.garrs[winnerHero->id].slots[slot] = raisedStack;
winnerHero->showNecromancyDialog(raisedStack);
sendAndApply(&sg);
}
@@ -617,15 +621,15 @@ void CGameHandler::prepareAttacked(BattleStackAttacked &bsa, const CStack *def)
bsa.newHP = def->firstHPleft - damageFirst;
}
if(def->amount <= bsa.killedAmount) //stack killed
if(def->count <= bsa.killedAmount) //stack killed
{
bsa.newAmount = 0;
bsa.flags |= 1;
bsa.killedAmount = def->amount; //we cannot kill more creatures than we have
bsa.killedAmount = def->count; //we cannot kill more creatures than we have
}
else
{
bsa.newAmount = def->amount - bsa.killedAmount;
bsa.newAmount = def->count - bsa.killedAmount;
}
}
@@ -637,7 +641,8 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
BattleStackAttacked *bsa = &bat.bsa.back();
bsa->stackAttacked = def->ID;
bsa->attackerID = att->ID;
if(gs->curB->Luck(att) > 0 && rand()%24 < gs->curB->Luck(att))
int attackerLuck = att->LuckVal();
if(attackerLuck > 0 && rand()%24 < attackerLuck) //TODO?: negative luck option?
{
bsa->damageAmount *= 2;
bat.flags |= 4;
@@ -650,7 +655,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
prepareAttacked(*bsa, def);
//fire shield handling
if ( !bat.shot() && def->hasFeatureOfType(StackFeature::FIRE_SHIELD) && !bsa->killed() )
if ( !bat.shot() && def->hasBonusOfType(Bonus::FIRE_SHIELD) && !bsa->killed() )
{
bat.bsa.push_back(BattleStackAttacked());
BattleStackAttacked *bsa = &bat.bsa.back();
@@ -659,7 +664,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
bsa->flags |= 2;
bsa->effect = 11;
bsa->damageAmount = (dmg * def->valOfFeatures(StackFeature::FIRE_SHIELD)) / 100;
bsa->damageAmount = (dmg * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100;
prepareAttacked(*bsa, att);
}
}
@@ -739,7 +744,7 @@ int CGameHandler::moveStack(int stack, int dest)
}
//shifting destination (if we have double wide stack and we can occupy dest but not be exactly there)
if(!stackAtEnd && curStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && !accessibility[dest])
if(!stackAtEnd && curStack->doubleWide() && !accessibility[dest])
{
if(curStack->attackerOwned)
{
@@ -770,11 +775,11 @@ int CGameHandler::moveStack(int stack, int dest)
//if(dists[dest] > curStack->creature->speed && !(stackAtEnd && dists[dest] == curStack->creature->speed+1)) //we can attack a stack if we can go to adjacent hex
// return false;
std::pair< std::vector<int>, int > path = gs->curB->getPath(curStack->position, dest, accessibilityWithOccupyable, curStack->hasFeatureOfType(StackFeature::FLYING), curStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE), curStack->attackerOwned);
std::pair< std::vector<int>, int > path = gs->curB->getPath(curStack->position, dest, accessibilityWithOccupyable, curStack->hasBonusOfType(Bonus::FLYING), curStack->doubleWide(), curStack->attackerOwned);
ret = path.second;
if(curStack->hasFeatureOfType(StackFeature::FLYING))
if(curStack->hasBonusOfType(Bonus::FLYING))
{
if(path.second <= curStack->Speed() && path.first.size() > 0)
{
@@ -912,8 +917,8 @@ void CGameHandler::newTurn()
break;
}
for(std::list<HeroBonus>::iterator j = h->bonuses.begin(); j != h->bonuses.end(); j++)
if(j->type == HeroBonus::GENERATE_RESOURCE)
for(std::list<Bonus>::iterator j = h->bonuses.begin(); j != h->bonuses.end(); j++)
if(j->type == Bonus::GENERATE_RESOURCE)
n.res[i->first][j->subtype] += j->val;
//TODO player bonuses
@@ -939,7 +944,7 @@ void CGameHandler::newTurn()
{
sac.creatures[k].first += (**j).creatureGrowth(k);
if(!gs->getDate(0)) //first day of game: use only basic growths
amin(sac.creatures[k].first, VLC->creh->creatures[(*j)->town->basicCreatures[k]].growth);
amin(sac.creatures[k].first, VLC->creh->creatures[(*j)->town->basicCreatures[k]]->growth);
}
}
n.cres.push_back(sac);
@@ -1007,7 +1012,8 @@ void CGameHandler::newTurn()
}
}
void CGameHandler::run(bool resume)
{
{
using namespace boost::posix_time;
BOOST_FOREACH(CConnection *cc, conns)
{//init conn.
ui8 quantity, pom;
@@ -1050,7 +1056,6 @@ void CGameHandler::run(bool resume)
resume = false;
for(; i != gs->players.end(); i++)
{
if(i->second.towns.size()==0 && i->second.heroes.size()==0
|| i->second.color<0
|| i->first>=PLAYER_LIMIT
@@ -1070,8 +1075,7 @@ void CGameHandler::run(bool resume)
boost::unique_lock<boost::mutex> lock(states.mx);
while(states.players[i->first].makingTurn && !end2)
{
boost::posix_time::time_duration p;
p = boost::posix_time::milliseconds(200);
static time_duration p = milliseconds(200);
states.cv.timed_wait(lock,p);
}
}
@@ -1099,14 +1103,14 @@ namespace CGH
}
}
void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet &army1, const CCreatureSet &army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town)
void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstance *army1, const CArmedInstance *army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town)
{
battleResult.set(NULL);
std::vector<CStack*> & stacks = (curB->stacks);
curB->tile = tile;
curB->army1=army1;
curB->army2=army2;
curB->belligerents[0] = const_cast<CArmedInstance*>(army1);
curB->belligerents[1] = const_cast<CArmedInstance*>(army2);
curB->heroes[0] = const_cast<CGHeroInstance*>(hero1);
curB->heroes[1] = const_cast<CGHeroInstance*>(hero2);
curB->round = -2;
@@ -1150,42 +1154,42 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
//battleStartpos read
int k = 0; //stack serial
for(TSlots::const_iterator i = army1.slots.begin(); i!=army1.slots.end(); i++, k++)
for(TSlots::const_iterator i = army1->Slots().begin(); i!=army1->Slots().end(); i++, k++)
{
int pos;
if(creatureBank)
pos = attackerCreBank[army1.slots.size()-1][k];
else if(army1.formation)
pos = attackerTight[army1.slots.size()-1][k];
pos = attackerCreBank[army1->stacksCount()-1][k];
else if(army1->formation)
pos = attackerTight[army1->stacksCount()-1][k];
else
pos = attackerLoose[army1.slots.size()-1][k];
pos = attackerLoose[army1->stacksCount()-1][k];
CStack * stack = curB->generateNewStack(hero1, i->second.type->idNumber, i->second.count, stacks.size(), true, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos);
CStack * stack = curB->generateNewStack(i->second, stacks.size(), true, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos);
stacks.push_back(stack);
}
k = 0;
for(TSlots::const_iterator i = army2.slots.begin(); i!=army2.slots.end(); i++, k++)
for(TSlots::const_iterator i = army2->Slots().begin(); i!=army2->Slots().end(); i++, k++)
{
int pos;
if(creatureBank)
pos = defenderCreBank[army2.slots.size()-1][k];
else if(army2.formation)
pos = defenderTight[army2.slots.size()-1][k];
pos = defenderCreBank[army2->stacksCount()-1][k];
else if(army2->formation)
pos = defenderTight[army2->stacksCount()-1][k];
else
pos = defenderLoose[army2.slots.size()-1][k];
pos = defenderLoose[army2->stacksCount()-1][k];
CStack * stack = curB->generateNewStack(hero2, i->second.type->idNumber, i->second.count, stacks.size(), false, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos);
CStack * stack = curB->generateNewStack(i->second, stacks.size(), false, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos);
stacks.push_back(stack);
}
for(unsigned g=0; g<stacks.size(); ++g) //shifting positions of two-hex creatures
{
if((stacks[g]->position%17)==1 && stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && stacks[g]->attackerOwned)
if((stacks[g]->position%17)==1 && stacks[g]->doubleWide() && stacks[g]->attackerOwned)
{
stacks[g]->position += 1;
}
else if((stacks[g]->position%17)==15 && stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && !stacks[g]->attackerOwned)
else if((stacks[g]->position%17)==15 && stacks[g]->doubleWide() && !stacks[g]->attackerOwned)
{
stacks[g]->position -= 1;
}
@@ -1196,17 +1200,17 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
{
if(hero1->getArt(13)) //ballista
{
CStack * stack = curB->generateNewStack(hero1, 146, 1, stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 52);
CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 52);
stacks.push_back(stack);
}
if(hero1->getArt(14)) //ammo cart
{
CStack * stack = curB->generateNewStack(hero1, 148, 1, stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 18);
CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 18);
stacks.push_back(stack);
}
if(hero1->getArt(15)) //first aid tent
{
CStack * stack = curB->generateNewStack(hero1, 147, 1, stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 154);
CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 154);
stacks.push_back(stack);
}
}
@@ -1214,23 +1218,23 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
{
if(hero2->getArt(13)) //ballista
{
CStack * stack = curB->generateNewStack(hero2, 146, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 66);
CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 66);
stacks.push_back(stack);
}
if(hero2->getArt(14)) //ammo cart
{
CStack * stack = curB->generateNewStack(hero2, 148, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 32);
CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 32);
stacks.push_back(stack);
}
if(hero2->getArt(15)) //first aid tent
{
CStack * stack = curB->generateNewStack(hero2, 147, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 168);
CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 168);
stacks.push_back(stack);
}
}
if(town && hero1 && town->hasFort()) //catapult
{
CStack * stack = curB->generateNewStack(hero1, 145, 1, stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 120);
CStack * stack = curB->generateNewStack(CStackInstance(145, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 120);
stacks.push_back(stack);
}
//war machines added
@@ -1240,14 +1244,14 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
case 3: //castle
{//lower tower / upper tower
CStack * stack = curB->generateNewStack(hero2, 149, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -4);
CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -4);
stacks.push_back(stack);
stack = curB->generateNewStack(hero2, 149, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -3);
stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -3);
stacks.push_back(stack);
}
case 2: //citadel
{//main tower
CStack * stack = curB->generateNewStack(hero2, 149, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -2);
CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -2);
stacks.push_back(stack);
}
}
@@ -1335,7 +1339,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
if (val)
{
GiveBonus gs;
gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::PRIMARY_SKILL, HeroBonus::OBJECT, val, -1, "", i);
gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::PRIMARY_SKILL, Bonus::OBJECT, val, -1, "", i);
gs.id = hero2->id;
sendAndApply(&gs);
}
@@ -1345,15 +1349,15 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
{
if(town->subID == 0 && vstd::contains(town->builtBuildings,22)) //castle, brotherhood of sword built
for(int g=0; g<stacks.size(); ++g)
stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, 2, StackFeature::OTHER_SOURCE));
stacks[g]->bonuses.push_back(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]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE));
stacks[g]->bonuses.push_back(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]->features.push_back(makeFeature(StackFeature::LUCK_BONUS, StackFeature::WHOLE_BATTLE, 0, 2, StackFeature::OTHER_SOURCE));
stacks[g]->bonuses.push_back(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, 2, Bonus::TOWN_STRUCTURE));
}
}
@@ -1393,7 +1397,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
if(cHero == NULL) continue;
GiveBonus gs;
gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::MAGIC_SCHOOL_SKILL, HeroBonus::OBJECT, 3, -1, "", bonusSubtype);
gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL, Bonus::OBJECT, 3, -1, "", bonusSubtype);
gs.id = cHero->id;
sendAndApply(&gs);
@@ -1406,10 +1410,10 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
{
for(int g=0; g<stacks.size(); ++g) //+1 morale bonus for good creatures, -1 morale bonus for evil creatures
{
if (stacks[g]->creature->isGood())
stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE));
else if (stacks[g]->creature->isEvil())
stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, -1, StackFeature::OTHER_SOURCE));
if (stacks[g]->type->isGood())
stacks[g]->bonuses.push_back(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY));
else if (stacks[g]->type->isEvil())
stacks[g]->bonuses.push_back(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY));
}
break;
}
@@ -1417,9 +1421,9 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
{
for(int g=0; g<stacks.size(); ++g)
{
if(stacks[g]->creature->faction == -1) //+2 luck bonus for neutral creatures
if(stacks[g]->type->faction == -1) //+2 luck bonus for neutral creatures
{
stacks[g]->features.push_back(makeFeature(StackFeature::LUCK_BONUS, StackFeature::WHOLE_BATTLE, 0, 2, StackFeature::OTHER_SOURCE));
stacks[g]->bonuses.push_back(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, 2, Bonus::TERRAIN_OVERLAY));
}
}
break;
@@ -1428,10 +1432,10 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
{
for(int g=0; g<stacks.size(); ++g) //-1 morale bonus for good creatures, +1 morale bonus for evil creatures
{
if (stacks[g]->creature->isGood())
stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, -1, StackFeature::OTHER_SOURCE));
else if (stacks[g]->creature->isEvil())
stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE));
if (stacks[g]->type->isGood())
stacks[g]->bonuses.push_back(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY));
else if (stacks[g]->type->isEvil())
stacks[g]->bonuses.push_back(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY));
}
break;
}
@@ -1439,8 +1443,8 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
{
for(int g=0; g<stacks.size(); ++g) //no luck nor morale
{
stacks[g]->features.push_back(makeFeature(StackFeature::NO_MORALE, StackFeature::WHOLE_BATTLE, 0, 0, StackFeature::OTHER_SOURCE));
stacks[g]->features.push_back(makeFeature(StackFeature::NO_LUCK, StackFeature::WHOLE_BATTLE, 0, 0, StackFeature::OTHER_SOURCE));
stacks[g]->bonuses.push_back(makeFeature(Bonus::NO_MORALE, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY));
stacks[g]->bonuses.push_back(makeFeature(Bonus::NO_LUCK, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY));
}
const CGHeroInstance * cHero = NULL;
@@ -1452,7 +1456,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
if(cHero == NULL) continue;
GiveBonus gs;
gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL, HeroBonus::OBJECT, 1, -1, "", bonusSubtype);
gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::BLOCK_SPELLS_ABOVE_LEVEL, Bonus::OBJECT, 1, -1, "", bonusSubtype);
gs.id = cHero->id;
sendAndApply(&gs);
@@ -1478,7 +1482,7 @@ void CGameHandler::checkForBattleEnd( std::vector<CStack*> &stacks )
hasStack[0] = hasStack[1] = false;
for(int b = 0; b<stacks.size(); ++b)
{
if(stacks[b]->alive() && !stacks[b]->hasFeatureOfType(StackFeature::SIEGE_WEAPON))
if(stacks[b]->alive() && !stacks[b]->hasBonusOfType(Bonus::SIEGE_WEAPON))
{
hasStack[1-stacks[b]->attackerOwned] = true;
}
@@ -1772,19 +1776,19 @@ void CGameHandler::giveResource(int player, int which, int val)
}
void CGameHandler::giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures)
{
if (creatures.slots.size() <= 0)
if (creatures.stacksCount() <= 0)
return;
CCreatureSet heroArmy = h->army;
while (creatures.slots.size() > 0)
CCreatureSet heroArmy = h->getArmy();
while (creatures.stacksCount() > 0)
{
int slot = heroArmy.getSlotFor(creatures.slots.begin()->second.type->idNumber);
int slot = heroArmy.getSlotFor(creatures.Slots().begin()->second.type->idNumber);
if (slot < 0)
break;
heroArmy.addToSlot(slot, creatures.slots.begin()->second);
creatures.slots.erase (creatures.slots.begin());
}
if (creatures.slots.size() == 0) //all creatures can be moved to hero army - do that
if (creatures.stacksCount() == 0) //all creatures can be moved to hero army - do that
{
SetGarrisons sg;
sg.garrs[h->id] = heroArmy;
@@ -1804,7 +1808,7 @@ void CGameHandler::takeCreatures (int objid, TSlots creatures) //probably we cou
if (creatures.size() <= 0)
return;
const CArmedInstance* obj = static_cast<const CArmedInstance*>(getObj(objid));
CCreatureSet newArmy = obj->army;
CCreatureSet newArmy = obj->getArmy();
while (creatures.size() > 0)
{
int slot = newArmy.getSlotFor(creatures.begin()->second.type->idNumber);
@@ -2227,7 +2231,7 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2,
{
CArmedInstance *s1 = static_cast<CArmedInstance*>(gs->map->objects[id1]),
*s2 = static_cast<CArmedInstance*>(gs->map->objects[id2]);
CCreatureSet temp1 = s1->army, temp2 = s2->army,
CCreatureSet temp1 = s1->getArmy(), temp2 = s2->getArmy(),
&S1 = temp1, &S2 = (s1!=s2)?(temp2):(temp1);
if(!isAllowedExchange(id1,id2))
@@ -2295,8 +2299,8 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2,
if(!S1.slots[p1].count) //if we've moved all creatures
S1.slots.erase(p1);
}
if((s1->needsLastStack() && !S1.slots.size()) //it's not allowed to take last stack from hero army!
|| (s2->needsLastStack() && !S2.slots.size())
if((s1->needsLastStack() && !S1.stacksCount()) //it's not allowed to take last stack from hero army!
|| (s2->needsLastStack() && !S2.stacksCount())
)
{
complain("Cannot take the last stack!");
@@ -2339,14 +2343,14 @@ int CGameHandler::getPlayerAt( CConnection *c ) const
bool CGameHandler::disbandCreature( si32 id, ui8 pos )
{
CArmedInstance *s1 = static_cast<CArmedInstance*>(gs->map->objects[id]);
if(!vstd::contains(s1->army.slots,pos))
if(!vstd::contains(s1->slots,pos))
{
complain("Illegal call to disbandCreature - no such stack in army!");
return false;
}
s1->army.slots.erase(pos);
s1->slots.erase(pos);
SetGarrisons sg;
sg.garrs[id] = s1->army;
sg.garrs[id] = s1->getArmy();
sendAndApply(&sg);
return true;
}
@@ -2398,7 +2402,7 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid )
SetAvailableCreatures ssi;
ssi.tid = tid;
ssi.creatures = t->creatures;
ssi.creatures[bid-30].first = VLC->creh->creatures[crid].growth;
ssi.creatures[bid-30].first = VLC->creh->creatures[crid]->growth;
ssi.creatures[bid-30].second.push_back(crid);
sendAndApply(&ssi);
}
@@ -2495,10 +2499,10 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram )
break;
}
}
int slot = dst->army.getSlotFor(crid);
int slot = dst-> getSlotFor(crid);
if(!found && complain("Cannot recruit: no such creatures!")
|| cram > VLC->creh->creatures[crid].maxAmount(gs->getPlayer(dst->tempOwner)->resources) && complain("Cannot recruit: lack of resources!")
|| cram > VLC->creh->creatures[crid]->maxAmount(gs->getPlayer(dst->tempOwner)->resources) && complain("Cannot recruit: lack of resources!")
|| cram<=0 && complain("Cannot recruit: cram <= 0!")
|| slot<0 && complain("Cannot recruit: no available slot!"))
{
@@ -2509,7 +2513,7 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram )
SetResources sr;
sr.player = dst->tempOwner;
for(int i=0;i<RESOURCE_QUANTITY;i++)
sr.res[i] = gs->getPlayer(dst->tempOwner)->resources[i] - (VLC->creh->creatures[crid].cost[i] * cram);
sr.res[i] = gs->getPlayer(dst->tempOwner)->resources[i] - (VLC->creh->creatures[crid]->cost[i] * cram);
SetAvailableCreatures sac;
sac.tid = objid;
@@ -2517,7 +2521,7 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram )
sac.creatures[level].first -= cram;
SetGarrisons sg;
sg.garrs[dst->id] = dst->army;
sg.garrs[dst->id] = dst->getArmy();
sg.garrs[dst->id] .addToSlot(slot, crid, cram);
sendAndApply(&sr);
@@ -2531,7 +2535,7 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
CArmedInstance *obj = static_cast<CArmedInstance*>(gs->map->objects[objid]);
UpgradeInfo ui = gs->getUpgradeInfo(obj,pos);
int player = obj->tempOwner;
int crQuantity = obj->army.slots[pos].count;
int crQuantity = obj->slots[pos].count;
//check if upgrade is possible
if((ui.oldID<0 || !vstd::contains(ui.newID,upgID)) && complain("That upgrade is not possible!"))
@@ -2567,7 +2571,7 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
//upgrade creature
SetGarrisons sg;
sg.garrs[objid] = obj->army;
sg.garrs[objid] = obj->getArmy();
sg.garrs[objid].slots[pos].setType(upgID);
sendAndApply(&sg);
return true;
@@ -2578,7 +2582,7 @@ bool CGameHandler::garrisonSwap( si32 tid )
CGTownInstance *town = gs->getTown(tid);
if(!town->garrisonHero && town->visitingHero) //visiting => garrison, merge armies: town army => hero army
{
CCreatureSet csn = town->visitingHero->army, cso = town->army;
CCreatureSet csn = town->visitingHero->getArmy(), cso = town->getArmy();
while(!cso.slots.empty())//while there are unmoved creatures
{
int pos = csn.getSlotFor(cso.slots.begin()->second.type->idNumber);
@@ -2645,8 +2649,8 @@ bool CGameHandler::garrisonSwap( si32 tid )
else if (town->garrisonHero && town->visitingHero) //swap visiting and garrison hero
{
SetGarrisons sg;
sg.garrs[town->id] = town->visitingHero->army;
sg.garrs[town->garrisonHero->id] = town->garrisonHero->army;
sg.garrs[town->id] = town->visitingHero->getArmy();;
sg.garrs[town->garrisonHero->id] = town->garrisonHero->getArmy();
SetHeroesInTown intown;
intown.tid = tid;
@@ -2915,7 +2919,7 @@ bool CGameHandler::tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 )
bool CGameHandler::setFormation( si32 hid, ui8 formation )
{
gs->getHero(hid)->army.formation = formation;
gs->getHero(hid)-> formation = formation;
return true;
}
@@ -3032,12 +3036,12 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
*stackAtEnd = gs->curB->getStackT(ba.additionalInfo);
if(curStack->position != ba.destinationTile //we wasn't able to reach destination tile
&& !(curStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE)
&& !(curStack->doubleWide()
&& ( curStack->position == ba.destinationTile + (curStack->attackerOwned ? +1 : -1 ) )
) //nor occupy specified hex
)
{
std::string problem = "We cannot move this stack to its destination " + curStack->creature->namePl;
std::string problem = "We cannot move this stack to its destination " + curStack->type->namePl;
tlog3 << problem << std::endl;
complain(problem);
ok = false;
@@ -3068,11 +3072,11 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
if( !(
(BattleInfo::mutualPosition(curpos, enemypos) >= 0) //front <=> front
|| (curStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) //back <=> front
|| (curStack->doubleWide() //back <=> front
&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos) >= 0)
|| (stackAtEnd->hasFeatureOfType(StackFeature::DOUBLE_WIDE) //front <=> back
|| (stackAtEnd->doubleWide() //front <=> back
&& BattleInfo::mutualPosition(curpos, enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
|| (stackAtEnd->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && curStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE)//back <=> back
|| (stackAtEnd->doubleWide() && curStack->doubleWide()//back <=> back
&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
)
)
@@ -3089,11 +3093,11 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
handleAfterAttackCasting(bat);
//counterattack
if(!curStack->hasFeatureOfType(StackFeature::BLOCKS_RETALIATION)
if(!curStack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
&& stackAtEnd->alive()
&& ( stackAtEnd->counterAttacks > 0 || stackAtEnd->hasFeatureOfType(StackFeature::UNLIMITED_RETALIATIONS) )
&& !stackAtEnd->hasFeatureOfType(StackFeature::SIEGE_WEAPON)
&& !stackAtEnd->hasFeatureOfType(StackFeature::HYPNOTIZED))
&& ( stackAtEnd->counterAttacks > 0 || stackAtEnd->hasBonusOfType(Bonus::UNLIMITED_RETALIATIONS) )
&& !stackAtEnd->hasBonusOfType(Bonus::SIEGE_WEAPON)
&& !stackAtEnd->hasBonusOfType(Bonus::HYPNOTIZED))
{
prepareAttack(bat, stackAtEnd, curStack, 0);
bat.flags |= 2;
@@ -3102,8 +3106,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
}
//second attack
if(curStack->valOfFeatures(StackFeature::ADDITIONAL_ATTACK) > 0
&& !curStack->hasFeatureOfType(StackFeature::SHOOTER)
if(curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0
&& !curStack->hasBonusOfType(Bonus::SHOOTER)
&& curStack->alive()
&& stackAtEnd->alive() )
{
@@ -3114,7 +3118,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
}
//return
if(curStack->hasFeatureOfType(StackFeature::RETURN_AFTER_STRIKE) && startingPos != curStack->position && curStack->alive())
if(curStack->hasBonusOfType(Bonus::RETURN_AFTER_STRIKE) && startingPos != curStack->position && curStack->alive())
{
moveStack(ba.stackNumber, startingPos);
//NOTE: curStack->ID == ba.stackNumber (rev 1431)
@@ -3136,7 +3140,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
bat.flags |= 1;
sendAndApply(&bat);
if(curStack->valOfFeatures(StackFeature::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
if(curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
&& curStack->alive()
&& destStack->alive()
&& curStack->shots
@@ -3260,7 +3264,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
CStack *healer = gs->curB->getStack(ba.stackNumber),
*destStack = gs->curB->getStackT(ba.destinationTile);
if(healer == NULL || destStack == NULL || !healer->hasFeatureOfType(StackFeature::HEALER))
if(healer == NULL || destStack == NULL || !healer->hasBonusOfType(Bonus::HEALER))
{
complain("There is either no healer, no destination, or healer cannot heal :P");
}
@@ -3337,24 +3341,30 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
}
else if(message == "vcmiainur") //gives 5 archangels into each slot
{
SetGarrisons sg;
CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection);
if(!hero) return;
sg.garrs[hero->id] = hero->army;
for(int i=0;i<7;i++)
if(!vstd::contains(sg.garrs[hero->id].slots,i))
sg.garrs[hero->id].slots[i] = CStackInstance(13,5);
SetGarrisons sg;
CCreatureSet &newArmy = sg.garrs[hero->id];
newArmy = hero->getArmy();
for(int i=0; i<ARMY_SIZE; i++)
if(newArmy.slotEmpty(i))
newArmy.addToSlot(i, CStackInstance(13,5));
sendAndApply(&sg);
}
else if(message == "vcmiangband") //gives 10 black knight into each slot
{
SetGarrisons sg;
CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection);
if(!hero) return;
sg.garrs[hero->id] = hero->army;
for(int i=0;i<7;i++)
if(!vstd::contains(sg.garrs[hero->id].slots,i))
sg.garrs[hero->id].slots[i] = CStackInstance(66,10);
SetGarrisons sg;
CCreatureSet &newArmy = sg.garrs[hero->id];
newArmy = hero->getArmy();
for(int i=0; i<ARMY_SIZE; i++)
if(newArmy.slotEmpty(i))
newArmy.addToSlot(i, CStackInstance(66,10));
sendAndApply(&sg);
}
else if(message == "vcminoldor") //all war machines
@@ -3447,9 +3457,9 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
std::vector<ui32> ret;
for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it)
{
if ((*it)->hasFeatureOfType(StackFeature::SPELL_IMMUNITY, sp->id) //100% sure spell immunity
|| ( (*it)->hasFeatureOfType(StackFeature::LEVEL_SPELL_IMMUNITY) &&
(*it)->valOfFeatures(StackFeature::LEVEL_SPELL_IMMUNITY) >= sp->level) ) //some creature abilities have level 0
if ((*it)->hasBonusOfType(Bonus::SPELL_IMMUNITY, sp->id) //100% sure spell immunity
|| ( (*it)->hasBonusOfType(Bonus::LEVEL_SPELL_IMMUNITY) &&
(*it)->valOfBonuses(Bonus::LEVEL_SPELL_IMMUNITY) >= sp->level) ) //some creature abilities have level 0
{
ret.push_back((*it)->ID);
continue;
@@ -3465,11 +3475,11 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
else
bonusHero = hero2;
int prob = (*it)->valOfFeatures(StackFeature::MAGIC_RESISTANCE); //probability of resistance in %
int prob = (*it)->valOfBonuses(Bonus::MAGIC_RESISTANCE); //probability of resistance in %
if(bonusHero)
{
//bonusHero's resistance support (secondary skils and artifacts)
prob += bonusHero->valOfBonuses(HeroBonus::MAGIC_RESISTANCE);
prob += bonusHero->valOfBonuses(Bonus::MAGIC_RESISTANCE);
switch(bonusHero->getSecSkillLevel(26)) //resistance
{
@@ -3496,8 +3506,8 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
{
for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it)
{
if( (*it)->hasFeatureOfType(StackFeature::SPELL_IMMUNITY, sp->id) //100% sure spell immunity
|| ( (*it)->amount - 1 ) * (*it)->MaxHealth() + (*it)->firstHPleft
if( (*it)->hasBonusOfType(Bonus::SPELL_IMMUNITY, sp->id) //100% sure spell immunity
|| ( (*it)->count - 1 ) * (*it)->MaxHealth() + (*it)->firstHPleft
>
caster->getPrimSkillLevel(2) * 25 + sp->powers[caster->getSpellSchoolLevel(sp)]
)
@@ -3630,7 +3640,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
{
if(vstd::contains(sc.resisted, (*it)->ID) //this creature resisted the spell
|| (spellID == 39 && !(*it)->hasFeatureOfType(StackFeature::UNDEAD)) //we try to cast animate dead on living stack
|| (spellID == 39 && !(*it)->hasBonusOfType(Bonus::UNDEAD)) //we try to cast animate dead on living stack
)
continue;
StacksHealedOrResurrected::HealInfo hi;
@@ -3690,7 +3700,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|| (h->mana < gs->curB->getSpellCost(s, h)) //not enough mana
|| (ba.additionalInfo < 10) //it's adventure spell (not combat)
|| (gs->curB->castSpells[ba.side]) //spell has been cast
|| (NBonus::hasOfType(secondHero, HeroBonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell
|| (NBonus::hasOfType(secondHero, Bonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell
|| (gs->battleMaxSpellLevel() < s->level) //non - casting hero stops caster from casting this spell
)
{
@@ -4159,12 +4169,12 @@ bool CGameHandler::dig( const CGHeroInstance *h )
void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
{
const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
if( attacker->hasFeatureOfType(StackFeature::SPELL_AFTER_ATTACK) )
if( attacker->hasBonusOfType(Bonus::SPELL_AFTER_ATTACK) )
{
for (int it=0; it<attacker->features.size(); ++it)
BOOST_FOREACH(const Bonus & sf, attacker->bonuses)
{
const StackFeature & sf = attacker->features[it];
if (sf.type == StackFeature::SPELL_AFTER_ATTACK)
if (sf.type == Bonus::SPELL_AFTER_ATTACK)
{
const CStack * oneOfAttacked = NULL;
for(int g=0; g<bat.bsa.size(); ++g)
@@ -4179,7 +4189,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
return;
int spellID = sf.subtype;
int spellLevel = sf.value;
int spellLevel = sf.val;
int chance = sf.additionalInfo % 1000;
int meleeRanged = sf.additionalInfo / 1000;
int destination = oneOfAttacked->position;
@@ -4188,7 +4198,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
continue;
//casting
handleSpellCasting(spellID, spellLevel, destination, !attacker->attackerOwned, attacker->owner, NULL, NULL, attacker->amount);
handleSpellCasting(spellID, spellLevel, destination, !attacker->attackerOwned, attacker->owner, NULL, NULL, attacker->count);
}
}
}
@@ -4304,7 +4314,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &p
COMPLAIN_RET("Destination tile doesn't exist!");
if(!h->movement)
COMPLAIN_RET("Hero needs movement points to cast Dimension Door!");
if(h->getBonusesCount(HeroBonus::CASTED_SPELL, Spells::DIMENSION_DOOR) >= s->powers[schoolLevel]) //limit casts per turn
if(h->getBonusesCount(Bonus::CASTED_SPELL, Spells::DIMENSION_DOOR) >= s->powers[schoolLevel]) //limit casts per turn
{
InfoWindow iw;
iw.player = h->tempOwner;
@@ -4316,7 +4326,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &p
GiveBonus gb;
gb.id = h->id;
gb.bonus = HeroBonus(HeroBonus::ONE_DAY, HeroBonus::NONE, HeroBonus::CASTED_SPELL, 0, Spells::DIMENSION_DOOR);
gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::NONE, Bonus::CASTED_SPELL, 0, Spells::DIMENSION_DOOR);
sendAndApply(&gb);
if(!dest->isClear(curr)) //wrong dest tile

View File

@@ -101,7 +101,7 @@ public:
void prepareAttack(BattleAttack &bat, const CStack *att, const CStack *def, int distance); //distance - number of hexes travelled before attacking
void prepareAttacked(BattleStackAttacked &bsa, const CStack *def);
void checkForBattleEnd( std::vector<CStack*> &stacks );
void setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet &army1, const CCreatureSet &army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town);
void setupBattle( BattleInfo * curB, int3 tile, const CArmedInstance *army1, const CArmedInstance *army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town);
CGameHandler(void);
~CGameHandler(void);