
-Removal of Q00344_1000YearsTheEndOfLamentation. -Fixed starting conditions for Q00144_PailakaInjuredDragon. -Fixed starting conditions for last Seven Sign quests. -Added missing MonasteryOfSilence.xml instance spawns and doors. -Removed many catacomb spawns.
1235 lines
30 KiB
Java
1235 lines
30 KiB
Java
/*
|
|
* 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;
|
|
|
|
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.List;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.logging.Level;
|
|
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.data.xml.impl.CastleData;
|
|
import com.l2jserver.gameserver.data.xml.impl.DoorData;
|
|
import com.l2jserver.gameserver.data.xml.impl.NpcData;
|
|
import com.l2jserver.gameserver.enums.CastleSide;
|
|
import com.l2jserver.gameserver.enums.MountType;
|
|
import com.l2jserver.gameserver.instancemanager.CastleManager;
|
|
import com.l2jserver.gameserver.instancemanager.CastleManorManager;
|
|
import com.l2jserver.gameserver.instancemanager.FortManager;
|
|
import com.l2jserver.gameserver.instancemanager.SiegeManager;
|
|
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.TowerSpawn;
|
|
import com.l2jserver.gameserver.model.actor.L2Npc;
|
|
import com.l2jserver.gameserver.model.actor.instance.L2ArtefactInstance;
|
|
import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
|
|
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
|
|
import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
|
|
import com.l2jserver.gameserver.model.holders.CastleSpawnHolder;
|
|
import com.l2jserver.gameserver.model.itemcontainer.Inventory;
|
|
import com.l2jserver.gameserver.model.skills.CommonSkill;
|
|
import com.l2jserver.gameserver.model.skills.Skill;
|
|
import com.l2jserver.gameserver.model.zone.type.L2CastleZone;
|
|
import com.l2jserver.gameserver.model.zone.type.L2ResidenceTeleportZone;
|
|
import com.l2jserver.gameserver.model.zone.type.L2SiegeZone;
|
|
import com.l2jserver.gameserver.network.SystemMessageId;
|
|
import com.l2jserver.gameserver.network.serverpackets.ExCastleState;
|
|
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
|
|
import com.l2jserver.gameserver.network.serverpackets.PledgeShowInfoUpdate;
|
|
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
|
|
import com.l2jserver.gameserver.util.Broadcast;
|
|
|
|
public final class Castle extends AbstractResidence
|
|
{
|
|
protected static final Logger _log = Logger.getLogger(Castle.class.getName());
|
|
|
|
private final List<L2DoorInstance> _doors = new ArrayList<>();
|
|
private final List<L2Npc> _sideNpcs = new ArrayList<>();
|
|
private int _ownerId = 0;
|
|
private Siege _siege = null;
|
|
private Calendar _siegeDate;
|
|
private boolean _isTimeRegistrationOver = true; // true if Castle Lords set the time, or 24h is elapsed after the siege
|
|
private Calendar _siegeTimeRegistrationEndDate; // last siege end date + 1 day
|
|
private CastleSide _castleSide = null;
|
|
private double _taxRate;
|
|
private long _treasury = 0;
|
|
private boolean _showNpcCrest = false;
|
|
private L2SiegeZone _zone = null;
|
|
private L2ResidenceTeleportZone _teleZone;
|
|
private L2Clan _formerOwner = null;
|
|
private final List<L2ArtefactInstance> _artefacts = new ArrayList<>(1);
|
|
private final Map<Integer, CastleFunction> _function;
|
|
private int _ticketBuyCount = 0;
|
|
|
|
/** Castle 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 CastleFunction
|
|
{
|
|
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 CastleFunction(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 (getOwnerId() <= 0)
|
|
{
|
|
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 (getOwnerId() <= 0)
|
|
{
|
|
return;
|
|
}
|
|
if ((ClanTable.getInstance().getClan(getOwnerId()).getWarehouse().getAdena() >= _fee) || !_cwh)
|
|
{
|
|
int fee = _fee;
|
|
if (getEndTime() == -1)
|
|
{
|
|
fee = _tempFee;
|
|
}
|
|
|
|
setEndTime(System.currentTimeMillis() + getRate());
|
|
dbSave();
|
|
if (_cwh)
|
|
{
|
|
ClanTable.getInstance().getClan(getOwnerId()).getWarehouse().destroyItemByItemId("CS_function_fee", Inventory.ADENA_ID, fee, null, null);
|
|
}
|
|
ThreadPoolManager.getInstance().scheduleGeneral(new FunctionTask(true), getRate());
|
|
}
|
|
else
|
|
{
|
|
removeFunction(getType());
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.SEVERE, "", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void dbSave()
|
|
{
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("REPLACE INTO castle_functions (castle_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: Castle.updateFunctions(int type, int lvl, int lease, long rate, long time, boolean addNew): " + e.getMessage(), e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Castle(int castleId)
|
|
{
|
|
super(castleId);
|
|
load();
|
|
_function = new HashMap<>();
|
|
initResidenceZone();
|
|
spawnSideNpcs();
|
|
if (getOwnerId() != 0)
|
|
{
|
|
loadFunctions();
|
|
loadDoorUpgrade();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return function with id
|
|
* @param type
|
|
* @return
|
|
*/
|
|
public CastleFunction getFunction(int type)
|
|
{
|
|
if (_function.containsKey(type))
|
|
{
|
|
return _function.get(type);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public synchronized void engrave(L2Clan clan, L2Object target, CastleSide side)
|
|
{
|
|
if (!_artefacts.contains(target))
|
|
{
|
|
return;
|
|
}
|
|
setSide(side);
|
|
setOwner(clan);
|
|
final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.CLAN_S1_HAS_SUCCEEDED_IN_S2);
|
|
msg.addString(clan.getName());
|
|
msg.addString(getName());
|
|
getSiege().announceToPlayer(msg, true);
|
|
}
|
|
|
|
// This method add to the treasury
|
|
/**
|
|
* Add amount to castle instance's treasury (warehouse).
|
|
* @param amount
|
|
*/
|
|
public void addToTreasury(long amount)
|
|
{
|
|
// check if owned
|
|
if (getOwnerId() <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (getName().toLowerCase())
|
|
{
|
|
case "schuttgart":
|
|
case "goddard":
|
|
{
|
|
final Castle rune = CastleManager.getInstance().getCastle("rune");
|
|
if (rune != null)
|
|
{
|
|
final long runeTax = (long) (amount * rune.getTaxRate());
|
|
if (rune.getOwnerId() > 0)
|
|
{
|
|
rune.addToTreasury(runeTax);
|
|
}
|
|
amount -= runeTax;
|
|
}
|
|
break;
|
|
}
|
|
case "dion":
|
|
case "giran":
|
|
case "gludio":
|
|
case "innadril":
|
|
case "oren":
|
|
{
|
|
final Castle aden = CastleManager.getInstance().getCastle("aden");
|
|
if (aden != null)
|
|
{
|
|
final long adenTax = (long) (amount * aden.getTaxRate()); // Find out what Aden gets from the current castle instance's income
|
|
if (aden.getOwnerId() > 0)
|
|
{
|
|
aden.addToTreasury(adenTax); // Only bother to really add the tax to the treasury if not npc owned
|
|
}
|
|
amount -= adenTax; // Subtract Aden's income from current castle instance's income
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
addToTreasuryNoTax(amount);
|
|
}
|
|
|
|
/**
|
|
* Add amount to castle instance's treasury (warehouse), no tax paying.
|
|
* @param amount
|
|
* @return
|
|
*/
|
|
public boolean addToTreasuryNoTax(long amount)
|
|
{
|
|
if (getOwnerId() <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (amount < 0)
|
|
{
|
|
amount *= -1;
|
|
if (_treasury < amount)
|
|
{
|
|
return false;
|
|
}
|
|
_treasury -= amount;
|
|
}
|
|
else
|
|
{
|
|
if ((_treasury + amount) > Inventory.MAX_ADENA)
|
|
{
|
|
_treasury = Inventory.MAX_ADENA;
|
|
}
|
|
else
|
|
{
|
|
_treasury += amount;
|
|
}
|
|
}
|
|
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("UPDATE castle SET treasury = ? WHERE id = ?"))
|
|
{
|
|
ps.setLong(1, getTreasury());
|
|
ps.setInt(2, getResidenceId());
|
|
ps.execute();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, e.getMessage(), e);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Move non clan members off castle area and to nearest town.
|
|
*/
|
|
public void banishForeigners()
|
|
{
|
|
getResidenceZone().banishForeigners(getOwnerId());
|
|
}
|
|
|
|
/**
|
|
* Return true if object is inside the zone
|
|
* @param x
|
|
* @param y
|
|
* @param z
|
|
* @return
|
|
*/
|
|
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 L2CastleZone getResidenceZone()
|
|
{
|
|
return (L2CastleZone) super.getResidenceZone();
|
|
}
|
|
|
|
public L2ResidenceTeleportZone getTeleZone()
|
|
{
|
|
if (_teleZone == null)
|
|
{
|
|
for (L2ResidenceTeleportZone zone : ZoneManager.getInstance().getAllZones(L2ResidenceTeleportZone.class))
|
|
{
|
|
if (zone.getResidenceId() == getResidenceId())
|
|
{
|
|
_teleZone = zone;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return _teleZone;
|
|
}
|
|
|
|
public void oustAllPlayers()
|
|
{
|
|
getTeleZone().oustAllPlayers();
|
|
}
|
|
|
|
/**
|
|
* Get the objects distance to this castle
|
|
* @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.getClanId() != getOwnerId())
|
|
{
|
|
return;
|
|
}
|
|
|
|
L2DoorInstance door = getDoor(doorId);
|
|
if (door != null)
|
|
{
|
|
if (open)
|
|
{
|
|
door.openMe();
|
|
}
|
|
else
|
|
{
|
|
door.closeMe();
|
|
}
|
|
}
|
|
}
|
|
|
|
// This method is used to begin removing all castle upgrades
|
|
public void removeUpgrade()
|
|
{
|
|
removeDoorUpgrade();
|
|
removeTrapUpgrade();
|
|
for (Integer fc : _function.keySet())
|
|
{
|
|
removeFunction(fc);
|
|
}
|
|
_function.clear();
|
|
}
|
|
|
|
// This method updates the castle tax rate
|
|
public void setOwner(L2Clan clan)
|
|
{
|
|
// Remove old owner
|
|
if ((getOwnerId() > 0) && ((clan == null) || (clan.getId() != getOwnerId())))
|
|
{
|
|
L2Clan oldOwner = ClanTable.getInstance().getClan(getOwnerId()); // Try to find clan instance
|
|
if (oldOwner != null)
|
|
{
|
|
if (_formerOwner == null)
|
|
{
|
|
_formerOwner = oldOwner;
|
|
if (Config.REMOVE_CASTLE_CIRCLETS)
|
|
{
|
|
CastleManager.getInstance().removeCirclet(_formerOwner, getResidenceId());
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
oldOwner.setCastleId(0); // Unset has castle flag for old owner
|
|
for (L2PcInstance member : oldOwner.getOnlineMembers(0))
|
|
{
|
|
removeResidentialSkills(member);
|
|
member.sendSkillList();
|
|
member.broadcastUserInfo();
|
|
}
|
|
}
|
|
}
|
|
|
|
updateOwnerInDB(clan); // Update in database
|
|
setShowNpcCrest(false);
|
|
|
|
// if clan have fortress, remove it
|
|
if ((clan != null) && (clan.getFortId() > 0))
|
|
{
|
|
FortManager.getInstance().getFortByOwner(clan).removeOwner(true);
|
|
}
|
|
|
|
if (getSiege().isInProgress())
|
|
{
|
|
getSiege().midVictory(); // Mid victory phase of siege
|
|
}
|
|
|
|
if (clan != null)
|
|
{
|
|
for (L2PcInstance member : clan.getOnlineMembers(0))
|
|
{
|
|
giveResidentialSkills(member);
|
|
member.sendSkillList();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void removeOwner(L2Clan clan)
|
|
{
|
|
if (clan != null)
|
|
{
|
|
_formerOwner = clan;
|
|
if (Config.REMOVE_CASTLE_CIRCLETS)
|
|
{
|
|
CastleManager.getInstance().removeCirclet(_formerOwner, getResidenceId());
|
|
}
|
|
for (L2PcInstance member : clan.getOnlineMembers(0))
|
|
{
|
|
removeResidentialSkills(member);
|
|
member.sendSkillList();
|
|
}
|
|
clan.setCastleId(0);
|
|
clan.broadcastToOnlineMembers(new PledgeShowInfoUpdate(clan));
|
|
}
|
|
|
|
setSide(CastleSide.NEUTRAL);
|
|
updateOwnerInDB(null);
|
|
if (getSiege().isInProgress())
|
|
{
|
|
getSiege().midVictory();
|
|
}
|
|
|
|
for (Integer fc : _function.keySet())
|
|
{
|
|
removeFunction(fc);
|
|
}
|
|
_function.clear();
|
|
}
|
|
|
|
/**
|
|
* Respawn all doors on castle grounds.
|
|
*/
|
|
public void spawnDoor()
|
|
{
|
|
spawnDoor(false);
|
|
}
|
|
|
|
/**
|
|
* Respawn all doors on castle grounds<BR>
|
|
* <BR>
|
|
* @param isDoorWeak
|
|
*/
|
|
public void spawnDoor(boolean isDoorWeak)
|
|
{
|
|
for (L2DoorInstance door : _doors)
|
|
{
|
|
if (door.isDead())
|
|
{
|
|
door.doRevive();
|
|
door.setCurrentHp((isDoorWeak) ? (door.getMaxHp() / 2) : (door.getMaxHp()));
|
|
}
|
|
|
|
if (door.getOpen())
|
|
{
|
|
door.closeMe();
|
|
}
|
|
}
|
|
}
|
|
|
|
// This method loads castle
|
|
@Override
|
|
protected void load()
|
|
{
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps1 = con.prepareStatement("SELECT * FROM castle WHERE id = ?");
|
|
PreparedStatement ps2 = con.prepareStatement("SELECT clan_id FROM clan_data WHERE hasCastle = ?"))
|
|
{
|
|
ps1.setInt(1, getResidenceId());
|
|
try (ResultSet rs = ps1.executeQuery())
|
|
{
|
|
while (rs.next())
|
|
{
|
|
setName(rs.getString("name"));
|
|
// _OwnerId = rs.getInt("ownerId");
|
|
|
|
_siegeDate = Calendar.getInstance();
|
|
_siegeDate.setTimeInMillis(rs.getLong("siegeDate"));
|
|
_siegeTimeRegistrationEndDate = Calendar.getInstance();
|
|
_siegeTimeRegistrationEndDate.setTimeInMillis(rs.getLong("regTimeEnd"));
|
|
_isTimeRegistrationOver = rs.getBoolean("regTimeOver");
|
|
|
|
_castleSide = Enum.valueOf(CastleSide.class, rs.getString("side"));
|
|
|
|
_treasury = rs.getLong("treasury");
|
|
|
|
_showNpcCrest = rs.getBoolean("showNpcCrest");
|
|
|
|
_ticketBuyCount = rs.getInt("ticketBuyCount");
|
|
}
|
|
}
|
|
|
|
setTaxRate(getTaxPercent() / 100);
|
|
ps2.setInt(1, getResidenceId());
|
|
try (ResultSet rs = ps2.executeQuery())
|
|
{
|
|
while (rs.next())
|
|
{
|
|
_ownerId = rs.getInt("clan_id");
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, "Exception: loadCastleData(): " + e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
/** Load All Functions */
|
|
private void loadFunctions()
|
|
{
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("SELECT * FROM castle_functions WHERE castle_id = ?"))
|
|
{
|
|
ps.setInt(1, getResidenceId());
|
|
try (ResultSet rs = ps.executeQuery())
|
|
{
|
|
while (rs.next())
|
|
{
|
|
_function.put(rs.getInt("type"), new CastleFunction(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: Castle.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 castle_functions WHERE castle_id=? AND type=?"))
|
|
{
|
|
ps.setInt(1, getResidenceId());
|
|
ps.setInt(2, functionType);
|
|
ps.execute();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.SEVERE, "Exception: Castle.removeFunctions(int functionType): " + e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
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 CastleFunction(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 CastleFunction(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 castle door data from database
|
|
private void loadDoor()
|
|
{
|
|
for (L2DoorInstance door : DoorData.getInstance().getDoors())
|
|
{
|
|
if ((door.getCastle() != null) && (door.getCastle().getResidenceId() == getResidenceId()))
|
|
{
|
|
_doors.add(door);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This method loads castle door upgrade data from database
|
|
private void loadDoorUpgrade()
|
|
{
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("SELECT * FROM castle_doorupgrade WHERE castleId=?"))
|
|
{
|
|
ps.setInt(1, getResidenceId());
|
|
try (ResultSet rs = ps.executeQuery())
|
|
{
|
|
while (rs.next())
|
|
{
|
|
setDoorUpgrade(rs.getInt("doorId"), rs.getInt("ratio"), false);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, "Exception: loadCastleDoorUpgrade(): " + e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
private void removeDoorUpgrade()
|
|
{
|
|
for (L2DoorInstance door : _doors)
|
|
{
|
|
door.getStat().setUpgradeHpRatio(1);
|
|
door.setCurrentHp(door.getCurrentHp());
|
|
}
|
|
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("DELETE FROM castle_doorupgrade WHERE castleId=?"))
|
|
{
|
|
ps.setInt(1, getResidenceId());
|
|
ps.execute();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, "Exception: removeDoorUpgrade(): " + e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public void setDoorUpgrade(int doorId, int ratio, boolean save)
|
|
{
|
|
final L2DoorInstance door = (getDoors().isEmpty()) ? DoorData.getInstance().getDoor(doorId) : getDoor(doorId);
|
|
if (door == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
door.getStat().setUpgradeHpRatio(ratio);
|
|
door.setCurrentHp(door.getMaxHp());
|
|
|
|
if (save)
|
|
{
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("REPLACE INTO castle_doorupgrade (doorId, ratio, castleId) values (?,?,?)"))
|
|
{
|
|
ps.setInt(1, doorId);
|
|
ps.setInt(2, ratio);
|
|
ps.setInt(3, getResidenceId());
|
|
ps.execute();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, "Exception: setDoorUpgrade(int doorId, int ratio, int castleId): " + e.getMessage(), e);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void updateOwnerInDB(L2Clan clan)
|
|
{
|
|
if (clan != null)
|
|
{
|
|
_ownerId = clan.getId(); // Update owner id property
|
|
}
|
|
else
|
|
{
|
|
_ownerId = 0; // Remove owner
|
|
CastleManorManager.getInstance().resetManorData(getResidenceId());
|
|
}
|
|
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection())
|
|
{
|
|
// Need to remove has castle flag from clan_data, should be checked from castle table.
|
|
try (PreparedStatement ps = con.prepareStatement("UPDATE clan_data SET hasCastle = 0 WHERE hasCastle = ?"))
|
|
{
|
|
ps.setInt(1, getResidenceId());
|
|
ps.execute();
|
|
}
|
|
|
|
try (PreparedStatement ps = con.prepareStatement("UPDATE clan_data SET hasCastle = ? WHERE clan_id = ?"))
|
|
{
|
|
ps.setInt(1, getResidenceId());
|
|
ps.setInt(2, getOwnerId());
|
|
ps.execute();
|
|
}
|
|
|
|
// Announce to clan members
|
|
if (clan != null)
|
|
{
|
|
clan.setCastleId(getResidenceId()); // Set has castle flag for new owner
|
|
clan.broadcastToOnlineMembers(new PledgeShowInfoUpdate(clan));
|
|
clan.broadcastToOnlineMembers(new PlaySound(1, "Siege_Victory", 0, 0, 0, 0, 0));
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, "Exception: updateOwnerInDB(L2Clan clan): " + e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
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<L2DoorInstance> getDoors()
|
|
{
|
|
return _doors;
|
|
}
|
|
|
|
public final int getOwnerId()
|
|
{
|
|
return _ownerId;
|
|
}
|
|
|
|
public final L2Clan getOwner()
|
|
{
|
|
return (_ownerId != 0) ? ClanTable.getInstance().getClan(_ownerId) : null;
|
|
}
|
|
|
|
public final Siege getSiege()
|
|
{
|
|
if (_siege == null)
|
|
{
|
|
_siege = new Siege(this);
|
|
}
|
|
return _siege;
|
|
}
|
|
|
|
public final Calendar getSiegeDate()
|
|
{
|
|
return _siegeDate;
|
|
}
|
|
|
|
public boolean getIsTimeRegistrationOver()
|
|
{
|
|
return _isTimeRegistrationOver;
|
|
}
|
|
|
|
public void setIsTimeRegistrationOver(boolean val)
|
|
{
|
|
_isTimeRegistrationOver = val;
|
|
}
|
|
|
|
public Calendar getTimeRegistrationOverDate()
|
|
{
|
|
if (_siegeTimeRegistrationEndDate == null)
|
|
{
|
|
_siegeTimeRegistrationEndDate = Calendar.getInstance();
|
|
}
|
|
return _siegeTimeRegistrationEndDate;
|
|
}
|
|
|
|
public final int getTaxPercent()
|
|
{
|
|
final int taxPercent;
|
|
switch (getSide())
|
|
{
|
|
case LIGHT:
|
|
taxPercent = Config.CASTLE_TAX_LIGHT;
|
|
break;
|
|
case DARK:
|
|
taxPercent = Config.CASTLE_TAX_DARK;
|
|
break;
|
|
default:
|
|
taxPercent = Config.CASTLE_TAX_NEUTRAL;
|
|
break;
|
|
}
|
|
return taxPercent;
|
|
}
|
|
|
|
public void setTaxRate(double taxRate)
|
|
{
|
|
_taxRate = taxRate;
|
|
}
|
|
|
|
public final double getTaxRate()
|
|
{
|
|
return _taxRate;
|
|
}
|
|
|
|
public final long getTreasury()
|
|
{
|
|
return _treasury;
|
|
}
|
|
|
|
public final boolean getShowNpcCrest()
|
|
{
|
|
return _showNpcCrest;
|
|
}
|
|
|
|
public final void setShowNpcCrest(boolean showNpcCrest)
|
|
{
|
|
if (_showNpcCrest != showNpcCrest)
|
|
{
|
|
_showNpcCrest = showNpcCrest;
|
|
updateShowNpcCrest();
|
|
}
|
|
}
|
|
|
|
public void updateClansReputation()
|
|
{
|
|
if (_formerOwner != null)
|
|
{
|
|
if (_formerOwner != ClanTable.getInstance().getClan(getOwnerId()))
|
|
{
|
|
int maxreward = Math.max(0, _formerOwner.getReputationScore());
|
|
_formerOwner.takeReputationScore(Config.LOOSE_CASTLE_POINTS, true);
|
|
L2Clan owner = ClanTable.getInstance().getClan(getOwnerId());
|
|
if (owner != null)
|
|
{
|
|
owner.addReputationScore(Math.min(Config.TAKE_CASTLE_POINTS, maxreward), true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_formerOwner.addReputationScore(Config.CASTLE_DEFENDED_POINTS, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
L2Clan owner = ClanTable.getInstance().getClan(getOwnerId());
|
|
if (owner != null)
|
|
{
|
|
owner.addReputationScore(Config.TAKE_CASTLE_POINTS, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void updateShowNpcCrest()
|
|
{
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("UPDATE castle SET showNpcCrest = ? WHERE id = ?"))
|
|
{
|
|
ps.setString(1, String.valueOf(getShowNpcCrest()));
|
|
ps.setInt(2, getResidenceId());
|
|
ps.execute();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.info("Error saving showNpcCrest for castle " + getName() + ": " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register Artefact to castle
|
|
* @param artefact
|
|
*/
|
|
public void registerArtefact(L2ArtefactInstance artefact)
|
|
{
|
|
_artefacts.add(artefact);
|
|
}
|
|
|
|
public List<L2ArtefactInstance> getArtefacts()
|
|
{
|
|
return _artefacts;
|
|
}
|
|
|
|
/**
|
|
* @return the tickets exchanged for this castle
|
|
*/
|
|
public int getTicketBuyCount()
|
|
{
|
|
return _ticketBuyCount;
|
|
}
|
|
|
|
/**
|
|
* Set the exchanged tickets count.<br>
|
|
* Performs database update.
|
|
* @param count the ticket count to set
|
|
*/
|
|
public void setTicketBuyCount(int count)
|
|
{
|
|
_ticketBuyCount = count;
|
|
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("UPDATE castle SET ticketBuyCount = ? WHERE id = ?"))
|
|
{
|
|
ps.setInt(1, _ticketBuyCount);
|
|
ps.setInt(2, getResidenceId());
|
|
ps.execute();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
public int getTrapUpgradeLevel(int towerIndex)
|
|
{
|
|
final TowerSpawn spawn = SiegeManager.getInstance().getFlameTowers(getResidenceId()).get(towerIndex);
|
|
return (spawn != null) ? spawn.getUpgradeLevel() : 0;
|
|
}
|
|
|
|
public void setTrapUpgrade(int towerIndex, int level, boolean save)
|
|
{
|
|
if (save)
|
|
{
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("REPLACE INTO castle_trapupgrade (castleId, towerIndex, level) values (?,?,?)"))
|
|
{
|
|
ps.setInt(1, getResidenceId());
|
|
ps.setInt(2, towerIndex);
|
|
ps.setInt(3, level);
|
|
ps.execute();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, "Exception: setTrapUpgradeLevel(int towerIndex, int level, int castleId): " + e.getMessage(), e);
|
|
}
|
|
}
|
|
final TowerSpawn spawn = SiegeManager.getInstance().getFlameTowers(getResidenceId()).get(towerIndex);
|
|
if (spawn != null)
|
|
{
|
|
spawn.setUpgradeLevel(level);
|
|
}
|
|
}
|
|
|
|
private void removeTrapUpgrade()
|
|
{
|
|
for (TowerSpawn ts : SiegeManager.getInstance().getFlameTowers(getResidenceId()))
|
|
{
|
|
ts.setUpgradeLevel(0);
|
|
}
|
|
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("DELETE FROM castle_trapupgrade WHERE castleId=?"))
|
|
{
|
|
ps.setInt(1, getResidenceId());
|
|
ps.execute();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, "Exception: removeDoorUpgrade(): " + e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void initResidenceZone()
|
|
{
|
|
for (L2CastleZone zone : ZoneManager.getInstance().getAllZones(L2CastleZone.class))
|
|
{
|
|
if (zone.getResidenceId() == getResidenceId())
|
|
{
|
|
setResidenceZone(zone);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void giveResidentialSkills(L2PcInstance player)
|
|
{
|
|
super.giveResidentialSkills(player);
|
|
final Skill skill = getSide() == CastleSide.DARK ? CommonSkill.ABILITY_OF_DARKNESS.getSkill() : CommonSkill.ABILITY_OF_LIGHT.getSkill();
|
|
player.addSkill(skill);
|
|
}
|
|
|
|
@Override
|
|
public void removeResidentialSkills(L2PcInstance player)
|
|
{
|
|
super.removeResidentialSkills(player);
|
|
player.removeSkill(CommonSkill.ABILITY_OF_DARKNESS.getId());
|
|
player.removeSkill(CommonSkill.ABILITY_OF_LIGHT.getId());
|
|
}
|
|
|
|
public void spawnSideNpcs()
|
|
{
|
|
_sideNpcs.stream().filter(Objects::nonNull).forEach(L2Npc::deleteMe);
|
|
_sideNpcs.clear();
|
|
|
|
for (CastleSpawnHolder holder : getSideSpawns())
|
|
{
|
|
if (holder != null)
|
|
{
|
|
final L2NpcTemplate npcTemplate = NpcData.getInstance().getTemplate(holder.getNpcId());
|
|
if (npcTemplate == null)
|
|
{
|
|
_log.warning(Castle.class.getSimpleName() + ": Spawn of the nonexisting NPC ID: " + holder.getNpcId());
|
|
return;
|
|
}
|
|
|
|
L2Spawn spawn;
|
|
try
|
|
{
|
|
spawn = new L2Spawn(npcTemplate);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.warning(Castle.class.getSimpleName() + ": " + e.getMessage());
|
|
return;
|
|
}
|
|
spawn.setX(holder.getX());
|
|
spawn.setY(holder.getY());
|
|
spawn.setZ(holder.getZ());
|
|
spawn.setHeading(holder.getHeading());
|
|
final L2Npc npc = spawn.doSpawn(false);
|
|
npc.broadcastInfo();
|
|
_sideNpcs.add(npc);
|
|
}
|
|
}
|
|
}
|
|
|
|
public List<CastleSpawnHolder> getSideSpawns()
|
|
{
|
|
return CastleData.getInstance().getSpawnsForSide(getResidenceId(), getSide());
|
|
}
|
|
|
|
public void setSide(CastleSide side)
|
|
{
|
|
if (_castleSide == side)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try (Connection con = L2DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("UPDATE castle SET side = ? WHERE id = ?"))
|
|
{
|
|
ps.setString(1, side.toString());
|
|
ps.setInt(2, getResidenceId());
|
|
ps.execute();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, e.getMessage(), e);
|
|
}
|
|
_castleSide = side;
|
|
setTaxRate(getTaxPercent() / 100);
|
|
Broadcast.toAllOnlinePlayers(new ExCastleState(this));
|
|
spawnSideNpcs();
|
|
}
|
|
|
|
public CastleSide getSide()
|
|
{
|
|
return _castleSide;
|
|
}
|
|
}
|