Browse Source

Faror's 2nd part of fortresses implementation up to 18/09/08. All information on this thread: http://www.l2jserver.com/forum/thread.php?threadid=31217
Thank you Faror and all people that has worked on this patch

DrHouse 16 years ago
parent
commit
eea28540b9

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

@@ -222,6 +222,56 @@ ClanHallCurtainFunctionFeeLvl2 = 2500
 ClanHallFrontPlatformFunctionFeeLvl1 = 1300
 ClanHallFrontPlatformFunctionFeeLvl2 = 4000
 
+#============================================================#
+#                        Fortress                            #
+#============================================================#
+# values are taken from http://lineage2.naturalbornkillers.it
+#-------------------------------------------------------------
+# Teleport Function price
+# Price = 7 day
+#-------------------------------------------------------------
+# 1st level
+FortressTeleportFunctionFeeLvl1 = 1000
+# 2nd level
+FortressTeleportFunctionFeeLvl2 = 10000
+
+#-------------------------------------------------------------
+# Support magic buff price
+# Price = 1 day
+#-------------------------------------------------------------
+# 1st level
+FortressSupportFeeLvl1 = 7000
+# 2nd level
+FortressSupportFeeLvl2 = 17000
+
+#-------------------------------------------------------------
+# MP Regeneration price
+# Price = 1 day
+#-------------------------------------------------------------
+# 40% MpRegeneration
+FortressMpRegenerationFeeLvl1 = 6500
+# 50% MpRegeneration
+FortressMpRegenerationFeeLvl2 = 9300
+
+#-------------------------------------------------------------
+# Hp Regeneration price
+# Price = 1 day
+#-------------------------------------------------------------
+
+# 300% HpRegeneration
+FortressHpRegenerationFeeLvl1 = 2000
+# 400% HpRegeneration
+FortressHpRegenerationFeeLvl2 = 3500
+
+#-------------------------------------------------------------
+# Exp Regeneration price
+# Price = 1 day
+#-------------------------------------------------------------
+# 45% ExpRegeneration
+FortressExpRegenerationFeeLvl1 = 9000
+# 50% ExpRegeneration
+FortressExpRegenerationFeeLvl2 = 10000
+
 #============================================================#
 #                        Seven Signs                         #
 #============================================================#

+ 44 - 3
L2_GameServer/java/net/sf/l2j/Config.java

@@ -263,7 +263,7 @@ public final class Config
 	/** ************************************************** **/
 
     /** ************************************************** **/
-	/** Castle Settings -Begin                           **/
+	/** Castle Settings -Begin                             **/
 	/** ************************************************** **/
 
     public static long 		CS_TELE_FEE_RATIO;
@@ -295,9 +295,33 @@ public final class Config
     public static List<Integer> SIEGE_HOUR_LIST_AFTERNOON;
     
     /** ************************************************** **/
-	/** Castlel Settings -End                             **/
+	/** Castle Settings -End                               **/
+	/** ************************************************** **/
+    
+    /** ************************************************** **/
+	/** Fortress Settings -Begin                           **/
 	/** ************************************************** **/
 
+    public static long 		FS_TELE_FEE_RATIO;
+    public static int 		FS_TELE1_FEE;
+    public static int 		FS_TELE2_FEE;
+    public static long 		FS_MPREG_FEE_RATIO;
+    public static int 		FS_MPREG1_FEE;
+    public static int 		FS_MPREG2_FEE;
+    public static long 		FS_HPREG_FEE_RATIO;
+    public static int 		FS_HPREG1_FEE;
+    public static int 		FS_HPREG2_FEE;
+    public static long 		FS_EXPREG_FEE_RATIO;
+    public static int 		FS_EXPREG1_FEE;
+    public static int 		FS_EXPREG2_FEE;
+    public static long 		FS_SUPPORT_FEE_RATIO;
+    public static int 		FS_SUPPORT1_FEE;
+    public static int 		FS_SUPPORT2_FEE;
+    
+    /** ************************************************** **/
+	/** Fortress Settings -End                             **/
+	/** ************************************************** **/
+    
     /** ************************************************** **/
 	/** Feature Settings -Begin                            **/
 	/** ************************************************** **/
@@ -1115,7 +1139,24 @@ public final class Config
 	                CS_EXPREG4_FEE                                      = Integer.parseInt(Feature.getProperty("CastleExpRegenerationFeeLvl4", "30000"));
 	                //
 	                
-	                
+	                //
+	                FS_TELE_FEE_RATIO                                   = Long.parseLong(Feature.getProperty("FortressTeleportFunctionFeeRatio", "604800000"));
+	                FS_TELE1_FEE                                        = Integer.parseInt(Feature.getProperty("FortressTeleportFunctionFeeLvl1", "1000"));
+	                FS_TELE2_FEE                                        = Integer.parseInt(Feature.getProperty("FortressTeleportFunctionFeeLvl2", "10000"));
+	                FS_SUPPORT_FEE_RATIO                                = Long.parseLong(Feature.getProperty("FortressSupportFunctionFeeRatio", "86400000"));
+	                FS_SUPPORT1_FEE                                     = Integer.parseInt(Feature.getProperty("FortressSupportFeeLvl1", "7000"));
+	                FS_SUPPORT2_FEE                                     = Integer.parseInt(Feature.getProperty("FortressSupportFeeLvl2", "17000"));
+	                FS_MPREG_FEE_RATIO                                  = Long.parseLong(Feature.getProperty("FortressMpRegenerationFunctionFeeRatio", "86400000"));
+	                FS_MPREG1_FEE                                       = Integer.parseInt(Feature.getProperty("FortressMpRegenerationFeeLvl1", "6500"));
+	                FS_MPREG2_FEE                                       = Integer.parseInt(Feature.getProperty("FortressMpRegenerationFeeLvl2", "9300"));
+	                FS_HPREG_FEE_RATIO                                  = Long.parseLong(Feature.getProperty("FortressHpRegenerationFunctionFeeRatio", "86400000"));
+	                FS_HPREG1_FEE                                       = Integer.parseInt(Feature.getProperty("FortressHpRegenerationFeeLvl1", "2000"));
+	                FS_HPREG2_FEE                                       = Integer.parseInt(Feature.getProperty("FortressHpRegenerationFeeLvl2", "3500"));
+	                FS_EXPREG_FEE_RATIO                                 = Long.parseLong(Feature.getProperty("FortressExpRegenerationFunctionFeeRatio", "86400000"));
+	                FS_EXPREG1_FEE                                      = Integer.parseInt(Feature.getProperty("FortressExpRegenerationFeeLvl1", "9000"));
+	                FS_EXPREG2_FEE                                      = Integer.parseInt(Feature.getProperty("FortressExpRegenerationFeeLvl2", "10000"));
+	                //
+	                	                
 					ALT_GAME_CASTLE_DAWN    					= Boolean.parseBoolean(Feature.getProperty("AltCastleForDawn", "True"));
 					ALT_GAME_CASTLE_DUSK    					= Boolean.parseBoolean(Feature.getProperty("AltCastleForDusk", "True"));
 	                ALT_GAME_REQUIRE_CLAN_CASTLE    					= Boolean.parseBoolean(Feature.getProperty("AltRequireClanCastle", "False"));

+ 2 - 1
L2_GameServer/java/net/sf/l2j/gameserver/model/L2Character.java

@@ -200,8 +200,9 @@ public abstract class L2Character extends L2Object
 	public static final byte ZONE_CASTLE = 10;
 	public static final byte ZONE_SWAMP = 11;
 	public static final byte ZONE_NOSUMMONFRIEND = 12;
+	public static final byte ZONE_FORT = 13;
 	
-	private final byte[] _zones = new byte[13];
+	private final byte[] _zones = new byte[14];
 	protected byte _zoneValidateCounter = 4;
 
 	private boolean _isRaid = false;

+ 45 - 7
L2_GameServer/java/net/sf/l2j/gameserver/model/actor/instance/L2DoormenInstance.java

@@ -39,6 +39,7 @@ public class L2DoormenInstance extends L2FolkInstance
     private static int COND_BUSY_BECAUSE_OF_SIEGE = 1;
     private static int COND_CASTLE_OWNER = 2;
     private static int COND_HALL_OWNER = 3;
