View Single Post
  #3  
Old 12-19-2010, 02:31 PM
l0stmancd
Fire Beetle
 
Join Date: Apr 2005
Posts: 23
Default Updating patch to work with Revision 1771

Howdy folks,

There has been a few changes lately to the trunk source - updated my local to the latest revision (1771), validated that all is as it should be, and produced a new patch file.

This is a single patch that can be applied to the trunk and has everything needed -except- the mandatory sql mentioned in the first post.

I will keep updating this to work with the latest revision but it would be nice to get this into the source proper so that this is not needed.

EQEmu_Patch_AugmentationContainer_rev1771.patch
Code:
Index: common/Item.cpp
===================================================================
--- common/Item.cpp	(revision 1771)
+++ common/Item.cpp	(working copy)
@@ -219,6 +219,52 @@
 	return m_item->IsEquipable(race, class_);
 }
 
+bool ItemInst::WillAugmentCauseLoreCollision(ItemInst* newAugment)
+{
+	bool returnValue = false;
+
+	// If the new augment is an augment -and- it is lore (in some fashion)
+	//	perform further checks.
+	if (newAugment->IsAugment() && newAugment->m_item->LoreGroup != 0)
+	{
+		// Check all augments and see if any share the same loregroup status.
+		for(uint8 ctr = 0; ctr < 10; ctr++) {
+			
+			ItemInst* itemAugment = this->GetAugment(ctr);
+			if (itemAugment) {
+				// Lore Group Specific check... 
+				if (itemAugment->m_item->LoreGroup != -1 && itemAugment->m_item->LoreGroup == newAugment->m_item->LoreGroup) {
+					returnValue = true;
+					break;
+				} 
+				// Or they have the same id and they are lore...
+				else if (-1 == newAugment->m_item->LoreGroup && itemAugment->GetID() == newAugment->GetID()) {
+					returnValue = true;
+					break;
+				}
+			}
+		}
+	}
+
+	return returnValue;
+}
+
+bool ItemInst::SharesACommonSlot(ItemInst* itemToCompare) const
+{
+	bool returnValue = false;
+
+	// Go over all possible slots - each slot that is available
+	//	in this item, check to see if it is an available slot in the passed
+	//	item.  If so, exit out.
+	for(int i = 0; i <= 22 && !returnValue; i++) {
+		if (m_item->Slots & ( 1 << i )) {
+			returnValue = itemToCompare->IsEquipable( (i == 22) ? 9999 : i );
+		}
+	}
+
+	return returnValue;
+}
+
 // Can equip at this slot?
 bool ItemInst::IsEquipable(sint16 slot_id) const
 {
@@ -363,6 +409,20 @@
 	}
 }
 
+uint8 ItemInst::GetAvailableItemCount()
+{
+	uint8 returnValue = 0;
+
+	for(uint8 i = 0; i < 10; i++) {
+		const ItemInst* inst = this->GetItem(i);
+		if (inst) {
+			returnValue++;
+		}
+	}
+
+	return returnValue;
+}
+
 // Retrieve item inside container
 ItemInst* ItemInst::GetItem(uint8 index) const
 {
Index: common/Item.h
===================================================================
--- common/Item.h	(revision 1771)
+++ common/Item.h	(working copy)
@@ -266,6 +266,7 @@
 	virtual bool IsStackable() const;
 
 	// Can item be equipped by/at?
+	bool SharesACommonSlot(ItemInst* itemToCompare) const;
 	virtual bool IsEquipable(int16 race, int16 class_) const;
 	virtual bool IsEquipable(sint16 slot_id) const;
 	
@@ -275,6 +276,8 @@
 	inline bool IsAugmentable() const { return m_item->AugSlotType[0]!=0; }
 	bool AvailableWearSlot(uint32 aug_wear_slots) const;
 	sint8 AvailableAugmentSlot(sint32 augtype) const;
+	inline bool IsAugment() const { return m_item->AugType!=0; }
+	bool WillAugmentCauseLoreCollision(ItemInst* newAugment);
 	inline sint32 GetAugmentType() const { return m_item->AugType; }
 
 	inline bool IsExpendable() const { return ((m_item->Click.Type == ET_Expendable ) || (m_item->ItemType == ItemTypePotion)); }
@@ -283,6 +286,7 @@
 	// Contents
 	//
 	ItemInst* GetItem(uint8 slot) const;
+	uint8 GetAvailableItemCount();
 	virtual uint32 GetItemID(uint8 slot) const;
 	inline const ItemInst* operator[](uint8 slot) const { return GetItem(slot); }
 	void PutItem(uint8 slot, const ItemInst& inst);
Index: common/ruletypes.h
===================================================================
--- common/ruletypes.h	(revision 1771)
+++ common/ruletypes.h	(working copy)
@@ -92,6 +92,7 @@
 RULE_INT ( Skills, MaxTrainTradeskills, 21 )
 RULE_BOOL ( Skills, UseLimitTradeskillSearchSkillDiff, true )
 RULE_INT ( Skills, MaxTradeskillSearchSkillDiff, 50 )
+RULE_INT ( Skills, ContainerIdToAllowAugCombines, 0 )
 RULE_CATEGORY_END()
 
 RULE_CATEGORY( Pets )
Index: zone/object.h
===================================================================
--- zone/object.h	(revision 1771)
+++ zone/object.h	(working copy)
@@ -148,7 +148,9 @@
 	static void HandleCombine(Client* user, const NewCombine_Struct* in_combine, Object *worldo);
 	static void HandleAugmentation(Client* user, const AugmentItem_Struct* in_augment, Object *worldo);
 	static void HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac);
