Jelajahi Sumber

BETA: The Hellbound Core part!
* Items auto destroy time support.
* Hellbound Manager.
* Walking Manager.
* L2QuestGuardInstance.
* L2NoRestartZone.

Special Thanks:
'''_DS_''' first Hellbound Manager implementation.

'''VlLight''' as '''GKR''' for the other support and features.

Code review, cleanup, code refactoring, typo fixing by me.

Zoey76 13 tahun lalu
induk
melakukan
cbc49d5757
25 mengubah file dengan 684 tambahan dan 25 penghapusan
  1. 13 1
      L2J_Server_BETA/dist/game/config/Grandboss.properties
  2. 4 0
      L2J_Server_BETA/dist/game/config/NPC.properties
  3. 9 0
      L2J_Server_BETA/dist/game/config/l2jmods.properties
  4. 4 0
      L2J_Server_BETA/dist/game/config/rates.properties
  5. 44 0
      L2J_Server_BETA/java/com/l2jserver/Config.java
  6. 3 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/GameServer.java
  7. 12 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/ItemsAutoDestroy.java
  8. 3 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/Shutdown.java
  9. 5 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/ai/L2CharacterAI.java
  10. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/datatables/MerchantPriceConfigTable.java
  11. 346 11
      L2J_Server_BETA/java/com/l2jserver/gameserver/instancemanager/HellboundManager.java
  12. 1 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/L2Object.java
  13. 2 2
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/L2Attackable.java
  14. 2 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/L2Character.java
  15. 4 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/L2Npc.java
  16. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2GuardInstance.java
  17. 89 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java
  18. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2TransformManagerInstance.java
  19. 3 2
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/knownlist/AttackableKnownList.java
  20. 80 3
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/knownlist/NpcKnownList.java
  21. 17 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/zone/type/L2DamageZone.java
  22. 1 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/L2GameClient.java
  23. 21 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/NpcStringId.java
  24. 7 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/SystemMessageId.java
  25. 11 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/templates/item/L2Item.java

+ 13 - 1
L2J_Server_BETA/dist/game/config/Grandboss.properties

@@ -74,4 +74,16 @@ RandomOfZakenSpawn = 35
 IntervalOfFrintezzaSpawn = 48
 
 # Random interval. Range 1-192
-RandomOfFrintezzaSpawn = 8
+RandomOfFrintezzaSpawn = 8
+
+# ---------------------------------------------------------------------------
+Beleth
+# ---------------------------------------------------------------------------
+# Interval time of Beleth. Value is hour. Range 1-480. Retail: 192
+IntervalOfBelethSpawn = 192
+
+# Random interval. Range 1-192. Retail: 148
+RandomOfBelethSpawn = 148
+
+#Minimal count of players for enter to Beleth. Retail: 36
+BelethMinPlayers = 36

+ 4 - 0
L2J_Server_BETA/dist/game/config/NPC.properties

@@ -168,6 +168,10 @@ RaidMaxRespawnMultiplier = 1.0
 # Default: 300000
 RaidMinionRespawnTime = 300000
 
+# Let's make handling of minions with non-standard static respawn easier - no additional code, just config.
+# Format: minionId1,timeInSec1;minionId2,timeInSec2
+CustomMinionsRespawnTime = 22450,30;22371,120;22543,0;25545,0;22424,30;22425,30;22426,30;22427,30;22428,30;22429,30;22430,30;22432,30;22433,30;22434,30;22435,30;22436,30;22437,30;22438,30;25596,30;25605,0;25606,0;25607,0;25608,0
+
 # Disable Raid Curse if raid more than 8 levels lower.
 # Caution: drop will be reduced or even absent if DeepBlue drop rules enabled.  
 # Default: False

+ 9 - 0
L2J_Server_BETA/dist/game/config/l2jmods.properties

@@ -367,6 +367,15 @@ AnnouncePvpMsg = $killer has defeated $target
 ChatAdmin = False
 
 
+# ---------------------------------------------------------------------------
+# Hellbound Status Voice Command
+# ---------------------------------------------------------------------------
+# This option will enable using of the voice commands .hellbound
+# for retrieving information about current Hellbound level and trust.
+# Default: False
+HellboundStatus = False
+
+
 # ---------------------------------------------------------------------------
 # Multilingual support
 # ---------------------------------------------------------------------------

+ 4 - 0
L2J_Server_BETA/dist/game/config/rates.properties

@@ -24,6 +24,10 @@ RateExtractFish = 1
 RateKarmaExpLost = 1
 RateSiegeGuardsPrice = 1
 
+# Hellbound trust increase/decrease multipliers
+RateHellboundTrustIncrease = 1
+RateHellboundTrustDecrease = 1
+
 # Quest Multipliers
 # Warning: Many quests need to be rewritten 
 # for this setting to work properly.

+ 44 - 0
L2J_Server_BETA/java/com/l2jserver/Config.java

@@ -716,6 +716,7 @@ public final class Config
 	public static boolean L2JMOD_WEDDING_SAMESEX;
 	public static boolean L2JMOD_WEDDING_FORMALWEAR;
 	public static int L2JMOD_WEDDING_DIVORCE_COSTS;
+	public static boolean L2JMOD_HELLBOUND_STATUS;
 	public static boolean BANKING_SYSTEM_ENABLED;
 	public static int BANKING_SYSTEM_GOLDBARS;
 	public static int BANKING_SYSTEM_ADENA;
@@ -794,6 +795,7 @@ public final class Config
 	public static double RAID_PATTACK_MULTIPLIER;
 	public static double RAID_MATTACK_MULTIPLIER;
 	public static double RAID_MINION_RESPAWN_TIMER;
+	public static TIntIntHashMap MINIONS_RESPAWN_TIME;
 	public static float RAID_MIN_RESPAWN_MULTIPLIER;
 	public static float RAID_MAX_RESPAWN_MULTIPLIER;
 	public static boolean RAID_DISABLE_CURSE;
@@ -830,6 +832,8 @@ public final class Config
 	public static float RATE_PARTY_XP;
 	public static float RATE_PARTY_SP;
 	public static float RATE_CONSUMABLE_COST;
+	public static float RATE_HB_TRUST_INCREASE;
+	public static float RATE_HB_TRUST_DECREASE;
 	public static float RATE_EXTR_FISH;
 	public static float RATE_DROP_ITEMS;
 	public static float RATE_DROP_ITEMS_BY_RAID;
@@ -1055,6 +1059,9 @@ public final class Config
 	public static int Random_Of_Zaken_Spawn;
 	public static int Interval_Of_Frintezza_Spawn;
 	public static int Random_Of_Frintezza_Spawn;
