1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Stacks #2 -> towards new system of stack operations.

This commit is contained in:
Michał W. Urbańczyk 2010-11-27 01:46:19 +00:00
parent 32ce20af15
commit 7c3f3d20c3
17 changed files with 406 additions and 126 deletions

View File

@ -317,7 +317,7 @@ float CGeniusAI::TownObjective::getValue() const
case upgradeCreatures:
UpgradeInfo ui = AI->m_cb->getUpgradeInfo(whichTown->t,which);
ID = whichTown->creaturesInGarrison.getCreature(which)->idNumber;
howMany = whichTown->creaturesInGarrison.getAmount(which);
howMany = whichTown->creaturesInGarrison.getStackCount(which);
newID = ui.newID.back();
int upgrade_serial = ui.newID.size() - 1;

View File

@ -113,7 +113,10 @@ public:
void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures, bool remove) {};
void takeCreatures (int objid, TSlots creatures){};
void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures){};
void changeCreatureType (int objid, TSlot slot, TCreature creature){};
void changeStackType(const StackLocation &sl, CCreature *c){};
void changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false){};
void insertNewStack(const StackLocation &sl, CCreature *c, TQuantity count){};
void eraseStack(const StackLocation &sl){};
void showCompInfo(ShowInInfobox * comp){};
void heroVisitCastle(int obj, int heroID){};
void stopHeroVisitCastle(int obj, int heroID){};

View File

