1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

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

This commit is contained in:
Michał W. Urbańczyk 2010-11-27 20:17:28 +00:00
parent 7c3f3d20c3
commit fdb541d81e
13 changed files with 339 additions and 187 deletions

View File

@ -113,10 +113,14 @@ 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 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){};
bool changeStackType(const StackLocation &sl, CCreature *c){return false;};
bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false){return false;};
bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count){return false;};
bool eraseStack(const StackLocation &sl){return false;};
bool swapStacks(const StackLocation &sl1, const StackLocation &sl2){return false;}
bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count){return false;}
void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished){}
bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1){return false;}
void showCompInfo(ShowInInfobox * comp){};
void heroVisitCastle(int obj, int heroID){};
void stopHeroVisitCastle(int obj, int heroID){};

View File

@ -122,6 +122,40 @@ void SetAvailableHeroes::applyCl( CClient *cl )
//TODO: inform interface?
}
void ChangeStackCount::applyCl( CClient *cl )
{
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,garrisonChanged,sl.army);
}
void SetStackType::applyCl( CClient *cl )
{
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,garrisonChanged,sl.army);
}
void EraseStack::applyCl( CClient *cl )
{
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,garrisonChanged,sl.army);
}
void SwapStacks::applyCl( CClient *cl )
{
INTERFACE_CALL_IF_PRESENT(sl1.army->tempOwner,garrisonChanged,sl1.army);
if(sl1.army != sl2.army)
INTERFACE_CALL_IF_PRESENT(sl2.army->tempOwner,garrisonChanged,sl2.army);
}
void InsertNewStack::applyCl( CClient *cl )
{
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,garrisonChanged,sl.army);
}
void RebalanceStacks::applyCl( CClient *cl )
{
INTERFACE_CALL_IF_PRESENT(src.army->tempOwner,garrisonChanged,src.army);
if(src.army != dst.army)
INTERFACE_CALL_IF_PRESENT(dst.army->tempOwner,garrisonChanged,dst.army);
}
void GiveBonus::applyCl( CClient *cl )
{
switch(who)

View File

@ -139,6 +139,11 @@ bool CCreature::isMyUpgrade(const CCreature *anotherCre) const
return vstd::contains(upgrades, anotherCre->idNumber);
}
bool CCreature::valid() const
{
return this == VLC->creh->creatures[idNumber];
}
int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo()
{
befi=i;

View File

@ -61,6 +61,8 @@ public:
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
bool isMyUpgrade(const CCreature *anotherCre) const;
bool valid() const;
void addBonus(int val, int type, int subtype = -1);
//void getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const;

View File

@ -1766,10 +1766,11 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h, ui32 answer ) co
int crid = creatures[0].second[0];
CCreature *crs = VLC->creh->creatures[crid];
TQuantity count = creatures[0].first;
if(crs->level == 1 && ID != 78) //first level - creatures are for free
{
if(creatures[0].first) //there are available creatures
if(count) //there are available creatures
{
int slot = h->getSlotFor(crid);
if(slot < 0) //no available slot
@ -1787,19 +1788,16 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h, ui32 answer ) co
sac.creatures = creatures;
sac.creatures[0].first = 0;
SetGarrisons sg;
sg.garrs[h->id] = *h;
sg.garrs[h->id].addToSlot(slot, crid, creatures[0].first);
InfoWindow iw;
iw.player = h->tempOwner;
iw.text.addTxt(MetaString::GENERAL_TXT, 423); //%d %s join your army.
iw.text.addReplacement(creatures[0].first);
iw.text.addReplacement(count);
iw.text.addReplacement(MetaString::CRE_PL_NAMES, crid);
cb->showInfoDialog(&iw);
cb->sendAndApply(&sac);
cb->sendAndApply(&sg);
cb->addToSlot(StackLocation(h, slot), crs, count);
}
}
else //there no creatures
@ -3102,20 +3100,21 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co
if(cost)
cb->giveResource(h->tempOwner,6,-cost);
int slot = h->getSlotFor(subID);
if(slot >= 0) //there is place
{
//add creatures
SetGarrisons sg;
sg.garrs[h->id] = h->getArmy();
sg.garrs[h->id].addToSlot(slot, subID, getStackCount(0));
cb->sendAndApply(&sg);
cb->removeObject(id);
}
else
{
cb->showGarrisonDialog(id,h->id,true,boost::bind(&IGameCallback::removeObject,cb,id)); //show garrison window and remove ourselves from map when player ends
}
cb->tryJoiningArmy(this, h, true);
// int slot = h->getSlotFor(subID);
// if(slot >= 0) //there is place
// {
// //add creatures
// SetGarrisons sg;
// sg.garrs[h->id] = h->getArmy();
// sg.garrs[h->id].addToSlot(slot, subID, getStackCount(0));
// cb->sendAndApply(&sg);
// cb->removeObject(id);
// }
// else
// {
// cb->showGarrisonDialog(id,h->id,true,boost::bind(&IGameCallback::removeObject,cb,id)); //show garrison window and remove ourselves from map when player ends
// }
}
}
@ -6158,14 +6157,13 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
{
giveDummyBonus(h->id, Bonus::ONE_BATTLE);
int xp = 0;
SetGarrisons sg;
sg.garrs[h->id] = h->getArmy();
for (TSlots::const_iterator i = h->Slots().begin(); i != h->Slots().end(); i++)
{
int drown = (int)(i->second->count * 0.3);
TQuantity drown = i->second->count * 0.3;
if(drown)
{
sg.garrs[h->id].setStackCount(i->first, i->second->count - drown);
cb->changeStackCount(StackLocation(h, i->first), -drown);
xp += drown * i->second->type->valOfBonuses(Bonus::STACK_HEALTH);
}
}
@ -6174,7 +6172,6 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
{
iw.text.addTxt(11,132);
iw.text.addReplacement(xp);
cb->sendAndApply(&sg);
}
else
{
@ -6182,6 +6179,8 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
}
}
cb->showInfoDialog(&iw);
//////////////////////////////////////////////////////////////////////////
///TODO: WHAT WITH EXP?
}
//bool IShipyard::validLocation() const

