Pārlūkot izejas kodu

Castle siege time fixes by Gigii-kun:
- Castle Sieges are on the weekend before the seal validation period end.
- Castle Lords can set next siege time for 24h after the siege and only once.
- Admin command for siege time change.

Comments:
- after the update the first siege time wont be changed if it is in seal validation period, change will occur only if it is in Quest event period. Day of Week will change only after the first siege!
- be careful with regular server restarts, do not allow CL to set siege time right before server restarts! For this edit the Feature.properties config file!

Sami 16 gadi atpakaļ
vecāks
revīzija
79a0eebcc8

+ 12 - 0
L2_GameServer/java/config/Feature.properties

@@ -15,6 +15,18 @@
 #============================================================#
 #                        Castle                              #
 #============================================================#
+# -----------------------------------------
+# Siege Time set rules
+# -----------------------------------------
+
+# Which values can change Castle Lords
+#   default : day,hour,minute
+CLSetSiegeTimeList = day,hour,minute
+
+# Which hours can change Castle Lords
+#   default : 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
+SiegeHourList = 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
+
 # correct values are unknown, temporally used from clanhalls
 #-------------------------------------------------------------
 # Teleport Function price

+ 49 - 1
L2_GameServer/java/net/sf/l2j/Config.java

@@ -290,6 +290,9 @@ public final class Config
     public static int 		CS_SUPPORT2_FEE;
     public static int 		CS_SUPPORT3_FEE;
     public static int 		CS_SUPPORT4_FEE;
+    public static List<String> CL_SET_SIEGE_TIME_LIST;
+    public static List<Integer> SIEGE_HOUR_LIST_MORNING;
+    public static List<Integer> SIEGE_HOUR_LIST_AFTERNOON;
     
     /** ************************************************** **/
 	/** Castlel Settings -End                             **/
@@ -1003,7 +1006,52 @@ public final class Config
                 
                 
                 //
-				CS_TELE_FEE_RATIO                                   = Long.parseLong(Feature.getProperty("CastleTeleportFunctionFeeRatio", "604800000"));
+                CL_SET_SIEGE_TIME_LIST = new FastList<String>();
+                SIEGE_HOUR_LIST_MORNING = new FastList<Integer>();
+        		SIEGE_HOUR_LIST_AFTERNOON = new FastList<Integer>();
+        		String[] sstl = Feature.getProperty("CLSetSiegeTimeList", "").split(",");
+                if (sstl.length != 0)
+                {
+                	boolean isHour = false;
+                	for (String st : sstl)
+                	{
+                		if (st.equalsIgnoreCase("day") || st.equalsIgnoreCase("hour") || st.equalsIgnoreCase("minute"))
+                		{
+                			if (st.equalsIgnoreCase("hour")) isHour = true;
+                			CL_SET_SIEGE_TIME_LIST.add(st.toLowerCase());
+                		}
+                		else
+                		{
+                			System.out.println("[CLSetSiegeTimeList]: invalid config property -> CLSetSiegeTimeList \"" + st + "\"");
+                		}
+                	}
+                	if (isHour)
+                	{
+                		String[] shl = Feature.getProperty("SiegeHourList", "").split(","); 
+                    	for (String st : shl)
+                    	{
+                    		if (!st.equalsIgnoreCase(""))
+                    		{
+                        		int val = Integer.valueOf(st);
+                        		if (val > 23 || val < 0)
+                        			System.out.println("[SiegeHourList]: invalid config property -> SiegeHourList \"" + st + "\"");
+                        		else if (val < 12)
+                        			SIEGE_HOUR_LIST_MORNING.add(val);
+                        		else
+                        		{
+                        			val -= 12;
+                        			SIEGE_HOUR_LIST_AFTERNOON.add(val);
+                        		}	
+                    		}                    			
+                    	}                			
+                    	if (Config.SIEGE_HOUR_LIST_AFTERNOON.isEmpty() && Config.SIEGE_HOUR_LIST_AFTERNOON.isEmpty())
+                    	{
+                			System.out.println("[SiegeHourList]: invalid config property -> SiegeHourList is empty");
+                    		CL_SET_SIEGE_TIME_LIST.remove("hour");
+                    	}
+                	}
+                }
+                CS_TELE_FEE_RATIO                                   = Long.parseLong(Feature.getProperty("CastleTeleportFunctionFeeRatio", "604800000"));
                 CS_TELE1_FEE                                        = Integer.parseInt(Feature.getProperty("CastleTeleportFunctionFeeLvl1", "7000"));
                 CS_TELE2_FEE                                        = Integer.parseInt(Feature.getProperty("CastleTeleportFunctionFeeLvl2", "14000"));
                 CS_SUPPORT_FEE_RATIO                                = Long.parseLong(Feature.getProperty("CastleSupportFunctionFeeRatio", "86400000"));

