/* * This file is part of aion-unique <aion-unique.org>. * * aion-unique 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. * * aion-unique 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 aion-unique. If not, see <http://www.gnu.org/licenses/>. */ package com.aionemu.gameserver.services; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javolution.util.FastMap; import org.apache.log4j.Logger; import com.aionemu.commons.database.dao.DAOManager; import com.aionemu.gameserver.dao.DropListDAO; import com.aionemu.gameserver.model.drop.DropItem; import com.aionemu.gameserver.model.drop.DropList; import com.aionemu.gameserver.model.drop.DropTemplate; import com.aionemu.gameserver.model.gameobjects.DropNpc; import com.aionemu.gameserver.model.gameobjects.Npc; import com.aionemu.gameserver.model.gameobjects.player.Player; import com.aionemu.gameserver.model.gameobjects.state.CreatureState; import com.aionemu.gameserver.network.aion.serverpackets.SM_EMOTION; import com.aionemu.gameserver.network.aion.serverpackets.SM_LOOT_ITEMLIST; import com.aionemu.gameserver.network.aion.serverpackets.SM_LOOT_STATUS; import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE; import com.aionemu.gameserver.utils.PacketSendUtility; import com.aionemu.gameserver.world.World; import com.google.inject.Inject; /** * @author ATracer */ public class DropService { private static final Logger log = Logger.getLogger(DropService.class); private DropList dropList; private Map<Integer, Set<DropItem>> currentDropMap = Collections .synchronizedMap(new HashMap<Integer, Set<DropItem>>()); private Map<Integer, DropNpc> dropRegistrationMap = new FastMap<Integer, DropNpc>(); private ItemService itemService; private GroupService groupService; private QuestService questService; private World world; @Inject public DropService(ItemService itemService, World world, GroupService groupService, QuestService questService) { this.itemService = itemService; this.world = world; this.groupService = groupService; this.questService = questService; dropList = DAOManager.getDAO(DropListDAO.class).load(); log.info(dropList.getSize() + " npc drops loaded"); } /** * @return the dropList */ public DropList getDropList() { return dropList; } /** * After NPC dies - it can register arbitrary drop * * @param npc */ public void registerDrop(Npc npc, Player player) { int npcUniqueId = npc.getObjectId(); int npcTemplateId = npc.getObjectTemplate().getTemplateId(); Set<DropItem> droppedItems = new HashSet<DropItem>(); Set<DropTemplate> templates = dropList.getDropsFor(npcTemplateId); int index = 1; if(templates != null) { for(DropTemplate dropTemplate : templates) { DropItem dropItem = new DropItem(dropTemplate); dropItem.calculateCount(player.getRates().getDropRate()); if(dropItem.getCount() > 0) { dropItem.setIndex(index++); droppedItems.add(dropItem); } } } questService.getQuestDrop(droppedItems, index, npc, player); currentDropMap.put(npcUniqueId, droppedItems); // TODO player should not be null if(player != null) { if(player.isInGroup()) { dropRegistrationMap.put(npcUniqueId, new DropNpc(groupService.getMembersToRegistrateByRules(player, player.getPlayerGroup()))); } else { List<Integer> singlePlayer = new ArrayList<Integer>(); singlePlayer.add(player.getObjectId()); dropRegistrationMap.put(npcUniqueId, new DropNpc(singlePlayer)); } } } /** * After NPC respawns - drop should be unregistered //TODO more correct - on despawn * * @param npc */ public void unregisterDrop(Npc npc) { int npcUniqueId = npc.getObjectId(); currentDropMap.remove(npcUniqueId); if(dropRegistrationMap.containsKey(npcUniqueId)) { dropRegistrationMap.remove(npcUniqueId); } } /** * When player clicks on dead NPC to request drop list * * @param player * @param npcId */ public void requestDropList(Player player, int npcId) { if(player == null || !dropRegistrationMap.containsKey(npcId)) return; DropNpc dropNpc = dropRegistrationMap.get(npcId); if(!dropNpc.containsKey(player.getObjectId())) { PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_LOOT_NO_RIGHT()); return; } if(dropNpc.isBeingLooted()) { PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_LOOT_FAIL_ONLOOTING()); return; } dropNpc.setBeingLooted(player.getObjectId()); Set<DropItem> dropItems = currentDropMap.get(npcId); if(dropItems == null) { dropItems = Collections.emptySet(); } PacketSendUtility.sendPacket(player, new SM_LOOT_ITEMLIST(npcId, dropItems, player)); // PacketSendUtility.sendPacket(player, new SM_LOOT_STATUS(npcId, size > 0 ? size - 1 : size)); PacketSendUtility.sendPacket(player, new SM_LOOT_STATUS(npcId, 2)); player.unsetState(CreatureState.ACTIVE); player.setState(CreatureState.LOOTING); PacketSendUtility.broadcastPacket(player, new SM_EMOTION(player, 35, 0, npcId), true); // if dropitems is empty, resend droplist for close loot if(dropItems.size() == 0) resendDropList(player, npcId, dropItems); } /** * This method will change looted corpse to not in use * @param player * @param npcId * @param close */ public void requestDropList(Player player, int npcId, boolean close) { if(!dropRegistrationMap.containsKey(npcId)) return; DropNpc dropNpc = dropRegistrationMap.get(npcId); dropNpc.setBeingLooted(0); if(player.isInGroup()) { if(player.getPlayerGroup().getGroupLeader().getObjectId() == player.getObjectId()) dropRegistrationMap.put(npcId, new DropNpc(groupService.getGroupMembers(player.getPlayerGroup(), true))); } player.unsetState(CreatureState.LOOTING); player.setState(CreatureState.ACTIVE); PacketSendUtility.broadcastPacket(player, new SM_EMOTION(player, 36, 0, npcId), true); } public void requestDropItem(Player player, int npcId, int itemIndex) { Set<DropItem> dropItems = currentDropMap.get(npcId); // drop was unregistered if(dropItems == null) { return; } // TODO prevent possible exploits DropItem requestedItem = null; synchronized(dropItems) { for(DropItem dropItem : dropItems) { if(dropItem.getIndex() == itemIndex) { requestedItem = dropItem; break; } } } if(requestedItem != null) { int currentDropItemCount = requestedItem.getCount(); int itemId = requestedItem.getDropTemplate().getItemId(); currentDropItemCount = itemService.addItem(player, itemId, currentDropItemCount); if(currentDropItemCount == 0) { dropItems.remove(requestedItem); } else { // If player didnt got all item stack requestedItem.setCount(currentDropItemCount); } // show updated droplist resendDropList(player, npcId, dropItems); } } private void resendDropList(Player player, int npcId, Set<DropItem> dropItems) { if(dropItems.size() != 0) { PacketSendUtility.sendPacket(player, new SM_LOOT_ITEMLIST(npcId, dropItems, player)); PacketSendUtility.sendPacket(player, new SM_LOOT_STATUS(npcId, 0)); } else { PacketSendUtility.sendPacket(player, new SM_LOOT_STATUS(npcId, 3)); player.unsetState(CreatureState.LOOTING); player.setState(CreatureState.ACTIVE); PacketSendUtility.broadcastPacket(player, new SM_EMOTION(player, 36, 0, npcId), true); Npc npc = (Npc) world.findAionObject(npcId); if(npc != null) { npc.getController().onDespawn(true); } } } }