瀏覽代碼

* 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!

OnionKnight 16 年之前
父節點
當前提交
ef5b1ca1de
共有 9 個文件被更改,包括 141 次插入22 次删除
  1. 5 4
      client/GUIClasses.cpp
  2. 5 5
      client/GUIClasses.h
  3. 75 0
      hch/CArtHandler.cpp
  4. 3 1
      hch/CArtHandler.h
  5. 20 0
      hch/CObjectHandler.cpp
  6. 1 0
      hch/CObjectHandler.h
  7. 1 1
      lib/CGameState.cpp
  8. 2 2
      lib/map.cpp
  9. 29 9
      server/CGameHandler.cpp

+ 5 - 4
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;
 	}
 

+ 5 - 5
client/GUIClasses.h

@@ -674,11 +674,11 @@ public:
 	{
 		std::set<CArtifactsOfHero *> 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__

+ 75 - 0
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<ui32>(6);
+				*nart.constituents += 31, 32, 33, 34, 35, 36;
+				break;
+
+			case 130: // Cloak of the Undead King
+				nart.constituents = new std::vector<ui32>(3);
+				*nart.constituents += 54, 55, 56;
+				break;
+
+			case 131: // Elixir of Life
+				nart.constituents = new std::vector<ui32>(3);
+				*nart.constituents += 94, 95, 96;
+				break;
+
+			case 132: // Armor of the Damned
+				nart.constituents = new std::vector<ui32>(4);
+				*nart.constituents += 8, 14, 20, 26;
+				break;
+
+			case 133: // Statue of Legion
+				nart.constituents = new std::vector<ui32>(5);
+				*nart.constituents += 118, 119, 120, 121, 122;
+				break;
+
+			case 134: // Power of the Dragon Father
+				nart.constituents = new std::vector<ui32>(9);
+				*nart.constituents += 37, 38, 39, 40, 41, 42, 43, 44, 45;
+				break;
+
+			case 135: // Titan's Thunder
+				nart.constituents = new std::vector<ui32>(4);
+				*nart.constituents += 12, 18, 24, 30;
+				break;
+
+			case 136: // Admiral's Hat
+				nart.constituents = new std::vector<ui32>(2);
+				*nart.constituents += 71, 123;
+				break;
+
+			case 137: // Bow of the Sharpshooter
+				nart.constituents = new std::vector<ui32>(3);
+				*nart.constituents += 60, 61, 62;
+				break;
+
+			case 138: // Wizards' Well
+				nart.constituents = new std::vector<ui32>(3);
+				*nart.constituents += 73, 74, 75;
+				break;
+
+			case 139: // Ring of the Magi
+				nart.constituents = new std::vector<ui32>(3);
+				*nart.constituents += 76, 77, 78;
+				break;
+
+			case 140: // Cornucopia
+				nart.constituents = new std::vector<ui32>(4);
+				*nart.constituents += 109, 110, 111, 113;
+				break;
+
+			// TODO: WoG combinationals
+
+			default:
+				nart.constituents = NULL;
+				break;
+		}
+
 		if(!onlyTxt)
 			artifacts.push_back(nart);
 	}

+ 3 - 1
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<ui16> possibleSlots; //ids of slots where artifact can be placed
+	std::vector<ui32> * constituents; // Artifacts IDs a combined artifact consists of, or NULL.
 	EartClass aClass;
 	ui32 id;
 	std::list<HeroBonus> bonuses; //bonuses given by artifact
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & name & description & price & possibleSlots & aClass & id & bonuses;
+		h & name & description & price & possibleSlots & constituents & aClass & id & bonuses;
 	}
 };
 

+ 20 - 0
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<ui16>::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

+ 1 - 0
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;

+ 1 - 1
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);
 			}
 		}
 	}

+ 2 - 2
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

+ 29 - 9
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);
+
+	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;
+		}
 
-	// TODO: Deal with war machine placement.
+		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;