瀏覽代碼

BETA: Punishment system rework:
* Added ability to keep unlimited amount of punishments.
* Added ability to ban/jail by char, account and ip.
* Each ban now has issuer and can be limited for specified time.
* Reviewed by: Zoey76, DrHouse

Rumen Nikiforov 12 年之前
父節點
當前提交
b46b58c359
共有 27 個文件被更改,包括 822 次插入395 次删除
  1. 3 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/GameServer.java
  2. 5 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/LoginServerThread.java
  3. 2 2
      L2J_Server_BETA/java/com/l2jserver/gameserver/communitybbs/Manager/RegionBBSManager.java
  4. 38 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/handler/IPunishmentHandler.java
  5. 72 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/handler/PunishmentHandler.java
  6. 136 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/instancemanager/PunishmentManager.java
  7. 36 299
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java
  8. 46 45
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/tasks/player/TeleportTask.java
  9. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/entity/FortSiege.java
  10. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/entity/Siege.java
  11. 91 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/holders/PunishmentHolder.java
  12. 42 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/punishment/PunishmentAffect.java
  13. 227 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/punishment/PunishmentTask.java
  14. 41 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/punishment/PunishmentType.java
  15. 21 16
      L2J_Server_BETA/java/com/l2jserver/gameserver/model/zone/type/L2JailZone.java
  16. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/L2GameClient.java
  17. 12 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/CharacterSelect.java
  18. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/RequestDropItem.java
  19. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/RequestJoinParty.java
  20. 2 2
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/RequestRestartPoint.java
  21. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/RequestSendPost.java
  22. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/Say2.java
  23. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/TradeRequest.java
  24. 1 1
      L2J_Server_BETA/java/com/l2jserver/gameserver/network/serverpackets/Die.java
  25. 12 19
      L2J_Server_BETA/java/com/l2jserver/gameserver/util/FloodProtectorAction.java
  26. 6 2
      L2J_Server_BETA/java/com/l2jserver/gameserver/util/IllegalPlayerAction.java
  27. 21 0
      L2J_Server_BETA/java/com/l2jserver/gameserver/util/Util.java

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

@@ -107,6 +107,7 @@ import com.l2jserver.gameserver.instancemanager.MailManager;
 import com.l2jserver.gameserver.instancemanager.MapRegionManager;
 import com.l2jserver.gameserver.instancemanager.MercTicketManager;
 import com.l2jserver.gameserver.instancemanager.PetitionManager;
+import com.l2jserver.gameserver.instancemanager.PunishmentManager;
 import com.l2jserver.gameserver.instancemanager.QuestManager;
 import com.l2jserver.gameserver.instancemanager.RaidBossPointsManager;
 import com.l2jserver.gameserver.instancemanager.RaidBossSpawnManager;
@@ -370,6 +371,8 @@ public class GameServer
 			GeoEditorListener.getInstance();
 		}
 		
+		PunishmentManager.getInstance();
+		
 		Runtime.getRuntime().addShutdownHook(Shutdown.getInstance());
 		
 		_log.info("IdFactory: Free ObjectID's remaining: " + IdFactory.getInstance().size());

+ 5 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/LoginServerThread.java

@@ -757,6 +757,11 @@ public class LoginServerThread extends Thread
 		}
 	}
 	
+	public L2GameClient getClient(String name)
+	{
+		return name != null ? _accountsInGameServer.get(name) : null;
+	}
+	
 	public static class SessionKey
 	{
 		public int playOkID1;

+ 2 - 2
L2J_Server_BETA/java/com/l2jserver/gameserver/communitybbs/Manager/RegionBBSManager.java

@@ -208,7 +208,7 @@ public class RegionBBSManager extends BaseBBSManager
 					separateAndSend(htmlCode.toString(), activeChar);
 					return;
 				}
-				if (Config.JAIL_DISABLE_CHAT && receiver.isInJail())
+				if (Config.JAIL_DISABLE_CHAT && receiver.isJailed())
 				{
 					activeChar.sendMessage("Player is in jail.");
 					return;
@@ -218,7 +218,7 @@ public class RegionBBSManager extends BaseBBSManager
 					activeChar.sendMessage("Player is chat banned.");
 					return;
 				}