+    private static int COND_FORT_OWNER = 4;
 
     /**
      * @param template
@@ -64,7 +65,7 @@ public class L2DoormenInstance extends L2FolkInstance
         int condition = validateCondition(player);
         if (condition <= COND_ALL_FALSE) return;
         if (condition == COND_BUSY_BECAUSE_OF_SIEGE) return;
-        else if (condition == COND_CASTLE_OWNER || condition == COND_HALL_OWNER)
+        else if (condition == COND_CASTLE_OWNER || condition == COND_HALL_OWNER || condition == COND_FORT_OWNER)
         {
             if (command.startsWith("Chat"))
             {
@@ -80,11 +81,11 @@ public class L2DoormenInstance extends L2FolkInstance
                         "<html><body>You have <font color=\"FF9955\">opened</font> the clan hall door.<br>Outsiders may enter the clan hall while the door is open. Please close it when you've finished your business.<br><center><button value=\"Close\" action=\"bypass -h npc_"
                        + getObjectId() + "_close_doors\" width=80 height=27 back=\"L2UI_CT1.Button_DF_Down\" fore=\"L2UI_CT1.Button_DF\"></center></body></html>"));
                 }
-                else
+                else if (condition == COND_CASTLE_OWNER)
                 {
                     //DoorTable doorTable = DoorTable.getInstance();
                     StringTokenizer st = new StringTokenizer(command.substring(10), ", ");
-                    st.nextToken(); // Bypass first value since its castleid/hallid
+                    st.nextToken(); // Bypass first value since its castleid/hallid/fortid
 
                     if (condition == 2)
                     {
@@ -94,7 +95,21 @@ public class L2DoormenInstance extends L2FolkInstance
                         }
                         return;
                     }
+                }
+                else
+                {
+                	//DoorTable doorTable = DoorTable.getInstance();
+                    StringTokenizer st = new StringTokenizer(command.substring(10), ", ");
+                    st.nextToken(); // Bypass first value since its castleid/hallid/fortid
 
+                    if (condition == 4)
+                    {
+                        while (st.hasMoreTokens())
+                        {
+                            getFort().openDoor(player, Integer.parseInt(st.nextToken()));
+                        }
+                        return;
+                    }
                 }
             }
             else if (command.startsWith("close_doors"))
@@ -106,11 +121,11 @@ public class L2DoormenInstance extends L2FolkInstance
                         "<html><body>You have <font color=\"FF9955\">closed</font> the clan hall door.<br>Good day!<br><center><button value=\"To Beginning\" action=\"bypass -h npc_"
                         + getObjectId() + "_Chat\" width=80 height=27 back=\"L2UI_CT1.Button_DF_Down\" fore=\"L2UI_CT1.Button_DF\"></center></body></html>"));
                 }
-                else
+                else if (condition == COND_CASTLE_OWNER)
                 {
                     //DoorTable doorTable = DoorTable.getInstance();
                     StringTokenizer st = new StringTokenizer(command.substring(11), ", ");
-                    st.nextToken(); // Bypass first value since its castleid/hallid
+                    st.nextToken(); // Bypass first value since its castleid/hallid/fortid
 
                     //L2Clan playersClan = player.getClan();
 
@@ -123,6 +138,23 @@ public class L2DoormenInstance extends L2FolkInstance
                         return;
                     }
                 }
+                else
+                {
+                	//DoorTable doorTable = DoorTable.getInstance();
+                    StringTokenizer st = new StringTokenizer(command.substring(11), ", ");
+                    st.nextToken(); // Bypass first value since its castleid/hallid/fortid
+
+                    //L2Clan playersClan = player.getClan();
+
+                    if (condition == 4)
+                    {
+                        while (st.hasMoreTokens())
+                        {
+                            getFort().closeDoor(player, Integer.parseInt(st.nextToken()));
+                        }
+                        return;
+                    }
+                }
             }
         }
 
@@ -176,9 +208,9 @@ public class L2DoormenInstance extends L2FolkInstance
         int condition = validateCondition(player);
         if (condition == COND_BUSY_BECAUSE_OF_SIEGE) filename = "data/html/doormen/"
             + getTemplate().npcId + "-busy.htm"; // Busy because of siege
-        else if (condition == COND_CASTLE_OWNER) // Clan owns castle
+        else if (condition == COND_CASTLE_OWNER || condition == COND_FORT_OWNER) // Clan owns castle or fort
             filename = "data/html/doormen/" + getTemplate().npcId + ".htm"; // Owner message window
-
+        
         // Prepare doormen for clan hall
         NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
         String str;
@@ -232,6 +264,12 @@ public class L2DoormenInstance extends L2FolkInstance
                 if (getCastle().getOwnerId() == player.getClanId()) // Clan owns castle
                     return COND_CASTLE_OWNER; // Owner
             }
+            
+            if (getFort() != null && getFort().getFortId() > 0)
+            {
+            	if (getFort().getOwnerId() == player.getClanId()) // Clan owns fortress
+            		return COND_FORT_OWNER; // Owner
+            }
         }
 
         return COND_ALL_FALSE;

+ 959 - 0
L2_GameServer/java/net/sf/l2j/gameserver/model/actor/instance/L2FortManagerInstance.java

@@ -0,0 +1,959 @@
+/*
+ * This program 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.
+ * 
+ * This program 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 net.sf.l2j.gameserver.model.actor.instance;
+
+import java.text.SimpleDateFormat;
+import java.util.StringTokenizer;
+
+import net.sf.l2j.Config;
+import net.sf.l2j.gameserver.ai.CtrlIntention;
+import net.sf.l2j.gameserver.datatables.ClanTable;
+import net.sf.l2j.gameserver.datatables.SkillTable;
+import net.sf.l2j.gameserver.datatables.TeleportLocationTable;
+import net.sf.l2j.gameserver.model.L2Clan;
+import net.sf.l2j.gameserver.model.L2Skill;
+import net.sf.l2j.gameserver.model.L2TeleportLocation;
+import net.sf.l2j.gameserver.model.entity.Fort;
+import net.sf.l2j.gameserver.network.serverpackets.ActionFailed;
+import net.sf.l2j.gameserver.network.serverpackets.MyTargetSelected;
+import net.sf.l2j.gameserver.network.serverpackets.NpcHtmlMessage;
+import net.sf.l2j.gameserver.network.serverpackets.ValidateLocation;
+import net.sf.l2j.gameserver.templates.L2NpcTemplate;
+import net.sf.l2j.gameserver.templates.L2SkillType;
+
+/**
+ * Fortress Foreman implementation used for:
+ * Area Teleports, Support Magic, Clan Warehouse, Exp Loss Reduction
+ */
+public class L2FortManagerInstance 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;
+
+	public L2FortManagerInstance(int objectId, L2NpcTemplate template)
+	{
+		super(objectId, template);
+	}
+
+	private void sendHtmlMessage(L2PcInstance player, NpcHtmlMessage html)
+	{
+		html.replace("%objectId%", String.valueOf(getObjectId()));
+		html.replace("%npcId%", String.valueOf(getNpcId()));
+		player.sendPacket(html);
+	}
+
+	@Override
+	public void onAction(L2PcInstance player)
+	{
+		if (!canTarget(player))
+			return;
+
+		player.setLastFolkNPC(this);
+
+		// Check if the L2PcInstance already target the L2NpcInstance
+		if (this != player.getTarget())
+		{
+			// Set the target of the L2PcInstance player
+			player.setTarget(this);
+
+			// Send a Server->Client packet MyTargetSelected to the L2PcInstance player
+			MyTargetSelected my = new MyTargetSelected(getObjectId(), 0);
+			player.sendPacket(my);
+
+			// Send a Server->Client packet ValidateLocation to correct the zL2NpcInstance position and heading on the client
+			player.sendPacket(new ValidateLocation(this));
+		}
+		else
+		{
+			// Calculate the distance between the L2PcInstance and the L2NpcInstance
+			if (!canInteract(player))
+			{
+				// Notify the L2PcInstance AI with AI_INTENTION_INTERACT
+				player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);
+			}
+			else
+			{
+				showMessageWindow(player);
+			}
+		}
+		// Send a Server->Client ActionFailed to the L2PcInstance in order to
+		// avoid that the client wait another packet
+		player.sendPacket(ActionFailed.STATIC_PACKET);
+	}
+
+	@Override
+	public void onBypassFeedback(L2PcInstance player, String command)
+	{
+		// BypassValidation Exploit plug.
+		if (player.getLastFolkNPC().getObjectId() != this.getObjectId())
+			return;
+		SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+		int condition = validateCondition(player);
+		if (condition <= COND_ALL_FALSE)
+			return;
+
+		if (condition == COND_BUSY_BECAUSE_OF_SIEGE)
+			return;
+		else if (condition == COND_OWNER)
+		{
+			StringTokenizer st = new StringTokenizer(command, " ");
+			String actualCommand = st.nextToken(); // Get actual command
+
+			String val = "";
+			if (st.countTokens() >= 1)
+			{
+				val = st.nextToken();
+			}
+
+			if (actualCommand.equalsIgnoreCase("banish_foreigner"))
+			{
+				if ((player.getClanPrivileges() & L2Clan.CP_CS_DISMISS) == L2Clan.CP_CS_DISMISS)
+				{
+					getFort().banishForeigners(); // Move non-clan members off fortress area
+					return;
+				}
+				else
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
+					html.setFile("data/html/fortress/foreman-noprivs.htm");
+					html.replace("%objectId%", String.valueOf(getObjectId()));
+					player.sendPacket(html);
+					return;
+				}
+			}
+			else if (actualCommand.equalsIgnoreCase("list_siege_clans"))
+			{
+				if ((player.getClanPrivileges() & L2Clan.CP_CS_MANAGE_SIEGE) == L2Clan.CP_CS_MANAGE_SIEGE)
+				{
+					getFort().getSiege().listRegisterClan(player); // List current register clan
+					return;
+				}
+				else
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
+					html.setFile("data/html/fortress/foreman-noprivs.htm");
+					html.replace("%objectId%", String.valueOf(getObjectId()));
+					player.sendPacket(html);
+					return;
+				}
+			}
+			else if (actualCommand.equalsIgnoreCase("receive_report"))
+			{
+				if (player.isClanLeader())
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
+					html.setFile("data/html/fortress/foreman-report.htm");
+					html.replace("%objectId%", String.valueOf(getObjectId()));
+					L2Clan clan = ClanTable.getInstance().getClan(getFort().getOwnerId());
+					html.replace("%clanname%", clan.getName());
+					html.replace("%clanleadername%", clan.getLeaderName());
+					html.replace("%fortname%", getFort().getName());
+					player.sendPacket(html);
+					return;
+				}
+				else
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
+					html.setFile("data/html/fortress/foreman-noprivs.htm");
+					html.replace("%objectId%", String.valueOf(getObjectId()));
+					player.sendPacket(html);
+					return;
+				}
+			}
+			else if (actualCommand.equalsIgnoreCase("manage_siege_defender"))
+			{
+				if ((player.getClanPrivileges() & L2Clan.CP_CS_MANAGE_SIEGE) == L2Clan.CP_CS_MANAGE_SIEGE)
+				{
+					getFort().getSiege().listRegisterClan(player);
+					return;
+				}
+				else
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
+					html.setFile("data/html/fortress/foreman-noprivs.htm");
+					html.replace("%objectId%", String.valueOf(getObjectId()));
+					player.sendPacket(html);
+					return;
+				}
+			}
+			else if (actualCommand.equalsIgnoreCase("operate_door")) // door
+			// control
+			{
+				if ((player.getClanPrivileges() & L2Clan.CP_CS_OPEN_DOOR) == L2Clan.CP_CS_OPEN_DOOR)
+				{
+					if (val != "")
+					{
+						boolean open = (Integer.parseInt(val) == 1);
+						while (st.hasMoreTokens())
+							getFort().openCloseDoor(player, Integer.parseInt(st.nextToken()), open);
+					}
+
+					NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
+					html.setFile("data/html/fortress/" + getTemplate().npcId	+ "-d.htm");
+					html.replace("%objectId%", String.valueOf(getObjectId()));
+					html.replace("%npcname%", getName());
+					player.sendPacket(html);
+					return;
+				}
+				else
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
+					html.setFile("data/html/fortress/foreman-noprivs.htm");
+					html.replace("%objectId%", String.valueOf(getObjectId()));
+					player.sendPacket(html);
+					return;
+				}
+			}
+			else if (actualCommand.equalsIgnoreCase("manage_functions"))
+			{
+				NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
+				html.setFile("data/html/fortress/foreman-manage.htm");
+				html.replace("%objectId%", String.valueOf(getObjectId()));
+				player.sendPacket(html);
+				return;
+			}
+			else if (actualCommand.equalsIgnoreCase("functions"))
+			{
+				if (val.equalsIgnoreCase("tele"))
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(1);
+					if (getFort().getFunction(Fort.FUNC_TELEPORT) == null)
+						html.setFile("data/html/fortress/foreman-nac.htm");
+					else
+						html.setFile("data/html/fortress/"+ getNpcId()+ "-t"
+								+ getFort().getFunction(Fort.FUNC_TELEPORT).getLvl()+ ".htm");
+					sendHtmlMessage(player, html);
+				}
+				else if (val.equalsIgnoreCase("support"))
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(1);
+					if (getFort().getFunction(Fort.FUNC_SUPPORT) == null)
+						html.setFile("data/html/fortress/foreman-nac.htm");
+					else
+					{
+						html.setFile("data/html/fortress/support"
+								+ getFort().getFunction(Fort.FUNC_SUPPORT).getLvl()+ ".htm");
+						html.replace("%mp%", String.valueOf((int)getCurrentMp()));
+					}
+					sendHtmlMessage(player, html);
+				}
+				else if (val.equalsIgnoreCase("back"))
+					showMessageWindow(player);
+				else
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(1);
+					html.setFile("data/html/fortress/foreman-functions.htm");
+					if (getFort().getFunction(Fort.FUNC_RESTORE_EXP) != null)
+						html.replace("%xp_regen%", String.valueOf(getFort().getFunction(Fort.FUNC_RESTORE_EXP).getLvl()));
+					else
+						html.replace("%xp_regen%", "0");
+					if (getFort().getFunction(Fort.FUNC_RESTORE_HP) != null)
+						html.replace("%hp_regen%", String.valueOf(getFort().getFunction(Fort.FUNC_RESTORE_HP).getLvl()));
+					else
+						html.replace("%hp_regen%", "0");
+					if (getFort().getFunction(Fort.FUNC_RESTORE_MP) != null)
+						html.replace("%mp_regen%", String.valueOf(getFort().getFunction(Fort.FUNC_RESTORE_MP).getLvl()));
+					else
+						html.replace("%mp_regen%", "0");
+					sendHtmlMessage(player, html);
+				}
+			}
+			else if (actualCommand.equalsIgnoreCase("manage"))
+			{
+				if ((player.getClanPrivileges() & L2Clan.CP_CS_SET_FUNCTIONS) == L2Clan.CP_CS_SET_FUNCTIONS)
+				{
+					if (val.equalsIgnoreCase("recovery"))
+					{
+						if (st.countTokens() >= 1)
+						{
+							if (getFort().getOwnerId() == 0)
+							{
+								player.sendMessage("This fortress have no owner, you cannot change configuration");
+								return;
+							}
+							val = st.nextToken();
+							if (val.equalsIgnoreCase("hp_cancel"))
+							{
+								NpcHtmlMessage html = new NpcHtmlMessage(1);
+								html.setFile("data/html/fortress/functions-cancel.htm");
+								html.replace("%apply%", "recovery hp 0");
+								sendHtmlMessage(player, html);
+								return;
+							}
+							else if (val.equalsIgnoreCase("mp_cancel"))
+							{
+								NpcHtmlMessage html = new NpcHtmlMessage(1);
+								html.setFile("data/html/fortress/functions-cancel.htm");
+								html.replace("%apply%", "recovery mp 0");
+								sendHtmlMessage(player, html);
+								return;
+							}
+							else if (val.equalsIgnoreCase("exp_cancel"))
+							{
+								NpcHtmlMessage html = new NpcHtmlMessage(1);
+								html.setFile("data/html/fortress/functions-cancel.htm");
+								html.replace("%apply%", "recovery exp 0");
+								sendHtmlMessage(player, html);
+								return;
+							}
+							else if (val.equalsIgnoreCase("edit_hp"))
+							{
+								val = st.nextToken();
+								NpcHtmlMessage html = new NpcHtmlMessage(1);
+								html.setFile("data/html/fortress/functions-apply.htm");
+								html.replace("%name%", "(HP Recovery Device)");
+								int percent = Integer.valueOf(val);
+								int cost;
+								switch (percent)
+								{
+									case 300:
+										cost = Config.FS_HPREG1_FEE;
+										break;
+									default: // 400
+										cost = Config.FS_HPREG2_FEE;
+										break;
+								}
+
+								html.replace("%cost%", String.valueOf(cost)
+										+ "</font>Adena /"
+										+ String.valueOf(Config.FS_HPREG_FEE_RATIO
+												/ 1000 / 60 / 60 / 24)
+										+ " Day</font>)");
+								html.replace("%use%", "Provides additional HP recovery for clan members in the fortress.<font color=\"00FFFF\">"
+										+ String.valueOf(percent) + "%</font>");
+								html.replace("%apply%", "recovery hp "
+										+ String.valueOf(percent));
+								sendHtmlMessage(player, html);
+								return;
+							}
+							else if (val.equalsIgnoreCase("edit_mp"))
+							{
+								val = st.nextToken();
+								NpcHtmlMessage html = new NpcHtmlMessage(1);
+								html.setFile("data/html/fortress/functions-apply.htm");
+								html.replace("%name%", "(MP Recovery)");
+								int percent = Integer.valueOf(val);
+								int cost;
+								switch (percent)
+								{
+									case 40:
+										cost = Config.FS_MPREG1_FEE;
+										break;
+									default: // 50
+										cost = Config.FS_MPREG2_FEE;
+										break;
+								}
+								html.replace("%cost%", String.valueOf(cost)
+										+ "</font>Adena /"
+										+ String.valueOf(Config.FS_MPREG_FEE_RATIO
+												/ 1000 / 60 / 60 / 24)
+										+ " Day</font>)");
+								html.replace("%use%", "Provides additional MP recovery for clan members in the fortress.<font color=\"00FFFF\">"
+										+ String.valueOf(percent) + "%</font>");
+								html.replace("%apply%", "recovery mp "
+										+ String.valueOf(percent));
+								sendHtmlMessage(player, html);
+								return;
+							}
+							else if (val.equalsIgnoreCase("edit_exp"))
+							{
+								val = st.nextToken();
+								NpcHtmlMessage html = new NpcHtmlMessage(1);
+								html.setFile("data/html/fortress/functions-apply.htm");
+								html.replace("%name%", "(EXP Recovery Device)");
+								int percent = Integer.valueOf(val);
+								int cost;
+								switch (percent)
+								{
+									case 45:
+										cost = Config.FS_EXPREG1_FEE;
+										break;
+									default: // 50
+										cost = Config.FS_EXPREG2_FEE;
+										break;
+								}
+								html.replace("%cost%", String.valueOf(cost)
+										+ "</font>Adena /"
+										+ String.valueOf(Config.FS_EXPREG_FEE_RATIO
+												/ 1000 / 60 / 60 / 24)
+										+ " Day</font>)");
+								html.replace("%use%", "Restores the Exp of any clan member who is resurrected in the fortress.<font color=\"00FFFF\">"
+										+ String.valueOf(percent) + "%</font>");
+								html.replace("%apply%", "recovery exp "
+										+ String.valueOf(percent));
+								sendHtmlMessage(player, html);
+								return;
+							}
+							else if (val.equalsIgnoreCase("hp"))
+							{
+								if (st.countTokens() >= 1)
+								{
+									int fee;
+									if (Config.DEBUG)
+										_log.warning("Mp editing invoked");
+									val = st.nextToken();
+									NpcHtmlMessage html = new NpcHtmlMessage(1);
+									html.setFile("data/html/fortress/functions-apply_confirmed.htm");
+									if (getFort().getFunction(Fort.FUNC_RESTORE_HP) != null)
+									{
+										if (getFort().getFunction(Fort.FUNC_RESTORE_HP).getLvl() == Integer.valueOf(val))
+										{
+											html.setFile("data/html/fortress/functions-used.htm");
+											html.replace("%val%", String.valueOf(val)
+													+ "%");
+											sendHtmlMessage(player, html);
+											return;
+										}
+									}
+									int percent = Integer.valueOf(val);
+									switch (percent)
+									{
+										case 0:
+											fee = 0;
+											html.setFile("data/html/fortress/functions-cancel_confirmed.htm");
+											break;
+										case 300:
+											fee = Config.FS_HPREG1_FEE;
+											break;
+										default: // 400
+											fee = Config.FS_HPREG2_FEE;
+											break;
+									}
+									if (!getFort().updateFunctions(player, Fort.FUNC_RESTORE_HP, percent, fee, Config.FS_HPREG_FEE_RATIO, (getFort().getFunction(Fort.FUNC_RESTORE_HP) == null)))
+									{
+										html.setFile("data/html/fortress/low_adena.htm");
+										sendHtmlMessage(player, html);
+									}
+									sendHtmlMessage(player, html);
+								}
+								return;
+							}
+							else if (val.equalsIgnoreCase("mp"))
+							{
+								if (st.countTokens() >= 1)
+								{
+									int fee;
+									if (Config.DEBUG)
+										_log.warning("Mp editing invoked");
+									val = st.nextToken();
+									NpcHtmlMessage html = new NpcHtmlMessage(1);
+									html.setFile("data/html/fortress/functions-apply_confirmed.htm");
+									if (getFort().getFunction(Fort.FUNC_RESTORE_MP) != null)
+									{
+										if (getFort().getFunction(Fort.FUNC_RESTORE_MP).getLvl() == Integer.valueOf(val))
+										{
+											html.setFile("data/html/fortress/functions-used.htm");
+											html.replace("%val%", String.valueOf(val)
+													+ "%");
+											sendHtmlMessage(player, html);
+											return;
+										}
+									}
+									int percent = Integer.valueOf(val);
+									switch (percent)
+									{
+										case 0:
+											fee = 0;
+											html.setFile("data/html/fortress/functions-cancel_confirmed.htm");
+											break;
+										case 40:
+											fee = Config.FS_MPREG1_FEE;
+											break;
+										default: // 50
+											fee = Config.FS_MPREG2_FEE;
+											break;
+									}
+									if (!getFort().updateFunctions(player, Fort.FUNC_RESTORE_MP, percent, fee, Config.FS_MPREG_FEE_RATIO, (getFort().getFunction(Fort.FUNC_RESTORE_MP) == null)))
+									{
+										html.setFile("data/html/fortress/low_adena.htm");
+										sendHtmlMessage(player, html);
+									}
+									sendHtmlMessage(player, html);
+								}
+								return;
+							}
+							else if (val.equalsIgnoreCase("exp"))
+							{
+								if (st.countTokens() >= 1)
+								{
+									int fee;
+									if (Config.DEBUG)
+										_log.warning("Exp editing invoked");
+									val = st.nextToken();
+									NpcHtmlMessage html = new NpcHtmlMessage(1);
+									html.setFile("data/html/fortress/functions-apply_confirmed.htm");
+									if (getFort().getFunction(Fort.FUNC_RESTORE_EXP) != null)
+									{
+										if (getFort().getFunction(Fort.FUNC_RESTORE_EXP).getLvl() == Integer.valueOf(val))
+										{
+											html.setFile("data/html/fortress/functions-used.htm");
+											html.replace("%val%", String.valueOf(val)
+													+ "%");
+											sendHtmlMessage(player, html);
+											return;
+										}
+									}
+									int percent = Integer.valueOf(val);
+									switch (percent)
+									{
+										case 0:
+											fee = 0;
+											html.setFile("data/html/fortress/functions-cancel_confirmed.htm");
+											break;
+										case 45:
+											fee = Config.FS_EXPREG1_FEE;
+											break;
+										default: // 50
+											fee = Config.FS_EXPREG2_FEE;
+											break;
+									}
+									if (!getFort().updateFunctions(player, Fort.FUNC_RESTORE_EXP, percent, fee, Config.FS_EXPREG_FEE_RATIO, (getFort().getFunction(Fort.FUNC_RESTORE_EXP) == null)))
+									{
+										html.setFile("data/html/fortress/low_adena.htm");
+										sendHtmlMessage(player, html);
+									}
+									sendHtmlMessage(player, html);
+								}
+								return;
+							}
+						}
+						NpcHtmlMessage html = new NpcHtmlMessage(1);
+						html.setFile("data/html/fortress/edit_recovery.htm");
+						String hp = "[<a action=\"bypass -h npc_%objectId%_manage recovery edit_hp 300\">300%</a>][<a action=\"bypass -h npc_%objectId%_manage recovery edit_hp 400\">400%</a>]";
+						String exp = "[<a action=\"bypass -h npc_%objectId%_manage recovery edit_exp 45\">45%</a>][<a action=\"bypass -h npc_%objectId%_manage recovery edit_exp 50\">50%</a>]";
+						String mp = "[<a action=\"bypass -h npc_%objectId%_manage recovery edit_mp 40\">40%</a>][<a action=\"bypass -h npc_%objectId%_manage recovery edit_mp 50\">50%</a>]";
+						if (getFort().getFunction(Fort.FUNC_RESTORE_HP) != null)
+						{
+							html.replace("%hp_recovery%", String.valueOf(getFort().getFunction(Fort.FUNC_RESTORE_HP).getLvl())
+									+ "%</font> (<font color=\"FFAABB\">"
+									+ String.valueOf(getFort().getFunction(Fort.FUNC_RESTORE_HP).getLease())
+									+ "</font>Adena /"
+									+ String.valueOf(Config.FS_HPREG_FEE_RATIO
+											/ 1000 / 60 / 60 / 24) + " Day)");
+							html.replace("%hp_period%", "Withdraw the fee for the next time at "
+									+ format.format(getFort().getFunction(Fort.FUNC_RESTORE_HP).getEndTime()));
+							html.replace("%change_hp%", "[<a action=\"bypass -h npc_%objectId%_manage recovery hp_cancel\">Deactivate</a>]"
+									+ hp);
+						}
+						else
+						{
+							html.replace("%hp_recovery%", "none");
+							html.replace("%hp_period%", "none");
+							html.replace("%change_hp%", hp);
+						}
+						if (getFort().getFunction(Fort.FUNC_RESTORE_EXP) != null)
+						{
+							html.replace("%exp_recovery%", String.valueOf(getFort().getFunction(Fort.FUNC_RESTORE_EXP).getLvl())
+									+ "%</font> (<font color=\"FFAABB\">"
+									+ String.valueOf(getFort().getFunction(Fort.FUNC_RESTORE_EXP).getLease())
+									+ "</font>Adena /"
+									+ String.valueOf(Config.FS_EXPREG_FEE_RATIO
+											/ 1000 / 60 / 60 / 24) + " Day)");
+							html.replace("%exp_period%", "Withdraw the fee for the next time at "
+									+ format.format(getFort().getFunction(Fort.FUNC_RESTORE_EXP).getEndTime()));
+							html.replace("%change_exp%", "[<a action=\"bypass -h npc_%objectId%_manage recovery exp_cancel\">Deactivate</a>]"
+									+ exp);
+						}
+						else
+						{
+							html.replace("%exp_recovery%", "none");
+							html.replace("%exp_period%", "none");
+							html.replace("%change_exp%", exp);
+						}
+						if (getFort().getFunction(Fort.FUNC_RESTORE_MP) != null)
+						{
+							html.replace("%mp_recovery%", String.valueOf(getFort().getFunction(Fort.FUNC_RESTORE_MP).getLvl())
+									+ "%</font> (<font color=\"FFAABB\">"
+									+ String.valueOf(getFort().getFunction(Fort.FUNC_RESTORE_MP).getLease())
+									+ "</font>Adena /"
+									+ String.valueOf(Config.FS_MPREG_FEE_RATIO
+											/ 1000 / 60 / 60 / 24) + " Day)");
+							html.replace("%mp_period%", "Withdraw the fee for the next time at "
+									+ format.format(getFort().getFunction(Fort.FUNC_RESTORE_MP).getEndTime()));
+							html.replace("%change_mp%", "[<a action=\"bypass -h npc_%objectId%_manage recovery mp_cancel\">Deactivate</a>]"
+									+ mp);
+						}
+						else
+						{
+							html.replace("%mp_recovery%", "none");
+							html.replace("%mp_period%", "none");
+							html.replace("%change_mp%", mp);
+						}
+						sendHtmlMessage(player, html);
+					}
+					else if (val.equalsIgnoreCase("other"))
+					{
+						if (st.countTokens() >= 1)
+						{
+							if (getFort().getOwnerId() == 0)
+							{
+								player.sendMessage("This fortress have no owner, you cannot change configuration");
+								return;
+							}
+							val = st.nextToken();
+							if (val.equalsIgnoreCase("tele_cancel"))
+							{
+								NpcHtmlMessage html = new NpcHtmlMessage(1);
+								html.setFile("data/html/fortress/functions-cancel.htm");
+								html.replace("%apply%", "other tele 0");
+								sendHtmlMessage(player, html);
+								return;
+							}
+							else if (val.equalsIgnoreCase("support_cancel"))
+							{
+								NpcHtmlMessage html = new NpcHtmlMessage(1);
+								html.setFile("data/html/fortress/functions-cancel.htm");
+								html.replace("%apply%", "other support 0");
+								sendHtmlMessage(player, html);
+								return;
+							}
+							else if (val.equalsIgnoreCase("edit_support"))
+							{
+								val = st.nextToken();
+								NpcHtmlMessage html = new NpcHtmlMessage(1);
+								html.setFile("data/html/fortress/functions-apply.htm");
+								html.replace("%name%", "Insignia (Supplementary Magic)");
+								int stage = Integer.valueOf(val);
+								int cost;
+								switch (stage)
+								{
+									case 1:
+										cost = Config.FS_SUPPORT1_FEE;
+										break;
+									default:
+										cost = Config.FS_SUPPORT2_FEE;
+										break;
+								}
+								html.replace("%cost%", String.valueOf(cost)
+										+ "</font>Adena /"
+										+ String.valueOf(Config.FS_SUPPORT_FEE_RATIO
+												/ 1000 / 60 / 60 / 24)
+										+ " Day</font>)");
+								html.replace("%use%", "Enables the use of supplementary magic.");
+								html.replace("%apply%", "other support "
+										+ String.valueOf(stage));
+								sendHtmlMessage(player, html);
+								return;
+							}
+							else if (val.equalsIgnoreCase("edit_tele"))
+							{
+								val = st.nextToken();
+								NpcHtmlMessage html = new NpcHtmlMessage(1);
+								html.setFile("data/html/fortress/functions-apply.htm");
+								html.replace("%name%", "Mirror (Teleportation Device)");
+								int stage = Integer.valueOf(val);
+								int cost;
+								switch (stage)
+								{
+									case 1:
+										cost = Config.FS_TELE1_FEE;
+										break;
+									default:
+										cost = Config.FS_TELE2_FEE;
+										break;
+								}
+								html.replace("%cost%", String.valueOf(cost)
+										+ "</font>Adena /"
+										+ String.valueOf(Config.FS_TELE_FEE_RATIO
+												/ 1000 / 60 / 60 / 24)
+										+ " Day</font>)");
+								html.replace("%use%", "Teleports clan members in a fort to the target <font color=\"00FFFF\">Stage "
+										+ String.valueOf(stage)
+										+ "</font> staging area");
+								html.replace("%apply%", "other tele "+ String.valueOf(stage));
+								sendHtmlMessage(player, html);
+								return;
+							}
+							else if (val.equalsIgnoreCase("tele"))
+							{
+								if (st.countTokens() >= 1)
+								{
+									int fee;
+									if (Config.DEBUG)
+										_log.warning("Tele editing invoked");
+									val = st.nextToken();
+									NpcHtmlMessage html = new NpcHtmlMessage(1);
+									html.setFile("data/html/fortress/functions-apply_confirmed.htm");
+									if (getFort().getFunction(Fort.FUNC_TELEPORT) != null)
+									{
+										if (getFort().getFunction(Fort.FUNC_TELEPORT).getLvl() == Integer.valueOf(val))
+										{
+											html.setFile("data/html/fortress/functions-used.htm");
+											html.replace("%val%", "Stage "	+ String.valueOf(val));
+											sendHtmlMessage(player, html);
+											return;
+										}
+									}
+									int lvl = Integer.valueOf(val);
+									switch (lvl)
+									{
+										case 0:
+											fee = 0;
+											html.setFile("data/html/fortress/functions-cancel_confirmed.htm");
+											break;
+										case 1:
+											fee = Config.FS_TELE1_FEE;
+											break;
+										default:
+											fee = Config.FS_TELE2_FEE;
+											break;
+									}
+									if (!getFort().updateFunctions(player, Fort.FUNC_TELEPORT, lvl, fee, Config.FS_TELE_FEE_RATIO, (getFort().getFunction(Fort.FUNC_TELEPORT) == null)))
+									{
+										html.setFile("data/html/fortress/low_adena.htm");
+										sendHtmlMessage(player, html);
+									}
+									sendHtmlMessage(player, html);
+								}
+								return;
+							}
+							else if (val.equalsIgnoreCase("support"))
+							{
+								if (st.countTokens() >= 1)
+								{
+									int fee;
+									if (Config.DEBUG)
+										_log.warning("Support editing invoked");
+									val = st.nextToken();
+									NpcHtmlMessage html = new NpcHtmlMessage(1);
+									html.setFile("data/html/fortress/functions-apply_confirmed.htm");
+									if (getFort().getFunction(Fort.FUNC_SUPPORT) != null)
+									{
+										if (getFort().getFunction(Fort.FUNC_SUPPORT).getLvl() == Integer.valueOf(val))
+										{
+											html.setFile("data/html/fortress/functions-used.htm");
+											html.replace("%val%", "Stage "
+													+ String.valueOf(val));
+											sendHtmlMessage(player, html);
+											return;
+										}
+									}
+									int lvl = Integer.valueOf(val);
+									switch (lvl)
+									{
+										case 0:
+											fee = 0;
+											html.setFile("data/html/fortress/functions-cancel_confirmed.htm");
+											break;
+										case 1:
+											fee = Config.FS_SUPPORT1_FEE;
+											break;
+										default:
+											fee = Config.FS_SUPPORT2_FEE;
+											break;
+									}
+									if (!getFort().updateFunctions(player, Fort.FUNC_SUPPORT, lvl, fee, Config.FS_SUPPORT_FEE_RATIO, (getFort().getFunction(Fort.FUNC_SUPPORT) == null)))
+									{
+										html.setFile("data/html/fortress/low_adena.htm");
+										sendHtmlMessage(player, html);
+									}
+									else
+										sendHtmlMessage(player, html);
+								}
+								return;
+							}
+						}
+						NpcHtmlMessage html = new NpcHtmlMessage(1);
+						html.setFile("data/html/fortress/edit_other.htm");
+						String tele = "[<a action=\"bypass -h npc_%objectId%_manage other edit_tele 1\">Level 1</a>][<a action=\"bypass -h npc_%objectId%_manage other edit_tele 2\">Level 2</a>]";
+						String support = "[<a action=\"bypass -h npc_%objectId%_manage other edit_support 1\">Level 1</a>][<a action=\"bypass -h npc_%objectId%_manage other edit_support 2\">Level 2</a>]";
+						if (getFort().getFunction(Fort.FUNC_TELEPORT) != null)
+						{
+							html.replace("%tele%", "Stage "
+									+ String.valueOf(getFort().getFunction(Fort.FUNC_TELEPORT).getLvl())
+									+ "</font> (<font color=\"FFAABB\">"
+									+ String.valueOf(getFort().getFunction(Fort.FUNC_TELEPORT).getLease())
+									+ "</font>Adena /"
+									+ String.valueOf(Config.FS_TELE_FEE_RATIO
+											/ 1000 / 60 / 60 / 24) + " Day)");
+							html.replace("%tele_period%", "Withdraw the fee for the next time at "
+									+ format.format(getFort().getFunction(Fort.FUNC_TELEPORT).getEndTime()));
+							html.replace("%change_tele%", "[<a action=\"bypass -h npc_%objectId%_manage other tele_cancel\">Deactivate</a>]"
+									+ tele);
+						}
+						else
+						{
+							html.replace("%tele%", "none");
+							html.replace("%tele_period%", "none");
+							html.replace("%change_tele%", tele);
+						}
+						if (getFort().getFunction(Fort.FUNC_SUPPORT) != null)
+						{
+							html.replace("%support%", "Stage "
+									+ String.valueOf(getFort().getFunction(Fort.FUNC_SUPPORT).getLvl())
+									+ "</font> (<font color=\"FFAABB\">"
+									+ String.valueOf(getFort().getFunction(Fort.FUNC_SUPPORT).getLease())
+									+ "</font>Adena /"
+									+ String.valueOf(Config.FS_SUPPORT_FEE_RATIO
+											/ 1000 / 60 / 60 / 24) + " Day)");
+							html.replace("%support_period%", "Withdraw the fee for the next time at "
+									+ format.format(getFort().getFunction(Fort.FUNC_SUPPORT).getEndTime()));
+							html.replace("%change_support%", "[<a action=\"bypass -h npc_%objectId%_manage other support_cancel\">Deactivate</a>]"
+									+ support);
+						}
+						else
+						{
+							html.replace("%support%", "none");
+							html.replace("%support_period%", "none");
+							html.replace("%change_support%", support);
+						}
+						sendHtmlMessage(player, html);
+					}
+					else if (val.equalsIgnoreCase("back"))
+						showMessageWindow(player);
+					else
+					{
+						NpcHtmlMessage html = new NpcHtmlMessage(1);
+						html.setFile("data/html/fortress/manage.htm");
+						sendHtmlMessage(player, html);
+					}
+				}
+				else
+				{
+					NpcHtmlMessage html = new NpcHtmlMessage(1);
+					html.setFile("data/html/fortress/foreman-noprivs.htm");
+					sendHtmlMessage(player, html);
+				}
+				return;
+			}
+			else if (actualCommand.equalsIgnoreCase("support"))
+			{
+				setTarget(player);
+				L2Skill skill;
+				if (val == "")
+					return;
+
+				try
+				{
+					int skill_id = Integer.parseInt(val);
+					try
+					{
+						if (getFort().getFunction(Fort.FUNC_SUPPORT) == null)
+							return;
+						if (getFort().getFunction(Fort.FUNC_SUPPORT).getLvl() == 0)
+							return;
+						NpcHtmlMessage html = new NpcHtmlMessage(1);
+						int skill_lvl = 0;
+						if (st.countTokens() >= 1)
+							skill_lvl = Integer.parseInt(st.nextToken());
+						skill = SkillTable.getInstance().getInfo(skill_id, skill_lvl);
+						if (skill.getSkillType() == L2SkillType.SUMMON)
+							player.doCast(skill);
+						else
+						{
+							if (!((skill.getMpConsume() + skill.getMpInitialConsume()) > this.getCurrentMp()))
+								this.doCast(skill);
+							else
+							{
+								html.setFile("data/html/fortress/support-no_mana.htm");
+								html.replace("%mp%", String.valueOf((int)getCurrentMp()));
+								sendHtmlMessage(player, html);
+								return;
+							}
+						}
+						html.setFile("data/html/fortress/support-done.htm");
+						html.replace("%mp%", String.valueOf((int)getCurrentMp()));
+						sendHtmlMessage(player, html);
+					}
+					catch (Exception e)
+					{
+						player.sendMessage("Invalid skill level, contact your admin!");
+					}
+				}
+				catch (Exception e)
+				{
+					player.sendMessage("Invalid skill level, contact your admin!");
+				}
+				return;
+			}
+			else if (actualCommand.equalsIgnoreCase("support_back"))
+			{
+				NpcHtmlMessage html = new NpcHtmlMessage(1);
+				if (getFort().getFunction(Fort.FUNC_SUPPORT).getLvl() == 0)
+					return;
+				html.setFile("data/html/fortress/support"
+						+ getFort().getFunction(Fort.FUNC_SUPPORT).getLvl()	+ ".htm");
+				html.replace("%mp%", String.valueOf((int)getStatus().getCurrentMp()));
+				sendHtmlMessage(player, html);
+			}
+			else if (actualCommand.equalsIgnoreCase("goto"))
+			{
+				int whereTo = Integer.parseInt(val);
+				doTeleport(player, whereTo);
+				return;
+			}
+			super.onBypassFeedback(player, command);
+		}
+	}
+
+	private void showMessageWindow(L2PcInstance player)
+	{
+		player.sendPacket(ActionFailed.STATIC_PACKET);
+		String filename = "data/html/fortress/foreman-no.htm";
+
+		int condition = validateCondition(player);
+		if (condition > COND_ALL_FALSE)
+		{
+			if (condition == COND_BUSY_BECAUSE_OF_SIEGE)
+				filename = "data/html/fortress/foreman-busy.htm"; // Busy because of siege
+			else if (condition == COND_OWNER) // Clan owns Fortress
+				filename = "data/html/fortress/foreman.htm"; // Owner message window
+		}
+
+		NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
+		html.setFile(filename);
+		html.replace("%objectId%", String.valueOf(getObjectId()));
+		html.replace("%npcname%", getName());
+		player.sendPacket(html);
+	}
+
+	private void doTeleport(L2PcInstance player, int val)
+	{
+		if (Config.DEBUG)
+			_log.warning("doTeleport(L2PcInstance player, int val) is called");
+		L2TeleportLocation list = TeleportLocationTable.getInstance().getTemplate(val);
+		if (list != null)
+		{
+			if (player.reduceAdena("Teleport", list.getPrice(), this, true))
+			{
+				if (Config.DEBUG)
+					_log.warning("Teleporting player " + player.getName()
+							+ " for Fortress to new location: " + list.getLocX()
+							+ ":" + list.getLocY() + ":" + list.getLocZ());
+				player.teleToLocation(list.getLocX(), list.getLocY(), list.getLocZ());
+			}
+		}
+		else
+			_log.warning("No teleport destination with id:" + val);
+		player.sendPacket(ActionFailed.STATIC_PACKET);
+	}
+
+	protected int validateCondition(L2PcInstance player)
+	{
+		if (getFort() != null && getFort().getFortId() > 0)
+		{
+			if (player.getClan() != null)
+			{
+				if (getFort().getSiege().getIsInProgress())
+					return COND_BUSY_BECAUSE_OF_SIEGE; // Busy because of siege
+				else if (getFort().getOwnerId() == player.getClanId()) // Clan owns fortress
+					return COND_OWNER; // Owner
+			}
+		}
+		return COND_ALL_FALSE;
+	}
+}

