Sync with L2jServer HighFive Oct 2nd 2015.
This commit is contained in:
parent
c90d8eb135
commit
7259087da5
5
trunk/dist/game/config/NPC.ini
vendored
5
trunk/dist/game/config/NPC.ini
vendored
@ -182,8 +182,9 @@ GrandChaosTime = 10
|
||||
MinionChaosTime = 10
|
||||
|
||||
# It removes STR,CON... bonuses.
|
||||
# With this npcs will use the stats given directly from the xml.
|
||||
IgnoreNpcStatFormulas = True
|
||||
# With this enabled npcs will use the stats given directly from the xml.
|
||||
# Default: False
|
||||
IgnoreNpcStatFormulas = False
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
@ -224,10 +224,8 @@ public class GeoData
|
||||
{
|
||||
if (target.isDoor())
|
||||
{
|
||||
// can always see doors :o
|
||||
return true;
|
||||
}
|
||||
|
||||
return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), cha.getInstanceId(), target.getX(), target.getY(), target.getZ(), target.getInstanceId());
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,6 @@ import com.l2jserver.gameserver.GameTimeController;
|
||||
import com.l2jserver.gameserver.GeoData;
|
||||
import com.l2jserver.gameserver.ThreadPoolManager;
|
||||
import com.l2jserver.gameserver.data.sql.impl.TerritoryTable;
|
||||
import com.l2jserver.gameserver.data.xml.impl.NpcData;
|
||||
import com.l2jserver.gameserver.enums.AISkillScope;
|
||||
import com.l2jserver.gameserver.enums.AIType;
|
||||
import com.l2jserver.gameserver.model.L2Object;
|
||||
@ -51,7 +50,6 @@ import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2RaidBossInstance;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2StaticObjectInstance;
|
||||
import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
|
||||
import com.l2jserver.gameserver.model.effects.L2EffectType;
|
||||
import com.l2jserver.gameserver.model.events.EventDispatcher;
|
||||
import com.l2jserver.gameserver.model.events.impl.character.npc.attackable.OnAttackableFactionCall;
|
||||
@ -66,6 +64,7 @@ import com.l2jserver.util.Rnd;
|
||||
|
||||
/**
|
||||
* This class manages AI of L2Attackable.
|
||||
* @author Zoey76
|
||||
*/
|
||||
public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
{
|
||||
@ -111,7 +110,6 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
|
||||
private int _timePass = 0;
|
||||
private int _chaosTime = 0;
|
||||
private final L2NpcTemplate _skillrender;
|
||||
private int _lastBuffTick;
|
||||
// Fear parameters
|
||||
private int _fearTime;
|
||||
@ -124,7 +122,6 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
public L2AttackableAI(L2Attackable creature)
|
||||
{
|
||||
super(creature);
|
||||
_skillrender = NpcData.getInstance().getTemplate(getActiveChar().getTemplate().getId());
|
||||
_attackTimeout = Integer.MAX_VALUE;
|
||||
_globalAggro = -10; // 10 seconds timeout of ATTACK after respawn
|
||||
}
|
||||
@ -370,11 +367,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
super.changeIntention(AI_INTENTION_IDLE, null, null);
|
||||
|
||||
// Stop AI task and detach AI from NPC
|
||||
if (_aiTask != null)
|
||||
{
|
||||
_aiTask.cancel(true);
|
||||
_aiTask = null;
|
||||
}
|
||||
stopAITask();
|
||||
|
||||
// Cancel the AI
|
||||
_actor.detachAI();
|
||||
@ -403,11 +396,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
// self and buffs
|
||||
if ((_lastBuffTick + 30) < GameTimeController.getInstance().getGameTicks())
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.BUFF))
|
||||
for (Skill buff : getActiveChar().getTemplate().getAISkills(AISkillScope.BUFF))
|
||||
{
|
||||
if (cast(sk))
|
||||
if (checkSkillCastConditions(getActiveChar(), buff))
|
||||
{
|
||||
break;
|
||||
if (!_actor.isAffectedBySkill(buff.getId()))
|
||||
{
|
||||
_actor.setTarget(_actor);
|
||||
_actor.doCast(buff);
|
||||
_actor.setTarget(target);
|
||||
_log.info(this.getActor().getName() + "used buff skill " + buff.getName() + " on " + _actor.getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_lastBuffTick = GameTimeController.getInstance().getGameTicks();
|
||||
@ -634,7 +634,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
else if (Rnd.nextInt(RANDOM_WALK_RATE) == 0)
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.BUFF))
|
||||
for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.BUFF))
|
||||
{
|
||||
if (cast(sk))
|
||||
{
|
||||
@ -651,7 +651,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
int z1 = 0;
|
||||
final int range = Config.MAX_DRIFT_RANGE;
|
||||
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.BUFF))
|
||||
for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.BUFF))
|
||||
{
|
||||
if (cast(sk))
|
||||
{
|
||||
@ -659,7 +659,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
// If NPC with random coord in territory - old method (for backward compartibility)
|
||||
// If NPC with random coord in territory - old method (for backward compatibility)
|
||||
if ((npc.getSpawn().getX() == 0) && (npc.getSpawn().getY() == 0) && (npc.getSpawn().getSpawnTerritory() == null))
|
||||
{
|
||||
// Calculate a destination point in the spawn area
|
||||
@ -708,8 +708,6 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
z1 = npc.getZ();
|
||||
}
|
||||
}
|
||||
|
||||
// _log.debug("Current pos ("+getX()+", "+getY()+"), moving to ("+x1+", "+y1+").");
|
||||
// Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
|
||||
final Location moveLoc = GeoData.getInstance().moveCheck(npc.getX(), npc.getY(), npc.getZ(), x1, y1, z1, npc.getInstanceId());
|
||||
|
||||
@ -725,9 +723,8 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
* <li>Call all L2Object of its Faction inside the Faction Range</li>
|
||||
* <li>Chose a target and order to attack it with magic skill or physical attack</li>
|
||||
* </ul>
|
||||
* TODO: Manage casting rules to healer mobs (like Ant Nurses)
|
||||
*/
|
||||
protected void thinkAttack()
|
||||
protected synchronized void thinkAttack()
|
||||
{
|
||||
final L2Attackable npc = getActiveChar();
|
||||
if (npc.isCastingNow())
|
||||
@ -774,13 +771,11 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
Set<Integer> clans = getActiveChar().getTemplate().getClans();
|
||||
if ((clans != null) && !clans.isEmpty())
|
||||
{
|
||||
int factionRange = npc.getTemplate().getClanHelpRange() + collision;
|
||||
final int factionRange = npc.getTemplate().getClanHelpRange() + collision;
|
||||
// Go through all L2Object that belong to its faction
|
||||
Collection<L2Object> objs = npc.getKnownList().getKnownObjects().values();
|
||||
|
||||
try
|
||||
{
|
||||
for (L2Object obj : objs)
|
||||
for (L2Object obj : npc.getKnownList().getKnownCharactersInRadius(factionRange))
|
||||
{
|
||||
if (obj instanceof L2Npc)
|
||||
{
|
||||
@ -792,7 +787,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
|
||||
// Check if the L2Object is inside the Faction Range of the actor
|
||||
if (npc.isInsideRadius(called, factionRange, true, false) && called.hasAI())
|
||||
if (called.hasAI())
|
||||
{
|
||||
if ((Math.abs(originalAttackTarget.getZ() - called.getZ()) < 600) && npc.getAttackByList().contains(originalAttackTarget) && ((called.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (called.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE)) && (called.getInstanceId() == npc.getInstanceId()))
|
||||
{
|
||||
@ -815,7 +810,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
catch (NullPointerException e)
|
||||
{
|
||||
_log.warning(getClass().getSimpleName() + ": thinkAttack() faction call failed: " + e.getMessage());
|
||||
_log.warning(getClass().getSimpleName() + ": There has been a problem trying to think the attack!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -837,30 +832,22 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
|
||||
final int combinedCollision = collision + mostHate.getTemplate().getCollisionRadius();
|
||||
|
||||
List<Skill> aiSuicideSkills = _skillrender.getAISkills(AISkillScope.SUICIDE);
|
||||
final List<Skill> aiSuicideSkills = npc.getTemplate().getAISkills(AISkillScope.SUICIDE);
|
||||
if (!aiSuicideSkills.isEmpty() && ((int) ((npc.getCurrentHp() / npc.getMaxHp()) * 100) < 30))
|
||||
{
|
||||
final Skill skill = aiSuicideSkills.get(Rnd.nextInt(aiSuicideSkills.size()));
|
||||
if (Util.checkIfInRange(skill.getAffectRange(), getActiveChar(), mostHate, false) && (Rnd.get(100) < Rnd.get(npc.getMinSkillChance(), npc.getMaxSkillChance())))
|
||||
final Skill skill = aiSuicideSkills.get(Rnd.get(aiSuicideSkills.size()));
|
||||
if (Util.checkIfInRange(skill.getAffectRange(), getActiveChar(), mostHate, false) && npc.hasSkillChance())
|
||||
{
|
||||
if (cast(skill))
|
||||
{
|
||||
_log.info(this.getActor().getName() + " used suicide skill " + skill.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
for (Skill sk : aiSuicideSkills)
|
||||
{
|
||||
if (cast(sk))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
// In case many mobs are trying to hit from same place, move a bit,
|
||||
// circling around the target
|
||||
// In case many mobs are trying to hit from same place, move a bit, circling around the target
|
||||
// Note from Gnacik:
|
||||
// On l2js because of that sometimes mobs don't attack player only running
|
||||
// around player without any sense, so decrease chance for now
|
||||
@ -1000,11 +987,12 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
if (!_skillrender.getAISkills(AISkillScope.GENERAL).isEmpty())
|
||||
final List<Skill> generalSkills = npc.getTemplate().getAISkills(AISkillScope.GENERAL);
|
||||
if (!generalSkills.isEmpty())
|
||||
{
|
||||
// -------------------------------------------------------------------------------
|
||||
// Heal Condition
|
||||
List<Skill> aiHealSkills = _skillrender.getAISkills(AISkillScope.HEAL);
|
||||
final List<Skill> aiHealSkills = npc.getTemplate().getAISkills(AISkillScope.HEAL);
|
||||
if (!aiHealSkills.isEmpty())
|
||||
{
|
||||
double percentage = (npc.getCurrentHp() / npc.getMaxHp()) * 100;
|
||||
@ -1013,52 +1001,64 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
L2Character leader = npc.getLeader();
|
||||
if ((leader != null) && !leader.isDead() && (Rnd.get(100) > ((leader.getCurrentHp() / leader.getMaxHp()) * 100)))
|
||||
{
|
||||
for (Skill sk : aiHealSkills)
|
||||
for (Skill healSkill : aiHealSkills)
|
||||
{
|
||||
if (sk.getTargetType() == L2TargetType.SELF)
|
||||
if (healSkill.getTargetType() == L2TargetType.SELF)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!checkSkillCastConditions(sk))
|
||||
|
||||
if (!checkSkillCastConditions(npc, healSkill))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!Util.checkIfInRange((sk.getCastRange() + collision + leader.getTemplate().getCollisionRadius()), npc, leader, false) && !isParty(sk) && !npc.isMovementDisabled())
|
||||
|
||||
if (!Util.checkIfInRange((healSkill.getCastRange() + collision + leader.getTemplate().getCollisionRadius()), npc, leader, false) && !isParty(healSkill) && !npc.isMovementDisabled())
|
||||
{
|
||||
moveToPawn(leader, sk.getCastRange() + collision + leader.getTemplate().getCollisionRadius());
|
||||
moveToPawn(leader, healSkill.getCastRange() + collision + leader.getTemplate().getCollisionRadius());
|
||||
return;
|
||||
}
|
||||
|
||||
if (GeoData.getInstance().canSeeTarget(npc, leader))
|
||||
{
|
||||
clientStopMoving(null);
|
||||
final L2Object target = npc.getTarget();
|
||||
npc.setTarget(leader);
|
||||
clientStopMoving(null);
|
||||
npc.doCast(sk);
|
||||
npc.doCast(healSkill);
|
||||
npc.setTarget(target);
|
||||
_log.info(this.getActor().getName() + " used heal skill " + healSkill.getName() + " on leader " + leader.getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Rnd.get(100) < ((100 - percentage) / 3))
|
||||
{
|
||||
for (Skill sk : aiHealSkills)
|
||||
{
|
||||
if (!checkSkillCastConditions(sk))
|
||||
if (!checkSkillCastConditions(npc, sk))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
clientStopMoving(null);
|
||||
final L2Object target = npc.getTarget();
|
||||
npc.setTarget(npc);
|
||||
npc.doCast(sk);
|
||||
npc.setTarget(target);
|
||||
_log.info(this.getActor().getName() + " used heal skill " + sk.getName() + " on itself");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (Skill sk : aiHealSkills)
|
||||
{
|
||||
if (!checkSkillCastConditions(sk))
|
||||
if (!checkSkillCastConditions(npc, sk))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sk.getTargetType() == L2TargetType.ONE)
|
||||
{
|
||||
for (L2Character obj : npc.getKnownList().getKnownCharactersInRadius(sk.getCastRange() + collision))
|
||||
@ -1068,24 +1068,29 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
continue;
|
||||
}
|
||||
|
||||
L2Attackable targets = ((L2Attackable) obj);
|
||||
if (!((L2Attackable) obj).isInMyClan(npc))
|
||||
final L2Attackable targets = (L2Attackable) obj;
|
||||
if (!targets.isInMyClan(npc))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
percentage = (targets.getCurrentHp() / targets.getMaxHp()) * 100;
|
||||
if (Rnd.get(100) < ((100 - percentage) / 10))
|
||||
{
|
||||
if (GeoData.getInstance().canSeeTarget(npc, targets))
|
||||
{
|
||||
clientStopMoving(null);
|
||||
final L2Object target = npc.getTarget();
|
||||
npc.setTarget(obj);
|
||||
npc.doCast(sk);
|
||||
npc.setTarget(target);
|
||||
_log.info(this.getActor().getName() + " used heal skill " + sk.getName() + " on " + obj.getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isParty(sk))
|
||||
{
|
||||
clientStopMoving(null);
|
||||
@ -1094,9 +1099,10 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Res Skill Condition
|
||||
List<Skill> aiResSkills = _skillrender.getAISkills(AISkillScope.RES);
|
||||
final List<Skill> aiResSkills = npc.getTemplate().getAISkills(AISkillScope.RES);
|
||||
if (!aiResSkills.isEmpty())
|
||||
{
|
||||
if (npc.isMinion())
|
||||
@ -1110,28 +1116,35 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!checkSkillCastConditions(sk))
|
||||
|
||||
if (!checkSkillCastConditions(npc, sk))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Util.checkIfInRange((sk.getCastRange() + collision + leader.getTemplate().getCollisionRadius()), npc, leader, false) && !isParty(sk) && !npc.isMovementDisabled())
|
||||
{
|
||||
moveToPawn(leader, sk.getCastRange() + collision + leader.getTemplate().getCollisionRadius());
|
||||
return;
|
||||
}
|
||||
|
||||
if (GeoData.getInstance().canSeeTarget(npc, leader))
|
||||
{
|
||||
clientStopMoving(null);
|
||||
final L2Object target = npc.getTarget();
|
||||
npc.setTarget(leader);
|
||||
npc.doCast(sk);
|
||||
npc.setTarget(target);
|
||||
_log.info(this.getActor().getName() + " used resurrection skill " + sk.getName() + " on leader " + leader.getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Skill sk : aiResSkills)
|
||||
{
|
||||
if (!checkSkillCastConditions(sk))
|
||||
if (!checkSkillCastConditions(npc, sk))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -1154,20 +1167,25 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
if (GeoData.getInstance().canSeeTarget(npc, targets))
|
||||
{
|
||||
clientStopMoving(null);
|
||||
final L2Object target = npc.getTarget();
|
||||
npc.setTarget(obj);
|
||||
npc.doCast(sk);
|
||||
npc.setTarget(target);
|
||||
_log.info(this.getActor().getName() + " used heal skill " + sk.getName() + " on clan member " + obj.getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isParty(sk))
|
||||
{
|
||||
clientStopMoving(null);
|
||||
L2Object target = getAttackTarget();
|
||||
final L2Object target = npc.getTarget();
|
||||
npc.setTarget(npc);
|
||||
npc.doCast(sk);
|
||||
npc.setTarget(target);
|
||||
_log.info(this.getActor().getName() + " used heal skill " + sk.getName() + " on party");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1195,69 +1213,35 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
|
||||
setTimepass(0);
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Skill Use
|
||||
List<Skill> aiGeneralSkills = _skillrender.getAISkills(AISkillScope.GENERAL);
|
||||
if (!aiGeneralSkills.isEmpty())
|
||||
// Long/Short Range skill usage.
|
||||
if (!npc.getShortRangeSkills().isEmpty() && npc.hasSkillChance())
|
||||
{
|
||||
if (Rnd.get(100) < Rnd.get(npc.getMinSkillChance(), npc.getMaxSkillChance()))
|
||||
final Skill shortRangeSkill = npc.getShortRangeSkills().get(Rnd.get(npc.getShortRangeSkills().size()));
|
||||
if (checkSkillCastConditions(npc, shortRangeSkill))
|
||||
{
|
||||
Skill skills = aiGeneralSkills.get(Rnd.nextInt(aiGeneralSkills.size()));
|
||||
if (cast(skills))
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (Skill sk : aiGeneralSkills)
|
||||
{
|
||||
if (cast(sk))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
clientStopMoving(null);
|
||||
npc.doCast(shortRangeSkill);
|
||||
_log.info(this.getActor().getName() + " used short range skill " + shortRangeSkill.getName() + " on " + npc.getTarget().getName());
|
||||
return;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Long/Short Range skill usage.
|
||||
if (npc.hasLSkill() || npc.hasSSkill())
|
||||
}
|
||||
|
||||
if (!npc.getLongRangeSkills().isEmpty() && npc.hasSkillChance())
|
||||
{
|
||||
final Skill longRangeSkill = npc.getLongRangeSkills().get(Rnd.get(npc.getLongRangeSkills().size()));
|
||||
if (checkSkillCastConditions(npc, longRangeSkill))
|
||||
{
|
||||
final List<Skill> shortRangeSkills = shortRangeSkillRender();
|
||||
if (!shortRangeSkills.isEmpty() && npc.hasSSkill() && (dist2 <= 150) && (Rnd.get(100) <= npc.getSSkillChance()))
|
||||
{
|
||||
final Skill shortRangeSkill = shortRangeSkills.get(Rnd.get(shortRangeSkills.size()));
|
||||
if ((shortRangeSkill != null) && cast(shortRangeSkill))
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (Skill sk : shortRangeSkills)
|
||||
{
|
||||
if ((sk != null) && cast(sk))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<Skill> longRangeSkills = longRangeSkillRender();
|
||||
if (!longRangeSkills.isEmpty() && npc.hasLSkill() && (dist2 > 150) && (Rnd.get(100) <= npc.getLSkillChance()))
|
||||
{
|
||||
final Skill longRangeSkill = longRangeSkills.get(Rnd.get(longRangeSkills.size()));
|
||||
if ((longRangeSkill != null) && cast(longRangeSkill))
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (Skill sk : longRangeSkills)
|
||||
{
|
||||
if ((sk != null) && cast(sk))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
clientStopMoving(null);
|
||||
npc.doCast(longRangeSkill);
|
||||
_log.info(this.getActor().getName() + " used long range skill " + longRangeSkill.getName() + " on " + npc.getTarget().getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Starts Melee or Primary Skill
|
||||
// Starts melee attack
|
||||
if ((dist2 > range) || !GeoData.getInstance().canSeeTarget(npc, mostHate))
|
||||
{
|
||||
if (npc.isMovementDisabled())
|
||||
@ -1279,54 +1263,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
return;
|
||||
}
|
||||
|
||||
melee(npc.getPrimarySkillId());
|
||||
}
|
||||
|
||||
private void melee(int type)
|
||||
{
|
||||
if (type != 0)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case -1:
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.GENERAL))
|
||||
{
|
||||
if (cast(sk))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.ATTACK))
|
||||
{
|
||||
if (cast(sk))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.GENERAL))
|
||||
{
|
||||
if (sk.getId() == getActiveChar().getPrimarySkillId())
|
||||
{
|
||||
if (cast(sk))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attacks target
|
||||
_actor.doAttack(getAttackTarget());
|
||||
}
|
||||
|
||||
@ -1338,16 +1275,11 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
|
||||
final L2Attackable caster = getActiveChar();
|
||||
|
||||
if (caster.isCastingNow() && !sk.isSimultaneousCast())
|
||||
if (!checkSkillCastConditions(caster, sk))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkSkillCastConditions(sk))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (getAttackTarget() == null)
|
||||
{
|
||||
if (caster.getMostHated() != null)
|
||||
@ -1829,6 +1761,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
/**
|
||||
* This AI task will start when ACTOR cannot move and attack range larger than distance
|
||||
*/
|
||||
// TODO(Zoey76): Rework this method.
|
||||
private void movementDisable()
|
||||
{
|
||||
final L2Attackable npc = getActiveChar();
|
||||
@ -1854,16 +1787,16 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
|
||||
// Check if activeChar has any skill
|
||||
if (!_skillrender.getAISkills(AISkillScope.GENERAL).isEmpty())
|
||||
if (!npc.getTemplate().getAISkills(AISkillScope.GENERAL).isEmpty())
|
||||
{
|
||||
// -------------------------------------------------------------
|
||||
// Try to stop the target or disable the target as priority
|
||||
int random = Rnd.get(100);
|
||||
if (!getAttackTarget().isImmobilized() && (random < 2))
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.IMMOBILIZE))
|
||||
for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.IMMOBILIZE))
|
||||
{
|
||||
if (!checkSkillCastConditions(sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)))
|
||||
if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -1886,9 +1819,9 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
// Same as Above, but with Mute/FEAR etc....
|
||||
if (random < 5)
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.COT))
|
||||
for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.COT))
|
||||
{
|
||||
if (!checkSkillCastConditions(sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)))
|
||||
if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -1910,9 +1843,9 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
// -------------------------------------------------------------
|
||||
if (random < 8)
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.DEBUFF))
|
||||
for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.DEBUFF))
|
||||
{
|
||||
if (!checkSkillCastConditions(sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)))
|
||||
if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -1935,9 +1868,9 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
// Some side effect skill like CANCEL or NEGATE
|
||||
if (random < 9)
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.NEGATIVE))
|
||||
for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.NEGATIVE))
|
||||
{
|
||||
if (!checkSkillCastConditions(sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)))
|
||||
if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -1960,9 +1893,9 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
// Start ATK SKILL when nothing can be done
|
||||
if ((npc.isMovementDisabled() || (npc.getAiType() == AIType.MAGE) || (npc.getAiType() == AIType.HEALER)))
|
||||
{
|
||||
for (Skill sk : _skillrender.getAISkills(AISkillScope.ATTACK))
|
||||
for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.ATTACK))
|
||||
{
|
||||
if (!checkSkillCastConditions(sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)))
|
||||
if (!checkSkillCastConditions(npc, sk) || (((sk.getCastRange() + npc.getTemplate().getCollisionRadius() + getAttackTarget().getTemplate().getCollisionRadius()) <= dist2) && !canAura(sk)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -2034,22 +1967,29 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
|
||||
}
|
||||
|
||||
melee(npc.getPrimarySkillId());
|
||||
// Attacks target
|
||||
_actor.doAttack(getAttackTarget());
|
||||
}
|
||||
catch (NullPointerException e)
|
||||
{
|
||||
setIntention(AI_INTENTION_ACTIVE);
|
||||
_log.warning(getClass().getSimpleName() + ": " + this + " - failed executing movementDisable(): " + e.getMessage());
|
||||
_log.warning(getClass().getSimpleName() + ": " + this.getActor().getName() + " - failed executing movementDisable()!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param caster the caster
|
||||
* @param skill the skill to check.
|
||||
* @return {@code true} if the skill is available for casting {@code false} otherwise.
|
||||
*/
|
||||
private boolean checkSkillCastConditions(Skill skill)
|
||||
private boolean checkSkillCastConditions(L2Attackable caster, Skill skill)
|
||||
{
|
||||
if (caster.isCastingNow() && !skill.isSimultaneousCast())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not enough MP.
|
||||
if (skill.getMpConsume() >= getActiveChar().getCurrentMp())
|
||||
{
|
||||
@ -2550,26 +2490,6 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
private List<Skill> longRangeSkillRender()
|
||||
{
|
||||
List<Skill> longRangeSkills = _skillrender.getAISkills(AISkillScope.LONG_RANGE);
|
||||
if (longRangeSkills.isEmpty())
|
||||
{
|
||||
longRangeSkills = getActiveChar().getLongRangeSkill();
|
||||
}
|
||||
return longRangeSkills;
|
||||
}
|
||||
|
||||
private List<Skill> shortRangeSkillRender()
|
||||
{
|
||||
List<Skill> shortRangeSkills = _skillrender.getAISkills(AISkillScope.SHORT_RANGE);
|
||||
if (shortRangeSkills.isEmpty())
|
||||
{
|
||||
shortRangeSkills = getActiveChar().getShortRangeSkill();
|
||||
}
|
||||
return shortRangeSkills;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage AI thinking actions of a L2Attackable.
|
||||
*/
|
||||
@ -2603,7 +2523,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.warning(getClass().getSimpleName() + ": " + this + " - onEvtThink() failed: " + e.getMessage());
|
||||
_log.warning(getClass().getSimpleName() + ": " + this.getActor().getName() + " - onEvtThink() failed!");
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -1629,7 +1629,7 @@ public class L2CharacterAI extends AbstractAI
|
||||
|
||||
public boolean canParty(Skill sk)
|
||||
{
|
||||
if (sk.getTargetType() == L2TargetType.PARTY)
|
||||
if (isParty(sk))
|
||||
{
|
||||
int count = 0;
|
||||
int ccount = 0;
|
||||
|
@ -509,98 +509,100 @@ public class NpcData implements IXmlReader
|
||||
Map<AISkillScope, List<Skill>> aiSkillLists = null;
|
||||
for (Skill skill : skills.values())
|
||||
{
|
||||
if (!skill.isPassive())
|
||||
if (skill.isPassive())
|
||||
{
|
||||
if (aiSkillLists == null)
|
||||
{
|
||||
aiSkillLists = new EnumMap<>(AISkillScope.class);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aiSkillLists == null)
|
||||
{
|
||||
aiSkillLists = new EnumMap<>(AISkillScope.class);
|
||||
}
|
||||
|
||||
final List<AISkillScope> aiSkillScopes = new ArrayList<>();
|
||||
final AISkillScope shortOrLongRangeScope = skill.getCastRange() <= 150 ? AISkillScope.SHORT_RANGE : AISkillScope.SHORT_RANGE;
|
||||
if (skill.isSuicideAttack())
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.SUICIDE);
|
||||
}
|
||||
else
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.GENERAL);
|
||||
|
||||
List<AISkillScope> aiSkillScopes = new ArrayList<>();
|
||||
final AISkillScope shortOrLongRangeScope = skill.getCastRange() <= 150 ? AISkillScope.SHORT_RANGE : AISkillScope.SHORT_RANGE;
|
||||
if (skill.isSuicideAttack())
|
||||
if (skill.isContinuous())
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.SUICIDE);
|
||||
}
|
||||
else
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.GENERAL);
|
||||
|
||||
if (skill.isContinuous())
|
||||
if (!skill.isDebuff())
|
||||
{
|
||||
if (!skill.isDebuff())
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.BUFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.DEBUFF);
|
||||
aiSkillScopes.add(AISkillScope.COT);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
aiSkillScopes.add(AISkillScope.BUFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (skill.hasEffectType(L2EffectType.DISPEL, L2EffectType.DISPEL_BY_SLOT))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.NEGATIVE);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.HEAL))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.HEAL);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.PHYSICAL_ATTACK, L2EffectType.PHYSICAL_ATTACK_HP_LINK, L2EffectType.MAGICAL_ATTACK, L2EffectType.DEATH_LINK, L2EffectType.HP_DRAIN))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.ATTACK);
|
||||
aiSkillScopes.add(AISkillScope.UNIVERSAL);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.SLEEP))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.IMMOBILIZE);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.STUN, L2EffectType.ROOT))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.IMMOBILIZE);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.MUTE, L2EffectType.FEAR))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.COT);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.PARALYZE))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.IMMOBILIZE);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.DMG_OVER_TIME, L2EffectType.DMG_OVER_TIME_PERCENT))
|
||||
{
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.RESURRECTION))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.RES);
|
||||
}
|
||||
else
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.UNIVERSAL);
|
||||
}
|
||||
aiSkillScopes.add(AISkillScope.DEBUFF);
|
||||
aiSkillScopes.add(AISkillScope.COT);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (skill.hasEffectType(L2EffectType.DISPEL, L2EffectType.DISPEL_BY_SLOT))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.NEGATIVE);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.HEAL))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.HEAL);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.PHYSICAL_ATTACK, L2EffectType.PHYSICAL_ATTACK_HP_LINK, L2EffectType.MAGICAL_ATTACK, L2EffectType.DEATH_LINK, L2EffectType.HP_DRAIN))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.ATTACK);
|
||||
aiSkillScopes.add(AISkillScope.UNIVERSAL);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.SLEEP))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.IMMOBILIZE);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.STUN, L2EffectType.ROOT))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.IMMOBILIZE);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.MUTE, L2EffectType.FEAR))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.COT);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.PARALYZE))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.IMMOBILIZE);
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.DMG_OVER_TIME, L2EffectType.DMG_OVER_TIME_PERCENT))
|
||||
{
|
||||
aiSkillScopes.add(shortOrLongRangeScope);
|
||||
}
|
||||
else if (skill.hasEffectType(L2EffectType.RESURRECTION))
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.RES);
|
||||
}
|
||||
else
|
||||
{
|
||||
aiSkillScopes.add(AISkillScope.UNIVERSAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (AISkillScope aiSkillScope : aiSkillScopes)
|
||||
{
|
||||
List<Skill> aiSkills = aiSkillLists.get(aiSkillScope);
|
||||
if (aiSkills == null)
|
||||
{
|
||||
aiSkills = new ArrayList<>();
|
||||
aiSkillLists.put(aiSkillScope, aiSkills);
|
||||
}
|
||||
|
||||
for (AISkillScope aiSkillScope : aiSkillScopes)
|
||||
{
|
||||
List<Skill> aiSkills = aiSkillLists.get(aiSkillScope);
|
||||
if (aiSkills == null)
|
||||
{
|
||||
aiSkills = new ArrayList<>();
|
||||
aiSkillLists.put(aiSkillScope, aiSkills);
|
||||
}
|
||||
|
||||
aiSkills.add(skill);
|
||||
}
|
||||
aiSkills.add(skill);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ import com.l2jserver.util.Rnd;
|
||||
*/
|
||||
public class AugmentationData
|
||||
{
|
||||
// Zoey76: TODO: Implement using IXmlReader.
|
||||
// TODO(Zoey76): Implement using IXmlReader.
|
||||
private static final Logger LOGGER = Logger.getLogger(AugmentationData.class.getName());
|
||||
|
||||
// stats
|
||||
@ -350,7 +350,6 @@ public class AugmentationData
|
||||
{
|
||||
NamedNodeMap aNodeAttributes = null;
|
||||
|
||||
// System.out.println("We're going through the list now.");
|
||||
for (Node n = l.getFirstChild(); n != null; n = n.getNextSibling())
|
||||
{
|
||||
if (n.getNodeName().equals("weapon"))
|
||||
@ -359,7 +358,6 @@ public class AugmentationData
|
||||
|
||||
aWeaponType = aNodeAttributes.getNamedItem("type").getNodeValue();
|
||||
|
||||
// System.out.println("Now showing Augmentations for " + aWeaponType + " Weapons.");
|
||||
for (Node c = n.getFirstChild(); c != null; c = c.getNextSibling())
|
||||
{
|
||||
if (c.getNodeName().equals("stone"))
|
||||
@ -384,7 +382,6 @@ public class AugmentationData
|
||||
|
||||
aCategoryChance = Integer.parseInt(aNodeAttributes.getNamedItem("probability").getNodeValue());
|
||||
|
||||
// System.out.println("Stone Id: " + aStoneId + ", Variation Id: " + aVariationId + ", Category Chances: " + aCategoryChance);
|
||||
for (Node e = j.getFirstChild(); e != null; e = e.getNextSibling())
|
||||
{
|
||||
if (e.getNodeName().equals("augment"))
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
package com.l2jserver.gameserver.instancemanager;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@ -26,9 +28,11 @@ import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jserver.gameserver.model.entity.Duel;
|
||||
import com.l2jserver.gameserver.model.skills.Skill;
|
||||
import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
|
||||
import com.l2jserver.util.Rnd;
|
||||
|
||||
public final class DuelManager
|
||||
{
|
||||
private static final List<String> ARENAS = Arrays.asList("OlympiadGrassyArena.xml", "OlympiadHerossVestigesArena.xml", "OlympiadOrbisArena.xml", "OlympiadThreeBridgesArena.xml");
|
||||
private final Map<Integer, Duel> _duels = new ConcurrentHashMap<>();
|
||||
private final AtomicInteger _currentDuelId = new AtomicInteger();
|
||||
|
||||
@ -209,6 +213,15 @@ public final class DuelManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets new a random Olympiad Stadium instance name.
|
||||
* @return an instance name
|
||||
*/
|
||||
public String getDuelArena()
|
||||
{
|
||||
return ARENAS.get(Rnd.get(ARENAS.size()));
|
||||
}
|
||||
|
||||
public static final DuelManager getInstance()
|
||||
{
|
||||
return SingletonHolder._instance;
|
||||
|
@ -362,7 +362,7 @@ public class StatsSet implements IParserAdvUtils
|
||||
Object val = _set.get(key);
|
||||
if (val == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Integer value required, but not specified");
|
||||
throw new IllegalArgumentException("Long value required, but not specified");
|
||||
}
|
||||
if (val instanceof Number)
|
||||
{
|
||||
@ -374,7 +374,7 @@ public class StatsSet implements IParserAdvUtils
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("Integer value required, but found: " + val);
|
||||
throw new IllegalArgumentException("Long value required, but found: " + val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -396,7 +396,7 @@ public class StatsSet implements IParserAdvUtils
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("Integer value required, but found: " + val);
|
||||
throw new IllegalArgumentException("Long value required, but found: " + val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,7 +414,7 @@ public class StatsSet implements IParserAdvUtils
|
||||
}
|
||||
try
|
||||
{
|
||||
return (float) Double.parseDouble((String) val);
|
||||
return Float.parseFloat((String) val);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -436,7 +436,7 @@ public class StatsSet implements IParserAdvUtils
|
||||
}
|
||||
try
|
||||
{
|
||||
return (float) Double.parseDouble((String) val);
|
||||
return Float.parseFloat((String) val);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -450,7 +450,7 @@ public class StatsSet implements IParserAdvUtils
|
||||
Object val = _set.get(key);
|
||||
if (val == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Float value required, but not specified");
|
||||
throw new IllegalArgumentException("Double value required, but not specified");
|
||||
}
|
||||
if (val instanceof Number)
|
||||
{
|
||||
@ -462,7 +462,7 @@ public class StatsSet implements IParserAdvUtils
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("Float value required, but found: " + val);
|
||||
throw new IllegalArgumentException("Double value required, but found: " + val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -484,7 +484,7 @@ public class StatsSet implements IParserAdvUtils
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("Float value required, but found: " + val);
|
||||
throw new IllegalArgumentException("Double value required, but found: " + val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -607,7 +607,7 @@ public class StatsSet implements IParserAdvUtils
|
||||
Object obj = _set.get(key);
|
||||
if ((obj == null) || !(obj instanceof List<?>))
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return (List<MinionHolder>) obj;
|
||||
|
@ -111,6 +111,7 @@ public class L2Attackable extends L2Npc
|
||||
// Misc
|
||||
private boolean _mustGiveExpSp;
|
||||
protected int _onKillDelay = 5000;
|
||||
private long _lastAttack;
|
||||
|
||||
/**
|
||||
* Creates an attackable NPC.
|
||||
@ -1575,6 +1576,16 @@ public class L2Attackable extends L2Npc
|
||||
return _onKillDelay;
|
||||
}
|
||||
|
||||
public long getLastAttack()
|
||||
{
|
||||
return _lastAttack;
|
||||
}
|
||||
|
||||
public void setLastAttack(long lastAttack)
|
||||
{
|
||||
_lastAttack = lastAttack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the server allows Random Animation.
|
||||
*/
|
||||
|
@ -5409,7 +5409,6 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
|
||||
// Remove all its Func objects from the L2Character calculator set
|
||||
if (oldSkill != null)
|
||||
{
|
||||
|
||||
// Stop casting if this skill is used right now
|
||||
if ((getLastSkillCast() != null) && isCastingNow())
|
||||
{
|
||||
@ -5444,7 +5443,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
|
||||
*/
|
||||
public final Collection<Skill> getAllSkills()
|
||||
{
|
||||
return new ArrayList<>(_skills.values());
|
||||
return _skills.values();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,6 @@ package com.l2jserver.gameserver.model.actor;
|
||||
|
||||
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -83,7 +82,6 @@ import com.l2jserver.gameserver.model.items.L2Weapon;
|
||||
import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
|
||||
import com.l2jserver.gameserver.model.olympiad.Olympiad;
|
||||
import com.l2jserver.gameserver.model.skills.Skill;
|
||||
import com.l2jserver.gameserver.model.skills.targets.L2TargetType;
|
||||
import com.l2jserver.gameserver.model.variables.NpcVariables;
|
||||
import com.l2jserver.gameserver.model.zone.type.L2TownZone;
|
||||
import com.l2jserver.gameserver.network.SystemMessageId;
|
||||
@ -193,14 +191,6 @@ public class L2Npc extends L2Character
|
||||
return getTemplate().getSpiritShotChance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the primary attack skill Id
|
||||
*/
|
||||
public int getPrimarySkillId()
|
||||
{
|
||||
return getTemplate().getPrimarySkillId();
|
||||
}
|
||||
|
||||
public int getMinSkillChance()
|
||||
{
|
||||
return getTemplate().getMinSkillChance();
|
||||
@ -211,6 +201,15 @@ public class L2Npc extends L2Character
|
||||
return getTemplate().getMaxSkillChance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if the NPC can cast a skill given the minimum and maximum skill chances.
|
||||
* @return {@code true} if the NPC has chances of casting a skill
|
||||
*/
|
||||
public boolean hasSkillChance()
|
||||
{
|
||||
return Rnd.get(100) < Rnd.get(getMinSkillChance(), getMaxSkillChance());
|
||||
}
|
||||
|
||||
public boolean canMove()
|
||||
{
|
||||
return getTemplate().canMove();
|
||||
@ -226,169 +225,57 @@ public class L2Npc extends L2Character
|
||||
return getTemplate().getDodge();
|
||||
}
|
||||
|
||||
public int getSSkillChance()
|
||||
public List<Skill> getLongRangeSkills()
|
||||
{
|
||||
return getTemplate().getShortRangeSkillChance();
|
||||
return getTemplate().getAISkills(AISkillScope.LONG_RANGE);
|
||||
}
|
||||
|
||||
public int getLSkillChance()
|
||||
public List<Skill> getShortRangeSkills()
|
||||
{
|
||||
return getTemplate().getLongRangeSkillChance();
|
||||
}
|
||||
|
||||
public boolean hasLSkill()
|
||||
{
|
||||
return getTemplate().getLongRangeSkillId() > 0;
|
||||
}
|
||||
|
||||
public boolean hasSSkill()
|
||||
{
|
||||
return getTemplate().getShortRangeSkillId() > 0;
|
||||
}
|
||||
|
||||
public List<Skill> getLongRangeSkill()
|
||||
{
|
||||
final List<Skill> skilldata = new ArrayList<>();
|
||||
if (getTemplate().getLongRangeSkillId() == 0)
|
||||
{
|
||||
return skilldata;
|
||||
}
|
||||
|
||||
switch (getTemplate().getLongRangeSkillId())
|
||||
{
|
||||
case -1:
|
||||
{
|
||||
final Collection<Skill> skills = getAllSkills();
|
||||
if (skills != null)
|
||||
{
|
||||
for (Skill sk : skills)
|
||||
{
|
||||
if ((sk == null) || sk.isPassive() || (sk.getTargetType() == L2TargetType.SELF))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sk.getCastRange() >= 200)
|
||||
{
|
||||
skilldata.add(sk);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
for (Skill sk : getTemplate().getAISkills(AISkillScope.UNIVERSAL))
|
||||
{
|
||||
if (sk.getCastRange() >= 200)
|
||||
{
|
||||
skilldata.add(sk);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
for (Skill sk : getAllSkills())
|
||||
{
|
||||
if (sk.getId() == getTemplate().getLongRangeSkillId())
|
||||
{
|
||||
skilldata.add(sk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return skilldata;
|
||||
}
|
||||
|
||||
public List<Skill> getShortRangeSkill()
|
||||
{
|
||||
final List<Skill> skilldata = new ArrayList<>();
|
||||
if (getTemplate().getShortRangeSkillId() == 0)
|
||||
{
|
||||
return skilldata;
|
||||
}
|
||||
|
||||
switch (getTemplate().getShortRangeSkillId())
|
||||
{
|
||||
case -1:
|
||||
{
|
||||
Collection<Skill> skills = getAllSkills();
|
||||
if (skills != null)
|
||||
{
|
||||
for (Skill sk : skills)
|
||||
{
|
||||
if ((sk == null) || sk.isPassive() || (sk.getTargetType() == L2TargetType.SELF))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (sk.getCastRange() <= 200)
|
||||
{
|
||||
skilldata.add(sk);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
for (Skill sk : getTemplate().getAISkills(AISkillScope.UNIVERSAL))
|
||||
{
|
||||
if (sk.getCastRange() <= 200)
|
||||
{
|
||||
skilldata.add(sk);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
for (Skill sk : getAllSkills())
|
||||
{
|
||||
if (sk.getId() == getTemplate().getShortRangeSkillId())
|
||||
{
|
||||
skilldata.add(sk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return skilldata;
|
||||
return getTemplate().getAISkills(AISkillScope.SHORT_RANGE);
|
||||
}
|
||||
|
||||
/** Task launching the function onRandomAnimation() */
|
||||
protected class RandomAnimationTask implements Runnable
|
||||
protected static class RandomAnimationTask implements Runnable
|
||||
{
|
||||
private final L2Npc _npc;
|
||||
|
||||
protected RandomAnimationTask(L2Npc npc)
|
||||
{
|
||||
_npc = npc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isMob())
|
||||
if (_npc.isMob())
|
||||
{
|
||||
// Cancel further animation timers until intention is changed to ACTIVE again.
|
||||
if (getAI().getIntention() != AI_INTENTION_ACTIVE)
|
||||
if (_npc.getAI().getIntention() != AI_INTENTION_ACTIVE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isInActiveRegion())
|
||||
if (!_npc.isInActiveRegion())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(isDead() || isStunned() || isSleeping() || isParalyzed()))
|
||||
if (!(_npc.isDead() || _npc.isStunned() || _npc.isSleeping() || _npc.isParalyzed()))
|
||||
{
|
||||
onRandomAnimation(Rnd.get(2, 3));
|
||||
_npc.onRandomAnimation(Rnd.get(2, 3));
|
||||
}
|
||||
|
||||
startRandomAnimationTimer();
|
||||
_npc.startRandomAnimationTimer();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.log(Level.SEVERE, "", e);
|
||||
_log.log(Level.SEVERE, "There has been an error trying to perform a random animation for NPC " + _npc.getId() + "!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -425,7 +312,7 @@ public class L2Npc extends L2Character
|
||||
int interval = Rnd.get(minWait, maxWait) * 1000;
|
||||
|
||||
// Create a RandomAnimation Task that will be launched after the calculated delay
|
||||
_rAniTask = new RandomAnimationTask();
|
||||
_rAniTask = new RandomAnimationTask(this);
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(_rAniTask, interval);
|
||||
}
|
||||
|
||||
|
@ -6774,8 +6774,8 @@ public final class L2PcInstance extends L2Playable
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the _accessLevel of the L2PcInstance.
|
||||
* @param level
|
||||
* Set the access level for this player.
|
||||
* @param level the access level
|
||||
* @param broadcast
|
||||
*/
|
||||
public void setAccessLevel(int level, boolean broadcast)
|
||||
@ -6793,7 +6793,7 @@ public final class L2PcInstance extends L2Playable
|
||||
|
||||
if (!AdminData.getInstance().hasAccessLevel(level))
|
||||
{
|
||||
_log.warning("Tryed to set unregistered access level " + level + " for " + toString() + ". Setting access level without privileges!");
|
||||
_log.warning("Tried to set unregistered access level " + level + " for " + toString() + ". Setting access level without privileges!");
|
||||
}
|
||||
else if (level > 0)
|
||||
{
|
||||
|
@ -89,11 +89,6 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
|
||||
private int _spiritShotChance;
|
||||
private int _minSkillChance;
|
||||
private int _maxSkillChance;
|
||||
private int _primarySkillId;
|
||||
private int _shortRangeSkillId;
|
||||
private int _shortRangeSkillChance;
|
||||
private int _longRangeSkillId;
|
||||
private int _longRangeSkillChance;
|
||||
private Map<Integer, Skill> _skills;
|
||||
private Map<AISkillScope, List<Skill>> _aiSkillLists;
|
||||
private Set<Integer> _clans;
|
||||
@ -166,11 +161,6 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
|
||||
|
||||
_minSkillChance = set.getInt("minSkillChance", 7);
|
||||
_maxSkillChance = set.getInt("maxSkillChance", 15);
|
||||
_primarySkillId = set.getInt("primarySkillId", 0);
|
||||
_shortRangeSkillId = set.getInt("shortRangeSkillId", 0);
|
||||
_shortRangeSkillChance = set.getInt("shortRangeSkillChance", 0);
|
||||
_longRangeSkillId = set.getInt("longRangeSkillId", 0);
|
||||
_longRangeSkillChance = set.getInt("longRangeSkillChance", 0);
|
||||
|
||||
_collisionRadiusGrown = set.getDouble("collisionRadiusGrown", 0);
|
||||
_collisionHeightGrown = set.getDouble("collisionHeightGrown", 0);
|
||||
@ -397,31 +387,6 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
|
||||
return _maxSkillChance;
|
||||
}
|
||||
|
||||
public int getPrimarySkillId()
|
||||
{
|
||||
return _primarySkillId;
|
||||
}
|
||||
|
||||
public int getShortRangeSkillId()
|
||||
{
|
||||
return _shortRangeSkillId;
|
||||
}
|
||||
|
||||
public int getShortRangeSkillChance()
|
||||
{
|
||||
return _shortRangeSkillChance;
|
||||
}
|
||||
|
||||
public int getLongRangeSkillId()
|
||||
{
|
||||
return _longRangeSkillId;
|
||||
}
|
||||
|
||||
public int getLongRangeSkillChance()
|
||||
{
|
||||
return _longRangeSkillChance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, Skill> getSkills()
|
||||
{
|
||||
@ -430,18 +395,17 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
|
||||
|
||||
public void setSkills(Map<Integer, Skill> skills)
|
||||
{
|
||||
_skills = skills != null ? Collections.unmodifiableMap(skills) : Collections.<Integer, Skill> emptyMap();
|
||||
_skills = skills != null ? Collections.unmodifiableMap(skills) : Collections.emptyMap();
|
||||
}
|
||||
|
||||
public List<Skill> getAISkills(AISkillScope aiSkillScope)
|
||||
{
|
||||
final List<Skill> aiSkills = _aiSkillLists.get(aiSkillScope);
|
||||
return aiSkills != null ? aiSkills : Collections.<Skill> emptyList();
|
||||
return _aiSkillLists.getOrDefault(aiSkillScope, Collections.emptyList());
|
||||
}
|
||||
|
||||
public void setAISkillLists(Map<AISkillScope, List<Skill>> aiSkillLists)
|
||||
{
|
||||
_aiSkillLists = aiSkillLists != null ? Collections.unmodifiableMap(aiSkillLists) : Collections.<AISkillScope, List<Skill>> emptyMap();
|
||||
_aiSkillLists = aiSkillLists != null ? Collections.unmodifiableMap(aiSkillLists) : Collections.emptyMap();
|
||||
}
|
||||
|
||||
public Set<Integer> getClans()
|
||||
|
@ -20,7 +20,9 @@ package com.l2jserver.gameserver.model.entity;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@ -29,10 +31,17 @@ import com.l2jserver.gameserver.ai.CtrlIntention;
|
||||
import com.l2jserver.gameserver.enums.DuelResult;
|
||||
import com.l2jserver.gameserver.enums.Team;
|
||||
import com.l2jserver.gameserver.instancemanager.DuelManager;
|
||||
import com.l2jserver.gameserver.instancemanager.InstanceManager;
|
||||
import com.l2jserver.gameserver.instancemanager.ZoneManager;
|
||||
import com.l2jserver.gameserver.model.Location;
|
||||
import com.l2jserver.gameserver.model.actor.L2Npc;
|
||||
import com.l2jserver.gameserver.model.actor.L2Summon;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2OlympiadManagerInstance;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jserver.gameserver.model.skills.Skill;
|
||||
import com.l2jserver.gameserver.model.zone.ZoneId;
|
||||
import com.l2jserver.gameserver.model.zone.type.L2OlympiadStadiumZone;
|
||||
import com.l2jserver.gameserver.network.SystemMessageId;
|
||||
import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
|
||||
import com.l2jserver.gameserver.network.serverpackets.ExDuelEnd;
|
||||
@ -43,6 +52,7 @@ import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
|
||||
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
|
||||
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
|
||||
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
|
||||
import com.l2jserver.util.Rnd;
|
||||
|
||||
public class Duel
|
||||
{
|
||||
@ -56,16 +66,20 @@ public class Duel
|
||||
|
||||
private static final PlaySound B04_S01 = new PlaySound(1, "B04_S01", 0, 0, 0, 0, 0);
|
||||
|
||||
private static final int PARTY_DUEL_DURATION = 300;
|
||||
private static final int PLAYER_DUEL_DURATION = 120;
|
||||
|
||||
private final int _duelId;
|
||||
private L2PcInstance _playerA;
|
||||
private L2PcInstance _playerB;
|
||||
private final boolean _partyDuel;
|
||||
private final Calendar _duelEndTime;
|
||||
private int _surrenderRequest = 0;
|
||||
private int _countdown = 4;
|
||||
private int _countdown = 5;
|
||||
private boolean _finished = false;
|
||||
|
||||
private final List<PlayerCondition> _playerConditions = new CopyOnWriteArrayList<>();
|
||||
private final Map<Integer, PlayerCondition> _playerConditions = new ConcurrentHashMap<>();
|
||||
private int _duelInstanceId;
|
||||
|
||||
public Duel(L2PcInstance playerA, L2PcInstance playerB, int partyDuel, int duelId)
|
||||
{
|
||||
@ -75,21 +89,12 @@ public class Duel
|
||||
_partyDuel = partyDuel == 1 ? true : false;
|
||||
|
||||
_duelEndTime = Calendar.getInstance();
|
||||
if (_partyDuel)
|
||||
{
|
||||
_duelEndTime.add(Calendar.SECOND, 300);
|
||||
}
|
||||
else
|
||||
{
|
||||
_duelEndTime.add(Calendar.SECOND, 120);
|
||||
}
|
||||
_duelEndTime.add(Calendar.SECOND, _partyDuel ? PARTY_DUEL_DURATION : PLAYER_DUEL_DURATION);
|
||||
|
||||
setFinished(false);
|
||||
|
||||
if (_partyDuel)
|
||||
{
|
||||
// increase countdown so that start task can teleport players
|
||||
_countdown++;
|
||||
// inform players that they will be ported shortly
|
||||
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.IN_A_MOMENT_YOU_WILL_BE_TRANSPORTED_TO_THE_SITE_WHERE_THE_DUEL_WILL_TAKE_PLACE);
|
||||
broadcastToTeam1(sm);
|
||||
@ -107,7 +112,7 @@ public class Duel
|
||||
private double _cp;
|
||||
private boolean _paDuel;
|
||||
private int _x, _y, _z;
|
||||
private List<Skill> _debuffs;
|
||||
private Set<Skill> _debuffs;
|
||||
|
||||
public PlayerCondition(L2PcInstance player, boolean partyDuel)
|
||||
{
|
||||
@ -159,7 +164,7 @@ public class Duel
|
||||
{
|
||||
if (_debuffs == null)
|
||||
{
|
||||
_debuffs = new CopyOnWriteArrayList<>();
|
||||
_debuffs = ConcurrentHashMap.newKeySet();
|
||||
}
|
||||
|
||||
_debuffs.add(debuff);
|
||||
@ -169,7 +174,7 @@ public class Duel
|
||||
{
|
||||
if (_paDuel)
|
||||
{
|
||||
_player.teleToLocation(new Location(_x, _y, _z));
|
||||
_player.teleToLocation(_x, _y, _z);
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,28 +198,33 @@ public class Duel
|
||||
{
|
||||
try
|
||||
{
|
||||
DuelResult status = _duel.checkEndDuelCondition();
|
||||
|
||||
if (status == DuelResult.Canceled)
|
||||
switch (_duel.checkEndDuelCondition())
|
||||
{
|
||||
// do not schedule duel end if it was interrupted
|
||||
setFinished(true);
|
||||
_duel.endDuel(status);
|
||||
}
|
||||
else if (status != DuelResult.Continue)
|
||||
{
|
||||
setFinished(true);
|
||||
playKneelAnimation();
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleEndDuelTask(_duel, status), 5000);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(this, 1000);
|
||||
case Canceled:
|
||||
{
|
||||
// do not schedule duel end if it was interrupted
|
||||
setFinished(true);
|
||||
_duel.endDuel(DuelResult.Canceled);
|
||||
break;
|
||||
}
|
||||
case Continue:
|
||||
{
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(this, 1000);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
setFinished(true);
|
||||
playKneelAnimation();
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleEndDuelTask(_duel, _duel.checkEndDuelCondition()), 5000);
|
||||
InstanceManager.getInstance().destroyInstance(_duel.getDueldInstanceId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.log(Level.SEVERE, "", e);
|
||||
_log.log(Level.SEVERE, "There has been a problem while runing a duel task!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -238,13 +248,13 @@ public class Duel
|
||||
|
||||
if (count == 4)
|
||||
{
|
||||
// players need to be teleportet first
|
||||
// TODO: stadia manager needs a function to return an unused stadium for duels
|
||||
// currently only teleports to the same stadium
|
||||
_duel.teleportPlayers(-83760, -238825, -3331);
|
||||
// Save player conditions before teleporting players
|
||||
_duel.savePlayerConditions();
|
||||
|
||||
// give players 20 seconds to complete teleport and get ready (its ought to be 30 on offical..)
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(this, 20000);
|
||||
_duel.teleportPlayers();
|
||||
|
||||
// give players 20 seconds to complete teleport and get ready (its ought to be 30 on official..)
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(this, _duel.isPartyDuel() ? 20000 : 1);
|
||||
}
|
||||
else if (count > 0) // duel not started yet - continue countdown
|
||||
{
|
||||
@ -287,6 +297,11 @@ public class Duel
|
||||
}
|
||||
}
|
||||
|
||||
public int getDueldInstanceId()
|
||||
{
|
||||
return _duelInstanceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops all players from attacking. Used for duel timeout / interrupt.
|
||||
*/
|
||||
@ -301,6 +316,19 @@ public class Duel
|
||||
temp.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
|
||||
temp.setTarget(null);
|
||||
temp.sendPacket(af);
|
||||
if (temp.hasSummon())
|
||||
{
|
||||
for (L2Summon summon : temp.getServitors().values())
|
||||
{
|
||||
if (!summon.isDead())
|
||||
{
|
||||
summon.abortCast();
|
||||
summon.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
|
||||
summon.setTarget(null);
|
||||
summon.sendPacket(af);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (L2PcInstance temp : _playerB.getParty().getMembers())
|
||||
{
|
||||
@ -308,6 +336,19 @@ public class Duel
|
||||
temp.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
|
||||
temp.setTarget(null);
|
||||
temp.sendPacket(af);
|
||||
if (temp.hasSummon())
|
||||
{
|
||||
for (L2Summon summon : temp.getServitors().values())
|
||||
{
|
||||
if (!summon.isDead())
|
||||
{
|
||||
summon.abortCast();
|
||||
summon.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
|
||||
summon.setTarget(null);
|
||||
summon.sendPacket(af);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -320,6 +361,32 @@ public class Duel
|
||||
_playerB.setTarget(null);
|
||||
_playerA.sendPacket(af);
|
||||
_playerB.sendPacket(af);
|
||||
if (_playerA.hasSummon())
|
||||
{
|
||||
for (L2Summon summon : _playerA.getServitors().values())
|
||||
{
|
||||
if (!summon.isDead())
|
||||
{
|
||||
summon.abortCast();
|
||||
summon.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
|
||||
summon.setTarget(null);
|
||||
summon.sendPacket(af);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_playerB.hasSummon())
|
||||
{
|
||||
for (L2Summon summon : _playerB.getServitors().values())
|
||||
{
|
||||
if (!summon.isDead())
|
||||
{
|
||||
summon.abortCast();
|
||||
summon.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
|
||||
summon.setTarget(null);
|
||||
summon.sendPacket(af);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -353,9 +420,6 @@ public class Duel
|
||||
*/
|
||||
public void startDuel()
|
||||
{
|
||||
// Save player Conditions
|
||||
savePlayerConditions();
|
||||
|
||||
if ((_playerA == null) || (_playerB == null) || _playerA.isInDuel() || _playerB.isInDuel())
|
||||
{
|
||||
_playerConditions.clear();
|
||||
@ -365,8 +429,7 @@ public class Duel
|
||||
|
||||
if (_partyDuel)
|
||||
{
|
||||
// set isInDuel() state
|
||||
// cancel all active trades, just in case? xD
|
||||
// Set duel state and team
|
||||
for (L2PcInstance temp : _playerA.getParty().getMembers())
|
||||
{
|
||||
temp.cancelActiveTrade();
|
||||
@ -384,31 +447,35 @@ public class Duel
|
||||
broadcastToTeam1(new ExDuelUpdateUserInfo(temp));
|
||||
}
|
||||
|
||||
// Send duel Start packets
|
||||
ExDuelReady ready = new ExDuelReady(1);
|
||||
ExDuelStart start = new ExDuelStart(1);
|
||||
// Send duel packets
|
||||
broadcastToTeam1(ExDuelReady.PARTY_DUEL);
|
||||
broadcastToTeam2(ExDuelReady.PARTY_DUEL);
|
||||
broadcastToTeam1(ExDuelStart.PARTY_DUEL);
|
||||
broadcastToTeam2(ExDuelStart.PARTY_DUEL);
|
||||
|
||||
broadcastToTeam1(ready);
|
||||
broadcastToTeam2(ready);
|
||||
broadcastToTeam1(start);
|
||||
broadcastToTeam2(start);
|
||||
// Open arena doors
|
||||
for (L2DoorInstance door : InstanceManager.getInstance().getInstance(getDueldInstanceId()).getDoors())
|
||||
{
|
||||
if ((door != null) && !door.getOpen())
|
||||
{
|
||||
door.openMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// set isInDuel() state
|
||||
// Set duel state and team
|
||||
_playerA.setIsInDuel(_duelId);
|
||||
_playerA.setTeam(Team.BLUE);
|
||||
_playerB.setIsInDuel(_duelId);
|
||||
_playerB.setTeam(Team.RED);
|
||||
|
||||
// Send duel Start packets
|
||||
ExDuelReady ready = new ExDuelReady(0);
|
||||
ExDuelStart start = new ExDuelStart(0);
|
||||
|
||||
broadcastToTeam1(ready);
|
||||
broadcastToTeam2(ready);
|
||||
broadcastToTeam1(start);
|
||||
broadcastToTeam2(start);
|
||||
// Send duel packets
|
||||
broadcastToTeam1(ExDuelReady.PLAYER_DUEL);
|
||||
broadcastToTeam2(ExDuelReady.PLAYER_DUEL);
|
||||
broadcastToTeam1(ExDuelStart.PLAYER_DUEL);
|
||||
broadcastToTeam2(ExDuelStart.PLAYER_DUEL);
|
||||
|
||||
broadcastToTeam1(new ExDuelUpdateUserInfo(_playerB));
|
||||
broadcastToTeam2(new ExDuelUpdateUserInfo(_playerA));
|
||||
@ -421,7 +488,7 @@ public class Duel
|
||||
broadcastToTeam1(B04_S01);
|
||||
broadcastToTeam2(B04_S01);
|
||||
|
||||
// start duelling task
|
||||
// start dueling task
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleDuelTask(this), 1000);
|
||||
}
|
||||
|
||||
@ -434,17 +501,17 @@ public class Duel
|
||||
{
|
||||
for (L2PcInstance player : _playerA.getParty().getMembers())
|
||||
{
|
||||
_playerConditions.add(new PlayerCondition(player, _partyDuel));
|
||||
_playerConditions.put(player.getObjectId(), new PlayerCondition(player, _partyDuel));
|
||||
}
|
||||
for (L2PcInstance player : _playerB.getParty().getMembers())
|
||||
{
|
||||
_playerConditions.add(new PlayerCondition(player, _partyDuel));
|
||||
_playerConditions.put(player.getObjectId(), new PlayerCondition(player, _partyDuel));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_playerConditions.add(new PlayerCondition(_playerA, _partyDuel));
|
||||
_playerConditions.add(new PlayerCondition(_playerB, _partyDuel));
|
||||
_playerConditions.put(_playerA.getObjectId(), new PlayerCondition(_playerA, _partyDuel));
|
||||
_playerConditions.put(_playerB.getObjectId(), new PlayerCondition(_playerB, _partyDuel));
|
||||
}
|
||||
}
|
||||
|
||||
@ -487,7 +554,7 @@ public class Duel
|
||||
}
|
||||
|
||||
// restore player conditions
|
||||
_playerConditions.forEach(c -> c.restoreCondition());
|
||||
_playerConditions.values().forEach(c -> c.restoreCondition());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -546,30 +613,46 @@ public class Duel
|
||||
}
|
||||
|
||||
/**
|
||||
* teleport all players to the given coordinates
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* Teleports all players to a free arena.
|
||||
*/
|
||||
public void teleportPlayers(int x, int y, int z)
|
||||
public void teleportPlayers()
|
||||
{
|
||||
// TODO: adjust the values if needed... or implement something better (especially using more then 1 arena)
|
||||
if (!_partyDuel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int offset = 0;
|
||||
|
||||
final String instanceName = DuelManager.getInstance().getDuelArena();
|
||||
final L2OlympiadStadiumZone zone = ZoneManager.getInstance().getAllZones(L2OlympiadStadiumZone.class) //
|
||||
.stream().filter(z -> z.getInstanceTemplate().equals(instanceName)).findFirst().orElse(null);
|
||||
|
||||
if (zone == null)
|
||||
{
|
||||
throw new RuntimeException("Unable to find a party duel arena!");
|
||||
}
|
||||
|
||||
final List<Location> spawns = zone.getSpawns();
|
||||
_duelInstanceId = InstanceManager.getInstance().createDynamicInstance(instanceName);
|
||||
|
||||
// Remove Olympiad buffers
|
||||
for (L2Npc buffer : InstanceManager.getInstance().getInstance(getDueldInstanceId()).getNpcs())
|
||||
{
|
||||
if ((buffer instanceof L2OlympiadManagerInstance) && buffer.isVisible())
|
||||
{
|
||||
buffer.decayMe();
|
||||
}
|
||||
}
|
||||
|
||||
final Location spawn1 = spawns.get(Rnd.get(spawns.size() / 2));
|
||||
for (L2PcInstance temp : _playerA.getParty().getMembers())
|
||||
{
|
||||
temp.teleToLocation(new Location((x + offset) - 180, y - 150, z));
|
||||
offset += 40;
|
||||
temp.teleToLocation(spawn1.getX(), spawn1.getY(), spawn1.getZ(), 0, _duelInstanceId, 0);
|
||||
}
|
||||
offset = 0;
|
||||
|
||||
final Location spawn2 = spawns.get(Rnd.get(spawns.size() / 2, spawns.size()));
|
||||
for (L2PcInstance temp : _playerB.getParty().getMembers())
|
||||
{
|
||||
temp.teleToLocation(new Location((x + offset) - 180, y + 150, z));
|
||||
offset += 40;
|
||||
temp.teleToLocation(spawn2.getX(), spawn2.getY(), spawn2.getZ(), 0, _duelInstanceId, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -664,7 +747,7 @@ public class Duel
|
||||
}
|
||||
|
||||
/**
|
||||
* Playback the bow animation for all loosers
|
||||
* Playback the bow animation for all looser
|
||||
*/
|
||||
public void playKneelAnimation()
|
||||
{
|
||||
@ -794,17 +877,7 @@ public class Duel
|
||||
break;
|
||||
}
|
||||
|
||||
// Send end duel packet
|
||||
ExDuelEnd duelEnd = null;
|
||||
if (_partyDuel)
|
||||
{
|
||||
duelEnd = new ExDuelEnd(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
duelEnd = new ExDuelEnd(0);
|
||||
}
|
||||
|
||||
final ExDuelEnd duelEnd = _partyDuel ? ExDuelEnd.PARTY_DUEL : ExDuelEnd.PLAYER_DUEL;
|
||||
broadcastToTeam1(duelEnd);
|
||||
broadcastToTeam2(duelEnd);
|
||||
|
||||
@ -1014,7 +1087,7 @@ public class Duel
|
||||
// if he's either playerA or playerB cancel the duel and port the players back
|
||||
if ((player == _playerA) || (player == _playerB))
|
||||
{
|
||||
for (PlayerCondition cond : _playerConditions)
|
||||
for (PlayerCondition cond : _playerConditions.values())
|
||||
{
|
||||
cond.teleportBack();
|
||||
cond.getPlayer().setIsInDuel(0);
|
||||
@ -1026,7 +1099,7 @@ public class Duel
|
||||
else
|
||||
// teleport the player back & delete his PlayerCondition record
|
||||
{
|
||||
final PlayerCondition cond = _playerConditions.stream().filter(c -> c.getPlayer() == player).findFirst().orElse(null);
|
||||
final PlayerCondition cond = _playerConditions.get(player.getObjectId());
|
||||
if (cond != null)
|
||||
{
|
||||
cond.teleportBack();
|
||||
@ -1038,7 +1111,7 @@ public class Duel
|
||||
|
||||
public void onBuff(L2PcInstance player, Skill debuff)
|
||||
{
|
||||
final PlayerCondition cond = _playerConditions.stream().filter(c -> c.getPlayer() == player).findFirst().orElse(null);
|
||||
final PlayerCondition cond = _playerConditions.get(player.getObjectId());
|
||||
if (cond != null)
|
||||
{
|
||||
cond.registerDebuff(debuff);
|
||||
|
@ -19,15 +19,19 @@
|
||||
package com.l2jserver.gameserver.network.serverpackets;
|
||||
|
||||
/**
|
||||
* @author KenM
|
||||
* Duel End packet implementation.
|
||||
* @author KenM, Zoey76
|
||||
*/
|
||||
public class ExDuelEnd extends L2GameServerPacket
|
||||
{
|
||||
private final int _unk1;
|
||||
public static final ExDuelEnd PLAYER_DUEL = new ExDuelEnd(false);
|
||||
public static final ExDuelEnd PARTY_DUEL = new ExDuelEnd(true);
|
||||
|
||||
public ExDuelEnd(int unk1)
|
||||
private final int _partyDuel;
|
||||
|
||||
private ExDuelEnd(boolean isPartyDuel)
|
||||
{
|
||||
_unk1 = unk1;
|
||||
_partyDuel = isPartyDuel ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -36,6 +40,6 @@ public class ExDuelEnd extends L2GameServerPacket
|
||||
writeC(0xFE);
|
||||
writeH(0x50);
|
||||
|
||||
writeD(_unk1);
|
||||
writeD(_partyDuel);
|
||||
}
|
||||
}
|
||||
|
@ -19,15 +19,19 @@
|
||||
package com.l2jserver.gameserver.network.serverpackets;
|
||||
|
||||
/**
|
||||
* @author KenM
|
||||
* Duel Ready packet implementation.
|
||||
* @author KenM, Zoey76
|
||||
*/
|
||||
public class ExDuelReady extends L2GameServerPacket
|
||||
{
|
||||
private final int _unk1;
|
||||
public static final ExDuelReady PLAYER_DUEL = new ExDuelReady(false);
|
||||
public static final ExDuelReady PARTY_DUEL = new ExDuelReady(true);
|
||||
|
||||
public ExDuelReady(int unk1)
|
||||
private final boolean _partyDuel;
|
||||
|
||||
public ExDuelReady(boolean partyDuel)
|
||||
{
|
||||
_unk1 = unk1;
|
||||
_partyDuel = partyDuel;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -36,6 +40,6 @@ public class ExDuelReady extends L2GameServerPacket
|
||||
writeC(0xFE);
|
||||
writeH(0x4E);
|
||||
|
||||
writeD(_unk1);
|
||||
writeD(_partyDuel ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
@ -19,15 +19,19 @@
|
||||
package com.l2jserver.gameserver.network.serverpackets;
|
||||
|
||||
/**
|
||||
* @author KenM
|
||||
* Duel Start packet implementation.
|
||||
* @author KenM, Zoey76
|
||||
*/
|
||||
public class ExDuelStart extends L2GameServerPacket
|
||||
{
|
||||
private final int _unk1;
|
||||
public static final ExDuelReady PLAYER_DUEL = new ExDuelReady(false);
|
||||
public static final ExDuelReady PARTY_DUEL = new ExDuelReady(true);
|
||||
|
||||
public ExDuelStart(int unk1)
|
||||
private final boolean _partyDuel;
|
||||
|
||||
public ExDuelStart(boolean partyDuel)
|
||||
{
|
||||
_unk1 = unk1;
|
||||
_partyDuel = partyDuel;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -36,6 +40,6 @@ public class ExDuelStart extends L2GameServerPacket
|
||||
writeC(0xFE);
|
||||
writeH(0x4F);
|
||||
|
||||
writeD(_unk1);
|
||||
writeD(_partyDuel ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import java.util.List;
|
||||
|
||||
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.interfaces.IPositionable;
|
||||
|
||||
/**
|
||||
@ -50,16 +49,7 @@ public final class MagicSkillUse extends L2GameServerPacket
|
||||
_skillLevel = skillLevel;
|
||||
_hitTime = hitTime;
|
||||
_reuseDelay = reuseDelay;
|
||||
Location skillWorldPos = null;
|
||||
if (cha.isPlayer())
|
||||
{
|
||||
final L2PcInstance player = cha.getActingPlayer();
|
||||
if (player.getCurrentSkillWorldPosition() != null)
|
||||
{
|
||||
skillWorldPos = player.getCurrentSkillWorldPosition();
|
||||
}
|
||||
}
|
||||
_groundLocations = skillWorldPos != null ? Arrays.asList(skillWorldPos) : Collections.<Location> emptyList();
|
||||
_groundLocations = cha.isPlayer() && (cha.getActingPlayer().getCurrentSkillWorldPosition() != null) ? Arrays.asList(cha.getActingPlayer().getCurrentSkillWorldPosition()) : Collections.<Location> emptyList();
|
||||
}
|
||||
|
||||
public MagicSkillUse(L2Character cha, int skillId, int skillLevel, int hitTime, int reuseDelay)
|
||||
|
Loading…
Reference in New Issue
Block a user