Browse Source

Add missing feature reuseDelay in NpcData from xml

Add some Intentions in L2PlayerAI
Fixed: login world inside seven signs, teleport to town, possible fix
client crash. (with character "isIn7sDungeon = 1")
Fixed: bow/cross bow delay next action, if you attack or use skill,
character wait finish and start the next action like
attack/follow/pickup/interact. Example (use nobless and try one next
action)
Fixed: character stop a bit if start new atack "/attack" with bow/cross
bow on around end of red BAR delay.
Fixed: attack delay and use fast next action, (bug fixed: stop the
actual action).
Fixed: attack with bow/cross finish and walk.
Fixed: npc attack animation.
Fixed: npc fast Bow/Cross attack delay
Fixed: range npc attack all AI classes
Maneco2 3 years ago
parent
commit
1da02a3c2a

+ 23 - 7
src/main/java/com/l2jserver/gameserver/ai/L2AttackableAI.java

@@ -36,6 +36,7 @@ import org.slf4j.LoggerFactory;
 import com.l2jserver.commons.util.Rnd;
 import com.l2jserver.gameserver.GameTimeController;
 import com.l2jserver.gameserver.GeoData;
+import com.l2jserver.gameserver.SevenSigns;
 import com.l2jserver.gameserver.ThreadPoolManager;
 import com.l2jserver.gameserver.data.sql.impl.TerritoryTable;
 import com.l2jserver.gameserver.enums.AISkillScope;
@@ -43,6 +44,7 @@ import com.l2jserver.gameserver.enums.AIType;
 import com.l2jserver.gameserver.instancemanager.DimensionalRiftManager;
 import com.l2jserver.gameserver.model.L2Object;
 import com.l2jserver.gameserver.model.Location;
+import com.l2jserver.gameserver.model.TeleportWhereType;
 import com.l2jserver.gameserver.model.actor.L2Attackable;
 import com.l2jserver.gameserver.model.actor.L2Character;
 import com.l2jserver.gameserver.model.actor.L2Npc;
@@ -372,6 +374,23 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable {
 			_lastBuffTick = GameTimeController.getInstance().getGameTicks();
 		}
 		
+		if (getActiveChar().isSevenNpc()) {
+			final L2PcInstance player = target.getActingPlayer();
+			if (SevenSigns.getInstance().isSealValidationPeriod() || SevenSigns.getInstance().isCompResultsPeriod()) {
+				if (!player.isGM() && player.isIn7sDungeon() && (SevenSigns.getInstance().getPlayerCabal(player.getObjectId()) != SevenSigns.getInstance().getCabalHighestScore())) {
+					player.teleToLocation(TeleportWhereType.TOWN);
+					player.setIsIn7sDungeon(false);
+					player.sendMessage("You have been teleported to the nearest town due to the beginning of the Seal Validation period.");
+				}
+			} else {
+				if (!player.isGM() && player.isIn7sDungeon() && (SevenSigns.getInstance().getPlayerCabal(player.getObjectId()) == SevenSigns.CABAL_NULL)) {
+					player.teleToLocation(TeleportWhereType.TOWN);
+					player.setIsIn7sDungeon(false);
+					player.sendMessage("You have been teleported to the nearest town because you have not signed for any cabal.");
+				}
+			}
+		}
+		
 		// Manage the Attack Intention : Stop current Attack (if necessary), Start a new Attack and Launch Think Event
 		super.onIntentionAttack(target);
 	}
