first commit

This commit is contained in:
2026-09-12 13:23:01 +00:00
parent 3d98459187
commit 9fa534b20e
1905 changed files with 303180 additions and 0 deletions
@@ -0,0 +1,305 @@
/*
* Copyright © 2004-2026 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.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_IDLE;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_MOVE_TO;
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.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.skills.Skill;
import com.l2jserver.gameserver.model.skills.targets.TargetType;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
public class L2PlayerAI extends L2PlayableAI {
private boolean _thinking; // to prevent recursive thinking
private IntentionCommand _nextIntention = null;
public L2PlayerAI(L2PcInstance creature) {
super(creature);
}
void saveNextIntention(CtrlIntention intention, Object arg0, Object arg1) {
_nextIntention = new IntentionCommand(intention, arg0, arg1);
}
@Override
public IntentionCommand getNextIntention() {
return _nextIntention;
}
/**
* Saves the current Intention for this L2PlayerAI if necessary and calls changeIntention in AbstractAI.
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention
* @param arg1 The second parameter of the Intention
*/
@Override
protected synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1) {
// Forget next if it's not cast or it's cast and skill is toggle.
if ((intention != AI_INTENTION_CAST) || ((arg0 != null) && !((Skill) arg0).isToggle())) {
_nextIntention = null;
super.changeIntention(intention, arg0, arg1);
return;
}
// do nothing if next intention is same as current one.
if ((intention == _intention) && (arg0 == _intentionArg0) && (arg1 == _intentionArg1)) {
super.changeIntention(intention, arg0, arg1);
return;
}
// save current intention so it can be used after cast
saveNextIntention(_intention, _intentionArg0, _intentionArg1);
super.changeIntention(intention, arg0, arg1);
}
/**
* Launch actions corresponding to the Event ReadyToAct.<br>
* <B><U> Actions</U> :</B>
* <ul>
* <li>Launch actions corresponding to the Event Think</li>
* </ul>
*/
@Override
protected void onEvtReadyToAct() {
// Launch actions corresponding to the Event Think
if (_nextIntention != null) {
setIntention(_nextIntention._crtlIntention, _nextIntention._arg0, _nextIntention._arg1);
_nextIntention = null;
}
super.onEvtReadyToAct();
}
/**
* Launch actions corresponding to the Event Cancel.<br>
* <B><U> Actions</U> :</B>
* <ul>
* <li>Stop an AI Follow Task</li>
* <li>Launch actions corresponding to the Event Think</li>
* </ul>
*/
@Override
protected void onEvtCancel() {
_nextIntention = null;
super.onEvtCancel();
}
/**
* Finalize the casting of a skill. This method overrides L2CharacterAI method.<br>
* <B>What it does:</B><br>
* Check if actual intention is set to CAST and, if so, retrieves latest intention before the actual CAST and set it as the current intention for the player.
*/
@Override
protected void onEvtFinishCasting() {
if (getIntention() == AI_INTENTION_CAST) {
// run interrupted or next intention
IntentionCommand nextIntention = _nextIntention;
if (nextIntention != null) {
if (nextIntention._crtlIntention != AI_INTENTION_CAST) // previous state shouldn't be casting
{
setIntention(nextIntention._crtlIntention, nextIntention._arg0, nextIntention._arg1);
} else {
setIntention(AI_INTENTION_IDLE);
}
} else {
// set intention to idle if skill doesn't change intention.
setIntention(AI_INTENTION_IDLE);
}
}
}
@Override
protected void onIntentionRest() {
if (getIntention() != AI_INTENTION_REST) {
changeIntention(AI_INTENTION_REST, null, null);
setTarget(null);
if (getAttackTarget() != null) {
setAttackTarget(null);
}
clientStopMoving(null);
}
}
@Override
protected void onIntentionActive() {
setIntention(AI_INTENTION_IDLE);
}
/**
* Manage the Move To Intention : Stop current Attack and Launch a Move to Location Task.<br>
* <B><U> Actions</U> : </B>
* <ul>
* <li>Stop the actor auto-attack server side AND client side by sending Server->Client packet AutoAttackStop (broadcast)</li>
* <li>Set the Intention of this AI to AI_INTENTION_MOVE_TO</li>
* <li>Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)</li>
* </ul>
*/
@Override
protected void onIntentionMoveTo(Location loc) {
if (getIntention() == AI_INTENTION_REST) {
// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
clientActionFailed();
return;
}
if (_actor.getActingPlayer().getDuelState() == DuelState.DEAD) {
clientActionFailed();
_actor.getActingPlayer().sendPacket(SystemMessage.getSystemMessage(SystemMessageId.CANNOT_MOVE_FROZEN));
return;
}
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow()) {
clientActionFailed();
saveNextIntention(AI_INTENTION_MOVE_TO, loc, 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_MOVE_TO
changeIntention(AI_INTENTION_MOVE_TO, loc, null);
// Abort the attack of the L2Character and send Server->Client ActionFailed packet
_actor.abortAttack();
// Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
moveTo(loc.getX(), loc.getY(), loc.getZ());
}
@Override
protected void clientNotifyDead() {
_clientMovingToPawnOffset = 0;
_clientMoving = false;
super.clientNotifyDead();
}
private void thinkAttack() {
L2Character target = getAttackTarget();
if (target == null) {
return;
}
if (checkTargetLostOrDead(target)) {
// Notify the target
setAttackTarget(null);
return;
}
if (maybeMoveToPawn(target, _actor.getPhysicalAttackRange())) {
return;
}
clientStopMoving(null);
_actor.doAttack(target);
}
private void thinkCast() {
L2Character target = getCastTarget();
if ((_skill.getTargetType() == TargetType.GROUND) && (_actor instanceof L2PcInstance)) {
if (maybeMoveToPosition(((L2PcInstance) _actor).getCurrentSkillWorldPosition(), _actor.getMagicalAttackRange(_skill))) {
_actor.setIsCastingNow(false);
return;
}
} else {
if (checkTargetLost(target)) {
if (_skill.isBad() && (getAttackTarget() != null)) {
// Notify the target
setCastTarget(null);
}
_actor.setIsCastingNow(false);
return;
}
if ((target != null) && maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill))) {
_actor.setIsCastingNow(false);
return;
}
}
if ((_skill.getHitTime() > 50) && !_skill.isSimultaneousCast()) {
clientStopMoving(null);
}
_actor.doCast(_skill);
}
private void thinkPickUp() {
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow()) {
return;
}
L2Object target = getTarget();
if (checkTargetLost(target)) {
return;
}
if (maybeMoveToPawn(target, 36)) {
return;
}
setIntention(AI_INTENTION_IDLE);
_actor.getActingPlayer().doPickupItem(target);
}
private void thinkInteract() {
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow()) {
return;
}
L2Object target = getTarget();
if (checkTargetLost(target)) {
return;
}
if (maybeMoveToPawn(target, 36)) {
return;
}
if (!(target instanceof L2StaticObjectInstance)) {
_actor.getActingPlayer().doInteract((L2Character) target);
}
setIntention(AI_INTENTION_IDLE);
}
@Override
protected void onEvtThink() {
if (_thinking && (getIntention() != AI_INTENTION_CAST)) {
return;
}
_thinking = true;
try {
if (getIntention() == AI_INTENTION_ATTACK) {
thinkAttack();
} else if (getIntention() == AI_INTENTION_CAST) {
thinkCast();
} else if (getIntention() == AI_INTENTION_PICK_UP) {
thinkPickUp();
} else if (getIntention() == AI_INTENTION_INTERACT) {
thinkInteract();
}
} finally {
_thinking = false;
}
}
}