소스 검색

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 년 전
부모
커밋
cbc49d5757
25개의 변경된 파일684개의 추가작업 그리고 25개의 파일을 삭제
  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