Kaynağa Gözat

BETA: Implementing "Next Action" by CSharpRU as Yaroslav:
* Queued sit action while running by CSharpRU.
* Queued equip/unequip item action while casting a spell by me.
* Player should stop moving after casting self-buff committed in [5055].
'''Note:''' More "next actions" implementations are missing which require retail confirmation.

Zoey76 13 yıl önce
ebeveyn
işleme
13df7558e4

+ 35 - 7
L2J_Server_BETA/java/com/l2jserver/gameserver/ai/AbstractAI.java

@@ -40,18 +40,34 @@ import com.l2jserver.gameserver.network.serverpackets.StopMove;
 import com.l2jserver.gameserver.network.serverpackets.StopRotation;
 import com.l2jserver.gameserver.taskmanager.AttackStanceTaskManager;
 
-
 /**
- * Mother class of all objects AI in the world.<BR><BR>
- *
- * AbastractAI :<BR><BR>
- * <li>L2CharacterAI</li><BR><BR>
+ * Mother class of all objects AI in the world.<br>
+ * AbastractAI :<br>
+ * <li>L2CharacterAI</li>
  */
-abstract class AbstractAI implements Ctrl
+public abstract class AbstractAI implements Ctrl
 {
 	protected static final Logger _log = Logger.getLogger(AbstractAI.class.getName());
 	
-	class FollowTask implements Runnable
+	private NextAction _nextAction;
+	
+	/**
+	 * @return the _nextAction
+	 */
+	public NextAction getNextAction()
+	{
+		return _nextAction;
+	}
+	
+	/**
+	 * @param nextAction the next action to set.
+	 */
+	public void setNextAction(NextAction nextAction)
+	{
+		_nextAction = nextAction;
+	}
+	
+	private class FollowTask implements Runnable
 	{
 		protected int _range = 70;
 		
@@ -329,6 +345,12 @@ abstract class AbstractAI implements Ctrl
 				onIntentionInteract((L2Object) arg0);
 				break;
 		}
+		
+		// If do move or follow intention drop next action.
+		if ((_nextAction != null) && _nextAction.getIntentions().contains(intention))
+		{
+			_nextAction = null;
+		}
 	}
 	
 	/**
@@ -484,6 +506,12 @@ abstract class AbstractAI implements Ctrl
 				onEvtFinishCasting();
 				break;
 		}
+		
+		// Do next action.
+		if ((_nextAction != null) && _nextAction.getEvents().contains(evt))
+		{
+			_nextAction.doAction();
+		}
 	}
 	
 	protected abstract void onIntentionIdle();

+ 202 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/ai/NextAction.java

@@ -0,0 +1,202 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.gameserver.ai;
+
+import java.util.ArrayList;
+
+/**
+ * Class for AI action after some event.<br>
+ * Has 2 array list for "work" and "break".
+ * @author Yaroslav
+ */
+public class NextAction
+{
+	public interface NextActionCallback
+	{
+		public void doWork();
+	}
+	
+	private ArrayList<CtrlEvent> _events;
+	private ArrayList<CtrlIntention> _intentions;
+	private NextActionCallback _callback;
+	
+	/**
+	 * Main constructor.
+	 * @param events
+	 * @param intentions
+	 * @param callback
+	 */
+	public NextAction(ArrayList<CtrlEvent> events, ArrayList<CtrlIntention> intentions, NextActionCallback callback)
+	{
+		_events = events;
+		_intentions = intentions;
+		setCallback(callback);
+	}
+	
+	/**
+	 * Single constructor.
+	 * @param event
+	 * @param intention
+	 * @param callback
+	 */
+	public NextAction(CtrlEvent event, CtrlIntention intention, NextActionCallback callback)
+	{
+		if (_events == null)
+		{
+			_events = new ArrayList<>();
+		}
+		
+		if (_intentions == null)
+		{
+			_intentions = new ArrayList<>();
+		}
+		
+		if (event != null)
+		{
+			_events.add(event);
+		}
+		
+		if (intention != null)
+		{
+			_intentions.add(intention);
+		}
+		setCallback(callback);
+	}
+	
+	/**
+	 * Do action.
+	 */
+	public void doAction()
+	{
+		if (_callback != null)
+		{
+			_callback.doWork();
+		}
+	}
+	
+	/**
+	 * @return the _event
+	 */
+	public ArrayList<CtrlEvent> getEvents()
+	{
+		// If null return empty list.
+		if (_events == null)
+		{
+			_events = new ArrayList<>();
+		}
+		return _events;
+	}
+	
+	/**
+	 * @param event the event to set.
+	 */
+	public void setEvents(ArrayList<CtrlEvent> event)
+	{
+		_events = event;
+	}
+	
+	/**
+	 * @param event
+	 */
+	public void addEvent(CtrlEvent event)
+	{
+		if (_events == null)
+		{
+			_events = new ArrayList<>();
+		}
+		
+		if (event != null)
+		{
+			_events.add(event);
+		}
+	}
+	
+	/**
+	 * @param event
+	 */
+	public void removeEvent(CtrlEvent event)
+	{
+		if (_events == null)
+		{
+			return;
+		}
+		_events.remove(event);
+	}
+	
+	/**
+	 * @return the _callback
+	 */
+	public NextActionCallback getCallback()
+	{
+		return _callback;
+	}
+	
+	/**
+	 * @param callback the callback to set.
+	 */
+	public void setCallback(NextActionCallback callback)
+	{
+		_callback = callback;
+	}
+	
+	/**
+	 * @return the _intentions
+	 */
+	public ArrayList<CtrlIntention> getIntentions()
+	{
+		// If null return empty list.
+		if (_intentions == null)
+		{
+			_intentions = new ArrayList<>();
+		}
+		return _intentions;
+	}
+	
+	/**
+	 * @param intentions the intention to set.
+	 */
+	public void setIntentions(ArrayList<CtrlIntention> intentions)
+	{
+		_intentions = intentions;
+	}
+	
+	/**
+	 * @param intention
+	 */
+	public void addIntention(CtrlIntention intention)
+	{
+		if (_intentions == null)
+		{
+			_intentions = new ArrayList<>();
+		}
+		
+		if (intention != null)
+		{
+			_intentions.add(intention);
+		}
+	}
+	
+	/**
+	 * @param intention
+	 */
+	public void removeIntention(CtrlIntention intention)
+	{
+		if (_intentions == null)
+		{
+			return;
+		}
+		_intentions.remove(intention);
+	}
+}

