/* * 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 . */ package com.l2jserver.gameserver.model.olympiad; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import com.l2jserver.Config; import com.l2jserver.gameserver.idfactory.IdFactory; import com.l2jserver.gameserver.model.L2World; import com.l2jserver.gameserver.model.Location; import com.l2jserver.gameserver.model.actor.L2Character; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.model.zone.type.L2OlympiadStadiumZone; import com.l2jserver.gameserver.network.SystemMessageId; import com.l2jserver.gameserver.network.serverpackets.ExOlympiadUserInfo; import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket; import com.l2jserver.gameserver.network.serverpackets.SystemMessage; import com.l2jserver.util.Rnd; /** * * @author Pere, DS */ public class OlympiadGameTeams extends AbstractOlympiadGame { public static final int MAX_TEAM_SIZE = 3; protected boolean _teamOneDefaulted; protected boolean _teamTwoDefaulted; protected int _damageT1 = 0; protected int _damageT2 = 0; protected final int _teamOneSize; protected final int _teamTwoSize; protected final Participant[] _teamOne; protected final Participant[] _teamTwo; protected OlympiadGameTeams(int id, Participant[] teamOne, Participant[] teamTwo) { super(id); _teamOneSize = Math.min(teamOne.length, MAX_TEAM_SIZE); _teamTwoSize = Math.min(teamTwo.length, MAX_TEAM_SIZE); _teamOne = new Participant[MAX_TEAM_SIZE]; _teamTwo = new Participant[MAX_TEAM_SIZE]; Participant par; for (int i = 0; i < MAX_TEAM_SIZE; i++) { if (i < _teamOneSize) { par = teamOne[i]; _teamOne[i] = par; if (par.player != null) par.player.setOlympiadGameId(id); } else _teamOne[i] = new Participant(IdFactory.getInstance().getNextId(), 1); if (i < _teamTwoSize) { par = teamTwo[i]; _teamTwo[i] = par; if (par.player != null) par.player.setOlympiadGameId(id); } else _teamTwo[i] = new Participant(IdFactory.getInstance().getNextId(), 2); } } protected static final Participant[][] createListOfParticipants(List> list) { if (list == null || list.isEmpty() || list.size() < 2) return null; List teamOne = null; List teamTwo = null; L2PcInstance player; List teamOnePlayers = new ArrayList(MAX_TEAM_SIZE); List teamTwoPlayers = new ArrayList(MAX_TEAM_SIZE); while (list.size() > 1) { teamOne = list.remove(Rnd.nextInt(list.size())); if ((teamOne == null || teamOne.isEmpty())) continue; for (int objectId : teamOne) { player = L2World.getInstance().getPlayer(objectId); if (player == null || !player.isOnline()) { teamOnePlayers.clear(); break; } teamOnePlayers.add(player); } if (teamOnePlayers.isEmpty()) continue; teamTwo = list.remove(Rnd.nextInt(list.size())); if (teamTwo == null || teamTwo.isEmpty()) { list.add(teamOne); teamOnePlayers.clear(); continue; } for (int objectId : teamTwo) { player = L2World.getInstance().getPlayer(objectId); if (player == null || !player.isOnline()) { teamTwoPlayers.clear(); break; } teamTwoPlayers.add(player); } if (teamTwoPlayers.isEmpty()) { list.add(teamOne); teamOnePlayers.clear(); continue; } Participant[] t1 = new Participant[teamOnePlayers.size()]; Participant[] t2 = new Participant[teamTwoPlayers.size()]; Participant[][] result = new Participant[2][]; for (int i = 0; i < t1.length; i++) t1[i] = new Participant(teamOnePlayers.get(i), 1); for (int i = 0; i < t2.length; i++) t2[i] = new Participant(teamTwoPlayers.get(i), 2); result[0] = t1; result[1] = t2; return result; } return null; } protected static OlympiadGameTeams createGame(int id, List> list) { final Participant[][] teams = createListOfParticipants(list); if (teams == null) return null; return new OlympiadGameTeams(id, teams[0], teams[1]); } @Override public CompetitionType getType() { return CompetitionType.TEAMS; } @Override protected int getDivider() { return 5; } @Override protected int[][] getReward() { return Config.ALT_OLY_TEAM_REWARD; } @Override public final boolean containsParticipant(int playerId) { for (int i = _teamOneSize; --i >= 0;) { if (_teamOne[i].objectId == playerId) return true; } for (int i = _teamTwoSize; --i >= 0;) { if (_teamTwo[i].objectId == playerId) return true; } return false; } @Override public final void sendOlympiadInfo(L2Character player) { for (int i = 0; i < MAX_TEAM_SIZE; i++) player.sendPacket(new ExOlympiadUserInfo(_teamOne[i])); for (int i = 0; i < MAX_TEAM_SIZE; i++) player.sendPacket(new ExOlympiadUserInfo(_teamTwo[i])); } @Override public final void broadcastOlympiadInfo(L2OlympiadStadiumZone stadium) { for (int i = 0; i < MAX_TEAM_SIZE; i++) stadium.broadcastPacket(new ExOlympiadUserInfo(_teamOne[i])); for (int i = 0; i < MAX_TEAM_SIZE; i++) stadium.broadcastPacket(new ExOlympiadUserInfo(_teamTwo[i])); } @Override protected final void broadcastPacket(L2GameServerPacket packet) { Participant par; for (int i = 0; i < _teamOneSize; i++) { par = _teamOne[i]; par.updatePlayer(); if (par.player != null) par.player.sendPacket(packet); } for (int i = 0; i < _teamTwoSize; i++) { par = _teamTwo[i]; par. updatePlayer(); if (par.player != null) par.player.sendPacket(packet); } } @Override protected boolean needBuffers() { return false; } @Override protected final boolean portPlayersToArena(List spawns) { boolean result = true; try { for (int i = 0; i < _teamOneSize; i++) result &= portPlayerToArena(_teamOne[i], spawns.get(i), _stadiumID); final int offset = spawns.size() / 2; for (int i = 0; i < _teamTwoSize; i++) result &= portPlayerToArena(_teamTwo[i], spawns.get(i + offset), _stadiumID); } catch (Exception e) { _log.log(Level.WARNING, "", e); return false; } return result; } @Override protected final void removals() { for (int i = _teamOneSize; --i >= 0;) removals(_teamOne[i].player, false); for (int i = _teamTwoSize; --i >= 0;) removals(_teamTwo[i].player, false); } @Override protected final boolean makeCompetitionStart() { if (!super.makeCompetitionStart()) return false; Participant par; for (int i = 0; i < _teamOneSize; i++) { par = _teamOne[i]; if (par.player == null) return false; par.player.setIsOlympiadStart(true); par.player.updateEffectIcons(); } for (int i = 0; i < _teamTwoSize; i++) { par = _teamTwo[i]; if (par.player == null) return false; par.player.setIsOlympiadStart(true); par.player.updateEffectIcons(); } return true; } @Override protected final void cleanEffects() { Participant par; for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; if (par.player != null && !par.defaulted && !par.disconnected && par.player.getOlympiadGameId() == _stadiumID) cleanEffects(par.player); } for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; if (par.player != null && !par.defaulted && !par.disconnected && par.player.getOlympiadGameId() == _stadiumID) cleanEffects(par.player); } } @Override protected final void portPlayersBack() { Participant par; for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; if (par.player != null && !par.defaulted && !par.disconnected) portPlayerBack(par.player); } for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; if (par.player != null && !par.defaulted && !par.disconnected) portPlayerBack(par.player); } } @Override protected final void playersStatusBack() { Participant par; for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; if (par.player != null && !par.defaulted && !par.disconnected && par.player.getOlympiadGameId() == _stadiumID) playerStatusBack(par.player); } for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; if (par.player != null && !par.defaulted && !par.disconnected && par.player.getOlympiadGameId() == _stadiumID) playerStatusBack(par.player); } } @Override protected final void clearPlayers() { for (int i = 0; i < MAX_TEAM_SIZE; i++) { if (i < _teamOneSize) _teamOne[i].player = null; else IdFactory.getInstance().releaseId(_teamOne[i].objectId); if (i < _teamTwoSize) _teamTwo[i].player = null; else IdFactory.getInstance().releaseId(_teamTwo[i].objectId); _teamOne[i] = null; _teamTwo[i] = null; } } @Override protected final void handleDisconnect(L2PcInstance player) { Participant par; for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; if (par.objectId == player.getObjectId()) { par.disconnected = true; return; } } for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; if (par.objectId == player.getObjectId()) { par.disconnected = true; return; } } } @Override protected final boolean haveWinner() { if (!checkBattleStatus()) return true; boolean teamOneLost = true; boolean teamTwoLost = true; Participant par; for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; if (!par.disconnected) { if (par.player != null && par.player.getOlympiadGameId() == _stadiumID) teamOneLost &= par.player.isDead(); } } for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; if (!par.disconnected) { if (par.player != null && par.player.getOlympiadGameId() == _stadiumID) teamTwoLost &= par.player.isDead(); } } return teamOneLost || teamTwoLost; } @Override protected final boolean checkBattleStatus() { if (_aborted) return false; if (teamOneAllDisconnected()) return false; if (teamTwoAllDisconnected()) return false; return true; } @Override protected void validateWinner(L2OlympiadStadiumZone stadium) { if (_aborted) return; final boolean tOneCrash = teamOneAllDisconnected(); final boolean tTwoCrash = teamTwoAllDisconnected(); Participant par; SystemMessage sm; int points; // Check for if a team defaulted before battle started if (_teamOneDefaulted || _teamTwoDefaulted) { try { if (_teamOneDefaulted) { for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; removePointsFromParticipant(par, Math.min(par.stats.getInteger(POINTS) / 3, Config.ALT_OLY_MAX_POINTS)); par.updateNobleStats(); } } if (_teamTwoDefaulted) { for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; removePointsFromParticipant(par, Math.min(par.stats.getInteger(POINTS) / 3, Config.ALT_OLY_MAX_POINTS)); par.updateNobleStats(); } } } catch (Exception e) { _log.log(Level.WARNING, "Exception on validateWinner(): " + e.getMessage(), e); } return; } // points to be dedicted in case of losing final int[] pointsTeamOne = new int[_teamOneSize]; final int[] pointsTeamTwo = new int[_teamTwoSize]; final int[] maxPointsTeamOne = new int[_teamOneSize]; final int[] maxPointsTeamTwo = new int[_teamTwoSize]; int totalPointsTeamOne = 0; int totalPointsTeamTwo = 0; for (int i = 0; i < _teamOneSize; i++) { points = _teamOne[i].stats.getInteger(POINTS) / getDivider(); if (points <= 0) points = 1; else if (points > Config.ALT_OLY_MAX_POINTS) points = Config.ALT_OLY_MAX_POINTS; totalPointsTeamOne += points; pointsTeamOne[i] = points; maxPointsTeamOne[i] = points; } for (int i = _teamTwoSize; --i >= 0;) { points = _teamTwo[i].stats.getInteger(POINTS) / getDivider(); if (points <= 0) points = 1; else if (points > Config.ALT_OLY_MAX_POINTS) points = Config.ALT_OLY_MAX_POINTS; totalPointsTeamTwo += points; pointsTeamTwo[i] = points; maxPointsTeamTwo[i] = points; } // Choose minimum sum int min = Math.min(totalPointsTeamOne, totalPointsTeamTwo); // make sure all team members got same number of the points: round down to 3x min = (min / MAX_TEAM_SIZE) * MAX_TEAM_SIZE; // calculating coefficients and trying to correct total number of points for each team // due to rounding errors total points after correction will always be lower or equal // than needed minimal sum final double dividerOne = (double)totalPointsTeamOne / min; final double dividerTwo = (double)totalPointsTeamTwo / min; totalPointsTeamOne = min; totalPointsTeamTwo = min; for (int i = 0; i < _teamOneSize; i++) { points = Math.max((int)(pointsTeamOne[i] / dividerOne), 1); pointsTeamOne[i] = points; totalPointsTeamOne -= points; } for (int i = _teamTwoSize; --i >= 0;) { points = Math.max((int)(pointsTeamTwo[i] / dividerTwo), 1); pointsTeamTwo[i] = points; totalPointsTeamTwo -= points; } // compensating remaining points, first team from begin to end, second from end to begin for (int i = 0; totalPointsTeamOne > 0 && i < _teamOneSize; i++) { if (pointsTeamOne[i] < maxPointsTeamOne[i]) { pointsTeamOne[i]++; totalPointsTeamOne--; } } for (int i = _teamTwoSize; totalPointsTeamTwo > 0 && --i >= 0;) { if (pointsTeamTwo[i] < maxPointsTeamTwo[i]) { pointsTeamTwo[i]++; totalPointsTeamTwo--; } } // Create results for players if a team crashed if (tOneCrash || tTwoCrash) { try { if (tTwoCrash && !tOneCrash) { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_WON_THE_GAME); sm.addString(_teamOne[0].name); stadium.broadcastPacket(sm); for (int i = 0; i < _teamTwoSize; i++) { par = _teamTwo[i]; par.updateStat(COMP_LOST, 1); points = pointsTeamTwo[i]; removePointsFromParticipant(par, points); } points = min / MAX_TEAM_SIZE; for (int i = 0; i < _teamOneSize; i++) { par = _teamOne[i]; par.updateStat(COMP_WON, 1); addPointsToParticipant(par, points); } for (int i = 0; i < _teamOneSize; i++) rewardParticipant(_teamOne[i].player, getReward()); } else if (tOneCrash && !tTwoCrash) { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_WON_THE_GAME); sm.addString(_teamTwo[0].name); stadium.broadcastPacket(sm); for (int i = 0; i < _teamOneSize; i++) { par = _teamOne[i]; par.updateStat(COMP_LOST, 1); points = pointsTeamOne[i]; removePointsFromParticipant(par, points); } points = min / MAX_TEAM_SIZE; for (int i = 0; i < _teamTwoSize; i++) { par = _teamTwo[i]; par.updateStat(COMP_WON, 1); addPointsToParticipant(par, points); } for (int i = 0; i < _teamTwoSize; i++) rewardParticipant(_teamTwo[i].player, getReward()); } else if (tOneCrash && tTwoCrash) { stadium.broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.THE_GAME_ENDED_IN_A_TIE)); for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; par.updateStat(COMP_LOST, 1); removePointsFromParticipant(par, pointsTeamOne[i]); } for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; par.updateStat(COMP_LOST, 1); removePointsFromParticipant(par, pointsTeamTwo[i]); } } for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; par.updateStat(COMP_DONE, 1); par.updateNobleStats(); } for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; par.updateStat(COMP_DONE, 1); par.updateNobleStats(); } } catch (Exception e) { _log.log(Level.WARNING, "Exception on validateWinner(): " + e.getMessage(), e); } return; } try { double hp; double teamOneHp = 0; double teamTwoHp = 0; for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; if (!par.disconnected && par.player != null && !par.player.isDead()) { hp = par.player.getCurrentHp() + par.player.getCurrentCp(); if (hp >= 0.5) teamOneHp += hp; } par.updatePlayer(); } for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; if (!par.disconnected && par.player != null && !par.player.isDead()) { hp = par.player.getCurrentHp() + par.player.getCurrentCp(); if (hp >= 0.5) teamTwoHp += hp; } par.updatePlayer(); } if ((teamTwoHp == 0 && teamOneHp != 0) || (_damageT1 > _damageT2 && teamTwoHp != 0 && teamOneHp != 0)) { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_WON_THE_GAME); sm.addString(_teamOne[0].name); stadium.broadcastPacket(sm); for (int i = 0; i < _teamTwoSize; i++) { par = _teamTwo[i]; par.updateStat(COMP_LOST, 1); points = pointsTeamTwo[i]; removePointsFromParticipant(par, points); } points = min / MAX_TEAM_SIZE; for (int i = 0; i < _teamOneSize; i++) { par = _teamOne[i]; par.updateStat(COMP_WON, 1); addPointsToParticipant(par, points); } for (int i = 0; i < _teamOneSize; i++) rewardParticipant(_teamOne[i].player, getReward()); } else if ((teamOneHp == 0 && teamTwoHp != 0) || (_damageT2 > _damageT1 && teamOneHp != 0 && teamTwoHp != 0)) { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_WON_THE_GAME); sm.addString(_teamTwo[0].name); stadium.broadcastPacket(sm); for (int i = 0; i < _teamOneSize; i++) { par = _teamOne[i]; par.updateStat(COMP_LOST, 1); points = pointsTeamOne[i]; removePointsFromParticipant(par, points); } points = min / MAX_TEAM_SIZE; for (int i = 0; i < _teamTwoSize; i++) { par = _teamTwo[i]; par.updateStat(COMP_WON, 1); addPointsToParticipant(par, points); } for (int i = 0; i < _teamTwoSize; i++) rewardParticipant(_teamTwo[i].player, getReward()); } else { stadium.broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.THE_GAME_ENDED_IN_A_TIE)); for (int i = 0; i < _teamOneSize; i++) { par = _teamOne[i]; par.updateStat(COMP_DRAWN, 1); points = Math.min(par.stats.getInteger(POINTS) / getDivider(), Config.ALT_OLY_MAX_POINTS); removePointsFromParticipant(par, points); } for (int i = 0; i < _teamTwoSize; i++) { par = _teamTwo[i]; par.updateStat(COMP_DRAWN, 1); points = Math.min(par.stats.getInteger(POINTS) / getDivider(), Config.ALT_OLY_MAX_POINTS); removePointsFromParticipant(par, points); } } for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; par.updateStat(COMP_DONE, 1); par.updateNobleStats(); } for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; par.updateStat(COMP_DONE, 1); par.updateNobleStats(); } } catch (Exception e) { _log.log(Level.WARNING, "Exception on validateWinner(): " + e.getMessage(), e); } } @Override protected final void addDamage(L2PcInstance player, int damage) { Participant par; for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; if (par.objectId == player.getObjectId()) { if (!par.disconnected) _damageT1 += damage; return; } } for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; if (par.objectId == player.getObjectId()) { if (!par.disconnected) _damageT2 += damage; return; } } } @Override public final String[] getPlayerNames() { return new String[] {_teamOne[0].name, _teamTwo[0].name}; } @Override public final boolean checkDefaulted() { try { SystemMessage reason = null; Participant par; for (int i = _teamOneSize; --i >= 0;) { par = _teamOne[i]; par.updatePlayer(); reason = AbstractOlympiadGame.checkDefaulted(par.player); if (reason != null) { par.defaulted = true; if (!_teamOneDefaulted) { _teamOneDefaulted = true; for (Participant t : _teamTwo) { if (t.player != null) t.player.sendPacket(reason); } } } } reason = null; for (int i = _teamTwoSize; --i >= 0;) { par = _teamTwo[i]; par.updatePlayer(); reason = AbstractOlympiadGame.checkDefaulted(par.player); if (reason != null) { par.defaulted = true; if (!_teamTwoDefaulted) { _teamTwoDefaulted = true; for (Participant t : _teamOne) { if (t.player != null) t.player.sendPacket(reason); } } } } return _teamOneDefaulted || _teamTwoDefaulted; } catch (Exception e) { _log.log(Level.WARNING, "Exception on checkDefaulted(): " + e.getMessage(), e); return true; } } @Override public final void resetDamage() { _damageT1 = 0; _damageT2 = 0; } protected final boolean teamOneAllDisconnected() { for (int i = _teamOneSize; --i >= 0;) { if (!_teamOne[i].disconnected) return false; } return true; } protected final boolean teamTwoAllDisconnected() { for (int i = _teamTwoSize; --i >= 0;) { if (!_teamTwo[i].disconnected) return false; } return true; } }