+ 50 - 0
L2_GameServer/java/net/sf/l2j/gameserver/SevenSigns.java

@@ -20,6 +20,7 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.Calendar;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 import java.util.logging.Logger;
 
@@ -33,6 +34,7 @@ import net.sf.l2j.gameserver.model.AutoSpawnHandler;
 import net.sf.l2j.gameserver.model.L2World;
 import net.sf.l2j.gameserver.model.AutoSpawnHandler.AutoSpawnInstance;
 import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
+import net.sf.l2j.gameserver.model.entity.Castle;
 import net.sf.l2j.gameserver.network.SystemMessageId;
 import net.sf.l2j.gameserver.network.serverpackets.SSQInfo;
 import net.sf.l2j.gameserver.network.serverpackets.SystemMessage;
@@ -482,6 +484,47 @@ public class SevenSigns
 	{
 		return (_activePeriod == PERIOD_COMP_RESULTS);
 	}
+	
+	/**
+	 * returns true if the given date is in Seal Validation or in Quest Event Results period 
+	 * @param date
+	 */
+	public boolean isDateInSealValidPeriod(Calendar date)
+	{
+        long nextPeriodChange = getMilliToPeriodChange();
+        long nextQuestStart = 0;
+        long nextValidStart = 0;
+        long tillDate = date.getTimeInMillis() - Calendar.getInstance().getTimeInMillis();
+        while ((2 * PERIOD_MAJOR_LENGTH + 2 * PERIOD_MINOR_LENGTH) < tillDate)
+        	tillDate -= (2 * PERIOD_MAJOR_LENGTH + 2 * PERIOD_MINOR_LENGTH);
+        while (tillDate < 0)
+        	tillDate += (2 * PERIOD_MAJOR_LENGTH + 2 * PERIOD_MINOR_LENGTH);
+        
+		switch (getCurrentPeriod())
+		{
+			case PERIOD_COMP_RECRUITING:
+				nextValidStart = nextPeriodChange + PERIOD_MAJOR_LENGTH;
+				nextQuestStart = nextValidStart + PERIOD_MAJOR_LENGTH + PERIOD_MINOR_LENGTH;
+				break;
+			case PERIOD_COMPETITION:
+				nextValidStart = nextPeriodChange;
+				nextQuestStart = nextPeriodChange + PERIOD_MAJOR_LENGTH + PERIOD_MINOR_LENGTH;
+				break;
+			case PERIOD_COMP_RESULTS:
+				nextQuestStart = nextPeriodChange + PERIOD_MAJOR_LENGTH;
+				nextValidStart = nextQuestStart + PERIOD_MAJOR_LENGTH + PERIOD_MINOR_LENGTH;
+				break;
+			case PERIOD_SEAL_VALIDATION:
+				nextQuestStart = nextPeriodChange;
+				nextValidStart = nextPeriodChange + PERIOD_MAJOR_LENGTH + PERIOD_MINOR_LENGTH;				
+				break;
+		}
+		
+		if ((nextQuestStart < tillDate && tillDate < nextValidStart) ||
+				(nextValidStart < nextQuestStart && (tillDate < nextValidStart || nextQuestStart < tillDate)))
+			return false;
+		return true;
+	}
 
 	public final int getCurrentScore(int cabal)
 	{
@@ -1410,6 +1453,13 @@ public class SevenSigns
             _log.info("SevenSigns: The " + getCurrentPeriodName() + " period has begun!");
 
             setCalendarForNextPeriodChange();
+            
+            // make sure that all the scheduled siege dates are in the Seal Validation period
+            List<Castle> castles = CastleManager.getInstance().getCastles();
+            for (Castle castle : castles)
+            {
+            	castle.getSiege().correctSiegeDateTime();
+            }
 
 	        SevenSignsPeriodChange sspc = new SevenSignsPeriodChange();
 	        ThreadPoolManager.getInstance().scheduleGeneral(sspc, getMilliToPeriodChange());

+ 62 - 0
L2_GameServer/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminSiege.java

@@ -14,9 +14,11 @@
  */
 package net.sf.l2j.gameserver.handler.admincommandhandlers;
 
+import java.util.Calendar;
 import java.util.StringTokenizer;
 
 import javolution.text.TextBuilder;
+import net.sf.l2j.gameserver.SevenSigns;
 import net.sf.l2j.gameserver.datatables.ClanTable;
 import net.sf.l2j.gameserver.handler.IAdminCommandHandler;
 import net.sf.l2j.gameserver.instancemanager.AuctionManager;
@@ -52,6 +54,7 @@ public class AdminSiege implements IAdminCommandHandler
 		"admin_spawn_doors",
 		"admin_endsiege",
 		"admin_startsiege",
+		"admin_setsiegetime",
 		"admin_setcastle",
 		"admin_removecastle",
 		"admin_clanhall",
@@ -146,6 +149,31 @@ public class AdminSiege implements IAdminCommandHandler
 				else
 					activeChar.sendMessage("Unable to remove castle");
 			}