@ -2919,7 +2919,7 @@ void CTradeWindow::initSubs(bool Left)
switch(itemsType[1])
{
case CREATURE:
t->subtitle = boost::lexical_cast<std::string>(hero->getAmount(t->serial));
t->subtitle = boost::lexical_cast<std::string>(hero->getStackCount(t->serial));
break;
case RESOURCE:
t->subtitle = boost::lexical_cast<std::string>(LOCPLINT->cb->getResourceAmount(t->serial));
@ -2992,7 +2992,7 @@ void CTradeWindow::removeItem(CTradeableItem * t)
void CTradeWindow::getEmptySlots(std::set<CTradeableItem *> &toRemove)
{
BOOST_FOREACH(CTradeableItem *t, items[1])
if(!hero->getAmount(t->serial))
if(!hero->getStackCount(t->serial))
toRemove.insert(t);
}
@ -3225,7 +3225,7 @@ void CMarketplaceWindow::selectionChanged(bool side)
if(itemsType[1] == RESOURCE)
newAmount = LOCPLINT->cb->getResourceAmount(hLeft->id);
else if(itemsType[1] == CREATURE)
newAmount = hero->getAmount(hLeft->serial) - (hero->Slots().size() == 1 && hero->needsLastStack());
newAmount = hero->getStackCount(hLeft->serial) - (hero->Slots().size() == 1 && hero->needsLastStack());
else
assert(0);
@ -3598,7 +3598,7 @@ void CAltarWindow::SacrificeAll()
{
bool movedAnything = false;
BOOST_FOREACH(CTradeableItem *t, items[1])
sacrificedUnits[t->serial] = hero->getAmount(t->serial);
sacrificedUnits[t->serial] = hero->getStackCount(t->serial);
sacrificedUnits[items[1].front()->serial]--;
@ -3637,10 +3637,10 @@ void CAltarWindow::selectionChanged(bool side)
int stackCount = 0;
for (int i = 0; i < ARMY_SIZE; i++)
if(hero->getAmount(i) > sacrificedUnits[i])
if(hero->getStackCount(i) > sacrificedUnits[i])
stackCount++;
slider->setAmount(hero->getAmount(hLeft->serial) - (stackCount == 1));
slider->setAmount(hero->getStackCount(hLeft->serial) - (stackCount == 1));
slider->block(!slider->amount);
slider->value = sacrificedUnits[hLeft->serial];
max->block(!slider->amount);
@ -5783,7 +5783,7 @@ CTransformerWindow::CTransformerWindow(const CGHeroInstance * _hero, const CGTow
for (int i=0; i<7; i++ )
if ( army->getCreature(i) )
items.push_back(new CItem(this, army->getAmount(i), i));
items.push_back(new CItem(this, army->getStackCount(i), i));
all = new AdventureMapButton(CGI->generaltexth->zelp[590],boost::bind(&CTransformerWindow::addAll,this), 146,416,"ALTARMY.DEF",SDLK_a);
convert= new AdventureMapButton(CGI->generaltexth->zelp[591],boost::bind(&CTransformerWindow::makeDeal,this), 269,416,"ALTSACR.DEF",SDLK_RETURN);
@ -6024,7 +6024,7 @@ void CHillFortWindow::updateGarrisons()
if (info.newID.size())//we have upgrades here - update costs
for(std::set<std::pair<int,int> >::iterator it=info.cost[0].begin(); it!=info.cost[0].end(); it++)
{
std::pair<int, int> pair = std::make_pair(it->first, it->second * hero->getAmount(i) );
std::pair<int, int> pair = std::make_pair(it->first, it->second * hero->getStackCount(i) );
costs[i].insert(pair);
totalSumm[pair.first] += pair.second;
}
@ -6137,7 +6137,7 @@ std::string CHillFortWindow::getTextForSlot(int slot)
return "";
std::string str = CGI->generaltexth->allTexts[318];
int amount = hero->getAmount(slot);
int amount = hero->getStackCount(slot);
if ( amount == 1 )
boost::algorithm::replace_first(str,"%s",hero->getCreature(slot)->nameSing);
else
@ -6172,7 +6172,7 @@ int CHillFortWindow::getState(int slot)
return 1;
for(std::set<std::pair<int,int> >::iterator it=info.cost[0].begin(); it!=info.cost[0].end(); it++)
if(LOCPLINT->cb->getResourceAmount(it->first) < it->second * hero->getAmount(slot))
if(LOCPLINT->cb->getResourceAmount(it->first) < it->second * hero->getStackCount(slot))
return 0;
return 2;//can upgrade
}

View File

@ -893,7 +893,7 @@ void CGHeroInstance::initArmy(CCreatureSet *dst /*= NULL*/)
}
}
else
dst->addStack(stackNo-warMachinesGiven, new CStackInstance(creID, count));
dst->putStack(stackNo-warMachinesGiven, new CStackInstance(creID, count));
}
}
void CGHeroInstance::initHeroDefInfo()
@ -1587,7 +1587,7 @@ void CGDwelling::initObj()
creatures[0].second.push_back(crid);
hoverName = VLC->generaltexth->creGens[subID];
if(crs->level > 4)
addStack(0, new CStackInstance(crs, (crs->growth) * 3));
putStack(0, new CStackInstance(crs, (crs->growth) * 3));
if (getOwner() != 255)
cb->gameState()->players[getOwner()].dwellings.push_back (this);
}
@ -1602,8 +1602,8 @@ void CGDwelling::initObj()
creatures[2].second.push_back(116); //Gold Golem
creatures[3].second.push_back(117); //Diamond Golem
//guards
addStack(0, new CStackInstance(116, 9));
addStack(1, new CStackInstance(117, 6));
putStack(0, new CStackInstance(116, 9));
putStack(1, new CStackInstance(117, 6));
}
else if(subID == 0) // Elemental Conflux
{
@ -1612,7 +1612,7 @@ void CGDwelling::initObj()
creatures[2].second.push_back(113); //Earth Elemental
creatures[3].second.push_back(115); //Water Elemental
//guards
addStack(0, new CStackInstance(113, 12));
putStack(0, new CStackInstance(113, 12));
}
else
{
@ -2170,38 +2170,34 @@ void CGTownInstance::newTurn() const
if (nativeCrits.size())
{
TSlot pos = nativeCrits[rand() % nativeCrits.size()];
StackLocation sl(this, pos);
const CCreature *c = getCreature(pos);
if (rand()%100 < 90 || c->upgrades.empty()) //increase number if no upgrade avaliable
{
SetGarrisons sg;
sg.garrs[id] = getArmy();
sg.garrs[id].slots[pos]->count += c->growth;
cb->sendAndApply(&sg);
cb->changeStackCount(sl, c->growth);
}
else //upgrade
{
SetGarrisons sg; //somewhat better upgrade pack would come in handy
sg.garrs[id] = getArmy();
//////////////////////////////////////////////////////////////////////////
//sg.garrs[id].t (pos, *c->upgrades.begin(), );
//sg.garrs[id].setCreature(pos, *c->upgrades.begin(), slt[pos].count);
cb->sendAndApply(&sg);
cb->changeStackType(sl, VLC->creh->creatures[*c->upgrades.begin()]);
}
}
if ((stacksCount() < ARMY_SIZE && rand()%100 < 25) || Slots().empty()) //add new stack
{
int n, i = rand() % std::min (ARMY_SIZE, cb->getDate(3)<<1);
int i = rand() % std::min (ARMY_SIZE, cb->getDate(3)<<1);
TCreature c = town->basicCreatures[i];
TSlot n = -1;
TQuantity count = creatureGrowth(i);
{//no lower tiers or above current month
if ((n = getSlotFor(town->basicCreatures[i], ARMY_SIZE))>=0)
if ((n = getSlotFor(c))>=0)
{
SetGarrisons sg;
sg.garrs[id] = getArmy();
StackLocation sl(this, n);
if (slotEmpty(n))
sg.garrs[id].setCreature (n, town->basicCreatures[i], creatureGrowth(i)); //if the stack is not yet present
else
sg.garrs[id].addToSlot(n, town->basicCreatures[i], creatureGrowth(i)); //add to existing
cb->sendAndApply(&sg);
cb->insertNewStack(sl, VLC->creh->creatures[c], count);
else //add to existing
cb->changeStackCount(sl, count);
}
}
}
@ -2896,7 +2892,7 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
BlockingDialog ynd(true,false);
ynd.player = h->tempOwner;
std::string tmp = VLC->generaltexth->advobtxt[90];
boost::algorithm::replace_first(tmp,"%d",boost::lexical_cast<std::string>(getAmount(0)));
boost::algorithm::replace_first(tmp,"%d",boost::lexical_cast<std::string>(getStackCount(0)));
boost::algorithm::replace_first(tmp,"%d",boost::lexical_cast<std::string>(action));
boost::algorithm::replace_first(tmp,"%s",VLC->creh->creatures[subID]->namePl);
ynd.text << tmp;
@ -3040,7 +3036,7 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
if(h->getSecSkillLevel(4) + sympathy + 1 >= character)
return 0; //join for free
else if(h->getSecSkillLevel(4) * 2 + sympathy + 1 >= character)
return VLC->creh->creatures[subID]->cost[6] * getAmount(0); //join for gold
return VLC->creh->creatures[subID]->cost[6] * getStackCount(0); //join for gold
}
}
@ -3112,7 +3108,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co
//add creatures
SetGarrisons sg;
sg.garrs[h->id] = h->getArmy();
sg.garrs[h->id].addToSlot(slot, subID, getAmount(0));
sg.garrs[h->id].addToSlot(slot, subID, getStackCount(0));
cb->sendAndApply(&sg);
cb->removeObject(id);
}
@ -3180,7 +3176,7 @@ void CGMine::initObj()
//set guardians
int howManyTroglodytes = 100 + ran()%100;
CStackInstance *troglodytes = new CStackInstance(70, howManyTroglodytes);
addStack(0, troglodytes);
putStack(0, troglodytes);
//after map reading tempOwner placeholds bitmask for allowed resources
std::vector<int> possibleResources;
@ -4673,7 +4669,7 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
iw.components.push_back(Component(Component::CREATURE,11,0,1));
for (TSlots::const_iterator i = creatures.slots.begin(); i != creatures.slots.end(); ++i)
{
cb->changeCreatureType(h->id, i->first, 11);
cb->changeStackType(StackLocation(h, i->first), VLC->creh->creatures[11]);
}
}
else
@ -6525,20 +6521,6 @@ void CGLighthouse::giveBonusTo( ui8 player ) const
gb.bonus.source = Bonus::OBJECT;
gb.bonus.id = id;
cb->sendAndApply(&gb);
}
void CArmedInstance::setArmy(const CCreatureSet &src)
{
assert(0);
// slots.clear();
//
// for(TSlots::const_iterator i = src.Slots().begin(); i != src.Slots().end(); i++)
// {
// CStackInstance &inserted = slots[i->first];
// inserted = i->second;
// inserted.setArmyObj(this);
// }
}
CCreatureSet& CArmedInstance::getArmy() const