+	public static int BELETH_MIN_PLAYERS;
+	public static int INTERVAL_OF_BELETH_SPAWN;
+	public static int RANDOM_OF_BELETH_SPAWN;
 	
 	// Gracia Seeds Settings
 	
@@ -2150,6 +2157,27 @@ public final class Config
 					RAID_MIN_RESPAWN_MULTIPLIER = Float.parseFloat(NPC.getProperty("RaidMinRespawnMultiplier", "1.0"));
 					RAID_MAX_RESPAWN_MULTIPLIER = Float.parseFloat(NPC.getProperty("RaidMaxRespawnMultiplier", "1.0"));
 					RAID_MINION_RESPAWN_TIMER = Integer.parseInt(NPC.getProperty("RaidMinionRespawnTime", "300000"));
+					final String[] propertySplit = NPC.getProperty("CustomMinionsRespawnTime", "").split(";");
+					MINIONS_RESPAWN_TIME = new TIntIntHashMap(propertySplit.length);
+					for (String prop : propertySplit)
+					{
+						String[] propSplit = prop.split(",");
+						if (propSplit.length != 2)
+						{
+							_log.warning(StringUtil.concat("[CustomMinionsRespawnTime]: invalid config property -> CustomMinionsRespawnTime \"", prop, "\""));
+						}
+						
+						try
+						{
+							MINIONS_RESPAWN_TIME.put(Integer.valueOf(propSplit[0]), Integer.valueOf(propSplit[1]));
+						}
+						catch (NumberFormatException nfe)
+						{
+							if (!prop.isEmpty())
+								_log.warning(StringUtil.concat("[CustomMinionsRespawnTime]: invalid config property -> CustomMinionsRespawnTime \"", propSplit[0], "\"", propSplit[1]));
+						}
+					}
+					
 					RAID_DISABLE_CURSE = Boolean.parseBoolean(NPC.getProperty("DisableRaidCurse", "False"));
 					RAID_CHAOS_TIME = Integer.parseInt(NPC.getProperty("RaidChaosTime", "10"));
 					GRAND_CHAOS_TIME = Integer.parseInt(NPC.getProperty("GrandChaosTime", "10"));
@@ -2207,6 +2235,8 @@ public final class Config
 					RATE_QUEST_REWARD_SCROLL = Float.parseFloat(ratesSettings.getProperty("RateQuestRewardScroll", "1."));
 					RATE_QUEST_REWARD_RECIPE = Float.parseFloat(ratesSettings.getProperty("RateQuestRewardRecipe", "1."));
 					RATE_QUEST_REWARD_MATERIAL = Float.parseFloat(ratesSettings.getProperty("RateQuestRewardMaterial", "1."));
+					RATE_HB_TRUST_INCREASE = Float.parseFloat(ratesSettings.getProperty("RateHellboundTrustIncrease", "1."));
+					RATE_HB_TRUST_DECREASE = Float.parseFloat(ratesSettings.getProperty("RateHellboundTrustDecrease", "1."));
 					
 					RATE_VITALITY_LEVEL_1 = Float.parseFloat(ratesSettings.getProperty("RateVitalityLevel1", "1.5"));
 					RATE_VITALITY_LEVEL_2 = Float.parseFloat(ratesSettings.getProperty("RateVitalityLevel2", "2."));
@@ -2570,6 +2600,7 @@ public final class Config
 					L2JMOD_MULTILANG_DEFAULT = L2JModSettings.getProperty("MultiLangDefault", "en");
 					if (!L2JMOD_MULTILANG_ALLOWED.contains(L2JMOD_MULTILANG_DEFAULT))
 						_log.warning("MultiLang[Config.load()]: default language: " + L2JMOD_MULTILANG_DEFAULT + " is not in allowed list !");
+					L2JMOD_HELLBOUND_STATUS = Boolean.parseBoolean(L2JModSettings.getProperty("HellboundStatus", "False"));
 					L2JMOD_MULTILANG_VOICED_ALLOW = Boolean.parseBoolean(L2JModSettings.getProperty("MultiLangVoiceCommand", "True"));
 					L2JMOD_MULTILANG_SM_ENABLE = Boolean.parseBoolean(L2JModSettings.getProperty("MultiLangSystemMessageEnable", "false"));
 					allowed = L2JModSettings.getProperty("MultiLangSystemMessageAllowed", "").split(";");
@@ -2834,6 +2865,17 @@ public final class Config
 						Random_Of_Frintezza_Spawn = 8;
 					Random_Of_Frintezza_Spawn = Random_Of_Frintezza_Spawn * 3600000;
 					