+ 66 - 21
L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/RequestActionUse.java

@@ -19,8 +19,11 @@ import java.util.logging.Logger;
 
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.GameTimeController;
+import com.l2jserver.gameserver.ai.CtrlEvent;
 import com.l2jserver.gameserver.ai.CtrlIntention;
 import com.l2jserver.gameserver.ai.L2SummonAI;
+import com.l2jserver.gameserver.ai.NextAction;
+import com.l2jserver.gameserver.ai.NextAction.NextActionCallback;
 import com.l2jserver.gameserver.datatables.PetDataTable;
 import com.l2jserver.gameserver.datatables.SkillTable;
 import com.l2jserver.gameserver.datatables.SummonSkillsTable;
@@ -76,8 +79,7 @@ public final class RequestActionUse extends L2GameClientPacket
 	@Override
 	protected void runImpl()
 	{
-		L2PcInstance activeChar = getClient().getActiveChar();
-		
+		final L2PcInstance activeChar = getClient().getActiveChar();
 		if (activeChar == null)
 			return;
 		
@@ -110,8 +112,8 @@ public final class RequestActionUse extends L2GameClientPacket
 			}
 		}
 		
-		L2Summon pet = activeChar.getPet();
-		L2Object target = activeChar.getTarget();
+		final L2Summon pet = activeChar.getPet();
+		final L2Object target = activeChar.getTarget();
 		
 		if (Config.DEBUG)
 			_log.info("Requested Action ID: " + String.valueOf(_actionId));
