Forráskód Böngészése

BETA: Retail Drop Protection (Based on DrHouse's work improved by Nik)

Rumen Nikiforov 14 éve
szülő
commit
15418258a2

+ 95 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/DropProtection.java

@@ -0,0 +1,95 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.gameserver.model;
+
+import java.util.concurrent.ScheduledFuture;
+
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PetInstance;
+
+/**
+ * 
+ * @author DrHouse
+ *
+ */
+public class DropProtection implements Runnable
+{
+	private volatile boolean _isProtected = false;
+	private L2PcInstance _owner = null;
+	private ScheduledFuture<?> _task = null;
+	
+	private static final long PROTECTED_MILLIS_TIME = 15000;
+	
+	public synchronized void run()
+	{
+		_isProtected = false;
+		_owner = null;
+		_task = null;
+	}
+	
+	public boolean isProtected()
+	{
+		return _isProtected;
+	}
+	
+	public L2PcInstance getOwner()
+	{
+		return _owner;
+	}
+	
+	public synchronized boolean tryPickUp(L2PcInstance actor)
+	{
+		if (!_isProtected)
+			return true;
+		
+		if (_owner == actor)
+			return true;
+		
+		if (_owner.getParty() != null && _owner.getParty() == actor.getParty())
+			return true;
+		
+		/*if (_owner.getClan() != null && _owner.getClan() == actor.getClan())
+			return true;*/
+		
+		return false;
+	}
+	
+	public boolean tryPickUp(L2PetInstance pet)
+	{
+		return tryPickUp(pet.getOwner());
+	}
+	
+	public synchronized void unprotect()
+	{
+		if (_task != null)
+			_task.cancel(false);
+		_isProtected = false;
+		_owner = null;
+		_task = null;
+	}
+	
+	public synchronized void protect(L2PcInstance player)
+	{
+		unprotect();
+		
+		_isProtected = true;
+		
+		if ((_owner = player) == null)
+			throw new NullPointerException("Trying to protect dropped item to null owner");
+		
+		_task = ThreadPoolManager.getInstance().scheduleGeneral(this, PROTECTED_MILLIS_TIME);
+	}
+}

+ 7 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/L2ItemInstance.java

@@ -158,6 +158,8 @@ public final class L2ItemInstance extends L2Object
 	
 	private ScheduledFuture<?> itemLootShedule = null;
 	public ScheduledFuture<?> _lifeTimeTask;
+	
+	private final DropProtection _dropProtection = new DropProtection();
 	/**
 	 * Constructor of the L2ItemInstance from the objectId and the itemId.
 	 * @param objectId : int designating the ID of the object in the world
@@ -1891,6 +1893,11 @@ public final class L2ItemInstance extends L2Object
 			activeChar.sendPacket(new SpawnItem(this));
 	}
 	
+	public final DropProtection getDropProtection()
+	{
+		return _dropProtection;
+	}
+	
 	public boolean isPublished()
 	{
 		return _published;

+ 28 - 17
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/L2Attackable.java

@@ -595,19 +595,13 @@ public class L2Attackable extends L2Npc
 			if (getAggroList().isEmpty())
 				return;
 			
-			// Manage Base, Quests and Sweep drops of the L2Attackable
-			doItemDrop(lastAttacker);
-			
-			// Manage drop of Special Events created by GM for a defined period
-			doEventDrop(lastAttacker);
-			
-			if (!getMustRewardExpSP())
-				return;
-			
 			int damage;
 			L2Character attacker, ddealer;
 			RewardInfo reward;
 			
+			L2PcInstance maxDealer = null;
+			int maxDamage = 0;
+			
 			// While Interating over This Map Removing Object is Not Allowed
 			//synchronized (getAggroList())
 			{
@@ -644,9 +638,25 @@ public class L2Attackable extends L2Npc
 							reward.addDamage(damage);
 						
 						rewards.put(ddealer, reward);
+						
+						if (ddealer.getActingPlayer() != null && reward._dmg > maxDamage)
+						{ 
+							maxDealer = ddealer.getActingPlayer();
+							maxDamage = reward._dmg;
+						}
 					}
 				}
 			}
+			
+			// Manage Base, Quests and Sweep drops of the L2Attackable
+			doItemDrop(maxDealer != null && maxDealer.isOnline() == true ? maxDealer : lastAttacker);
+
+			// Manage drop of Special Events created by GM for a defined period
+			doEventDrop(lastAttacker);
+
+			if (!getMustRewardExpSP())
+				return;
+		 	
 			if (!rewards.isEmpty())
 			{
 				L2Party attackerParty;
@@ -1575,9 +1585,9 @@ public class L2Attackable extends L2Npc
 		return null;
 	}
 	
-	public void doItemDrop(L2Character lastAttacker)
+	public void doItemDrop(L2Character mainDamageDealer)
 	{
-		doItemDrop(getTemplate(),lastAttacker);
+		doItemDrop(getTemplate(),mainDamageDealer);
 	}
 	
 	/**
@@ -1599,12 +1609,12 @@ public class L2Attackable extends L2Npc
 	 *
 	 * @param lastAttacker The L2Character that has killed the L2Attackable
 	 */
-	public void doItemDrop(L2NpcTemplate npcTemplate, L2Character lastAttacker)
+	public void doItemDrop(L2NpcTemplate npcTemplate, L2Character mainDamageDealer)
 	{
-		if (lastAttacker == null)
+		if (mainDamageDealer == null)
 			return;
 		
-		L2PcInstance player = lastAttacker.getActingPlayer();
+		L2PcInstance player = mainDamageDealer.getActingPlayer();
 		
 		// Don't drop anything if the last attacker or owner isn't L2PcInstance
 		if (player == null)
@@ -1780,7 +1790,7 @@ public class L2Attackable extends L2Npc
 	/**
 	 * Drop reward item.
 	 */
-	public L2ItemInstance dropItem(L2PcInstance lastAttacker, RewardItem item)
+	public L2ItemInstance dropItem(L2PcInstance mainDamageDealer, RewardItem item)
 	{
 		int randDropLim = 70;
 		
@@ -1790,12 +1800,13 @@ public class L2Attackable extends L2Npc
 			// Randomize drop position
 			int newX = getX() + Rnd.get(randDropLim * 2 + 1) - randDropLim;
 			int newY = getY() + Rnd.get(randDropLim * 2 + 1) - randDropLim;
-			int newZ = Math.max(getZ(), lastAttacker.getZ()) + 20; // TODO: temp hack, do somethign nicer when we have geodatas
+			int newZ = Math.max(getZ(), mainDamageDealer.getZ()) + 20; // TODO: temp hack, do somethign nicer when we have geodatas
 			
 			if (ItemTable.getInstance().getTemplate(item.getItemId()) != null)
 			{
 				// Init the dropped L2ItemInstance and add it in the world as a visible object at the position where mob was last
-				ditem = ItemTable.getInstance().createItem("Loot", item.getItemId(), item.getCount(), lastAttacker, this);
+				ditem = ItemTable.getInstance().createItem("Loot", item.getItemId(), item.getCount(), mainDamageDealer, this);
+				ditem.getDropProtection().protect(mainDamageDealer);
 				ditem.dropMe(this, newX, newY, newZ);
 				
 				// Add drop to auto destroy item task

+ 37 - 10
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java

@@ -3454,7 +3454,7 @@ public final class L2PcInstance extends L2Playable
 			
 			// If over capacity, drop the item
 			if (!isGM() && !_inventory.validateCapacity(0, item.isQuestItem()) && newitem.isDropable() && (!newitem.isStackable() || newitem.getLastChange() != L2ItemInstance.MODIFIED))
-				dropItem("InvDrop", newitem, null, true);
+				dropItem("InvDrop", newitem, null, true, true);
 			
 			// Cursed Weapon
 			else if(CursedWeaponsManager.getInstance().isCursed(newitem.getItemId()))
@@ -3859,9 +3859,10 @@ public final class L2PcInstance extends L2Playable
 	 * @param item : L2ItemInstance to be dropped
 	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
 	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
+	 * @param protectItem: whether or not dropped item must be protected temporary against other players
 	 * @return boolean informing if the action was successfull
 	 */
-	public boolean dropItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage)
+	public boolean dropItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage, boolean protectItem)
 	{
 		item = _inventory.dropItem(process, item, this, reference);
 		
@@ -3875,19 +3876,27 @@ public final class L2PcInstance extends L2Playable
 		
 		item.dropMe(this, getX() + Rnd.get(50) - 25, getY() + Rnd.get(50) - 25, getZ() + 20);
 		
-		if (Config.AUTODESTROY_ITEM_AFTER >0 && Config.DESTROY_DROPPED_PLAYER_ITEM && !Config.LIST_PROTECTED_ITEMS.contains(item.getItemId()))
-		{
-			if ( (item.isEquipable() && Config.DESTROY_EQUIPABLE_PLAYER_ITEM) || !item.isEquipable())
+		if (Config.AUTODESTROY_ITEM_AFTER > 0
+				&& Config.DESTROY_DROPPED_PLAYER_ITEM
+				&& !Config.LIST_PROTECTED_ITEMS.contains(item.getItemId())) {
+			if ((item.isEquipable() && Config.DESTROY_EQUIPABLE_PLAYER_ITEM)
+					|| !item.isEquipable())
 				ItemsAutoDestroy.getInstance().addItem(item);
 		}
-		if (Config.DESTROY_DROPPED_PLAYER_ITEM){
-			if (!item.isEquipable() || (item.isEquipable()  && Config.DESTROY_EQUIPABLE_PLAYER_ITEM ))
+		
+		// protection against auto destroy dropped item
+		if (Config.DESTROY_DROPPED_PLAYER_ITEM) {
+			if (!item.isEquipable()
+					|| (item.isEquipable() && Config.DESTROY_EQUIPABLE_PLAYER_ITEM))
 				item.setProtected(false);
 			else
 				item.setProtected(true);
-		}
-		else
+		} else
 			item.setProtected(true);
+
+		// retail drop protection 
+		if (protectItem)
+			item.getDropProtection().protect(this);
 		
 		// Send inventory update packet
 		if (!Config.FORCE_INVENTORY_UPDATE)
@@ -3914,6 +3923,11 @@ public final class L2PcInstance extends L2Playable
 		return true;
 	}
 	
+	public boolean dropItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage)
+	{
+		return dropItem(process, item, reference, sendMessage, false);
+	}
+	
 	/**
 	 * Drop item from inventory by using its <B>objectID</B> and send a Server->Client InventoryUpdate packet to the L2PcInstance.
 	 * @param process : String Identifier of process triggering this action
@@ -3926,7 +3940,7 @@ public final class L2PcInstance extends L2Playable
 	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
 	 * @return L2ItemInstance corresponding to the new item or the updated item in inventory
 	 */
-	public L2ItemInstance dropItem(String process, int objectId, long count, int x, int y, int z, L2Object reference, boolean sendMessage)
+	public L2ItemInstance dropItem(String process, int objectId, long count, int x, int y, int z, L2Object reference, boolean sendMessage, boolean protectItem)
 	{
 		L2ItemInstance invitem = _inventory.getItemByObjectId(objectId);
 		L2ItemInstance item = _inventory.dropItem(process, objectId, count, this, reference);
@@ -3955,6 +3969,10 @@ public final class L2PcInstance extends L2Playable
 		else
 			item.setProtected(true);
 		
+		// retail drop protection 
+		if (protectItem)
+			item.getDropProtection().protect(this);
+		
 		// Send inventory update packet
 		if (!Config.FORCE_INVENTORY_UPDATE)
 		{
@@ -4652,6 +4670,15 @@ public final class L2PcInstance extends L2Playable
 				sendPacket(ActionFailed.STATIC_PACKET);
 				return;
 			}
+
+			if (!target.getDropProtection().tryPickUp(this))
+			{
+				sendPacket(ActionFailed.STATIC_PACKET);
+				SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1);
+				smsg.addItemName(target);
+				sendPacket(smsg);
+				return;
+			}
 			
 			if ( ((isInParty() && getParty().getLootDistribution() == L2Party.ITEM_LOOTER) || !isInParty()) && !_inventory.validateCapacity(target))
 			{

+ 8 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2PetInstance.java

@@ -766,16 +766,23 @@ public class L2PetInstance extends L2Summon
 		}
 	}
 	
-	public void dropItemHere(L2ItemInstance dropit)
+	public void dropItemHere(L2ItemInstance dropit, boolean protect)
 	{
 		dropit = getInventory().dropItem("Drop", dropit.getObjectId(), dropit.getCount(), getOwner(), this);
 		
 		if (dropit != null)
 		{
+			if (protect)
+				dropit.getDropProtection().protect(getOwner());
 			_logPet.finer("Item id to drop: "+dropit.getItemId()+" amount: "+dropit.getCount());
 			dropit.dropMe(this, getX(), getY(), getZ()+100);
 		}
 	}
+	
+	public void dropItemHere(L2ItemInstance dropit)
+	{
+		dropItemHere(dropit, false);
+	}
 
 	/** @return Returns the mount able. */
 	@Override

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/RequestDropItem.java

@@ -200,7 +200,7 @@ public final class RequestDropItem extends L2GameClientPacket
 			activeChar.sendPacket(il);
 		}
 		
-		L2ItemInstance dropedItem = activeChar.dropItem("Drop", _objectId, _count, _x, _y, _z, null, false);
+		L2ItemInstance dropedItem = activeChar.dropItem("Drop", _objectId, _count, _x, _y, _z, null, false, true);
 		
 		if (Config.DEBUG)
 			_log.fine("dropping " + _objectId + " item(" + _count + ") at: " + _x + " " + _y + " " + _z);