From 02e4ef507eaef210698fee4be1c5ac1bb42ea57c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Sun, 12 Dec 2010 23:44:16 +0000 Subject: [PATCH] Stacks #5: giving creatures, practically finished (many fixes needed). --- client/CBattleInterface.cpp | 2 +- client/Client.h | 4 +- hch/CObjectHandler.cpp | 8 +- hch/CObjectHandler.h | 2 +- lib/CCreatureSet.cpp | 31 ++++++-- lib/CCreatureSet.h | 2 +- lib/IGameCallback.h | 4 +- lib/map.cpp | 2 +- server/CGameHandler.cpp | 142 +++++++++++++++--------------------- server/CGameHandler.h | 5 +- 10 files changed, 96 insertions(+), 106 deletions(-) diff --git a/client/CBattleInterface.cpp b/client/CBattleInterface.cpp index 5c4b20299..fb9a0ecd2 100644 --- a/client/CBattleInterface.cpp +++ b/client/CBattleInterface.cpp @@ -3589,7 +3589,7 @@ void CBattleHex::mouseMoved(const SDL_MouseMotionEvent &sEvent) if(hovered && strictHovered) //print attacked creature to console { - if(myInterface->console->alterTxt.size() == 0 && myInterface->curInt->cb->battleGetStackByID(myNumber) != NULL && + if(myInterface->console->alterTxt.size() == 0 && myInterface->curInt->cb->battleGetStackByPos(myNumber) != NULL && myInterface->curInt->cb->battleGetStackByPos(myNumber)->owner != myInterface->curInt->playerID && myInterface->curInt->cb->battleGetStackByPos(myNumber)->alive()) { diff --git a/client/Client.h b/client/Client.h index dea748714..98397ce4e 100644 --- a/client/Client.h +++ b/client/Client.h @@ -110,7 +110,7 @@ public: void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function &cb){}; void showThievesGuildWindow(int requestingObjId){}; void giveResource(int player, int which, int val){}; - void giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) {}; + void giveCreatures (const CArmedInstance * objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) {}; void takeCreatures (int objid, TSlots creatures){}; void takeCreatures (int objid, std::vector creatures){}; bool changeStackType(const StackLocation &sl, CCreature *c){return false;}; @@ -119,7 +119,7 @@ public: bool eraseStack(const StackLocation &sl, bool forceRemoval = false){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){} + void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging){} bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1){return false;} void showCompInfo(ShowInInfobox * comp){}; void heroVisitCastle(int obj, int heroID){}; diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index ce32c6144..49eec8077 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -3106,7 +3106,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co if(cost) cb->giveResource(h->tempOwner,6,-cost); - cb->tryJoiningArmy(this, h, true); + cb->tryJoiningArmy(this, h, true, false); // int slot = h->getSlotFor(subID); // if(slot >= 0) //there is place // { @@ -4461,7 +4461,7 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward { CCreatureSet creatures; creatures.setCreature(0, rID, rVal); - cb->giveCreatures(id, h, creatures, false); + cb->giveCreatures(this, h, creatures, false); } break; default: @@ -5029,7 +5029,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con iw.text.addReplacement(h->name); cb->showInfoDialog(&iw); - cb->giveCreatures (id, h, creatures, true); + cb->giveCreatures(this, h, creatures, true); //boost::bind(&CGPandoraBox::endBattle, this, h, _1) } if(!afterBattle && message.size()) @@ -5909,7 +5909,7 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons iw.text.addReplacement(loot.buildList()); iw.text.addReplacement(h->name); cb->showInfoDialog(&iw); - cb->giveCreatures (id, h, ourArmy, false); + cb->giveCreatures(this, h, ourArmy, false); } cb->setObjProperty (id, 15, 0); //bc = NULL } diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index ab3fd11f1..7b104582d 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -675,7 +675,7 @@ public: } }; -class DLL_EXPORT CGSeerHut : public CGObjectInstance, public CQuest +class DLL_EXPORT CGSeerHut : public CArmedInstance, public CQuest //army is used when giving reward { public: ui8 rewardType; //type of reward: 0 - no reward; 1 - experience; 2 - mana points; 3 - morale bonus; 4 - luck bonus; 5 - resources; 6 - main ability bonus (attak, defence etd.); 7 - secondary ability gain; 8 - artifact; 9 - spell; 10 - creature diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index 5dd14720d..1db035c9a 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -345,17 +345,32 @@ void CCreatureSet::setStackType(TSlot slot, const CCreature *type) s->setType(type->idNumber); } -bool CCreatureSet::canBeMergedWith(const CCreatureSet &cs) const +bool CCreatureSet::canBeMergedWith(const CCreatureSet &cs, bool allowMergingStacks) const { - std::set cres; + if(!allowMergingStacks) + { + int freeSlots = stacksCount() - ARMY_SIZE; + std::set cresToAdd; + for(TSlots::const_iterator i = cs.slots.begin(); i != cs.slots.end(); i++) + { + TSlot dest = getSlotFor(i->second->type); + if(dest < 0 || hasStackAtSlot(dest)) + cresToAdd.insert(i->second->type); + } + return cresToAdd.size() <= freeSlots; + } + else + { + std::set 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); + //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; + return cres.size() <= ARMY_SIZE; + } } bool CCreatureSet::hasStackAtSlot(TSlot slot) const diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index 98d3ed8af..efdafe22f 100644 --- a/lib/CCreatureSet.h +++ b/lib/CCreatureSet.h @@ -124,7 +124,7 @@ public: bool hasStackAtSlot(TSlot slot) const; bool contains(const CStackInstance *stack) const; - bool canBeMergedWith(const CCreatureSet &cs) const; + bool canBeMergedWith(const CCreatureSet &cs, bool allowMergingStacks = true) const; template void serialize(Handler &h, const int version) { diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index f953924de..36cb22f64 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -87,7 +87,7 @@ public: virtual void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function &cb) =0; //cb will be called when player closes garrison window virtual void showThievesGuildWindow(int requestingObjId) =0; virtual void giveResource(int player, int which, int val)=0; - virtual void giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0; + virtual void giveCreatures (const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0; //virtual void takeCreatures (int objid, TSlots creatures) =0; virtual void takeCreatures (int objid, std::vector creatures) =0; virtual bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0; @@ -96,7 +96,7 @@ public: virtual bool eraseStack(const StackLocation &sl, bool forceRemoval = false) =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 void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging) =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; diff --git a/lib/map.cpp b/lib/map.cpp index a333e02e7..1bbd11ae8 100644 --- a/lib/map.cpp +++ b/lib/map.cpp @@ -1439,7 +1439,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) CStackInstance *hlp = new CStackInstance(); hlp->count = readNormalNr(bufor,i, 2); i+=2; //type will be set during initialization - cre->slots[0] = hlp; + cre->putStack(0, hlp); cre->character = bufor[i]; ++i; bool isMesTre = bufor[i]; ++i; //true if there is message or treasury diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index d46c2c083..731c5596b 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include /* @@ -50,6 +51,7 @@ extern bool end2; #undef max #endif +#define COMPLAIN_RET_IF(cond, txt) do {if(cond){complain(txt); return;}} while(0) #define COMPLAIN_RET(txt) {complain(txt); return false;} #define NEW_ROUND BattleNextRound bnr;\ bnr.round = gs->curB->round + 1;\ @@ -2062,41 +2064,25 @@ void CGameHandler::giveResource(int player, int which, int val) sr.val = gs->players.find(player)->second.resources[which]+val; sendAndApply(&sr); } -void CGameHandler::giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) + +void CGameHandler::giveCreatures(const CArmedInstance *obj, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) { - assert(0); -// if (creatures.stacksCount() <= 0) -// return; -// CCreatureSet heroArmy = h->getArmy(); -// std::set takenSlots; -// for (TSlots::const_iterator it = creatures.Slots().begin(); it != creatures.Slots().end(); it++) -// { -// int slot = heroArmy.getSlotFor(it->second->type->idNumber); -// if (slot >= 0) -// { -// heroArmy.addToSlot(slot, it->second); //move all matching creatures to hero's army -// takenSlots.insert(it->first); //slot id -// } -// } -// for (std::set::iterator it = takenSlots.begin(); it != takenSlots.end(); it++) -// creatures.eraseStack(*it); //delete them from used army -// -// SetGarrisons sg; -// sg.garrs[h->id] = heroArmy; -// sg.garrs[objid] = creatures; -// sendAndApply (&sg); -// -// if (remove) //show garrison window and let player pick remaining creatures -// { -// if (creatures.stacksCount()) //Pandora needs to exist until we close garrison window -// { -// showGarrisonDialog (objid, h->id, true, boost::bind(&CGameHandler::removeObject, this, objid)); -// } -// else -// removeObject(objid); -// } -// else if (creatures.stacksCount()) -// showGarrisonDialog (objid, h->id, true, 0); + boost::function removeOrNot = 0; + if(remove) + removeOrNot = boost::bind(&CGameHandler::removeObject, this, obj->id); + + COMPLAIN_RET_IF(!creatures.stacksCount(), "Strange, giveCreatures called without args!"); + COMPLAIN_RET_IF(obj->stacksCount(), "Cannot give creatures from not-cleared object!"); + COMPLAIN_RET_IF(creatures.stacksCount() > ARMY_SIZE, "Too many stacks to give!"); + + //first we move creatures to give to make them army of object-source + for(int i = 0; creatures.stacksCount(); i++) + { + TSlots::const_iterator stack = creatures.Slots().begin(); + addToSlot(StackLocation(obj, i), stack->second->type, stack->second->count); + } + + tryJoiningArmy(obj, h, remove, false); } void CGameHandler::takeCreatures(int objid, std::vector creatures) @@ -2994,6 +2980,38 @@ bool CGameHandler::changeStackType(const StackLocation &sl, CCreature *c) return true; } +void CGameHandler::moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging) +{ + assert(src->canBeMergedWith(*dst, allowMerging)); + while(!src->stacksCount())//while there are unmoved creatures + { + TSlots::const_iterator i = src->Slots().begin(); //iterator to stack to move + StackLocation sl(src, i->first); //location of stack to move + + TSlot pos = dst->getSlotFor(i->second->type); + if(pos < 0) + { + //try to merge two other stacks to make place + std::pair toMerge; + if(dst->mergableStacks(toMerge, i->first) && allowMerging) + { + moveStack(StackLocation(dst, toMerge.first), StackLocation(dst, toMerge.second)); //merge toMerge.first into toMerge.second + assert(!dst->hasStackAtSlot(toMerge.first)); //we have now a new free slot + moveStack(sl, StackLocation(dst, toMerge.first)); //move stack to freed slot + } + else + { + complain("Unexpected failure during an attempt to move army from " + src->nodeName() + " to " + dst->nodeName() + "!"); + return; + } + } + else + { + moveStack(sl, StackLocation(dst, pos)); + } + } +} + bool CGameHandler::garrisonSwap( si32 tid ) { CGTownInstance *town = gs->getTown(tid); @@ -3005,36 +3023,8 @@ bool CGameHandler::garrisonSwap( si32 tid ) 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 - { - 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 toMerge; - if(csn.mergableStacks(toMerge, i->first)) - { - 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("Unexpected failure during an attempt to merge town and visiting hero armies!"); - return false; - } - } - else - { - moveStack(sl, StackLocation(town->visitingHero, pos)); - } - } + + moveArmy(town, town->visitingHero, true); SetHeroesInTown intown; intown.tid = tid; @@ -5274,15 +5264,14 @@ bool CGameHandler::addToSlot(const StackLocation &sl, const CCreature *c, TQuant changeStackCount(sl, count); else { - tlog1 << "Cannot add " << c->namePl << " to slot " << sl.slot << std::endl; - COMPLAIN_RET("Cannot add stack to slot!"); + COMPLAIN_RET("Cannot add " + c->namePl + " to slot " + boost::lexical_cast(sl.slot) + "!"); } return true; } -void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished) +void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging) { - if(!dst->canBeMergedWith(*src)) + if(!dst->canBeMergedWith(*src, allowMerging)) { boost::function removeOrNot = 0; if(removeObjWhenFinished) @@ -5291,22 +5280,7 @@ void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstanc } 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; - } - } - + moveArmy(src, dst, allowMerging); if(removeObjWhenFinished) removeObject(src->id); } diff --git a/server/CGameHandler.h b/server/CGameHandler.h index f1701bd31..5d8dd1a8a 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -148,7 +148,7 @@ public: void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function &cb); void showThievesGuildWindow(int requestingObjId); //TODO: make something more general? void giveResource(int player, int which, int val); - void giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove); + void giveCreatures (const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove); void takeCreatures (int objid, std::vector creatures); bool changeStackType(const StackLocation &sl, CCreature *c); bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false); @@ -156,7 +156,7 @@ public: bool eraseStack(const StackLocation &sl, bool forceRemoval = false); 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); + void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging); bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1); void showCompInfo(ShowInInfobox * comp); void heroVisitCastle(int obj, int heroID); @@ -221,6 +221,7 @@ public: void engageIntoBattle( ui8 player ); bool dig(const CGHeroInstance *h); bool castSpell(const CGHeroInstance *h, int spellID, const int3 &pos); + void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging); template void serialize(Handler &h, const int version) {