+			else if (command.equalsIgnoreCase("admin_setsiegetime"))
+			{
+				if (st.hasMoreTokens())
+				{
+					Calendar newAdminSiegeDate = castle.getSiegeDate();
+					if (val.equalsIgnoreCase("day"))
+						newAdminSiegeDate.set(Calendar.DAY_OF_YEAR, Integer.parseInt(st.nextToken()));						
+					else if (val.equalsIgnoreCase("hour"))
+						newAdminSiegeDate.set(Calendar.HOUR_OF_DAY, Integer.parseInt(st.nextToken()));
+					else if (val.equalsIgnoreCase("min"))
+						newAdminSiegeDate.set(Calendar.MINUTE, Integer.parseInt(st.nextToken()));
+
+					if (newAdminSiegeDate.getTimeInMillis() < Calendar.getInstance().getTimeInMillis())
+					{
+						activeChar.sendMessage("Unable to change Siege Date");
+					}
+					else if (newAdminSiegeDate.getTimeInMillis() != castle.getSiegeDate().getTimeInMillis())
+					{
+						castle.getSiegeDate().setTimeInMillis(newAdminSiegeDate.getTimeInMillis());
+						// castle.getSiege().saveSiegeDate();
+					}
+				}
+				showSiegeTimePage(activeChar,castle);
+				return true;
+			}
 			else if (command.equalsIgnoreCase("admin_clanhallset"))
 			{
 				if (player == null || player.getClan() == null)
@@ -269,6 +297,40 @@ public class AdminSiege implements IAdminCommandHandler
 		activeChar.sendPacket(adminReply);
 	}
 	