@@ -644,7 +663,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable {
 	 */
 	protected void thinkAttack() {
 		final L2Attackable npc = getActiveChar();
-		if (npc.isCastingNow()) {
+		if (npc.isCastingNow() || npc.isAttackingNow()) {
 			return;
 		}
 		
@@ -778,7 +797,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable {
 			}
 		}
 		// Calculate Archer movement
-		if (!npc.isMovementDisabled() && (npc.getAiType() == AIType.ARCHER)) {
+		if (!npc.isMovementDisabled() && (npc.getTemplate().getBaseAttackRange() >= 700)) {
 			if (Rnd.get(100) <= 15) {
 				double distance2 = npc.calculateDistance(mostHate, false, true);
 				if (Math.sqrt(distance2) <= (60 + combinedCollision)) {
@@ -1055,8 +1074,8 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable {
 		double dist = npc.calculateDistance(mostHate, false, false);
 		int dist2 = (int) dist - collision;
 		int range = npc.getPhysicalAttackRange() + combinedCollision;
-		if (npc.getAiType() == AIType.ARCHER) {
-			range = 850 + combinedCollision; // Base Bow Range NPC
+		if (npc.getTemplate().getBaseAttackRange() >= 700) {
+			range = npc.getTemplate().getBaseAttackRange(); // Base Bow Range NPC
 		}
 		if (mostHate.isMoving()) {
 			range = range + 50;
@@ -1072,9 +1091,6 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable {
 			} else {
 				final L2Character target = getAttackTarget();
 				if (target != null) {
-					if (target.isMoving()) {
-						range -= 100;
-					}
 					moveToPawn(target, Math.max(range, 5));
 				}
 			}

+ 8 - 7
src/main/java/com/l2jserver/gameserver/ai/L2CharacterAI.java

@@ -29,12 +29,13 @@ import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
 import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
 import static com.l2jserver.gameserver.config.Configuration.geodata;
 import static com.l2jserver.gameserver.model.skills.targets.AffectScope.PARTY;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import com.l2jserver.commons.util.Rnd;
-import com.l2jserver.gameserver.GameTimeController;
 import com.l2jserver.gameserver.GeoData;
 import com.l2jserver.gameserver.ThreadPoolManager;
 import com.l2jserver.gameserver.enums.ItemLocation;
@@ -289,8 +290,8 @@ public class L2CharacterAI extends AbstractAI {
 			return;
 		}
 		
-		if (_actor.getBowAttackEndTime() > GameTimeController.getInstance().getGameTicks()) {
-			ThreadPoolManager.getInstance().scheduleGeneral(new CastTask(_actor, skill, target), (_actor.getBowAttackEndTime() - GameTimeController.getInstance().getGameTicks()) * GameTimeController.MILLIS_IN_TICK);
+		if (_actor.isAttackingNow()) {
+			ThreadPoolManager.getInstance().scheduleGeneral(new CastTask(_actor, skill, target), MILLISECONDS.convert(_actor.getAttackEndTime() - System.nanoTime(), NANOSECONDS));
 		} else {
 			changeIntentionToCast(skill, target);
 		}
@@ -325,7 +326,7 @@ public class L2CharacterAI extends AbstractAI {
 			return;
 		}
 		
-		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow()) {
+		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow()) {
 			// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
 			clientActionFailed();
 			return;
@@ -361,7 +362,7 @@ public class L2CharacterAI extends AbstractAI {
 			return;
 		}
 		
-		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow()) {
+		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow()) {
 			// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
 			clientActionFailed();
 			return;
@@ -412,7 +413,7 @@ public class L2CharacterAI extends AbstractAI {
 			return;
 		}
 		
-		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow()) {
+		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow()) {
 			// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
 			clientActionFailed();
 			return;
@@ -458,7 +459,7 @@ public class L2CharacterAI extends AbstractAI {
 			return;
 		}
 		
-		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow()) {
+		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow()) {
 			// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
 			clientActionFailed();
 			return;

+ 152 - 3
src/main/java/com/l2jserver/gameserver/ai/L2PlayerAI.java

@@ -20,6 +20,7 @@ package com.l2jserver.gameserver.ai;
 
 import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
 import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
 import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
 import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
 import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_MOVE_TO;
@@ -27,11 +28,13 @@ import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
 import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
 
 import com.l2jserver.gameserver.enums.DuelState;
+import com.l2jserver.gameserver.enums.ItemLocation;
 import com.l2jserver.gameserver.model.L2Object;
 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.instance.L2StaticObjectInstance;
+import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
 import com.l2jserver.gameserver.model.skills.Skill;
 import com.l2jserver.gameserver.model.skills.targets.TargetType;
 import com.l2jserver.gameserver.network.SystemMessageId;
@@ -154,6 +157,51 @@ public class L2PlayerAI extends L2PlayableAI {
 		setIntention(AI_INTENTION_IDLE);
 	}
 	
+	@Override
+	protected void onIntentionAttack(L2Character target) {
+		if (target == null) {
+			clientActionFailed();
+			return;
+		}
+		if (getIntention() == AI_INTENTION_REST) {
+			// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+			clientActionFailed();
+			return;
+		}
+		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAfraid()) {
+			clientActionFailed();
+			saveNextIntention(AI_INTENTION_ATTACK, target, null);
+			return;
+		}
+		
+		// Check if the Intention is already AI_INTENTION_ATTACK
+		if (getIntention() == AI_INTENTION_ATTACK) {
+			// Check if the AI already targets the L2Character
+			if (getAttackTarget() != target) {
+				// Set the AI attack target (change target)
+				setAttackTarget(target);
+				
+				stopFollow();
+				
+				// Launch the Think Event
+				notifyEvent(CtrlEvent.EVT_THINK);
+			} else {
+				clientActionFailed(); // else client freezes until cancel target
+			}
+		} else {
+			// Set the Intention of this AbstractAI to AI_INTENTION_ATTACK
+			changeIntention(AI_INTENTION_ATTACK, target, null);
+			
+			// Set the AI attack target
+			setAttackTarget(target);
+			
+			stopFollow();
+			
+			// Launch the Think Event
+			notifyEvent(CtrlEvent.EVT_THINK);
+		}
+	}
+	
 	/**
 	 * Manage the Move To Intention : Stop current Attack and Launch a Move to Location Task.<br>
 	 * <B><U> Actions</U> : </B>
@@ -181,12 +229,12 @@ public class L2PlayerAI extends L2PlayableAI {
 			return;
 		}
 		
-		// Set the Intention of this AbstractAI to AI_INTENTION_MOVE_TO
-		changeIntention(AI_INTENTION_MOVE_TO, loc, null);
-		
 		// Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
 		clientStopAutoAttack();
 		
+		// Set the Intention of this AbstractAI to AI_INTENTION_MOVE_TO
+		changeIntention(AI_INTENTION_MOVE_TO, loc, null);
+		
 		// Abort the attack of the L2Character and send Server->Client ActionFailed packet
 		_actor.abortAttack();
 		
@@ -194,6 +242,107 @@ public class L2PlayerAI extends L2PlayableAI {
 		moveTo(loc.getX(), loc.getY(), loc.getZ());
 	}
 	
+	@Override
+	protected void onIntentionFollow(L2Character target) {
+		if (getIntention() == AI_INTENTION_REST) {
+			// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+			clientActionFailed();
+			return;
+		}
+		
+		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow()) {
+			// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+			clientActionFailed();
+			saveNextIntention(AI_INTENTION_FOLLOW, target, null);
+			return;
+		}
+		
+		// Dead actors can`t follow
+		if (_actor.isDead()) {
+			clientActionFailed();
+			return;
+		}
+		
+		// do not follow yourself
+		if (_actor == target) {
+			clientActionFailed();
+			return;
+		}
+		
+		// Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+		clientStopAutoAttack();
+		
+		// Set the Intention of this AbstractAI to AI_INTENTION_FOLLOW
+		changeIntention(AI_INTENTION_FOLLOW, target, null);
+		
+		// Create and Launch an AI Follow Task to execute every 1s
+		startFollow(target);
+	}
+	
+	@Override
+	protected void onIntentionPickUp(L2Object object) {
+		if (getIntention() == AI_INTENTION_REST) {
+			// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+			clientActionFailed();
+			return;
+		}
+		
+		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow()) {
+			// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+			clientActionFailed();
+			saveNextIntention(AI_INTENTION_PICK_UP, object, null);
+			return;
+		}
+		
+		// Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+		clientStopAutoAttack();
+		
+		if ((object instanceof L2ItemInstance) && (((L2ItemInstance) object).getItemLocation() != ItemLocation.VOID)) {
+			return;
+		}
+		
+		// Set the Intention of this AbstractAI to AI_INTENTION_PICK_UP
+		changeIntention(AI_INTENTION_PICK_UP, object, null);
+		
+		// Set the AI pick up target
+		setTarget(object);
+		if ((object.getX() == 0) && (object.getY() == 0)) // TODO: Find the drop&spawn bug
+		{
+			LOG.warn("Object in coords 0,0 - using a temporary fix");
+			object.setXYZ(getActor().getX(), getActor().getY(), getActor().getZ() + 5);
+		}
+		
+		// Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
+		moveToPawn(object, 20);
+	}
+	
+	@Override
+	protected void onIntentionInteract(L2Object object) {
+		if (getIntention() == AI_INTENTION_REST) {
+			// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+			clientActionFailed();
+			return;
+		}
+		
+		if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow()) {
+			clientActionFailed();
+			saveNextIntention(AI_INTENTION_INTERACT, object, null);
+			return;
+		}
+		
+		// Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+		clientStopAutoAttack();
+		
+		// Set the Intention of this AbstractAI to AI_INTENTION_INTERACT
+		changeIntention(AI_INTENTION_INTERACT, object, null);
+		
+		// Set the AI interact target
+		setTarget(object);
+		
+		// Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
+		moveToPawn(object, 60);
+	}
+	
 	@Override
 	protected void clientNotifyDead() {
 		_clientMovingToPawnOffset = 0;

+ 1 - 1
src/main/java/com/l2jserver/gameserver/data/xml/impl/NpcData.java

@@ -176,7 +176,7 @@ public class NpcData implements IXmlReader {
 												set.set("baseCritRate", parseInteger(attrs, "critical"));
 												set.set("accuracy", parseDouble(attrs, "accuracy"));// TODO: Implement me
 												set.set("basePAtkSpd", parseInteger(attrs, "attackSpeed"));
-												set.set("reuseDelay", parseInteger(attrs, "reuseDelay"));// TODO: Implement me
+												set.set("reuseDelay", parseInteger(attrs, "reuseDelay"));
 												set.set("baseAtkType", parseString(attrs, "type"));
 												set.set("baseAtkRange", parseInteger(attrs, "range"));
 												set.set("distance", parseInteger(attrs, "distance"));// TODO: Implement me

+ 47 - 42
src/main/java/com/l2jserver/gameserver/model/actor/L2Character.java

@@ -268,7 +268,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 	private L2Object _target;
 	/** Represents the time where the attack should end, in nanoseconds. */
 	private volatile long _attackEndTime;
-	private int _disableBowAttackEndTime;
+	private long _disableBowAttackEndTime;
 	
 	private int _castInterruptTime;
 	
@@ -723,11 +723,13 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 		}
 		L2Weapon weaponItem = getActiveWeaponItem();
 		
-		if ((weaponItem == null) || !weaponItem.isRange()) {
-			return false;
-		}
+		final long betweenRangedAttack = _disableBowAttackEndTime - System.currentTimeMillis();
 		// Check for arrows and MP
 		if (isPlayer()) {
+			if ((weaponItem == null) || !weaponItem.isRange()) {
+				return false;
+			}
+			
 			// Equip arrows needed in left hand and send a Server->Client packet ItemList to the L2PcInstance then return True
 			if (!checkAndEquipArrows()) {
 				// Cancel the action because the L2PcInstance have no arrow
@@ -738,37 +740,38 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 			}
 			
 			// Verify if the bow can be use
-			if (_disableBowAttackEndTime <= GameTimeController.getInstance().getGameTicks()) {
-				// Verify if L2PcInstance owns enough MP
-				int mpConsume = weaponItem.getMpConsume();
-				if ((weaponItem.getReducedMpConsume() > 0) && (Rnd.get(100) < weaponItem.getReducedMpConsumeChance())) {
-					mpConsume = weaponItem.getReducedMpConsume();
-				}
-				mpConsume = (int) calcStat(Stats.BOW_MP_CONSUME_RATE, mpConsume, null, null);
-				
-				if (getCurrentMp() < mpConsume) {
-					// If L2PcInstance doesn't have enough MP, stop the attack
-					ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), 1000);
-					sendPacket(SystemMessageId.NOT_ENOUGH_MP);
-					sendPacket(ActionFailed.STATIC_PACKET);
-					return false;
-				}
-				
-				// If L2PcInstance have enough MP, the bow consumes it
-				if (mpConsume > 0) {
-					getStatus().reduceMp(mpConsume);
-				}
-				
-				// Set the period of bow no re-use
-				_disableBowAttackEndTime = (5 * GameTimeController.TICKS_PER_SECOND) + GameTimeController.getInstance().getGameTicks();
-			} else {
+			if (betweenRangedAttack > 0) {
 				// Cancel the action because the bow can't be re-use at this moment
-				ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), 1000);
+				ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), betweenRangedAttack);
 				sendPacket(ActionFailed.STATIC_PACKET);
 				return false;
 			}
+			// Verify if L2PcInstance owns enough MP
+			int mpConsume = weaponItem.getMpConsume();
+			if ((weaponItem.getReducedMpConsume() > 0) && (Rnd.get(100) < weaponItem.getReducedMpConsumeChance())) {
+				mpConsume = weaponItem.getReducedMpConsume();
+			}
+			mpConsume = (int) calcStat(Stats.BOW_MP_CONSUME_RATE, mpConsume, null, null);
+			
+			if (getCurrentMp() < mpConsume) {
+				// If L2PcInstance doesn't have enough MP, stop the attack
+				ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), 100);
+				sendPacket(SystemMessageId.NOT_ENOUGH_MP);
+				sendPacket(ActionFailed.STATIC_PACKET);
+				return false;
+			}
+			
+			// If L2PcInstance have enough MP, the bow consumes it
+			if (mpConsume > 0) {
+				getStatus().reduceMp(mpConsume);
+			}
 		} else if (isNpc()) {
-			return _disableBowAttackEndTime <= GameTimeController.getInstance().getGameTicks();
+			// Verify reuse attack
+			if (betweenRangedAttack > 0) {
+				ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), betweenRangedAttack);
+				sendPacket(ActionFailed.STATIC_PACKET);
+				return false;
+			}
 		}
 		return true;
 	}