View File

@ -49,9 +49,16 @@ bool CCreatureSet::setCreature(TSlot slot, TCreature type, TQuantity quantity) /
TSlot CCreatureSet::getSlotFor(TCreature creature, ui32 slotsAmount/*=7*/) const /*returns -1 if no slot available */
{
return getSlotFor(VLC->creh->creatures[creature], slotsAmount);
}
TSlot CCreatureSet::getSlotFor(const CCreature *c, ui32 slotsAmount/*=ARMY_SIZE*/) const
{
assert(c->valid());
for(TSlots::const_iterator i=slots.begin(); i!=slots.end(); ++i)
{
if(i->second->type->idNumber == creature)
assert(i->second->type->valid());
if(i->second->type == c)
{
return i->first; //if there is already such creature we return its slot id
}
@ -317,6 +324,7 @@ CStackInstance * CCreatureSet::detachStack(TSlot slot)
if(CArmedInstance *armedObj = castToArmyObj())
ret->detachFrom(armedObj);
slots.erase(slot);
return ret;
}
@ -327,6 +335,24 @@ void CCreatureSet::setStackType(TSlot slot, const CCreature *type)
s->setType(type->idNumber);
}
bool CCreatureSet::canBeMergedWith(const CCreatureSet &cs) const
{
std::set<const CCreature*> cres;
//get types of creatures that need their own slot
for(TSlots::const_iterator i = cs.slots.begin(); i != cs.slots.end(); i++)
cres.insert(i->second->type);
for(TSlots::const_iterator i = slots.begin(); i != slots.end(); i++)
cres.insert(i->second->type);
return cres.size() <= ARMY_SIZE;
}
bool CCreatureSet::hasStackAtSlot(TSlot slot) const
{
return vstd::contains(slots, slot);
}
CStackInstance::CStackInstance()
: armyObj(_armyObj)
{

View File

@ -106,6 +106,7 @@ public:
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
TSlot getSlotFor(const CCreature *c, 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;
@ -114,9 +115,10 @@ public:
int getArmyStrength() const; //sum of AI values of creatures
ui64 getPower (TSlot slot) const; //value of specific stack
std::string getRoughAmount (TSlot slot) const; //rough size of specific stack
bool hasStackAtSlot(TSlot slot) const;
bool contains(const CStackInstance *stack) const;
bool canBeMergedWith(const CCreatureSet &cs) const;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -90,10 +90,14 @@ 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 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 bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0;
virtual bool changeStackType(const StackLocation &sl, CCreature *c) =0;
virtual bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count = -1) =0; //count -1 => moves whole stack
virtual bool eraseStack(const StackLocation &sl) =0;
virtual bool swapStacks(const StackLocation &sl1, const StackLocation &sl2) =0;
virtual bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count) =0; //makes new stack or increases count of already existing
virtual void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished) =0; //merges army from src do dst or opens a garrison window
virtual bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count) = 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