+	private void showSiegeTimePage(L2PcInstance activeChar, Castle castle)
+	{
+		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
+		adminReply.setFile("data/html/admin/castlesiegetime.htm");
+		adminReply.replace("%castleName%", castle.getName());
+		adminReply.replace("%time%", castle.getSiegeDate().getTime().toString());
+		Calendar newDay = Calendar.getInstance();
+		boolean isSunday = false;
+		if (newDay.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
+			isSunday = true;
+		else
+			newDay.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
+		if (!SevenSigns.getInstance().isDateInSealValidPeriod(newDay))
+			newDay.add(Calendar.DAY_OF_MONTH, 7);
+		
+		if (isSunday)
+		{
+			adminReply.replace("%sundaylink%", String.valueOf(newDay.get(Calendar.DAY_OF_YEAR)));
+			adminReply.replace("%sunday%", String.valueOf(newDay.get(Calendar.MONTH) + "/" + String.valueOf(newDay.get(Calendar.DAY_OF_MONTH))));
+			newDay.add(Calendar.DAY_OF_MONTH, 13);
+			adminReply.replace("%saturdaylink%", String.valueOf(newDay.get(Calendar.DAY_OF_YEAR)));
+			adminReply.replace("%saturday%", String.valueOf(newDay.get(Calendar.MONTH) + "/" + String.valueOf(newDay.get(Calendar.DAY_OF_MONTH))));
+		}
+		else
+		{
+			adminReply.replace("%saturdaylink%", String.valueOf(newDay.get(Calendar.DAY_OF_YEAR)));
+			adminReply.replace("%saturday%", String.valueOf(newDay.get(Calendar.MONTH) + "/" + String.valueOf(newDay.get(Calendar.DAY_OF_MONTH))));			
+			newDay.add(Calendar.DAY_OF_MONTH, 1);
+			adminReply.replace("%sundaylink%", String.valueOf(newDay.get(Calendar.DAY_OF_YEAR)));
+			adminReply.replace("%sunday%", String.valueOf(newDay.get(Calendar.MONTH) + "/" + String.valueOf(newDay.get(Calendar.DAY_OF_MONTH))));
+		}
+		activeChar.sendPacket(adminReply);
+	}
+
 	private void showClanHallPage(L2PcInstance activeChar, ClanHall clanhall)
 	{
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);

+ 138 - 0
L2_GameServer/java/net/sf/l2j/gameserver/model/actor/instance/L2CastleChamberlainInstance.java

@@ -15,6 +15,8 @@
 package net.sf.l2j.gameserver.model.actor.instance;
 
 import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.StringTokenizer;
 
@@ -57,6 +59,8 @@ public class L2CastleChamberlainInstance extends L2MerchantInstance
 	protected static final int COND_ALL_FALSE = 0;
 	protected static final int COND_BUSY_BECAUSE_OF_SIEGE = 1;
 	protected static final int COND_OWNER = 2;
+	private int _preDay;
+	private int _preHour;
 
 	public L2CastleChamberlainInstance(int objectId, L2NpcTemplate template)
 	{
@@ -1246,9 +1250,143 @@ public class L2CastleChamberlainInstance extends L2MerchantInstance
 				doTeleport(player, whereTo);
 				return;
 			}
+			else if (actualCommand.equalsIgnoreCase("siege_change")) // siege day set
+			{
+				if (Config.CL_SET_SIEGE_TIME_LIST.isEmpty())
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(1);
+					html.setFile("data/html/chamberlain/chamberlain-noadmin.htm");
+					sendHtmlMessage(player, html);
+				}
+				else if (player.isClanLeader())
+				{
+					if (getCastle().getSiege().getTimeRegistrationOverDate().getTimeInMillis() < Calendar.getInstance().getTimeInMillis())
+					{
+						NpcHtmlMessage html = new NpcHtmlMessage(1);
+						html.setFile("data/html/chamberlain/siegetime1.htm");
+						sendHtmlMessage(player, html);						
+					}
+					else if (getCastle().getSiege().getIsTimeRegistrationOver()) 
+					{
+						NpcHtmlMessage html = new NpcHtmlMessage(1);
+						html.setFile("data/html/chamberlain/siegetime2.htm");
+						sendHtmlMessage(player, html);						
+					}
+					else
+					{
+						NpcHtmlMessage html = new NpcHtmlMessage(1);
+						html.setFile("data/html/chamberlain/siegetime3.htm");
+						html.replace("%time%", String.valueOf(getCastle().getSiegeDate().getTime()));
+						sendHtmlMessage(player, html);						
+					}
+				}
+				else
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(1);
+					html.setFile("data/html/chamberlain/chamberlain-noprivs.htm");
+					sendHtmlMessage(player, html);
+				}
+			}
+			else if (actualCommand.equalsIgnoreCase("siege_time_set")) // set preDay
+			{
+				boolean isAfternoon = Config.SIEGE_HOUR_LIST_MORNING.isEmpty();
+				switch (Integer.parseInt(val))
+				{
+					case 0:
+					case 4:
+						break;
+					case 1:
+						_preDay = Integer.parseInt(st.nextToken());
+						break;
+					case 2:
+						isAfternoon = Boolean.parseBoolean(st.nextToken());
+						break;
+					case 3:
+						_preHour = Integer.parseInt(st.nextToken());
+						break;
+					default:
+						break;
+				}
+				NpcHtmlMessage html = getNextSiegeTimePage(Integer.parseInt(val),isAfternoon);
+				
+				if (html == null)
+				{
+					if (Config.CL_SET_SIEGE_TIME_LIST.contains("day"))
+						getCastle().getSiegeDate().set(Calendar.DAY_OF_WEEK, _preDay);
+					if (Config.CL_SET_SIEGE_TIME_LIST.contains("hour"))
+						getCastle().getSiegeDate().set(Calendar.HOUR_OF_DAY, _preHour);
+					if (Config.CL_SET_SIEGE_TIME_LIST.contains("minute"))
+						getCastle().getSiegeDate().set(Calendar.MINUTE, Integer.parseInt(st.nextToken()));
+					// now store the changed time and finished next Siege Time registration
+					getCastle().getSiege().endTimeRegistration(false);
+					
+					html = new NpcHtmlMessage(1);
+					html.setFile("data/html/chamberlain/siegetime8.htm");
+					html.replace("%time%", String.valueOf(getCastle().getSiegeDate().getTime()));
+				}
+				sendHtmlMessage(player, html);				
+			}
+
 			super.onBypassFeedback(player, command);
 		}
 	}