-	
+	static bool Object::Internal_HandleAugmentation(Client* user, ItemInst* tobe_auged, ItemInst* auged_with, Object *worldo, ItemInst* heldContainer, sint32 augmentationSlotToRemoveFrom, sint32 heldContainer_ContainerSlot);
+	static bool Object::HandleTradeskillAugmentationCombine(Client* user, const NewCombine_Struct* in_combine, ItemInst* container);
+		
 	static SkillType TypeToSkill(uint32 type);
 	
 	// Packet functions
Index: zone/tradeskills.cpp
===================================================================
--- zone/tradeskills.cpp	(revision 1771)
+++ zone/tradeskills.cpp	(working copy)
@@ -53,7 +53,6 @@
 	}
 	
 	ItemInst *tobe_auged, *auged_with = NULL;
-	sint8 slot=-1;
 	ItemInst* container = worldo->m_inst;
 
 	if (!container) {
@@ -78,40 +77,187 @@
 		}
 	}
 
+	Internal_HandleAugmentation(user,tobe_auged,auged_with,worldo,NULL,in_augment->augment_slot, in_augment->augment_slot);
+}
+
+bool Object::Internal_HandleAugmentation(Client* user, ItemInst* tobe_auged, ItemInst* auged_with, Object *worldo, ItemInst* heldContainer, sint32 augmentationSlotToRemoveFrom, sint32 heldContainer_ContainerSlot)
+{
+	// Flag denoting whether an action was performed for augmentation.
+	// If an aug action was performed successfully, we need to wipe out the users "ingredients"
+	bool wipeContainer = false;
+
 	// Adding augment
-	if (in_augment->augment_slot == -1) {
+	if (augmentationSlotToRemoveFrom == -1) {
+		sint8 slot=-1;
 		if (((slot=tobe_auged->AvailableAugmentSlot(auged_with->GetAugmentType()))!=-1) && (tobe_auged->AvailableWearSlot(auged_with->GetItem()->Slots))) {
+			wipeContainer = true;
+
 			tobe_auged->PutAugment(slot,*auged_with);
 			user->PushItemOnCursor(*tobe_auged,true);
-			container->Clear();
+		} else {
+			// Only give warning / error message if this is an official augmentation sealer (world object).
+			if (worldo != NULL) {
+				user->Message(13, "Error: No available slot for augment");
+			}
+		}
+	} else {
+		
+		ItemInst *old_aug=NULL;
+		const uint32 id=auged_with->GetID();
+		
+		if (id==40408 || id==40409 || id==40410) {
+			tobe_auged->DeleteAugment(augmentationSlotToRemoveFrom);
+		}
+		else {
+			old_aug=tobe_auged->RemoveAugment(augmentationSlotToRemoveFrom);
+		}
+
+		user->PushItemOnCursor(*tobe_auged,true);
+
+		if (old_aug)
+			user->PushItemOnCursor(*old_aug,true);
+
+		wipeContainer = true;		
+	}
+	
+	if (wipeContainer) {
+		if (worldo != NULL) {
+			// Clear the container
+			worldo->m_inst->Clear();
+			
+			// Sent out container clear packer.
 			EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClearObject, sizeof(ClearObject_Struct));
 			ClearObject_Struct *cos = (ClearObject_Struct *)outapp->pBuffer;
 			cos->Clear = 1;
 			user->QueuePacket(outapp);
 			safe_delete(outapp);
+			
+			// Delete world container contents explicitly.
 			database.DeleteWorldContainer(worldo->m_id, zone->GetZoneID());
 		} else {
-			user->Message(13, "Error: No available slot for augment");
+			// Delete items in our inventory container... 
+			for (uint8 i=0; i<10; i++){
+				const ItemInst* inst = heldContainer->GetItem(i);
+				if (inst) {
+					user->DeleteItemInInventory(Inventory::CalcSlotId(heldContainer_ContainerSlot,i),0,true);
+				}
+			}
+			// Explicitly mark container as cleared.
+			heldContainer->Clear();
 		}
-	} else {
-		ItemInst *old_aug=NULL;
-		const uint32 id=auged_with->GetID();
-		if (id==40408 || id==40409 || id==40410)
-			tobe_auged->DeleteAugment(in_augment->augment_slot);
-		else
-			old_aug=tobe_auged->RemoveAugment(in_augment->augment_slot);
+	}
 
-		user->PushItemOnCursor(*tobe_auged,true);
-		if (old_aug)
-			user->PushItemOnCursor(*old_aug,true);
-		container->Clear();
-		EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClearObject, sizeof(ClearObject_Struct));
-		ClearObject_Struct *cos = (ClearObject_Struct *)outapp->pBuffer;
-		cos->Clear = 1;
+	return wipeContainer;
+}
+
+bool Object::HandleTradeskillAugmentationCombine(Client* user, const NewCombine_Struct* in_combine, ItemInst* container) 
+{
+	// Early out - if there are more than two items we are combining, we will not consider an aug combine.
+	if (2 != container->GetAvailableItemCount()){
+		return false;
+	}
+
+	bool augmentationActionHandled = false;
+
+	// For a successful augmentation, we need to have an augmentable item and either an augment or a distiller.
+	ItemInst* toBeAuged = NULL; // If set, this -will- be the item that will be modified.
+	ItemInst* augment = NULL; // If set, this will be the augment we attempt to apply.
+	ItemInst* otherItem = NULL; // If this is set, this -may- be an augment solvent (or similar) that we need to remove.
+
+	// Find the augment and the item to aug - or, the item to aug and the "other item" that may be an augment solvent.
+	int itemsFoundCount = 0;
+	for(uint8 ctr = 0; ctr < 10 && itemsFoundCount < 2; ctr++) {
+		
+		ItemInst* itemFound = container->GetItem(ctr);
+		if (itemFound) {
+			itemsFoundCount++;
+			if (itemFound->IsAugmentable()) {
+				toBeAuged = itemFound;
+			} else if (itemFound->IsAugment()) {
+				augment = itemFound;
+			} else {
+				otherItem = itemFound;
+			}
+		}
+	}
+
+	// Now that we know the two items we have to work with, lets see what we can do.
+	// We should have an item to be augmented and either an "other item" (solvent) or an augment.
+	if (toBeAuged) {
+		
+		// If we are passed an augment and:
+		//	1.  augment is usable by my race/class
+		//	2.  shares a common slot with the item to be augmented.
+		//  3.  will not cause an augment-lore collision on the item
+		//  then let us send the augmentation command to the internal augment function.
+		if (augment) {
+			if (augment->IsEquipable(user->GetPP().race, user->GetPP().class_) &&
+				augment->SharesACommonSlot(toBeAuged) &&
+				!toBeAuged->WillAugmentCauseLoreCollision(augment)
+				) {
+				// Attempt to augment.
+				augmentationActionHandled = Internal_HandleAugmentation(user,toBeAuged,augment,NULL,container,-1,in_combine->container_slot);	
+			}
+		}
+		// If we are not passed an augment and our item-to-augment is not augmented, there is no work to do.
+		else if (toBeAuged->IsAugmented()) {
+			// REMOVE AN AUGMENT.
+
+			// Important thing here - we cannot let users choose which item to remove so let us limit this, 
+			//	explicitly, to exclude the "delete augment" distillers.  Better to make this a safe remove 
+			//	only rather than to allow functionality that would destroy an augment on accident.
+			// 
+
+			const uint32 idOfAssumedSolvent = otherItem->GetID();
+			if(idOfAssumedSolvent==40408 || idOfAssumedSolvent==40409 || idOfAssumedSolvent==40410) {
+				user->Message(13, "Container based augmentation is not allowed for augment deletion.  Use a safe-removal solvent or an augmentation world container.");
+				
+				// If we are explicitly refusing to handle a case, then there should be no tradeskill combine that is allowed here.  Out!
+				augmentationActionHandled = true;
+
+			} else {
+
+				// Time to determine which augment (if any) can be removed by the proposed solvent.
+				// This will hit the database.  It -may- be worthwhile to consider pulling this data into the database
+				//	all at one time as opposed to performing checks whenever needed.  That said, the lookup is a lightweight
+				//	one and no performance issues were found when testing.  Lets not prematurely optimize this.
+				
+				// We will find the first augment that can be removed with this solvent and remove it.  If the user wishes
+				//	to control de-augmentation in a finer way, the world container is still an option.
+				
+				sint32 slotToRemove = -1;
+				
+				for(uint8 ctr = 0; ctr < 10; ctr++) {
+
+					ItemInst* augToRemove = toBeAuged->GetAugment(ctr);
+					if (augToRemove) {
+						
+						// Check if this item can be removed... 
+						if (database.GetIsAllowedAugmentRemoval(augToRemove->GetID(), idOfAssumedSolvent)) {
+							slotToRemove = ctr;
+							break;
+						}						
+					}
+				}
+				
+				// If we found something to remove, lets do it.
+				if (slotToRemove > -1) {
+					augmentationActionHandled = Internal_HandleAugmentation(user,toBeAuged,otherItem,NULL,container,slotToRemove,in_combine->container_slot);	
+				}
+			}
+		}
+	}
+
+	// If we actually -did- something that will stop tradeskills from continuing, let us
+	//	go ahead and send the tradeskill combine acknowledgement packet so that the client is not
+	//	paused and waiting for us.
+	if (augmentationActionHandled) {
+		EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
 		user->QueuePacket(outapp);
 		safe_delete(outapp);
-		database.DeleteWorldContainer(worldo->m_id, zone->GetZoneID());
 	}
+	
+	return augmentationActionHandled;
 }
 
 // Perform tradeskill combine