-				if (activeChar.isInJail() && Config.JAIL_DISABLE_CHAT)
+				if (activeChar.isJailed() && Config.JAIL_DISABLE_CHAT)
 				{
 					activeChar.sendMessage("You can not chat while in jail.");
 					return;

+ 38 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/handler/IPunishmentHandler.java

@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2004-2013 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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.
+ * 
+ * L2J Server 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 com.l2jserver.gameserver.handler;
+
+import java.util.logging.Logger;
+
+import com.l2jserver.gameserver.model.punishment.PunishmentTask;
+import com.l2jserver.gameserver.model.punishment.PunishmentType;
+
+/**
+ * @author UnAfraid
+ */
+public interface IPunishmentHandler
+{
+	static final Logger _log = Logger.getLogger(IPunishmentHandler.class.getName());
+	
+	public void onStart(PunishmentTask task);
+	
+	public void onEnd(PunishmentTask task);
+	
+	public PunishmentType getType();
+}

+ 72 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/handler/PunishmentHandler.java

@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2004-2013 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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.
+ * 
+ * L2J Server 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 com.l2jserver.gameserver.handler;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.l2jserver.gameserver.model.punishment.PunishmentType;
+
+/**
+ * This class manages handlers of punishments.
+ * @author UnAfraid
+ */
+public class PunishmentHandler implements IHandler<IPunishmentHandler, PunishmentType>
+{
+	private final Map<PunishmentType, IPunishmentHandler> _handlers = new HashMap<>();
+	
+	protected PunishmentHandler()
+	{
+		
+	}
+	
+	@Override
+	public void registerHandler(IPunishmentHandler handler)
+	{
+		_handlers.put(handler.getType(), handler);
+	}
+	
+	@Override
+	public synchronized void removeHandler(IPunishmentHandler handler)
+	{
+		_handlers.remove(handler.getType());
+	}
+	
+	@Override
+	public IPunishmentHandler getHandler(PunishmentType val)
+	{
+		return _handlers.get(val);
+	}
+	
+	@Override
+	public int size()
+	{
+		return _handlers.size();
+	}
+	
+	public static PunishmentHandler getInstance()
+	{
+		return SingletonHolder._instance;
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final PunishmentHandler _instance = new PunishmentHandler();
+	}
+}

+ 136 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/instancemanager/PunishmentManager.java

@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2004-2013 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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.
+ * 
+ * L2J Server 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 com.l2jserver.gameserver.instancemanager;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.model.holders.PunishmentHolder;
+import com.l2jserver.gameserver.model.punishment.PunishmentAffect;
+import com.l2jserver.gameserver.model.punishment.PunishmentTask;
+import com.l2jserver.gameserver.model.punishment.PunishmentType;
+
+/**
+ * @author UnAfraid
+ */
+public class PunishmentManager
+{
+	private static final Logger _log = Logger.getLogger(PunishmentManager.class.getName());
+	
+	private final Map<PunishmentAffect, PunishmentHolder> _tasks = new ConcurrentHashMap<>();
+	
+	protected PunishmentManager()
+	{
+		load();
+	}
+	
+	private void load()
+	{
+		// Initiate task holders.
+		for (PunishmentAffect affect : PunishmentAffect.values())
+		{
+			_tasks.put(affect, new PunishmentHolder());
+		}
+		
+		int initiated = 0;
+		int expired = 0;
+		
+		// Load punishments.
+		try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+			Statement st = con.createStatement();
+			ResultSet rset = st.executeQuery("SELECT * FROM punishments"))
+		{
+			while (rset.next())
+			{
+				final Object key = rset.getInt("key");
+				final PunishmentAffect affect = PunishmentAffect.getByName(rset.getString("affect"));
+				final PunishmentType type = PunishmentType.getByName(rset.getString("type"));
+				final long expirationTime = rset.getLong("expiration");
+				final String reason = rset.getString("reason");
+				final String punishedBy = rset.getString("punishedBy");
+				if ((type != null) && (affect != null))
+				{
+					PunishmentTask task = new PunishmentTask(key, affect, type, expirationTime, reason, punishedBy, true);
+					if (task.isExpired())
+					{
+						expired++;
+					}
+					else
+					{
+						initiated++;
+						_tasks.get(affect).addPunishment(task);
+					}
+				}
+			}
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.WARNING, getClass().getSimpleName() + ": Error while loading punishments: ", e);
+		}
+		
+		_log.log(Level.INFO, getClass().getSimpleName() + ": Loaded " + initiated + " active and " + expired + " expired punishments.");
+	}
+	
+	public void startPunishment(PunishmentTask task)
+	{
+		_tasks.get(task.getAffect()).addPunishment(task);
+	}
+	
+	public void stopPunishment(Object key, PunishmentAffect affect, PunishmentType type)
+	{
+		final PunishmentTask task = getPunishment(key, affect, type);
+		if (task != null)
+		{
+			_tasks.get(affect).stopPunishment(task);
+		}
+	}
+	
+	public boolean hasPunishment(Object key, PunishmentAffect affect, PunishmentType type)
+	{
+		final PunishmentHolder holder = _tasks.get(affect);
+		return holder.hasPunishment(key, type);
+	}
+	
+	public long getPunishmentExpiration(Object key, PunishmentAffect affect, PunishmentType type)
+	{
+		final PunishmentTask p = getPunishment(key, affect, type);
+		return p != null ? p.getExpirationTime() : 0;
+	}
+	
+	private PunishmentTask getPunishment(Object key, PunishmentAffect affect, PunishmentType type)
+	{
+		return _tasks.get(affect).getPunishment(key, type);
+	}
+	
+	public static final PunishmentManager getInstance()
+	{
+		return SingletonHolder._instance;
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final PunishmentManager _instance = new PunishmentManager();
+	}
+}

+ 36 - 299
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java

@@ -101,6 +101,7 @@ import com.l2jserver.gameserver.instancemanager.HandysBlockCheckerManager;
 import com.l2jserver.gameserver.instancemanager.InstanceManager;
 import com.l2jserver.gameserver.instancemanager.ItemsOnGroundManager;
 import com.l2jserver.gameserver.instancemanager.MapRegionManager;
+import com.l2jserver.gameserver.instancemanager.PunishmentManager;
 import com.l2jserver.gameserver.instancemanager.QuestManager;
 import com.l2jserver.gameserver.instancemanager.SiegeManager;
 import com.l2jserver.gameserver.instancemanager.TerritoryWarManager;
@@ -160,7 +161,6 @@ import com.l2jserver.gameserver.model.actor.tasks.player.HerbTask;
 import com.l2jserver.gameserver.model.actor.tasks.player.InventoryEnableTask;
 import com.l2jserver.gameserver.model.actor.tasks.player.LookingForFishTask;
 import com.l2jserver.gameserver.model.actor.tasks.player.PetFeedTask;
-import com.l2jserver.gameserver.model.actor.tasks.player.PunishTask;
 import com.l2jserver.gameserver.model.actor.tasks.player.PvPFlagTask;
 import com.l2jserver.gameserver.model.actor.tasks.player.RecoBonusTaskEnd;
 import com.l2jserver.gameserver.model.actor.tasks.player.RecoGiveTask;
@@ -219,6 +219,8 @@ import com.l2jserver.gameserver.model.multisell.PreparedListContainer;
 import com.l2jserver.gameserver.model.olympiad.OlympiadGameManager;
 import com.l2jserver.gameserver.model.olympiad.OlympiadGameTask;
 import com.l2jserver.gameserver.model.olympiad.OlympiadManager;
+import com.l2jserver.gameserver.model.punishment.PunishmentAffect;
+import com.l2jserver.gameserver.model.punishment.PunishmentType;
 import com.l2jserver.gameserver.model.quest.Quest;
 import com.l2jserver.gameserver.model.quest.Quest.QuestEventType;
 import com.l2jserver.gameserver.model.quest.QuestState;
@@ -350,8 +352,8 @@ public final class L2PcInstance extends L2Playable
 	
 	// Character Character SQL String Definitions:
 	private static final String INSERT_CHARACTER = "INSERT INTO characters (account_name,charId,char_name,level,maxHp,curHp,maxCp,curCp,maxMp,curMp,face,hairStyle,hairColor,sex,exp,sp,karma,fame,pvpkills,pkkills,clanid,race,classid,deletetime,cancraft,title,title_color,accesslevel,online,isin7sdungeon,clan_privs,wantspeace,base_class,newbie,nobless,power_grade,createDate) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