View File

@ -222,7 +222,6 @@ class DLL_EXPORT CArmedInstance: public CGObjectInstance, public CBonusSystemNod
public:
BattleInfo *battle; //set to the current battle, if engaged
void setArmy(const CCreatureSet &src);
CCreatureSet& getArmy() const;
void randomizeArmy(int type);

View File

@ -17,7 +17,7 @@ const CStackInstance &CCreatureSet::operator[](TSlot slot) const
throw std::string("That slot is empty!");
}
const CCreature* CCreatureSet::getCreature(TSlot slot) const /*workaround of map issue */
const CCreature* CCreatureSet::getCreature(TSlot slot) const
{
TSlots::const_iterator i = slots.find(slot);
if (i != slots.end())
@ -37,16 +37,14 @@ bool CCreatureSet::setCreature(TSlot slot, TCreature type, TQuantity quantity) /
{
tlog2 << "Using set creature to delete stack?\n";
eraseStack(slot);
return true;
}
if(vstd::contains(slots, slot)) //remove old creature
{
eraseStack(slot);
}
CStackInstance *stack = new CStackInstance(type, quantity);
stack->armyObj = castToArmyObj(); //brutal force
slots[slot] = stack;
putStack(slot, new CStackInstance(type, quantity));
return true;
}
TSlot CCreatureSet::getSlotFor(TCreature creature, ui32 slotsAmount/*=7*/) const /*returns -1 if no slot available */
@ -68,7 +66,7 @@ TSlot CCreatureSet::getSlotFor(TCreature creature, ui32 slotsAmount/*=7*/) const
return -1; //no slot available
}
int CCreatureSet::getAmount(TSlot slot) const
int CCreatureSet::getStackCount(TSlot slot) const
{
TSlots::const_iterator i = slots.find(slot);
if (i != slots.end())
@ -130,24 +128,31 @@ void CCreatureSet::addToSlot(TSlot slot, TCreature cre, TQuantity count, bool al
{
setCreature(slot, cre, count);
}
else if(slots[slot]->type == c && allowMerging); //that slot was empty or contained same type creature
else if(getCreature(slot) == c && allowMerging) //that slot was empty or contained same type creature
{
setStackCount(slot, slots[slot]->count + count);
setStackCount(slot, getStackCount(slot) + count);
}
else
{
tlog1 << "Failed adding to slot!\n";
}
}
void CCreatureSet::addToSlot(TSlot slot, CStackInstance *stack, bool allowMerging/* = true*/)
{
assert(stack->type == VLC->creh->creatures[stack->type->idNumber]);
assert(stack->valid(true));
if(!vstd::contains(slots, slot))
{
slots[slot] = stack;
stack->setArmyObj(castToArmyObj());
putStack(slot, stack);
}
else if(allowMerging && stack->type == getCreature(slot))
{
joinStack(slot, stack);
}
else
{
addToSlot(slot, stack->type->idNumber, stack->count, allowMerging);
tlog1 << "Cannot add to slot " << slot << " stack " << *stack << std::endl;
}
}
@ -155,14 +160,8 @@ bool CCreatureSet::validTypes(bool allowUnrandomized /*= false*/) const
{
for(TSlots::const_iterator i=slots.begin(); i!=slots.end(); ++i)
{
bool isRand = (i->second->idRand != -1);
if(!isRand)
{
assert(i->second->type);
assert(i->second->type == VLC->creh->creatures[i->second->type->idNumber]);
}
else
assert(allowUnrandomized);
if(!i->second->valid(allowUnrandomized))
return false;
}
return true;
}
@ -187,11 +186,11 @@ int CCreatureSet::getArmyStrength() const
ui64 CCreatureSet::getPower (TSlot slot) const
{
return getCreature(slot)->AIValue * getAmount(slot);
return getCreature(slot)->AIValue * getStackCount(slot);
}
std::string CCreatureSet::getRoughAmount (TSlot slot) const
{
return VLC->generaltexth->arraytxt[174 + 3*CCreature::getQuantityID(getAmount(slot))];
return VLC->generaltexth->arraytxt[174 + 3*CCreature::getQuantityID(getStackCount(slot))];
}
int CCreatureSet::stacksCount() const
@ -199,11 +198,6 @@ int CCreatureSet::stacksCount() const
return slots.size();
}
void CCreatureSet::addStack(TSlot slot, CStackInstance *stack)
{
addToSlot(slot, stack, false);
}
void CCreatureSet::setFormation(bool tight)
{
formation = tight;
@ -218,7 +212,10 @@ void CCreatureSet::setStackCount(TSlot slot, TQuantity count)
void CCreatureSet::clear()
{
slots.clear();
while(!slots.empty())
{
eraseStack(slots.begin()->first);
}
}
const CStackInstance& CCreatureSet::getStack(TSlot slot) const
@ -230,6 +227,7 @@ const CStackInstance& CCreatureSet::getStack(TSlot slot) const
void CCreatureSet::eraseStack(TSlot slot)
{
assert(vstd::contains(slots, slot));
delNull(slots[slot]);
slots.erase(slot);
}
@ -262,20 +260,89 @@ CArmedInstance * CCreatureSet::castToArmyObj()
return dynamic_cast<CArmedInstance *>(this);
}
void CCreatureSet::putStack(TSlot slot, CStackInstance *stack)
{
assert(!vstd::contains(slots, slot));
slots[slot] = stack;
stack->setArmyObj(castToArmyObj());
}
void CCreatureSet::joinStack(TSlot slot, CStackInstance * stack)
{
const CCreature *c = getCreature(slot);
assert(c == stack->type);
assert(c);
//TODO move stuff
changeStackCount(slot, stack->count);
delNull(stack);
}
void CCreatureSet::changeStackCount(TSlot slot, TQuantity toAdd)
{
setStackCount(slot, getStackCount(slot) + toAdd);
}
CCreatureSet::CCreatureSet()
{
formation = false;
}
CCreatureSet::~CCreatureSet()
{
clear();
}
void CCreatureSet::setToArmy(CCreatureSet &src)
{
clear();
while(src)
{
TSlots::iterator i = src.slots.begin();
assert(i->second->type);
assert(i->second->valid(false));
assert(i->second->armyObj == NULL);
putStack(i->first, i->second);
src.slots.erase(i);
}
}
CStackInstance * CCreatureSet::detachStack(TSlot slot)
{
assert(vstd::contains(slots, slot));
CStackInstance *ret = slots[slot];
if(CArmedInstance *armedObj = castToArmyObj())
ret->detachFrom(armedObj);
return ret;
}
void CCreatureSet::setStackType(TSlot slot, const CCreature *type)
{
assert(vstd::contains(slots, slot));
CStackInstance *s = slots[slot];
s->setType(type->idNumber);
}
CStackInstance::CStackInstance()
: armyObj(_armyObj)
{
init();
}
CStackInstance::CStackInstance(TCreature id, TQuantity Count, const CArmedInstance *ArmyObj)
CStackInstance::CStackInstance(TCreature id, TQuantity Count)
: armyObj(_armyObj)
{
init();
setType(id);
setArmyObj(ArmyObj);
count = Count;
}
CStackInstance::CStackInstance(const CCreature *cre, TQuantity Count)
: armyObj(_armyObj)
{
init();
type = cre;
@ -288,7 +355,7 @@ void CStackInstance::init()
count = 0;
type = NULL;
idRand = -1;
armyObj = NULL;
_armyObj = NULL;
nodeType = STACK;
}
@ -298,23 +365,31 @@ int CStackInstance::getQuantityID() const
}
void CStackInstance::setType(int creID)
{
setType(VLC->creh->creatures[creID]);
}
void CStackInstance::setType(const CCreature *c)
{
if(type)
detachFrom(const_cast<CCreature*>(type));
type = VLC->creh->creatures[creID];
type = c;
attachTo(const_cast<CCreature*>(type));
}
void CStackInstance::setArmyObj(const CArmedInstance *ArmyObj)
{
if(armyObj)
detachFrom(const_cast<CArmedInstance*>(armyObj));
if(_armyObj)
detachFrom(const_cast<CArmedInstance*>(_armyObj));
armyObj = ArmyObj;
if(ArmyObj)
{
_armyObj = ArmyObj;
attachTo(const_cast<CArmedInstance*>(armyObj));
attachTo(const_cast<CArmedInstance*>(_armyObj));
}
}
// void CStackInstance::getParents(TCNodes &out, const CBonusSystemNode *source /*= NULL*/) const
// {
@ -334,6 +409,17 @@ std::string CStackInstance::getQuantityTXT(bool capitalized /*= true*/) const
return VLC->generaltexth->arraytxt[174 + getQuantityID()*3 + 2 - capitalized];
}
bool CStackInstance::valid(bool allowUnrandomized) const
{
bool isRand = (idRand != -1);
if(!isRand)
{
return (type && type == VLC->creh->creatures[type->idNumber]);
}
else
return allowUnrandomized;
}
CStackBasicDescriptor::CStackBasicDescriptor()
{
type = NULL;
@ -343,4 +429,18 @@ CStackBasicDescriptor::CStackBasicDescriptor()
CStackBasicDescriptor::CStackBasicDescriptor(TCreature id, TQuantity Count)
: type (VLC->creh->creatures[id]), count(Count)
{
}
DLL_EXPORT std::ostream & operator<<(std::ostream & str, const CStackInstance & sth)
{
if(!sth.valid(true))
str << "an invalid stack!";
str << "stack with " << sth.count << " of ";
if(sth.type)
str << sth.type->namePl;
else
str << sth.idRand;
return str;
}

View File

@ -33,10 +33,11 @@ public:
class DLL_EXPORT CStackInstance : public CBonusSystemNode, public CStackBasicDescriptor
{
const CArmedInstance *_armyObj; //stack must be part of some army, army must be part of some object
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 CArmedInstance * const & armyObj; //stack must be part of some army, army must be part of some object
ui32 experience; //TODO: handle
//TODO: stack artifacts
@ -44,7 +45,7 @@ public:
{
h & static_cast<CBonusSystemNode&>(*this);
h & static_cast<CStackBasicDescriptor&>(*this);
h & armyObj & experience;
h & _armyObj & experience;
}
//overrides CBonusSystemNode
@ -54,12 +55,15 @@ public:
std::string getQuantityTXT(bool capitalized = true) const;
void init();
CStackInstance();
CStackInstance(TCreature id, TQuantity count, const CArmedInstance *ArmyObj = NULL);
CStackInstance(TCreature id, TQuantity count);
CStackInstance(const CCreature *cre, TQuantity count);
void setType(int creID);
void setType(const CCreature *c);
void setArmyObj(const CArmedInstance *ArmyObj);
bool valid(bool allowUnrandomized) const;
};
DLL_EXPORT std::ostream & operator<<(std::ostream & str, const CStackInstance & sth);
typedef std::map<TSlot, CStackInstance*> TSlots;
@ -71,22 +75,35 @@ public:
TSlots slots; //slots[slot_id]->> pair(creature_id,creature_quantity)
ui8 formation; //false - wide, true - tight
CCreatureSet();
virtual ~CCreatureSet();
const CStackInstance &operator[](TSlot slot) const;
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, CStackInstance *stack, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature
void addStack(TSlot slot, 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);
CArmedInstance *castToArmyObj();
//basic operations
void eraseStack(TSlot slot); //slot must be occupied
void putStack(TSlot slot, CStackInstance *stack); //adds new stack to the army, slot must be empty
void joinStack(TSlot slot, CStackInstance * stack); //adds new stack to the existing stack of the same type
void setStackCount(TSlot slot, TQuantity count); //stack must exist!
void eraseStack(TSlot slot);
CStackInstance *detachStack(TSlot slot); //removes stack from army but doesn't destroy it (so it can be moved somewhere else)
void setStackType(TSlot slot, const CCreature *type);
//derivative
void changeStackCount(TSlot slot, TQuantity toAdd); //stack must exist!
bool setCreature (TSlot slot, TCreature type, TQuantity quantity); //replaces creature in stack; slots 0 to 6, if quantity=0 erases stack
void setToArmy(CCreatureSet &src); //erases all our army and moves stacks from src to us; src MUST NOT be an armed object! WARNING: use it wisely. Or better do not use at all.
const CStackInstance& getStack(TSlot slot) const;
const CCreature* getCreature(TSlot slot) const; //workaround of map issue;
int getAmount (TSlot slot) const;
int getStackCount (TSlot slot) const;
TSlot findStack(const CStackInstance *stack) const; //-1 if none
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;
@ -100,7 +117,6 @@ public:
bool contains(const CStackInstance *stack) const;
CArmedInstance *castToArmyObj();
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -1019,6 +1019,12 @@ std::vector<si32> CStack::activeSpells() const
return ret;
}
CStack::~CStack()
{
if(vstd::contains(state, SUMMONED))
delNull(base);
}
CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, int player, const CTown *town, std::map<ui32,CGHeroInstance *> &available, const CHeroClass *bannedClass /*= NULL*/) const
{
CGHeroInstance *ret = NULL;

View File

@ -272,6 +272,7 @@ public:
CStack(const CStackInstance *base, int O, int I, bool AO, int S); //c-tor
CStack(const CStackBasicDescriptor *stack, int O, int I, bool AO, int S = 255); //c-tor
CStack(); //c-tor
~CStack();
void init(); //set initial (invalid) values
void postInit(); //used to finish initialization when inheriting creature parameters is working

View File

@ -109,7 +109,7 @@ void DLL_EXPORT BonusList::removeSpells(Bonus::BonusSource sourceType)
void BonusList::limit(const CBonusSystemNode &node)
{
remove_if(boost::bind(&CBonusSystemNode::isLimitedOnUs, node, _1));
remove_if(boost::bind(&CBonusSystemNode::isLimitedOnUs, boost::ref(node), _1));
}
int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
@ -300,7 +300,13 @@ CBonusSystemNode::CBonusSystemNode()
CBonusSystemNode::~CBonusSystemNode()
{
while(parents.size())
detachFrom(parents.front());
if(children.size())
{
tlog2 << "Warning: an orphaned child!\n";
}
}
void CBonusSystemNode::attachTo(CBonusSystemNode *parent)

View File

@ -37,6 +37,7 @@ class CArmedInstance;
struct TerrainTile;
struct PlayerState;
class CTown;
struct StackLocation;
class DLL_EXPORT IGameCallback
{
@ -89,7 +90,10 @@ public:
virtual void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures, bool remove) =0;
virtual void takeCreatures (int objid, TSlots creatures) =0;
virtual void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures) =0;
virtual void changeCreatureType (int objid, TSlot slot, TCreature creature) =0;
virtual void changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0;
virtual void changeStackType(const StackLocation &sl, CCreature *c) =0;
virtual void insertNewStack(const StackLocation &sl, CCreature *c, TQuantity count) =0;
virtual void eraseStack(const StackLocation &sl) =0;
virtual void showCompInfo(ShowInInfobox * comp)=0;
virtual void heroVisitCastle(int obj, int heroID)=0;
virtual void stopHeroVisitCastle(int obj, int heroID)=0;