+ 1 - 1
L2_GameServer/java/net/sf/l2j/gameserver/model/actor/instance/L2FortMerchantInstance.java

@@ -129,7 +129,7 @@ public class L2FortMerchantInstance extends L2NpcWalkerInstance
         else
             html.replace("%clanname%", "NPC");
         
-        html.replace("%castleid%", Integer.toString(getCastle().getCastleId()));
+        html.replace("%castleid%", Integer.toString(getFort().getFortId()));
         player.sendPacket(html);
     }
     

+ 294 - 39
L2_GameServer/java/net/sf/l2j/gameserver/model/entity/Fort.java

@@ -18,13 +18,16 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.util.Calendar;
 import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import javolution.util.FastList;
+import javolution.util.FastMap;
+import net.sf.l2j.Config;
 import net.sf.l2j.L2DatabaseFactory;
 import net.sf.l2j.gameserver.Announcements;
 import net.sf.l2j.gameserver.FortUpdater;
-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.DoorTable;
@@ -53,6 +56,180 @@ public class Fort
 	private Calendar _lastOwnedTime;
 	private L2FortZone _zone;
 	private L2Clan _formerOwner = null;
+	private Map<Integer, FortFunction> _function;
+	
+	/** 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 int _type;
+		private int _lvl;
+		protected int _fee;
+		protected int _tempFee;
+		private 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 (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;
+			}
+			
+			public void run()
+			{
+				try
+				{
+					if (getOwnerId() <= 0)
+						return;
+					if (ClanTable.getInstance().getClan(getOwnerId()).getWarehouse().getAdena() >= _fee || !_cwh)
+					{
+						int fee = _fee;
+						boolean newfc = true;
+						if (getEndTime() == 0 || getEndTime() == -1)
+						{
+							if (getEndTime() == -1)
+							{
+								newfc = false;
+								fee = _tempFee;
+							}
+						}
+						else
+							newfc = false;
+						setEndTime(System.currentTimeMillis() + getRate());
+						dbSave(newfc);
+						if (_cwh)
+						{
+							ClanTable.getInstance().getClan(getOwnerId()).getWarehouse().destroyItemByItemId("CS_function_fee", 57, fee, null, null);
+							if (Config.DEBUG)
+								_log.warning("deducted " + fee + " adena from " + getName() + " owner's cwh for function id : " + getType());
+						}
+						ThreadPoolManager.getInstance().scheduleGeneral(new FunctionTask(true), getRate());
+					}
+					else
+						removeFunction(getType());
+				}
+				catch (Throwable t)
+				{
+				}
+			}
+		}
+		
+		public void dbSave(boolean newFunction)
+		{
+			java.sql.Connection con = null;
+			try
+			{
+				PreparedStatement statement;
+				
+				con = L2DatabaseFactory.getInstance().getConnection();
+				if (newFunction)
+				{
+					statement = con.prepareStatement("INSERT INTO fort_functions (fort_id, type, lvl, lease, rate, endTime) VALUES (?,?,?,?,?,?)");
+					statement.setInt(1, getFortId());
+					statement.setInt(2, getType());
+					statement.setInt(3, getLvl());
+					statement.setInt(4, getLease());
+					statement.setLong(5, getRate());
+					statement.setLong(6, getEndTime());
+				}
+				else
+				{
+					statement = con.prepareStatement("UPDATE fort_functions SET lvl=?, lease=?, endTime=? WHERE fort_id=? AND type=?");
+					statement.setInt(1, getLvl());
+					statement.setInt(2, getLease());
+					statement.setLong(3, getEndTime());
+					statement.setInt(4, getFortId());
+					statement.setInt(5, getType());
+				}
+				statement.execute();
+				statement.close();
+			}
+			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);
+			}
+			finally
+			{
+				try
+				{
+					con.close();
+				}
+				catch (Exception e)
+				{
+				}
+			}
+		}
+	}
 	
 	// =========================================================
 	// Constructor
@@ -61,6 +238,19 @@ public class Fort
 		_fortId = fortId;
 		load();
 		loadDoor();
+		_function = new FastMap<Integer, FortFunction>();
+		if (getOwnerId() != 0)
+		{
+			loadFunctions();
+		}
+	}
+	
+	/** Return function with id */
+	public FortFunction getFunction(int type)
+	{
+		if (_function.get(type) != null)
+			return _function.get(type);
+		return null;
 	}
 	
 	// =========================================================