@@ -896,21 +899,28 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 			setHeading(Util.calculateHeadingFrom(this, target));
 			int reuse = calculateReuseTime(weaponItem);
 			
+			if (isNpc()) {
+				if (weaponItem == null) {
+					reuse = timeAtk;
+				}
+				reuse = reuse + getTemplate().getBaseReuseDelay();
+			}
+			
 			boolean hitted;
 			switch (getAttackType()) {
 				case BOW: {
-					if (isPlayer() && !canUseRangeWeapon()) {
+					if (!canUseRangeWeapon()) {
 						return;
 					}
-					_attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeToHit + (reuse / 2), TimeUnit.MILLISECONDS);
+					_attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS);
 					hitted = doAttackHitByBow(attack, target, timeAtk, reuse);
 					break;
 				}
 				case CROSSBOW: {
-					if (isPlayer() && !canUseRangeWeapon()) {
+					if (!canUseRangeWeapon()) {
 						return;
 					}
-					_attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeToHit + (reuse / 2), TimeUnit.MILLISECONDS);
+					_attackEndTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeAtk, TimeUnit.MILLISECONDS);
 					hitted = doAttackHitByCrossBow(attack, target, timeAtk, reuse);
 					break;
 				}
@@ -977,8 +987,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 				broadcastPacket(attack);
 			}
 			