-	private static final String UPDATE_CHARACTER = "UPDATE characters SET level=?,maxHp=?,curHp=?,maxCp=?,curCp=?,maxMp=?,curMp=?,face=?,hairStyle=?,hairColor=?,sex=?,heading=?,x=?,y=?,z=?,exp=?,expBeforeDeath=?,sp=?,karma=?,fame=?,pvpkills=?,pkkills=?,clanid=?,race=?,classid=?,deletetime=?,title=?,title_color=?,accesslevel=?,online=?,isin7sdungeon=?,clan_privs=?,wantspeace=?,base_class=?,onlinetime=?,punish_level=?,punish_timer=?,newbie=?,nobless=?,power_grade=?,subpledge=?,lvl_joined_academy=?,apprentice=?,sponsor=?,clan_join_expiry_time=?,clan_create_expiry_time=?,char_name=?,death_penalty_level=?,bookmarkslot=?,vitality_points=?,language=? WHERE charId=?";
-	private static final String RESTORE_CHARACTER = "SELECT account_name, charId, char_name, level, maxHp, curHp, maxCp, curCp, maxMp, curMp, face, hairStyle, hairColor, sex, heading, x, y, z, exp, expBeforeDeath, sp, karma, fame, pvpkills, pkkills, clanid, race, classid, deletetime, cancraft, title, title_color, accesslevel, online, char_slot, lastAccess, clan_privs, wantspeace, base_class, onlinetime, isin7sdungeon, punish_level, punish_timer, newbie, nobless, power_grade, subpledge, lvl_joined_academy, apprentice, sponsor, clan_join_expiry_time,clan_create_expiry_time,death_penalty_level,bookmarkslot,vitality_points,createDate,language FROM characters WHERE charId=?";
+	private static final String UPDATE_CHARACTER = "UPDATE characters SET level=?,maxHp=?,curHp=?,maxCp=?,curCp=?,maxMp=?,curMp=?,face=?,hairStyle=?,hairColor=?,sex=?,heading=?,x=?,y=?,z=?,exp=?,expBeforeDeath=?,sp=?,karma=?,fame=?,pvpkills=?,pkkills=?,clanid=?,race=?,classid=?,deletetime=?,title=?,title_color=?,accesslevel=?,online=?,isin7sdungeon=?,clan_privs=?,wantspeace=?,base_class=?,onlinetime=?,newbie=?,nobless=?,power_grade=?,subpledge=?,lvl_joined_academy=?,apprentice=?,sponsor=?,clan_join_expiry_time=?,clan_create_expiry_time=?,char_name=?,death_penalty_level=?,bookmarkslot=?,vitality_points=?,language=? WHERE charId=?";
+	private static final String RESTORE_CHARACTER = "SELECT * FROM characters WHERE charId=?";
 	
 	// Character Teleport Bookmark:
 	private static final String INSERT_TP_BOOKMARK = "INSERT INTO character_tpbookmark (charId,Id,x,y,z,icon,tag,name) values (?,?,?,?,?,?,?,?)";
@@ -519,43 +521,11 @@ public final class L2PcInstance extends L2Playable
 	
 	private final Map<Integer, TeleportBookmark> _tpbookmarks = new FastMap<>();
 	
-	private PunishLevel _punishLevel = PunishLevel.NONE;
-	private long _punishTimer = 0;
-	private ScheduledFuture<?> _punishTask;
-	
 	private boolean _canFeed;
 	private int _eventEffectId = 0;
 	private boolean _isInSiege;
 	private boolean _isInHideoutSiege = false;
 	
-	public enum PunishLevel
-	{
-		NONE(0, ""),
-		CHAT(1, "chat banned"),
-		JAIL(2, "jailed"),
-		CHAR(3, "banned"),
-		ACC(4, "banned");
-		
-		private final int punValue;
-		private final String punString;
-		
-		PunishLevel(int value, String string)
-		{
-			punValue = value;
-			punString = string;
-		}
-		
-		public int value()
-		{
-			return punValue;
-		}
-		
-		public String string()
-		{
-			return punString;
-		}
-	}
-	
 	/** Olympiad */
 	private boolean _inOlympiadMode = false;
 	private boolean _OlympiadStart = false;
@@ -4340,6 +4310,16 @@ public final class L2PcInstance extends L2Playable
 		_client = client;
 	}
 	
+	public String getIPAddress()
+	{
+		String ip = "N/A";
+		if ((_client != null) && (_client.getConnectionAddress() != null))
+		{
+			ip = _client.getConnectionAddress().getHostAddress();
+		}
+		return ip;
+	}
+	
 	/**
 	 * Close the active connection with the client.
 	 * @param closeClient
@@ -6239,7 +6219,6 @@ public final class L2PcInstance extends L2Playable
 		storePetFood(_mountNpcId);
 		stopRentPet();
 		stopPvpRegTask();
-		stopPunishTask(true);
 		stopSoulTask();
 		stopChargeTask();
 		stopFameTask();
@@ -7514,15 +7493,6 @@ public final class L2PcInstance extends L2Playable
 					player.setSponsor(rset.getInt("sponsor"));
 					player.setLvlJoinedAcademy(rset.getInt("lvl_joined_academy"));
 					player.setIsIn7sDungeon(rset.getInt("isin7sdungeon") == 1);
-					player.setPunishLevel(rset.getInt("punish_level"));
-					if (player.getPunishLevel() != PunishLevel.NONE)
-					{
-						player.setPunishTimer(rset.getLong("punish_timer"));
-					}
-					else
-					{
-						player.setPunishTimer(0);
-					}
 					
 					CursedWeaponsManager.getInstance().checkPlayer(player);
 					
@@ -7974,23 +7944,21 @@ public final class L2PcInstance extends L2Playable
 			}
 			
 			statement.setLong(35, totalOnlineTime);
-			statement.setInt(36, getPunishLevel().value());
-			statement.setLong(37, getPunishTimer());
-			statement.setInt(38, getNewbie());
-			statement.setInt(39, isNoble() ? 1 : 0);
-			statement.setInt(40, getPowerGrade());
-			statement.setInt(41, getPledgeType());
-			statement.setInt(42, getLvlJoinedAcademy());
-			statement.setLong(43, getApprentice());
-			statement.setLong(44, getSponsor());
-			statement.setLong(45, getClanJoinExpiryTime());
-			statement.setLong(46, getClanCreateExpiryTime());
-			statement.setString(47, getName());
-			statement.setLong(48, getDeathPenaltyBuffLevel());
-			statement.setInt(49, getBookMarkSlot());
-			statement.setInt(50, getVitalityPoints());
-			statement.setString(51, getLang());
-			statement.setInt(52, getObjectId());
+			statement.setInt(36, getNewbie());
+			statement.setInt(37, isNoble() ? 1 : 0);
+			statement.setInt(38, getPowerGrade());
+			statement.setInt(39, getPledgeType());
+			statement.setInt(40, getLvlJoinedAcademy());
+			statement.setLong(41, getApprentice());
+			statement.setLong(42, getSponsor());
+			statement.setLong(43, getClanJoinExpiryTime());
+			statement.setLong(44, getClanCreateExpiryTime());
+			statement.setString(45, getName());
+			statement.setLong(46, getDeathPenaltyBuffLevel());
+			statement.setInt(47, getBookMarkSlot());
+			statement.setInt(48, getVitalityPoints());
+			statement.setString(49, getLang());
+			statement.setInt(50, getObjectId());
 			
 			statement.execute();
 			statement.close();
@@ -10437,7 +10405,7 @@ public final class L2PcInstance extends L2Playable
 	 */
 	public boolean canDuel()
 	{
-		if (isInCombat() || (getPunishLevel() == PunishLevel.JAIL))
+		if (isInCombat() || isJailed())
 		{
 			_noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_CURRENTLY_ENGAGED_IN_BATTLE;
 			return false;
@@ -11104,9 +11072,6 @@ public final class L2PcInstance extends L2Playable
 			}
 		}
 		