@@ -78,19 +268,6 @@ public class Fort
 		setOwner(clan);
 	}
 	
-	// This method add to the treasury
-	/** Add amount to fort instance's treasury (warehouse). */
-	public void addToTreasury(int amount)
-	{
-		return;
-	}
-	
-	/** Add amount to fort instance's treasury (warehouse), no tax paying. */
-	public boolean addToTreasuryNoTax(int amount)
-	{
-		return true;
-	}
-	
 	/**
 	 * Move non clan members off fort area and to nearest town.<BR><BR>
 	 */
@@ -217,31 +394,6 @@ public class Fort
 		updateClansReputation();
 	}
 	
-	// This method updates the fort tax rate
-	public void setTaxPercent(L2PcInstance activeChar, int taxPercent)
-	{
-		int maxTax;
-		switch (SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_STRIFE))
-		{
-			case SevenSigns.CABAL_DAWN:
-				maxTax = 25;
-				break;
-			case SevenSigns.CABAL_DUSK:
-				maxTax = 5;
-				break;
-			default: // no owner
-				maxTax = 15;
-		}
-		
-		if (taxPercent < 0 || taxPercent > maxTax)
-		{
-			activeChar.sendMessage("Tax value must be between 0 and " + maxTax + ".");
-			return;
-		}
-		
-		activeChar.sendMessage(getName() + " fort tax changed to " + taxPercent + "%.");
-	}
-	
 	/**
 	 * Respawn all doors on fort grounds<BR><BR>
 	 */