@ -736,12 +736,17 @@ struct StackLocation
}
};
struct ChangeStackCount : CPackForClient //521
struct CGarrisonOperationPack : CPackForClient
{
};
struct ChangeStackCount : CGarrisonOperationPack //521
{
StackLocation sl;
TQuantity count;
ui8 absoluteValue; //if not -> count will be added (or subtracted if negative)
void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
@ -750,11 +755,12 @@ struct ChangeStackCount : CPackForClient //521
}
};
struct SetStackType : CPackForClient //522
struct SetStackType : CGarrisonOperationPack //522
{
StackLocation sl;
CCreature *type;
void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
@ -763,10 +769,11 @@ struct SetStackType : CPackForClient //522
}
};
struct EraseStack : CPackForClient //523
struct EraseStack : CGarrisonOperationPack //523
{
StackLocation sl;
void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
@ -775,10 +782,11 @@ struct EraseStack : CPackForClient //523
}
};
struct SwapStacks : CPackForClient //524
struct SwapStacks : CGarrisonOperationPack //524
{
StackLocation sl1, sl2;
void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
@ -787,11 +795,12 @@ struct SwapStacks : CPackForClient //524
}
};
struct InsertNewStack : CPackForClient //525
struct InsertNewStack : CGarrisonOperationPack //525
{
StackLocation sl;
CStackInstance *stack;
void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)
@ -801,11 +810,12 @@ struct InsertNewStack : CPackForClient //525
};
//moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
struct RebalanceStacks : CPackForClient //525
struct RebalanceStacks : CGarrisonOperationPack //525
{
StackLocation src, dst;
TQuantity count;
void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs);
template <typename Handler> void serialize(Handler &h, const int version)

View File

@ -625,7 +625,11 @@ DLL_EXPORT void EraseStack::applyGs( CGameState *gs )
DLL_EXPORT void SwapStacks::applyGs( CGameState *gs )
{
CStackInstance *s1 = sl1.army->detachStack(sl1.slot),
*s2 = sl2.army->detachStack(sl2.slot);
sl2.army->putStack(sl2.slot, s1);
sl1.army->putStack(sl1.slot, s2);
}
DLL_EXPORT void InsertNewStack::applyGs( CGameState *gs )

View File