+	
+	private NpcHtmlMessage getNextSiegeTimePage(int now, boolean isAfternoon)
+	{
+		NpcHtmlMessage ret = new NpcHtmlMessage(1);
+		if (now == 0 && Config.CL_SET_SIEGE_TIME_LIST.contains("day"))
+		{
+			ret.setFile("data/html/chamberlain/siegetime4.htm");
+			return ret;
+		}
+		if (now < 3 && Config.CL_SET_SIEGE_TIME_LIST.contains("hour"))
+		{
+			switch (now)
+			{
+				case 0:
+				case 1:
+					if (!Config.SIEGE_HOUR_LIST_MORNING.isEmpty() && !Config.SIEGE_HOUR_LIST_AFTERNOON.isEmpty())
+					{
+						ret.setFile("data/html/chamberlain/siegetime5.htm");
+						return ret;
+					}
+				case 2:
+					ret.setFile("data/html/chamberlain/siegetime6.htm");
+					List<Integer> list;
+					int inc = 0;
+					String ampm = "";
+					
+					if (!isAfternoon)
+					{
+						if (Config.SIEGE_HOUR_LIST_AFTERNOON.isEmpty()) ampm = "AM";
+						list = Config.SIEGE_HOUR_LIST_MORNING;
+					}
+					else
+					{
+						if (Config.SIEGE_HOUR_LIST_MORNING.isEmpty()) ampm = "PM";
+						inc = 12;
+						list = Config.SIEGE_HOUR_LIST_AFTERNOON;
+					}
+					TextBuilder tList = new TextBuilder();
+					for (Integer hour : list)
+					{
+						if (hour == 0) 
+							tList.append("<a action=\"bypass -h npc_%objectId%_siege_time_set 3 " + String.valueOf(hour + inc) + "\">" + String.valueOf(hour + 12) + ":00 " + ampm + "</a><br>");
+						else
+							tList.append("<a action=\"bypass -h npc_%objectId%_siege_time_set 3 " + String.valueOf(hour + inc) + "\">" + String.valueOf(hour) + ":00 " + ampm + "</a><br>");
+					}
+					ret.replace("%links%", tList.toString());
+			}
+			return ret;
+		}
+		if (now < 4 && Config.CL_SET_SIEGE_TIME_LIST.contains("minute"))
+		{
+			ret.setFile("data/html/chamberlain/siegetime7.htm");
+			return ret;
+		}
+		
+		return null;
+	}
 
 	private void sendHtmlMessage(L2PcInstance player, String htmlMessage)
 	{

+ 16 - 14
L2_GameServer/java/net/sf/l2j/gameserver/model/entity/Castle.java

@@ -74,8 +74,8 @@ public class Castle
 	private int _ownerId = 0;
 	private Siege _siege = null;
 	private Calendar _siegeDate;
-	private int _siegeDayOfWeek = 7; // Default to saturday
-	private int _siegeHourOfDay = 20; // Default to 8 pm server time
+    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 int _taxPercent = 0;
 	private double _taxRate = 0;
 	private int _treasury = 0;
@@ -667,14 +667,9 @@ public class Castle
 				
 				_siegeDate = Calendar.getInstance();
 				_siegeDate.setTimeInMillis(rs.getLong("siegeDate"));
-				
-				_siegeDayOfWeek = rs.getInt("siegeDayOfWeek");
-				if (_siegeDayOfWeek < 1 || _siegeDayOfWeek > 7)
-					_siegeDayOfWeek = 7;
-				
-				_siegeHourOfDay = rs.getInt("siegeHourOfDay");
-				if (_siegeHourOfDay < 0 || _siegeHourOfDay > 23)
-					_siegeHourOfDay = 20;
+				_siegeTimeRegistrationEndDate = Calendar.getInstance();
+				_siegeTimeRegistrationEndDate.setTimeInMillis(rs.getLong("regTimeEnd"));
+        	    _isTimeRegistrationOver = rs.getBoolean("regTimeOver");
 				
 				_taxPercent = rs.getInt("taxPercent");
 				_treasury = rs.getInt("treasury");
@@ -1063,14 +1058,21 @@ public class Castle
 		return _siegeDate;
 	}
 	