@@ -346,6 +498,109 @@ public class Fort
 		}
 	}
 	
+	/** Load All Functions */
+	private void loadFunctions()
+	{
+		java.sql.Connection con = null;
+		try
+		{
+			PreparedStatement statement;
+			ResultSet rs;
+			con = L2DatabaseFactory.getInstance().getConnection();
+			statement = con.prepareStatement("Select * from fort_functions where fort_id = ?");
+			statement.setInt(1, getFortId());
+			rs = statement.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));
+			}
+			statement.close();
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.SEVERE, "Exception: Fort.loadFunctions(): " + e.getMessage(), e);
+		}
+		finally
+		{
+			try
+			{
+				con.close();
+			}
+			catch (Exception e)
+			{
+			}
+		}
+	}
+	
+	/** Remove function In List and in DB */
+	public void removeFunction(int functionType)
+	{
+		_function.remove(functionType);
+		java.sql.Connection con = null;
+		try
+		{
+			PreparedStatement statement;
+			con = L2DatabaseFactory.getInstance().getConnection();
+			statement = con.prepareStatement("DELETE FROM fort_functions WHERE fort_id=? AND type=?");
+			statement.setInt(1, getFortId());
+			statement.setInt(2, functionType);
+			statement.execute();
+			statement.close();
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.SEVERE, "Exception: Fort.removeFunctions(int functionType): " + e.getMessage(), e);
+		}
+		finally
+		{
+			try
+			{
+				con.close();
+			}
+			catch (Exception e)
+			{
+			}
+		}
+	}
+	
+	public boolean updateFunctions(L2PcInstance player, int type, int lvl, int lease, long rate, boolean addNew)
+	{
+		if (player == null)
+			return false;
+		if (Config.DEBUG)
+			_log.warning("Called Fort.updateFunctions(int type, int lvl, int lease, long rate, boolean addNew) Owner : " + getOwnerId());
+		if (lease > 0)
+			if (!player.destroyItemByItemId("Consume", 57, 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 (Config.DEBUG)
+					_log.warning("Called Fort.updateFunctions diffLease : " + diffLease);
+				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(false);
+				}
+			}
+		}
+		return true;
+	}
+	
 	// This method loads fort door data from database
 	private void loadDoor()
 	{

+ 9 - 0
L2_GameServer/java/net/sf/l2j/gameserver/model/zone/type/L2FortZone.java

@@ -77,11 +77,14 @@ public class L2FortZone extends L2ZoneType
 		{
 			character.setInsideZone(L2Character.ZONE_PVP, true);
 			character.setInsideZone(L2Character.ZONE_SIEGE, true);
+			character.setInsideZone(L2Character.ZONE_FORT, true);
 			character.setInsideZone(L2Character.ZONE_NOSUMMONFRIEND, true);
 			
 			if (character instanceof L2PcInstance)
 				((L2PcInstance) character).sendPacket(new SystemMessage(SystemMessageId.ENTERED_COMBAT_ZONE));
 		}
+		else
+			character.setInsideZone(L2Character.ZONE_FORT, true);
 	}
 	
 	@Override