@ -640,20 +640,13 @@ 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->getSlotFor(raisedStack.type->idNumber);
TSlot slot = winnerHero->getSlotFor(raisedStack.type);
if (slot != -1)
{
SetGarrisons sg;
sg.garrs[winnerHero->id] = winnerHero->getArmy();
sg.garrs[winnerHero->id].addToSlot(slot, raisedStack.type->idNumber, raisedStack.count);
// 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);
addToSlot(StackLocation(winnerHero, slot), raisedStack.type, raisedStack.count);
}
}
}
@ -926,6 +919,7 @@ int CGameHandler::moveStack(int stack, int dest)
return ret;
}
CGameHandler::CGameHandler(void)
{
QID = 1;
@ -2624,8 +2618,8 @@ 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->getArmy(), temp2 = s2->getArmy(),
&S1 = temp1, &S2 = (s1!=s2)?(temp2):(temp1);
CCreatureSet &S1 = *s1, &S2 = *s2;
StackLocation sl1(s1, p1), sl2(s2, p2);
if(!isAllowedExchange(id1,id2))
{
@ -2641,14 +2635,8 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2,
complain("Can't take troops from another player!");
return false;
}
std::swap(S1.slots[p1], S2.slots[p2]); //swap slots
//if one of them is empty, remove entry
if(!S1.slots[p1]->count)
S1.slots.erase(p1);
if(!S2.slots[p2]->count)
S2.slots.erase(p2);
swapStacks(sl1, sl2);
}
else if(what==2)//merge
{
@ -2656,11 +2644,17 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2,
|| ((s1->tempOwner != player && s1->tempOwner != 254) && S2.slots[p2]->count) && complain("Can't take troops from another player!"))
return false;
S2.slots[p2]->count += S1.slots[p1]->count;
S1.slots.erase(p1);
moveStack(sl1, sl2);
}
else if(what==3) //split
{
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;
}
//general conditions checking
if((!vstd::contains(S1.slots,p1) && complain("no creatures to split"))
|| (val<1 && complain("no creatures to split")) )
@ -2679,8 +2673,9 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2,
return false;
}
S2.slots[p2]->count = val;
S1.slots[p1]->count = total - val;
moveStack(sl1, sl2, val - S2.slots[p2]->count);
//S2.slots[p2]->count = val;
//S1.slots[p1]->count = total - val;
}
else //split one stack to the two
{
@ -2689,35 +2684,12 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2,
complain("Cannot split that stack, not enough creatures!");
return false;
}
S2.slots[p2]->type = S1.slots[p1]->type;
S2.slots[p2]->count = val;
S1.slots[p1]->count -= val;
moveStack(sl1, sl2, val);
}
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;
}
if(!S1.slots[p1]->count) //if we've moved all creatures
S1.slots.erase(p1);
}
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!");
return false; //leave without applying changes to garrison
}
//apply changes
SetGarrisons sg;
sg.garrs[id1] = S1;
if(s1 != s2)
sg.garrs[id2] = S2;
sendAndApply(&sg);
return true;
}
@ -2753,10 +2725,8 @@ bool CGameHandler::disbandCreature( si32 id, ui8 pos )
complain("Illegal call to disbandCreature - no such stack in army!");
return false;
}
s1->slots.erase(pos);
SetGarrisons sg;
sg.garrs[id] = s1->getArmy();
sendAndApply(&sg);
eraseStack(StackLocation(s1, pos));
return true;
}
@ -2983,10 +2953,7 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram, si32 from
}
else
{
SetGarrisons sg;
sg.garrs[dst->id] = dst->getArmy();
sg.garrs[dst->id] .addToSlot(slot, crid, cram);
sendAndApply(&sg);
addToSlot(StackLocation(dst, slot), c, cram);
}
return true;
}
@ -2994,6 +2961,7 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram, si32 from
bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
{
CArmedInstance *obj = static_cast<CArmedInstance*>(gs->map->objects[objid]);
assert(obj->hasStackAtSlot(pos));
UpgradeInfo ui = gs->getUpgradeInfo(obj->getStack(pos));
int player = obj->tempOwner;
int crQuantity = obj->slots[pos]->count;
@ -3027,21 +2995,20 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
}
//upgrade creature
SetGarrisons sg;
sg.garrs[objid] = obj->getArmy();
sg.garrs[objid].slots[pos]->setType(upgID);
sendAndApply(&sg);
changeStackType(StackLocation(obj, pos), VLC->creh->creatures[upgID]);
return true;
}
void CGameHandler::changeStackType(const StackLocation &sl, CCreature *c)
bool CGameHandler::changeStackType(const StackLocation &sl, CCreature *c)
{
assert(sl.army->getCreature(sl.slot));
if(!sl.army->hasStackAtSlot(sl.slot))
COMPLAIN_RET("Cannot find a stack to change type");
SetStackType sst;
sst.sl = sl;
sst.type = c;
sendAndApply(&sst);
return true;
}
bool CGameHandler::garrisonSwap( si32 tid )
@ -3049,42 +3016,43 @@ 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->getArmy(), cso = town->getArmy();
if(!town->visitingHero->canBeMergedWith(*town))
{
complain("Cannot make garrison swap, not enough free slots!");
return false;
}
const CCreatureSet &cso = *town;
const CCreatureSet &csn = *town->visitingHero;
while(!cso.slots.empty())//while there are unmoved creatures
{
int pos = csn.getSlotFor(cso.slots.begin()->second->type->idNumber);
if(pos<0)
TSlots::const_iterator i = cso.slots.begin(); //iterator to stack to move
StackLocation sl(town, i->first); //location of stack to move
TSlot pos = csn.getSlotFor(i->second->type);
if(pos < 0)
{
//try to merge two other stacks to make place
std::pair<TSlot, TSlot> toMerge;
if(csn.mergableStacks(toMerge, cso.slots.begin()->first))
if(csn.mergableStacks(toMerge, i->first))
{
//merge
csn.slots[toMerge.second]->count += csn.slots[toMerge.first]->count;
csn.slots[toMerge.first] = cso.slots.begin()->second;
moveStack(StackLocation(town->visitingHero, toMerge.first), StackLocation(town->visitingHero, toMerge.second)); //merge toMerge.first into toMerge.second
moveStack(sl, StackLocation(town->visitingHero, toMerge.first)); //move stack to freed slot
}
else
{
complain("Cannot make garrison swap, not enough free slots!");
complain("Unexpected failure during an attempt to merge town and visiting hero armies!");
return false;
}
}
else if(csn.slots.find(pos) != csn.slots.end()) //add creatures to the existing stack
else
{
csn.slots[pos]->count += cso.slots.begin()->second->count;
moveStack(sl, StackLocation(town->visitingHero, pos));
}
else //move stack on the free pos
{
csn.slots[pos]->type = cso.slots.begin()->second->type;
csn.slots[pos]->count = cso.slots.begin()->second->count;
}
cso.slots.erase(cso.slots.begin());
}
SetGarrisons sg;
sg.garrs[town->visitingHero->id] = csn;
sg.garrs[town->id] = csn;
sendAndApply(&sg);
SetHeroesInTown intown;
intown.tid = tid;
intown.visiting = -1;
@ -3106,25 +3074,14 @@ bool CGameHandler::garrisonSwap( si32 tid )
intown.garrison = -1;
intown.visiting = town->garrisonHero->id;
sendAndApply(&intown);
//town will be empty
SetGarrisons sg;
sg.garrs[tid] = CCreatureSet();
sendAndApply(&sg);
return true;
}
else if (town->garrisonHero && town->visitingHero) //swap visiting and garrison hero
{
SetGarrisons sg;
sg.garrs[town->id] = town->visitingHero->getArmy();;
sg.garrs[town->garrisonHero->id] = town->garrisonHero->getArmy();
SetHeroesInTown intown;
intown.tid = tid;
intown.garrison = town->visitingHero->id;
intown.visiting = town->garrisonHero->id;
sendAndApply(&intown);
sendAndApply(&sg);
return true;
}
else
@ -3537,14 +3494,7 @@ bool CGameHandler::sellCreatures(ui32 count, const IMarket *market, const CGHero
assert(0);
}
SetGarrisons sg;
sg.garrs[hero->id] = hero->getArmy();
if(s.count > count)
sg.garrs[hero->id].setStackCount(slot, s.count - count);
else
sg.garrs[hero->id].eraseStack(slot);
sendAndApply(&sg);
changeStackCount(StackLocation(hero, slot), -count);
SetResource sr;
sr.player = hero->tempOwner;
@ -3561,13 +3511,14 @@ bool CGameHandler::transformInUndead(const IMarket *market, const CGHeroInstance
if (hero)
army = hero;
else
{
army = dynamic_cast<const CGTownInstance *>(market->o);
}
if (!army)
COMPLAIN_RET("Incorrect call to transform in undead!");
if(!vstd::contains(army->Slots(), slot))
if(!army->hasStackAtSlot(slot))
COMPLAIN_RET("Army doesn't have any creature in that slot!");
const CStackInstance &s = army->getStack(slot);
int resCreature;//resulting creature - bone dragons or skeletons
@ -3575,10 +3526,8 @@ bool CGameHandler::transformInUndead(const IMarket *market, const CGHeroInstance
resCreature = 68;
else
resCreature = 56;
SetGarrisons sg;
sg.garrs[army->id] = army->getArmy();
sg.garrs[army->id].setCreature(slot, resCreature, s.count);
sendAndApply(&sg);
changeStackType(StackLocation(army, slot), VLC->creh->creatures[resCreature]);
return true;
}
@ -4054,30 +4003,22 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
else if(message == "vcmiainur") //gives 5 archangels into each slot
{
CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection);
const CCreature *archangel = VLC->creh->creatures[13];
if(!hero) return;
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, 13, 5);
sendAndApply(&sg);
for(int i = 0; i < ARMY_SIZE; i++)
if(!hero->hasStackAtSlot(i))
insertNewStack(StackLocation(hero, i), archangel, 10);
}
else if(message == "vcmiangband") //gives 10 black knight into each slot
{
CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection);
const CCreature *blackKnight = VLC->creh->creatures[66];
if(!hero) return;
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, 66, 10);
sendAndApply(&sg);
for(int i = 0; i < ARMY_SIZE; i++)
if(!hero->hasStackAtSlot(i))
insertNewStack(StackLocation(hero, i), blackKnight, 10);
}
else if(message == "vcminoldor") //all war machines
{
@ -5244,7 +5185,6 @@ bool CGameHandler::tryAttackingGuard(const int3 &guardPos, const CGHeroInstance
bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstance *hero, TSlot slot, ui32 count)
{
int oldCount = hero->getStackCount(slot);
int newCount = oldCount - count;
if(oldCount < count)
COMPLAIN_RET("Not enough creatures to sacrifice!")
@ -5253,18 +5193,12 @@ bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstanc
int crid = hero->getStack(slot).type->idNumber;
SetGarrisons sg;
sg.garrs[hero->id] = hero->getArmy();
if(newCount)
sg.garrs[hero->id].setStackCount(slot, newCount);
else
sg.garrs[hero->id].eraseStack(slot);
sendAndApply(&sg);
changeStackCount(StackLocation(hero, slot), -count);
int dump, exp;
market->getOffer(crid, 0, dump, exp, CREATURE_EXP);
exp *= count;
changePrimSkill (hero->id, 4, exp*(100+hero->getSecSkillLevel(21)*5)/100.0f);
changePrimSkill(hero->id, 4, exp*(100+hero->getSecSkillLevel(21)*5)/100.0f);
return true;
}
@ -5280,26 +5214,149 @@ bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * h
return true;
}
void CGameHandler::insertNewStack(const StackLocation &sl, CCreature *c, TQuantity count)
bool CGameHandler::insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count)
{
if(sl.army->hasStackAtSlot(sl.slot))
COMPLAIN_RET("Slot is already taken!");
InsertNewStack ins;
ins.sl = sl;
ins.stack = new CStackInstance(c, count);
sendAndApply(&ins);
return true;
}
void CGameHandler::eraseStack(const StackLocation &sl)
bool CGameHandler::eraseStack(const StackLocation &sl)
{
if(!sl.army->hasStackAtSlot(sl.slot))
COMPLAIN_RET("Cannot find a stack to erase");
if(sl.army->Slots().size() == 1 //from the last stack
&& sl.army->needsLastStack()) //that must be left
{
COMPLAIN_RET("Cannot erase the last stack!");
}
EraseStack es;
es.sl = sl;
sendAndApply(&es);
return true;
}
void CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue /*= false*/)
bool CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue /*= false*/)
{
ChangeStackCount csc;
csc.sl = sl;
csc.count = count;
csc.absoluteValue = absoluteValue;
sendAndApply(&csc);
TQuantity currentCount = sl.army->getStackCount(sl.slot);
if(absoluteValue && count < 0
|| !absoluteValue && -count > currentCount)
{
COMPLAIN_RET("Cannot take more stacks than present!");
}
if(currentCount == -count && !absoluteValue
|| !count && absoluteValue)
{
eraseStack(sl);
}
else
{
ChangeStackCount csc;
csc.sl = sl;
csc.count = count;
csc.absoluteValue = absoluteValue;
sendAndApply(&csc);
}
return true;
}
bool CGameHandler::addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count)
{
const CCreature *slotC = sl.army->getCreature(sl.slot);
if(!slotC) //slot is empty
insertNewStack(sl, c, count);
else if(c == slotC)
changeStackCount(sl, count);
else
{
tlog1 << "Cannot add " << c->namePl << " to slot " << sl.slot << std::endl;
COMPLAIN_RET("Cannot add stack to slot!");
}
return true;
}
void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished)
{
if(!dst->canBeMergedWith(*src))
{
boost::function<void()> removeOrNot = 0;
if(removeObjWhenFinished)
removeOrNot = boost::bind(&IGameCallback::removeObject,this,src->id);
showGarrisonDialog(src->id, dst->id, true, removeOrNot); //show garrison window and optionally remove ourselves from map when player ends
}
else //merge
{
while(src->slots.size()) //there are not moved cres
{
TSlots::const_iterator i = src->slots.begin();
TSlot dstSlot = dst->getSlotFor(i->second->type);
if(dstSlot >= 0) //there is place
{
moveStack(StackLocation(src, i->first), StackLocation(dst, dstSlot), i->second->count);
}
else
{
tlog1 << "Unexpected Failure on merging armies!\n";
return;
}
}
if(removeObjWhenFinished)
removeObject(src->id);
}
}
bool CGameHandler::moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count)
{
if(!src.army->hasStackAtSlot(src.slot))
COMPLAIN_RET("No stack to move!");
if(dst.army->hasStackAtSlot(dst.slot) && dst.army->getCreature(dst.slot) != src.army->getCreature(src.slot))
COMPLAIN_RET("Cannot move: stack of different type at destination pos!");
if(count == -1)
{
count = src.army->getStackCount(src.slot);
}
if(src.army != dst.army //moving away
&& count == src.army->getStackCount(src.slot) //all creatures
&& src.army->Slots().size() == 1 //from the last stack
&& src.army->needsLastStack()) //that must be left
{
COMPLAIN_RET("Cannot move away the alst creature!");
}
RebalanceStacks rs;
rs.src = src;
rs.dst = dst;
rs.count = count;
sendAndApply(&rs);
return true;
}
bool CGameHandler::swapStacks(const StackLocation &sl1, const StackLocation &sl2)
{
if(!sl1.army->hasStackAtSlot(sl1.slot))
return moveStack(sl2, sl1);
else if(!sl2.army->hasStackAtSlot(sl2.slot))
return moveStack(sl1, sl2);
else
{
SwapStacks ss;
ss.sl1 = sl1;
ss.sl2 = sl2;
sendAndApply(&ss);
return true;
}
}

View File

@ -138,10 +138,14 @@ 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 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);
bool changeStackType(const StackLocation &sl, CCreature *c);
bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false);
bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count);
bool eraseStack(const StackLocation &sl);
bool swapStacks(const StackLocation &sl1, const StackLocation &sl2);
bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count);
void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished);
bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1);
void showCompInfo(ShowInInfobox * comp);
void heroVisitCastle(int obj, int heroID);
void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h);

View File

@ -22,6 +22,7 @@
*
*/
CGameState* CPackForServer::GS(CGameHandler *gh)
{
return gh->gs;