-	public final int getSiegeDayOfWeek()
+	public boolean getIsTimeRegistrationOver()
+	{
+		return _isTimeRegistrationOver;
+	}
+	
+	public void setIsTimeRegistrationOver(boolean val)
 	{
-		return _siegeDayOfWeek;
+		_isTimeRegistrationOver = val;
+		return;
 	}
 	
-	public final int getSiegeHourOfDay()
+	public Calendar getTimeRegistrationOverDate()
 	{
-		return _siegeHourOfDay;
+		if (_siegeTimeRegistrationEndDate == null) _siegeTimeRegistrationEndDate = Calendar.getInstance();
+		return _siegeTimeRegistrationEndDate;
 	}
 	
 	public final int getTaxPercent()

+ 75 - 30
L2_GameServer/java/net/sf/l2j/gameserver/model/entity/Siege.java

@@ -19,11 +19,13 @@ import java.sql.ResultSet;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.ScheduledFuture;
 import java.util.logging.Logger;
 
 import javolution.util.FastList;
 import net.sf.l2j.L2DatabaseFactory;
 import net.sf.l2j.gameserver.Announcements;
+import net.sf.l2j.gameserver.SevenSigns;
 import net.sf.l2j.gameserver.ThreadPoolManager;
 import net.sf.l2j.gameserver.datatables.ClanTable;
 import net.sf.l2j.gameserver.datatables.MapRegionTable;