-			// Notify AI with EVT_READY_TO_ACT
-			ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk + reuse);
+			ThreadPoolManager.getInstance().scheduleAi(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk);
 		} finally {
 			_attackLock.unlockWrite(stamp);
 		}
@@ -1042,7 +1051,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 		ThreadPoolManager.getInstance().scheduleAi(new HitTask(this, target, damage1, crit1, miss1, attack.hasSoulshot(), shld1), sAtk);
 		
 		// Calculate and set the disable delay of the bow in function of the Attack Speed
-		_disableBowAttackEndTime = ((sAtk + reuse) / GameTimeController.MILLIS_IN_TICK) + GameTimeController.getInstance().getGameTicks();
+		_disableBowAttackEndTime = (sAtk + reuse) + System.currentTimeMillis();
 		
 		// Add this hit to the Server-Client packet Attack
 		attack.addHit(target, damage1, miss1, crit1, shld1);
@@ -1109,7 +1118,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 		ThreadPoolManager.getInstance().scheduleAi(new HitTask(this, target, damage1, crit1, miss1, attack.hasSoulshot(), shld1), sAtk);
 		
 		// Calculate and set the disable delay of the bow in function of the Attack Speed
-		_disableBowAttackEndTime = ((sAtk + reuse) / GameTimeController.MILLIS_IN_TICK) + GameTimeController.getInstance().getGameTicks();
+		_disableBowAttackEndTime = (sAtk + reuse) + System.currentTimeMillis();
 		
 		// Add this hit to the Server-Client packet Attack
 		attack.addHit(target, damage1, miss1, crit1, shld1);
