/*
* Copyright (C) 2004-2015 L2J Server
*
* This file is part of L2J Server.
*
* L2J Server 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.
*
* L2J Server 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.l2jserver.gameserver.model.entity.clanhall;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.data.sql.impl.ClanTable;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.enums.SiegeClanType;
import com.l2jserver.gameserver.instancemanager.CHSiegeManager;
import com.l2jserver.gameserver.instancemanager.MapRegionManager;
import com.l2jserver.gameserver.model.L2Clan;
import com.l2jserver.gameserver.model.L2SiegeClan;
import com.l2jserver.gameserver.model.L2Spawn;
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.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.entity.Siegable;
import com.l2jserver.gameserver.model.quest.Quest;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.gameserver.util.Broadcast;
/**
* @author BiggBoss
*/
public abstract class ClanHallSiegeEngine extends Quest implements Siegable
{
private static final String SQL_LOAD_ATTACKERS = "SELECT attacker_id FROM clanhall_siege_attackers WHERE clanhall_id = ?";
private static final String SQL_SAVE_ATTACKERS = "INSERT INTO clanhall_siege_attackers VALUES (?,?)";
private static final String SQL_LOAD_GUARDS = "SELECT * FROM clanhall_siege_guards WHERE clanHallId = ?";
public static final int FORTRESS_RESSISTANCE = 21;
public static final int DEVASTATED_CASTLE = 34;
public static final int BANDIT_STRONGHOLD = 35;
public static final int RAINBOW_SPRINGS = 62;
public static final int BEAST_FARM = 63;
public static final int FORTRESS_OF_DEAD = 64;
protected final Logger _log;
private final HashMap<Integer, L2SiegeClan> _attackers = new HashMap<>();
private ArrayList<L2Spawn> _guards;
public SiegableHall _hall;
public ScheduledFuture<?> _siegeTask;
public boolean _missionAccomplished = false;
public ClanHallSiegeEngine(String name, String descr, final int hallId)
{
super(-1, name, descr);
_log = Logger.getLogger(getClass().getName());
_hall = CHSiegeManager.getInstance().getSiegableHall(hallId);
_hall.setSiege(this);
_siegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new PrepareOwner(), _hall.getNextSiegeTime() - System.currentTimeMillis() - 3600000);
_log.config(_hall.getName() + " siege scheduled for: " + getSiegeDate().getTime());
loadAttackers();
}
// XXX Load methods -------------------------------
public void loadAttackers()
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(SQL_LOAD_ATTACKERS))
{
statement.setInt(1, _hall.getId());
try (ResultSet rset = statement.executeQuery())
{
while (rset.next())
{
final int id = rset.getInt("attacker_id");
L2SiegeClan clan = new L2SiegeClan(id, SiegeClanType.ATTACKER);
_attackers.put(id, clan);
}
}
}
catch (Exception e)
{
_log.warning(getName() + ": Could not load siege attackers!:");
}
}
public final void saveAttackers()
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement delStatement = con.prepareStatement("DELETE FROM clanhall_siege_attackers WHERE clanhall_id = ?"))
{
delStatement.setInt(1, _hall.getId());
delStatement.execute();
if (getAttackers().size() > 0)
{
try (PreparedStatement insert = con.prepareStatement(SQL_SAVE_ATTACKERS))
{
for (L2SiegeClan clan : getAttackers().values())
{
insert.setInt(1, _hall.getId());
insert.setInt(2, clan.getClanId());
insert.execute();
insert.clearParameters();
}
}
}
_log.config(getName() + ": Sucessfully saved attackers down to database!");
}
catch (Exception e)
{
_log.warning(getName() + ": Couldnt save attacker list!");
}
}
public final void loadGuards()
{
if (_guards == null)
{
_guards = new ArrayList<>();
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(SQL_LOAD_GUARDS))
{
statement.setInt(1, _hall.getId());
try (ResultSet rset = statement.executeQuery())
{
while (rset.next())
{
final L2Spawn spawn = new L2Spawn(rset.getInt("npcId"));
spawn.setX(rset.getInt("x"));
spawn.setY(rset.getInt("y"));
spawn.setZ(rset.getInt("z"));
spawn.setHeading(rset.getInt("heading"));
spawn.setRespawnDelay(rset.getInt("respawnDelay"));
spawn.setAmount(1);
_guards.add(spawn);
}
}
}
catch (Exception e)
{
_log.warning(getName() + ": Couldnt load siege guards!:");
}
}
}
// XXX Npc Management methods ----------------------------
private final void spawnSiegeGuards()
{
for (L2Spawn guard : _guards)
{
if (guard != null)
{
guard.init();
}
}
}
private final void unSpawnSiegeGuards()
{
if ((_guards != null) && (_guards.size() > 0))
{
for (L2Spawn guard : _guards)
{
if (guard != null)
{
guard.stopRespawn();
if (guard.getLastSpawn() != null)
{
guard.getLastSpawn().deleteMe();
}
}
}
}
}
@Override
public List<L2Npc> getFlag(L2Clan clan)
{
List<L2Npc> result = null;
L2SiegeClan sClan = getAttackerClan(clan);
if (sClan != null)
{
result = sClan.getFlag();
}
return result;
}
// XXX Attacker clans management -----------------------------
public final HashMap<Integer, L2SiegeClan> getAttackers()
{
return _attackers;
}
@Override
public boolean checkIsAttacker(L2Clan clan)
{
if (clan == null)
{
return false;
}
return _attackers.containsKey(clan.getId());
}
@Override
public boolean checkIsDefender(L2Clan clan)
{
return false;
}
@Override
public L2SiegeClan getAttackerClan(int clanId)
{
return _attackers.get(clanId);
}
@Override
public L2SiegeClan getAttackerClan(L2Clan clan)
{
return getAttackerClan(clan.getId());
}
@Override
public List<L2SiegeClan> getAttackerClans()
{
ArrayList<L2SiegeClan> result = new ArrayList<>();
result.addAll(_attackers.values());
return result;
}
@Override
public List<L2PcInstance> getAttackersInZone()
{
final Collection<L2PcInstance> list = _hall.getSiegeZone().getPlayersInside();
List<L2PcInstance> attackers = new ArrayList<>();
for (L2PcInstance pc : list)
{
final L2Clan clan = pc.getClan();
if ((clan != null) && getAttackers().containsKey(clan.getId()))
{
attackers.add(pc);
}
}
return attackers;
}
@Override
public L2SiegeClan getDefenderClan(int clanId)
{
return null;
}
@Override
public L2SiegeClan getDefenderClan(L2Clan clan)
{
return null;
}
@Override
public List<L2SiegeClan> getDefenderClans()
{
return null;
}
// XXX Siege execution --------------------------
public void prepareOwner()
{
if (_hall.getOwnerId() > 0)
{
final L2SiegeClan clan = new L2SiegeClan(_hall.getOwnerId(), SiegeClanType.ATTACKER);
getAttackers().put(clan.getClanId(), new L2SiegeClan(clan.getClanId(), SiegeClanType.ATTACKER));
}
_hall.free();
_hall.banishForeigners();
SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.THE_REGISTRATION_TERM_FOR_S1_HAS_ENDED);
msg.addString(getName());
Broadcast.toAllOnlinePlayers(msg);
_hall.updateSiegeStatus(SiegeStatus.WAITING_BATTLE);
_siegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new SiegeStarts(), 3600000);
}
@Override
public void startSiege()
{
if ((getAttackers().size() < 1) && (_hall.getId() != 21)) // Fortress of resistance dont have attacker list
{
onSiegeEnds();
getAttackers().clear();
_hall.updateNextSiege();
_siegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new PrepareOwner(), _hall.getSiegeDate().getTimeInMillis());
_hall.updateSiegeStatus(SiegeStatus.WAITING_BATTLE);
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_SIEGE_OF_S1_HAS_BEEN_CANCELED_DUE_TO_LACK_OF_INTEREST);
sm.addString(_hall.getName());
Broadcast.toAllOnlinePlayers(sm);
return;
}
_hall.spawnDoor();
loadGuards();
spawnSiegeGuards();
_hall.updateSiegeZone(true);
final byte state = 1;
for (L2SiegeClan sClan : getAttackerClans())
{
final L2Clan clan = ClanTable.getInstance().getClan(sClan.getClanId());
if (clan == null)
{
continue;
}
for (L2PcInstance pc : clan.getOnlineMembers(0))
{
if (pc != null)
{
pc.setSiegeState(state);
pc.broadcastUserInfo();
pc.setIsInHideoutSiege(true);
}
}
}
_hall.updateSiegeStatus(SiegeStatus.RUNNING);
onSiegeStarts();
_siegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new SiegeEnds(), _hall.getSiegeLenght());
}
@Override
public void endSiege()
{
SystemMessage end = SystemMessage.getSystemMessage(SystemMessageId.THE_S1_SIEGE_HAS_FINISHED);
end.addString(_hall.getName());
Broadcast.toAllOnlinePlayers(end);
L2Clan winner = getWinner();
SystemMessage finalMsg = null;
if (_missionAccomplished && (winner != null))
{
_hall.setOwner(winner);
winner.setHideoutId(_hall.getId());
finalMsg = SystemMessage.getSystemMessage(SystemMessageId.CLAN_S1_IS_VICTORIOUS_OVER_S2_S_CASTLE_SIEGE);
finalMsg.addString(winner.getName());
finalMsg.addString(_hall.getName());
Broadcast.toAllOnlinePlayers(finalMsg);
}
else
{
finalMsg = SystemMessage.getSystemMessage(SystemMessageId.THE_SIEGE_OF_S1_HAS_ENDED_IN_A_DRAW);
finalMsg.addString(_hall.getName());
Broadcast.toAllOnlinePlayers(finalMsg);
}
_missionAccomplished = false;
_hall.updateSiegeZone(false);
_hall.updateNextSiege();
_hall.spawnDoor(false);
_hall.banishForeigners();
final byte state = 0;
for (L2SiegeClan sClan : getAttackerClans())
{
final L2Clan clan = ClanTable.getInstance().getClan(sClan.getClanId());
if (clan == null)
{
continue;
}
for (L2PcInstance player : clan.getOnlineMembers(0))
{
player.setSiegeState(state);
player.broadcastUserInfo();
player.setIsInHideoutSiege(false);
}
}
// Update pvp flag for winners when siege zone becomes inactive
for (L2Character chr : _hall.getSiegeZone().getCharactersInside())
{
if ((chr != null) && chr.isPlayer())
{
chr.getActingPlayer().startPvPFlag();
}
}
getAttackers().clear();
onSiegeEnds();
_siegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new PrepareOwner(), _hall.getNextSiegeTime() - System.currentTimeMillis() - 3600000);
_log.config("Siege of " + _hall.getName() + " scheduled for: " + _hall.getSiegeDate().getTime());
_hall.updateSiegeStatus(SiegeStatus.REGISTERING);
unSpawnSiegeGuards();
}
@Override
public void updateSiege()
{
cancelSiegeTask();
_siegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new PrepareOwner(), _hall.getNextSiegeTime() - 3600000);
_log.config(_hall.getName() + " siege scheduled for: " + _hall.getSiegeDate().getTime().toString());
}
public void cancelSiegeTask()
{
if (_siegeTask != null)
{
_siegeTask.cancel(false);
}
}
@Override
public Calendar getSiegeDate()
{
return _hall.getSiegeDate();
}
// XXX Fame settings ---------------------------
@Override
public boolean giveFame()
{
return Config.CHS_ENABLE_FAME;
}
@Override
public int getFameAmount()
{
return Config.CHS_FAME_AMOUNT;
}
// XXX Misc methods -----------------------------
@Override
public int getFameFrequency()
{
return Config.CHS_FAME_FREQUENCY;
}
public final void broadcastNpcSay(final L2Npc npc, final ChatType type, final NpcStringId messageId)
{
final NpcSay npcSay = new NpcSay(npc.getObjectId(), type, npc.getId(), messageId);
final int sourceRegion = MapRegionManager.getInstance().getMapRegionLocId(npc);
for (L2PcInstance pc : L2World.getInstance().getPlayers())
{
if ((pc != null) && (MapRegionManager.getInstance().getMapRegionLocId(pc) == sourceRegion))
{
pc.sendPacket(npcSay);
}
}
}
// XXX Siege task and abstract methods -------------------
public Location getInnerSpawnLoc(L2PcInstance player)
{
return null;
}
public boolean canPlantFlag()
{
return true;
}
public boolean doorIsAutoAttackable()
{
return true;
}
public void onSiegeStarts()
{
}
public void onSiegeEnds()
{
}
public abstract L2Clan getWinner();
public class PrepareOwner implements Runnable
{
@Override
public void run()
{
prepareOwner();
}
}
public class SiegeStarts implements Runnable
{
@Override
public void run()
{
startSiege();
}
}
public class SiegeEnds implements Runnable
{
@Override
public void run()
{
endSiege();
}
}
}