/* * This file is part of the L2J Mobius project. * * 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.l2jmobius.gameserver.instancemanager; import java.sql.Connection; import java.sql.PreparedStatement; import java.util.Comparator; import java.util.List; import java.util.logging.Logger; import java.util.stream.Collectors; import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.commons.util.Rnd; import com.l2jmobius.gameserver.enums.CategoryType; import com.l2jmobius.gameserver.enums.CeremonyOfChaosState; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.ceremonyofchaos.CeremonyOfChaosEvent; import com.l2jmobius.gameserver.model.ceremonyofchaos.CeremonyOfChaosMember; import com.l2jmobius.gameserver.model.eventengine.AbstractEventManager; import com.l2jmobius.gameserver.model.eventengine.ScheduleTarget; import com.l2jmobius.gameserver.model.events.EventType; import com.l2jmobius.gameserver.model.events.ListenerRegisterType; import com.l2jmobius.gameserver.model.events.annotations.RegisterEvent; import com.l2jmobius.gameserver.model.events.annotations.RegisterType; import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerBypass; import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogin; import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogout; import com.l2jmobius.gameserver.model.events.returns.TerminateReturn; import com.l2jmobius.gameserver.model.olympiad.OlympiadManager; import com.l2jmobius.gameserver.model.punishment.PunishmentAffect; import com.l2jmobius.gameserver.model.punishment.PunishmentType; import com.l2jmobius.gameserver.model.variables.PlayerVariables; import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; import com.l2jmobius.gameserver.network.serverpackets.ceremonyofchaos.ExCuriousHouseState; /** * @author Sdw */ public class CeremonyOfChaosManager extends AbstractEventManager { protected static final Logger LOGGER = Logger.getLogger(CeremonyOfChaosManager.class.getName()); public static final String INITIAL_BUFF_KEY = "initial_buff"; public static final String INITIAL_ITEMS_KEY = "initial_items"; public static final String MAX_PLAYERS_KEY = "max_players"; public static final String MAX_ARENAS_KEY = "max_arenas"; public static final String INSTANCE_TEMPLATES_KEY = "instance_templates"; public static final String END_BUFFS_KEYH = "end_buffs"; protected CeremonyOfChaosManager() { } @Override public void onInitialized() { if (getState() == null) { setState(CeremonyOfChaosState.SCHEDULED); } } @ScheduleTarget private void onPeriodEnd(String text) { try (Connection con = DatabaseFactory.getInstance().getConnection(); PreparedStatement ps = con.prepareStatement("DELETE FROM character_variables WHERE var = ?")) { ps.setString(1, PlayerVariables.CEREMONY_OF_CHAOS_PROHIBITED_PENALTIES); ps.execute(); } catch (Exception e) { LOGGER.severe(getClass().getSimpleName() + ": Could not reset Ceremony Of Chaos penalties: " + e); } // Update data for online players. L2World.getInstance().getPlayers().stream().forEach(player -> { player.getVariables().remove(PlayerVariables.CEREMONY_OF_CHAOS_PROHIBITED_PENALTIES); player.getVariables().storeMe(); }); LOGGER.info(getClass().getSimpleName() + ": Ceremony of Chaos penalties have been reset."); LOGGER.info(getClass().getSimpleName() + ": Ceremony of Chaos period has ended!"); } @ScheduleTarget private void onEventStart() { LOGGER.info(getClass().getSimpleName() + ": Ceremony of Chaos event has started!"); } @ScheduleTarget private void onEventEnd() { PunishmentManager.getInstance().stopPunishment(PunishmentAffect.CHARACTER, PunishmentType.COC_BAN); LOGGER.info(getClass().getSimpleName() + ": Ceremony of Chaos event has ended!"); } @ScheduleTarget private void onRegistrationStart() { if (getState() != CeremonyOfChaosState.SCHEDULED) { return; } setState(CeremonyOfChaosState.REGISTRATION); for (L2PcInstance player : L2World.getInstance().getPlayers()) { if (player.isOnline()) { player.sendPacket(SystemMessageId.REGISTRATION_FOR_THE_CEREMONY_OF_CHAOS_HAS_BEGUN); if (canRegister(player, false)) { player.sendPacket(ExCuriousHouseState.REGISTRATION_PACKET); } } } } @ScheduleTarget private void onRegistrationEnd() { if (getState() != CeremonyOfChaosState.REGISTRATION) { return; } setState(CeremonyOfChaosState.PREPARING_FOR_TELEPORT); for (L2PcInstance player : L2World.getInstance().getPlayers()) { if (player.isOnline()) { player.sendPacket(SystemMessageId.REGISTRATION_FOR_THE_CEREMONY_OF_CHAOS_HAS_ENDED); if (!isRegistered(player)) { player.sendPacket(ExCuriousHouseState.IDLE_PACKET); } } } getTimers().addTimer("count_down", StatsSet.valueOf("time", 60), 60 * 1000, null, null); } @ScheduleTarget private void onPrepareForFight() { if (getState() != CeremonyOfChaosState.PREPARING_FOR_TELEPORT) { return; } setState(CeremonyOfChaosState.PREPARING_FOR_FIGHT); int eventId = 0; int position = 1; CeremonyOfChaosEvent event = null; final List players = getRegisteredPlayers().stream().sorted(Comparator.comparingInt(L2PcInstance::getLevel)).collect(Collectors.toList()); final int maxPlayers = getMaxPlayersInArena(); final List templates = getVariables().getList(INSTANCE_TEMPLATES_KEY, Integer.class); for (L2PcInstance player : players) { if (player.isOnline() && canRegister(player, true)) { if ((event == null) || (event.getMembers().size() >= maxPlayers)) { final int template = templates.get(Rnd.get(templates.size())); event = new CeremonyOfChaosEvent(eventId++, InstanceManager.getInstance().getInstanceTemplate(template)); position = 1; getEvents().add(event); } event.addMember(new CeremonyOfChaosMember(player, event, position++)); } else { player.prohibiteCeremonyOfChaos(); player.sendPacket(ExCuriousHouseState.IDLE_PACKET); } } // Clear previously registrated players getRegisteredPlayers().clear(); // Prepare all event's players for start getEvents().forEach(CeremonyOfChaosEvent::preparePlayers); } @ScheduleTarget private void onStartFight() { if (getState() != CeremonyOfChaosState.PREPARING_FOR_FIGHT) { return; } setState(CeremonyOfChaosState.RUNNING); getEvents().forEach(CeremonyOfChaosEvent::startFight); } @ScheduleTarget private void onEndFight() { if (getState() != CeremonyOfChaosState.RUNNING) { return; } setState(CeremonyOfChaosState.SCHEDULED); getEvents().forEach(CeremonyOfChaosEvent::stopFight); getEvents().clear(); } @Override public void onTimerEvent(String event, StatsSet params, L2Npc npc, L2PcInstance player) { switch (event) { case "count_down": { final int time = params.getInt("time", 0); final SystemMessage countdown = SystemMessage.getSystemMessage(SystemMessageId.YOU_WILL_BE_MOVED_TO_THE_ARENA_IN_S1_SECOND_S); countdown.addByte(time); broadcastPacket(countdown); // Reschedule if (time == 60) { getTimers().addTimer(event, params.set("time", 10), 50 * 1000, null, null); } else if (time == 10) { getTimers().addTimer(event, params.set("time", 5), 5 * 1000, null, null); } else if ((time > 1) && (time <= 5)) { getTimers().addTimer(event, params.set("time", time - 1), 1000, null, null); } break; } } } public final void broadcastPacket(IClientOutgoingPacket... packets) { getRegisteredPlayers().forEach(member -> member.sendPacket(packets)); } @Override public boolean canRegister(L2PcInstance player, boolean sendMessage) { boolean canRegister = true; final L2Clan clan = player.getClan(); SystemMessageId sm = null; if (player.getLevel() < 85) { sm = SystemMessageId.ONLY_CHARACTERS_LEVEL_85_OR_ABOVE_MAY_PARTICIPATE_IN_THE_TOURNAMENT; canRegister = false; } else if (player.isFlyingMounted()) { sm = SystemMessageId.YOU_CANNOT_PARTICIPATE_IN_THE_CEREMONY_OF_CHAOS_AS_A_FLYING_TRANSFORMED_OBJECT; canRegister = false; } else if (!player.isInCategory(CategoryType.AWAKEN_GROUP)) { sm = SystemMessageId.ONLY_CHARACTERS_WHO_HAVE_COMPLETED_THE_3RD_CLASS_TRANSFER_MAY_PARTICIPATE; canRegister = false; } else if (!player.isInventoryUnder80(false) || (player.getWeightPenalty() != 0)) { sm = SystemMessageId.UNABLE_TO_PROCESS_THIS_REQUEST_UNTIL_YOUR_INVENTORY_S_WEIGHT_AND_SLOT_COUNT_ARE_LESS_THAN_80_PERCENT_OF_CAPACITY; canRegister = false; } else if ((clan == null) || (clan.getLevel() < 6)) { sm = SystemMessageId.ONLY_CHARACTERS_WHO_ARE_A_PART_OF_A_CLAN_OF_LEVEL_6_OR_ABOVE_MAY_PARTICIPATE; canRegister = false; } else if (getRegisteredPlayers().size() >= (getVariables().getInt(MAX_ARENAS_KEY, 5) * getMaxPlayersInArena())) { sm = SystemMessageId.THERE_ARE_TOO_MANY_CHALLENGERS_YOU_CANNOT_PARTICIPATE_NOW; canRegister = false; } else if (player.isCursedWeaponEquipped() || (player.getReputation() < 0)) { sm = SystemMessageId.WAITING_LIST_REGISTRATION_IS_NOT_ALLOWED_WHILE_THE_CURSED_SWORD_IS_BEING_USED_OR_THE_STATUS_IS_IN_A_CHAOTIC_STATE; canRegister = false; } else if (player.isInDuel()) { sm = SystemMessageId.YOU_CANNOT_REGISTER_IN_THE_WAITING_LIST_DURING_A_DUEL; canRegister = false; } else if (player.isInOlympiadMode() || OlympiadManager.getInstance().isRegistered(player)) { sm = SystemMessageId.YOU_CANNOT_REGISTER_IN_THE_WAITING_LIST_WHILE_PARTICIPATING_IN_OLYMPIAD; canRegister = false; } else if (player.isOnEvent(CeremonyOfChaosEvent.class) || (player.getBlockCheckerArena() > -1)) // TODO underground coliseum and kratei checks. { sm = SystemMessageId.YOU_CANNOT_REGISTER_FOR_THE_WAITING_LIST_WHILE_PARTICIPATING_IN_THE_BLOCK_CHECKER_COLISEUM_OLYMPIAD_KRATEI_S_CUBE_CEREMONY_OF_CHAOS; canRegister = false; } else if (player.isInInstance()) { sm = SystemMessageId.YOU_MAY_NOT_REGISTER_WHILE_USING_THE_INSTANT_ZONE; canRegister = false; } else if (player.isInSiege()) { sm = SystemMessageId.YOU_CANNOT_REGISTER_FOR_THE_WAITING_LIST_ON_THE_BATTLEFIELD_CASTLE_SIEGE_FORTRESS_SIEGE; canRegister = false; } else if (player.isInsideZone(ZoneId.SIEGE)) { sm = SystemMessageId.YOU_CANNOT_REGISTER_IN_THE_WAITING_LIST_WHILE_BEING_INSIDE_OF_A_BATTLEGROUND_CASTLE_SIEGE_FORTRESS_SIEGE; canRegister = false; } else if (player.isFlyingMounted()) { sm = SystemMessageId.YOU_CANNOT_PARTICIPATE_IN_THE_CEREMONY_OF_CHAOS_AS_A_FLYING_TRANSFORMED_OBJECT; canRegister = false; } else if (player.isFishing()) { sm = SystemMessageId.YOU_CANNOT_PARTICIPATE_IN_THE_CEREMONY_OF_CHAOS_WHILE_FISHING; canRegister = false; } else if (player.isCeremonyOfChaosProhibited()) { canRegister = false; } // TODO : One player can take part in 16 matches per day. if ((sm != null) && sendMessage) { player.sendPacket(sm); } return canRegister; } @RegisterEvent(EventType.ON_PLAYER_BYPASS) @RegisterType(ListenerRegisterType.GLOBAL_PLAYERS) private TerminateReturn OnPlayerBypass(OnPlayerBypass event) { final L2PcInstance player = event.getActiveChar(); if (player == null) { return null; } if (event.getCommand().equalsIgnoreCase("pledgegame?command=apply")) { if (registerPlayer(player)) { player.sendPacket(SystemMessageId.YOU_ARE_NOW_ON_THE_WAITING_LIST_YOU_WILL_AUTOMATICALLY_BE_TELEPORTED_WHEN_THE_TOURNAMENT_STARTS_AND_WILL_BE_REMOVED_FROM_THE_WAITING_LIST_IF_YOU_LOG_OUT_IF_YOU_CANCEL_REGISTRATION_WITHIN_THE_LAST_MINUTE_OF_ENTERING_THE_ARENA_AFTER_SIGNING_UP_30_TIMES_OR_MORE_OR_FORFEIT_AFTER_ENTERING_THE_ARENA_30_TIMES_OR_MORE_DURING_A_CYCLE_YOU_BECOME_INELIGIBLE_FOR_PARTICIPATION_IN_THE_CEREMONY_OF_CHAOS_UNTIL_THE_NEXT_CYCLE_ALL_THE_BUFFS_EXCEPT_THE_VITALITY_BUFF_WILL_BE_REMOVED_ONCE_YOU_ENTER_THE_ARENAS); player.sendPacket(SystemMessageId.EXCEPT_THE_VITALITY_BUFF_ALL_BUFFS_INCLUDING_ART_OF_SEDUCTION_WILL_BE_DELETED); player.sendPacket(ExCuriousHouseState.PREPARE_PACKET); } return new TerminateReturn(true, false, false); } return null; } @RegisterEvent(EventType.ON_PLAYER_LOGIN) @RegisterType(ListenerRegisterType.GLOBAL_PLAYERS) private void OnPlayerLogin(OnPlayerLogin event) { if (getState() == CeremonyOfChaosState.REGISTRATION) { final L2PcInstance player = event.getActiveChar(); if (canRegister(player, false)) { player.sendPacket(ExCuriousHouseState.REGISTRATION_PACKET); } } } @RegisterEvent(EventType.ON_PLAYER_LOGOUT) @RegisterType(ListenerRegisterType.GLOBAL_PLAYERS) private void OnPlayerLogout(OnPlayerLogout event) { if (getState() == CeremonyOfChaosState.REGISTRATION) { final L2PcInstance player = event.getActiveChar(); if (getRegisteredPlayers().contains(player)) { getRegisteredPlayers().remove(player); } } } // player leave clan public int getMaxPlayersInArena() { return getVariables().getInt(MAX_PLAYERS_KEY, 18); } public static CeremonyOfChaosManager getInstance() { return SingletonHolder._instance; } private static class SingletonHolder { protected static final CeremonyOfChaosManager _instance = new CeremonyOfChaosManager(); } }