@@ -157,6 +303,17 @@
 	}
 	
 	container = inst;
+
+	// Do we allow augmentation combines from this container?
+	if (some_id > 0 && RuleI(Skills, ContainerIdToAllowAugCombines)==some_id) {
+		
+		// Attempt to handle a possible aug combination.
+		if (HandleTradeskillAugmentationCombine(user, in_combine, container)) {
+			
+			// Do no further work as the combine is already handled.
+			return;
+		}
+	}
 	
  	DBTradeskillRecipe_Struct spec;
  	if (!database.GetTradeRecipe(container, c_type, some_id, user->CharacterID(), &spec)) {
@@ -1016,7 +1173,36 @@
 	_log(TRADESKILLS__TRACE, "...Stage2 chance was: %f percent. 0 percent means stage1 failed",  chance_stage2);
 }
 
+/// Just a quick check to see if an augment dissolver is allowed to be used against a particular augment.
+bool ZoneDatabase::GetIsAllowedAugmentRemoval(uint32 augmentId, uint32 dissolverToTest)
+{
+	bool returnValue = false;
 
+	char errbuf[MYSQL_ERRMSG_SIZE];
+    MYSQL_RES *result;
+    char *query = 0;
+	uint32 qlen = 0;
+
+	qlen = MakeAnyLenString(&query, "SELECT 1 FROM items WHERE id = %u AND augdistiller = %u AND id <> 0 AND augdistiller <> 0", augmentId, dissolverToTest);
+
+	if (!RunQuery(query, qlen, errbuf, &result)) {
+		LogFile->write(EQEMuLog::Error, "Error in GetIsAllowedAugmentRemoval search, query: %s", query);
+		safe_delete_array(query);
+		LogFile->write(EQEMuLog::Error, "Error in GetIsAllowedAugmentRemoval search, error: %s", errbuf);
+		return(false);
+	}
+
+	safe_delete_array(query);
+	
+	// If even a single row is returned, then augmentation removal is allowed.
+	returnValue = mysql_num_rows(result) > 0;
+
+	// Clean up string allocation.
+	safe_delete_array(query);
+
+	return(returnValue);
+}
+
 bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint32 some_id, 
 	uint32 char_id, DBTradeskillRecipe_Struct *spec)
 {
Index: zone/zonedb.h
===================================================================
--- zone/zonedb.h	(revision 1771)
+++ zone/zonedb.h	(working copy)
@@ -277,6 +277,7 @@
 	int32   GetZoneForage(int32 ZoneID, int8 skill);    /* for foraging - BoB */
 	int32   GetZoneFishing(int32 ZoneID, int8 skill, uint32 &npc_id, uint8 &npc_chance);
 	void	UpdateRecipeMadecount(uint32 recipe_id, uint32 char_id, uint32 madecount);
+	bool	GetIsAllowedAugmentRemoval(uint32 augmentId, uint32 dissolverToTest);
 	
 	/*
 	 * Tribute
Reply With Quote