@@ -119,23 +121,26 @@ public final class RequestActionUse extends L2GameClientPacket
 		switch (_actionId)
 		{
 			case 0: // Sit/Stand
-				if (activeChar.getMountType() != 0)
-					break;
-				
-				if (target != null && !activeChar.isSitting() && target instanceof L2StaticObjectInstance && ((L2StaticObjectInstance) target).getType() == 1 && CastleManager.getInstance().getCastle(target) != null
-						&& activeChar.isInsideRadius(target, L2StaticObjectInstance.INTERACTION_DISTANCE, false, false))
+				if (activeChar.isSitting() || !activeChar.isMoving())
 				{
-					final ChairSit cs = new ChairSit(activeChar, ((L2StaticObjectInstance) target).getStaticObjectId());
-					activeChar.sendPacket(cs);
-					activeChar.sitDown();
-					activeChar.broadcastPacket(cs);
-					break;
+					useSit(activeChar, target);
 				}
-				
-				if (activeChar.isSitting())
-					activeChar.standUp();
 				else
-					activeChar.sitDown();
+				{
+					// Sit when arrive using next action.
+					// Creating next action class.
+					final NextAction nextAction = new NextAction(CtrlEvent.EVT_ARRIVED, CtrlIntention.AI_INTENTION_MOVE_TO, new NextActionCallback()
+					{
+						@Override
+						public void doWork()
+						{
+							useSit(activeChar, target);
+						}
+					});
+					
+					// Binding next action to AI.
+					activeChar.getAI().setNextAction(nextAction);
+				}
 				
 				if (Config.DEBUG)
 					_log.fine("new wait type: " + (activeChar.isSitting() ? "SITTING" : "STANDING"));
@@ -148,7 +153,7 @@ public final class RequestActionUse extends L2GameClientPacket
 					activeChar.setRunning();
 				
 				if (Config.DEBUG)
-					_log.fine("new move type: " + (activeChar.isRunning() ? "RUNNING" : "WALKIN"));
+					_log.fine("New move type: " + (activeChar.isRunning() ? "RUNNING" : "WALKING"));
 				break;
 			case 10: // Private Store - Sell
 				activeChar.tryOpenPrivateSellStore(false);
@@ -181,7 +186,7 @@ public final class RequestActionUse extends L2GameClientPacket
 					
 					if (activeChar.isInOlympiadMode() && !activeChar.isOlympiadStart())
 					{
-						// if L2PcInstance is in Olympia and the match isn't already start, send a Server->Client packet ActionFailed
+						// If L2PcInstance is in Olympiad and the match isn't already start, send a Server->Client packet ActionFailed
 						activeChar.sendPacket(ActionFailed.STATIC_PACKET);
 						return;
 					}
@@ -763,10 +768,50 @@ public final class RequestActionUse extends L2GameClientPacket
 		}
 	}
 	
