Browse Source

It's now possible to assemble and disassemble artifacts.
There is some strange behavior when right-clicking on the artifact screen outside the slots though, all slots then get right-click handling and display the assembly dialog for whatever it finds.

OnionKnight 15 years ago
parent
commit
ad3371b4c0
5 changed files with 85 additions and 12 deletions
  1. 38 0
      client/CPlayerInterface.cpp
  2. 1 0
      client/CPlayerInterface.h
  3. 37 10
      client/GUIClasses.cpp
  4. 2 0
      client/GUIClasses.h
  5. 7 2
      server/CGameHandler.cpp

+ 38 - 0
client/CPlayerInterface.cpp

@@ -32,6 +32,7 @@
 #include "../mapHandler.h"
 #include "../timeHandler.h"
 #include <boost/lexical_cast.hpp>
+#include <boost/format.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/assign/std/vector.hpp>
@@ -1098,6 +1099,43 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
 	GH.pushInt(cgw);
 }
 
+/**
+ * Shows the dialog that appears when right-clicking an artifact that can be assembled
+ * into a combinational one on an artifact screen. Does not require the combination of
+ * artifacts to be legal.
+ * @param artifactID ID of a constituent artifact.
+ * @param assembleTo ID of artifact to assemble a constituent into, not used when assemble
+ * is false.
+ * @param assemble True if the artifact is to be assembled, false if it is to be disassembled.
+ */
+void CPlayerInterface::showArtifactAssemblyDialog (ui32 artifactID, ui32 assembleTo, bool assemble, CFunctionList<void()> onYes, CFunctionList<void()> onNo)
+{
+	const CArtifact &artifact = CGI->arth->artifacts[artifactID];
+	std::string text = artifact.Description();
+	text += "\n\n";
+	std::vector<SComponent*> scs;
+
+	if (assemble) {
+		const CArtifact &assembledArtifact = CGI->arth->artifacts[assembleTo];
+
+		// You possess all of the components to...
+		text += boost::str(boost::format(CGI->generaltexth->allTexts[732]) % assembledArtifact.Name());
+
+		// Picture of assembled artifact at bottom.
+		SComponent* sc = new SComponent;
+		sc->type = SComponent::Etype::artifact;
+		sc->subtype = assembledArtifact.id;
+		sc->description = assembledArtifact.Description();
+		sc->subtitle = assembledArtifact.Name();
+		scs.push_back(sc);
+	} else {
+		// Do you wish to disassemble this artifact?
+		text += CGI->generaltexth->allTexts[733];
+	}
+
+	showYesNoDialog(text, scs, onYes, onNo, true); 
+}
+
 void CPlayerInterface::requestRealized( PackageApplied *pa )
 {
 	if(stillMoveHero.get() == DURING_MOVE)

+ 1 - 0
client/CPlayerInterface.h

@@ -159,6 +159,7 @@ public:
 	void showShipyardDialog(const IShipyard *obj); //obj may be town or shipyard; 
 	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel); //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
 	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd);
+	void showArtifactAssemblyDialog(ui32 artifactID, ui32 assembleTo, bool assemble, CFunctionList<void()> onYes, CFunctionList<void()> onNo);
 	void showPuzzleMap();
 	void tileHidden(const std::set<int3> &pos); //called when given tiles become hidden under fog of war
 	void tileRevealed(const std::set<int3> &pos); //called when fog of war disappears from given tiles

+ 37 - 10
client/GUIClasses.cpp