@@ -167,42 +169,57 @@ public class Siege
 		
 		public void run()
 		{
+			_scheduledStartSiegeTask.cancel(false);
 			if (getIsInProgress())
 				return;
 			
 			try
 			{
+	           	if (!getIsTimeRegistrationOver())
+            	{
+                	long regTimeRemaining = getTimeRegistrationOverDate().getTimeInMillis() - Calendar.getInstance().getTimeInMillis();
+                	if (regTimeRemaining > 0)
+                	{
+                		_scheduledStartSiegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), regTimeRemaining);
+                		return;
+                	}
+                	else
+                	{
+                		endTimeRegistration(true);
+                	}
+            	}
+
 				long timeRemaining = getSiegeDate().getTimeInMillis() - Calendar.getInstance().getTimeInMillis();
 				if (timeRemaining > 86400000)
 				{
-					ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining - 86400000); // Prepare task for 24 before siege start to end registration
+					_scheduledStartSiegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining - 86400000); // Prepare task for 24 before siege start to end registration
 				}
 				else if ((timeRemaining <= 86400000) && (timeRemaining > 13600000))
 				{
 					announceToPlayer("The registration term for " + getCastle().getName() + " has ended.", false);
 					_isRegistrationOver = true;
 					clearSiegeWaitingClan();
-					ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining - 13600000); // Prepare task for 1 hr left before siege start.
+					_scheduledStartSiegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining - 13600000); // Prepare task for 1 hr left before siege start.
 				}
 				else if ((timeRemaining <= 13600000) && (timeRemaining > 600000))
 				{
 					announceToPlayer(Math.round(timeRemaining / 60000) + " minute(s) until " + getCastle().getName() + " siege begin.", false);
-					ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining - 600000); // Prepare task for 10 minute left.
+					_scheduledStartSiegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining - 600000); // Prepare task for 10 minute left.
 				}
 				else if ((timeRemaining <= 600000) && (timeRemaining > 300000))
 				{
 					announceToPlayer(Math.round(timeRemaining / 60000) + " minute(s) until " + getCastle().getName() + " siege begin.", false);
-					ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining - 300000); // Prepare task for 5 minute left.
+					_scheduledStartSiegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining - 300000); // Prepare task for 5 minute left.
 				}
 				else if ((timeRemaining <= 300000) && (timeRemaining > 10000))
 				{
 					announceToPlayer(Math.round(timeRemaining / 60000) + " minute(s) until " + getCastle().getName() + " siege begin.", false);
-					ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining - 10000); // Prepare task for 10 seconds count down
+					_scheduledStartSiegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining - 10000); // Prepare task for 10 seconds count down
 				}
 				else if ((timeRemaining <= 10000) && (timeRemaining > 0))
 				{
 					announceToPlayer(getCastle().getName() + " siege " + Math.round(timeRemaining / 1000) + " second(s) to start!", false);
-					ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining); // Prepare task for second count down
+					_scheduledStartSiegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartSiegeTask(_castleInst), timeRemaining); // Prepare task for second count down
 				}
 				else
 				{
@@ -233,7 +250,7 @@ public class Siege
 	protected boolean _isRegistrationOver = false;
 	protected Calendar _siegeEndDate;
 	private SiegeGuardManager _siegeGuardManager;
-	protected Calendar _siegeRegistrationEndDate;
+	protected ScheduledFuture<?> _scheduledStartSiegeTask = null;
 	
 	// =========================================================
 	// Constructor
@@ -416,6 +433,7 @@ public class Siege
 					sm = new SystemMessage(SystemMessageId.S1_SIEGE_WAS_CANCELED_BECAUSE_NO_CLANS_PARTICIPATED);
 				sm.addString(getCastle().getName());
 				Announcements.getInstance().announceToAll(sm);
+				saveCastleSiege();
 				return;
 			}
 			
@@ -859,13 +877,10 @@ public class Siege
 		
 		loadSiegeClan();
 		
-		// Schedule registration end
-		_siegeRegistrationEndDate = Calendar.getInstance();
-		_siegeRegistrationEndDate.setTimeInMillis(getCastle().getSiegeDate().getTimeInMillis());
-		_siegeRegistrationEndDate.add(Calendar.DAY_OF_MONTH, -1);
-		
 		// Schedule siege auto start