@@ -5044,10 +5053,6 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 		return _attackEndTime;
 	}
 	
-	public int getBowAttackEndTime() {
-		return _disableBowAttackEndTime;
-	}
-	
 	/**
 	 * Not Implemented.
 	 * @return

+ 0 - 14
src/main/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java

@@ -7906,20 +7906,6 @@ public final class L2PcInstance extends L2Playable {
 		
 		getHuntingSystem().onPlayerLogin();
 		
-		if (SevenSigns.getInstance().isSealValidationPeriod() || SevenSigns.getInstance().isCompResultsPeriod()) {
-			if (!isGM() && isIn7sDungeon() && (SevenSigns.getInstance().getPlayerCabal(getObjectId()) != SevenSigns.getInstance().getCabalHighestScore())) {
-				teleToLocation(TeleportWhereType.TOWN);
-				setIsIn7sDungeon(false);
-				sendMessage("You have been teleported to the nearest town due to the beginning of the Seal Validation period.");
-			}
-		} else {
-			if (!isGM() && isIn7sDungeon() && (SevenSigns.getInstance().getPlayerCabal(getObjectId()) == SevenSigns.CABAL_NULL)) {
-				teleToLocation(TeleportWhereType.TOWN);
-				setIsIn7sDungeon(false);
-				sendMessage("You have been teleported to the nearest town because you have not signed for any cabal.");
-			}
-		}
-		
 		if (isGM()) {
 			if (isInvul()) {
 				sendMessage("Entering world in Invulnerable mode.");

+ 9 - 0
src/main/java/com/l2jserver/gameserver/model/actor/templates/L2CharTemplate.java

@@ -59,6 +59,7 @@ public class L2CharTemplate extends ListenersContainer {
 	private int _baseShldRate;
 	private int _baseCritRate;
 	private int _baseMCritRate;
+	private int _baseReuseDelay;
 	// SpecialStats
 	private int _baseBreath;
 	private int _baseFire;
@@ -116,6 +117,7 @@ public class L2CharTemplate extends ListenersContainer {
 		_baseShldRate = set.getInt("baseShldRate", 0);
 		_baseCritRate = set.getInt("baseCritRate", 4);
 		_baseMCritRate = set.getInt("baseMCritRate", 0);
+		_baseReuseDelay = set.getInt("reuseDelay", 0);
 		
 		// SpecialStats
 		_baseBreath = set.getInt("baseBreath", 100);
@@ -394,6 +396,13 @@ public class L2CharTemplate extends ListenersContainer {
 		return _baseMCritRate;
 	}
 	
+	/**
+	 * @return the baseReuseDelay
+	 */
+	public int getBaseReuseDelay() {
+		return _baseReuseDelay;
+	}
+	
 	public void setBaseMoveSpeed(MoveType type, double val) {
 		_moveType[type.ordinal()] = val;
 	}