-		// jail task
-		updatePunishState();
-		
 		if (isGM())
 		{
 			if (isInvul())
@@ -12835,247 +12800,19 @@ public final class L2PcInstance extends L2Playable
 	}
 	
 	/**
-	 * returns punishment level of player
-	 * @return
+	 * @return {@code true} if player is jailed, {@code false} otherwise.
 	 */
-	public PunishLevel getPunishLevel()
+	public boolean isJailed()
 	{
-		return _punishLevel;
+		return PunishmentManager.getInstance().hasPunishment(getObjectId(), PunishmentAffect.CHARACTER, PunishmentType.JAIL) || PunishmentManager.getInstance().hasPunishment(getAccountName(), PunishmentAffect.ACCOUNT, PunishmentType.JAIL) || PunishmentManager.getInstance().hasPunishment(getIPAddress(), PunishmentAffect.IP, PunishmentType.JAIL);
 	}
 	
 	/**
-	 * @return True if player is jailed
-	 */
-	public boolean isInJail()
-	{
-		return _punishLevel == PunishLevel.JAIL;
-	}
-	
-	/**
-	 * @return True if player is chat banned
+	 * @return {@code true} if player is chat banned, {@code false} otherwise.
 	 */
 	public boolean isChatBanned()
 	{
-		return _punishLevel == PunishLevel.CHAT;
-	}
-	
-	public void setPunishLevel(int state)
-	{
-		switch (state)
-		{
-			case 0:
-			{
-				_punishLevel = PunishLevel.NONE;
-				break;
-			}
-			case 1:
-			{
-				_punishLevel = PunishLevel.CHAT;
-				break;
-			}
-			case 2:
-			{
-				_punishLevel = PunishLevel.JAIL;
-				break;
-			}
-			case 3:
-			{
-				_punishLevel = PunishLevel.CHAR;
-				break;
-			}
-			case 4:
-			{
-				_punishLevel = PunishLevel.ACC;
-				break;
-			}
-		}
-	}
-	
-	/**
-	 * Sets punish level for player based on delay
-	 * @param state
-	 * @param delayInMinutes 0 - Indefinite
-	 */
-	public void setPunishLevel(PunishLevel state, int delayInMinutes)
-	{
-		long delayInMilliseconds = delayInMinutes * 60000L;
-		switch (state)
-		{
-			case NONE: // Remove Punishments
-			{
-				switch (_punishLevel)
-				{
-					case CHAT:
-					{
-						_punishLevel = state;
-						stopPunishTask(true);
-						sendPacket(new EtcStatusUpdate(this));
-						sendMessage("Your Chat ban has been lifted");
-						break;
-					}
-					case JAIL:
-					{
-						_punishLevel = state;
-						// Open a Html message to inform the player
-						NpcHtmlMessage htmlMsg = new NpcHtmlMessage(0);
-						String jailInfos = HtmCache.getInstance().getHtm(getHtmlPrefix(), "data/html/jail_out.htm");
-						if (jailInfos != null)
-						{
-							htmlMsg.setHtml(jailInfos);
-						}
-						else
-						{
-							htmlMsg.setHtml("<html><body>You are free for now, respect server rules!</body></html>");
-						}
-						sendPacket(htmlMsg);
-						stopPunishTask(true);
-						teleToLocation(17836, 170178, -3507, true); // Floran
-						break;
-					}
-				}
-				break;
-			}
-			case CHAT: // Chat Ban
-			{
-				// not allow player to escape jail using chat ban
-				if (_punishLevel == PunishLevel.JAIL)
-				{
-					break;
-				}
-				_punishLevel = state;
-				_punishTimer = 0;
-				sendPacket(new EtcStatusUpdate(this));
-				// Remove the task if any
-				stopPunishTask(false);
-				
-				if (delayInMinutes > 0)
-				{
-					_punishTimer = delayInMilliseconds;
-					
-					// start the countdown
-					_punishTask = ThreadPoolManager.getInstance().scheduleGeneral(new PunishTask(this), _punishTimer);
-					sendMessage("You are chat banned for " + delayInMinutes + " minutes.");
-				}
-				else
-				{
-					sendMessage("You have been chat banned");
-				}
-				break;
-				
-			}
-			case JAIL: // Jail Player
-			{
-				_punishLevel = state;
-				_punishTimer = 0;
-				// Remove the task if any
-				stopPunishTask(false);
-				
-				if (delayInMinutes > 0)
-				{
-					_punishTimer = delayInMilliseconds;
-					
-					// start the countdown
-					_punishTask = ThreadPoolManager.getInstance().scheduleGeneral(new PunishTask(this), _punishTimer);
-					sendMessage("You are in jail for " + delayInMinutes + " minutes.");
-				}
-				
-				if (!TvTEvent.isInactive() && TvTEvent.isPlayerParticipant(getObjectId()))
-				{
-					TvTEvent.removeParticipant(getObjectId());
-				}
-				if (OlympiadManager.getInstance().isRegisteredInComp(this))
-				{
-					OlympiadManager.getInstance().removeDisconnectedCompetitor(this);
-				}
-				
-				// Open a Html message to inform the player
-				NpcHtmlMessage htmlMsg = new NpcHtmlMessage(0);
-				String jailInfos = HtmCache.getInstance().getHtm(getHtmlPrefix(), "data/html/jail_in.htm");
-				if (jailInfos != null)
-				{
-					htmlMsg.setHtml(jailInfos);
-				}
-				else
-				{
-					htmlMsg.setHtml("<html><body>You have been put in jail by an admin.</body></html>");
-				}
-				sendPacket(htmlMsg);
-				setInstanceId(0);
-				setIsIn7sDungeon(false);
-				
-				teleToLocation(-114356, -249645, -2984, false); // Jail
-				break;
-			}
-			case CHAR: // Ban Character
-			{
-				setAccessLevel(-1);
-				logout();
-				break;
-			}
-			case ACC: // Ban Account
-			{
-				setAccountAccesslevel(-1);
-				logout();
-				break;
-			}
-			default:
-			{
-				_punishLevel = state;
-				break;
-			}
-		}
-		
-		// store in database
-		storeCharBase();
-	}
-	
-	public long getPunishTimer()
-	{
-		return _punishTimer;
-	}
-	
-	public void setPunishTimer(long time)
-	{
-		_punishTimer = time;
-	}
-	
-	private void updatePunishState()
-	{
-		if (getPunishLevel() != PunishLevel.NONE)
-		{
-			// If punish timer exists, restart punishtask.
-			if (_punishTimer > 0)
-			{
-				_punishTask = ThreadPoolManager.getInstance().scheduleGeneral(new PunishTask(this), _punishTimer);
-				sendMessage("You are still " + getPunishLevel().string() + " for " + Math.round(_punishTimer / 60000f) + " minutes.");
-			}
-			if (getPunishLevel() == PunishLevel.JAIL)
-			{
-				// If player escaped, put him back in jail
-				if (!isInsideZone(ZoneId.JAIL))
-				{
-					teleToLocation(-114356, -249645, -2984, true);
-				}
-			}
-		}
-	}
-	
-	public void stopPunishTask(boolean save)
-	{
-		if (_punishTask != null)
-		{
-			if (save)
-			{
-				long delay = _punishTask.getDelay(TimeUnit.MILLISECONDS);
-				if (delay < 0)
-				{
-					delay = 0;
-				}
-				setPunishTimer(delay);
-			}
-			_punishTask.cancel(false);
-			_punishTask = null;
-		}
+		return PunishmentManager.getInstance().hasPunishment(getObjectId(), PunishmentAffect.CHARACTER, PunishmentType.CHAT_BAN) || PunishmentManager.getInstance().hasPunishment(getAccountName(), PunishmentAffect.ACCOUNT, PunishmentType.CHAT_BAN) || PunishmentManager.getInstance().hasPunishment(getIPAddress(), PunishmentAffect.IP, PunishmentType.CHAT_BAN);
 	}
 	
 	public void startFameTask(long delay, int fameFixRate)