View File

@ -527,7 +527,8 @@ struct TryMoveHero : public CPackForClient //501
{
h & id & result & start & end & movePoints & fowRevealed & attackedFrom;
}
};
};
struct SetGarrisons : public CPackForClient //502
{
SetGarrisons(){type = 502;};
@ -713,6 +714,106 @@ struct NewArtifact : public CPackForClient
}
};
struct StackLocation
{
CArmedInstance *army;
TSlot slot;
StackLocation()
{
army = NULL;
slot = -1;
}
StackLocation(const CArmedInstance *Army, TSlot Slot)
{
army = const_cast<CArmedInstance*>(Army); //we are allowed here to const cast -> change will go through one of our packages... do not abuse!
slot = Slot;
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & army & slot;
}
};
struct ChangeStackCount : CPackForClient //521
{
StackLocation sl;
TQuantity count;
ui8 absoluteValue; //if not -> count will be added (or subtracted if negative)
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & sl & count;
}
};
struct SetStackType : CPackForClient //522
{
StackLocation sl;
CCreature *type;
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & sl & type;
}
};
struct EraseStack : CPackForClient //523
{
StackLocation sl;
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & sl;
}
};
struct SwapStacks : CPackForClient //524
{
StackLocation sl1, sl2;
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & sl1 & sl2;
}
};
struct InsertNewStack : CPackForClient //525
{
StackLocation sl;
CStackInstance *stack;
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & sl & stack;
}
};
//moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
struct RebalanceStacks : CPackForClient //525
{
StackLocation src, dst;
TQuantity count;
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & src & dst & count;
}
};
struct NewTurn : public CPackForClient //101
{
enum weekType {NORMAL, DOUBLE_GROWTH, BONUS_GROWTH, DEITYOFFIRE, PLAGUE, CUSTOM, NO_ACTION, NONE};

View File

@ -178,7 +178,7 @@ DLL_EXPORT void SetAvailableHeroes::applyGs( CGameState *gs )
{
CGHeroInstance *h = (hid[i]>=0 ? gs->hpool.heroesPool[hid[i]] : NULL);
if(h && army[i])
h->setArmy(*army[i]);
h->setToArmy(*army[i]);
p->availableHeroes.push_back(h);
}
}
@ -380,15 +380,15 @@ 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->setArmy(i->second);
ai->setToArmy(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)->setArmy(i->second);
const_cast<CGHeroInstance*>((static_cast<CGTownInstance*>(ai))->garrisonHero)->setToArmy(i->second);
else if(ai->ID==HEROI_TYPE)
{
CGHeroInstance *h = static_cast<CGHeroInstance*>(ai);
CGTownInstance *t = const_cast<CGTownInstance *>(h->visitedTown);
if(t && h->inTownGarrison)
t->setArmy(i->second);
t->setToArmy(i->second);
}
}
}
@ -605,6 +605,38 @@ DLL_EXPORT void NewArtifact::applyGs( CGameState *gs )
gs->map->artInstances.push_back(art);
}
DLL_EXPORT void ChangeStackCount::applyGs( CGameState *gs )
{
if(absoluteValue)
sl.army->setStackCount(sl.slot, count);
else
sl.army->changeStackCount(sl.slot, count);
}
DLL_EXPORT void SetStackType::applyGs( CGameState *gs )
{
sl.army->setStackType(sl.slot, type);
}
DLL_EXPORT void EraseStack::applyGs( CGameState *gs )
{
sl.army->eraseStack(sl.slot);
}
DLL_EXPORT void SwapStacks::applyGs( CGameState *gs )
{
}
DLL_EXPORT void InsertNewStack::applyGs( CGameState *gs )
{
sl.army->putStack(sl.slot, stack);
}
DLL_EXPORT void RebalanceStacks::applyGs( CGameState *gs )
{
}
DLL_EXPORT void SetAvailableArtifacts::applyGs( CGameState *gs )
{
if(id >= 0)
@ -1007,10 +1039,11 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
}
}
CStack * summonedStack = gs->curB->generateNewStack(CStackInstance(creID, h->getPrimSkillLevel(2) * VLC->spellh->spells[id].powers[skill], h), gs->curB->stacks.size(), !side, 255, pos);
CStackInstance *csi = new CStackInstance(creID, h->getPrimSkillLevel(2) * VLC->spellh->spells[id].powers[skill]); //deleted by d-tor of summoned stack
csi->setArmyObj(h);
CStack * summonedStack = gs->curB->generateNewStack(*csi, gs->curB->stacks.size(), !side, 255, pos);
summonedStack->state.insert(SUMMONED);
//summonedStack->addNewBonus( makeFeature(HeroBonus::SUMMONED, HeroBonus::ONE_BATTLE, 0, 0, HeroBonus::BONUS_FROM_HERO) );
gs->curB->stacks.push_back(summonedStack);
}
}

