package l2p.gameserver.model;
import l2p.Config;
import l2p.common.ThreadPoolManager;
import l2p.gameserver.cache.Msg;
import l2p.gameserver.instancemanager.PartyRoomManager;
import l2p.gameserver.model.L2ObjectTasks.SoulConsumeTask;
import l2p.gameserver.model.base.Experience;
import l2p.gameserver.model.entity.DimensionalRift;
import l2p.gameserver.model.entity.SevenSignsFestival.DarknessFestival;
import l2p.gameserver.model.instances.L2MonsterInstance;
import l2p.gameserver.model.instances.L2NpcInstance;
import l2p.gameserver.model.items.L2ItemInstance;
import l2p.gameserver.serverpackets.ExPartyPetWindowAdd;
import l2p.gameserver.serverpackets.ExPartyPetWindowDelete;
import l2p.gameserver.serverpackets.L2GameServerPacket;
import l2p.gameserver.serverpackets.PartyMemberPosition;
import l2p.gameserver.serverpackets.PartySmallWindowAdd;
import l2p.gameserver.serverpackets.PartySmallWindowAll;
import l2p.gameserver.serverpackets.PartySmallWindowDelete;
import l2p.gameserver.serverpackets.PartySpelled;
import l2p.gameserver.serverpackets.RelationChanged;
import l2p.gameserver.serverpackets.SpawnEmitter;
import l2p.gameserver.serverpackets.SystemMessage;
import l2p.gameserver.skills.Stats;
import l2p.gameserver.tables.ItemTable;
import l2p.gameserver.tables.ReflectionTable;
import l2p.util.GArray;
import l2p.util.Location;
import l2p.util.Log;
import l2p.util.Rnd;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.HashMap;
import java.util.Vector;
import java.util.concurrent.ScheduledFuture;
public class L2Party
{
private final Vector<Long> members_list = new Vector<Long>(9);
private int _partyLvl = 0;
private int _itemDistribution = 0;
private int _itemOrder = 0;
private long _dr;
private long _reflection;
private L2CommandChannel _commandChannel;
public static final int ITEM_LOOTER = 0;
public static final int ITEM_RANDOM = 1;
public static final int ITEM_RANDOM_SPOIL = 2;
public static final int ITEM_ORDER = 3;
public static final int ITEM_ORDER_SPOIL = 4;
public static final int MAX_SIZE = 9;
public float _rateExp;
public float _rateSp;
public float _rateDrop;
public float _rateAdena;
public float _rateSpoil;
private final UpdatePositionTask posTask = new UpdatePositionTask(this);
private ScheduledFuture<?> posTaskThread;
/**
* constructor ensures party has always one member - leader
*
* @param leader создатель парти
* @param itemDistribution режим распределения лута
*/
public L2Party(L2Player leader, int itemDistribution)
{
_itemDistribution = itemDistribution;
members_list.add(leader.getStoredId());
_partyLvl = leader.getLevel();
posTaskThread = ThreadPoolManager.getInstance().scheduleGeneral(posTask, 11000);
// для надежности
_rateExp = leader.getBonus().RATE_XP;
_rateSp = leader.getBonus().RATE_SP;
_rateAdena = leader.getBonus().RATE_DROP_ADENA;
_rateDrop = leader.getBonus().RATE_DROP_ITEMS;
_rateSpoil = leader.getBonus().RATE_DROP_SPOIL;
}
/**
* @return number of party members
*/
public int getMemberCount()
{
return members_list.size();
}
public int getMemberCountInRange(L2Player player, int range)
{
int ret = 0;
L2Player member;
synchronized(members_list)
{
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null && (member == player || member.getReflectionId() == player.getReflectionId() && member.isInRange(player, range)))
{
ret++;
}
}
}
return ret;
}
/**
* @return all party members
*/
public GArray<L2Player> getPartyMembers()
{
synchronized(members_list)
{
GArray<L2Player> result = new GArray<L2Player>(members_list.size());
L2Player member;
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null)
{
result.add(member);
}
}
return result;
}
}
public GArray<Integer> getPartyMembersObjIds()
{
synchronized(members_list)
{
GArray<Integer> result = new GArray<Integer>(members_list.size());
for(Long storedId : members_list)
{
result.add(L2ObjectsStorage.getStoredObjectId(storedId));
}
return result;
}
}
public GArray<L2Playable> getPartyMembersWithPets()
{
synchronized(members_list)
{
GArray<L2Playable> result = new GArray<L2Playable>(members_list.size());
L2Player member;
L2Summon member_pet;
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null)
{
result.add(member);
if((member_pet = member.getPet()) != null)
{
result.add(member_pet);
}
}
}
return result;
}
}
public L2Player getRandomMember()
{
GArray<L2Player> members = getPartyMembers();
return members.get(Rnd.get(members.size()));
}
/**
* @return random member from party
*/
private L2Player getRandomMemberInRange(L2Player player, L2ItemInstance item, int range)
{
GArray<L2Player> ret = new GArray<L2Player>();
synchronized(members_list)
{
L2Player member;
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null)
{
if(member.getReflectionId() == player.getReflectionId() && member.isInRange(player, range) && !member.isDead() && member.getInventory().validateCapacity(item) && member.getInventory().validateWeight(item))
{
ret.add(member);
}
}
}
}
return ret.isEmpty() ? null : ret.get(Rnd.get(ret.size()));
}
/**
* @return next item looter
*/
private L2Player getNextLooterInRange(L2Player player, L2ItemInstance item, int range)
{
synchronized(members_list)
{
int antiloop = members_list.size();
while(--antiloop > 0)
{
int looter = _itemOrder;
_itemOrder++;
if(_itemOrder > members_list.size() - 1)
{
_itemOrder = 0;
}
L2Player ret = looter < members_list.size() ? L2ObjectsStorage.getAsPlayer(members_list.get(looter)) : player;
if(ret != null && ret.getReflectionId() == player.getReflectionId() && ret.isInRange(player, range) && !ret.isDead())
{
return ret;
}
}
return player;
}
}
/**
* true if player is party leader
*/
public boolean isLeader(L2Player player)
{
L2Player leader = getPartyLeader();
return leader != null && player.equals(leader);
}
/**
* Returns the Object ID for the party leader to be used as a unique identifier of this party
*/
public int getPartyLeaderOID()
{
synchronized(members_list)
{
if(members_list.isEmpty())
{
return 0;
}
return L2ObjectsStorage.getStoredObjectId(members_list.get(0));
}
}
/**
* Возвращает лидера партии
*
* @return L2Player Лидер партии
*/
public L2Player getPartyLeader()
{
if(members_list.isEmpty())
{
return null;
}
return L2ObjectsStorage.getAsPlayer(members_list.get(0));
}
/**
* Broadcasts packet to every party member
*
* @param msg packet to broadcast
*/
public void broadcastToPartyMembers(L2GameServerPacket... msg)
{
synchronized(members_list)
{
L2Player member;
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null)
{
member.sendPacket(msg);
}
}
}
}
/**
* Рассылает текстовое сообщение всем членам группы
*
* @param msg сообщение
*/
public void broadcastMessageToPartyMembers(String msg)
{
broadcastToPartyMembers(new SystemMessage(msg));
}
/**
* Рассылает пакет всем членам группы исключая указанного персонажа<BR><BR>
*/
public void broadcastToPartyMembers(L2Player exclude, L2GameServerPacket msg)
{
synchronized(members_list)
{
L2Player member;
for(Long storedId : members_list)
{
if(exclude.getStoredId() != storedId && (member = L2ObjectsStorage.getAsPlayer(storedId)) != null)
{
member.sendPacket(msg);
}
}
}
}
public void broadcastToPartyMembersInRange(L2Player player, L2GameServerPacket msg, int range)
{
synchronized(members_list)
{
L2Player member;
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null && member.getReflectionId() == player.getReflectionId() && player.isInRange(member, range))
{
member.sendPacket(msg);
}
}
}
}
public boolean containsMember(L2Character cha)
{
L2Player player = cha.getPlayer();
if(player == null)
{
return false;
}
synchronized(members_list)
{
int player_id = player.getObjectId();
for(Long storedId : members_list)
{
if(L2ObjectsStorage.getStoredObjectId(storedId) == player_id)
{
return true;
}
}
}
return false;
}
/**
* adds new member to party
*
* @param player L2Player to add
*/
public void addPartyMember(L2Player player)
{
L2Player leader = getPartyLeader();
if(leader == null)
{
return;
}
L2Player member;
L2Summon player_pet, member_pet;
Collection<L2GameServerPacket> pmember, pmember_proto = new GArray<L2GameServerPacket>(), pplayer = new GArray<L2GameServerPacket>();
synchronized(members_list)
{
members_list.add(player.getStoredId());
//sends new member party window for all members
//we do all actions before adding member to a list, this speeds things up a little
pplayer.add(new PartySmallWindowAll(this, player));
pplayer.add(new SystemMessage(SystemMessage.YOU_HAVE_JOINED_S1S_PARTY).addString(leader.getName()));
pmember_proto.add(new SystemMessage(SystemMessage.S1_HAS_JOINED_THE_PARTY).addString(player.getName()));
pmember_proto.add(new PartySmallWindowAdd(player));
pmember_proto.add(new PartySpelled(player, true));
if((player_pet = player.getPet()) != null)
{
pmember_proto.add(new ExPartyPetWindowAdd(player_pet));
pmember_proto.add(new PartySpelled(player_pet, true));
}
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null && member != player)
{
pmember = new GArray<L2GameServerPacket>();
pmember.addAll(pmember_proto);
pmember.addAll(RelationChanged.update(member, player, member));
member.sendPackets(pmember);
pplayer.add(new PartySpelled(member, true));
if((member_pet = member.getPet()) != null)
{
pplayer.add(new PartySpelled(member_pet, true));
}
pplayer.addAll(RelationChanged.update(player, member, player)); //FIXME
}
}
// Если партия уже в СС, то вновь прибывшем посылаем пакет открытия окна СС
if(isInCommandChannel())
{
pplayer.add(Msg.ExMPCCOpen);
}
}
player.sendPackets(pplayer);
recalculatePartyData();
if(isInReflection() && getReflection() instanceof DimensionalRift)
{
((DimensionalRift) getReflection()).partyMemberInvited();
}
if(player.getPartyRoom() > 0)
{
PartyRoom room = PartyRoomManager.getInstance().getRooms().get(player.getPartyRoom());
if(room != null)
{
room.updateInfo();
}
}
}
/**
* Удаляет все связи
*/
public void dissolveParty()
{
synchronized(members_list)
{
for(L2Player p : getPartyMembers())
{
p.setParty(null);
}
members_list.clear();
}
setDimensionalRift(null);
_commandChannel = null;
posTaskThread.cancel(false);
}
/**
* removes player from party
*
* @param player L2Player to remove
*/
private void removePartyMember(L2Player player)
{
synchronized(members_list)
{
members_list.remove(player.getStoredId());
posTask.remove(player);
}
recalculatePartyData();
Collection<L2GameServerPacket> pplayer = new GArray<L2GameServerPacket>();
// Отсылаемы вышедшему пакет закрытия СС
if(isInCommandChannel())
{
pplayer.add(Msg.ExMPCCClose);
}
pplayer.add(Msg.YOU_HAVE_WITHDRAWN_FROM_THE_PARTY);
pplayer.add(Msg.PartySmallWindowDeleteAll);
player.setParty(null);
L2Summon player_pet;
Collection<L2GameServerPacket> pmember_proto = new GArray<L2GameServerPacket>();
if((player_pet = player.getPet()) != null)
{
pmember_proto.add(new ExPartyPetWindowDelete(player_pet));
}
pmember_proto.add(new PartySmallWindowDelete(player));
pmember_proto.add(new SystemMessage(SystemMessage.S1_HAS_LEFT_THE_PARTY).addString(player.getName()));
synchronized(members_list)
{
L2Player member;
Collection<L2GameServerPacket> pmember;
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null)
{
pmember = new GArray<L2GameServerPacket>();
pmember.addAll(pmember_proto);
pmember.addAll(RelationChanged.update(member, player, member));
member.sendPackets(pmember);
pplayer.addAll(RelationChanged.update(player, member, player));
}
}
}
player.sendPackets(pplayer);
Reflection reflection = getReflection();
if(reflection instanceof DarknessFestival)
{
((DarknessFestival) reflection).partyMemberExited();
}
else if(isInReflection() && getReflection() instanceof DimensionalRift)
{
((DimensionalRift) getReflection()).partyMemberExited(player);
}
if(reflection != null && player.getReflection().getId() == reflection.getId() && reflection.getReturnLoc() != null)
{
player.teleToLocation(reflection.getReturnLoc(), 0);
}
if(player.getDuel() != null)
{
player.getDuel().onRemoveFromParty(player);
}
L2Player leader = getPartyLeader();
if(members_list.size() == 1 || leader == null)
{
if(leader != null && leader.getDuel() != null)
{
leader.getDuel().onRemoveFromParty(leader);
}
// Если в партии остался 1 человек, то удаляем ее из СС
if(isInCommandChannel())
{
_commandChannel.removeParty(this);
}
if(reflection != null)
{
setReflection(null);
}
if(leader != null)
{
leader.setParty(null);
}
dissolveParty();
}
else if(isInCommandChannel() && _commandChannel.getChannelLeader() == player)
{
_commandChannel.setChannelLeader(leader);
}
if(player.getPartyRoom() > 0)
{
PartyRoom room = PartyRoomManager.getInstance().getRooms().get(player.getPartyRoom());
if(room != null)
{
room.updateInfo();
}
}
}
/**
* Change party leader (used for string arguments)
*
* @param name имя нового лидера парти
*/
public void changePartyLeader(String name)
{
L2Player new_leader = getPlayerByName(name);
synchronized(members_list)
{
L2Player current_leader = getPartyLeader();
if(new_leader == null || current_leader == null)
{
return;
}
if(current_leader.equals(new_leader))
{
current_leader.sendPacket(Msg.YOU_CANNOT_TRANSFER_RIGHTS_TO_YOURSELF);
return;
}
if(!members_list.contains(new_leader.getStoredId()))
{
current_leader.sendPacket(Msg.YOU_CAN_TRANSFER_RIGHTS_ONLY_TO_ANOTHER_PARTY_MEMBER);
return;
}
// Меняем местами нового и текущего лидера
int idx = members_list.indexOf(new_leader.getStoredId());
members_list.set(0, new_leader.getStoredId());
members_list.set(idx, current_leader.getStoredId());
updateLeaderInfo();
if(isInCommandChannel() && _commandChannel.getChannelLeader() == current_leader)
{
_commandChannel.setChannelLeader(new_leader);
}
}
}
public void updateLeaderInfo()
{
synchronized(members_list)
{
L2Player member = getPartyLeader();
if(member == null)
{
return;
}
SystemMessage msg = new SystemMessage(SystemMessage.S1_HAS_BECOME_A_PARTY_LEADER).addString(member.getName());
for(Long storedId : members_list)
// индивидуальные пакеты - удаления и инициализация пати
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null)
{
member.sendPacket(Msg.PartySmallWindowDeleteAll, // Удаляем все окошки
new PartySmallWindowAll(this, member), // Показываем окошки
msg);
}
} // Сообщаем о смене лидера
for(Long storedId : members_list)
// броадкасты состояний
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null)
{
broadcastToPartyMembers(member, new PartySpelled(member, true)); // Показываем иконки
if(member.getPet() != null)
{
broadcastToPartyMembers(new ExPartyPetWindowAdd(member.getPet()));
} // Показываем окошки петов
// broadcastToPartyMembers(member, new PartyMemberPosition(member)); // Обновляем позицию на карте
}
}
posTask.lastpositions.clear();
}
}
/**
* finds a player in the party by name
*
* @param name имя для поиска
* @return найденый L2Player или null если не найдено
*/
public L2Player getPlayerByName(String name)
{
synchronized(members_list)
{
L2Player member;
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null && name.equalsIgnoreCase(member.getName()))
{
return member;
}
}
}
return null;
}
/**
* Oust player from party
*
* @param player L2Player которого выгоняют
*/
public void oustPartyMember(L2Player player)
{
synchronized(members_list)
{
if(player == null || !members_list.contains(player.getStoredId()))
{
return;
}
}
boolean leader = isLeader(player);
removePartyMember(player);
if(leader && members_list.size() > 1)
{
updateLeaderInfo();
}
}
/**
* Oust player from party Overloaded method that takes player's name as
* parameter
*
* @param name имя игрока для изгнания
*/
public void oustPartyMember(String name)
{
oustPartyMember(getPlayerByName(name));
}
/**
* distribute item(s) to party members
*
* @param player
* @param item
*/
public void distributeItem(L2Player player, L2ItemInstance item)
{
distributeItem(player, item, null);
}
public void distributeItem(L2Player player, L2ItemInstance item, L2NpcInstance fromNpc)
{
L2Player target;
switch(_itemDistribution)
{
case ITEM_RANDOM:
case ITEM_RANDOM_SPOIL:
target = getRandomMemberInRange(player, item, Config.ALT_PARTY_DISTRIBUTION_RANGE);
break;
case ITEM_ORDER:
case ITEM_ORDER_SPOIL:
target = getNextLooterInRange(player, item, Config.ALT_PARTY_DISTRIBUTION_RANGE);
break;
case ITEM_LOOTER:
default:
target = player;
break;
}
if(target == null)
{
item.dropToTheGround(player, fromNpc);
return;
}
if(!target.getInventory().validateWeight(item))
{
target.sendPacket(Msg.ActionFail, Msg.YOU_HAVE_EXCEEDED_THE_WEIGHT_LIMIT);
item.dropToTheGround(target, fromNpc);
return;
}
if(!target.getInventory().validateCapacity(item))
{
target.sendPacket(Msg.ActionFail, Msg.YOUR_INVENTORY_IS_FULL);
item.dropToTheGround(player, fromNpc);
return;
}
if(!item.pickupMe(target))
{
return;
}
target.sendPacket(SystemMessage.obtainItems(item));
broadcastToPartyMembers(target, SystemMessage.obtainItemsBy(item, target.getName()));
L2ItemInstance item2 = target.getInventory().addItem(item);
Log.LogItem(target, fromNpc, Log.GetItemInPaty, item2);
target.sendChanges();
}
/**
* distribute adena to party members
*
* @param adena инстанс адены для распределения
*/
public void distributeAdena(L2ItemInstance adena, L2Player player)
{
distributeAdena(adena, null, player);
}
public void distributeAdena(L2ItemInstance adena, L2NpcInstance fromNpc, L2Player player)
{
if(player == null)
{
return;
}
GArray<L2Player> membersInRange = new GArray<L2Player>();
synchronized(members_list)
{
if(adena.getCount() < members_list.size())
{
membersInRange.add(player);
}
else
{
L2Player member;
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null)
{
if(member.equals(player) || player.isInRange(member, Config.ALT_PARTY_DISTRIBUTION_RANGE) && !member.isDead())
{
membersInRange.add(member);
}
}
}
}
}
if(membersInRange.isEmpty())
{
membersInRange.add(player);
}
long totalAdena = adena.getCount();
long amount = totalAdena / membersInRange.size();
long ost = totalAdena % membersInRange.size();
for(L2Player member : membersInRange)
{
L2ItemInstance newAdena = ItemTable.getInstance().createItem(57);
newAdena.setCount(member.equals(player) ? amount + ost : amount);
member.sendPacket(SystemMessage.obtainItems(newAdena));
L2ItemInstance item2 = member.getInventory().addItem(newAdena);
if(fromNpc == null)
{
Log.LogItem(member, Log.GetItemInPaty, item2);
}
else
{
Log.LogItem(member, fromNpc, Log.GetItemInPaty, item2);
}
}
}
public void distributeXpAndSp(double xpReward, double spReward, GArray<L2Player> rewardedMembers, L2Character lastAttacker, L2MonsterInstance monster)
{
recalculatePartyData();
GArray<L2Player> mtr = new GArray<L2Player>();
int minPartyLevel = lastAttacker.getLevel();
int maxPartyLevel = lastAttacker.getLevel();
double partyLvlSum = 0;
// считаем минимальный/максимальный уровень
for(L2Player member : rewardedMembers)
{
if(!lastAttacker.isInRange(member, Config.ALT_PARTY_DISTRIBUTION_RANGE))
{
continue;
}
minPartyLevel = Math.min(minPartyLevel, member.getLevel());
maxPartyLevel = Math.max(maxPartyLevel, member.getLevel());
}
// составляем список игроков, удовлетворяющих требованиям
for(L2Player member : rewardedMembers)
{
if(!lastAttacker.isInRange(member, Config.ALT_PARTY_DISTRIBUTION_RANGE))
{
continue;
}
if(member.getLevel() < maxPartyLevel - 20)
{
continue;
}
partyLvlSum += member.getLevel();
mtr.add(member);
}
if(mtr.isEmpty())
{
return;
}
// бонус за пати
double bonus = Config.ALT_PARTY_BONUS[mtr.size() - 1];
// количество эксп и сп для раздачи на всех
double XP = xpReward * bonus;
double SP = spReward * bonus;
for(L2Player member : mtr)
{
double lvlPenalty = Experience.penaltyModifier(monster.calculateLevelDiffForDrop(member.getLevel()), 9);
// отдаем его часть с учетом пенальти
double memberXp = XP * lvlPenalty * member.getLevel() / partyLvlSum;
double memberSp = SP * lvlPenalty * member.getLevel() / partyLvlSum;
// больше чем соло не дадут
memberXp = Math.min(memberXp, xpReward);
memberSp = Math.min(memberSp, spReward);
// Начисление душ камаэлянам
double neededExp = member.calcStat(Stats.SOULS_CONSUME_EXP, 0, monster, null);
if(neededExp > 0 && memberXp > neededExp)
{
monster.broadcastPacket(new SpawnEmitter(monster, member));
ThreadPoolManager.getInstance().scheduleGeneral(new SoulConsumeTask(member), 1000);
}
double[] xpsp = member.applyVitality(monster, memberXp, memberSp, memberXp / xpReward);
member.addExpAndSp((long) xpsp[0], (long) xpsp[1], false, true);
}
recalculatePartyData();
}
public void recalculatePartyData()
{
_partyLvl = 0;
float rateExp = 0;
float rateSp = 0;
float rateDrop = 0;
float rateAdena = 0;
float rateSpoil = 0;
float minRateExp = Float.MAX_VALUE;
float minRateSp = Float.MAX_VALUE;
float minRateDrop = Float.MAX_VALUE;
float minRateAdena = Float.MAX_VALUE;
float minRateSpoil = Float.MAX_VALUE;
byte count = 0;
L2Player member;
synchronized(members_list)
{
for(Long storedId : members_list)
{
if((member = L2ObjectsStorage.getAsPlayer(storedId)) != null)
{
int level = member.getLevel();
_partyLvl = Math.max(_partyLvl, level);
count++;
rateExp += member.getBonus().RATE_XP;
rateSp += member.getBonus().RATE_SP;
rateDrop += member.getBonus().RATE_DROP_ITEMS;
rateAdena += member.getBonus().RATE_DROP_ADENA;
rateSpoil += member.getBonus().RATE_DROP_SPOIL;
minRateExp = Math.min(minRateExp, member.getBonus().RATE_XP);
minRateSp = Math.min(minRateSp, member.getBonus().RATE_SP);
minRateDrop = Math.min(minRateDrop, member.getBonus().RATE_DROP_ITEMS);
minRateAdena = Math.min(minRateAdena, member.getBonus().RATE_DROP_ADENA);
minRateSpoil = Math.min(minRateSpoil, member.getBonus().RATE_DROP_SPOIL);
}
}
}
_rateExp = Config.RATE_PARTY_MIN ? minRateExp : rateExp / count;
_rateSp = Config.RATE_PARTY_MIN ? minRateSp : rateSp / count;
_rateDrop = Config.RATE_PARTY_MIN ? minRateDrop : rateDrop / count;
_rateAdena = Config.RATE_PARTY_MIN ? minRateAdena : rateAdena / count;
_rateSpoil = Config.RATE_PARTY_MIN ? minRateSpoil : rateSpoil / count;
}
public int getLevel()
{
return _partyLvl;
}
public int getLootDistribution()
{
return _itemDistribution;
}
public boolean isDistributeSpoilLoot()
{
boolean rv = false;
if(_itemDistribution == ITEM_RANDOM_SPOIL || _itemDistribution == ITEM_ORDER_SPOIL)
{
rv = true;
}
return rv;
}
public boolean isInDimensionalRift()
{
return _dr > 0 && getDimensionalRift() != null;
}
public void setDimensionalRift(DimensionalRift dr)
{
_dr = dr == null ? 0 : dr.getId();
}
public DimensionalRift getDimensionalRift()
{
return _dr == 0 ? null : (DimensionalRift) ReflectionTable.getInstance().get(_dr);
}
public boolean isInReflection()
{
if(_reflection > 0)
{
return true;
}
if(_commandChannel != null)
{
return _commandChannel.isInReflection();
}
return false;
}
public void setReflection(Reflection reflection)
{
_reflection = reflection == null ? 0 : reflection.getId();
}
public Reflection getReflection()
{
if(_reflection > 0)
{
return ReflectionTable.getInstance().get(_reflection);
}
if(_commandChannel != null)
{
return _commandChannel.getReflection();
}
return null;
}
public boolean isInCommandChannel()
{
return _commandChannel != null;
}
public L2CommandChannel getCommandChannel()
{
return _commandChannel;
}
public void setCommandChannel(L2CommandChannel channel)
{
_commandChannel = channel;
}
/**
* Телепорт всей пати в одну точку (x,y,z)
*/
public void Teleport(int x, int y, int z)
{
TeleportParty(getPartyMembers(), new Location(x, y, z));
}
/**
* Телепорт всей пати в одну точку dest
*/
public void Teleport(Location dest)
{
TeleportParty(getPartyMembers(), dest);
}
/**
* Телепорт всей пати на территорию, игроки расставляются рандомно по территории
*/
public void Teleport(L2Territory territory)
{
RandomTeleportParty(getPartyMembers(), territory);
}
/**
* Телепорт всей пати на территорию, лидер попадает в точку dest, а все остальные относительно лидера
*/
public void Teleport(L2Territory territory, Location dest)
{
TeleportParty(getPartyMembers(), territory, dest);
}
public static void TeleportParty(GArray<L2Player> members, Location dest)
{
for(L2Player _member : members)
{
if(_member == null)
{
continue;
}
_member.teleToLocation(dest);
}
}
public static void TeleportParty(GArray<L2Player> members, L2Territory territory, Location dest)
{
if(!territory.isInside(dest.x, dest.y))
{
Log.add("TeleportParty: dest is out of territory", "errors");
return;
}
int base_x = members.get(0).getX();
int base_y = members.get(0).getY();
for(L2Player _member : members)
{
if(_member == null)
{
continue;
}
int diff_x = _member.getX() - base_x;
int diff_y = _member.getY() - base_y;
Location loc = new Location(dest.x + diff_x, dest.y + diff_y, dest.z);
while(!territory.isInside(loc.x, loc.y))
{
diff_x = loc.x - dest.x;
diff_y = loc.y - dest.y;
if(diff_x != 0)
{
loc.x -= diff_x / Math.abs(diff_x);
}
if(diff_y != 0)
{
loc.y -= diff_y / Math.abs(diff_y);
}
}
_member.teleToLocation(loc);
}
}
public static void RandomTeleportParty(GArray<L2Player> members, L2Territory territory)
{
for(L2Player _member : members)
{
int[] _loc = territory.getRandomPoint();
if(_member == null || _loc == null)
{
continue;
}
_member.teleToLocation(_loc[0], _loc[1], _loc[2]);
}
}
private class UpdatePositionTask implements Runnable
{
private final WeakReference<L2Party> party_ref;
private final HashMap<Integer, int[]> lastpositions = new HashMap<Integer, int[]>();
public UpdatePositionTask(L2Party party)
{
party_ref = new WeakReference<L2Party>(party);
}
public void remove(L2Player player)
{
synchronized(lastpositions)
{
lastpositions.remove(new Integer(player.getObjectId()));
}
}
public void run()
{
L2Party party = party_ref.get();
if(party == null || party.getMemberCount() < 2)
{
synchronized(lastpositions)
{
lastpositions.clear();
}
party_ref.clear();
dissolveParty();
return;
}
try
{
GArray<L2Player> full_updated = new GArray<L2Player>();
GArray<L2Player> members = party.getPartyMembers();
PartyMemberPosition just_updated = new PartyMemberPosition();
int[] lastpos;
for(L2Player member : members)
{
if(member == null)
{
continue;
}
synchronized(lastpositions)
{
lastpos = lastpositions.get(new Integer(member.getObjectId()));
if(lastpos == null)
{
just_updated.add(member);
full_updated.add(member);
lastpositions.put(member.getObjectId(), new int[]
{
member.getX(), member.getY(), member.getZ()
});
}
else if(member.getDistance(lastpos[0], lastpos[1], lastpos[2]) > 256) //TODO подкорректировать
{
just_updated.add(member);
lastpos[0] = member.getX();
lastpos[1] = member.getY();
lastpos[2] = member.getZ();
}
}
}
// посылаем изменения позиций старым членам пати
if(just_updated.size() > 0)
{
for(L2Player member : members)
{
if(!full_updated.contains(member))
{
member.sendPacket(just_updated);
}
}
}
// посылаем полный список позиций новым членам пати
if(full_updated.size() > 0)
{
just_updated = new PartyMemberPosition().add(members);
for(L2Player member : full_updated)
{
member.sendPacket(just_updated);
}
full_updated.clear();
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
posTaskThread = ThreadPoolManager.getInstance().scheduleGeneral(this, 1000);
}
}
}
}