@@ -3692,24 +3692,51 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 void CArtPlace::clickRight(tribool down, bool previousState)
 {
 	if(ourArt && !locked() && text.size()) { //if there is no description or it's a lock, do nothing ;]
-		LRClickableAreaWTextComp::clickRight(down, previousState);
+		if (slotID < 19) {
+			selectedNo = false;
+
+			// If the artifact can be assembled, display dialog.
+			if (ourArt->constituentOf != NULL) {
+				BOOST_FOREACH(ui32 combination, *ourArt->constituentOf) {
+					if (ourArt->canBeAssembledTo(ourOwner->curHero->artifWorn, combination)) {
+						LOCPLINT->showArtifactAssemblyDialog(
+							ourArt->id,
+							combination,
+							true,
+							boost::bind(&CCallback::assembleArtifacts, LOCPLINT->cb, ourOwner->curHero, slotID, true, combination),
+							boost::bind(&CArtPlace::userSelectedNo, this));
+						if (!selectedNo)
+							return;
+					}
+				}
+			}
 
-		/*if (ourArt->constituentOf != NULL) {
-			BOOST_FOREACH(ui32 combination, *ourArt->constituentOf) {
-				if (ourArt->canBeAssembledTo(ourOwner->curHero->artifWorn, combination)) {
-					LOCPLINT->cb->assembleArtifacts(ourOwner->curHero, slotID, true, combination);
+			// Otherwise if the artifact can be diasassembled, display dialog.
+			if (ourArt->constituents != NULL) {
+				LOCPLINT->showArtifactAssemblyDialog(
+					ourArt->id,
+					0,
+					false,
+					boost::bind(&CCallback::assembleArtifacts, LOCPLINT->cb, ourOwner->curHero, slotID, false, 0),
+					boost::bind(&CArtPlace::userSelectedNo, this));
+				if (!selectedNo)
 					return;
-				}
 			}
 		}
 
-		if (ourArt->constituents != NULL) {
-			LOCPLINT->cb->assembleArtifacts(ourOwner->curHero, slotID, false, 0);
-			return;
-		}*/
+		// Lastly just show the artifact description.
+		LRClickableAreaWTextComp::clickRight(down, previousState);
 	}
 }
 
+/**
+ * Helper function to catch when a user selects no in an artifact assembly dialog.
+ */
+void CArtPlace::userSelectedNo ()
+{
+	selectedNo = true;
+}
+
 /**
  * Selects artifact slot so that the containing artifact looks like it's picked up.
  */

+ 2 - 0
client/GUIClasses.h

@@ -749,6 +749,7 @@ public:
 	ui16 slotID; //0   	head	1 	shoulders		2 	neck		3 	right hand		4 	left hand		5 	torso		6 	right ring		7 	left ring		8 	feet		9 	misc. slot 1		10 	misc. slot 2		11 	misc. slot 3		12 	misc. slot 4		13 	ballista (war machine 1)		14 	ammo cart (war machine 2)		15 	first aid tent (war machine 3)		16 	catapult		17 	spell book		18 	misc. slot 5		19+ 	backpack slots
 
 	bool marked;
+	bool selectedNo;
 	CArtifactsOfHero * ourOwner;
 	const CArtifact * ourArt;
 	CArtPlace(const CArtifact * Art); //c-tor
@@ -761,6 +762,7 @@ public:
 	void show(SDL_Surface * to);
 	bool fitsHere (const CArtifact * art); //returns true if given artifact can be placed here
 	bool locked () const;
+	void userSelectedNo ();
 	~CArtPlace(); //d-tor
 };
 

+ 7 - 2
server/CGameHandler.cpp

@@ -2680,7 +2680,7 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem
 	sha.artifWorn = hero->artifWorn;
 
 	if (assemble) {
-		if (VLC->arth->artifacts.size() >= assembleTo) {
+		if (VLC->arth->artifacts.size() < assembleTo) {
 			complain("Illegal artifact to assemble to.");
 			return false;
 		}
@@ -2718,13 +2718,18 @@ bool CGameHandler::assembleArtifacts (si32 heroID, ui16 artifactSlot, bool assem
 			}
 		}
 	} else {
+		bool destConsumed = false; // Determines which constituent that will be counted for together with the artifact.
 		BOOST_FOREACH(ui32 constituentID, *destArtifact->constituents) {
 			const CArtifact &constituent = VLC->arth->artifacts[constituentID];
 
 			BOOST_REVERSE_FOREACH(ui16 slotID, constituent.possibleSlots) {
 				if (sha.artifWorn.find(slotID) != sha.artifWorn.end()) {
-					if (sha.artifWorn[slotID] == 145 || slotID == artifactSlot)
+					if (sha.artifWorn[slotID] == 145 || (!destConsumed && slotID == artifactSlot)) {
+						if (slotID == artifactSlot)
+							destConsumed = true;
 						sha.artifWorn[slotID] = constituentID;
+						break;
+					}
 				}
 			}
 		}