/*
* 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 lineage2.gameserver.model.entity.olympiad;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;
import lineage2.commons.lang.ArrayUtils;
import lineage2.commons.util.Rnd;
import lineage2.gameserver.Config;
import lineage2.gameserver.cache.Msg;
import lineage2.gameserver.data.xml.holder.InstantZoneHolder;
import lineage2.gameserver.instancemanager.OlympiadHistoryManager;
import lineage2.gameserver.model.Party;
import lineage2.gameserver.model.Player;
import lineage2.gameserver.model.entity.Reflection;
import lineage2.gameserver.model.instances.DoorInstance;
import lineage2.gameserver.model.instances.NpcInstance;
import lineage2.gameserver.model.items.ItemInstance;
import lineage2.gameserver.model.quest.QuestState;
import lineage2.gameserver.network.serverpackets.ExOlympiadUserInfo;
import lineage2.gameserver.network.serverpackets.ExReceiveOlympiad;
import lineage2.gameserver.network.serverpackets.L2GameServerPacket;
import lineage2.gameserver.network.serverpackets.SystemMessage2;
import lineage2.gameserver.network.serverpackets.components.IStaticPacket;
import lineage2.gameserver.network.serverpackets.components.NpcString;
import lineage2.gameserver.network.serverpackets.components.SystemMsg;
import lineage2.gameserver.scripts.Functions;
import lineage2.gameserver.templates.InstantZone;
import lineage2.gameserver.templates.StatsSet;
import lineage2.gameserver.utils.Log;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Mobius
* @version $Revision: 1.0 $
*/
public class OlympiadGame
{
/**
* Field _log.
*/
private static final Logger _log = LoggerFactory.getLogger(OlympiadGame.class);
/**
* Field MAX_POINTS_LOOSE. (value is 10)
*/
public static final int MAX_POINTS_LOOSE = 10;
/**
* Field validated.
*/
public boolean validated = false;
/**
* Field _winner.
*/
private int _winner = 0;
/**
* Field _state.
*/
private int _state = 0;
/**
* Field _id.
*/
private final int _id;
/**
* Field _reflection.
*/
private final Reflection _reflection;
/**
* Field _type.
*/
private final CompType _type;
/**
* Field _team1.
*/
private final OlympiadTeam _team1;
/**
* Field _team2.
*/
private final OlympiadTeam _team2;
/**
* Field _spectators.
*/
private final List<Player> _spectators = new CopyOnWriteArrayList<>();
/**
* Field _startTime.
*/
private long _startTime;
/**
* Constructor for OlympiadGame.
* @param id int
* @param type CompType
* @param opponents List<Integer>
*/
public OlympiadGame(int id, CompType type, List<Integer> opponents)
{
_type = type;
_id = id;
_reflection = new Reflection();
InstantZone instantZone = InstantZoneHolder.getInstance().getInstantZone(Rnd.get(147, 150));
_reflection.init(instantZone);
_team1 = new OlympiadTeam(this, 1);
_team2 = new OlympiadTeam(this, 2);
for (int i = 0; i < (opponents.size() / 2); i++)
{
_team1.addMember(opponents.get(i));
}
for (int i = opponents.size() / 2; i < opponents.size(); i++)
{
_team2.addMember(opponents.get(i));
}
Log.add("Olympiad System: Game - " + id + ": " + _team1.getName() + " Vs " + _team2.getName(), "olympiad");
}
/**
* Method getBufferSpawnGroup.
* @param instancedZoneId int
* @return String
*/
private String getBufferSpawnGroup(int instancedZoneId)
{
String bufferGroup = null;
switch (instancedZoneId)
{
case 147:
bufferGroup = "olympiad_147_buffers";
break;
case 148:
bufferGroup = "olympiad_148_buffers";
break;
case 149:
bufferGroup = "olympiad_149_buffers";
break;
case 150:
bufferGroup = "olympiad_150_buffers";
break;
}
return bufferGroup;
}
/**
* Method addBuffers.
*/
public void addBuffers()
{
if (!_type.hasBuffer())
{
return;
}
if (getBufferSpawnGroup(_reflection.getInstancedZoneId()) != null)
{
_reflection.spawnByGroup(getBufferSpawnGroup(_reflection.getInstancedZoneId()));
}
}
/**
* Method deleteBuffers.
*/
public void deleteBuffers()
{
_reflection.despawnByGroup(getBufferSpawnGroup(_reflection.getInstancedZoneId()));
}
/**
* Method managerShout.
*/
public void managerShout()
{
for (NpcInstance npc : Olympiad.getNpcs())
{
NpcString npcString;
switch (_type)
{
case CLASSED:
npcString = NpcString.OLYMPIAD_CLASS_INDIVIDUAL_MATCH_IS_GOING_TO_BEGIN_IN_ARENA_S1_IN_A_MOMENT;
break;
case NON_CLASSED:
npcString = NpcString.OLYMPIAD_CLASSFREE_INDIVIDUAL_MATCH_IS_GOING_TO_BEGIN_IN_ARENA_S1_IN_A_MOMENT;
break;
default:
continue;
}
Functions.npcShout(npc, npcString, String.valueOf(_id + 1));
}
}
/**
* Method portPlayersToArena.
*/
public void portPlayersToArena()
{
_team1.portPlayersToArena();
_team2.portPlayersToArena();
}
/**
* Method preparePlayers.
*/
public void preparePlayers()
{
_team1.preparePlayers();
_team2.preparePlayers();
}
/**
* Method portPlayersBack.
*/
public void portPlayersBack()
{
_team1.portPlayersBack();
_team2.portPlayersBack();
}
/**
* Method collapse.
*/
public void collapse()
{
portPlayersBack();
clearSpectators();
_reflection.collapse();
}
/**
* Method validateWinner.
* @param aborted boolean
*/
public void validateWinner(boolean aborted)
{
int state = _state;
_state = 0;
if (validated)
{
Log.add("Olympiad Result: " + _team1.getName() + " vs " + _team2.getName() + " ... double validate check!!!", "olympiad");
return;
}
validated = true;
if ((state < 1) && aborted)
{
_team1.takePointsForCrash();
_team2.takePointsForCrash();
broadcastPacket(Msg.THE_GAME_HAS_BEEN_CANCELLED_BECAUSE_THE_OTHER_PARTY_ENDS_THE_GAME, true, false);
return;
}
boolean teamOneCheck = _team1.checkPlayers();
boolean teamTwoCheck = _team2.checkPlayers();
if (_winner <= 0)
{
if (!teamOneCheck && !teamTwoCheck)
{
_winner = 0;
}
else if (!teamTwoCheck)
{
_winner = 1;
}
else if (!teamOneCheck)
{
_winner = 2;
}
else if (_team1.getDamage() < _team2.getDamage())
{
_winner = 1;
}
else if (_team1.getDamage() > _team2.getDamage())
{
_winner = 2;
}
}
if (_winner == 1)
{
winGame(_team1, _team2);
}
else if (_winner == 2)
{
winGame(_team2, _team1);
}
else
{
tie();
}
_team1.saveNobleData();
_team2.saveNobleData();
broadcastRelation();
broadcastPacket(new SystemMessage2(SystemMsg.YOU_WILL_BE_MOVED_BACK_TO_TOWN_IN_S1_SECONDS).addInteger(20), true, true);
}
/**
* Method winGame.
* @param winnerTeam OlympiadTeam
* @param looseTeam OlympiadTeam
*/
public void winGame(OlympiadTeam winnerTeam, OlympiadTeam looseTeam)
{
ExReceiveOlympiad.MatchResult packet = new ExReceiveOlympiad.MatchResult(false, winnerTeam.getName());
int pointDiff = 0;
TeamMember[] looserMembers = looseTeam.getMembers().toArray(new TeamMember[looseTeam.getMembers().size()]);
TeamMember[] winnerMembers = winnerTeam.getMembers().toArray(new TeamMember[winnerTeam.getMembers().size()]);
for (int i = 0; i < Party.MAX_SIZE; i++)
{
TeamMember looserMember = ArrayUtils.valid(looserMembers, i);
TeamMember winnerMember = ArrayUtils.valid(winnerMembers, i);
if ((looserMember != null) && (winnerMember != null))
{
winnerMember.incGameCount();
looserMember.incGameCount();
int gamePoints = transferPoints(looserMember.getStat(), winnerMember.getStat());
packet.addPlayer(winnerTeam == _team1 ? 0 : 1, winnerMember, gamePoints);
packet.addPlayer(looseTeam == _team1 ? 0 : 1, looserMember, -gamePoints);
pointDiff += gamePoints;
}
}
if (_type != CompType.TEAM)
{
int team = _team1 == winnerTeam ? 1 : 2;
TeamMember member1 = ArrayUtils.valid(_team1 == winnerTeam ? winnerMembers : looserMembers, 0);
TeamMember member2 = ArrayUtils.valid(_team2 == winnerTeam ? winnerMembers : looserMembers, 0);
if ((member1 != null) && (member2 != null))
{
int diff = (int) ((System.currentTimeMillis() - _startTime) / 1000L);
OlympiadHistory h = new OlympiadHistory(member1.getObjectId(), member1.getObjectId(), member1.getClassId(), member2.getClassId(), member1.getName(), member2.getName(), _startTime, diff, team, _type.ordinal());
OlympiadHistoryManager.getInstance().saveHistory(h);
}
}
for (Player player : winnerTeam.getPlayers())
{
ItemInstance item = player.getInventory().addItem(Config.ALT_OLY_BATTLE_REWARD_ITEM, getType().getReward());
player.sendPacket(SystemMessage2.obtainItems(item.getItemId(), getType().getReward(), 0));
player.sendChanges();
}
List<Player> teamsPlayers = new ArrayList<>();
teamsPlayers.addAll(winnerTeam.getPlayers());
teamsPlayers.addAll(looseTeam.getPlayers());
for (Player player : teamsPlayers)
{
if (player != null)
{
for (QuestState qs : player.getAllQuestsStates())
{
if (qs.isStarted())
{
qs.getQuest().onOlympiadEnd(this, qs);
}
}
}
}
broadcastPacket(packet, true, false);
broadcastPacket(new SystemMessage2(SystemMsg.CONGRATULATIONS_C1_YOU_WIN_THE_MATCH).addString(winnerTeam.getName()), false, true);
Log.add("Olympiad Result: " + winnerTeam.getName() + " vs " + looseTeam.getName() + " ... (" + (int) winnerTeam.getDamage() + " vs " + (int) looseTeam.getDamage() + ") " + winnerTeam.getName() + " win " + pointDiff + " points", "olympiad");
}
/**
* Method tie.
*/
public void tie()
{
TeamMember[] teamMembers1 = _team1.getMembers().toArray(new TeamMember[_team1.getMembers().size()]);
TeamMember[] teamMembers2 = _team2.getMembers().toArray(new TeamMember[_team2.getMembers().size()]);
ExReceiveOlympiad.MatchResult packet = new ExReceiveOlympiad.MatchResult(true, StringUtils.EMPTY);
for (int i = 0; i < teamMembers1.length; i++)
{
try
{
TeamMember member1 = ArrayUtils.valid(teamMembers1, i);
TeamMember member2 = ArrayUtils.valid(teamMembers2, i);
if (member1 != null)
{
member1.incGameCount();
StatsSet stat1 = member1.getStat();
packet.addPlayer(0, member1, -2);
stat1.set(Olympiad.POINTS, stat1.getInteger(Olympiad.POINTS) - 2);
}
if (member2 != null)
{
member2.incGameCount();
StatsSet stat2 = member2.getStat();
packet.addPlayer(1, member2, -2);
stat2.set(Olympiad.POINTS, stat2.getInteger(Olympiad.POINTS) - 2);
}
}
catch (Exception e)
{
_log.error("OlympiadGame.tie(): " + e, e);
}
}
if (_type != CompType.TEAM)
{
TeamMember member1 = ArrayUtils.valid(teamMembers1, 0);
TeamMember member2 = ArrayUtils.valid(teamMembers2, 0);
if ((member1 != null) && (member2 != null))
{
int diff = (int) ((System.currentTimeMillis() - _startTime) / 1000L);
OlympiadHistory h = new OlympiadHistory(member1.getObjectId(), member1.getObjectId(), member1.getClassId(), member2.getClassId(), member1.getName(), member2.getName(), _startTime, diff, 0, _type.ordinal());
OlympiadHistoryManager.getInstance().saveHistory(h);
}
}
broadcastPacket(SystemMsg.THERE_IS_NO_VICTOR_THE_MATCH_ENDS_IN_A_TIE, false, true);
broadcastPacket(packet, true, false);
Log.add("Olympiad Result: " + _team1.getName() + " vs " + _team2.getName() + " ... tie", "olympiad");
}
/**
* Method transferPoints.
* @param from StatsSet
* @param to StatsSet
* @return int
*/
private int transferPoints(StatsSet from, StatsSet to)
{
int fromPoints = from.getInteger(Olympiad.POINTS);
int fromLoose = from.getInteger(Olympiad.COMP_LOOSE);
int fromPlayed = from.getInteger(Olympiad.COMP_DONE);
int toPoints = to.getInteger(Olympiad.POINTS);
int toWin = to.getInteger(Olympiad.COMP_WIN);
int toPlayed = to.getInteger(Olympiad.COMP_DONE);
int pointDiff = Math.max(1, Math.min(fromPoints, toPoints) / getType().getLooseMult());
pointDiff = pointDiff > OlympiadGame.MAX_POINTS_LOOSE ? OlympiadGame.MAX_POINTS_LOOSE : pointDiff;
from.set(Olympiad.POINTS, fromPoints - pointDiff);
from.set(Olympiad.COMP_LOOSE, fromLoose + 1);
from.set(Olympiad.COMP_DONE, fromPlayed + 1);
to.set(Olympiad.POINTS, toPoints + pointDiff);
to.set(Olympiad.COMP_WIN, toWin + 1);
to.set(Olympiad.COMP_DONE, toPlayed + 1);
return pointDiff;
}
/**
* Method openDoors.
*/
public void openDoors()
{
for (DoorInstance door : _reflection.getDoors())
{
door.openMe();
}
}
/**
* Method getId.
* @return int
*/
public int getId()
{
return _id;
}
/**
* Method getReflection.
* @return Reflection
*/
public Reflection getReflection()
{
return _reflection;
}
/**
* Method isRegistered.
* @param objId int
* @return boolean
*/
public boolean isRegistered(int objId)
{
return _team1.contains(objId) || _team2.contains(objId);
}
/**
* Method getSpectators.
* @return List<Player>
*/
public List<Player> getSpectators()
{
return _spectators;
}
/**
* Method addSpectator.
* @param spec Player
*/
public void addSpectator(Player spec)
{
_spectators.add(spec);
}
/**
* Method removeSpectator.
* @param spec Player
*/
public void removeSpectator(Player spec)
{
_spectators.remove(spec);
}
/**
* Method clearSpectators.
*/
public void clearSpectators()
{
for (Player pc : _spectators)
{
if ((pc != null) && pc.isInObserverMode())
{
pc.leaveOlympiadObserverMode(false);
}
}
_spectators.clear();
}
/**
* Method broadcastInfo.
* @param sender Player
* @param receiver Player
* @param onlyToSpectators boolean
*/
public void broadcastInfo(Player sender, Player receiver, boolean onlyToSpectators)
{
if (sender != null)
{
if (receiver != null)
{
receiver.sendPacket(new ExOlympiadUserInfo(sender, sender.getOlympiadSide()));
}
else
{
broadcastPacket(new ExOlympiadUserInfo(sender, sender.getOlympiadSide()), !onlyToSpectators, true);
}
}
else
{
for (Player player : _team1.getPlayers())
{
if (receiver != null)
{
receiver.sendPacket(new ExOlympiadUserInfo(player, player.getOlympiadSide()));
}
else
{
broadcastPacket(new ExOlympiadUserInfo(player, player.getOlympiadSide()), !onlyToSpectators, true);
player.broadcastRelationChanged();
}
}
for (Player player : _team2.getPlayers())
{
if (receiver != null)
{
receiver.sendPacket(new ExOlympiadUserInfo(player, player.getOlympiadSide()));
}
else
{
broadcastPacket(new ExOlympiadUserInfo(player, player.getOlympiadSide()), !onlyToSpectators, true);
player.broadcastRelationChanged();
}
}
}
}
/**
* Method broadcastRelation.
*/
public void broadcastRelation()
{
for (Player player : _team1.getPlayers())
{
player.broadcastRelationChanged();
}
for (Player player : _team2.getPlayers())
{
player.broadcastRelationChanged();
}
}
/**
* Method broadcastPacket.
* @param packet L2GameServerPacket
* @param toTeams boolean
* @param toSpectators boolean
*/
public void broadcastPacket(L2GameServerPacket packet, boolean toTeams, boolean toSpectators)
{
if (toTeams)
{
_team1.broadcast(packet);
_team2.broadcast(packet);
}
if (toSpectators && !_spectators.isEmpty())
{
for (Player spec : _spectators)
{
if (spec != null)
{
spec.sendPacket(packet);
}
}
}
}
/**
* Method broadcastPacket.
* @param packet IStaticPacket
* @param toTeams boolean
* @param toSpectators boolean
*/
public void broadcastPacket(IStaticPacket packet, boolean toTeams, boolean toSpectators)
{
if (toTeams)
{
_team1.broadcast(packet);
_team2.broadcast(packet);
}
if (toSpectators && !_spectators.isEmpty())
{
for (Player spec : _spectators)
{
if (spec != null)
{
spec.sendPacket(packet);
}
}
}
}
/**
* Method getAllPlayers.
* @return List<Player>
*/
public List<Player> getAllPlayers()
{
List<Player> result = new ArrayList<>();
for (Player player : _team1.getPlayers())
{
result.add(player);
}
for (Player player : _team2.getPlayers())
{
result.add(player);
}
if (!_spectators.isEmpty())
{
for (Player spec : _spectators)
{
if (spec != null)
{
result.add(spec);
}
}
}
return result;
}
/**
* Method setWinner.
* @param val int
*/
public void setWinner(int val)
{
_winner = val;
}
/**
* Method getWinnerTeam.
* @return OlympiadTeam
*/
public OlympiadTeam getWinnerTeam()
{
if (_winner == 1)
{
return _team1;
}
else if (_winner == 2)
{
return _team2;
}
return null;
}
/**
* Method setState.
* @param val int
*/
public void setState(int val)
{
_state = val;
if (_state == 1)
{
_startTime = System.currentTimeMillis();
}
}
/**
* Method getState.
* @return int
*/
public int getState()
{
return _state;
}
/**
* Method getTeamMembers.
* @param player Player
* @return List<Player>
*/
public List<Player> getTeamMembers(Player player)
{
return player.getOlympiadSide() == 1 ? _team1.getPlayers() : _team2.getPlayers();
}
/**
* Method addDamage.
* @param player Player
* @param damage double
*/
public void addDamage(Player player, double damage)
{
if (player.getOlympiadSide() == 1)
{
_team1.addDamage(player, damage);
}
else
{
_team2.addDamage(player, damage);
}
}
/**
* Method doDie.
* @param player Player
* @return boolean
*/
public boolean doDie(Player player)
{
return player.getOlympiadSide() == 1 ? _team1.doDie(player) : _team2.doDie(player);
}
/**
* Method checkPlayersOnline.
* @return boolean
*/
public boolean checkPlayersOnline()
{
return _team1.checkPlayers() && _team2.checkPlayers();
}
/**
* Method logoutPlayer.
* @param player Player
* @return boolean
*/
public boolean logoutPlayer(Player player)
{
return (player != null) && (player.getOlympiadSide() == 1 ? _team1.logout(player) : _team2.logout(player));
}
/**
* Field _task.
*/
OlympiadGameTask _task;
/**
* Field _shedule.
*/
ScheduledFuture<?> _shedule;
/**
* Method sheduleTask.
* @param task OlympiadGameTask
*/
public synchronized void sheduleTask(OlympiadGameTask task)
{
if (_shedule != null)
{
_shedule.cancel(false);
}
_task = task;
_shedule = task.shedule();
}
/**
* Method getTask.
* @return OlympiadGameTask
*/
public OlympiadGameTask getTask()
{
return _task;
}
/**
* Method getStatus.
* @return BattleStatus
*/
public BattleStatus getStatus()
{
if (_task != null)
{
return _task.getStatus();
}
return BattleStatus.Begining;
}
/**
* Method endGame.
* @param time long
* @param aborted boolean
*/
public void endGame(long time, boolean aborted)
{
try
{
validateWinner(aborted);
}
catch (Exception e)
{
_log.error("", e);
}
sheduleTask(new OlympiadGameTask(this, BattleStatus.Ending, 0, time));
}
/**
* Method getType.
* @return CompType
*/
public CompType getType()
{
return _type;
}
/**
* Method getTeamName1.
* @return String
*/
public String getTeamName1()
{
return _team1.getName();
}
/**
* Method getTeamName2.
* @return String
*/
public String getTeamName2()
{
return _team2.getName();
}
}