@@ -91,6 +94,7 @@ public class L2FortZone extends L2ZoneType
 		{
 			character.setInsideZone(L2Character.ZONE_PVP, false);
 			character.setInsideZone(L2Character.ZONE_SIEGE, false);
+			character.setInsideZone(L2Character.ZONE_FORT, false);
 			character.setInsideZone(L2Character.ZONE_NOSUMMONFRIEND, false);
 			
 			if (character instanceof L2PcInstance)
@@ -102,6 +106,9 @@ public class L2FortZone extends L2ZoneType
 					((L2PcInstance) character).startPvPFlag();
 			}
 		}
+		else
+			character.setInsideZone(L2Character.ZONE_FORT, true);
+		
 		if (character instanceof L2SiegeSummonInstance)
 		{
 			((L2SiegeSummonInstance) character).unSummon(((L2SiegeSummonInstance) character).getOwner());
@@ -141,6 +148,8 @@ public class L2FortZone extends L2ZoneType
 				{
 					character.setInsideZone(L2Character.ZONE_PVP, false);
 					character.setInsideZone(L2Character.ZONE_SIEGE, false);
+					character.setInsideZone(L2Character.ZONE_FORT, false);
+					character.setInsideZone(L2Character.ZONE_NOSUMMONFRIEND, false);
 					
 					if (character instanceof L2PcInstance)
 						((L2PcInstance) character).sendPacket(new SystemMessage(SystemMessageId.LEFT_COMBAT_ZONE));

+ 5 - 0
L2_GameServer/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestartPoint.java

@@ -136,6 +136,11 @@ public final class RequestRestartPoint extends L2GameClientPacket
 						return;
 					}
 					loc = MapRegionTable.getInstance().getTeleToLocation(activeChar, MapRegionTable.TeleportWhereType.Fortress);
+					if (FortManager.getInstance().getFortByOwner(activeChar.getClan())!= null &&
+							FortManager.getInstance().getFortByOwner(activeChar.getClan()).getFunction(Fort.FUNC_RESTORE_EXP) != null)
+					{
+						activeChar.restoreExp(FortManager.getInstance().getFortByOwner(activeChar.getClan()).getFunction(Fort.FUNC_RESTORE_EXP).getLvl());
+					}
 					break;
 
 				case 4: // to siege HQ

+ 26 - 0
L2_GameServer/java/net/sf/l2j/gameserver/skills/Formulas.java

@@ -20,6 +20,7 @@ import net.sf.l2j.Config;
 import net.sf.l2j.gameserver.SevenSigns;
 import net.sf.l2j.gameserver.SevenSignsFestival;
 import net.sf.l2j.gameserver.instancemanager.CastleManager;
+import net.sf.l2j.gameserver.instancemanager.FortManager;
 import net.sf.l2j.gameserver.instancemanager.ClanHallManager;
 import net.sf.l2j.gameserver.instancemanager.SiegeManager;
 import net.sf.l2j.gameserver.model.L2Character;
@@ -34,6 +35,7 @@ import net.sf.l2j.gameserver.model.actor.instance.L2PetInstance;
 import net.sf.l2j.gameserver.model.actor.instance.L2PlayableInstance;
 import net.sf.l2j.gameserver.model.entity.Castle;
 import net.sf.l2j.gameserver.model.entity.ClanHall;
+import net.sf.l2j.gameserver.model.entity.Fort;
 import net.sf.l2j.gameserver.model.entity.Siege;
 import net.sf.l2j.gameserver.model.itemcontainer.Inventory;
 import net.sf.l2j.gameserver.network.SystemMessageId;
@@ -1027,6 +1029,18 @@ public final class Formulas
             				hpRegenMultiplier *= 1+ castle.getFunction(Castle.FUNC_RESTORE_HP).getLvl()/100;
             	}
             }
