public class FortressSiege extends Siege
{
private final GArray<L2CommanderInstance> _commanders;
private final HashMap<L2ItemInstance, Location> _flags;
private ScheduledFuture<?> _commanderRespawnTask = null;
private final int addRepNewOwner = Config.CLANREP_SIEGE_FORT_NEW_OWNER;
private final int addRepOldOwner = Config.CLANREP_SIEGE_FORT_NEW_OWNER;
private final int addRepLoss = Config.CLANREP_SIEGE_FORT_NEW_OWNER;
public FortressSiege(final Fortress siegeUnit)
{
super(siegeUnit);
_database = new FortressSiegeDatabase(this);
_siegeGuardManager = new SiegeGuardManager(getSiegeUnit());
_database.loadSiegeClan();
_commanders = new GArray<L2CommanderInstance>();
_flags = new HashMap<L2ItemInstance, Location>();
}
public void startSiege()
{
if(!_isInProgress)
{
_database.loadSiegeClan();
// FIXME тут наверно ничего писать не надо
if(getAttackerClans().isEmpty())
{
if(getSiegeUnit().getOwnerId() <= 0)
announceToPlayer(new SystemMessage(SystemMessage.THE_SIEGE_OF_S1_HAS_BEEN_CANCELED_DUE_TO_LACK_OF_INTEREST).addString(getSiegeUnit().getName()), false, ANNOUNCE_TO_BOTH_SIDES);
else
announceToPlayer(new SystemMessage(SystemMessage.S1S_SIEGE_WAS_CANCELED_BECAUSE_THERE_WERE_NO_CLANS_THAT_PARTICIPATED).addString(getSiegeUnit().getName()), false, ANNOUNCE_TO_BOTH_SIDES);
return;
}
getZone().setActive(true);
_isInProgress = true; // Flag so that same siege instance cannot be started again
_isMidVictory = true;
_ownerBeforeStart = getSiegeUnit().getOwnerId();
updateSiegeClans(); // update list
updatePlayerSiegeStateFlags(false);
teleportPlayer(TeleportWhoType.Attacker, TeleportWhereType.ClosestTown); // Teleport to the closest town
teleportPlayer(TeleportWhoType.Spectator, TeleportWhereType.ClosestTown); // Teleport to the closest town
// Despawn commanders (Npcs)
despawnCommanderNpc();
// Spawn commander
spawnCommanders();
getSiegeUnit().spawnDoor(); // Spawn door
getSiegeGuardManager().spawnSiegeGuard(); // Spawn siege guard
getSiegeUnit().setVisibleFlag(false);
MercTicketManager.getInstance().deleteTickets(getSiegeUnit().getId()); // remove the tickets from the ground
_defenderRespawnPenalty = 0; // Reset respawn delay
// Schedule a task to prepare auto siege end
_siegeEndDate = Calendar.getInstance();
_siegeEndDate.add(Calendar.MINUTE, getSiegeLength());
L2GameThreadPools.getInstance().scheduleGeneral(new FortressSiegeEndTask(this), getSiegeLength() * 60 * 1000); // Prepare auto end task
_fameTask = L2GameThreadPools.getInstance().scheduleGeneralAtFixedRate(new SiegeFameTask(), Config.FORTRESS_ZONE_FAME_TASK_FREQUENCY, Config.FORTRESS_ZONE_FAME_TASK_FREQUENCY);
// Sends a system message to all attacking clans and to the owning clan of this Fort Siege.
announceToPlayer(new SystemMessage(SystemMessage.THE_FORTRESS_BATTLE_S1_HAS_BEGAN).addString(getSiegeUnit().getName()), false, ANNOUNCE_TO_BOTH_SIDES);
}
}
public void midVictory()
{
// Если осада закончилась
if(!isInProgress() || getSiegeUnit().getOwnerId() <= 0)
return;
// Поменять местами атакующих и защитников
for(final SiegeClan sc : getDefenderClans().values())
if(sc != null)
{
removeSiegeClan(sc, SiegeClanType.DEFENDER);
addSiegeClan(sc, SiegeClanType.ATTACKER);
}
final SiegeClan sc_newowner = getAttackerClan(getSiegeUnit().getOwner());
removeSiegeClan(sc_newowner, SiegeClanType.ATTACKER);
addSiegeClan(sc_newowner, SiegeClanType.OWNER);
endSiege();
}
public void endSiege()
{
getZone().setActive(false);
if(isInProgress())
{
announceToPlayer(new SystemMessage(SystemMessage.THE_FORTRESS_BATTLE_OF_S1_HAS_FINISHED).addString(getSiegeUnit().getName()), false, ANNOUNCE_TO_BOTH_SIDES);
if(getSiegeUnit().getOwnerId() <= 0)
announceToPlayer(new SystemMessage(SystemMessage.THE_SIEGE_OF_S1_HAS_ENDED_IN_A_DRAW).addString(getSiegeUnit().getName()), false, ANNOUNCE_TO_BOTH_SIDES);
else
{
L2Clan oldOwner = null;
if(_ownerBeforeStart != 0)
oldOwner = ClanTable.getInstance().getClan(_ownerBeforeStart);
final L2Clan newOwner = ClanTable.getInstance().getClan(getSiegeUnit().getOwnerId());
if(oldOwner == null)
{ // castle was taken over from scratch
if(newOwner.getLevel() >= 5)
newOwner.broadcastToOnlineMembers(new SystemMessage(SystemMessage.SINCE_YOUR_CLAN_EMERGED_VICTORIOUS_FROM_THE_SIEGE_S1_POINTS_HAVE_BEEN_ADDED_TO_YOUR_CLAN_REPUTATION_SCORE).addNumber(newOwner.incReputation(addRepNewOwner, true, "CastleSiege")));
SiegeManager.clearFortressRegistrations(newOwner);
}
else if(newOwner.equals(oldOwner))
{ // castle was defended
if(newOwner.getLevel() >= 5)
newOwner.broadcastToOnlineMembers(new SystemMessage(SystemMessage.SINCE_YOUR_CLAN_EMERGED_VICTORIOUS_FROM_THE_SIEGE_S1_POINTS_HAVE_BEEN_ADDED_TO_YOUR_CLAN_REPUTATION_SCORE).addNumber(newOwner.incReputation(addRepOldOwner, true, "CastleSiege")));
SiegeManager.clearFortressRegistrations(newOwner);
}
else
{ // castle was taken over by another clan
announceToPlayer(new SystemMessage(SystemMessage.S1_CLAN_IS_VICTORIOUS_IN_THE_FORTRESS_BATLE_OF_S2).addString(newOwner.getName()).addString(getSiegeUnit().getName()), false, ANNOUNCE_TO_BOTH_SIDES);
if(newOwner.getLevel() >= 5)
newOwner.broadcastToOnlineMembers(new SystemMessage(SystemMessage.SINCE_YOUR_CLAN_EMERGED_VICTORIOUS_FROM_THE_SIEGE_S1_POINTS_HAVE_BEEN_ADDED_TO_YOUR_CLAN_REPUTATION_SCORE).addNumber(newOwner.incReputation(addRepNewOwner, true, "CastleSiege")));
if(oldOwner.getLevel() >= 5)
oldOwner.broadcastToOnlineMembers(new SystemMessage(SystemMessage.YOUR_CLAN_HAS_FAILED_TO_DEFEND_THE_CASTLE_S1_POINTS_HAVE_BEEN_DEDUCTED_FROM_YOUR_CLAN_REPUTATION_SCORE).addNumber(-oldOwner.incReputation(-addRepLoss, Config.USE_REDUCE_REPSCORE_RATE, "CastleSiege")));
SiegeManager.clearFortressRegistrations(newOwner);
}
for(final L2NpcInstance envoyNpc : FortressSiegeManager.getEnvoyNpcsList(getSiegeUnit().getId()))
if(envoyNpc != null)
envoyNpc.spawnMe();
}
if(getSiegeUnit().getOwner() != null && getSiegeUnit().getFlagPole().getMeshIndex() == 0)
getSiegeUnit().setVisibleFlag(true);
unspawnCommanders(); // Remove commander from this fort
spawnCommanderNpc();
removeHeadquarters();
unSpawnFlags();
teleportPlayer(TeleportWhoType.Attacker, TeleportWhereType.ClosestTown); // Teleport to the closest town
teleportPlayer(TeleportWhoType.Spectator, TeleportWhereType.ClosestTown); // Teleport to the closest town
removeSiegeSummons();
_isInProgress = false; // Flag so that siege instance can be started
updatePlayerSiegeStateFlags(true);
saveSiege(); // Save castle specific data
_database.clearSiegeClan(); // Clear siege clan from db
getSiegeGuardManager().unspawnSiegeGuard(); // Remove all spawned siege guard from this castle
SiegeGuardManager.removeMercsFromDb(getSiegeUnit().getId());
getSiegeUnit().spawnDoor(); // Respawn door to castle
if(_ownerBeforeStart != getSiegeUnit().getOwnerId())
getSiegeUnit().setOwnDate((int) (System.currentTimeMillis() / 1000L));
getSiegeUnit().saveOwnDate();
clearSiegeClans();
if(_siegeStartTask != null)
{
_siegeStartTask.cancel(false);
_siegeStartTask = null;
}
if(_fameTask != null)
{
_fameTask.cancel(true);
_fameTask = null;
}
setRegistrationOver(false);
}
}
public void engrave(final L2Clan clan, final int objId)
{
if(clan.getHasCastle() > 0)
{
getSiegeUnit().changeOwner(null);
announceToPlayer(new SystemMessage(SystemMessage.THE_REBEL_ARMY_RECAPTURED_THE_FORTRESS), false, ANNOUNCE_TO_BOTH_SIDES);
}
else
getSiegeUnit().changeOwner(clan);
}
public void registerAttacker(final L2Player player, final boolean force)
{
super.registerAttacker(player, force);
startAutoTask(false);
}
/**
* Start the auto tasks<BR>
* <BR>
*/
public void startAutoTask(final boolean isServerStarted)
{
if(getAttackerClans().isEmpty() || _siegeStartTask != null)
return;
_siegeDate.setTimeInMillis(((Fortress) getSiegeUnit()).getSiegeDate() * 1000L);
setNextSiegeDate();
// Schedule registration end
_siegeRegistrationEndDate = Calendar.getInstance();
_siegeRegistrationEndDate.setTimeInMillis(_siegeDate.getTimeInMillis());
_siegeRegistrationEndDate.add(Calendar.MINUTE, -10);
// Если сервер только что стартовал, осада начнется не ранее чем через час
if(isServerStarted)
{
final Calendar minDate = Calendar.getInstance();
minDate.add(Calendar.HOUR_OF_DAY, 1);
_siegeDate.setTimeInMillis(Math.max(minDate.getTimeInMillis(), _siegeDate.getTimeInMillis()));
_database.saveSiegeDate();
// Если был рестарт во время осады, даем зарегистрироваться еще раз
if(_siegeDate.getTimeInMillis() <= minDate.getTimeInMillis())
{
setRegistrationOver(false);
_siegeRegistrationEndDate.setTimeInMillis(_siegeDate.getTimeInMillis());
_siegeRegistrationEndDate.add(Calendar.MINUTE, -10);
}
}
// отправляем сообщение клану который владеет фортом
if(getSiegeUnit().getOwner() != null)
{
final L2Clan owner = getSiegeUnit().getOwner();
owner.broadcastToOnlineMembers(Msg.A_FORTRESS_IS_UNDER_ATTACK);
}
_log.info("Siege of " + getSiegeUnit().getName() + " - " + Util.datetimeFormatter.format(_siegeDate.getTime()));
// Schedule siege auto start, через 1 час
_siegeStartTask = L2GameThreadPools.getInstance().scheduleGeneral(new FortressSiegeStartTask(this, 3600), 1000);
}
/** Set the date for the next siege. */
protected void setNextSiegeDate()
{
if(_siegeDate.getTimeInMillis() < Calendar.getInstance().getTimeInMillis())
{
_siegeDate = Calendar.getInstance();
// Осада не чаще, чем каждые 4 часа + 1 час на подготовку.
if(Calendar.getInstance().getTimeInMillis() - getSiegeUnit().getLastSiegeDate() * 1000 > 14400000)
_siegeDate.add(Calendar.HOUR_OF_DAY, 1);
else
{
_siegeDate.setTimeInMillis(getSiegeUnit().getLastSiegeDate() * 1000);
_siegeDate.add(Calendar.HOUR_OF_DAY, 5);
}
_database.saveSiegeDate();
}
}
protected void correctSiegeDateTime()
{}
protected void saveSiege()
{
// Выставляем дату прошедшей осады
getSiegeUnit().setLastSiegeDate((int) (getSiegeDate().getTimeInMillis() / 1000));
// Сохраняем дату прошедшей осады
_database.saveLastSiegeDate();
}
/** Display list of registered clans */
public void listRegisterClan(final L2Player player)
{
player.sendPacket(new SiegeInfo(getSiegeUnit()));
}
/** Один из командиров убит */
public void killedCommander(final L2CommanderInstance ct)
{
_commanders.remove(ct);
operateGuardDoors(true, _commanders.size());
if(_commanders.size() <= 0)
{
// spawn fort flags
spawnFlags();
// open doors in main building
operateCommandCenterDoors(true);
announceToPlayer(Msg.ALL_BARRACKS_ARE_OCCUPIED, false, Siege.ANNOUNCE_TO_BOTH_SIDES);
if(_commanderRespawnTask != null)
_commanderRespawnTask.cancel(true);
_commanderRespawnTask = null;
}
else
{
announceToPlayer(Msg.THE_BARRACKS_HAVE_BEEN_SEIZED, false, Siege.ANNOUNCE_TO_BOTH_SIDES);
if(_commanderRespawnTask == null)
_commanderRespawnTask = L2GameThreadPools.getInstance().scheduleGeneral(new CommanderRespawnTask(), 600000);
}
}
private final class CommanderRespawnTask implements Runnable
{
public void run()
{
if(isInProgress())
{
announceToPlayer(Msg.THE_BARRACKS_FUNCTION_HAS_BEEN_RESTORED, false, Siege.ANNOUNCE_TO_BOTH_SIDES);
unspawnCommanders();
spawnCommanders();
}
_commanderRespawnTask = null;
}
}
private void unspawnCommanders()
{
for(final L2CommanderInstance commander : _commanders)
if(commander != null)
commander.deleteMe();
_commanders.clear();
}
private void spawnCommanders()
{
for(final SiegeSpawn sp : FortressSiegeManager.getCommanderSpawnList(getSiegeUnit().getId()))
{
final L2CommanderInstance commander = new L2CommanderInstance(IdFactory.getInstance().getNextId(), NpcTable.getTemplate(sp.getNpcId()));
commander.setCurrentHpMp(commander.getMaxHp(), commander.getMaxMp(), true);
commander.setXYZInvisible(sp.getLoc().correctGeoZ());
commander.setSpawnedLoc(commander.getLoc());
commander.setHeading(sp.getLoc().h);
commander.spawnMe();
_commanders.add(commander);
}
}
public void operateGuardDoors(final boolean open, final int commanders_count)
{
FortressSiegeManager.getGuardDoors(getSiegeUnit().getId()).forEachEntry(new TIntIntProcedure()
{
private L2DoorInstance door;
public boolean execute(final int doorId, final int command_count)
{
if(command_count < commanders_count)
return true;
door = getSiegeUnit().getDoor(doorId);
if(door != null)
if(open)
door.openMe();
else
door.closeMe();
return true;
}
});
}
public void operateCommandCenterDoors(final boolean open)
{
for(final int doorId : FortressSiegeManager.getCommandCenterDoors(getSiegeUnit().getId()))
{
final L2DoorInstance door = getSiegeUnit().getDoor(doorId);
if(door != null)
if(open)
door.openMe();
else
door.closeMe();
}
}
public void returnFlag(final L2Player dropper, final L2ItemInstance flag)
{
final Location loc = _flags.get(flag);
if(loc != null)
flag.dropMe(dropper, loc);
// на всякий случай
else
flag.dropMe(dropper, dropper.getLoc().rnd(0, 100, false));
}
private void spawnFlags()
{
L2ItemInstance flag;
for(final SiegeSpawn sp : FortressSiegeManager.getFlagsList(getSiegeUnit().getId()))
{
flag = ItemTable.getInstance().createItem(sp.getNpcId(), 0, 0, "FortressSiege");
flag.setCustomFlags(L2ItemInstance.FLAG_EQUIP_ON_PICKUP | L2ItemInstance.FLAG_NO_DESTROY | L2ItemInstance.FLAG_NO_TRADE | L2ItemInstance.FLAG_NO_UNEQUIP, false);
flag.setXYZInvisible(sp.getLoc().correctGeoZ());
flag.spawnMe();
_flags.put(flag, sp.getLoc().correctGeoZ());
}
}
private void unSpawnFlags()
{
for(L2ItemInstance flag : _flags.keySet())
if(flag != null)
{
if(flag.getOwnerId() > 0)
{
final L2Player owner = L2ObjectsStorage.getPlayer(flag.getOwnerId());
if(owner != null)
flag = owner.getInventory().dropItem(flag, flag.getCount(), true);
}
flag.deleteMe();
}
_flags.clear();
}
public void announceToPlayer(final SystemMessage message, final boolean inAreaOnly, final byte announceType)
{
L2Clan clan;
for(final SiegeClan siegeClans : getAttackerClans().values())
{
clan = ClanTable.getInstance().getClan(siegeClans.getClanId());
for(final L2Player member : clan.getOnlineMembers(0))
if(member != null)
member.sendPacket(message);
}
clan = getSiegeUnit().getOwner();
if(clan != null)
for(final L2Player member : clan.getOnlineMembers(0))
if(member != null)
member.sendPacket(message);
}
/**
* Despawn commanders (Npcs)
*/
public final void despawnCommanderNpc()
{
// Despawn commanders (Npcs)
for(final L2NpcInstance commanderNpc : FortressSiegeManager.getCommanderNpcsList(getSiegeUnit().getId()))
if(commanderNpc != null)
commanderNpc.decayMe();
}
/**
* Spawn commanders (Npcs)
*/
public final void spawnCommanderNpc()
{
for(final L2NpcInstance commanderNpc : FortressSiegeManager.getCommanderNpcsList(getSiegeUnit().getId()))
if(commanderNpc != null)
commanderNpc.spawnMe();
}
public final boolean getIsInProgress()
{
return _isInProgress;
}
public GArray<L2CommanderInstance> getCommanders()
{
return _commanders;
}
}