/*
* 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 .
*/
package com.l2jserver.gameserver.model.entity;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.FortUpdater;
import com.l2jserver.gameserver.FortUpdater.UpdaterType;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.data.sql.impl.ClanTable;
import com.l2jserver.gameserver.data.xml.impl.DoorData;
import com.l2jserver.gameserver.data.xml.impl.StaticObjectData;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.enums.MountType;
import com.l2jserver.gameserver.instancemanager.CastleManager;
import com.l2jserver.gameserver.instancemanager.FortManager;
import com.l2jserver.gameserver.instancemanager.ZoneManager;
import com.l2jserver.gameserver.model.L2Clan;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.actor.instance.L2StaticObjectInstance;
import com.l2jserver.gameserver.model.itemcontainer.Inventory;
import com.l2jserver.gameserver.model.zone.type.L2FortZone;
import com.l2jserver.gameserver.model.zone.type.L2SiegeZone;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.network.serverpackets.PledgeShowInfoUpdate;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
public final class Fort extends AbstractResidence
{
protected static final Logger _log = Logger.getLogger(Fort.class.getName());
private final List _doors = new ArrayList<>();
private L2StaticObjectInstance _flagPole = null;
private volatile FortSiege _siege = null;
private Calendar _siegeDate;
private Calendar _lastOwnedTime;
private L2SiegeZone _zone;
private L2Clan _fortOwner = null;
private int _fortType = 0;
private int _state = 0;
private int _castleId = 0;
private int _supplyLvL = 0;
private final FastMap _function;
private final ScheduledFuture>[] _FortUpdater = new ScheduledFuture>[2];
// Spawn Data
private boolean _isSuspiciousMerchantSpawned = false;
private final FastList _siegeNpcs = new FastList<>();
private final FastList _npcCommanders = new FastList<>();
private final FastList _specialEnvoys = new FastList<>();
private final Map _envoyCastles = new HashMap<>(2);
private final Set _availableCastles = new HashSet<>(1);
/** Fortress Functions */
public static final int FUNC_TELEPORT = 1;
public static final int FUNC_RESTORE_HP = 2;
public static final int FUNC_RESTORE_MP = 3;
public static final int FUNC_RESTORE_EXP = 4;
public static final int FUNC_SUPPORT = 5;
public class FortFunction
{
private final int _type;
private int _lvl;
protected int _fee;
protected int _tempFee;
private final long _rate;
private long _endDate;
protected boolean _inDebt;
public boolean _cwh;
public FortFunction(int type, int lvl, int lease, int tempLease, long rate, long time, boolean cwh)
{
_type = type;
_lvl = lvl;
_fee = lease;
_tempFee = tempLease;
_rate = rate;
_endDate = time;
initializeTask(cwh);
}
public int getType()
{
return _type;
}
public int getLvl()
{
return _lvl;
}
public int getLease()
{
return _fee;
}
public long getRate()
{
return _rate;
}
public long getEndTime()
{
return _endDate;
}
public void setLvl(int lvl)
{
_lvl = lvl;
}
public void setLease(int lease)
{
_fee = lease;
}
public void setEndTime(long time)
{
_endDate = time;
}
private void initializeTask(boolean cwh)
{
if (getOwnerClan() == null)
{
return;
}
long currentTime = System.currentTimeMillis();
if (_endDate > currentTime)
{
ThreadPoolManager.getInstance().scheduleGeneral(new FunctionTask(cwh), _endDate - currentTime);
}
else
{
ThreadPoolManager.getInstance().scheduleGeneral(new FunctionTask(cwh), 0);
}
}
private class FunctionTask implements Runnable
{
public FunctionTask(boolean cwh)
{
_cwh = cwh;
}
@Override
public void run()
{
try
{
if (getOwnerClan() == null)
{
return;
}
if ((getOwnerClan().getWarehouse().getAdena() >= _fee) || !_cwh)
{
int fee = _fee;
if (getEndTime() == -1)
{
fee = _tempFee;
}
setEndTime(System.currentTimeMillis() + getRate());
dbSave();
if (_cwh)
{
getOwnerClan().getWarehouse().destroyItemByItemId("CS_function_fee", Inventory.ADENA_ID, fee, null, null);
}
ThreadPoolManager.getInstance().scheduleGeneral(new FunctionTask(true), getRate());
}
else
{
removeFunction(getType());
}
}
catch (Throwable t)
{
}
}
}
public void dbSave()
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("REPLACE INTO fort_functions (fort_id, type, lvl, lease, rate, endTime) VALUES (?,?,?,?,?,?)"))
{
ps.setInt(1, getResidenceId());
ps.setInt(2, getType());
ps.setInt(3, getLvl());
ps.setInt(4, getLease());
ps.setLong(5, getRate());
ps.setLong(6, getEndTime());
ps.execute();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Exception: Fort.updateFunctions(int type, int lvl, int lease, long rate, long time, boolean addNew): " + e.getMessage(), e);
}
}
}
public Fort(int fortId)
{
super(fortId);
load();
loadFlagPoles();
_function = new FastMap<>();
if (getOwnerClan() != null)
{
setVisibleFlag(true);
loadFunctions();
}
initResidenceZone();
initNpcs(); // load and spawn npcs (Always spawned)
initSiegeNpcs(); // load suspicious merchants (Despawned 10mins before siege)
// spawnSuspiciousMerchant();// spawn suspicious merchants
initNpcCommanders(); // npc Commanders (not monsters) (Spawned during siege)
spawnNpcCommanders(); // spawn npc Commanders
initSpecialEnvoys(); // envoys from castles (Spawned after fort taken)
if ((getOwnerClan() != null) && (getFortState() == 0))
{
spawnSpecialEnvoys();
}
}
/**
* Return function with id
* @param type
* @return
*/
public FortFunction getFunction(int type)
{
if (_function.get(type) != null)
{
return _function.get(type);
}
return null;
}
public void endOfSiege(L2Clan clan)
{
ThreadPoolManager.getInstance().executeAi(new endFortressSiege(this, clan));
}
/**
* Move non clan members off fort area and to nearest town.
*
*/
public void banishForeigners()
{
getResidenceZone().banishForeigners(getOwnerClan().getId());
}
/**
* @param x
* @param y
* @param z
* @return true if object is inside the zone
*/
public boolean checkIfInZone(int x, int y, int z)
{
return getZone().isInsideZone(x, y, z);
}
public L2SiegeZone getZone()
{
if (_zone == null)
{
for (L2SiegeZone zone : ZoneManager.getInstance().getAllZones(L2SiegeZone.class))
{
if (zone.getSiegeObjectId() == getResidenceId())
{
_zone = zone;
break;
}
}
}
return _zone;
}
@Override
public L2FortZone getResidenceZone()
{
return (L2FortZone) super.getResidenceZone();
}
/**
* Get the objects distance to this fort
* @param obj
* @return
*/
public double getDistance(L2Object obj)
{
return getZone().getDistanceToZone(obj);
}
public void closeDoor(L2PcInstance activeChar, int doorId)
{
openCloseDoor(activeChar, doorId, false);
}
public void openDoor(L2PcInstance activeChar, int doorId)
{
openCloseDoor(activeChar, doorId, true);
}
public void openCloseDoor(L2PcInstance activeChar, int doorId, boolean open)
{
if (activeChar.getClan() != getOwnerClan())
{
return;
}
L2DoorInstance door = getDoor(doorId);
if (door != null)
{
if (open)
{
door.openMe();
}
else
{
door.closeMe();
}
}
}
// This method is used to begin removing all fort upgrades
public void removeUpgrade()
{
removeDoorUpgrade();
}
/**
* This method will set owner for Fort
* @param clan
* @param updateClansReputation
* @return
*/
public boolean setOwner(L2Clan clan, boolean updateClansReputation)
{
if (clan == null)
{
_log.warning(getClass().getSimpleName() + ": Updating Fort owner with null clan!!!");
return false;
}
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_FORTRESS_BATTLE_OF_S1_HAS_FINISHED);
sm.addCastleId(getResidenceId());
getSiege().announceToPlayer(sm);
final L2Clan oldowner = getOwnerClan();
if ((oldowner != null) && (clan != oldowner))
{
// Remove points from old owner
updateClansReputation(oldowner, true);
try
{
L2PcInstance oldleader = oldowner.getLeader().getPlayerInstance();
if (oldleader != null)
{
if (oldleader.getMountType() == MountType.WYVERN)
{
oldleader.dismount();
}
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception in setOwner: " + e.getMessage(), e);
}
removeOwner(true);
}
setFortState(0, 0); // initialize fort state
// if clan already have castle, don't store him in fortress
if (clan.getCastleId() > 0)
{
getSiege().announceToPlayer(SystemMessage.getSystemMessage(SystemMessageId.NPCS_RECAPTURED_FORTRESS));
return false;
}
// Give points to new owner
if (updateClansReputation)
{
updateClansReputation(clan, false);
}
spawnSpecialEnvoys();
// if clan have already fortress, remove it
if (clan.getFortId() > 0)
{
FortManager.getInstance().getFortByOwner(clan).removeOwner(true);
}
setSupplyLvL(0);
setOwnerClan(clan);
updateOwnerInDB(); // Update in database
saveFortVariables();
if (getSiege().isInProgress())
{
getSiege().endSiege();
}
for (L2PcInstance member : clan.getOnlineMembers(0))
{
giveResidentialSkills(member);
member.sendSkillList();
}
return true;
}
public void removeOwner(boolean updateDB)
{
L2Clan clan = getOwnerClan();
if (clan != null)
{
for (L2PcInstance member : clan.getOnlineMembers(0))
{
removeResidentialSkills(member);
member.sendSkillList();
}
clan.setFortId(0);
clan.broadcastToOnlineMembers(new PledgeShowInfoUpdate(clan));
setOwnerClan(null);
setSupplyLvL(0);
saveFortVariables();
removeAllFunctions();
if (updateDB)
{
updateOwnerInDB();
}
}
}
public void raiseSupplyLvL()
{
_supplyLvL++;
if (_supplyLvL > Config.FS_MAX_SUPPLY_LEVEL)
{
_supplyLvL = Config.FS_MAX_SUPPLY_LEVEL;
}
}
public void setSupplyLvL(int val)
{
if (val <= Config.FS_MAX_SUPPLY_LEVEL)
{
_supplyLvL = val;
}
}
public int getSupplyLvL()
{
return _supplyLvL;
}
public void saveFortVariables()
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE fort SET supplyLvL=? WHERE id = ?"))
{
ps.setInt(1, _supplyLvL);
ps.setInt(2, getResidenceId());
ps.execute();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception: saveFortVariables(): " + e.getMessage(), e);
}
}
/**
* Show or hide flag inside flag pole.
* @param val
*/
public void setVisibleFlag(boolean val)
{
L2StaticObjectInstance flagPole = getFlagPole();
if (flagPole != null)
{
flagPole.setMeshIndex(val ? 1 : 0);
}
}
/**
* Respawn all doors on fort grounds
*
*/
public void resetDoors()
{
for (L2DoorInstance door : _doors)
{
if (door.getOpen())
{
door.closeMe();
}
if (door.isDead())
{
door.doRevive();
}
if (door.getCurrentHp() < door.getMaxHp())
{
door.setCurrentHp(door.getMaxHp());
}
}
loadDoorUpgrade(); // Check for any upgrade the doors may have
}
// This method upgrade door
public void upgradeDoor(int doorId, int hp, int pDef, int mDef)
{
L2DoorInstance door = getDoor(doorId);
if (door != null)
{
door.setCurrentHp(door.getMaxHp() + hp);
saveDoorUpgrade(doorId, hp, pDef, mDef);
return;
}
}
// This method loads fort
@Override
protected void load()
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM fort WHERE id = ?"))
{
ps.setInt(1, getResidenceId());
int ownerId = 0;
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
setName(rs.getString("name"));
_siegeDate = Calendar.getInstance();
_lastOwnedTime = Calendar.getInstance();
_siegeDate.setTimeInMillis(rs.getLong("siegeDate"));
_lastOwnedTime.setTimeInMillis(rs.getLong("lastOwnedTime"));
ownerId = rs.getInt("owner");
_fortType = rs.getInt("fortType");
_state = rs.getInt("state");
_castleId = rs.getInt("castleId");
_supplyLvL = rs.getInt("supplyLvL");
}
}
if (ownerId > 0)
{
L2Clan clan = ClanTable.getInstance().getClan(ownerId); // Try to find clan instance
clan.setFortId(getResidenceId());
setOwnerClan(clan);
int runCount = getOwnedTime() / (Config.FS_UPDATE_FRQ * 60);
long initial = System.currentTimeMillis() - _lastOwnedTime.getTimeInMillis();
while (initial > (Config.FS_UPDATE_FRQ * 60000L))
{
initial -= (Config.FS_UPDATE_FRQ * 60000L);
}
initial = (Config.FS_UPDATE_FRQ * 60000L) - initial;
if ((Config.FS_MAX_OWN_TIME <= 0) || (getOwnedTime() < (Config.FS_MAX_OWN_TIME * 3600)))
{
_FortUpdater[0] = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new FortUpdater(this, clan, runCount, UpdaterType.PERIODIC_UPDATE), initial, Config.FS_UPDATE_FRQ * 60000L); // Schedule owner tasks to start running
if (Config.FS_MAX_OWN_TIME > 0)
{
_FortUpdater[1] = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new FortUpdater(this, clan, runCount, UpdaterType.MAX_OWN_TIME), 3600000, 3600000); // Schedule owner tasks to remove owener
}
}
else
{
_FortUpdater[1] = ThreadPoolManager.getInstance().scheduleGeneral(new FortUpdater(this, clan, 0, UpdaterType.MAX_OWN_TIME), 60000); // Schedule owner tasks to remove owner
}
}
else
{
setOwnerClan(null);
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception: loadFortData(): " + e.getMessage(), e);
}
}
/** Load All Functions */
private void loadFunctions()
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM fort_functions WHERE fort_id = ?"))
{
ps.setInt(1, getResidenceId());
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
_function.put(rs.getInt("type"), new FortFunction(rs.getInt("type"), rs.getInt("lvl"), rs.getInt("lease"), 0, rs.getLong("rate"), rs.getLong("endTime"), true));
}
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Exception: Fort.loadFunctions(): " + e.getMessage(), e);
}
}
/**
* Remove function In List and in DB
* @param functionType
*/
public void removeFunction(int functionType)
{
_function.remove(functionType);
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM fort_functions WHERE fort_id=? AND type=?"))
{
ps.setInt(1, getResidenceId());
ps.setInt(2, functionType);
ps.execute();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Exception: Fort.removeFunctions(int functionType): " + e.getMessage(), e);
}
}
/**
* Remove all fort functions.
*/
private void removeAllFunctions()
{
for (int id : _function.keySet())
{
removeFunction(id);
}
}
public boolean updateFunctions(L2PcInstance player, int type, int lvl, int lease, long rate, boolean addNew)
{
if (player == null)
{
return false;
}
if (lease > 0)
{
if (!player.destroyItemByItemId("Consume", Inventory.ADENA_ID, lease, null, true))
{
return false;
}
}
if (addNew)
{
_function.put(type, new FortFunction(type, lvl, lease, 0, rate, 0, false));
}
else
{
if ((lvl == 0) && (lease == 0))
{
removeFunction(type);
}
else
{
int diffLease = lease - _function.get(type).getLease();
if (diffLease > 0)
{
_function.remove(type);
_function.put(type, new FortFunction(type, lvl, lease, 0, rate, -1, false));
}
else
{
_function.get(type).setLease(lease);
_function.get(type).setLvl(lvl);
_function.get(type).dbSave();
}
}
}
return true;
}
public void activateInstance()
{
loadDoor();
}
// This method loads fort door data from database
private void loadDoor()
{
for (L2DoorInstance door : DoorData.getInstance().getDoors())
{
if ((door.getFort() != null) && (door.getFort().getResidenceId() == getResidenceId()))
{
_doors.add(door);
}
}
}
private void loadFlagPoles()
{
for (L2StaticObjectInstance obj : StaticObjectData.getInstance().getStaticObjects())
{
if ((obj.getType() == 3) && obj.getName().startsWith(getName()))
{
_flagPole = obj;
break;
}
}
if (_flagPole == null)
{
throw new NullPointerException("Can't find flagpole for Fort " + this);
}
}
// This method loads fort door upgrade data from database
private void loadDoorUpgrade()
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM fort_doorupgrade WHERE fortId = ?"))
{
ps.setInt(1, getResidenceId());
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
upgradeDoor(rs.getInt("id"), rs.getInt("hp"), rs.getInt("pDef"), rs.getInt("mDef"));
}
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception: loadFortDoorUpgrade(): " + e.getMessage(), e);
}
}
private void removeDoorUpgrade()
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM fort_doorupgrade WHERE fortId = ?"))
{
ps.setInt(1, getResidenceId());
ps.execute();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception: removeDoorUpgrade(): " + e.getMessage(), e);
}
}
private void saveDoorUpgrade(int doorId, int hp, int pDef, int mDef)
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("INSERT INTO fort_doorupgrade (doorId, hp, pDef, mDef) VALUES (?,?,?,?)"))
{
ps.setInt(1, doorId);
ps.setInt(2, hp);
ps.setInt(3, pDef);
ps.setInt(4, mDef);
ps.execute();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception: saveDoorUpgrade(int doorId, int hp, int pDef, int mDef): " + e.getMessage(), e);
}
}
private void updateOwnerInDB()
{
L2Clan clan = getOwnerClan();
int clanId = 0;
if (clan != null)
{
clanId = clan.getId();
_lastOwnedTime.setTimeInMillis(System.currentTimeMillis());
}
else
{
_lastOwnedTime.setTimeInMillis(0);
}
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE fort SET owner=?,lastOwnedTime=?,state=?,castleId=? WHERE id = ?"))
{
ps.setInt(1, clanId);
ps.setLong(2, _lastOwnedTime.getTimeInMillis());
ps.setInt(3, 0);
ps.setInt(4, 0);
ps.setInt(5, getResidenceId());
ps.execute();
// Announce to clan members
if (clan != null)
{
clan.setFortId(getResidenceId()); // Set has fort flag for new owner
SystemMessage sm;
sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CLAN_IS_VICTORIOUS_IN_THE_FORTRESS_BATTLE_OF_S2);
sm.addString(clan.getName());
sm.addCastleId(getResidenceId());
L2World.getInstance().getPlayers().forEach(p -> p.sendPacket(sm));
clan.broadcastToOnlineMembers(new PledgeShowInfoUpdate(clan));
clan.broadcastToOnlineMembers(new PlaySound(1, "Siege_Victory", 0, 0, 0, 0, 0));
if (_FortUpdater[0] != null)
{
_FortUpdater[0].cancel(false);
}
if (_FortUpdater[1] != null)
{
_FortUpdater[1].cancel(false);
}
_FortUpdater[0] = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new FortUpdater(this, clan, 0, UpdaterType.PERIODIC_UPDATE), Config.FS_UPDATE_FRQ * 60000L, Config.FS_UPDATE_FRQ * 60000L); // Schedule owner tasks to start running
if (Config.FS_MAX_OWN_TIME > 0)
{
_FortUpdater[1] = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new FortUpdater(this, clan, 0, UpdaterType.MAX_OWN_TIME), 3600000, 3600000); // Schedule owner tasks to remove owener
}
}
else
{
if (_FortUpdater[0] != null)
{
_FortUpdater[0].cancel(false);
}
_FortUpdater[0] = null;
if (_FortUpdater[1] != null)
{
_FortUpdater[1].cancel(false);
}
_FortUpdater[1] = null;
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception: updateOwnerInDB(L2Clan clan): " + e.getMessage(), e);
}
}
public final L2Clan getOwnerClan()
{
return _fortOwner;
}
public final void setOwnerClan(L2Clan clan)
{
setVisibleFlag(clan != null);
_fortOwner = clan;
}
public final L2DoorInstance getDoor(int doorId)
{
if (doorId <= 0)
{
return null;
}
for (L2DoorInstance door : getDoors())
{
if (door.getId() == doorId)
{
return door;
}
}
return null;
}
public final List getDoors()
{
return _doors;
}
public final L2StaticObjectInstance getFlagPole()
{
return _flagPole;
}
public final FortSiege getSiege()
{
if (_siege == null)
{
synchronized (this)
{
if (_siege == null)
{
_siege = new FortSiege(this);
}
}
}
return _siege;
}
public final Calendar getSiegeDate()
{
return _siegeDate;
}
public final void setSiegeDate(Calendar siegeDate)
{
_siegeDate = siegeDate;
}
public final int getOwnedTime()
{
if (_lastOwnedTime.getTimeInMillis() == 0)
{
return 0;
}
return (int) ((System.currentTimeMillis() - _lastOwnedTime.getTimeInMillis()) / 1000);
}
public final int getTimeTillRebelArmy()
{
if (_lastOwnedTime.getTimeInMillis() == 0)
{
return 0;
}
return (int) (((_lastOwnedTime.getTimeInMillis() + (Config.FS_MAX_OWN_TIME * 3600000L)) - System.currentTimeMillis()) / 1000L);
}
public final long getTimeTillNextFortUpdate()
{
if (_FortUpdater[0] == null)
{
return 0;
}
return _FortUpdater[0].getDelay(TimeUnit.SECONDS);
}
public void updateClansReputation(L2Clan owner, boolean removePoints)
{
if (owner != null)
{
if (removePoints)
{
owner.takeReputationScore(Config.LOOSE_FORT_POINTS, true);
}
else
{
owner.addReputationScore(Config.TAKE_FORT_POINTS, true);
}
}
}
private static class endFortressSiege implements Runnable
{
private final Fort _f;
private final L2Clan _clan;
public endFortressSiege(Fort f, L2Clan clan)
{
_f = f;
_clan = clan;
}
@Override
public void run()
{
try
{
_f.setOwner(_clan, true);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception in endFortressSiege " + e.getMessage(), e);
}
}
}
/**
* @return Returns state of fortress.
*
* 0 - not decided yet
* 1 - independent
* 2 - contracted with castle
*/
public final int getFortState()
{
return _state;
}
/**
* @param state
* - 0 - not decided yet
* - 1 - independent
* - 2 - contracted with castle
*
* @param castleId the Id of the contracted castle (0 if no contract with any castle)
*/
public final void setFortState(int state, int castleId)
{
_state = state;
_castleId = castleId;
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE fort SET state=?,castleId=? WHERE id = ?"))
{
ps.setInt(1, getFortState());
ps.setInt(2, getContractedCastleId());
ps.setInt(3, getResidenceId());
ps.execute();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception: setFortState(int state, int castleId): " + e.getMessage(), e);
}
}
/**
* @return the fortress type (0 - small (3 commanders), 1 - big (4 commanders + control room))
*/
public final int getFortType()
{
return _fortType;
}
/**
* @param npcId the Id of the ambassador NPC
* @return the Id of the castle this ambassador represents
*/
public final int getCastleIdByAmbassador(int npcId)
{
return _envoyCastles.get(npcId);
}
/**
* @param npcId the Id of the ambassador NPC
* @return the castle this ambassador represents
*/
public final Castle getCastleByAmbassador(int npcId)
{
return CastleManager.getInstance().getCastleById(getCastleIdByAmbassador(npcId));
}
/**
* @return the Id of the castle contracted with this fortress
*/
public final int getContractedCastleId()
{
return _castleId;
}
/**
* @return the castle contracted with this fortress ({@code null} if no contract with any castle)
*/
public final Castle getContractedCastle()
{
return CastleManager.getInstance().getCastleById(getContractedCastleId());
}
/**
* Check if this is a border fortress (associated with multiple castles).
* @return {@code true} if this is a border fortress (associated with more than one castle), {@code false} otherwise
*/
public final boolean isBorderFortress()
{
return _availableCastles.size() > 1;
}
/**
* @return the amount of barracks in this fortress
*/
public final int getFortSize()
{
return getFortType() == 0 ? 3 : 5;
}
public void spawnSuspiciousMerchant()
{
if (_isSuspiciousMerchantSpawned)
{
return;
}
_isSuspiciousMerchantSpawned = true;
for (L2Spawn spawnDat : _siegeNpcs)
{
spawnDat.doSpawn();
spawnDat.startRespawn();
}
}
public void despawnSuspiciousMerchant()
{
if (!_isSuspiciousMerchantSpawned)
{
return;
}
_isSuspiciousMerchantSpawned = false;
for (L2Spawn spawnDat : _siegeNpcs)
{
spawnDat.stopRespawn();
spawnDat.getLastSpawn().deleteMe();
}
}
public void spawnNpcCommanders()
{
for (L2Spawn spawnDat : _npcCommanders)
{
spawnDat.doSpawn();
spawnDat.startRespawn();
}
}
public void despawnNpcCommanders()
{
for (L2Spawn spawnDat : _npcCommanders)
{
spawnDat.stopRespawn();
spawnDat.getLastSpawn().deleteMe();
}
}
public void spawnSpecialEnvoys()
{
for (L2Spawn spawnDat : _specialEnvoys)
{
spawnDat.doSpawn();
spawnDat.startRespawn();
}
}
private void initNpcs()
{
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM fort_spawnlist WHERE fortId = ? AND spawnType = ?"))
{
ps.setInt(1, getResidenceId());
ps.setInt(2, 0);
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
L2Spawn spawnDat = new L2Spawn(rs.getInt("npcId"));
spawnDat.setAmount(1);
spawnDat.setX(rs.getInt("x"));
spawnDat.setY(rs.getInt("y"));
spawnDat.setZ(rs.getInt("z"));
spawnDat.setHeading(rs.getInt("heading"));
spawnDat.setRespawnDelay(60);
SpawnTable.getInstance().addNewSpawn(spawnDat, false);
spawnDat.doSpawn();
spawnDat.startRespawn();
}
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Fort " + getResidenceId() + " initNpcs: Spawn could not be initialized: " + e.getMessage(), e);
}
}
private void initSiegeNpcs()
{
_siegeNpcs.clear();
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT id, npcId, x, y, z, heading FROM fort_spawnlist WHERE fortId = ? AND spawnType = ? ORDER BY id"))
{
ps.setInt(1, getResidenceId());
ps.setInt(2, 2);
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
final L2Spawn spawnDat = new L2Spawn(rs.getInt("npcId"));
spawnDat.setAmount(1);
spawnDat.setX(rs.getInt("x"));
spawnDat.setY(rs.getInt("y"));
spawnDat.setZ(rs.getInt("z"));
spawnDat.setHeading(rs.getInt("heading"));
spawnDat.setRespawnDelay(60);
_siegeNpcs.add(spawnDat);
}
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Fort " + getResidenceId() + " initSiegeNpcs: Spawn could not be initialized: " + e.getMessage(), e);
}
}
private void initNpcCommanders()
{
_npcCommanders.clear();
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT id, npcId, x, y, z, heading FROM fort_spawnlist WHERE fortId = ? AND spawnType = ? ORDER BY id"))
{
ps.setInt(1, getResidenceId());
ps.setInt(2, 1);
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
final L2Spawn spawnDat = new L2Spawn(rs.getInt("npcId"));
spawnDat.setAmount(1);
spawnDat.setX(rs.getInt("x"));
spawnDat.setY(rs.getInt("y"));
spawnDat.setZ(rs.getInt("z"));
spawnDat.setHeading(rs.getInt("heading"));
spawnDat.setRespawnDelay(60);
_npcCommanders.add(spawnDat);
}
}
}
catch (Exception e)
{
// problem with initializing spawn, go to next one
_log.log(Level.WARNING, "Fort " + getResidenceId() + " initNpcCommanders: Spawn could not be initialized: " + e.getMessage(), e);
}
}
private void initSpecialEnvoys()
{
_specialEnvoys.clear();
_envoyCastles.clear();
_availableCastles.clear();
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT id, npcId, x, y, z, heading, castleId FROM fort_spawnlist WHERE fortId = ? AND spawnType = ? ORDER BY id"))
{
ps.setInt(1, getResidenceId());
ps.setInt(2, 3);
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
final int castleId = rs.getInt("castleId");
final L2Spawn spawnDat = new L2Spawn(rs.getInt("npcId"));
spawnDat.setAmount(1);
spawnDat.setX(rs.getInt("x"));
spawnDat.setY(rs.getInt("y"));
spawnDat.setZ(rs.getInt("z"));
spawnDat.setHeading(rs.getInt("heading"));
spawnDat.setRespawnDelay(60);
_specialEnvoys.add(spawnDat);
_envoyCastles.put(spawnDat.getId(), castleId);
_availableCastles.add(castleId);
}
}
}
catch (Exception e)
{
// problem with initializing spawn, go to next one
_log.log(Level.WARNING, "Fort " + getResidenceId() + " initSpecialEnvoys: Spawn could not be initialized: " + e.getMessage(), e);
}
}
@Override
protected void initResidenceZone()
{
for (L2FortZone zone : ZoneManager.getInstance().getAllZones(L2FortZone.class))
{
if (zone.getResidenceId() == getResidenceId())
{
setResidenceZone(zone);
break;
}
}
}
}