+ 46 - 45
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/tasks/player/PunishTask.java → L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/tasks/player/TeleportTask.java

@@ -1,45 +1,46 @@
-/*
- * Copyright (C) 2004-2013 L2J Server
- * 
- * This file is part of L2J Server.
- * 
- * L2J Server 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.
- * 
- * L2J Server 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 com.l2jserver.gameserver.model.actor.tasks.player;
-
-import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
-import com.l2jserver.gameserver.model.actor.instance.L2PcInstance.PunishLevel;
-
-/**
- * Task dedicated to end player's punishment.
- * @author UnAfraid
- */
-public class PunishTask implements Runnable
-{
-	private final L2PcInstance _player;
-	
-	public PunishTask(L2PcInstance player)
-	{
-		_player = player;
-	}
-	
-	@Override
-	public void run()
-	{
-		if (_player != null)
-		{
-			_player.setPunishLevel(PunishLevel.NONE, 0);
-		}
-	}
-}
+/*
+ * Copyright (C) 2004-2013 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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.
+ * 
+ * L2J Server 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 com.l2jserver.gameserver.model.actor.tasks.player;
+
+import com.l2jserver.gameserver.model.Location;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * @author UnAfraid
+ */
+public class TeleportTask implements Runnable
+{
+	private final L2PcInstance _activeChar;
+	private final Location _loc;
+	
+	public TeleportTask(L2PcInstance player, Location loc)
+	{
+		_activeChar = player;
+		_loc = loc;
+	}
+	
+	@Override
+	public void run()
+	{
+		if ((_activeChar != null) && _activeChar.isOnline())
+		{
+			_activeChar.teleToLocation(_loc, true);
+		}
+	}
+}

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/model/entity/FortSiege.java