-	/*
+	/**
+	 * @param activeChar the player trying to sit.
+	 * @param target the target to sit, throne, bench or chair.
+	 * @return {@code true} if the player can sit, {@code false} otherwise.
+	 */
+	private boolean useSit(L2PcInstance activeChar, L2Object target)
+	{
+		if (activeChar.getMountType() != 0)
+		{
+			return false;
+		}
+		
+		if ((target != null) && !activeChar.isSitting() && (target instanceof L2StaticObjectInstance) && (((L2StaticObjectInstance) target).getType() == 1) && (CastleManager.getInstance().getCastle(target) != null)
+				&& activeChar.isInsideRadius(target, L2StaticObjectInstance.INTERACTION_DISTANCE, false, false))
+		{
+			final ChairSit cs = new ChairSit(activeChar, ((L2StaticObjectInstance) target).getStaticObjectId());
+			activeChar.sendPacket(cs);
+			activeChar.sitDown();
+			activeChar.broadcastPacket(cs);
+			return false;
+		}
+		
+		if (activeChar.isSitting())
+		{
+			activeChar.standUp();
+		}
+		else
+		{
+			activeChar.sitDown();
+		}
+		
+		if (Config.DEBUG)
+		{
+			_log.fine("New wait type: " + (activeChar.isSitting() ? "SITTING" : "STANDING"));
+		}
+		return true;
+	}
+	
+	/**
 	 * Cast a skill for active pet/servitor.
 	 * Target is specified as a parameter but can be
 	 * overwrited or ignored depending on skill type.
+	 * @param skillId 
+	 * @param target 
 	 */
 	private void useSkill(int skillId, L2Object target)
 	{

+ 27 - 12
L2J_Server_BETA/java/com/l2jserver/gameserver/network/clientpackets/UseItem.java

@@ -20,6 +20,10 @@ import java.util.logging.Logger;
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.GameTimeController;
 import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.ai.CtrlEvent;
+import com.l2jserver.gameserver.ai.CtrlIntention;
+import com.l2jserver.gameserver.ai.NextAction;
+import com.l2jserver.gameserver.ai.NextAction.NextActionCallback;
 import com.l2jserver.gameserver.handler.IItemHandler;
 import com.l2jserver.gameserver.handler.ItemHandler;
 import com.l2jserver.gameserver.instancemanager.FortSiegeManager;
@@ -191,18 +195,13 @@ public final class UseItem extends L2GameClientPacket
 				case L2Item.SLOT_L_HAND:
 				case L2Item.SLOT_R_HAND:
 				{
-					// prevent players to equip weapon while wearing combat flag
+					// Prevent players to equip weapon while wearing combat flag
 					if (activeChar.getActiveWeaponItem() != null && activeChar.getActiveWeaponItem().getItemId() == 9819)
 					{
 						activeChar.sendPacket(SystemMessageId.CANNOT_EQUIP_ITEM_DUE_TO_BAD_CONDITION);
 						return;
 					}
-					// Prevent player to remove the weapon on special conditions
-					if (activeChar.isCastingNow() || activeChar.isCastingSimultaneouslyNow())
-					{
-						activeChar.sendPacket(SystemMessageId.CANNOT_CHANGE_WEAPON_DURING_AN_ATTACK);
-						return;
-					}
+					
 					if (activeChar.isMounted())
 					{
 						activeChar.sendPacket(SystemMessageId.CANNOT_EQUIP_ITEM_DUE_TO_BAD_CONDITION);
@@ -282,13 +281,29 @@ public final class UseItem extends L2GameClientPacket
 				}
 			}
 			
-			if (activeChar.isAttackingNow())
+			if (activeChar.isCastingNow() || activeChar.isCastingSimultaneouslyNow())
 			{
-				ThreadPoolManager.getInstance().scheduleGeneral( new WeaponEquipTask(item,activeChar), (activeChar.getAttackEndTime()-GameTimeController.getGameTicks())*GameTimeController.MILLIS_IN_TICK);
-				return;
+				// Creating next action class.
+				final NextAction nextAction = new NextAction(CtrlEvent.EVT_FINISH_CASTING, CtrlIntention.AI_INTENTION_CAST, new NextActionCallback()
+				{
+					@Override
+					public void doWork()
+					{
+						activeChar.useEquippableItem(item, true);
+					}
+				});
+				
+				// Binding next action to AI.
+				activeChar.getAI().setNextAction(nextAction);
+			}
+			else if (activeChar.isAttackingNow())
+			{
+				ThreadPoolManager.getInstance().scheduleGeneral(new WeaponEquipTask(item, activeChar), (activeChar.getAttackEndTime() - GameTimeController.getGameTicks()) * GameTimeController.MILLIS_IN_TICK);
+			}
+			else
+			{
+				activeChar.useEquippableItem(item, true);
 			}
-			
-			activeChar.useEquippableItem(item, true);
 		}
 		else
 		{