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:
parent
7c3f3d20c3
commit
fdb541d81e
@ -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){};
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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 )
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -22,6 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
CGameState* CPackForServer::GS(CGameHandler *gh)
|
||||
{
|
||||
return gh->gs;
|
||||
|
Loading…
Reference in New Issue
Block a user