/*
* 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.List;
import java.util.concurrent.ScheduledFuture;
import javolution.util.FastMap;
import org.apache.log4j.Logger;
import com.aionemu.gameserver.configs.main.GroupConfig;
import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.Monster;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.gameobjects.player.RequestResponseHandler;
import com.aionemu.gameserver.model.group.GroupEvent;
import com.aionemu.gameserver.model.group.LootGroupRules;
import com.aionemu.gameserver.model.group.LootRuleType;
import com.aionemu.gameserver.model.group.PlayerGroup;
import com.aionemu.gameserver.network.aion.clientpackets.CM_VIEW_PLAYER_DETAILS;
import com.aionemu.gameserver.network.aion.serverpackets.SM_GROUP_INFO;
import com.aionemu.gameserver.network.aion.serverpackets.SM_GROUP_MEMBER_INFO;
import com.aionemu.gameserver.network.aion.serverpackets.SM_QUESTION_WINDOW;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SHOW_BRAND;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.questEngine.QuestEngine;
import com.aionemu.gameserver.questEngine.model.QuestEnv;
import com.aionemu.gameserver.restrictions.RestrictionsManager;
import com.aionemu.gameserver.utils.MathUtil;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.utils.idfactory.IDFactory;
import com.aionemu.gameserver.utils.idfactory.IDFactoryAionObject;
import com.aionemu.gameserver.utils.stats.StatFunctions;
import com.google.inject.Inject;
/**
* @author Simple
*/
public class GroupService
{
/**
* Definition for logging
*/
private static final Logger log = Logger.getLogger(CM_VIEW_PLAYER_DETAILS.class);
/**
* Caching group members
*/
private final FastMap<Integer, PlayerGroup> groupMembers = new FastMap<Integer, PlayerGroup>();
/**
* Caching remove group member schedule
*/
private FastMap<Integer, ScheduledFuture<?>> playerGroup = new FastMap<Integer, ScheduledFuture<?>>();
/**
* Injections
*/
@Inject
@IDFactoryAionObject
private IDFactory aionObjectsIDFactory;
@Inject
QuestEngine questEngine;
/**
* This method will add a member to the group member cache
*
* @param player
*/
public void addGroupMemberToCache(Player player)
{
if(!groupMembers.containsKey(player.getObjectId()))
groupMembers.put(player.getObjectId(), player.getPlayerGroup());
}
public void removeGroupMemberFromCache(int playerObjId)
{
if(groupMembers.containsKey(playerObjId))
groupMembers.remove(playerObjId);
}
/**
* @param playerObjId
* @return returns true if player is in the cache
*/
public boolean isGroupMember(int playerObjId)
{
return groupMembers.containsKey(playerObjId);
}
/**
* Returns the player's group
*
* @param playerObjId
* @return PlayerGroup
*/
public PlayerGroup getGroup(int playerObjId)
{
return groupMembers.get(playerObjId);
}
/**
* This method will handle everything to a player that is invited for a group
*
* @param inviter
* @param invited
*/
public void invitePlayerToGroup(final Player inviter, final Player invited)
{
if(RestrictionsManager.canInviteToGroup(inviter, invited))
{
final PlayerGroup group = inviter.getPlayerGroup();
RequestResponseHandler responseHandler = new RequestResponseHandler(inviter){
@Override
public void acceptRequest(Creature requester, Player responder)
{
if(group != null && group.isFull())
return;
PacketSendUtility.sendPacket(inviter, SM_SYSTEM_MESSAGE.REQUEST_GROUP_INVITE(invited.getName()));
if(group != null)
{
inviter.getPlayerGroup().addPlayerToGroup(invited);
addGroupMemberToCache(invited);
}
else
{
new PlayerGroup(aionObjectsIDFactory.nextId(), inviter);
inviter.getPlayerGroup().addPlayerToGroup(invited);
addGroupMemberToCache(inviter);
addGroupMemberToCache(invited);
}
}
@Override
public void denyRequest(Creature requester, Player responder)
{
PacketSendUtility.sendPacket(inviter, SM_SYSTEM_MESSAGE.REJECT_GROUP_INVITE(responder.getName()));
}
};
boolean result = invited.getResponseRequester().putRequest(SM_QUESTION_WINDOW.STR_REQUEST_GROUP_INVITE,
responseHandler);
if(result)
{
PacketSendUtility.sendPacket(invited, new SM_QUESTION_WINDOW(
SM_QUESTION_WINDOW.STR_REQUEST_GROUP_INVITE, 0, inviter.getName()));
}
}
}
/**
* @param player
*/
public void removePlayerFromGroup(Player player)
{
if(player.isInGroup())
{
final PlayerGroup group = player.getPlayerGroup();
group.removePlayerFromGroup(player);
removeGroupMemberFromCache(player.getObjectId());
if(group.size() < 2)
disbandGroup(group);
}
}
/**
* @param player
*/
public void setGroupLeader(Player player)
{
final PlayerGroup group = player.getPlayerGroup();
group.setGroupLeader(player);
group.updateGroupUIToEvent(player.getPlayerGroup().getGroupLeader(), GroupEvent.CHANGELEADER);
}
/**
* @param status
* @param playerObjId
* @param player
*/
public void playerStatusInfo(int status, Player player)
{
switch(status)
{
case 2:
removePlayerFromGroup(player);
break;
case 3:
setGroupLeader(player);
break;
case 6:
removePlayerFromGroup(player);
break;
}
log.info(String.valueOf(status));
}
/**
* @param player
* @param amount
*/
public void groupDistribution(Player player, int amount)
{
PlayerGroup pg = player.getPlayerGroup();
if(pg == null)
return;
int availableKinah = player.getInventory().getKinahItem().getItemCount();
if(availableKinah < amount)
{
// TODO retail message ?
return;
}
int rewardcount = pg.size() - 1;
if(rewardcount <= amount)
{
int reward = amount / rewardcount;
for(Player groupMember : pg.getMembers())
{
if(groupMember.equals(player))
groupMember.getInventory().decreaseKinah(amount);
else
groupMember.getInventory().increaseKinah(reward);
}
}
}
/**
* This method will send a reward if a player is in a group
*
* @param player
*/
public void doReward(Player player, Monster owner)
{
long xpReward = StatFunctions.calculateGroupExperienceReward(player, owner);
List<Player> players = new ArrayList<Player>();
int partyLvlSum = 0;
for(Player member : player.getPlayerGroup().getMembers())
{
if(MathUtil.isInRange(member, player, GroupConfig.GROUP_MAX_DISTANCE))
{
players.add(member);
partyLvlSum += member.getLevel();
}
}
double mod = 1;
if (players.size() == 0)
return;
else if (players.size() > 1)
mod = 1+(((players.size()-1)*10)/100);
xpReward *= mod;
for(Player member : players)
{
long currentExp = member.getCommonData().getExp();
long reward = (xpReward * member.getLevel())/partyLvlSum;
reward *= member.getRates().getGroupXpRate();
member.getCommonData().setExp(currentExp + reward);
PacketSendUtility.sendPacket(member, SM_SYSTEM_MESSAGE.EXP(Long.toString(reward)));
// DPreward
int currentDp = member.getCommonData().getDp();
int dpReward = StatFunctions.calculateGroupDPReward(member, owner);
member.getCommonData().setDp(dpReward + currentDp);
questEngine.onKill(new QuestEnv(owner, member, 0 , 0));
}
}
/**
* This method will send the show brand to every groupmember
*
* @param playerGroup
* @param brandId
* @param targetObjectId
*/
public void showBrand(PlayerGroup playerGroup, int brandId, int targetObjectId)
{
for(Player member : playerGroup.getMembers())
{
PacketSendUtility.sendPacket(member, new SM_SHOW_BRAND(brandId, targetObjectId));
}
}
/**
* This method is called when a group is disbanded
*/
private void disbandGroup(PlayerGroup group)
{
aionObjectsIDFactory.releaseId(group.getGroupId());
group.getGroupLeader().setPlayerGroup(null);
PacketSendUtility.sendPacket(group.getGroupLeader(), SM_SYSTEM_MESSAGE.DISBAND_GROUP());
}
/**
* @param player
*/
public void onLogin(Player activePlayer)
{
final PlayerGroup group = activePlayer.getPlayerGroup();
// Send legion info packets
PacketSendUtility.sendPacket(activePlayer, new SM_GROUP_INFO(group));
for(Player member : group.getMembers())
{
if(!activePlayer.equals(member))
PacketSendUtility.sendPacket(activePlayer, new SM_GROUP_MEMBER_INFO(group, member, GroupEvent.ENTER));
}
}
/**
* @param playerGroupCache
* the playerGroupCache to set
*/
public void addPlayerGroupCache(int playerObjId, ScheduledFuture<?> future)
{
if(!playerGroup.containsKey(playerObjId))
playerGroup.put(playerObjId, future);
}
/**
* This method will remove a schedule to remove a player from a group
*
* @param playerObjId
*/
public void cancelScheduleRemove(int playerObjId)
{
if(playerGroup.containsKey(playerObjId))
{
playerGroup.get(playerObjId).cancel(true);
playerGroup.remove(playerObjId);
}
}
/**
* This method will create a schedule to remove a player from a group
*
* @param player
*/
public void scheduleRemove(final Player player)
{
ScheduledFuture<?> future = ThreadPoolManager.getInstance().schedule(new Runnable(){
@Override
public void run()
{
removePlayerFromGroup(player);
playerGroup.remove(player.getObjectId());
}
}, GroupConfig.GROUP_REMOVE_TIME * 1000);
addPlayerGroupCache(player.getObjectId(), future);
player.getPlayerGroup().getMembers().remove(player.getObjectId());
for(Player groupMember : player.getPlayerGroup().getMembers())
{
// TODO: MISSING SEND PARTY MEMBER PACKETS
PacketSendUtility.sendPacket(groupMember, SM_SYSTEM_MESSAGE.PARTY_HE_BECOME_OFFLINE(player.getName()));
}
}
/**
* @param player
*/
public void setGroup(Player player)
{
if(!isGroupMember(player.getObjectId()))
return;
final PlayerGroup group = getGroup(player.getObjectId());
if(group.size() < 2)
{
removeGroupMemberFromCache(player.getObjectId());
cancelScheduleRemove(player.getObjectId());
return;
}
player.setPlayerGroup(group);
group.onGroupMemberLogIn(player);
cancelScheduleRemove(player.getObjectId());
if(group.getGroupLeader().getObjectId() == player.getObjectId())
group.setGroupLeader(player);
}
/**
* @return FastMap<Integer, Boolean>
*/
public List<Integer> getMembersToRegistrateByRules(final Player player, final PlayerGroup group)
{
final LootGroupRules lootRules = group.getLootGroupRules();
final LootRuleType lootRule = lootRules.getLootRule();
List<Integer> luckyMembers = new ArrayList<Integer>();
switch(lootRule)
{
case FREEFORALL:
luckyMembers = getGroupMembers(group, false);
break;
case ROUNDROBIN:
luckyMembers.add(group.getRandomMember());
break;
case LEADER:
luckyMembers.add(group.getGroupLeader().getObjectId());
break;
}
return luckyMembers;
}
/**
* This method will get all group members
*
* @param group
* @param except
* @return list of group members
*/
public List<Integer> getGroupMembers(final PlayerGroup group, boolean except)
{
List<Integer> luckyMembers = new ArrayList<Integer>();
for(int memberObjId : group.getMemberObjIds())
{
if(except)
{
if(group.getGroupLeader().getObjectId() != memberObjId)
luckyMembers.add(memberObjId);
}
else
luckyMembers.add(memberObjId);
}
return luckyMembers;
}
/**
* @param player
*/
public Player getLuckyPlayer(Player player)
{
final PlayerGroup group = player.getPlayerGroup();
switch(group.getLootGroupRules().getAutodistribution())
{
case NORMAL:
return player;
case ROLL_DICE:
// NOT FINISHED YET
return player;
case BID:
// NOT FINISHED YET
return player;
}
return player;
}
}