From ef5b1ca1de9e86320c840674e012cac9fd3a3a41 Mon Sep 17 00:00:00 2001 From: OnionKnight Date: Wed, 30 Dec 2009 15:33:28 +0000 Subject: [PATCH] * Fixed bug #112 * Improved the security checks for ExchangeArtifact and SetArtifact, but have also come to realize that SetArtifact is inherently broken and can be used for cheating. :( * Preliminary work for combination artifacts, it's now possible to identify artifacts that are combined and what they're made up of. * Happy New Year! --- client/GUIClasses.cpp | 9 ++--- client/GUIClasses.h | 10 +++--- hch/CArtHandler.cpp | 75 +++++++++++++++++++++++++++++++++++++++++ hch/CArtHandler.h | 4 ++- hch/CObjectHandler.cpp | 20 +++++++++++ hch/CObjectHandler.h | 1 + lib/CGameState.cpp | 2 +- lib/map.cpp | 4 +-- server/CGameHandler.cpp | 38 ++++++++++++++++----- 9 files changed, 141 insertions(+), 22 deletions(-) diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index 0f611dd57..6112bbb37 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -3696,10 +3696,11 @@ bool CArtPlace::fitsHere(const CArtifact * art) if(!art) return true; - // Anything can be placed in the backpack, except War Machines. - if (slotID >= 19 && !CGI->arth->isBigArtifact(art->id) - || vstd::contains(art->possibleSlots, slotID)) - { + // Anything can but War Machines can be placed in backpack. + if (slotID >= 19) { + return !CGI->arth->isBigArtifact(art->id); + } else if (vstd::contains(art->possibleSlots, slotID)) { + // TODO: Deal with combinational at dest and as src. return true; } diff --git a/client/GUIClasses.h b/client/GUIClasses.h index cd0f52173..0d93bf303 100644 --- a/client/GUIClasses.h +++ b/client/GUIClasses.h @@ -674,11 +674,11 @@ public: { std::set participants; // Needed to mark slots. const CArtifact * srcArtifact; // Held artifact. - const CArtifactsOfHero * srcAOH; // Following two needed to uniquely identify the source. - int srcSlotID; // + const CArtifactsOfHero * srcAOH; // Following two needed to uniquely identify the source. + int srcSlotID; // const CArtifactsOfHero * destAOH; // For swapping. (i.e. changing what is held) - int destSlotID; // Needed to determine what kind of action was last taken in setHero - const CArtifact * destArtifact; // For swapping. + int destSlotID; // Needed to determine what kind of action was last taken in setHero + const CArtifact * destArtifact; // For swapping. } * commonInfo; //when we have more than one CArtifactsOfHero in one window with exchange possibility, we use this (eg. in exchange window); to be provided externally AdventureMapButton * leftArtRoll, * rightArtRoll; @@ -812,4 +812,4 @@ class CFreelancersWindow : public CShopWindow {}; class CHillFortWindow : public CIntObject //garrison dialog? shop? {}; -#endif //__GUICLASSES_H__ +#endif //__GUICLASSES_H__ \ No newline at end of file diff --git a/hch/CArtHandler.cpp b/hch/CArtHandler.cpp index 378ae7f8d..ab0c61b9c 100644 --- a/hch/CArtHandler.cpp +++ b/hch/CArtHandler.cpp @@ -35,6 +35,12 @@ const std::string & CArtifact::Description() const else return VLC->generaltexth->artifDescriptions[id]; } + +bool CArtifact::isBig () const +{ + return VLC->arth->isBigArtifact(id); +} + CArtHandler::CArtHandler() { VLC->arth = this; @@ -79,6 +85,75 @@ void CArtHandler::loadArtifacts(bool onlyTxt) if(desc[0] == '\"' && desc[desc.size()-1] == '\"') desc = desc.substr(1,desc.size()-2); + // Fill in information about combined artifacts. + switch (nart.id) { + case 129: // Angelic Alliance + nart.constituents = new std::vector(6); + *nart.constituents += 31, 32, 33, 34, 35, 36; + break; + + case 130: // Cloak of the Undead King + nart.constituents = new std::vector(3); + *nart.constituents += 54, 55, 56; + break; + + case 131: // Elixir of Life + nart.constituents = new std::vector(3); + *nart.constituents += 94, 95, 96; + break; + + case 132: // Armor of the Damned + nart.constituents = new std::vector(4); + *nart.constituents += 8, 14, 20, 26; + break; + + case 133: // Statue of Legion + nart.constituents = new std::vector(5); + *nart.constituents += 118, 119, 120, 121, 122; + break; + + case 134: // Power of the Dragon Father + nart.constituents = new std::vector(9); + *nart.constituents += 37, 38, 39, 40, 41, 42, 43, 44, 45; + break; + + case 135: // Titan's Thunder + nart.constituents = new std::vector(4); + *nart.constituents += 12, 18, 24, 30; + break; + + case 136: // Admiral's Hat + nart.constituents = new std::vector(2); + *nart.constituents += 71, 123; + break; + + case 137: // Bow of the Sharpshooter + nart.constituents = new std::vector(3); + *nart.constituents += 60, 61, 62; + break; + + case 138: // Wizards' Well + nart.constituents = new std::vector(3); + *nart.constituents += 73, 74, 75; + break; + + case 139: // Ring of the Magi + nart.constituents = new std::vector(3); + *nart.constituents += 76, 77, 78; + break; + + case 140: // Cornucopia + nart.constituents = new std::vector(4); + *nart.constituents += 109, 110, 111, 113; + break; + + // TODO: WoG combinationals + + default: + nart.constituents = NULL; + break; + } + if(!onlyTxt) artifacts.push_back(nart); } diff --git a/hch/CArtHandler.h b/hch/CArtHandler.h index 31be33856..30dd753a6 100644 --- a/hch/CArtHandler.h +++ b/hch/CArtHandler.h @@ -25,16 +25,18 @@ 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; ui32 price; std::vector possibleSlots; //ids of slots where artifact can be placed + std::vector * constituents; // Artifacts IDs a combined artifact consists of, or NULL. EartClass aClass; ui32 id; std::list bonuses; //bonuses given by artifact template void serialize(Handler &h, const int version) { - h & name & description & price & possibleSlots & aClass & id & bonuses; + h & name & description & price & possibleSlots & constituents & aClass & id & bonuses; } }; diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index 79750a5e9..72a5e9a6c 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -1197,6 +1197,26 @@ si32 CGHeroInstance::getArtPos(int aid) const return -1; } +/** + * 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) +{ + const CArtifact &artifact = VLC->arth->artifacts[aid]; + + if (artifact.isBig()) { + for (std::vector::const_iterator it = artifact.possibleSlots.begin(); it != artifact.possibleSlots.end(); ++it) { + if (artifWorn.find(*it) == artifWorn.end()) { + artifWorn[*it] = aid; + break; + } + } + } else { + artifacts.push_back(aid); + } +} + void CGHeroInstance::recreateArtBonuses() { //clear all bonuses from artifacts (if present) and give them again diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index 5b1d17d2c..7b48bbf6a 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -296,6 +296,7 @@ public: ui32 getArtAtPos(ui16 pos) const; //-1 - 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) + void giveArtifact (ui32 aid); int getSpellSecLevel(int spell) const; //returns level of secondary ability (fire, water, earth, air magic) known to this hero and applicable to given spell; -1 if error static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest double getHeroStrength() const; diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 4efc3648a..b9c9cc1f1 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1448,7 +1448,7 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed) hero->recreateArtBonuses(); } else - hero->artifacts.push_back(toGive->id); + hero->giveArtifact(toGive->id); } } } diff --git a/lib/map.cpp b/lib/map.cpp index 2da1f923d..49bdd3116 100644 --- a/lib/map.cpp +++ b/lib/map.cpp @@ -1005,7 +1005,7 @@ void Mapa::loadHero( CGObjectInstance * &nobj, const unsigned char * bufor, int { id = readNormalNr(bufor,i, artidlen); i+=artidlen; if(id!=artmask) - nhi->artifacts.push_back(id); + nhi->giveArtifact(id); } } } //artifacts @@ -1244,7 +1244,7 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i) { id = readNormalNr(bufor,i, artidlen); i+=artidlen; if(id!=artmask) - cgh->artifacts.push_back(id); + cgh->giveArtifact(id); } } } //artifacts diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index ee415f9c4..150982bf0 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1673,10 +1673,10 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1 break; } } - if(i == art.possibleSlots.size()) //if haven't find proper slot, use backpack + if(i == art.possibleSlots.size() && !art.isBig()) //if haven't find proper slot, use backpack or discard big artifact sha.artifacts.push_back(artid); } - else //should be -1 => put artifact into backpack + else if (!art.isBig()) //should be -1 => put artifact into backpack { sha.artifacts.push_back(artid); } @@ -1687,7 +1687,7 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1 { sha.artifWorn[position] = artid; } - else + else if (!art.isBig()) { sha.artifacts.push_back(artid); } @@ -2330,10 +2330,13 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, return false; } - // TODO: This relates to bug #112, fix later. - // Make sure the artifacts are not war machines. - if ((srcSlot>=13 && srcSlot<=16) || (destSlot>=13 && destSlot<=16)) { - complain("Cannot move war machine!"); + if (destSlot >= 19 && srcArtifact->isBig()) { + complain("Cannot put big artifacts in backpack!"); + return false; + } + + if (srcSlot == 16 || destSlot == 16) { + complain("Cannot move catapult!"); return false; } @@ -2375,9 +2378,26 @@ bool CGameHandler::swapArtifacts(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, */ bool CGameHandler::setArtifact(si32 heroID, ui16 slot, int artID) { - CGHeroInstance *hero = gs->getHero(heroID); + const CGHeroInstance *hero = gs->getHero(heroID); - // TODO: Deal with war machine placement. + if (artID != -1) { + const CArtifact &artifact = VLC->arth->artifacts[artID]; + + if (slot < 19 && !vstd::contains(artifact.possibleSlots, slot)) { + complain("Artifact does not fit!"); + return false; + } + + if (slot >= 19 && artifact.isBig()) { + complain("Cannot put big artifacts in backpack!"); + return false; + } + } + + if (slot == 16) { + complain("Cannot alter catapult slot!"); + return false; + } // Perform the exchange. SetHeroArtifacts sha;