com.l2jfree.gameserver.model.entity.Siege.java Source code

Java tutorial

Introduction

Here is the source code for com.l2jfree.gameserver.model.entity.Siege.java

Source

/*
 * 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 com.l2jfree.gameserver.model.entity;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Calendar;
import java.util.Set;

import javolution.util.FastList;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.l2jfree.Config;
import com.l2jfree.L2DatabaseFactory;
import com.l2jfree.gameserver.Announcements;
import com.l2jfree.gameserver.datatables.ClanTable;
import com.l2jfree.gameserver.datatables.NpcTable;
import com.l2jfree.gameserver.gameobjects.L2Npc;
import com.l2jfree.gameserver.gameobjects.L2Object;
import com.l2jfree.gameserver.gameobjects.L2Player;
import com.l2jfree.gameserver.gameobjects.instance.L2ControlTowerInstance;
import com.l2jfree.gameserver.gameobjects.instance.L2FlameControlTowerInstance;
import com.l2jfree.gameserver.gameobjects.templates.L2NpcTemplate;
import com.l2jfree.gameserver.idfactory.IdFactory;
import com.l2jfree.gameserver.instancemanager.SiegeGuardManager;
import com.l2jfree.gameserver.instancemanager.SiegeManager;
import com.l2jfree.gameserver.instancemanager.SiegeManager.SiegeSpawn;
import com.l2jfree.gameserver.instancemanager.TownManager;
import com.l2jfree.gameserver.model.clan.L2Clan;
import com.l2jfree.gameserver.model.clan.L2SiegeClan;
import com.l2jfree.gameserver.model.clan.L2SiegeClan.SiegeClanType;
import com.l2jfree.gameserver.model.mapregion.TeleportWhereType;
import com.l2jfree.gameserver.model.sevensigns.SevenSigns;
import com.l2jfree.gameserver.model.world.L2World;
import com.l2jfree.gameserver.model.world.spawn.L2Spawn;
import com.l2jfree.gameserver.model.zone.L2SiegeDangerZone;
import com.l2jfree.gameserver.model.zone.L2SiegeZone;
import com.l2jfree.gameserver.model.zone.L2Zone;
import com.l2jfree.gameserver.network.SystemMessageId;
import com.l2jfree.gameserver.network.packets.server.SiegeInfo;
import com.l2jfree.gameserver.network.packets.server.SystemMessage;
import com.l2jfree.gameserver.threadmanager.ExclusiveTask;
import com.l2jfree.gameserver.util.Broadcast;
import com.l2jfree.util.L2FastSet;

public class Siege extends AbstractSiege {
    private final static Log _log = LogFactory.getLog(Siege.class);

    // ==========================================================================================
    // Message to add/check
    //  id=17  msg=[Castle siege has begun.] c3_attr1=[SystemMsg_k.17]
    //  id=18  msg=[Castle siege is over.]   c3_attr1=[SystemMsg_k.18]
    //  id=288 msg=[The castle gate has been broken down.]
    //  id=291 msg=[Clan $s1 is victorious over $s2's castle siege!]
    //  id=292 msg=[$s1 has announced the castle siege time.]
    //  - id=293 msg=[The registration term for $s1 has ended.]
    //  - id=358 msg=[$s1 hour(s) until castle siege conclusion.]
    //  - id=359 msg=[$s1 minute(s) until castle siege conclusion.]
    //  - id=360 msg=[Castle siege $s1 second(s) left!]
    //  id=640 msg=[You have failed to refuse castle defense aid.]
    //  id=641 msg=[You have failed to approve castle defense aid.]
    //  id=644 msg=[You are not yet registered for the castle siege.]
    //  - id=645 msg=[Only clans with Level 4 and higher may register for a castle siege.]
    //  id=646 msg=[You do not have the authority to modify the castle defender list.]
    //  - id=688 msg=[The clan that owns the castle is automatically registered on the defending side.]
    //  id=689 msg=[A clan that owns a castle cannot participate in another siege.]
    //  id=690 msg=[You cannot register on the attacking side because you are part of an alliance with the clan that owns the castle.]
    //  id=718 msg=[The castle gates cannot be opened and closed during a siege.]
    //  - id=295 msg=[$s1's siege was canceled because there were no clans that participated.]
    //  id=659 msg=[This is not the time for siege registration and so registrations cannot be accepted or rejected.]
    //  - id=660 msg=[This is not the time for siege registration and so registration and cancellation cannot be done.]
    //  id=663 msg=[The siege time has been declared for $s. It is not possible to change the time after a siege time has been declared. Do you want to continue?]
    //  id=667 msg=[You are registering on the attacking side of the $s1 siege. Do you want to continue?]
    //  id=668 msg=[You are registering on the defending side of the $s1 siege. Do you want to continue?]
    //  id=669 msg=[You are canceling your application to participate in the $s1 siege battle. Do you want to continue?]
    //  id=707 msg=[You cannot teleport to a village that is in a siege.]
    //  - id=711 msg=[The siege of $s1 has started.]
    //  - id=712 msg=[The siege of $s1 has finished.]
    //  id=844 msg=[The siege to conquer $s1 has begun.]
    //  - id=845 msg=[The deadline to register for the siege of $s1 has passed.]
    //  - id=846 msg=[The siege of $s1 has been canceled due to lack of interest.]
    //  - id=856 msg=[The siege of $s1 has ended in a draw.]
    //  id=285 msg=[Clan $s1 has succeeded in engraving the ruler!]
    //  - id=287 msg=[The opponent clan has begun to engrave the ruler.]

    public static enum TeleportWhoType {
        All, Attacker, DefenderNotOwner, Owner, Spectator
    }

    private int _controlTowerCount;
    private int _controlTowerMaxCount;

    private L2SiegeDangerZone[] _dangerZonesE = null;
    private L2SiegeDangerZone[] _dangerZonesW = null;

    // ===============================================================
    // Schedule task

    private final ExclusiveTask _endSiegeTask = new ExclusiveTask() {
        @Override
        protected void onElapsed() {
            if (!getIsInProgress()) {
                cancel();
                return;
            }

            final long timeRemaining = _siegeEndDate.getTimeInMillis() - System.currentTimeMillis();

            if (timeRemaining <= 0) {
                endSiege();
                cancel();
                return;
            }

            if (3600000 > timeRemaining) {
                if (timeRemaining > 120000)
                    announceToPlayer(new SystemMessage(SystemMessageId.S1_MINUTES_UNTIL_SIEGE_CONCLUSION)
                            .addNumber(Math.round(timeRemaining / 60000)), true);
                else
                    announceToPlayer(new SystemMessage(SystemMessageId.CASTLE_SIEGE_S1_SECONDS_LEFT)
                            .addNumber(Math.round(timeRemaining / 1000)), true);
            }

            int divider;

            if (timeRemaining > 3600000)
                divider = 3600000; // 1 hour

            else if (timeRemaining > 600000)
                divider = 600000; // 10 min

            else if (timeRemaining > 60000)
                divider = 60000; // 1 min

            else if (timeRemaining > 10000)
                divider = 10000; // 10 sec

            else
                divider = 1000; // 1 sec

            schedule(timeRemaining % divider);
        }
    };

    private final ExclusiveTask _startSiegeTask = new ExclusiveTask() {
        @Override
        protected void onElapsed() {
            if (getIsInProgress()) {
                cancel();
                return;
            }

            if (!getIsTimeRegistrationOver()) {
                long regTimeRemaining = getTimeRegistrationOverDate().getTimeInMillis()
                        - System.currentTimeMillis();

                if (regTimeRemaining > 0) {
                    schedule(regTimeRemaining);
                    return;
                }

                endTimeRegistration(true);
            }

            final long timeRemaining = getSiegeDate().getTimeInMillis() - System.currentTimeMillis();

            if (timeRemaining <= 0) {
                startSiege();
                cancel();
                return;
            }

            if (86400000 > timeRemaining) {
                if (!_isRegistrationOver) {
                    _isRegistrationOver = true;
                    announceToPlayer(new SystemMessage(SystemMessageId.REGISTRATION_TERM_FOR_S1_ENDED)
                            .addString(getCastle().getName()), false);
                    clearSiegeWaitingClan();
                }

                if (timeRemaining > 7200000)
                    announceToPlayer(Math.round(timeRemaining / 3600000.0) + " hour(s) until "
                            + getCastle().getName() + " siege begin.", false);

                else if (timeRemaining > 120000)
                    announceToPlayer(Math.round(timeRemaining / 60000.0) + " minute(s) until "
                            + getCastle().getName() + " siege begin.", false);

                else
                    announceToPlayer(getCastle().getName() + " siege " + Math.round(timeRemaining / 1000.0)
                            + " second(s) to start!", false);
            }

            int divider;

            if (timeRemaining > 86400000)
                divider = 86400000; // 1 day

            else if (timeRemaining > 3600000)
                divider = 3600000; // 1 hour

            else if (timeRemaining > 600000)
                divider = 600000; // 10 min

            else if (timeRemaining > 60000)
                divider = 60000; // 1 min

            else if (timeRemaining > 10000)
                divider = 10000; // 10 sec

            else
                divider = 1000; // 1 sec

            schedule(timeRemaining % divider);
        }
    };

    // =========================================================
    // Data Field
    // Attacker and Defender
    private final Set<L2SiegeClan> _attackerClans = new L2FastSet<L2SiegeClan>().setShared(true);

    private final Set<L2SiegeClan> _defenderClans = new L2FastSet<L2SiegeClan>().setShared(true);
    private final Set<L2SiegeClan> _defenderWaitingClans = new L2FastSet<L2SiegeClan>().setShared(true);

    // Castle setting
    private final Set<L2ControlTowerInstance> _controlTowers = new L2FastSet<L2ControlTowerInstance>()
            .setShared(true);
    private final Set<L2FlameControlTowerInstance> _flameTowers = new L2FastSet<L2FlameControlTowerInstance>()
            .setShared(true);

    private final Castle _castle;
    private boolean _isInProgress = false;
    protected boolean _isRegistrationOver = false;
    protected Calendar _siegeEndDate;
    private final SiegeGuardManager _siegeGuardManager;
    private int oldOwner = 0; // 0 - NPC, > 0 - clan

    // =========================================================
    // Constructor
    public Siege(Castle castle) {
        _castle = castle;
        _siegeGuardManager = new SiegeGuardManager(getCastle());
        startAutoTask();
    }

    // =========================================================
    // Siege phases
    /**
     * When siege ends<BR><BR>
     */
    public void endSiege() {
        if (getIsInProgress()) {
            announceToPlayer(SystemMessageId.CASTLE_SIEGE_HAS_ENDED.getSystemMessage(), true);
            SystemMessage sm;
            sm = new SystemMessage(SystemMessageId.SIEGE_OF_S1_FINISHED);
            sm.addString(getCastle().getName());
            announceToPlayer(sm, false);

            announceToParticipants(SystemMessageId.TEMPORARY_ALLIANCE_DISSOLVED.getSystemMessage());

            getCastle().destroyClanGate();

            if (getCastle().getOwnerId() <= 0) {
                sm = new SystemMessage(SystemMessageId.SIEGE_S1_DRAW);
                sm.addString(getCastle().getName());
                announceToPlayer(sm, false);
            }
            if (oldOwner != getCastle().getOwnerId()) {
                announceToPlayer(SystemMessageId.NEW_CASTLE_LORD.getSystemMessage(), true); //is it really true?
                sm = new SystemMessage(SystemMessageId.CLAN_S1_VICTORIOUS_OVER_S2_S_SIEGE);
                sm.addString(ClanTable.getInstance().getClan(getCastle().getOwnerId()).getName());
                sm.addString(getCastle().getName());
                announceToPlayer(sm, false);
            }

            getCastle().updateClansReputation();
            removeFlags(); // Removes all flags. Note: Remove flag before teleporting players
            teleportPlayer(Siege.TeleportWhoType.Attacker, TeleportWhereType.Town); // Teleport to the second closest town
            teleportPlayer(Siege.TeleportWhoType.DefenderNotOwner, TeleportWhereType.Town); // Teleport to the second closest town
            teleportPlayer(Siege.TeleportWhoType.Spectator, TeleportWhereType.Town); // Teleport to the second closest town
            _isInProgress = false; // Flag so that siege instance can be started
            updatePlayerSiegeStateFlags(true);
            getZone().updateSiegeStatus();
            saveCastleSiege(); // Save castle specific data
            clearSiegeClan(); // Clear siege clan from db
            removeControlTower(); // Remove all control tower from this castle
            deactivateZones(); // Control towers removed - bye to danger zone effects
            _siegeGuardManager.unspawnSiegeGuard(); // Remove all spawned siege guard from this castle
            getCastle().spawnDoor(); // Respawn door to castle
        }
    }

    private void removeDefender(L2SiegeClan sc) {
        if (sc != null)
            getDefenderClans().remove(sc);
    }

    private void removeAttacker(L2SiegeClan sc) {
        if (sc != null)
            getAttackerClans().remove(sc);
    }

    private void addDefender(L2SiegeClan sc, SiegeClanType type) {
        if (sc == null)
            return;
        sc.setType(type);
        getDefenderClans().add(sc);
    }

    private void addAttacker(L2SiegeClan sc) {
        if (sc == null)
            return;
        sc.setType(SiegeClanType.ATTACKER);
        getAttackerClans().add(sc);
    }

    /**
     * When control of castle changed during siege<BR><BR>
     */
    public void midVictory() {
        if (getIsInProgress()) // Siege still in progress
        {
            if (getCastle().getOwnerId() > 0)
                _siegeGuardManager.unspawnSiegeGuard();

            if (getDefenderClans().size() == 0 && // If defender doesn't exist (Pc vs Npc)
                    getAttackerClans().size() == 1 // Only 1 attacker
            ) {
                L2SiegeClan sc_newowner = getAttackerClan(getCastle().getOwnerId());
                removeAttacker(sc_newowner);
                addDefender(sc_newowner, SiegeClanType.OWNER);
                endSiege();
                return;
            }
            if (getCastle().getOwnerId() > 0) {
                int allyId = ClanTable.getInstance().getClan(getCastle().getOwnerId()).getAllyId();
                if (getDefenderClans().size() == 0) // If defender doesn't exist (Pc vs Npc)
                // and only an alliance attacks
                {
                    // The player's clan is in an alliance
                    if (allyId != 0) {
                        boolean allinsamealliance = true;
                        for (L2SiegeClan sc : getAttackerClans()) {
                            if (sc != null) {
                                if (ClanTable.getInstance().getClan(sc.getClanId()).getAllyId() != allyId)
                                    allinsamealliance = false;
                            }
                        }
                        if (allinsamealliance) {
                            L2SiegeClan sc_newowner = getAttackerClan(getCastle().getOwnerId());
                            removeAttacker(sc_newowner);
                            addDefender(sc_newowner, SiegeClanType.OWNER);
                            endSiege();
                            return;
                        }
                    }
                }

                for (L2SiegeClan sc : getDefenderClans()) {
                    if (sc != null) {
                        removeDefender(sc);
                        addAttacker(sc);
                    }
                }

                L2SiegeClan sc_newowner = getAttackerClan(getCastle().getOwnerId());
                removeAttacker(sc_newowner);
                addDefender(sc_newowner, SiegeClanType.OWNER);

                // The player's clan is in an alliance
                if (allyId != 0) {
                    L2Clan[] clanList = ClanTable.getInstance().getClans();

                    for (L2Clan clan : clanList) {
                        if (clan.getAllyId() == allyId) {
                            L2SiegeClan sc = getAttackerClan(clan.getClanId());
                            if (sc != null) {
                                removeAttacker(sc);
                                addDefender(sc, SiegeClanType.DEFENDER);
                            }
                        }
                    }
                }
                teleportPlayer(Siege.TeleportWhoType.Attacker, TeleportWhereType.SiegeFlag); // Teleport to the second closest town
                teleportPlayer(Siege.TeleportWhoType.Spectator, TeleportWhereType.Town); // Teleport to the second closest town

                removeDefenderFlags(); // Removes defenders' flags
                getCastle().removeUpgrade(); // Remove all castle upgrade
                getCastle().spawnDoor(true); // Respawn door to castle but make them weaker (50% hp)
                removeControlTower(); // Remove all control tower from this castle
                _controlTowerCount = 0;//Each new siege midvictory CT are completely respawned.
                _controlTowerMaxCount = 0;
                spawnControlTower(getCastle().getCastleId());
                updatePlayerSiegeStateFlags(false);

                announceToParticipants(SystemMessageId.TEMPORARY_ALLIANCE.getSystemMessage());
            }
        }
    }

    /**
     * When siege starts<BR><BR>
     */
    public void startSiege() {
        if (!getIsInProgress()) {
            if (getAttackerClans().size() <= 0) {
                SystemMessage sm;
                if (getCastle().getOwnerId() <= 0)
                    sm = new SystemMessage(SystemMessageId.SIEGE_OF_S1_HAS_BEEN_CANCELED_DUE_TO_LACK_OF_INTEREST);
                else
                    sm = new SystemMessage(SystemMessageId.S1_SIEGE_WAS_CANCELED_BECAUSE_NO_CLANS_PARTICIPATED);
                sm.addString(getCastle().getName());
                Announcements.getInstance().announceToAll(sm);
                saveCastleSiege();
                return;
            }

            _isInProgress = true; // Flag so that same siege instance cannot be started again
            loadSiegeClan(); // Load siege clan from db
            updatePlayerSiegeStateFlags(false);
            teleportPlayer(Siege.TeleportWhoType.Attacker, TeleportWhereType.Town); // Teleport to the closest town
            //teleportPlayer(Siege.TeleportWhoType.Spectator, MapRegionTable.TeleportWhereType.Town);     // Teleport to the second closest town
            _controlTowerCount = 0;
            _controlTowerMaxCount = 0;
            spawnControlTower(getCastle().getCastleId()); // Spawn control tower
            getCastle().spawnDoor(); // Spawn door
            spawnSiegeGuard(); // Spawn siege guard
            getZone().updateSiegeStatus();

            // Schedule a task to prepare auto siege end
            _siegeEndDate = Calendar.getInstance();
            _siegeEndDate.add(Calendar.MINUTE, Config.SIEGE_LENGTH_MINUTES);
            _endSiegeTask.schedule(1000);

            announceToPlayer(SystemMessageId.CASTLE_SIEGE_HAS_BEGUN.getSystemMessage(), true);
            SystemMessage sm;
            sm = new SystemMessage(SystemMessageId.SIEGE_OF_S1_HAS_STARTED);
            sm.addString(getCastle().getName());
            announceToPlayer(sm, false);
            sm = new SystemMessage(SystemMessageId.PARTICIPATING_IN_SIEGE_OF_S1);
            sm.addString(getCastle().getName());
            announceToParticipants(sm);
            oldOwner = getCastle().getOwnerId();
        }
    }

    // =========================================================
    // Method - Public
    /**
     * Announce to player.<BR><BR>
     * @param message The String of the message to send to player
     * @param inAreaOnly The boolean flag to show message to players in area only.
     */
    public void announceToPlayer(String message, boolean inAreaOnly) {
        // Get all players
        for (L2Player player : L2World.getInstance().getAllPlayers()) {
            if (!inAreaOnly || (inAreaOnly && checkIfInZone(player.getX(), player.getY(), player.getZ())))
                player.sendMessage(message);
        }
    }

    public void announceToPlayer(SystemMessage sm, boolean inAreaOnly) {
        for (L2Player player : L2World.getInstance().getAllPlayers()) {
            if (!inAreaOnly || (inAreaOnly && checkIfInZone(player.getX(), player.getY(), player.getZ())))
                player.sendPacket(sm);
        }
    }

    public void announceToParticipants(SystemMessage sm) {
        for (L2SiegeClan siegeclan : getAttackerClans())
            ClanTable.getInstance().getClan(siegeclan.getClanId()).broadcastToOnlineMembers(sm);
        for (L2SiegeClan siegeclan : getDefenderClans())
            ClanTable.getInstance().getClan(siegeclan.getClanId()).broadcastToOnlineMembers(sm);
    }

    public void announceToOpponent(SystemMessage sm, boolean toAtk) {
        Set<L2SiegeClan> clans = (toAtk ? getAttackerClans() : getDefenderClans());
        for (L2SiegeClan siegeclan : clans)
            ClanTable.getInstance().getClan(siegeclan.getClanId()).broadcastToOnlineMembers(sm);
    }

    public void announceToOpponent(SystemMessage sm, L2Clan self) {
        if (self != null) {
            boolean atk = true;
            if (getAttackerClan(self) != null)
                atk = false;
            else if (getDefenderClan(self) == null)
                return;
            announceToOpponent(sm, atk);
        }
    }

    public void updatePlayerSiegeStateFlags(boolean clear) {
        L2Clan clan;
        for (L2SiegeClan siegeclan : getAttackerClans()) {
            if (siegeclan == null)
                continue;
            clan = ClanTable.getInstance().getClan(siegeclan.getClanId());
            for (L2Player member : clan.getOnlineMembers(0)) {
                if (clear)
                    member.setSiegeState((byte) 0);
                else
                    member.setSiegeState((byte) 1);
                member.revalidateZone(true);
                member.broadcastUserInfo();
            }
        }
        for (L2SiegeClan siegeclan : getDefenderClans()) {
            if (siegeclan == null)
                continue;
            clan = ClanTable.getInstance().getClan(siegeclan.getClanId());
            for (L2Player member : clan.getOnlineMembers(0)) {
                if (clear)
                    member.setSiegeState((byte) 0);
                else
                    member.setSiegeState((byte) 2);
                member.revalidateZone(true);
                member.broadcastUserInfo();
            }
        }
    }

    /**
     * Approve clan as defender for siege<BR><BR>
     * @param clanId The int of player's clan id
     */
    public void approveSiegeDefenderClan(int clanId) {
        if (clanId <= 0)
            return;
        saveSiegeClan(ClanTable.getInstance().getClan(clanId), 0, true);
        loadSiegeClan();
    }

    /** Return true if object is inside the zone */
    public boolean checkIfInZone(L2Object object) {
        return checkIfInZone(object.getX(), object.getY(), object.getZ());
    }

    /** Return true if object is inside the zone */
    public boolean checkIfInZone(int x, int y, int z) {
        Town town = TownManager.getInstance().getTown(x, y, z);
        return (getIsInProgress() && (getCastle().checkIfInZone(x, y, z) || getZone().isInsideZone(x, y)
                || (town != null && getCastle().getCastleId() == town.getCastleId())));
    }

    /**
     * Return true if clan is attacker<BR><BR>
     * @param clan The L2Clan of the player
     */
    @Override
    public boolean checkIsAttacker(L2Clan clan) {
        return (getAttackerClan(clan) != null);
    }

    /**
     * Return true if clan is defender<BR><BR>
     * @param clan The L2Clan of the player
     */
    @Override
    public boolean checkIsDefender(L2Clan clan) {
        return (getDefenderClan(clan) != null);
    }

    /**
     * Return true if clan is defender waiting approval<BR><BR>
     * @param clan The L2Clan of the player
     */
    public boolean checkIsDefenderWaiting(L2Clan clan) {
        return (getDefenderWaitingClan(clan) != null);
    }

    /** Clear all registered siege clans from database for castle */
    public void clearSiegeClan() {
        Connection con = null;
        try {
            con = L2DatabaseFactory.getInstance().getConnection(con);
            PreparedStatement statement = con.prepareStatement("DELETE FROM siege_clans WHERE castle_id=?");
            statement.setInt(1, getCastle().getCastleId());
            statement.execute();
            statement.close();

            if (getCastle().getOwnerId() > 0) {
                PreparedStatement statement2 = con.prepareStatement("DELETE FROM siege_clans WHERE clan_id=?");
                statement2.setInt(1, getCastle().getOwnerId());
                statement2.execute();
                statement2.close();
            }

            getAttackerClans().clear();
            getDefenderClans().clear();
            getDefenderWaitingClans().clear();
        } catch (Exception e) {
            _log.error("Exception: clearSiegeClan(): " + e.getMessage(), e);
        } finally {
            L2DatabaseFactory.close(con);
        }
    }

    /** Clear all siege clans waiting for approval from database for castle */
    public void clearSiegeWaitingClan() {
        Connection con = null;
        try {
            con = L2DatabaseFactory.getInstance().getConnection(con);
            PreparedStatement statement = con
                    .prepareStatement("DELETE FROM siege_clans WHERE castle_id=? and type = 2");
            statement.setInt(1, getCastle().getCastleId());
            statement.execute();
            statement.close();

            getDefenderWaitingClans().clear();
        } catch (Exception e) {
            _log.error("Exception: clearSiegeWaitingClan(): " + e.getMessage(), e);
        } finally {
            L2DatabaseFactory.close(con);
        }
    }

    /** Return list of L2Player registered as attacker in the zone. */
    public FastList<L2Player> getAttackersInZone() {
        FastList<L2Player> players = new FastList<L2Player>();
        L2Clan clan;
        for (L2SiegeClan siegeclan : getAttackerClans()) {
            clan = ClanTable.getInstance().getClan(siegeclan.getClanId());
            for (L2Player player : clan.getOnlineMembers(0)) {
                if (checkIfInZone(player.getX(), player.getY(), player.getZ()))
                    players.add(player);
            }
        }
        return players;
    }

    /** Return list of L2Player registered as defender but not owner in the zone. */
    public FastList<L2Player> getDefendersButNotOwnersInZone() {
        FastList<L2Player> players = new FastList<L2Player>();
        L2Clan clan;
        for (L2SiegeClan siegeclan : getDefenderClans()) {
            clan = ClanTable.getInstance().getClan(siegeclan.getClanId());
            if (clan.getClanId() == getCastle().getOwnerId())
                continue;
            for (L2Player player : clan.getOnlineMembers(0)) {
                if (checkIfInZone(player.getX(), player.getY(), player.getZ()))
                    players.add(player);
            }
        }
        return players;
    }

    /** Return list of L2Player in the zone. */
    public FastList<L2Player> getPlayersInZone() {
        FastList<L2Player> players = new FastList<L2Player>();

        for (L2Player player : L2World.getInstance().getAllPlayers()) {
            // quick check from player states, which don't include siege number however
            if (!player.isInsideZone(L2Zone.FLAG_SIEGE))
                continue;
            if (checkIfInZone(player.getX(), player.getY(), player.getZ()))
                players.add(player);
        }

        return players;
    }

    /** Return list of L2Player owning the castle in the zone. */
    public FastList<L2Player> getOwnersInZone() {
        FastList<L2Player> players = new FastList<L2Player>();
        L2Clan clan;
        for (L2SiegeClan siegeclan : getDefenderClans()) {
            clan = ClanTable.getInstance().getClan(siegeclan.getClanId());
            if (clan.getClanId() != getCastle().getOwnerId())
                continue;
            for (L2Player player : clan.getOnlineMembers(0)) {
                if (checkIfInZone(player.getX(), player.getY(), player.getZ()))
                    players.add(player);
            }
        }
        return players;
    }

    /** Return list of L2Player not registered as attacker or defender in the zone. */
    public FastList<L2Player> getSpectatorsInZone() {
        FastList<L2Player> players = new FastList<L2Player>();

        for (L2Player player : L2World.getInstance().getAllPlayers()) {
            // quick check from player states, which don't include siege number however
            if (!player.isInsideZone(L2Zone.FLAG_SIEGE) || player.getSiegeState() != 0)
                continue;
            if (checkIfInZone(player.getX(), player.getY(), player.getZ()))
                players.add(player);
        }

        return players;
    }

    /**
     * Control Tower was killed
     * @param ct
     */
    public void killedCT(L2Npc ct) {
        _controlTowerCount--;
        if (_controlTowerCount < 0)
            _controlTowerCount = 0;
    }

    public void killedFlameCT(boolean side) {
        deactivateZones(side);
    }

    /** Remove the flag that was killed */
    public void killedFlag(L2Npc flag) {
        if (flag == null)
            return;
        for (L2SiegeClan clan : getAttackerClans()) {
            if (clan.removeFlag(flag))
                return;
        }
    }

    /** Display list of registered clans */
    public void listRegisterClan(L2Player player) {
        player.sendPacket(new SiegeInfo(getCastle()));
    }

    /**
     * Register clan as attacker<BR><BR>
     * @param player The L2Player of the player trying to register
     */
    public void registerAttacker(L2Player player) {
        registerAttacker(player, false);
    }

    public void registerAttacker(L2Player player, boolean force) {
        if (!force) {
            int allyId = 0;
            if (getCastle().getOwnerId() != 0)
                allyId = ClanTable.getInstance().getClan(getCastle().getOwnerId()).getAllyId();

            if (allyId != 0 && player.getClan().getAllyId() == allyId) {
                player.sendPacket(SystemMessageId.CANNOT_ATTACK_ALLIANCE_CASTLE);
                return;
            }
        }

        if ((force && player.getClan() != null) || checkIfCanRegister(player, 1))
            saveSiegeClan(player.getClan(), 1, false); // Save to database
    }

    /**
     * Register clan as defender<BR><BR>
     * @param player The L2Player of the player trying to register
     */
    public void registerDefender(L2Player player) {
        registerDefender(player, false);
    }

    public void registerDefender(L2Player player, boolean force) {
        if (!force) {
            if (getCastle().getOwnerId() <= 0) {
                player.sendPacket(SystemMessageId.DEFENDER_SIDE_FULL);
                return;
            }
            if (SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_STRIFE) == SevenSigns.CABAL_DUSK) {
                //strife restricts defenders to only clan's alliance
                int allyId = 0;
                if (getCastle().getOwnerId() != 0)
                    allyId = ClanTable.getInstance().getClan(getCastle().getOwnerId()).getAllyId();
                if (allyId != 0 && player.getClan().getAllyId() != allyId) {
                    player.sendPacket(SystemMessageId.DEFENDER_SIDE_FULL);
                    return;
                }
            }
        }

        if ((force && player.getClan() != null) || checkIfCanRegister(player, 2))
            saveSiegeClan(player.getClan(), 2, false); // Save to database
    }

    /**
     * Remove clan from siege<BR><BR>
     * @param clanId The int of player's clan id
     */
    public void removeSiegeClan(int clanId) {
        if (clanId <= 0)
            return;

        Connection con = null;
        try {
            con = L2DatabaseFactory.getInstance().getConnection(con);
            PreparedStatement statement = con
                    .prepareStatement("DELETE FROM siege_clans WHERE castle_id=? and clan_id=?");
            statement.setInt(1, getCastle().getCastleId());
            statement.setInt(2, clanId);
            statement.execute();
            statement.close();

            loadSiegeClan();
        } catch (Exception e) {
            _log.error(e.getMessage(), e);
        } finally {
            L2DatabaseFactory.close(con);
        }
    }

    /**
     * Remove clan from siege<BR><BR>
     * @param player The L2Player of player/clan being removed
     */
    public void removeSiegeClan(L2Clan clan) {
        if (clan == null || clan.getHasCastle() == getCastle().getCastleId()
                || !SiegeManager.getInstance().checkIsRegistered(clan, getCastle().getCastleId()))
            return;
        removeSiegeClan(clan.getClanId());
    }

    /**
     * Remove clan from siege<BR><BR>
     * @param player The L2Player of player/clan being removed
     */
    public void removeSiegeClan(L2Player player) {
        removeSiegeClan(player.getClan());
    }

    /**
     * Start the auto tasks<BR><BR>
     */
    public void startAutoTask() {
        correctSiegeDateTime();

        _log.info("Siege of " + getCastle().getName() + ": " + getCastle().getSiegeDate().getTime());

        loadSiegeClan();

        // Schedule siege auto start
        _startSiegeTask.schedule(1000);
    }

    /**
     * Teleport players
     */
    public void teleportPlayer(TeleportWhoType teleportWho, TeleportWhereType teleportWhere) {
        FastList<L2Player> players;
        switch (teleportWho) {
        case Owner:
            players = getOwnersInZone();
            break;
        case Attacker:
            players = getAttackersInZone();
            break;
        case DefenderNotOwner:
            players = getDefendersButNotOwnersInZone();
            break;
        case Spectator:
            players = getSpectatorsInZone();
            break;
        default:
            players = getPlayersInZone();
        }

        for (L2Player player : players) {
            if (player.isGM() || player.isInJail())
                continue;
            player.teleToLocation(teleportWhere);
        }
    }

    // =========================================================
    // Method - Private
    /**
     * Add clan as attacker<BR><BR>
     * @param clanId The int of clan's id
     */
    private void addAttacker(int clanId) {
        getAttackerClans().add(new L2SiegeClan(clanId, SiegeClanType.ATTACKER)); // Add registered attacker to attacker list
    }

    /**
     * Add clan as defender<BR><BR>
     * @param clanId The int of clan's id
     */
    private void addDefender(int clanId) {
        getDefenderClans().add(new L2SiegeClan(clanId, SiegeClanType.DEFENDER)); // Add registered defender to defender list
    }

    /**
     * <p>Add clan as defender with the specified type</p>
     * @param clanId The int of clan's id
     * @param type the type of the clan
     */
    private void addDefender(int clanId, SiegeClanType type) {
        getDefenderClans().add(new L2SiegeClan(clanId, type));
    }

    /**
     * Add clan as defender waiting approval<BR><BR>
     * @param clanId The int of clan's id
     */
    private void addDefenderWaiting(int clanId) {
        getDefenderWaitingClans().add(new L2SiegeClan(clanId, SiegeClanType.DEFENDER_PENDING)); // Add registered defender to defender list
    }

    /**
     * Return true if the player can register.<BR><BR>
     * @param player The L2Player of the player trying to register
     */
    private boolean checkIfCanRegister(L2Player player, int typeId) {
        L2Clan clan = player.getClan();
        if (clan == null || clan.getLevel() < Config.SIEGE_CLAN_MIN_LEVEL) {
            if (Config.SIEGE_CLAN_MIN_LEVEL == 4) //default retail
                player.sendPacket(SystemMessageId.ONLY_CLAN_LEVEL_5_ABOVE_MAY_SIEGE);
            else
                player.sendMessage("Only clans with Level " + Config.SIEGE_CLAN_MIN_LEVEL
                        + " and higher may register for a castle siege.");
            return false;
        } else if (getIsRegistrationOver()) {
            player.sendPacket(new SystemMessage(SystemMessageId.DEADLINE_FOR_SIEGE_S1_PASSED)
                    .addString(getCastle().getName()));
            return false;
        } else if (getIsInProgress()) {
            player.sendPacket(SystemMessageId.NOT_SIEGE_REGISTRATION_TIME2);
            return false;
        } else if (clan.getHasCastle() > 0) {
            player.sendPacket(SystemMessageId.CLAN_THAT_OWNS_CASTLE_CANNOT_PARTICIPATE_OTHER_SIEGE);
            return false;
        } else if (clan.getClanId() == getCastle().getOwnerId()) {
            player.sendPacket(SystemMessageId.CLAN_THAT_OWNS_CASTLE_IS_AUTOMATICALLY_REGISTERED_DEFENDING);
            return false;
        } else if (checkIfAlreadyRegisteredForSameDay(player.getClan())) {
            player.sendPacket(
                    SystemMessageId.APPLICATION_DENIED_BECAUSE_ALREADY_SUBMITTED_A_REQUEST_FOR_ANOTHER_SIEGE_BATTLE);
            return false;
        } else {
            for (int i = 0; i < 10; i++) {
                if (SiegeManager.getInstance().checkIsRegistered(player.getClan(), i)) {
                    player.sendPacket(SystemMessageId.ALREADY_REQUESTED_SIEGE_BATTLE);
                    return false;
                }
            }
        }

        if (typeId == 0 || typeId == 2 || typeId == -1) {
            if (getDefenderClans().size() + getDefenderWaitingClans().size() >= Config.SIEGE_MAX_DEFENDER) {
                player.sendPacket(SystemMessageId.DEFENDER_SIDE_FULL);
                return false;
            }
        }
        if (typeId == 1) {
            if (getAttackerClans().size() >= Config.SIEGE_MAX_ATTACKER) {
                player.sendPacket(SystemMessageId.ATTACKER_SIDE_FULL);
                return false;
            }
        }

        return true;
    }

    /**
     * Return true if the clan has already registered to a siege for the same day.<BR><BR>
     * @param clan The L2Clan of the player trying to register
     */
    public boolean checkIfAlreadyRegisteredForSameDay(L2Clan clan) {
        for (Siege siege : SiegeManager.getInstance().getSieges()) {
            if (siege == this)
                continue;
            if (siege.getSiegeDate().get(Calendar.DAY_OF_WEEK) == getSiegeDate().get(Calendar.DAY_OF_WEEK)) {
                if (siege.checkIsAttacker(clan))
                    return true;
                if (siege.checkIsDefender(clan))
                    return true;
                if (siege.checkIsDefenderWaiting(clan))
                    return true;
            }
        }
        return false;
    }

    /**
     * Return the correct siege date as Calendar.<BR><BR>
     * @param siegeDate The Calendar siege date and time
     */
    public void correctSiegeDateTime() {
        boolean corrected = false;

        if (getCastle().getSiegeDate().getTimeInMillis() < System.currentTimeMillis()) {
            // Since siege has past reschedule it to the next one
            // This is usually caused by server being down
            corrected = true;
            setNextSiegeDate();
        }

        if (!SevenSigns.getInstance().isDateInSealValidPeriod(getCastle().getSiegeDate())) {
            // no sieges in Quest period! reschedule it to the next SealValidationPeriod
            // This is usually caused by server being down
            corrected = true;
            setNextSiegeDate();
        }

        if (corrected)
            saveSiegeDate();
    }

    /** Load siege clans. */
    private void loadSiegeClan() {
        Connection con = null;
        try {
            getAttackerClans().clear();
            getDefenderClans().clear();
            getDefenderWaitingClans().clear();

            // Add castle owner as defender (add owner first so that they are on the top of the defender list)
            if (getCastle().getOwnerId() > 0)
                addDefender(getCastle().getOwnerId(), SiegeClanType.OWNER);

            PreparedStatement statement = null;
            ResultSet rs = null;

            con = L2DatabaseFactory.getInstance().getConnection(con);

            statement = con.prepareStatement("SELECT clan_id,type FROM siege_clans where castle_id=?");
            statement.setInt(1, getCastle().getCastleId());
            rs = statement.executeQuery();

            int typeId;
            while (rs.next()) {
                typeId = rs.getInt("type");
                if (typeId == 0)
                    addDefender(rs.getInt("clan_id"));
                else if (typeId == 1)
                    addAttacker(rs.getInt("clan_id"));
                else if (typeId == 2)
                    addDefenderWaiting(rs.getInt("clan_id"));
            }

            statement.close();
        } catch (Exception e) {
            _log.error("Exception: loadSiegeClan(): " + e.getMessage(), e);
        } finally {
            L2DatabaseFactory.close(con);
        }
    }

    /** Remove all control tower spawned. */
    private void removeControlTower() {
        // Remove all instance of control tower for this castle
        for (L2ControlTowerInstance ct : _controlTowers)
            if (ct != null)
                ct.decayMe();
        for (L2FlameControlTowerInstance fct : _flameTowers)
            if (fct != null)
                fct.decayMe();

        _controlTowers.clear();
        _flameTowers.clear();
    }

    /** Remove all flags. */
    private void removeFlags() {
        for (L2SiegeClan sc : getAttackerClans()) {
            if (sc != null)
                sc.removeFlags();
        }
        for (L2SiegeClan sc : getDefenderClans()) {
            if (sc != null)
                sc.removeFlags();
        }
    }

    /** Remove flags from defenders. */
    private void removeDefenderFlags() {
        for (L2SiegeClan sc : getDefenderClans()) {
            if (sc != null)
                sc.removeFlags();
        }
    }

    /** Save castle siege related to database. */
    private void saveCastleSiege() {
        setNextSiegeDate(); // Set the next set date for 2 weeks from now
        // Schedule Time registration end
        getTimeRegistrationOverDate().setTimeInMillis(System.currentTimeMillis());
        getTimeRegistrationOverDate().add(Calendar.DAY_OF_MONTH, 1);
        getCastle().setIsTimeRegistrationOver(false);

        saveSiegeDate(); // Save the new date
        startAutoTask(); // Prepare auto start siege and end registration
    }

    /** Save siege date to database. */
    public void saveSiegeDate() {
        if (_startSiegeTask.isScheduled())
            _startSiegeTask.schedule(1000);

        Connection con = null;
        try {
            con = L2DatabaseFactory.getInstance().getConnection(con);
            PreparedStatement statement = con.prepareStatement(
                    "UPDATE castle SET siegeDate = ?, regTimeEnd = ?, regTimeOver = ?  WHERE id = ?");
            statement.setLong(1, getSiegeDate().getTimeInMillis());
            statement.setLong(2, getTimeRegistrationOverDate().getTimeInMillis());
            statement.setString(3, String.valueOf(getIsTimeRegistrationOver()));
            statement.setInt(4, getCastle().getCastleId());
            statement.execute();

            statement.close();
        } catch (Exception e) {
            _log.error("Exception: saveSiegeDate(): " + e.getMessage(), e);
        } finally {
            L2DatabaseFactory.close(con);
        }
    }

    /**
     * Save registration to database.<BR><BR>
     * @param clan The L2Clan of player
     * @param typeId -1 = owner 0 = defender, 1 = attacker, 2 = defender waiting
     */
    private void saveSiegeClan(L2Clan clan, int typeId, boolean isUpdateRegistration) {
        if (clan.getHasCastle() > 0)
            return;

        Connection con = null;
        try {
            con = L2DatabaseFactory.getInstance().getConnection(con);
            PreparedStatement statement;
            if (!isUpdateRegistration) {
                statement = con.prepareStatement(
                        "INSERT INTO siege_clans (clan_id,castle_id,type,castle_owner) VALUES (?,?,?,0)");
                statement.setInt(1, clan.getClanId());
                statement.setInt(2, getCastle().getCastleId());
                statement.setInt(3, typeId);
                statement.execute();
                statement.close();
            } else {
                statement = con
                        .prepareStatement("UPDATE siege_clans SET type = ? WHERE castle_id = ? AND clan_id = ?");
                statement.setInt(1, typeId);
                statement.setInt(2, getCastle().getCastleId());
                statement.setInt(3, clan.getClanId());
                statement.execute();
                statement.close();
            }

            if (typeId == 0 || typeId == -1) {
                addDefender(clan.getClanId());
                announceToPlayer(clan.getName() + " has been registered to defend " + getCastle().getName(), false);
            } else if (typeId == 1) {
                addAttacker(clan.getClanId());
                announceToPlayer(clan.getName() + " has been registered to attack " + getCastle().getName(), false);
            } else if (typeId == 2) {
                addDefenderWaiting(clan.getClanId());
                announceToPlayer(clan.getName() + " has requested to defend " + getCastle().getName(), false);
            }
        } catch (Exception e) {
            _log.error("Exception: saveSiegeClan(L2Clan clan, int typeId, boolean isUpdateRegistration): "
                    + e.getMessage(), e);
        } finally {
            L2DatabaseFactory.close(con);
        }
    }

    /** Set the date for the next siege. */
    private void setNextSiegeDate() {
        while (getCastle().getSiegeDate().getTimeInMillis() < System.currentTimeMillis()) {
            if (getCastle().getSiegeDate().get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY
                    && getCastle().getSiegeDate().get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY)
                getCastle().getSiegeDate().set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);

            // from CT2.3 Castle sieges are on Sunday, but if server admins allow to set day of the siege
            // than sieges can occur on Saturdays as well
            if (getCastle().getSiegeDate().get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY
                    && !Config.CL_SET_SIEGE_TIME_LIST.contains("day"))
                getCastle().getSiegeDate().set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);

            // set the next siege day to the next weekend
            getCastle().getSiegeDate().add(Calendar.DAY_OF_MONTH, 7);
        }

        if (!SevenSigns.getInstance().isDateInSealValidPeriod(getCastle().getSiegeDate()))
            getCastle().getSiegeDate().add(Calendar.DAY_OF_MONTH, 7);

        _isRegistrationOver = false; // Allow registration for next siege
    }

    /** Spawn control tower. */
    private void spawnControlTower(int Id) {
        SiegeSpawn ss = SiegeManager.getInstance().getFlameControlTowerSpawn(Id, true);
        L2NpcTemplate template = NpcTable.getInstance().getTemplate(ss.getNpcId());
        template.setBaseHpMax(ss.getHp());
        L2FlameControlTowerInstance ft = new L2FlameControlTowerInstance(IdFactory.getInstance().getNextId(),
                template, true);
        ft.getStatus().setCurrentHpMp(ss.getHp(), ft.getMaxMp());
        ft.spawnMe(ss.getLocation().getX(), ss.getLocation().getY(), ss.getLocation().getZ() + 20);
        _flameTowers.add(ft);
        ss = SiegeManager.getInstance().getFlameControlTowerSpawn(Id, false);
        template = NpcTable.getInstance().getTemplate(ss.getNpcId());
        template.setBaseHpMax(ss.getHp());
        ft = new L2FlameControlTowerInstance(IdFactory.getInstance().getNextId(), template, false);
        ft.getStatus().setCurrentHpMp(ss.getHp(), ft.getMaxMp());
        ft.spawnMe(ss.getLocation().getX(), ss.getLocation().getY(), ss.getLocation().getZ() + 20);
        _flameTowers.add(ft);

        for (SiegeSpawn _sp : SiegeManager.getInstance().getControlTowerSpawnList(Id)) {
            template = NpcTable.getInstance().getTemplate(_sp.getNpcId());
            template.setBaseHpMax(_sp.getHp());

            L2ControlTowerInstance ct = new L2ControlTowerInstance(IdFactory.getInstance().getNextId(), template);
            ct.getStatus().setCurrentHpMp(_sp.getHp(), ct.getMaxMp());
            ct.spawnMe(_sp.getLocation().getX(), _sp.getLocation().getY(), _sp.getLocation().getZ() + 20);

            _controlTowerCount++;
            _controlTowerMaxCount++;
            _controlTowers.add(ct);
        }
    }

    /**
     * Spawn siege guard.<BR><BR>
     */
    private void spawnSiegeGuard() {
        getSiegeGuardManager().spawnSiegeGuard();

        // Register guard to the closest Control Tower
        // When CT dies, so do all the guards that it controls
        if (!getSiegeGuardManager().getSiegeGuardSpawn().isEmpty() && !_controlTowers.isEmpty()) {
            L2ControlTowerInstance closestCt;
            double distance, x, y, z;
            double distanceClosest = 0;
            for (L2Spawn spawn : getSiegeGuardManager().getSiegeGuardSpawn()) {
                if (spawn == null)
                    continue;
                closestCt = null;
                distanceClosest = 0;
                for (L2ControlTowerInstance ct : _controlTowers) {
                    if (ct == null)
                        continue;
                    x = (spawn.getLocx() - ct.getX());
                    y = (spawn.getLocy() - ct.getY());
                    z = (spawn.getLocz() - ct.getZ());

                    distance = (x * x) + (y * y) + (z * z);

                    if (closestCt == null || distance < distanceClosest) {
                        closestCt = ct;
                        distanceClosest = distance;
                    }
                }

                if (closestCt != null)
                    closestCt.registerGuard(spawn);
            }
        }
    }

    @Override
    public final L2SiegeClan getAttackerClan(L2Clan clan) {
        if (clan == null)
            return null;
        return getAttackerClan(clan.getClanId());
    }

    public final L2SiegeClan getAttackerClan(int clanId) {
        for (L2SiegeClan sc : getAttackerClans())
            if (sc != null && sc.getClanId() == clanId)
                return sc;
        return null;
    }

    public final Set<L2SiegeClan> getAttackerClans() {
        return _attackerClans;
    }

    public final int getAttackerRespawnDelay() {
        return (Config.SIEGE_RESPAWN_DELAY_ATTACKER);
    }

    public final Castle getCastle() {
        return _castle;
    }

    @Override
    public final L2SiegeClan getDefenderClan(L2Clan clan) {
        if (clan == null)
            return null;
        return getDefenderClan(clan.getClanId());
    }

    public final L2SiegeClan getDefenderClan(int clanId) {
        for (L2SiegeClan sc : getDefenderClans())
            if (sc != null && sc.getClanId() == clanId)
                return sc;
        return null;
    }

    public final Set<L2SiegeClan> getDefenderClans() {
        return _defenderClans;
    }

    public final L2SiegeClan getDefenderWaitingClan(L2Clan clan) {
        if (clan == null)
            return null;
        return getDefenderWaitingClan(clan.getClanId());
    }

    public final L2SiegeClan getDefenderWaitingClan(int clanId) {
        for (L2SiegeClan sc : getDefenderWaitingClans())
            if (sc != null && sc.getClanId() == clanId)
                return sc;
        return null;
    }

    public final Set<L2SiegeClan> getDefenderWaitingClans() {
        return _defenderWaitingClans;
    }

    @Override
    public final boolean getIsInProgress() {
        return _isInProgress;
    }

    public final boolean getIsRegistrationOver() {
        return _isRegistrationOver;
    }

    public final boolean getIsTimeRegistrationOver() {
        return getCastle().getIsTimeRegistrationOver();
    }

    public final Calendar getSiegeDate() {
        return getCastle().getSiegeDate();
    }

    public final Calendar getTimeRegistrationOverDate() {
        return getCastle().getTimeRegistrationOverDate();
    }

    public void endTimeRegistration(boolean automatic) {
        getCastle().setIsTimeRegistrationOver(true);
        if (!automatic) {
            saveSiegeDate();
            Broadcast.toAllOnlinePlayers(
                    new SystemMessage(SystemMessageId.S1_ANNOUNCED_SIEGE_TIME).addString(getCastle().getName()));
        }
    }

    public Set<L2Npc> getFlag(L2Clan clan) {
        if (clan != null) {
            L2SiegeClan sc = getAttackerClan(clan);
            if (sc != null)
                return sc.getFlag();
        }
        return null;
    }

    public L2Npc getClosestFlag(L2Object obj) {
        if ((obj != null) && (obj instanceof L2Player)) {
            if (((L2Player) obj).getClan() != null) {
                L2SiegeClan sc = getAttackerClan(((L2Player) obj).getClan());
                if (sc != null)
                    return sc.getClosestFlag(obj);
            }
        }
        return null;
    }

    public final SiegeGuardManager getSiegeGuardManager() {
        return _siegeGuardManager;
    }

    public final L2SiegeZone getZone() {
        return getCastle().getBattlefield();
    }

    public int getControlTowerCount() {
        return _controlTowerCount;
    }

    /**
     * Returns all zones in the given castle side
     * @param side Inner/Eastern = true, Outer/Western = false
     * @return Danger Zone Array
     */
    public L2SiegeDangerZone[] getDangerZones(boolean side) {
        if (side)
            return _dangerZonesE;
        else
            return _dangerZonesW;
    }

    /**
     * <B>Adds the given zone to the managed zone array.</B><BR><BR>
     * Called when loading zones.<BR>
     * <U>The first zone registered will <I>always</I> be at the 0th cell.</U>
     * @param sdz Siege danger zone
     * @param east Side of the castle
     */
    public void registerZone(L2SiegeDangerZone sdz, boolean east) {
        if (east) {
            if (_dangerZonesE == null)
                _dangerZonesE = new L2SiegeDangerZone[] { sdz };
            else
                _dangerZonesE = ArrayUtils.add(_dangerZonesE, sdz);
        } else {
            if (_dangerZonesW == null)
                _dangerZonesW = new L2SiegeDangerZone[] { sdz };
            else
                _dangerZonesW = ArrayUtils.add(_dangerZonesW, sdz);
        }
    }

    /**
     * @param east Side of the castle
     * @return How many danger zones are activated
     */
    public int getZoneAreaLevel(boolean east) {
        L2SiegeDangerZone[] list = getDangerZones(east);
        if (list == null) //no zones registered
            return 0;
        else if (_castle.getCastleId() == 5) {
            int level = 0;
            for (L2SiegeDangerZone finalElement : list)
                if (finalElement.isActive())
                    level++;
            return level;
        } else
            return (list[0].isActive() ? 1 : 0);
    }

    /**
     * Enforces only (area level)/(list.length) zones to be active.
     * @param east Which side of the castle?
     * @param level Area level
     */
    public void activateOnLoad(boolean east, int level) {
        L2SiegeDangerZone[] list = getDangerZones(east);
        if (list != null && level <= list.length) //if enough zones are loaded
            activateZones(east, 0, level);
    }

    /**
     * Activates siege danger zones.
     * @param east Which side of the castle?
     * @param oldLevel First zone activated in the array
     * @param newLevel Last zone activated in the array
     */
    public void activateZones(boolean east, int oldLevel, int newLevel) {
        L2SiegeDangerZone[] list = getDangerZones(east);
        if (list != null)
            for (int i = oldLevel; i < newLevel; i++)
                list[i].activate();
    }

    private void deactivateZones(boolean side) {
        L2SiegeDangerZone[] list;
        if ((list = getDangerZones(side)) != null)
            for (L2SiegeDangerZone sdz : list)
                sdz.deactivate();
    }

    /** Downgrades all managed zones and deletes their upgrade data from the database */
    public void deactivateZones() {
        deactivateZones(true);
        deactivateZones(false);
        _castle.resetDangerZones();
    }

    /** Clears the managed zone arrays */
    public void onZoneReload() {
        _dangerZonesE = null;
        _dangerZonesW = null;
    }
}