From bce805daccecf8a171d33c541078edf3bab2f80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Wed, 10 Nov 2010 00:06:25 +0000 Subject: [PATCH] Restored Warmonger's changes to artifacts system. They will be subject of my further work, along with next part of bonus system. --- CCallback.cpp | 1 + client/CKingdomInterface.cpp | 10 +- client/Client.h | 3 +- client/GUIClasses.cpp | 14 +-- hch/CArtHandler.cpp | 103 +++++++++++++------- hch/CArtHandler.h | 54 +++++++---- hch/CCampaignHandler.cpp | 2 +- hch/CObjectHandler.cpp | 102 +++++++++++-------- hch/CObjectHandler.h | 7 +- lib/CGameState.cpp | 2 +- lib/CGameState.h | 4 +- lib/Connection.cpp | 3 +- lib/IGameCallback.h | 3 +- lib/NetPacks.h | 23 ++++- lib/NetPacksLib.cpp | 39 ++++++-- lib/RegisterTypes.cpp | 1 + lib/map.cpp | 16 +-- lib/map.h | 5 +- server/CGameHandler.cpp | 183 ++++++++++++++++++++++++----------- server/CGameHandler.h | 5 +- server/NetPacksServer.cpp | 2 +- 21 files changed, 388 insertions(+), 194 deletions(-) diff --git a/CCallback.cpp b/CCallback.cpp index b52dcaaa8..64c403a86 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -17,6 +17,7 @@ #include #include #include "hch/CSpellHandler.h" +#include "hch/CArtHandler.h" #ifdef min #undef min #endif diff --git a/client/CKingdomInterface.cpp b/client/CKingdomInterface.cpp index 554aa0ad4..c8d4f43ce 100644 --- a/client/CKingdomInterface.cpp +++ b/client/CKingdomInterface.cpp @@ -784,7 +784,7 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero) for (int i=0; itype = hero->getArtAtPos(i); + artifacts[i]->type = hero->getArtAtPos(i)->id; if (artifacts[i]->type<0 || artifacts[i]->type == 145 ) artifacts[i]->hoverText = CGI->generaltexth->heroscrn[11]; else @@ -796,7 +796,7 @@ void CKingdomInterface::CHeroItem::setHero(const CGHeroInstance * newHero) for (int i=0; itype = hero->getArtAtPos(19+i); + backpack[i]->type = hero->getArtAtPos(19+i)->id; if (backpack[i]->type<0) backpack[i]->hoverText =""; else @@ -847,7 +847,7 @@ void CKingdomInterface::CHeroItem::scrollArts(int move) backpackPos = ( backpackPos + move + hero->artifacts.size()) % hero->artifacts.size(); for (int i=0; itype = hero->getArtAtPos(19+(backpackPos + i)%hero->artifacts.size()); + backpack[i]->type = hero->getArtAtPos(19+(backpackPos + i)%hero->artifacts.size())->id; if (backpack[i]->type<0) backpack[i]->hoverText =""; else @@ -912,7 +912,7 @@ void CKingdomInterface::CHeroItem::showAll(SDL_Surface * to) case 0://equipped arts for (int i = iter ; igetArtAtPos(i); + int artID = hero->getArtAtPos(i)->id; if (artID>=0) blitAt(graphics->artDefs->ourImages[artID].bitmap,pos.x+268+48*(i%9),pos.y+66,to); } @@ -923,7 +923,7 @@ void CKingdomInterface::CHeroItem::showAll(SDL_Surface * to) int max = hero->artifacts.size(); iter = std::min(8, max); for (size_t it = 0 ; itartDefs->ourImages[hero->artifacts[(it+backpackPos)%max]].bitmap,pos.x+293+48*it,pos.y+66,to); + blitAt(graphics->artDefs->ourImages[hero->artifacts[(it+backpackPos)%max]->id].bitmap,pos.x+293+48*it,pos.y+66,to); break; } show(to); diff --git a/client/Client.h b/client/Client.h index 4c9a75593..827cf6eed 100644 --- a/client/Client.h +++ b/client/Client.h @@ -117,7 +117,8 @@ public: void heroVisitCastle(int obj, int heroID){}; void stopHeroVisitCastle(int obj, int heroID){}; void giveHeroArtifact(int artid, int hid, int position){}; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack - bool removeArtifact(int artid, int hid){return false;}; + void giveNewArtifact(int hid, int position){}; + bool removeArtifact(CArtifact* art, int hid){return false;}; void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function cb = 0, const CGTownInstance *town = NULL){}; //use hero=NULL for no hero void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index 17509401b..2f3c8b0bf 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -2640,7 +2640,7 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState) movedArt = CGI->arth->artifacts[id]; aw->arts->commonInfo->srcAOH = aw->arts; aw->arts->commonInfo->srcArtifact = movedArt; - aw->arts->commonInfo->srcSlotID = 19 + vstd::findPos(aw->hero->artifacts, movedArt->id); + aw->arts->commonInfo->srcSlotID = 19 + vstd::findPos(aw->hero->artifacts, const_cast(movedArt)); aw->arts->commonInfo->destAOH = aw->arts; CGI->curh->dragAndDropCursor(graphics->artDefs->ourImages[movedArt->id].bitmap); @@ -3622,10 +3622,10 @@ void CAltarWindow::SacrificeAll() } else { - for(std::map::const_iterator i = hero->artifWorn.begin(); i != hero->artifWorn.end(); i++) + for(std::map::const_iterator i = hero->artifWorn.begin(); i != hero->artifWorn.end(); i++) { - if(i->second != 145) //ignore locks from assembled artifacts - moveFromSlotToAltar(i->first, NULL, i->second); + if(i->second->id != 145) //ignore locks from assembled artifacts + moveFromSlotToAltar(i->first, NULL, i->second->id); } SacrificeBackpack(); @@ -3778,13 +3778,13 @@ void CAltarWindow::SacrificeBackpack() for (int i = 0; i < hero->artifacts.size(); i++) { - if(vstd::contains(toOmmit, hero->artifacts[i])) + if(vstd::contains(toOmmit, hero->artifacts[i]->id)) { - toOmmit -= hero->artifacts[i]; + toOmmit -= hero->artifacts[i]->id; continue; } - putOnAltar(NULL, hero->artifacts[i]); + putOnAltar(NULL, hero->artifacts[i]->id); } arts->scrollBackpack(0); calcTotalExp(); diff --git a/hch/CArtHandler.cpp b/hch/CArtHandler.cpp index 527657ff6..7760bc326 100644 --- a/hch/CArtHandler.cpp +++ b/hch/CArtHandler.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "../lib/VCMI_Lib.h" extern CLodHandler *bitmaph; using namespace boost::assign; @@ -47,25 +48,31 @@ bool CArtifact::isBig () const return VLC->arth->isBigArtifact(id); } +bool CArtifact::isModable () const +{ + return (bool)dynamic_cast(this); +} + /** * Checks whether the artifact fits at a given slot. * @param artifWorn A hero's set of worn artifacts. */ -bool CArtifact::fitsAt (const std::map &artifWorn, ui16 slotID) const +bool CArtifact::fitsAt (const std::map &artifWorn, ui16 slotID) const { if (!vstd::contains(possibleSlots, slotID)) return false; // Can't put an artifact in a locked slot. - std::map::const_iterator it = artifWorn.find(slotID); - if (it != artifWorn.end() && it->second == 145) + std::map::const_iterator it = artifWorn.find(slotID); + if (it != artifWorn.end() && it->second->id == 145) return false; // Check if a combination artifact fits. // TODO: Might want a more general algorithm? // Assumes that misc & rings fits only in their slots, and others in only one slot and no duplicates. - if (constituents != NULL) { - std::map tempArtifWorn = artifWorn; + if (constituents != NULL) + { + std::map tempArtifWorn = artifWorn; const ui16 ringSlots[] = {6, 7}; const ui16 miscSlots[] = {9, 10, 11, 12, 18}; int rings = 0; @@ -108,7 +115,7 @@ bool CArtifact::fitsAt (const std::map &artifWorn, ui16 slotID) cons return true; } -bool CArtifact::canBeAssembledTo (const std::map &artifWorn, ui32 artifactID) const +bool CArtifact::canBeAssembledTo (const std::map &artifWorn, ui32 artifactID) const { if (constituentOf == NULL || !vstd::contains(*constituentOf, artifactID)) return false; @@ -119,9 +126,9 @@ bool CArtifact::canBeAssembledTo (const std::map &artifWorn, ui32 ar BOOST_FOREACH(ui32 constituentID, *artifact.constituents) { bool found = false; - for (std::map::const_iterator it = artifWorn.begin(); it != artifWorn.end(); ++it) + for (std::map::const_iterator it = artifWorn.begin(); it != artifWorn.end(); ++it) { - if (it->second == constituentID) + if (it->second->id == constituentID) { found = true; break; @@ -174,6 +181,12 @@ void CArtifact::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/ } } +void CScroll::Init() +{ + bonuses.push_back (Bonus (Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT, 1, id, spellid, Bonus::INDEPENDENT_MAX)); + //boost::algorithm::replace_first(description, "[spell name]", VLC->spellh->spells[spellid].name); +} + CArtHandler::CArtHandler() { VLC->arth = this; @@ -181,11 +194,13 @@ CArtHandler::CArtHandler() // War machines are the default big artifacts. for (ui32 i = 3; i <= 6; i++) bigArtifacts.insert(i); + modableArtifacts = boost::assign::map_list_of(1, 1)(146,3)(147,3)(148,3)(150,3)(151,3)(152,3)(154,3)(156,2); } CArtHandler::~CArtHandler() { - for (std::vector::iterator it = artifacts.begin(); it != artifacts.end(); ++it) { + for (std::vector::iterator it = artifacts.begin(); it != artifacts.end(); ++it) + { delete (*it)->constituents; delete (*it)->constituentOf; } @@ -205,9 +220,28 @@ void CArtHandler::loadArtifacts(bool onlyTxt) } VLC->generaltexth->artifNames.resize(ARTIFACTS_QUANTITY); VLC->generaltexth->artifDescriptions.resize(ARTIFACTS_QUANTITY); + std::map::iterator itr; for (int i=0; isecond) + { + case 1: + art = new CScroll; + break; + case 2: + art = new CCustomizableArt; + break; + case 3: + art = new CCommanderArt; + break; + }; + } + else + art = new CArtifact; + CArtifact &nart = *art; nart.id=i; loadToIt(VLC->generaltexth->artifNames[i],buf,it,4); @@ -718,36 +752,39 @@ void CArtHandler::clear() * @param artifWorn A hero's set of worn artifacts. * @param bonuses Optional list of bonuses to update. */ -void CArtHandler::equipArtifact(std::map &artifWorn, ui16 slotID, ui32 artifactID) +void CArtHandler::equipArtifact(std::map &artifWorn, ui16 slotID, const CArtifact* newArtifact) { unequipArtifact(artifWorn, slotID); - const CArtifact &artifact = *artifacts[artifactID]; - - // Add artifact. - artifWorn[slotID] = artifactID; - - // Add locks, in reverse order of being removed. - if (artifact.constituents != NULL) + if (newArtifact) //false when artifact is NULL -> slot set to empty { - bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact. + const CArtifact &artifact = *newArtifact; - BOOST_FOREACH(ui32 constituentID, *artifact.constituents) + // Add artifact. + artifWorn[slotID] = const_cast(newArtifact); + + // Add locks, in reverse order of being removed. + if (artifact.constituents != NULL) { - const CArtifact &constituent = *artifacts[constituentID]; + bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact. - if (!destConsumed && vstd::contains(constituent.possibleSlots, slotID)) + BOOST_FOREACH(ui32 constituentID, *artifact.constituents) { - destConsumed = true; - } - else - { - BOOST_FOREACH(ui16 slot, constituent.possibleSlots) + const CArtifact &constituent = *artifacts[constituentID]; + + if (!destConsumed && vstd::contains(constituent.possibleSlots, slotID)) { - if (!vstd::contains(artifWorn, slot)) + destConsumed = true; + } + else + { + BOOST_FOREACH(ui16 slot, constituent.possibleSlots) { - artifWorn[slot] = 145; - break; + if (!vstd::contains(artifWorn, slot)) + { + artifWorn[slot] = VLC->arth->artifacts[145]; //lock + break; + } } } } @@ -761,12 +798,12 @@ void CArtHandler::equipArtifact(std::map &artifWorn, ui16 slotID, ui * @param artifWorn A hero's set of worn artifacts. * @param bonuses Optional list of bonuses to update. */ -void CArtHandler::unequipArtifact(std::map &artifWorn, ui16 slotID) +void CArtHandler::unequipArtifact(std::map &artifWorn, ui16 slotID) { if (!vstd::contains(artifWorn, slotID)) return; - const CArtifact &artifact = *artifacts[artifWorn[slotID]]; + const CArtifact &artifact = *artifWorn[slotID]; // Remove artifact, if it's not already removed. artifWorn.erase(slotID); @@ -788,7 +825,7 @@ void CArtHandler::unequipArtifact(std::map &artifWorn, ui16 slotID) { BOOST_REVERSE_FOREACH(ui16 slot, constituent.possibleSlots) { - if (vstd::contains(artifWorn, slot) && artifWorn[slot] == 145) + if (vstd::contains(artifWorn, slot) && artifWorn[slot]->id == 145) { artifWorn.erase(slot); break; diff --git a/hch/CArtHandler.h b/hch/CArtHandler.h index 71e9b6b82..0989eb75f 100644 --- a/hch/CArtHandler.h +++ b/hch/CArtHandler.h @@ -17,19 +17,24 @@ * */ class CDefHandler; +class CArtifact; class DLL_EXPORT CArtifact : public CBonusSystemNode //container for artifacts { +protected: std::string name, description; //set if custom public: enum EartClass {ART_SPECIAL=1, ART_TREASURE=2, ART_MINOR=4, ART_MAJOR=8, ART_RELIC=16}; //artifact classes const std::string &Name() const; //getter const std::string &Description() const; //getter bool isBig () const; - bool fitsAt (const std::map &artifWorn, ui16 slot) const; - bool canBeAssembledTo (const std::map &artifWorn, ui32 artifactID) const; + bool isModable () const; + bool fitsAt (const std::map &artifWorn, ui16 slot) const; + bool canBeAssembledTo (const std::map &artifWorn, ui32 artifactID) const; void addBonusesTo (BonusList *otherBonuses) const; void removeBonusesFrom (BonusList *otherBonuses) const; + virtual void SetProperty (int mod){}; + virtual void Init(){}; int getArtClassSerial() const; //0 - treasure, 1 - minor, 2 - major, 3 - relic, 4 - spell scroll, 5 - other ui32 price; @@ -52,46 +57,58 @@ public: void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const; }; -class DLL_EXPORT IModableArt //artifact which can have different properties, such as scroll or banner -{ +class DLL_EXPORT IModableArt : public CArtifact //artifact which can have different properties, such as scroll or banner +{ //used only for dynamic cast :P public: - virtual void Init() = 0; -}; + si32 ID; //used for smart serialization -class DLL_EXPORT CScroll : public CArtifact, public IModableArt // Spell Scroll -{ -public: - spelltype spellid; - void Init(){}; template void serialize(Handler &h, const int version) { h & static_cast(*this); + h & ID; + } +}; + +class DLL_EXPORT CScroll : public IModableArt // Spell Scroll +{ +public: + CScroll(){spellid=0;}; + CScroll(spelltype sid){spellid = sid;}; + spelltype spellid; + void Init(); + void SetProperty (int mod){spellid = mod;}; + template void serialize(Handler &h, const int version) + { + h & static_cast(*this); h & spellid; } }; -class DLL_EXPORT CCustomizableArt : public CArtifact, public IModableArt // Warlord's Banner with multiple options +class DLL_EXPORT CCustomizableArt : public IModableArt // Warlord's Banner with multiple options { public: ui8 mode; + CCustomizableArt(){mode=0;}; void Init(){}; - void SelectMode (int mod){}; + void SetProperty (int mod){}; template void serialize(Handler &h, const int version) { - h & static_cast(*this); + h & static_cast(*this); h & mode; } }; -class DLL_EXPORT CCommanderArt : public CArtifact, public IModableArt // Growing with time +class DLL_EXPORT CCommanderArt : public IModableArt // Growing with time { public: ui32 level; + CCommanderArt(){level = 0;}; void Init(){}; + void SetProperty (int mod){level = mod;}; void Upgrade(){level++;}; template void serialize(Handler &h, const int version) { - h & static_cast(*this); + h & static_cast(*this); h & level; } }; @@ -104,6 +121,7 @@ public: std::vector artifacts; std::vector allowedArtifacts; std::set bigArtifacts; // Artifacts that cannot be moved to backpack, e.g. war machines. + std::map modableArtifacts; //1-scroll, 2-banner, 3-commander art with progressive bonus void loadArtifacts(bool onlyTxt); void sortArts(); @@ -116,8 +134,8 @@ public: void getAllowed(std::vector &out, int flags); void erasePickedArt (si32 id); bool isBigArtifact (ui32 artID) {return bigArtifacts.find(artID) != bigArtifacts.end();} - void equipArtifact (std::map &artifWorn, ui16 slotID, ui32 artifactID); - void unequipArtifact (std::map &artifWorn, ui16 slotID); + void equipArtifact (std::map &artifWorn, ui16 slotID, const CArtifact* art); + void unequipArtifact (std::map &artifWorn, ui16 slotID); void initAllowedArtifactsList(const std::vector &allowed); //allowed[art_id] -> 0 if not allowed, 1 if allowed static int convertMachineID(int id, bool creToArt); CArtHandler(); diff --git a/hch/CCampaignHandler.cpp b/hch/CCampaignHandler.cpp index baa638b69..a417bfc08 100644 --- a/hch/CCampaignHandler.cpp +++ b/hch/CCampaignHandler.cpp @@ -522,7 +522,7 @@ void CCampaignScenario::prepareCrossoverHeroes( std::vector he { BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes) { - cgh->artifacts -= g; + cgh->artifacts -= VLC->arth->artifacts[g]; } } } diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index dcff029b1..b17a797be 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -729,27 +729,23 @@ int CGHeroInstance::maxMovePoints(bool onLand) const return int(base + base*modifier) + bonus; } -ui32 CGHeroInstance::getArtAtPos(ui16 pos) const +CArtifact* CGHeroInstance::getArtAtPos(ui16 pos) const { if(pos<19) if(vstd::contains(artifWorn,pos)) return artifWorn.find(pos)->second; else - return -1; + return NULL; else if(pos-19 < artifacts.size()) return artifacts[pos-19]; else - return -1; + return NULL; } const CArtifact * CGHeroInstance::getArt(int pos) const { - int id = getArtAtPos(pos); - if(id>=0) - return VLC->arth->artifacts[id]; - else - return NULL; + return getArtAtPos(pos); } // int CGHeroInstance::getSpellSecLevel(int spell) const @@ -814,9 +810,9 @@ void CGHeroInstance::initHero() if(!vstd::contains(artifWorn, 16) && type->startingSpell >= 0) //no catapult means we haven't read pre-existant set { - VLC->arth->equipArtifact(artifWorn, 17, 0); //give spellbook + VLC->arth->equipArtifact(artifWorn, 17, VLC->arth->artifacts[0]); //give spellbook } - VLC->arth->equipArtifact(artifWorn, 16, 3); //everyone has a catapult + VLC->arth->equipArtifact(artifWorn, 16, VLC->arth->artifacts[3]); //everyone has a catapult if(portrait < 0 || portrait == 255) portrait = subID; @@ -886,13 +882,13 @@ void CGHeroInstance::initArmy(CCreatureSet *dst /*= NULL*/) switch (creID) { case 145: //catapult - VLC->arth->equipArtifact(artifWorn, 16, 3); + VLC->arth->equipArtifact(artifWorn, 16, VLC->arth->artifacts[3]); break; default: VLC->arth->equipArtifact( artifWorn, 9+CArtHandler::convertMachineID(creID,true), - CArtHandler::convertMachineID(creID,true)); + VLC->arth->artifacts[CArtHandler::convertMachineID(creID,true)]); break; } } @@ -1421,8 +1417,8 @@ si32 CGHeroInstance::manaRegain() const si32 CGHeroInstance::getArtPos(int aid) const { - for(std::map::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++) - if(i->second == aid) + for(std::map::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++) + if(i->second->id == aid) return i->first; return -1; } @@ -1431,33 +1427,34 @@ si32 CGHeroInstance::getArtPos(int aid) const * Places an artifact in hero's backpack. If it's a big artifact equips it * or discards it if it cannot be equipped. */ -void CGHeroInstance::giveArtifact (ui32 aid) +void CGHeroInstance::giveArtifact (ui32 aid) //use only for fixed artifacts { - const CArtifact &artifact = *VLC->arth->artifacts[aid]; + CArtifact * const artifact = VLC->arth->artifacts[aid]; //pointer to constant object - if (artifact.isBig()) + if (artifact->isBig()) { - for (std::vector::const_iterator it = artifact.possibleSlots.begin(); it != artifact.possibleSlots.end(); ++it) + for (std::vector::const_iterator it = artifact->possibleSlots.begin(); it != artifact->possibleSlots.end(); ++it) { if (!vstd::contains(artifWorn, *it)) { - VLC->arth->equipArtifact(artifWorn, *it, aid); + VLC->arth->equipArtifact(artifWorn, *it, artifact); break; } } } else { - artifacts.push_back(aid); + artifacts.push_back(artifact); } } bool CGHeroInstance::hasArt( ui32 aid ) const { - if(vstd::contains(artifacts, aid)) - return true; - for(std::map::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++) - if(i->second == aid) + for(std::vector::const_iterator i = artifacts.begin(); i != artifacts.end(); i++) + if((*i)->id == aid) + return true; + for(std::map::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++) + if(i->second->id == aid) return true; return false; @@ -1500,8 +1497,8 @@ void CGHeroInstance::getParents(TCNodes &out, const CBonusSystemNode *root /*= N out.insert(visitedTown); } - for (std::map::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++) - out.insert(VLC->arth->artifacts[i->second]); + for (std::map::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++) + out.insert(i->second); out.insert(&speciality); } @@ -3594,24 +3591,36 @@ void CGArtifact::initObj() blockVisit = true; if(ID == 5) hoverName = VLC->arth->artifacts[subID]->Name(); + if(ID == 93) + subID = 1; } void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const { if(!stacksCount()) { - if(ID == 5) + InfoWindow iw; + iw.soundID = soundBase::treasure; + iw.player = h->tempOwner; + switch(ID) { - InfoWindow iw; - iw.soundID = soundBase::treasure; - iw.player = h->tempOwner; - iw.components.push_back(Component(4,subID,0,0)); - if(message.length()) - iw.text << message; - else - iw.text << std::pair(12,subID); - cb->showInfoDialog(&iw); + case 5: + { + iw.components.push_back(Component(4,subID,0,0)); + if(message.length()) + iw.text << message; + else + iw.text << std::pair(12,subID); + } + break; + case 93: + iw.components.push_back (Component(Component::SPELL, spell,0,0)); + iw.text.addTxt (MetaString::ADVOB_TXT,135); + iw.text.addReplacement(MetaString::SPELL_NAME, spell); + break; + } + cb->showInfoDialog(&iw); pick(h); } else @@ -3632,14 +3641,23 @@ void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const void CGArtifact::pick(const CGHeroInstance * h) const { - if(ID == 5) //Artifact + if (VLC->arth->artifacts[subID]->isModable()) + {//TODO: create new instance, initialize it + if (ID == 93) //scroll + { + NewArtifact na; + na.value = spell; + na.artid = subID; + cb->sendAndApply(&na); + cb->giveNewArtifact(h->id, -2); + } + else + cb->giveNewArtifact(h->id, -2);; //nothing / zero / empty by default + } + else { cb->giveHeroArtifact(subID,h->id,-2); } - else if(ID == 93) // Spell scroll - { - //TODO: support for the spell scroll - } cb->removeObject(id); } @@ -4373,7 +4391,7 @@ void CGSeerHut::finishQuest (const CGHeroInstance * h, ui32 accept) const case CQuest::MISSION_ART: for (std::vector::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it) { - cb->removeArtifact(*it, h->id); + cb->removeArtifact(VLC->arth->artifacts[*it], h->id); } break; case CQuest::MISSION_ARMY: diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index 2cb9a2762..cca770dcd 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -47,6 +47,7 @@ struct InfoWindow; struct Component; struct BankConfig; struct UpdateHeroSpeciality; +struct NewArtifact; class CGBoat; class DLL_EXPORT CQuest @@ -266,8 +267,8 @@ public: ui8 inTownGarrison; // if hero is in town garrison const CGTownInstance * visitedTown; //set if hero is visiting town or in the town garrison const CGBoat *boat; //set to CGBoat when sailing - std::vector artifacts; //hero's artifacts from bag - std::map artifWorn; //map; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5 + std::vector artifacts; //hero's artifacts from bag + std::map artifWorn; //map; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5 std::set spells; //known spells (spell IDs) struct DLL_EXPORT Patrol @@ -337,7 +338,7 @@ public: int maxMovePoints(bool onLand) const; - ui32 getArtAtPos(ui16 pos) const; //-1 - no artifact + CArtifact* getArtAtPos(ui16 pos) const; //NULL - no artifact const CArtifact * getArt(int pos) const; si32 getArtPos(int aid) const; //looks for equipped artifact with given ID and returns its slot ID or -1 if none(if more than one such artifact lower ID is returned) bool hasArt(ui32 aid) const; //checks if hero possess artifact of given id (either in backack or worn) diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index b7d913320..d96a64112 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1949,7 +1949,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed ) CGHeroInstance *hero = k->second.heroes[0]; std::vector::iterator slot = vstd::findFirstNot (hero->artifWorn, toGive->possibleSlots); if(slot != toGive->possibleSlots.end()) - VLC->arth->equipArtifact(hero->artifWorn, *slot, toGive->id); + VLC->arth->equipArtifact(hero->artifWorn, *slot, toGive); else hero->giveArtifact(toGive->id); } diff --git a/lib/CGameState.h b/lib/CGameState.h index cc6938026..440b41762 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -61,6 +61,7 @@ struct TerrainTile; class CHeroClass; class CCampaign; class CCampaignState; +class IModableArt; namespace boost { @@ -142,7 +143,8 @@ public: template void serialize(Handler &h, const int version) { h & color & human & currentSelection & team & resources & status; - h & heroes & towns & availableHeroes & dwellings & bonuses & status & daysWithoutCastle; + h & heroes & towns & availableHeroes & dwellings & bonuses; + h & status & daysWithoutCastle; h & enteredLosingCheatCode & enteredWinningCheatCode; h & static_cast(*this); } diff --git a/lib/Connection.cpp b/lib/Connection.cpp index 040626113..8be453501 100644 --- a/lib/Connection.cpp +++ b/lib/Connection.cpp @@ -402,8 +402,9 @@ CSerializer::CSerializer() void CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib) { registerVectoredType(&gs->map->objects, &CGObjectInstance::id); + registerVectoredType(&lib->heroh->heroes, &CHero::ID); registerVectoredType(&lib->creh->creatures, &CCreature::idNumber); registerVectoredType(&lib->arth->artifacts, &CArtifact::id); - registerVectoredType(&lib->heroh->heroes, &CHero::ID); + registerVectoredType(&gs->map->artInstances, &IModableArt::ID); smartVectorMembersSerialization = true; } diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 3354462ea..3d8a7d349 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -93,7 +93,8 @@ public: virtual void heroVisitCastle(int obj, int heroID)=0; virtual void stopHeroVisitCastle(int obj, int heroID)=0; virtual void giveHeroArtifact(int artid, int hid, int position)=0; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack - virtual bool removeArtifact(int artid, int hid) = 0; + virtual void giveNewArtifact(int hid, int position)=0; + virtual bool removeArtifact(CArtifact* art, int hid) = 0; virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function cb = 0, const CGTownInstance *town = NULL)=0; //use hero=NULL for no hero virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 65ca11957..bcc37e405 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -602,18 +602,18 @@ struct SetHeroArtifacts : public CPackForClient //509 SetHeroArtifacts(){type = 509;}; void applyCl(CClient *cl); DLL_EXPORT void applyGs(CGameState *gs); - DLL_EXPORT void setArtAtPos(ui16 pos, int art); + DLL_EXPORT void setArtAtPos(ui16 pos, const CArtifact* art); si32 hid; - std::vector artifacts; //hero's artifacts from bag - std::map artifWorn; //map; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5 + std::vector artifacts; //hero's artifacts from bag + std::map artifWorn; //map; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5 template void serialize(Handler &h, const int version) { h & hid & artifacts & artifWorn; } - std::vector equiped, unequiped; //used locally + std::vector equiped, unequiped; //used locally BonusList gained, lost; //used locally as hlp when applying }; @@ -697,6 +697,21 @@ struct SetAvailableArtifacts : public CPackForClient //519 } }; +struct NewArtifact : public CPackForClient +{ + NewArtifact(){type = 520;}; + //void applyCl(CClient *cl); + DLL_EXPORT void applyGs(CGameState *gs); + + si32 artid; + si32 value; //initializing parameter + + template void serialize(Handler &h, const int version) + { + h & artid & value; + } +}; + struct NewTurn : public CPackForClient //101 { enum weekType {NORMAL, DOUBLE_GROWTH, BONUS_GROWTH, DEITYOFFIRE, PLAGUE, CUSTOM, NO_ACTION, NONE}; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 18702f218..c7b394952 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -451,20 +451,22 @@ DLL_EXPORT void SetHeroesInTown::applyGs( CGameState *gs ) DLL_EXPORT void SetHeroArtifacts::applyGs( CGameState *gs ) { CGHeroInstance *h = gs->getHero(hid); - for(std::map::const_iterator i = h->artifWorn.begin(); i != h->artifWorn.end(); i++) + for(std::map::const_iterator i = h->artifWorn.begin(); i != h->artifWorn.end(); i++) if(!vstd::contains(artifWorn,i->first) || artifWorn[i->first] != i->second) unequiped.push_back(i->second); - for(std::map::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++) + for(std::map::iterator i = artifWorn.begin(); i != artifWorn.end(); i++) if(!vstd::contains(h->artifWorn,i->first) || h->artifWorn[i->first] != i->second) + { equiped.push_back(i->second); + } //update hero data h->artifacts = artifacts; h->artifWorn = artifWorn; } -DLL_EXPORT void SetHeroArtifacts::setArtAtPos(ui16 pos, int art) +DLL_EXPORT void SetHeroArtifacts::setArtAtPos(ui16 pos, const CArtifact* art) { if(art < 0) { @@ -477,14 +479,14 @@ DLL_EXPORT void SetHeroArtifacts::setArtAtPos(ui16 pos, int art) { if (pos < 19) { - VLC->arth->equipArtifact(artifWorn, pos, (ui32) art); + VLC->arth->equipArtifact(artifWorn, pos, art); } else // Goes into the backpack. { if(pos - 19 < artifacts.size()) - artifacts.insert(artifacts.begin() + (pos - 19), art); + artifacts.insert(artifacts.begin() + (pos - 19), const_cast(art)); else - artifacts.push_back(art); + artifacts.push_back(const_cast(art)); } } } @@ -584,6 +586,31 @@ DLL_EXPORT void NewObject::applyGs( CGameState *gs ) o->initObj(); assert(o->defInfo); } +DLL_EXPORT void NewArtifact::applyGs( CGameState *gs ) +{ + IModableArt * art; + + std::map::iterator itr = VLC->arth->modableArtifacts.find(artid); + switch (itr->second) + { + case 1: + art = new CScroll; + break; + case 2: + art = new CCustomizableArt; + break; + case 3: + art = new CCommanderArt; + break; + default: + tlog1<<"unhandled customizable artifact!\n"; + }; + *art = *static_cast(VLC->arth->artifacts[artid]); //copy properties + art->ID = gs->map->artInstances.size(); + art->SetProperty (value); //init scroll, banner, commander art + art->Init(); //set bonuses for new instance + gs->map->artInstances.push_back(art); +} DLL_EXPORT void SetAvailableArtifacts::applyGs( CGameState *gs ) { diff --git a/lib/RegisterTypes.cpp b/lib/RegisterTypes.cpp index 2f6f279da..c7f01e1dd 100644 --- a/lib/RegisterTypes.cpp +++ b/lib/RegisterTypes.cpp @@ -137,6 +137,7 @@ void registerTypes2(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); + s.template registerType(); s.template registerType(); s.template registerType(); diff --git a/lib/map.cpp b/lib/map.cpp index d275b33a7..b488e6def 100644 --- a/lib/map.cpp +++ b/lib/map.cpp @@ -858,27 +858,27 @@ void Mapa::loadHero( CGObjectInstance * &nobj, const unsigned char * bufor, int { int id = readNormalNr(bufor,i, artidlen); i+=artidlen; if(id != artmask) - VLC->arth->equipArtifact(nhi->artifWorn, pom, id); + VLC->arth->equipArtifact(nhi->artifWorn, pom, VLC->arth->artifacts[id]); } //misc5 art //17 if(version>=SoD) { int id = readNormalNr(bufor,i, artidlen); i+=artidlen; if(id!=artmask) - VLC->arth->equipArtifact(nhi->artifWorn, 16, id); + VLC->arth->equipArtifact(nhi->artifWorn, 16, VLC->arth->artifacts[id]); else - VLC->arth->equipArtifact(nhi->artifWorn, 16, 3); //catapult by default + VLC->arth->equipArtifact(nhi->artifWorn, 16, VLC->arth->artifacts[3]); //catapult by default } //spellbook int id = readNormalNr(bufor,i, artidlen); i+=artidlen; if(id!=artmask) - VLC->arth->equipArtifact(nhi->artifWorn, 17, id); + VLC->arth->equipArtifact(nhi->artifWorn, 17, VLC->arth->artifacts[id]); //19 //???what is that? gap in file or what? - it's probably fifth slot.. if(version>RoE) { id = readNormalNr(bufor,i, artidlen); i+=artidlen; if(id!=artmask) - VLC->arth->equipArtifact(nhi->artifWorn, 18, id); + VLC->arth->equipArtifact(nhi->artifWorn, 18, VLC->arth->artifacts[id]); } else i+=1; @@ -1102,7 +1102,7 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i) { int id = readNormalNr(bufor,i, artidlen); i+=artidlen; if(id!=artmask) - VLC->arth->equipArtifact(cgh->artifWorn, pom, id); + VLC->arth->equipArtifact(cgh->artifWorn, pom, VLC->arth->artifacts[id]); } //misc5 art //17 if(version>=SoD) @@ -1115,13 +1115,13 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i) //spellbook int id = readNormalNr(bufor,i, artidlen); i+=artidlen; if(id!=artmask) - VLC->arth->equipArtifact(cgh->artifWorn, 17, id); + VLC->arth->equipArtifact(cgh->artifWorn, 17, VLC->arth->artifacts[id]); //19 //???what is that? gap in file or what? - it's probably fifth slot.. if(version>RoE) { id = readNormalNr(bufor,i, artidlen); i+=artidlen; if(id!=artmask) - VLC->arth->equipArtifact(cgh->artifWorn, 18, id); + VLC->arth->equipArtifact(cgh->artifWorn, 18, VLC->arth->artifacts[id]); } else i+=1; diff --git a/lib/map.h b/lib/map.h index 6b2c6c0b1..210c42296 100644 --- a/lib/map.h +++ b/lib/map.h @@ -30,7 +30,7 @@ class CGHeroInstance; class CGCreature; class CQuest; class CGTownInstance; - +class IModableArt; struct DLL_EXPORT TerrainTile @@ -279,6 +279,7 @@ struct DLL_EXPORT Mapa : public CMapHeader std::vector objects; std::vector heroes; std::vector towns; + std::vector artInstances; //stores single scrolls std::map monsters; std::map heroesToBeat; @@ -313,7 +314,7 @@ struct DLL_EXPORT Mapa : public CMapHeader { h & static_cast(*this); h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos; - h & monsters & heroesToBeat; //hoprfully serialization is now automagical? + h & monsters & heroesToBeat & artInstances; //hopefully serialization is now automagical? //TODO: viccondetails if(h.saving) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index b86676663..904a04f45 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2225,7 +2225,7 @@ void CGameHandler::stopHeroVisitCastle(int obj, int heroID) void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1 - first free slot in backpack { const CGHeroInstance* h = getHero(hid); - const CArtifact &art = *VLC->arth->artifacts[artid]; + CArtifact * const art = VLC->arth->artifacts[artid]; SetHeroArtifacts sha; sha.hid = hid; @@ -2237,38 +2237,84 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1 if(position == -2) { int i; - for(i=0; ipossibleSlots.size(); i++) //try to put artifact into first available slot { - if(art.fitsAt(sha.artifWorn, art.possibleSlots[i])) + if(art->fitsAt(sha.artifWorn, art->possibleSlots[i])) { //we've found a free suitable slot. - VLC->arth->equipArtifact(sha.artifWorn, art.possibleSlots[i], artid); + VLC->arth->equipArtifact(sha.artifWorn, art->possibleSlots[i], VLC->arth->artifacts[artid]); break; } } - if(i == art.possibleSlots.size() && !art.isBig()) //if haven't find proper slot, use backpack or discard big artifact - sha.artifacts.push_back(artid); + if(i == art->possibleSlots.size() && !art->isBig()) //if haven't find proper slot, use backpack or discard big artifact + sha.artifacts.push_back(art); } - else if (!art.isBig()) //should be -1 => put artifact into backpack + else if (!art->isBig()) //should be -1 => put artifact into backpack { - sha.artifacts.push_back(artid); + sha.artifacts.push_back(art); } } else { - if(art.fitsAt(sha.artifWorn, ui16(position))) + if(art->fitsAt(sha.artifWorn, ui16(position))) { - VLC->arth->equipArtifact(sha.artifWorn, position, artid); + VLC->arth->equipArtifact(sha.artifWorn, position, art); } - else if (!art.isBig()) + else if (!art->isBig()) { - sha.artifacts.push_back(artid); + sha.artifacts.push_back(art); } } sendAndApply(&sha); } -bool CGameHandler::removeArtifact(int artid, int hid) +void CGameHandler::giveNewArtifact(int hid, int position) +{ + const CGHeroInstance* h = getHero(hid); + CArtifact * art = gs->map->artInstances.back(); //we use it only to immediatelly equip new artifact + + SetHeroArtifacts sha; + sha.hid = hid; + sha.artifacts = h->artifacts; + sha.artifWorn = h->artifWorn; + + if(position<0) + { + if(position == -2) + { + int i; + for(i=0; ipossibleSlots.size(); i++) //try to put artifact into first available slot + { + if( !vstd::contains(sha.artifWorn, art->possibleSlots[i]) ) + { + //we've found a free suitable slot + VLC->arth->equipArtifact(sha.artifWorn, art->possibleSlots[i], art); + break; + } + } + if(i == art->possibleSlots.size() && !art->isBig()) //if haven't find proper slot, use backpack or discard big artifact + sha.artifacts.push_back(art); + } + else if (!art->isBig()) //should be -1 => put artifact into backpack + { + sha.artifacts.push_back(art); + } + } + else + { + if(!vstd::contains(sha.artifWorn,ui16(position))) + { + VLC->arth->equipArtifact(sha.artifWorn, position, art); + } + else if (!art->isBig()) + { + sha.artifacts.push_back(art); + } + } + + sendAndApply(&sha); +} +bool CGameHandler::removeArtifact(CArtifact* art, int hid) { const CGHeroInstance* h = getHero(hid); @@ -2277,15 +2323,15 @@ bool CGameHandler::removeArtifact(int artid, int hid) sha.artifacts = h->artifacts; sha.artifWorn = h->artifWorn; - std::vector::iterator it; - if ((it = std::find(sha.artifacts.begin(), sha.artifacts.end(), artid)) != sha.artifacts.end()) //it is in backpack + std::vector::iterator it; + if ((it = std::find(sha.artifacts.begin(), sha.artifacts.end(), art)) != sha.artifacts.end()) //it is in backpack sha.artifacts.erase(it); else //worn { - std::map::iterator itr; + std::map::iterator itr; for (itr = sha.artifWorn.begin(); itr != sha.artifWorn.end(); ++itr) { - if (itr->second == artid) + if (itr->second == art) { VLC->arth->unequipArtifact(sha.artifWorn, itr->first); break; @@ -2760,7 +2806,7 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ ) return false; } - removeArtifact(2, t->visitingHero->id); + removeArtifact(VLC->arth->artifacts[2], t->visitingHero->id); } NewStructures ns; @@ -3152,7 +3198,7 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, // Combinational artifacts needs to be removed first so they don't get denied movement because of their own locks. if (srcHeroID == destHeroID && srcSlot < 19 && destSlot < 19) { - sha.setArtAtPos(srcSlot, -1); + sha.setArtAtPos(srcSlot, NULL); if (!vstd::contains(sha.artifWorn, destSlot)) destArtifact = NULL; } @@ -3186,14 +3232,14 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, // If dest does not fit in src, put it in dest's backpack instead. if (srcHeroID == destHeroID) // To avoid stumbling on own locks, remove artifact first. - sha.setArtAtPos(destSlot, -1); + sha.setArtAtPos(destSlot, NULL); const bool destFits = !destArtifact || srcSlot >= 19 || destSlot >= 19 || destArtifact->fitsAt(sha.artifWorn, srcSlot); if (srcHeroID == destHeroID && destArtifact) - sha.setArtAtPos(destSlot, destArtifact->id); + sha.setArtAtPos(destSlot, destArtifact); - sha.setArtAtPos(srcSlot, -1); + sha.setArtAtPos(srcSlot, NULL); if (destSlot < 19 && (destArtifact || srcSlot < 19) && destFits) - sha.setArtAtPos(srcSlot, destArtifact ? destArtifact->id : -1); + sha.setArtAtPos(srcSlot, destArtifact ? destArtifact : NULL); // Internal hero artifact arrangement. if(srcHero == destHero) @@ -3211,7 +3257,7 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, sha2.hid = destHeroID; sha2.artifacts = destHero->artifacts; sha2.artifWorn = destHero->artifWorn; - sha2.setArtAtPos(destSlot, srcArtifact ? srcArtifact->id : -1); + sha2.setArtAtPos(destSlot, srcArtifact ? srcArtifact : NULL); if (!destFits) sha2.setArtAtPos(sha2.artifacts.size() + 19, destHero->getArtAtPos(destSlot)); sendAndApply(&sha2); @@ -3243,20 +3289,24 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem sha.artifacts = hero->artifacts; sha.artifWorn = hero->artifWorn; - if (assemble) { - if (VLC->arth->artifacts.size() < assembleTo) { + if (assemble) + { + if (VLC->arth->artifacts.size() < assembleTo) + { complain("Illegal artifact to assemble to."); return false; } - if (!destArtifact->canBeAssembledTo(hero->artifWorn, assembleTo)) { + if (!destArtifact->canBeAssembledTo(hero->artifWorn, assembleTo)) + { complain("Artifact cannot be assembled."); return false; } const CArtifact &artifact = *VLC->arth->artifacts[assembleTo]; - if (artifact.constituents == NULL) { + if (artifact.constituents == NULL) + { complain("Not a combinational artifact."); return false; } @@ -3265,32 +3315,43 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact. const bool destSpecific = vstd::contains(artifact.possibleSlots, artifactSlot); // Prefer the chosen slot as the location for the assembled artifact. - BOOST_FOREACH(ui32 constituentID, *artifact.constituents) { - if (destSpecific && constituentID == destArtifact->id) { - sha.artifWorn[artifactSlot] = assembleTo; + BOOST_FOREACH(ui32 constituentID, *artifact.constituents) + { + if (destSpecific && constituentID == destArtifact->id) + { + sha.artifWorn[artifactSlot] = VLC->arth->artifacts[assembleTo]; destConsumed = true; continue; } bool found = false; - for (std::map::iterator it = sha.artifWorn.begin(); it != sha.artifWorn.end(); ++it) { - if (it->second == constituentID) { // Found possible constituent to substitute. - if (destSpecific && !destConsumed && it->second == destArtifact->id) { + for (std::map::iterator it = sha.artifWorn.begin(); it != sha.artifWorn.end(); ++it) + { + if (it->second->id == constituentID) + { // Found possible constituent to substitute. + if (destSpecific && !destConsumed && it->second->id == destArtifact->id) + { // Find the specified destination for assembled artifact. - if (it->first == artifactSlot) { - it->second = assembleTo; + if (it->first == artifactSlot) + { + it->second = VLC->arth->artifacts[assembleTo]; destConsumed = true; found = true; break; } - } else { + } + else + { // Either put the assembled artifact in a fitting spot, or put a lock. - if (!destSpecific && !destConsumed && vstd::contains(artifact.possibleSlots, it->first)) { - it->second = assembleTo; + if (!destSpecific && !destConsumed && vstd::contains(artifact.possibleSlots, it->first)) + { + it->second = VLC->arth->artifacts[assembleTo]; destConsumed = true; - } else { - it->second = 145; + } + else + { + it->second = VLC->arth->artifacts[145]; } found = true; @@ -3303,19 +3364,27 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem return false; } } - } else { + } + else + { // Perform disassembly. bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact. - BOOST_FOREACH(ui32 constituentID, *destArtifact->constituents) { + BOOST_FOREACH(ui32 constituentID, *destArtifact->constituents) + { const CArtifact &constituent = *VLC->arth->artifacts[constituentID]; - if (!destConsumed && vstd::contains(constituent.possibleSlots, artifactSlot)) { - sha.artifWorn[artifactSlot] = constituentID; + if (!destConsumed && vstd::contains(constituent.possibleSlots, artifactSlot)) + { + sha.artifWorn[artifactSlot] = VLC->arth->artifacts[constituentID]; destConsumed = true; - } else { - BOOST_REVERSE_FOREACH(ui16 slotID, constituent.possibleSlots) { - if (vstd::contains(sha.artifWorn, slotID) && sha.artifWorn[slotID] == 145) { - sha.artifWorn[slotID] = constituentID; + } + else + { + BOOST_REVERSE_FOREACH(ui16 slotID, constituent.possibleSlots) + { + if (vstd::contains(sha.artifWorn, slotID) && sha.artifWorn[slotID]->id == 145) + { + sha.artifWorn[slotID]->id = constituentID; break; } } @@ -4049,9 +4118,9 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message ) sha.hid = hero->id; sha.artifacts = hero->artifacts; sha.artifWorn = hero->artifWorn; - VLC->arth->equipArtifact(sha.artifWorn, 13, 4); - VLC->arth->equipArtifact(sha.artifWorn, 14, 5); - VLC->arth->equipArtifact(sha.artifWorn, 15, 6); + VLC->arth->equipArtifact(sha.artifWorn, 13, VLC->arth->artifacts[4]); + VLC->arth->equipArtifact(sha.artifWorn, 14, VLC->arth->artifacts[5]); + VLC->arth->equipArtifact(sha.artifWorn, 15, VLC->arth->artifacts[6]); sendAndApply(&sha); } else if(message == "vcminahar") //1000000 movement points @@ -4108,10 +4177,10 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message ) sha.hid = hero->id; sha.artifacts = hero->artifacts; sha.artifWorn = hero->artifWorn; - sha.artifacts.push_back(2); //grail + sha.artifacts.push_back(VLC->arth->artifacts[2]); //grail for (int g=7; g<=140; ++g) { - sha.artifacts.push_back(g); + sha.artifacts.push_back(VLC->arth->artifacts[g]); } sendAndApply(&sha); } @@ -5231,13 +5300,13 @@ bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstanc return true; } -bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, ui32 artID) +bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, CArtifact* art) { - if(!removeArtifact(artID, hero->id)) + if(!removeArtifact(art, hero->id)) COMPLAIN_RET("Cannot find artifact to sacrifice!"); int dmp, expToGive; - m->getOffer(artID, 0, dmp, expToGive, ARTIFACT_EXP); + m->getOffer(art->id, 0, dmp, expToGive, ARTIFACT_EXP); changePrimSkill(hero->id, 4, expToGive); return true; } diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 081328eec..b68d8991a 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -143,8 +143,9 @@ public: void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h); void stopHeroVisitCastle(int obj, int heroID); void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack; pos==-2 - default if available or backpack + void giveNewArtifact(int hid, int position); void moveArtifact(int hid, int oldPosition, int destPos); - bool removeArtifact(int artid, int hid); + bool removeArtifact(CArtifact* art, int hid); void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function cb = 0, const CGTownInstance *town = NULL); //use hero=NULL for no hero void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle//void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function cb); //for hero<=>neutral army @@ -222,7 +223,7 @@ public: void run(bool resume); void newTurn(); void handleAfterAttackCasting( const BattleAttack & bat ); - bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, ui32 artID); + bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, CArtifact* art); friend class CVCMIServer; friend class CScriptCallback; }; diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index 37d7d8a7a..71c458fa4 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -166,7 +166,7 @@ bool TradeOnMarketplace::applyGh( CGameHandler *gh ) case CREATURE_EXP: return gh->sacrificeCreatures(m, hero, r1, val); case ARTIFACT_EXP: - return gh->sacrificeArtifact(m, hero, r1); + return gh->sacrificeArtifact(m, hero, hero->getArtAtPos(r1)); default: COMPLAIN_AND_RETURN("Unknown exchange mode!"); }