+					INTERVAL_OF_BELETH_SPAWN = Integer.parseInt(grandbossSettings.getProperty("IntervalOfBelethSpawn", "192"));
+					if (INTERVAL_OF_BELETH_SPAWN < 1 || INTERVAL_OF_BELETH_SPAWN > 480)
+						INTERVAL_OF_BELETH_SPAWN = 192;
+					INTERVAL_OF_BELETH_SPAWN *= 3600000;
+					
+					RANDOM_OF_BELETH_SPAWN = Integer.parseInt(grandbossSettings.getProperty("RandomOfBelethSpawn", "148"));
+					if (RANDOM_OF_BELETH_SPAWN < 1 || RANDOM_OF_BELETH_SPAWN > 192)
+						RANDOM_OF_BELETH_SPAWN = 148;
+					RANDOM_OF_BELETH_SPAWN *= 3600000;
+					
+					BELETH_MIN_PLAYERS = Integer.parseInt(grandbossSettings.getProperty("BelethMinPlayers", "36"));
 				}
 				catch (Exception e)
 				{
@@ -3085,6 +3127,8 @@ public final class Config
 		else if (pName.equalsIgnoreCase("RateQuestRewardScroll")) RATE_QUEST_REWARD_SCROLL = Float.parseFloat(pValue);
 		else if (pName.equalsIgnoreCase("RateQuestRewardRecipe")) RATE_QUEST_REWARD_RECIPE = Float.parseFloat(pValue);
 		else if (pName.equalsIgnoreCase("RateQuestRewardMaterial")) RATE_QUEST_REWARD_MATERIAL = Float.parseFloat(pValue);
+		else if (pName.equalsIgnoreCase("RateHellboundTrustIncrease")) RATE_HB_TRUST_INCREASE = Float.parseFloat(pValue);
+		else if (pName.equalsIgnoreCase("RateHellboundTrustDecrease")) RATE_HB_TRUST_DECREASE = Float.parseFloat(pValue);
 		else if (pName.equalsIgnoreCase("RateVitalityLevel1")) RATE_VITALITY_LEVEL_1 = Float.parseFloat(pValue);
 		else if (pName.equalsIgnoreCase("RateVitalityLevel2")) RATE_VITALITY_LEVEL_2 = Float.parseFloat(pValue);
 		else if (pName.equalsIgnoreCase("RateVitalityLevel3")) RATE_VITALITY_LEVEL_3 = Float.parseFloat(pValue);

+ 3 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/GameServer.java

@@ -108,6 +108,7 @@ import com.l2jserver.gameserver.instancemanager.RaidBossSpawnManager;
 import com.l2jserver.gameserver.instancemanager.SiegeManager;
 import com.l2jserver.gameserver.instancemanager.TerritoryWarManager;
 import com.l2jserver.gameserver.instancemanager.TransformationManager;
+import com.l2jserver.gameserver.instancemanager.WalkingManager;
 import com.l2jserver.gameserver.instancemanager.ZoneManager;
 import com.l2jserver.gameserver.model.AutoChatHandler;
 import com.l2jserver.gameserver.model.AutoSpawnHandler;
@@ -260,6 +261,7 @@ public class GameServer
 		HerbDropTable.getInstance();
 		NpcTable.getInstance();
 		NpcWalkerRoutesTable.getInstance();
+		WalkingManager.getInstance();
 		ZoneManager.getInstance();
 		DoorTable.getInstance();
 		StaticObjects.getInstance();
@@ -268,6 +270,7 @@ public class GameServer
 		FortManager.getInstance().loadInstances();
 		NpcBufferTable.getInstance();
 		SpawnTable.getInstance();
+		HellboundManager.getInstance();
 		RaidBossSpawnManager.getInstance();
 		DayNightSpawnManager.getInstance().trim().notifyChangeMode();
 		GrandBossManager.getInstance().initZones();
@@ -378,7 +381,6 @@ public class GameServer
 		MerchantPriceConfigTable.getInstance().updateReferences();
 		CastleManager.getInstance().activateInstances();
 		FortManager.getInstance().activateInstances();
-		HellboundManager.getInstance();
 		
 		if (Config.ALLOW_MAIL)
 			MailManager.getInstance();

+ 12 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/ItemsAutoDestroy.java

@@ -67,7 +67,18 @@ public class ItemsAutoDestroy
 				_items.remove(item);
 			else
 			{
-				if (item.getItemType() == L2EtcItemType.HERB)
+				if (item.getItem().getAutoDestroyTime() > 0)
+				{
+					if ((curtime - item.getDropTime()) > item.getItem().getAutoDestroyTime())
+					{
+						L2World.getInstance().removeVisibleObject(item, item.getWorldRegion());
+						L2World.getInstance().removeObject(item);
+						_items.remove(item);
+						if (Config.SAVE_DROPPED_ITEM)
+							ItemsOnGroundManager.getInstance().removeObject(item);
+					}
+				}
+				else if (item.getItemType() == L2EtcItemType.HERB)
 				{
 					if ((curtime - item.getDropTime()) > Config.HERB_AUTO_DESTROY_TIME)
 					{

+ 3 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/Shutdown.java

@@ -28,6 +28,7 @@ import com.l2jserver.gameserver.instancemanager.CastleManorManager;
 import com.l2jserver.gameserver.instancemanager.CursedWeaponsManager;
 import com.l2jserver.gameserver.instancemanager.GlobalVariablesManager;
 import com.l2jserver.gameserver.instancemanager.GrandBossManager;
+import com.l2jserver.gameserver.instancemanager.HellboundManager;
 import com.l2jserver.gameserver.instancemanager.ItemAuctionManager;
 import com.l2jserver.gameserver.instancemanager.ItemsOnGroundManager;
 import com.l2jserver.gameserver.instancemanager.QuestManager;
@@ -547,6 +548,8 @@ public class Shutdown extends Thread
 		_log.info("RaidBossSpawnManager: All raidboss info saved("+tc.getEstimatedTimeAndRestartCounter()+"ms).");
 		GrandBossManager.getInstance().cleanUp();
 		_log.info("GrandBossManager: All Grand Boss info saved("+tc.getEstimatedTimeAndRestartCounter()+"ms).");
+		HellboundManager.getInstance().cleanUp();
+		_log.info("Hellbound Manager: Data saved(" + tc.getEstimatedTimeAndRestartCounter() + "ms).");
 		_log.info("TradeController saving data.. This action may take some minutes! Please wait until completed!");
 		TradeController.getInstance().dataCountStore();
 		_log.info("TradeController: All count Item saved("+tc.getEstimatedTimeAndRestartCounter()+"ms).");

+ 5 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/ai/L2CharacterAI.java

@@ -30,6 +30,7 @@ import javolution.util.FastList;
 
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.GeoData;
+import com.l2jserver.gameserver.instancemanager.WalkingManager;
 import com.l2jserver.gameserver.model.L2CharPosition;
 import com.l2jserver.gameserver.model.L2Effect;
 import com.l2jserver.gameserver.model.L2ItemInstance;
@@ -692,6 +693,10 @@ public class L2CharacterAI extends AbstractAI
 		}
 		clientStoppedMoving();
 		
+		//Walking Manager support
+		if (_actor instanceof L2Npc)
+			WalkingManager.getInstance().onArrived((L2Npc) _actor);
+		
 		// If the Intention was AI_INTENTION_MOVE_TO, set the Intention to AI_INTENTION_ACTIVE
 		if (getIntention() == AI_INTENTION_MOVE_TO)
 			setIntention(AI_INTENTION_ACTIVE);

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/datatables/MerchantPriceConfigTable.java

@@ -60,7 +60,7 @@ public class MerchantPriceConfigTable implements InstanceListManager
 	{
 		for (MerchantPriceConfig mpc : _mpcs.values())
 		{
-			if (npc.getWorldRegion().containsZone(mpc.getZoneId()))
+			if (npc.getWorldRegion() != null && npc.getWorldRegion().containsZone(mpc.getZoneId()))
 			{
 				return mpc;
 			}

+ 346 - 11
L2J_Server_BETA/java/com/l2jserver/gameserver/instancemanager/HellboundManager.java

@@ -14,34 +14,369 @@
  */
 package com.l2jserver.gameserver.instancemanager;
 
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.List;
+import java.util.concurrent.ScheduledFuture;
 import java.util.logging.Logger;
 
+import javolution.util.FastList;
+
+import com.l2jserver.Config;
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.datatables.NpcTable;
+import com.l2jserver.gameserver.datatables.SpawnTable;
+import com.l2jserver.gameserver.model.L2Spawn;
+import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
+import com.l2jserver.util.Rnd;
+
+/**
+ * @author _DS_, GKR
+ */
 public class HellboundManager
 {
 	private static final Logger _log = Logger.getLogger(HellboundManager.class.getName());
 	
+	private static final String LOAD_SPAWNS = "SELECT npc_templateid, locx, locy, locz, heading, " +
+		"respawn_delay, respawn_random, min_hellbound_level, " +
+		"max_hellbound_level FROM hellbound_spawnlist ORDER BY npc_templateid";
+	
+	private int _level = 0;
+	private int _trust = 0;
+	private int _maxTrust = 0;
+	private int _minTrust = 0;
+	
+	private ScheduledFuture<?> _engine = null;
+	private final List<HellboundSpawn> _population;
+	
 	private HellboundManager()
 	{
-		_log.info(getClass().getSimpleName()+": Initializing");
-		init();
+		_population = new FastList<HellboundSpawn>();
+		
+		loadData();
+		loadSpawns();
 	}
 	
-	private void init()
+	public final int getLevel()
+	{
+		return _level;
+	}
+	
+	public final synchronized void updateTrust(int t, boolean useRates)
 	{
-		_log.info(getClass().getSimpleName()+": Mode: dummy");
 		if (isLocked())
-			_log.info(getClass().getSimpleName()+": State: locked");
+		{
+			return;
+		}
+		
+		int reward = t;
+		if (useRates)
+		{
+			reward = (int) (t > 0 ? Config.RATE_HB_TRUST_INCREASE * t : Config.RATE_HB_TRUST_DECREASE * t);
+		}
+		
+		final int trust = Math.max(_trust + reward, _minTrust);
+		if (_maxTrust > 0)
+		{
+			_trust = Math.min(trust, _maxTrust);
+		}
 		else
-			_log.info(getClass().getSimpleName()+": State: unlocked");
+		{
+			_trust = trust;
+		}
+	}
+	
+	public final void setLevel(int lvl)
+	{
+		_level = lvl;
+	}
+	
+	public final int getTrust()
+	{
+		return _trust;
+	}
+	
+	public final int getMaxTrust()
+	{
+		return _maxTrust;
+	}
+	
+	public final int getMinTrust()
+	{
+		return _minTrust;
+	}
+	
+	public final void setMaxTrust(int trust)
+	{
+		_maxTrust = trust;
+		if ((_maxTrust > 0) && (_trust > _maxTrust))
+		{
+			_trust = _maxTrust;
+		}
+	}
+	
+	public final void setMinTrust(int trust)
+	{
+		_minTrust = trust;
+		
+		if (_trust >= _maxTrust)
+		{
+			_trust = _minTrust;
+		}
 	}
 	
 	/**
-	 * Returns true if Hellbound is locked
-	 * @return 
+	 * @return true if Hellbound is locked
 	 */
-	public boolean isLocked()
+	public final boolean isLocked()
+	{
+		return _level == 0;
+	}
+	
+	public final void unlock()
+	{
+		if (_level == 0)
+		{
+			setLevel(1);
+		}
+	}
+	
+	public final void registerEngine(Runnable r, int interval)
+	{
+		if (_engine != null)
+		{
+			_engine.cancel(false);
+		}
+		_engine = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(r, interval, interval);
+	}
+	
+	public final void doSpawn()
+	{
+		int added = 0;
+		int deleted = 0;
+		for (HellboundSpawn spawnDat : _population)
+		{
+			try
+			{
+				if (spawnDat == null)
+				{
+					continue;
+				}
+				
+				L2Npc npc = spawnDat.getLastSpawn();
+				if ((_level < spawnDat.getMinLvl()) || (_level > spawnDat.getMaxLvl()))
+				{
+					// npc should be removed
+					spawnDat.stopRespawn();
+					
+					if ((npc != null) && npc.isVisible())
+					{
+						npc.deleteMe();
+						deleted++;
+					}
+				}
+				else
+				{
+					// npc should be added
+					spawnDat.startRespawn();
+					npc = spawnDat.getLastSpawn();
+					if (npc == null)
+					{
+						npc = spawnDat.doSpawn();
+						added++;
+					}
+					else
+					{
+						if (npc.isDecayed())
+						{
+							npc.setDecayed(false);
+						}
+						if (npc.isDead())
+						{
+							npc.doRevive();
+						}
+						if (!npc.isVisible())
+						{
+							added++;
+						}
+						
+						npc.setCurrentHp(npc.getMaxHp());
+						npc.setCurrentMp(npc.getMaxMp());
+						// npc.spawnMe(spawnDat.getLocx(), spawnDat.getLocy(),
+						// spawnDat.getLocz());
+					}
+				}
+			}
+			catch (Exception e)
+			{
+				e.printStackTrace();
+			}
+		}
+		
+		if (added > 0)
+		{
+			_log.info("HellboundManager: Spawned " + added + " NPCs.");
+		}
+		if (deleted > 0)
+		{
+			_log.info("HellboundManager: Removed " + deleted + " NPCs.");
+		}
+	}
+	
+	public final void cleanUp()
+	{
+		saveData();
+		
+		if (_engine != null)
+		{
+			_engine.cancel(true);
+			_engine = null;
+		}
+		_population.clear();
+	}
+	
+	private final void loadData()
+	{
+		if (GlobalVariablesManager.getInstance().isVariableStored("HBLevel"))
+		{
+			_level = Integer.parseInt(GlobalVariablesManager.getInstance().getStoredVariable("HBLevel"));
+			_trust = Integer.parseInt(GlobalVariablesManager.getInstance().getStoredVariable("HBTrust"));
+		}
+		else
+		{
+			saveData();
+		}
+	}
+	
+	public final void saveData()
+	{
+		GlobalVariablesManager.getInstance().storeVariable("HBLevel", String.valueOf(_level));
+		GlobalVariablesManager.getInstance().storeVariable("HBTrust", String.valueOf(_trust));
+	}
+	
+	private final void loadSpawns()
+	{
+		Connection con = null;
+		try
+		{
+			con = L2DatabaseFactory.getInstance().getConnection();
+			final PreparedStatement statement = con.prepareStatement(LOAD_SPAWNS);
+			final ResultSet rset = statement.executeQuery();
+			
+			HellboundSpawn spawnDat;
+			L2NpcTemplate template;
+			while (rset.next())
+			{
+				template = NpcTable.getInstance().getTemplate(rset.getInt("npc_templateid"));
+				if (template != null)
+				{
+					spawnDat = new HellboundSpawn(template);
+					spawnDat.setAmount(1);
+					spawnDat.setLocx(rset.getInt("locx"));
+					spawnDat.setLocy(rset.getInt("locy"));
+					spawnDat.setLocz(rset.getInt("locz"));
+					spawnDat.setHeading(rset.getInt("heading"));
+					spawnDat.setRespawnDelay(rset.getInt("respawn_delay"));
+					spawnDat.setRespawnMinDelay(0);
+					spawnDat.setRespawnMaxDelay(0);
+					int respawnRandom = (rset.getInt("respawn_random"));
+					if (respawnRandom > 0) // Random respawn time, if needed
+					{
+						spawnDat.setRespawnMinDelay(Math.max(rset.getInt("respawn_delay") - respawnRandom, 1));
+						spawnDat.setRespawnMaxDelay(rset.getInt("respawn_delay") + respawnRandom);
+					}
+					spawnDat.setMinLvl(rset.getInt("min_hellbound_level"));
+					spawnDat.setMaxLvl(rset.getInt("max_hellbound_level"));
+					
+					// _population.put(spawnDat, null);
+					_population.add(spawnDat);
+					SpawnTable.getInstance().addNewSpawn(spawnDat, false);
+				}
+				else
+				{
+					_log.warning("HellboundManager: Data missing in NPC table for ID: " + rset.getInt("npc_templateid") + ".");
+				}
+			}
+			rset.close();
+		}
+		catch (Exception e)
+		{
+			_log.warning("HellboundManager: problem while loading spawns: " + e);
+		}
+		finally
+		{
+			L2DatabaseFactory.close(con);
+		}
+		_log.config("HellboundManager: Loaded " + _population.size() + " npc spawn locations.");
+	}
+	
+	public static final class HellboundSpawn extends L2Spawn
 	{
-		return false;
+		/** The delay between a L2NpcInstance remove and its re-spawn */
+		private int _respawnDelay;
+		
+		private int _minLvl;
+		private int _maxLvl;
+		
+		public HellboundSpawn(L2NpcTemplate mobTemplate) throws SecurityException, ClassNotFoundException, NoSuchMethodException
+		{
+			super(mobTemplate);
+		}
+		
+		public final int getMinLvl()
+		{
+			return _minLvl;
+		}
+		
+		public final void setMinLvl(int lvl)
+		{
+			_minLvl = lvl;
+		}
+		
+		public final int getMaxLvl()
+		{
+			return _maxLvl;
+		}
+		
+		public final void setMaxLvl(int lvl)
+		{
+			_maxLvl = lvl;
+		}
+		
+		@Override
+		public final void decreaseCount(L2Npc oldNpc)
+		{
+			if (getRespawnDelay() <= 0)
+			{
+				stopRespawn();
+			}
+			else if (getRespawnMaxDelay() > getRespawnMinDelay())
+			{
+				setRespawnDelay(Rnd.get(getRespawnMinDelay(), getRespawnMaxDelay()));
+			}
+			
+			super.decreaseCount(oldNpc);
+		}
+		
+		/**
+		 * @param i delay in seconds
+		 */
+		@Override
+		public void setRespawnDelay(int i)
+		{
+			_respawnDelay = i * 1000;
+			
+			super.setRespawnDelay(i);
+		}
+		
+		@Override
+		public int getRespawnDelay()
+		{
+			return _respawnDelay;
+		}
 	}
 	
 	public static final HellboundManager getInstance()
@@ -54,4 +389,4 @@ public class HellboundManager
 	{
 		protected static final HellboundManager _instance = new HellboundManager();
 	}
-}
+}

+ 1 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/L2Object.java

@@ -95,6 +95,7 @@ public abstract class L2Object
 		// Attackable
 		L2Attackable(L2Npc),
 		L2GuardInstance(L2Attackable),
+		L2QuestGuardInstance(L2GuardInstance),
 		L2MonsterInstance(L2Attackable),
 		L2ChestInstance(L2MonsterInstance),
 		L2ControllableMobInstance(L2MonsterInstance),

+ 2 - 2
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/L2Attackable.java

@@ -322,7 +322,7 @@ public class L2Attackable extends L2Npc
 	
 	private int _isSpoiledBy = 0;
 	
-	private int _onKillDelay = 5000;
+	protected int _onKillDelay = 5000;
 	
 	/**
 	 * Constructor of L2Attackable (use L2Character and L2NpcInstance constructor).
@@ -550,7 +550,7 @@ public class L2Attackable extends L2Npc
 		return true;
 	}
 	
-	private static class OnKillNotifyTask implements Runnable
+	protected static class OnKillNotifyTask implements Runnable
 	{
 		private final L2Attackable _attackable;
 		private final Quest _quest;

+ 2 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/L2Character.java

@@ -203,8 +203,9 @@ public abstract class L2Character extends L2Object
 	public static final byte ZONE_ALTERED = 19;
 	public static final byte ZONE_NOBOOKMARK = 20;
 	public static final byte ZONE_NOITEMDROP = 21;
+	public static final byte ZONE_NORESTART = 22;
 	
-	private final byte[] _zones = new byte[22];
+	private final byte[] _zones = new byte[23];
 	protected byte _zoneValidateCounter = 4;
 	
 	private L2Character _debugger = null;

+ 4 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/L2Npc.java

@@ -33,6 +33,7 @@ import com.l2jserver.gameserver.instancemanager.CHSiegeManager;
 import com.l2jserver.gameserver.instancemanager.CastleManager;
 import com.l2jserver.gameserver.instancemanager.FortManager;
 import com.l2jserver.gameserver.instancemanager.TownManager;
+import com.l2jserver.gameserver.instancemanager.WalkingManager;
 import com.l2jserver.gameserver.model.L2ItemInstance;
 import com.l2jserver.gameserver.model.L2NpcAIData;
 import com.l2jserver.gameserver.model.L2Object;
@@ -1448,6 +1449,9 @@ public class L2Npc extends L2Character
 		// Decrease its spawn counter
 		if (_spawn != null)
 			_spawn.decreaseCount(this);
+		
+		//Notify Walking Manager
+		WalkingManager.getInstance().onDeath(this);
 	}
 	
 	/**

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2GuardInstance.java

@@ -41,7 +41,7 @@ import com.l2jserver.util.Rnd;
  *
  * @version $Revision: 1.11.2.1.2.7 $ $Date: 2005/04/06 16:13:40 $
  */
-public final class L2GuardInstance extends L2Attackable
+public class L2GuardInstance extends L2Attackable
 {
 	private static Logger _log = Logger.getLogger(L2GuardInstance.class.getName());
 	

+ 89 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java

@@ -94,6 +94,7 @@ import com.l2jserver.gameserver.instancemanager.MapRegionManager;
 import com.l2jserver.gameserver.instancemanager.QuestManager;
 import com.l2jserver.gameserver.instancemanager.SiegeManager;
 import com.l2jserver.gameserver.instancemanager.TerritoryWarManager;
+import com.l2jserver.gameserver.instancemanager.ZoneManager;
 import com.l2jserver.gameserver.model.BlockList;
 import com.l2jserver.gameserver.model.CharEffectList;
 import com.l2jserver.gameserver.model.FishData;
@@ -174,7 +175,9 @@ import com.l2jserver.gameserver.model.olympiad.OlympiadManager;
 import com.l2jserver.gameserver.model.quest.Quest;
 import com.l2jserver.gameserver.model.quest.QuestState;
 import com.l2jserver.gameserver.model.quest.State;
+import com.l2jserver.gameserver.model.zone.L2ZoneType;
 import com.l2jserver.gameserver.model.zone.type.L2BossZone;
+import com.l2jserver.gameserver.model.zone.type.L2NoRestartZone;
 import com.l2jserver.gameserver.network.L2GameClient;
 import com.l2jserver.gameserver.network.SystemMessageId;
 import com.l2jserver.gameserver.network.communityserver.CommunityServerThread;
@@ -323,6 +326,11 @@ public final class L2PcInstance extends L2Playable
 	// Character Transformation SQL String Definitions:
 	private static final String SELECT_CHAR_TRANSFORM = "SELECT transform_id FROM characters WHERE charId=?";
 	private static final String UPDATE_CHAR_TRANSFORM = "UPDATE characters SET transform_id=? WHERE charId=?";
+
+	// Character zone restart time SQL String Definitions - L2Master mod
+	private static final String DELETE_ZONE_RESTART_LIMIT = "DELETE FROM character_norestart_zone_time WHERE charId = ?";
+	private static final String LOAD_ZONE_RESTART_LIMIT = "SELECT time_limit FROM character_norestart_zone_time WHERE charId = ?";
+	private static final String UPDATE_ZONE_RESTART_LIMIT = "REPLACE INTO character_norestart_zone_time (charId, time_limit) VALUES (?,?)";
 	
 	public static final int REQUEST_TIMEOUT = 15;
 	public static final int STORE_PRIVATE_NONE = 0;
@@ -386,6 +394,7 @@ public final class L2PcInstance extends L2Playable
 	private long _onlineBeginTime;
 	private long _lastAccess;
 	private long _uptime;
+	private long _zoneRestartLimitTime = 0;
 	
 	private final ReentrantLock _subclassLock = new ReentrantLock();
 	protected int _baseClass;
@@ -3031,6 +3040,84 @@ public final class L2PcInstance extends L2Playable
 		_onlineTime = time;
 		_onlineBeginTime = System.currentTimeMillis();
 	}
+
+	public long getZoneRestartLimitTime()
+	{
+		return _zoneRestartLimitTime;
+	}
+	
+	public void setZoneRestartLimitTime(long time)
+	{
+		_zoneRestartLimitTime = time;
+	}
+	
+	public void storeZoneRestartLimitTime()
+	{
+		if (isInsideZone(L2Character.ZONE_NORESTART))
+		{
+			L2NoRestartZone zone = null; 
+			for (L2ZoneType tmpzone : ZoneManager.getInstance().getZones(this))
+			{
+				if (tmpzone instanceof L2NoRestartZone)
+				{
+					zone = (L2NoRestartZone) tmpzone;
+					break;
+				}
+			}
+			if (zone != null)
+			{
+				Connection con = null;
+				try
+				{
+					con = L2DatabaseFactory.getInstance().getConnection();
+					final PreparedStatement statement = con.prepareStatement(UPDATE_ZONE_RESTART_LIMIT);
+					statement.setInt(1, getObjectId());
+					statement.setLong(2, System.currentTimeMillis() + (zone.getRestartAllowedTime() * 1000));
+					statement.execute();
+					statement.close();
+				}
+				catch (SQLException e)
+				{
+					_log.log(Level.WARNING, "Cannot store zone norestart limit for character "+getObjectId(), e);
+				}
+				finally
+				{
+					L2DatabaseFactory.close(con);
+				}
+			}
+		}
+	}
+	
+	private void restoreZoneRestartLimitTime()
+	{
+		Connection con = null;
+		try
+		{
+			con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement statement = con.prepareStatement(LOAD_ZONE_RESTART_LIMIT);
+			statement.setInt(1, getObjectId());
+			final ResultSet rset = statement.executeQuery();
+			
+			if (rset.next())
+			{
+				setZoneRestartLimitTime(rset.getLong("time_limit"));
+				statement.close();
+				statement = con.prepareStatement(DELETE_ZONE_RESTART_LIMIT);
+				statement.setInt(1, getObjectId());
+				statement.executeUpdate();
+			}
+			rset.close();
+			statement.close();
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.WARNING, "Could not restore "+this+" zone restart time: " + e.getMessage(), e);
+		}
+		finally
+		{
+			L2DatabaseFactory.close(con);
+		}
+	}
 	
 	/**
 	 * Return the PcInventory Inventory of the L2PcInstance contained in _inventory.<BR><BR>
@@ -7312,6 +7399,8 @@ public final class L2PcInstance extends L2Playable
 			
 			if (Config.STORE_UI_SETTINGS)
 				player.restoreUISettings();
+			
+			player.restoreZoneRestartLimitTime();
 		}
 		catch (Exception e)
 		{

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2TransformManagerInstance.java

@@ -121,7 +121,7 @@ public final class L2TransformManagerInstance extends L2MerchantInstance
 				}
 				else
 				{
-					NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
+					final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
 					html.setFile(player.getHtmlPrefix(), htmlFolder + "master_transformation008.htm");
 					player.sendPacket(html);
 				}

+ 3 - 2
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/knownlist/AttackableKnownList.java

@@ -17,6 +17,7 @@ package com.l2jserver.gameserver.model.actor.knownlist;
 import java.util.Collection;
 
 import com.l2jserver.gameserver.ai.CtrlIntention;
+import com.l2jserver.gameserver.instancemanager.WalkingManager;
 import com.l2jserver.gameserver.model.L2Object;
 import com.l2jserver.gameserver.model.actor.L2Attackable;
 import com.l2jserver.gameserver.model.actor.L2Character;
@@ -43,8 +44,8 @@ public class AttackableKnownList extends NpcKnownList
 		// Set the L2Attackable Intention to AI_INTENTION_IDLE
 		final Collection<L2PcInstance> known = getKnownPlayers().values();
 		
-		//FIXME: This is a temporary solution
-		if (getActiveChar().hasAI() && (known == null || known.isEmpty()))
+		//FIXME: This is a temporary solution && support for Walking Manager
+		if (getActiveChar().hasAI() && (known == null || known.isEmpty()) && !WalkingManager.getInstance().isRegistered(getActiveChar()))
 			getActiveChar().getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null);
 		
 		return true;

+ 80 - 3
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/knownlist/NpcKnownList.java

@@ -14,18 +14,27 @@
  */
 package com.l2jserver.gameserver.model.actor.knownlist;
 
+import java.util.Collection;
+import java.util.concurrent.ScheduledFuture;
+
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.ai.CtrlIntention;
+import com.l2jserver.gameserver.instancemanager.WalkingManager;
 import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.actor.L2Attackable;
 import com.l2jserver.gameserver.model.actor.L2Character;
 import com.l2jserver.gameserver.model.actor.L2Npc;
 import com.l2jserver.gameserver.model.actor.L2Playable;
 import com.l2jserver.gameserver.model.actor.instance.L2CabaleBufferInstance;
 import com.l2jserver.gameserver.model.actor.instance.L2FestivalGuideInstance;
 import com.l2jserver.gameserver.model.actor.instance.L2NpcInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 
 public class NpcKnownList extends CharKnownList
 {
 	// =========================================================
 	// Data Field
+	private ScheduledFuture<?> _trackingTask = null;
 	
 	// =========================================================
 	// Constructor
@@ -43,26 +52,94 @@ public class NpcKnownList extends CharKnownList
 	// =========================================================
 	// Property - Public
 	@Override
-	public L2Npc getActiveChar() { return (L2Npc)super.getActiveChar(); }
+	public L2Npc getActiveChar()
+	{
+		return (L2Npc) super.getActiveChar();
+	}
 	
 	@Override
-	public int getDistanceToForgetObject(L2Object object) { return 2 * getDistanceToWatchObject(object); }
+	public int getDistanceToForgetObject(L2Object object)
+	{
+		return 2 * getDistanceToWatchObject(object);
+	}
 	
 	@Override
 	public int getDistanceToWatchObject(L2Object object)
 	{
 		if (object instanceof L2FestivalGuideInstance)
+		{
 			return 4000;
+		}
 		
-		if (object instanceof L2NpcInstance || !(object instanceof L2Character))
+		if ((object instanceof L2NpcInstance) || !(object instanceof L2Character))
+		{
 			return 0;
+		}
 		
 		if (object instanceof L2CabaleBufferInstance)
+		{
 			return 900;
+		}
 		
 		if (object instanceof L2Playable)
+		{
 			return 1500;
+		}
 		
 		return 500;
 	}
+	
+	//L2Master mod - support for Walking monsters aggro
+	public void startTrackingTask()
+	{
+		if ((_trackingTask == null) && (getActiveChar().getAggroRange() > 0))
+		{
+			_trackingTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new TrackingTask(), 2000, 2000);
+		}
+	}
+	
+	//L2Master mod - support for Walking monsters aggro
+	public void stopTrackingTask()
+	{
+		if (_trackingTask != null)
+		{
+			_trackingTask.cancel(true);
+			_trackingTask = null;
+		}
+	}
+	
+	//L2Master mod - support for Walking monsters aggro
+	private class TrackingTask implements Runnable
+	{
+		public TrackingTask()
+		{
+			//
+		}
+		
+		@Override
+		public void run()
+		{
+			if (getActiveChar() instanceof L2Attackable)
+			{
+				final L2Attackable monster = (L2Attackable) getActiveChar();
+				if (monster.getAI().getIntention() == CtrlIntention.AI_INTENTION_MOVE_TO)
+				{
+					final Collection<L2PcInstance> players = getKnownPlayers().values();
+					if (players != null)
+					{
+						for (L2PcInstance pl : players)
+						{
+							if (pl.isInsideRadius(monster, monster.getAggroRange(), true, false) && !pl.isDead() && !pl.isInvul())
+							{
+								WalkingManager.getInstance().stopMoving(getActiveChar(), false);
+								monster.addDamageHate(pl, 0, 100);
+								monster.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, pl, null);
+								break;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
 }

+ 17 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/zone/type/L2DamageZone.java

@@ -43,6 +43,8 @@ public class L2DamageZone extends L2ZoneType
 	private int _startTask;
 	private int _reuseTask;
 	
+	private boolean _enabled;
+	
 	public L2DamageZone(int id)
 	{
 		super(id);
@@ -59,6 +61,9 @@ public class L2DamageZone extends L2ZoneType
 		_castleId = 0;
 		_castle = null;
 		
+		//enabled by default
+		_enabled = true;
+		
 		setTargetType(InstanceType.L2Playable); // default only playabale
 	}
 	
@@ -85,6 +90,10 @@ public class L2DamageZone extends L2ZoneType
 		{
 			_reuseTask = Integer.parseInt(value);
 		}
+		else if (name.equalsIgnoreCase("enabled"))
+		{
+			_enabled = Boolean.parseBoolean(value);
+		}
 		else
 			super.setParameter(name, value);
 	}
@@ -168,6 +177,9 @@ public class L2DamageZone extends L2ZoneType
 				}
 			}
 			
+			if (!_enabled)
+				return;
+			
 			for (L2Character temp : _dmgZone.getCharactersInsideArray())
 			{
 				if (temp != null && !temp.isDead())
@@ -191,6 +203,11 @@ public class L2DamageZone extends L2ZoneType
 		}
 	}
 	
+	public void setEnabled(boolean state)
+	{
+		_enabled = state;
+	}
+	
 	@Override
 	public void onDieInside(L2Character character)
 	{

+ 1 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/network/L2GameClient.java

@@ -747,6 +747,7 @@ public final class L2GameClient extends MMOClient<MMOConnection<L2GameClient>> i
 			{
 				if ((getActiveChar() != null) && !isDetached())
 				{
+					getActiveChar().storeZoneRestartLimitTime();
 					setDetached(true);
 					if (offlineMode(getActiveChar()))
 					{

+ 21 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/network/NpcStringId.java

@@ -11731,6 +11731,12 @@ public final class NpcStringId
 	 * Message: ** Vacant Seat **
 	 */
 	public static final NpcStringId _VACANT_SEAT;
+	
+	/**
+	 * ID: 1010643<br>
+	 * Message: $s1 minute(s) are remaining.
+	 */
+	public static final NpcStringId S1_MINUTES_REMAINING;
 
 	/**
 	 * ID: 1010644<br>
@@ -13711,6 +13717,12 @@ public final class NpcStringId
 	 * Message: You have done well in finding me, but I cannot just hand you the key!
 	 */
 	public static final NpcStringId YOU_HAVE_DONE_WELL_IN_FINDING_ME_BUT_I_CANNOT_JUST_HAND_YOU_THE_KEY;
+	
+	/**
+	 * ID: 1800079<br>
+	 * Message: $s1 second(s) remaining.
+	 */
+	public static final NpcStringId S1_SECONDS_REMAINING;
 
 	/**
 	 * ID: 1800081<br>
@@ -13927,6 +13939,12 @@ public final class NpcStringId
 	 * Message: We'll have dinner in hell!!!
 	 */
 	public static final NpcStringId WELL_HAVE_DINNER_IN_HELL;
+	
+	/**
+	 * ID: 1800117<br>
+	 * Message: Detonator initialization- time set for $s1 minute(s) from now-
+	 */
+	public static final NpcStringId DETONATOR_INITIALIZATION_TIME_S1_MINUTES_FROM_NOW;
 
 	/**
 	 * ID: 1800118<br>
@@ -23540,6 +23558,7 @@ public final class NpcStringId
 		GRARR_S1_TEAM_IS_USING_THE_HOT_SPRINGS_SULFUR_ON_THE_OPPONENTS_CAMP = new NpcStringId(1010640);
 		GRARR_S1_TEAM_IS_ATTEMPTING_TO_STEAL_THE_JACKPOT = new NpcStringId(1010641);
 		_VACANT_SEAT = new NpcStringId(1010642);
+		S1_MINUTES_REMAINING = new NpcStringId(1010643);
 		HOW_DARE_YOU_RUIN_THE_PERFORMANCE_OF_THE_DARK_CHOIR_UNFORGIVABLE = new NpcStringId(1010644);
 		GET_RID_OF_THE_INVADERS_WHO_INTERRUPT_THE_PERFORMANCE_OF_THE_DARK_CHOIR = new NpcStringId(1010645);
 		DONT_YOU_HEAR_THE_MUSIC_OF_DEATH_REVEAL_THE_HORROR_OF_THE_DARK_CHOIR = new NpcStringId(1010646);
@@ -23870,6 +23889,7 @@ public final class NpcStringId
 		GUYS_SHOW_THEM_OUR_POWER = new NpcStringId(1800076);
 		YOU_HAVE_FINALLY_COME_HERE_BUT_YOU_WILL_NOT_BE_ABLE_TO_FIND_THE_SECRET_ROOM = new NpcStringId(1800077);
 		YOU_HAVE_DONE_WELL_IN_FINDING_ME_BUT_I_CANNOT_JUST_HAND_YOU_THE_KEY = new NpcStringId(1800078);
+		S1_SECONDS_REMAINING = new NpcStringId(1800079);
 		THE_MATCH_IS_AUTOMATICALLY_CANCELED_BECAUSE_YOU_ARE_TOO_FAR_FROM_THE_ADMISSION_MANAGER = new NpcStringId(1800081);
 		UGH_I_HAVE_BUTTERFLIES_IN_MY_STOMACH_THE_SHOW_STARTS_SOON = new NpcStringId(1800082);
 		THANK_YOU_ALL_FOR_COMING_HERE_TONIGHT = new NpcStringId(1800083);
@@ -23906,6 +23926,7 @@ public final class NpcStringId
 		FREEDOM_OR_DEATH = new NpcStringId(1800114);
 		THIS_IS_THE_WILL_OF_TRUE_WARRIORS = new NpcStringId(1800115);
 		WELL_HAVE_DINNER_IN_HELL = new NpcStringId(1800116);
+		DETONATOR_INITIALIZATION_TIME_S1_MINUTES_FROM_NOW = new NpcStringId(1800117);
 		ZZZZ_CITY_INTERFERENCE_ERROR_FORWARD_EFFECT_CREATED = new NpcStringId(1800118);
 		ZZZZ_CITY_INTERFERENCE_ERROR_RECURRENCE_EFFECT_CREATED = new NpcStringId(1800119);
 		GUARDS_ARE_COMING_RUN = new NpcStringId(1800120);

+ 7 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/network/SystemMessageId.java

@@ -13385,6 +13385,12 @@ public final class SystemMessageId
 	 */
 	public static final SystemMessageId NPCS_RECAPTURED_FORTRESS;
 	
+	/**
+	* ID: 2291<br>
+	* Message: You can operate the machine when you participate in the party.
+	*/
+	public static final SystemMessageId CAN_OPERATE_MACHINE_WHEN_IN_PARTY;
+	
 	/**
 	 * ID: 2293<br>
 	 * Message: Current location: $s1, $s2, $s3 (inside the Steel Citadel)
@@ -17053,6 +17059,7 @@ public final class SystemMessageId
 		USE_SHORTCUT_CONFIRM = new SystemMessageId(2272);
 		SKILL_NOT_FOR_SUBCLASS = new SystemMessageId(2273);
 		NPCS_RECAPTURED_FORTRESS = new SystemMessageId(2276);
+		CAN_OPERATE_MACHINE_WHEN_IN_PARTY = new SystemMessageId(2291);
 		LOC_IN_STEEL_CITADEL_S1_S2_S3 = new SystemMessageId(2293);
 		GAINED_VITALITY_POINTS = new SystemMessageId(2296);
 		LOC_STEEL_CITADEL = new SystemMessageId(2301);

+ 11 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/templates/item/L2Item.java

@@ -166,6 +166,7 @@ public abstract class L2Item
 	private final int _crystalType; // default to none-grade
 	private final int _duration;
 	private final int _time;
+	private final int _autoDestroyTime;
 	private final int _bodyPart;
 	private final int _referencePrice;
 	private final int _crystalCount;
@@ -210,6 +211,7 @@ public abstract class L2Item
 		_materialType = ItemTable._materials.get(set.getString("material", "steel")); // default is steel, yeah and what?
 		_duration = set.getInteger("duration", -1);
 		_time = set.getInteger("time", -1);
+		_autoDestroyTime = set.getInteger("auto_destroy_time", -1) * 1000;
 		_bodyPart = ItemTable._slots.get(set.getString("bodypart", "none"));
 		_referencePrice = set.getInteger("price", 0);
 		_crystalType = ItemTable._crystalTypes.get(set.getString("crystal_type", "none")); // default to none-grade
@@ -327,6 +329,15 @@ public abstract class L2Item
 	{
 		return _time;
 	}
+	
+	/**
+	 * @return the auto destroy time of the item in seconds: 0 or less - default
+	 */
+	public final int getAutoDestroyTime()
+	{
+		return _autoDestroyTime;
+	}
+	
 	/**
 	 * Returns the ID of the iden
 	 * @return int