+            
+            if (player.isInsideZone(L2Character.ZONE_FORT) && player.getClan() != null)
+            {
+            	int fortIndex = player.getClan().getHasFort();
+            	if (fortIndex > 0)
+            	{
+            		Fort fort = FortManager.getInstance().getFortById(fortIndex);
+            		if (fort != null)
+            			if (fort.getFunction(Fort.FUNC_RESTORE_HP) != null)
+            				hpRegenMultiplier *= 1+ fort.getFunction(Fort.FUNC_RESTORE_HP).getLvl()/100;
+            	}
+            }
 
 			// Mother Tree effect is calculated at last
 			if (player.isInsideZone(L2Character.ZONE_MOTHERTREE)) hpRegenBonus += 2;
@@ -1091,6 +1105,18 @@ public final class Formulas
             				mpRegenMultiplier *= 1+ castle.getFunction(Castle.FUNC_RESTORE_MP).getLvl()/100;
             	}
             }
+            
+            if (player.isInsideZone(L2Character.ZONE_FORT) && player.getClan() != null)
+            {
+            	int fortIndex = player.getClan().getHasFort();
+            	if (fortIndex > 0)
+            	{
+            		Fort fort = FortManager.getInstance().getFortById(fortIndex);
+            		if(fort != null)
+            			if (fort.getFunction(Fort.FUNC_RESTORE_MP) != null)
+            				mpRegenMultiplier *= 1+ fort.getFunction(Fort.FUNC_RESTORE_MP).getLvl()/100;
+            	}
+            }
 
 			// Calculate Movement bonus
             if (player.isSitting()) mpRegenMultiplier *= 1.5;      // Sitting