-		ThreadPoolManager.getInstance().scheduleGeneral(new Siege.ScheduleStartSiegeTask(getCastle()), 1000);
+		if (_scheduledStartSiegeTask != null)
+			_scheduledStartSiegeTask.cancel(false);
+		_scheduledStartSiegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new Siege.ScheduleStartSiegeTask(getCastle()), 1000);
 	}
 	
 	/**
@@ -992,32 +1007,26 @@ public class Siege
 	 * Return the correct siege date as Calendar.<BR><BR>
 	 * @param siegeDate The Calendar siege date and time
 	 */
-	private void correctSiegeDateTime()
+	public void correctSiegeDateTime()
 	{
 		boolean corrected = false;
 		
 		if (getCastle().getSiegeDate().getTimeInMillis() < Calendar.getInstance().getTimeInMillis())
 		{
-			// Since siege has past reschedule it to the next one (14 days)
+			// Since siege has past reschedule it to the next one
 			// This is usually caused by server being down
 			corrected = true;
 			setNextSiegeDate();
 		}
 		
-		if (getCastle().getSiegeDate().get(Calendar.DAY_OF_WEEK) != getCastle().getSiegeDayOfWeek())
-		{
-			corrected = true;
-			getCastle().getSiegeDate().set(Calendar.DAY_OF_WEEK, getCastle().getSiegeDayOfWeek());
-		}
-		
-		if (getCastle().getSiegeDate().get(Calendar.HOUR_OF_DAY) != getCastle().getSiegeHourOfDay())
+		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;
-			getCastle().getSiegeDate().set(Calendar.HOUR_OF_DAY, getCastle().getSiegeHourOfDay());
+			setNextSiegeDate();
 		}
 		
-		getCastle().getSiegeDate().set(Calendar.MINUTE, 0);
-		
 		if (corrected)
 			saveSiegeDate();
 	}
@@ -1121,20 +1130,32 @@ public class Siege
 	private void saveCastleSiege()
 	{
 		setNextSiegeDate(); // Set the next set date for 2 weeks from now
+		// Schedule Time registration end
+		getTimeRegistrationOverDate().setTimeInMillis(Calendar.getInstance().getTimeInMillis());
+		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. */
-	private void saveSiegeDate()
+	public void saveSiegeDate()
 	{
+		if (_scheduledStartSiegeTask != null)
+		{
+			_scheduledStartSiegeTask.cancel(true);
+			_scheduledStartSiegeTask = ThreadPoolManager.getInstance().scheduleGeneral(new Siege.ScheduleStartSiegeTask(getCastle()), 1000);
+		}
 		java.sql.Connection con = null;
 		try
 		{
 			con = L2DatabaseFactory.getInstance().getConnection();
-			PreparedStatement statement = con.prepareStatement("Update castle set siegeDate = ? where id = ?");
+			PreparedStatement statement = con.prepareStatement("Update castle set siegeDate = ?, regTimeEnd = ?, regTimeOver = ?  where id = ?");
 			statement.setLong(1, getSiegeDate().getTimeInMillis());
-			statement.setInt(2, getCastle().getCastleId());
+			statement.setLong(2, getTimeRegistrationOverDate().getTimeInMillis());
+			statement.setString(3, String.valueOf(getIsTimeRegistrationOver()));
+			statement.setInt(4, getCastle().getCastleId());
 			statement.execute();
 			
 			statement.close();
@@ -1239,9 +1260,16 @@ public class Siege
 	{
 		while (getCastle().getSiegeDate().getTimeInMillis() < Calendar.getInstance().getTimeInMillis())
 		{
-			// Set next siege date if siege has passed
-			getCastle().getSiegeDate().add(Calendar.DAY_OF_MONTH, 14); // Schedule to happen in 14 days
+			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);
+			// 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
 	}
 	
@@ -1407,11 +1435,28 @@ public class Siege
 		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();
+	}
+	
 	public List<L2NpcInstance> getFlag(L2Clan clan)
 	{
 		if (clan != null)