View File

@ -142,6 +142,12 @@ void registerTypes2(Serializer &s)
s.template registerType<OpenWindow>();
s.template registerType<NewObject>();
s.template registerType<NewArtifact>();
s.template registerType<ChangeStackCount>();
s.template registerType<SetStackType>();
s.template registerType<EraseStack>();
s.template registerType<SwapStacks>();
s.template registerType<InsertNewStack>();
s.template registerType<RebalanceStacks>();
s.template registerType<SetAvailableArtifacts>();
s.template registerType<SaveGame>();

View File

@ -106,7 +106,7 @@ void readCreatureSet(CCreatureSet *out, const unsigned char * bufor, int &i, int
else
hlp->setType(creID);
out->addStack(ir, hlp);
out->putStack(ir, hlp);
}
i+=number*bytesPerCre;

View File

@ -322,7 +322,7 @@ static CCreatureSet takeCasualties(int color, const CCreatureSet &set, BattleInf
if(vstd::contains(st->state, SUMMONED)) //don't take into account sumoned stacks
continue;
if(st->owner==color && !set.slotEmpty(st->slot) && st->count < set.getAmount(st->slot))
if(st->owner==color && !set.slotEmpty(st->slot) && st->count < set.getStackCount(st->slot))
{
if(st->alive())
ret.setStackCount(st->slot, st->count);
@ -2694,8 +2694,8 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2,
S1.slots[p1]->count -= val;
}
if ( (s1->tempOwner != player && S1.slots[p1]->count < s1->getArmy().getAmount(p1) )
|| (s2->tempOwner != player && S2.slots[p2]->count < s2->getArmy().getAmount(p2) ) )
if ( (s1->tempOwner != player && S1.slots[p1]->count < s1->getArmy().getStackCount(p1) )
|| (s2->tempOwner != player && S2.slots[p2]->count < s2->getArmy().getStackCount(p2) ) )
{
complain("Can't move troops of another player!");
return false;
@ -3034,18 +3034,14 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
return true;
}
void CGameHandler::changeCreatureType (int objid, TSlot slot, TCreature creature)
void CGameHandler::changeStackType(const StackLocation &sl, CCreature *c)
{
CArmedInstance *obj = static_cast<CArmedInstance*>(gs->map->objects[objid]);
if (obj)
{
SetGarrisons sg;
sg.garrs[objid] = obj->getArmy();
sg.garrs[objid].slots[slot]->setType(creature);
sendAndApply(&sg);
}
else
tlog2 <<"Illegal call of changeCreatureType for non-armed instance!\n";
assert(sl.army->getCreature(sl.slot));
SetStackType sst;
sst.sl = sl;
sst.type = c;
sendAndApply(&sst);
}
bool CGameHandler::garrisonSwap( si32 tid )
@ -5247,7 +5243,7 @@ bool CGameHandler::tryAttackingGuard(const int3 &guardPos, const CGHeroInstance
bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstance *hero, TSlot slot, ui32 count)
{
int oldCount = hero->getAmount(slot);
int oldCount = hero->getStackCount(slot);
int newCount = oldCount - count;
if(oldCount < count)
@ -5283,3 +5279,27 @@ bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * h
changePrimSkill(hero->id, 4, expToGive);
return true;
}
void CGameHandler::insertNewStack(const StackLocation &sl, CCreature *c, TQuantity count)
{
InsertNewStack ins;
ins.sl = sl;
ins.stack = new CStackInstance(c, count);
sendAndApply(&ins);
}
void CGameHandler::eraseStack(const StackLocation &sl)
{
EraseStack es;
es.sl = sl;
sendAndApply(&es);
}
void CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue /*= false*/)
{
ChangeStackCount csc;
csc.sl = sl;
csc.count = count;
csc.absoluteValue = absoluteValue;
sendAndApply(&csc);
}

View File

@ -138,7 +138,10 @@ public:
void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures, bool remove);
void takeCreatures (int objid, TSlots creatures);
void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures);
void changeCreatureType (int objid, TSlot slot, TCreature creature);
void changeStackType(const StackLocation &sl, CCreature *c);
void changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false);
void insertNewStack(const StackLocation &sl, CCreature *c, TQuantity count);
void eraseStack(const StackLocation &sl);
void showCompInfo(ShowInInfobox * comp);
void heroVisitCastle(int obj, int heroID);
void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h);