@@ -925,7 +925,7 @@ public class FortSiege implements Siegable
 		
 		for (L2PcInstance player : players)
 		{
-			if (player.canOverrideCond(PcCondOverride.FORTRESS_CONDITIONS) || player.isInJail())
+			if (player.canOverrideCond(PcCondOverride.FORTRESS_CONDITIONS) || player.isJailed())
 			{
 				continue;
 			}

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/model/entity/Siege.java

@@ -1072,7 +1072,7 @@ public class Siege implements Siegable
 		
 		for (L2PcInstance player : players)
 		{
-			if (player.canOverrideCond(PcCondOverride.CASTLE_CONDITIONS) || player.isInJail())
+			if (player.canOverrideCond(PcCondOverride.CASTLE_CONDITIONS) || player.isJailed())
 			{
 				continue;
 			}

+ 91 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/holders/PunishmentHolder.java

@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2004-2013 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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.
+ * 
+ * L2J Server 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 com.l2jserver.gameserver.model.holders;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.l2jserver.gameserver.model.punishment.PunishmentTask;
+import com.l2jserver.gameserver.model.punishment.PunishmentType;
+
+/**
+ * @author UnAfraid
+ */
+public class PunishmentHolder
+{
+	private final Map<Object, Map<PunishmentType, PunishmentTask>> _holder = new ConcurrentHashMap<>();
+	
+	/**
+	 * Stores the punishment task in the Map.
+	 * @param task
+	 */
+	public void addPunishment(PunishmentTask task)
+	{
+		if (!task.isExpired())
+		{
+			if (!_holder.containsKey(task.getKey()))
+			{
+				_holder.put(task.getKey(), new ConcurrentHashMap<PunishmentType, PunishmentTask>());
+			}
+			_holder.get(task.getKey()).put(task.getType(), task);
+		}
+	}
+	
+	/**
+	 * Removes previously stopped task from the Map.
+	 * @param task
+	 */
+	public void stopPunishment(PunishmentTask task)
+	{
+		if (_holder.containsKey(task.getKey()))
+		{
+			task.stopPunishment();
+			final Map<PunishmentType, PunishmentTask> punishments = _holder.get(task.getKey());
+			punishments.remove(task.getType());
+			if (punishments.isEmpty())
+			{
+				_holder.remove(task.getKey());
+			}
+		}
+	}
+	
+	/**
+	 * @param key
+	 * @param type
+	 * @return {@code true} if Map contains the current key and type, {@code false} otherwise.
+	 */
+	public boolean hasPunishment(Object key, PunishmentType type)
+	{
+		return getPunishment(key, type) != null;
+	}
+	
+	/**
+	 * @param key
+	 * @param type
+	 * @return {@link PunishmentTask} by specified key and type if exists, null otherwise.
+	 */
+	public PunishmentTask getPunishment(Object key, PunishmentType type)
+	{
+		if (_holder.containsKey(key))
+		{
+			return _holder.get(key).get(type);
+		}
+		return null;
+	}
+}

+ 42 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/punishment/PunishmentAffect.java

@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2004-2013 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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.
+ * 
+ * L2J Server 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 com.l2jserver.gameserver.model.punishment;
+
+/**
+ * @author UnAfraid
+ */
+public enum PunishmentAffect
+{
+	ACCOUNT,
+	CHARACTER,
+	IP;
+	// HWID; Not implemented yet.
+	
+	public static PunishmentAffect getByName(String name)
+	{
+		for (PunishmentAffect type : values())
+		{
+			if (type.name().equalsIgnoreCase(name))
+			{
+				return type;
+			}
+		}
+		return null;
+	}
+}

+ 227 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/punishment/PunishmentTask.java

@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2004-2013 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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.
+ * 
+ * L2J Server 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 com.l2jserver.gameserver.model.punishment;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.handler.IPunishmentHandler;
+import com.l2jserver.gameserver.handler.PunishmentHandler;
+import com.l2jserver.gameserver.instancemanager.PunishmentManager;
+
+/**
+ * @author UnAfraid
+ */
+public class PunishmentTask implements Runnable
+{
+	protected static final Logger _log = Logger.getLogger(PunishmentTask.class.getName());
+	
+	private static final String INSERT_QUERY = "INSERT INTO punishments (`key`, `affect`, `type`, `expiration`, `reason`, `punishedBy`) VALUES (?, ?, ?, ?, ?, ?)";
+	
+	private final Object _key;
+	private final PunishmentAffect _affect;
+	private final PunishmentType _type;
+	private final long _expirationTime;
+	private final String _reason;
+	private final String _punishedBy;
+	private boolean _isStored;
+	private ScheduledFuture<?> _task = null;
+	
+	public PunishmentTask(Object key, PunishmentAffect affect, PunishmentType type, long expirationTime, String reason, String punishedBy)
+	{
+		this(key, affect, type, expirationTime, reason, punishedBy, false);
+	}
+	
+	public PunishmentTask(Object key, PunishmentAffect affect, PunishmentType type, long expirationTime, String reason, String punishedBy, boolean isStored)
+	{
+		_key = key;
+		_affect = affect;
+		_type = type;
+		_expirationTime = expirationTime;
+		_reason = reason;
+		_punishedBy = punishedBy;
+		_isStored = isStored;
+		
+		startPunishment();
+	}
+	
+	/**
+	 * @return affection value charId, account, ip, etc..
+	 */
+	public Object getKey()
+	{
+		return _key;
+	}
+	
+	/**
+	 * @return {@link PunishmentAffect} affection type, account, character, ip, etc..
+	 */
+	public PunishmentAffect getAffect()
+	{
+		return _affect;
+	}
+	
+	/**
+	 * @return {@link PunishmentType} type of current punishment.
+	 */
+	public PunishmentType getType()
+	{
+		return _type;
+	}
+	
+	/**
+	 * @return milliseconds to the end of the current punishment, -1 for infinity.
+	 */
+	public final long getExpirationTime()
+	{
+		return _expirationTime;
+	}
+	
+	/**
+	 * @return the reason for this punishment.
+	 */
+	public String getReason()
+	{
+		return _reason;
+	}
+	
+	/**
+	 * @return name of the punishment issuer.
+	 */
+	public String getPunishedBy()
+	{
+		return _punishedBy;
+	}
+	
+	/**
+	 * @return {@code true} if current punishment task is stored in database, {@code false} otherwise.
+	 */
+	public boolean isStored()
+	{
+		return _isStored;
+	}
+	
+	/**
+	 * @return {@code true} if current punishment task has expired, {@code false} otherwise.
+	 */
+	public final boolean isExpired()
+	{
+		return (_expirationTime > 0) && (System.currentTimeMillis() > _expirationTime);
+	}
+	
+	/**
+	 * Activates the punishment task.
+	 */
+	private void startPunishment()
+	{
+		if (isExpired())
+		{
+			return;
+		}
+		
+		onStart();
+		if (_expirationTime > 0) // Has expiration?
+		{
+			_task = ThreadPoolManager.getInstance().scheduleGeneral(this, (_expirationTime - System.currentTimeMillis()));
+		}
+	}
+	
+	/**
+	 * Stops the punishment task.
+	 */
+	public final void stopPunishment()
+	{
+		abortTask();
+		onEnd();
+	}
+	
+	/**
+	 * Aborts the scheduled task.
+	 */
+	private void abortTask()
+	{
+		if (_task != null)
+		{
+			if (!_task.isCancelled() && !_task.isDone())
+			{
+				_task.cancel(false);
+			}
+			_task = null;
+		}
+	}
+	
+	/**
+	 * Store and activate punishment upon start.
+	 */
+	private void onStart()
+	{
+		if (!_isStored)
+		{
+			try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+				PreparedStatement st = con.prepareStatement(INSERT_QUERY))
+			{
+				st.setString(1, String.valueOf(_key));
+				st.setString(2, _affect.name());
+				st.setString(3, _type.name());
+				st.setLong(4, _expirationTime);
+				st.setString(5, _reason);
+				st.setString(6, _punishedBy);
+				st.execute();
+				_isStored = true;
+			}
+			catch (SQLException e)
+			{
+				_log.log(Level.WARNING, getClass().getSimpleName() + ": Couldn't store punishment task for: " + _affect + " " + _key, e);
+			}
+		}
+		
+		final IPunishmentHandler handler = PunishmentHandler.getInstance().getHandler(_type);
+		if (handler != null)
+		{
+			handler.onStart(this);
+		}
+	}
+	
+	/**
+	 * Remove and deactivate punishment when it ends.
+	 */
+	private void onEnd()
+	{
+		final IPunishmentHandler handler = PunishmentHandler.getInstance().getHandler(_type);
+		if (handler != null)
+		{
+			handler.onEnd(this);
+		}
+	}
+	
+	/**
+	 * Runs when punishment task ends in order to stop and remove it.
+	 */
+	@Override
+	public final void run()
+	{
+		PunishmentManager.getInstance().stopPunishment(_key, _affect, _type);
+	}
+}

+ 41 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/punishment/PunishmentType.java

@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2004-2013 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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.
+ * 
+ * L2J Server 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 com.l2jserver.gameserver.model.punishment;
+
+/**
+ * @author UnAfraid
+ */
+public enum PunishmentType
+{
+	BAN,
+	CHAT_BAN,
+	JAIL;
+	
+	public static PunishmentType getByName(String name)
+	{
+		for (PunishmentType type : values())
+		{
+			if (type.name().equalsIgnoreCase(name))
+			{
+				return type;
+			}
+		}
+		return null;
+	}
+}

+ 21 - 16
L2J_Server_BETA/java/com/l2jserver/gameserver/model/zone/type/L2JailZone.java

@@ -20,7 +20,10 @@ package com.l2jserver.gameserver.model.zone.type;
 
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.model.Location;
 import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.actor.tasks.player.TeleportTask;
 import com.l2jserver.gameserver.model.zone.L2ZoneType;
 import com.l2jserver.gameserver.model.zone.ZoneId;
 import com.l2jserver.gameserver.network.SystemMessageId;
@@ -31,6 +34,9 @@ import com.l2jserver.gameserver.network.SystemMessageId;
  */
 public class L2JailZone extends L2ZoneType
 {
+	private static final Location JAIL_IN_LOC = new Location(-114356, -249645, -2984);
+	private static final Location JAIL_OUT_LOC = new Location(17836, 170178, -3507);
+	
 	public L2JailZone(int id)
 	{
 		super(id);
@@ -42,6 +48,7 @@ public class L2JailZone extends L2ZoneType
 		if (character.isPlayer())
 		{
 			character.setInsideZone(ZoneId.JAIL, true);
+			character.setInsideZone(ZoneId.NO_SUMMON_FRIEND, true);
 			if (Config.JAIL_IS_PVP)
 			{
 				character.setInsideZone(ZoneId.PVP, true);
@@ -59,16 +66,20 @@ public class L2JailZone extends L2ZoneType
 	{
 		if (character.isPlayer())
 		{
-			character.setInsideZone(ZoneId.JAIL, false);
+			final L2PcInstance player = character.getActingPlayer();
+			player.setInsideZone(ZoneId.JAIL, false);
+			player.setInsideZone(ZoneId.NO_SUMMON_FRIEND, false);
+			
 			if (Config.JAIL_IS_PVP)
 			{
 				character.setInsideZone(ZoneId.PVP, false);
 				character.sendPacket(SystemMessageId.LEFT_COMBAT_ZONE);
 			}
-			if (character.getActingPlayer().isInJail())
+			
+			if (player.isJailed())
 			{
 				// when a player wants to exit jail even if he is still jailed, teleport him back to jail
-				ThreadPoolManager.getInstance().scheduleGeneral(new BackToJail(character), 2000);
+				ThreadPoolManager.getInstance().scheduleGeneral(new TeleportTask(player, JAIL_IN_LOC), 2000);
 				character.sendMessage("You cannot cheat your way out of here. You must wait until your jail time is over.");
 			}
 			if (Config.JAIL_DISABLE_TRANSACTION)
@@ -88,19 +99,13 @@ public class L2JailZone extends L2ZoneType
 	{
 	}
 	
-	private static class BackToJail implements Runnable
+	public static Location getLocationIn()
 	{
-		private final L2Character _activeChar;
-		
-		protected BackToJail(L2Character character)
-		{
-			_activeChar = character;
-		}
-		
-		@Override
-		public void run()
-		{
-			_activeChar.teleToLocation(-114356, -249645, -2984); // Jail
-		}
+		return JAIL_IN_LOC;
+	}
+	
+	public static Location getLocationOut()
+	{
+		return JAIL_OUT_LOC;
 	}
 }

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

@@ -799,7 +799,7 @@ public final class L2GameClient extends MMOClient<MMOConnection<L2GameClient>> i
 	protected boolean offlineMode(L2PcInstance player)
 	{
 		boolean canSetShop = false;
-		if (player.isInOlympiadMode() || player.isFestivalParticipant() || player.isBlockedFromExit() || player.isInJail() || (player.getVehicle() != null))
+		if (player.isInOlympiadMode() || player.isFestivalParticipant() || player.isBlockedFromExit() || player.isJailed() || (player.getVehicle() != null))
 		{
 			return false;
 		}

+ 12 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/CharacterSelect.java

@@ -28,8 +28,11 @@ import javolution.util.FastList;
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.datatables.CharNameTable;
 import com.l2jserver.gameserver.instancemanager.AntiFeedManager;
+import com.l2jserver.gameserver.instancemanager.PunishmentManager;
 import com.l2jserver.gameserver.model.CharSelectInfoPackage;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.punishment.PunishmentAffect;
+import com.l2jserver.gameserver.model.punishment.PunishmentType;
 import com.l2jserver.gameserver.network.L2GameClient;
 import com.l2jserver.gameserver.network.L2GameClient.GameClientState;
 import com.l2jserver.gameserver.network.serverpackets.CharSelected;
@@ -102,12 +105,20 @@ public class CharacterSelect extends L2GameClientPacket
 						return;
 					}
 					
-					// Selected character is banned.
+					// Banned?
+					if (PunishmentManager.getInstance().hasPunishment(info.getObjectId(), PunishmentAffect.CHARACTER, PunishmentType.BAN) || PunishmentManager.getInstance().hasPunishment(client.getAccountName(), PunishmentAffect.ACCOUNT, PunishmentType.BAN) || PunishmentManager.getInstance().hasPunishment(client.getConnectionAddress().getHostAddress(), PunishmentAffect.IP, PunishmentType.BAN))
+					{
+						client.close(ServerClose.STATIC_PACKET);
+						return;
+					}
+					
+					// Selected character is banned (compatibility with previous versions).
 					if (info.getAccessLevel() < 0)
 					{
 						client.close(ServerClose.STATIC_PACKET);
 						return;
 					}
+					
 					if ((Config.L2JMOD_DUALBOX_CHECK_MAX_PLAYERS_PER_IP > 0) && !AntiFeedManager.getInstance().tryAddClient(AntiFeedManager.GAME_ID, client, Config.L2JMOD_DUALBOX_CHECK_MAX_PLAYERS_PER_IP))
 					{
 						final NpcHtmlMessage msg = new NpcHtmlMessage(0);

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/RequestDropItem.java

@@ -107,7 +107,7 @@ public final class RequestDropItem extends L2GameClientPacket
 			return;
 		}
 		
-		if (Config.JAIL_DISABLE_TRANSACTION && activeChar.isInJail())
+		if (Config.JAIL_DISABLE_TRANSACTION && activeChar.isJailed())
 		{
 			activeChar.sendMessage("You cannot drop items in Jail.");
 			return;

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/RequestJoinParty.java

@@ -104,7 +104,7 @@ public final class RequestJoinParty extends L2GameClientPacket
 			return;
 		}
 		
-		if (target.isInJail() || requestor.isInJail())
+		if (target.isJailed() || requestor.isJailed())
 		{
 			requestor.sendMessage("You cannot invite a player while is in Jail.");
 			return;

+ 2 - 2
L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/RequestRestartPoint.java

@@ -121,7 +121,7 @@ public final class RequestRestartPoint extends L2GameClientPacket
 		int instanceId = 0;
 		
 		// force jail
-		if (activeChar.isInJail())
+		if (activeChar.isJailed())
 		{
 			_requestedPointType = 27;
 		}
@@ -254,7 +254,7 @@ public final class RequestRestartPoint extends L2GameClientPacket
 			}
 			case 27: // to jail
 			{
-				if (!activeChar.isInJail())
+				if (!activeChar.isJailed())
 				{
 					return;
 				}

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/RequestSendPost.java

@@ -222,7 +222,7 @@ public final class RequestSendPost extends L2GameClientPacket
 			return;
 		}
 		
-		if (activeChar.isInJail() && ((Config.JAIL_DISABLE_TRANSACTION && (_items != null)) || Config.JAIL_DISABLE_CHAT))
+		if (activeChar.isJailed() && ((Config.JAIL_DISABLE_TRANSACTION && (_items != null)) || Config.JAIL_DISABLE_CHAT))
 		{
 			activeChar.sendPacket(SystemMessageId.CANT_FORWARD_NOT_IN_PEACE_ZONE);
 			return;

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/Say2.java

@@ -215,7 +215,7 @@ public final class Say2 extends L2GameClientPacket
 			}
 		}
 		
-		if (activeChar.isInJail() && Config.JAIL_DISABLE_CHAT)
+		if (activeChar.isJailed() && Config.JAIL_DISABLE_CHAT)
 		{
 			if ((_type == TELL) || (_type == SHOUT) || (_type == TRADE) || (_type == HERO_VOICE))
 			{

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/TradeRequest.java

@@ -101,7 +101,7 @@ public final class TradeRequest extends L2GameClientPacket
 			return;
 		}
 		
-		if (Config.JAIL_DISABLE_TRANSACTION && (player.isInJail() || partner.isInJail()))
+		if (Config.JAIL_DISABLE_TRANSACTION && (player.isJailed() || partner.isJailed()))
 		{
 			player.sendMessage("You cannot trade while you are in in Jail.");
 			return;

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/network/serverpackets/Die.java

@@ -51,7 +51,7 @@ public class Die extends L2GameServerPacket
 			final L2PcInstance player = cha.getActingPlayer();
 			_access = player.getAccessLevel();
 			_clan = player.getClan();
-			_isJailed = player.isInJail();
+			_isJailed = player.isJailed();
 		}
 		
 		_canTeleport = cha.canRevive() && !cha.isPendingRevive();

+ 12 - 19
L2J_Server_BETA/java/com/l2jserver/gameserver/util/FloodProtectorAction.java

@@ -23,8 +23,11 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.l2jserver.gameserver.GameTimeController;
+import com.l2jserver.gameserver.instancemanager.PunishmentManager;
 import com.l2jserver.gameserver.model.PcCondOverride;
-import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.punishment.PunishmentAffect;
+import com.l2jserver.gameserver.model.punishment.PunishmentTask;
+import com.l2jserver.gameserver.model.punishment.PunishmentType;
 import com.l2jserver.gameserver.network.L2GameClient;
 import com.l2jserver.util.StringUtil;
 
@@ -160,20 +163,10 @@ public final class FloodProtectorAction
 	 */
 	private void banAccount()
 	{
-		if (_client.getActiveChar() != null)
-		{
-			_client.getActiveChar().setPunishLevel(L2PcInstance.PunishLevel.ACC, _config.PUNISHMENT_TIME);
-			
-			if (_log.isLoggable(Level.WARNING))
-			{
-				log(" banned for flooding ", _config.PUNISHMENT_TIME <= 0 ? "forever" : "for " + _config.PUNISHMENT_TIME + " mins");
-			}
-			
-			_client.getActiveChar().logout();
-		}
-		else
+		PunishmentManager.getInstance().startPunishment(new PunishmentTask(_client.getAccountName(), PunishmentAffect.ACCOUNT, PunishmentType.BAN, System.currentTimeMillis() + _config.PUNISHMENT_TIME, "", getClass().getSimpleName()));
+		if (_log.isLoggable(Level.WARNING))
 		{
-			log(" unable to ban account: no active player");
+			log(" banned for flooding ", _config.PUNISHMENT_TIME <= 0 ? "forever" : "for " + _config.PUNISHMENT_TIME + " mins");
 		}
 	}
 	
@@ -184,17 +177,17 @@ public final class FloodProtectorAction
 	{
 		if (_client.getActiveChar() != null)
 		{
-			_client.getActiveChar().setPunishLevel(L2PcInstance.PunishLevel.JAIL, _config.PUNISHMENT_TIME);
+			int charId = _client.getActiveChar().getObjectId();
+			if (charId > 0)
+			{
+				PunishmentManager.getInstance().startPunishment(new PunishmentTask(charId, PunishmentAffect.CHARACTER, PunishmentType.JAIL, System.currentTimeMillis() + _config.PUNISHMENT_TIME, "", getClass().getSimpleName()));
+			}
 			
 			if (_log.isLoggable(Level.WARNING))
 			{
 				log(" jailed for flooding ", _config.PUNISHMENT_TIME <= 0 ? "forever" : "for " + _config.PUNISHMENT_TIME + " mins");
 			}
 		}
-		else
-		{
-			log(" unable to jail: no active player");
-		}
 	}
 	
 	private void log(String... lines)

+ 6 - 2
L2J_Server_BETA/java/com/l2jserver/gameserver/util/IllegalPlayerAction.java

@@ -24,7 +24,11 @@ import java.util.logging.Logger;
 
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.datatables.AdminTable;
+import com.l2jserver.gameserver.instancemanager.PunishmentManager;
 import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.punishment.PunishmentAffect;
+import com.l2jserver.gameserver.model.punishment.PunishmentTask;
+import com.l2jserver.gameserver.model.punishment.PunishmentType;
 
 /**
  * This class ...
@@ -92,10 +96,10 @@ public final class IllegalPlayerAction implements Runnable
 					_actor.logout(false);
 					break;
 				case PUNISH_KICKBAN:
-					_actor.logout();
+					PunishmentManager.getInstance().startPunishment(new PunishmentTask(_actor.getObjectId(), PunishmentAffect.CHARACTER, PunishmentType.BAN, System.currentTimeMillis() + (Config.DEFAULT_PUNISH_PARAM * 1000), _message, getClass().getSimpleName()));
 					break;
 				case PUNISH_JAIL:
-					_actor.setPunishLevel(L2PcInstance.PunishLevel.JAIL, Config.DEFAULT_PUNISH_PARAM);
+					PunishmentManager.getInstance().startPunishment(new PunishmentTask(_actor.getObjectId(), PunishmentAffect.CHARACTER, PunishmentType.JAIL, System.currentTimeMillis() + (Config.DEFAULT_PUNISH_PARAM * 1000), _message, getClass().getSimpleName()));
 					break;
 			}
 		}

+ 21 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/util/Util.java

@@ -332,6 +332,27 @@ public final class Util
 		return result;
 	}
 	
+	/**
+	 * Based on implode() in PHP
+	 * @param <T>
+	 * @param array
+	 * @param delim
+	 * @return a delimited string for a given array of string elements.
+	 */
+	public static <T> String implode(T[] array, String delim)
+	{
+		String result = "";
+		for (T val : array)
+		{
+			result += val.toString() + delim;
+		}
+		if (!result.isEmpty())
+		{
+			result = result.substring(0, result.length() - 1);
+		}
+		return result;
+	}
+	
 	/**
 	 * (Based on round() in PHP)
 	 * @param number - the number to round