/** * Check if the skill can be used * * @return True if the skill can be used */ public boolean canUseSkill() { Properties properties = skillTemplate.getProperties(); if (properties != null && !properties.validate(this)) { log.debug("properties failed"); return false; } if (!preCastCheck()) return false; // check for counter skill if (effector instanceof Player) { Player player = (Player) effector; if (this.skillTemplate.getCounterSkill() != null) { long time = player.getLastCounterSkill(skillTemplate.getCounterSkill()); if ((time + 5000) < System.currentTimeMillis()) { log.debug("chain skill failed, too late"); return false; } } if (skillMethod == SkillMethod.ITEM && duration > 0 && player.getMoveController().isInMove()) { PacketSendUtility.sendPacket( player, SM_SYSTEM_MESSAGE.STR_ITEM_CANCELED(new DescriptionId(getItemTemplate().getNameId()))); return false; } } if (!validateEffectedList()) return false; return true; }
private void setCooldowns() { int cooldown = effector.getSkillCooldown(skillTemplate); if (cooldown != 0) { effector.setSkillCoolDown( skillTemplate.getCooldownId(), cooldown * 100 + System.currentTimeMillis()); effector.setSkillCoolDownBase(skillTemplate.getCooldownId(), System.currentTimeMillis()); } }
/** * Each skill is a separate object upon invocation Skill level will be populated from player * SkillList * * @param skillTemplate * @param effector * @param world */ public Skill(SkillTemplate skillTemplate, Player effector, Creature firstTarget) { this( skillTemplate, effector, effector.getSkillList().getSkillLevel(skillTemplate.getSkillId()), firstTarget, null); }
/** * @param skillTemplate * @param effector * @param skillLvl * @param firstTarget */ public Skill( SkillTemplate skillTemplate, Creature effector, int skillLvl, Creature firstTarget, ItemTemplate itemTemplate) { this.effectedList = new ArrayList<Creature>(); this.conditionChangeListener = new StartMovingListener(); this.firstTarget = firstTarget; this.skillLevel = skillLvl; this.skillStackLvl = skillTemplate.getLvl(); this.skillTemplate = skillTemplate; this.effector = effector; this.duration = skillTemplate.getDuration(); this.itemTemplate = itemTemplate; if (itemTemplate != null) skillMethod = SkillMethod.ITEM; else if (skillTemplate.isPassive()) skillMethod = SkillMethod.PASSIVE; else if (skillTemplate.isProvoked()) skillMethod = SkillMethod.PROVOKED; else if (skillTemplate.isCharge()) skillMethod = SkillMethod.CHARGE; }
/** @return true if the present skill is a self buff includes items (such as scroll buffs) */ public boolean isSelfBuff() { return (firstTargetAttribute == FirstTargetAttribute.ME && targetRangeAttribute == TargetRangeAttribute.ONLYONE && skillTemplate.getSubType() == SkillSubType.BUFF && !skillTemplate.isDeityAvatar()); }
/** @return true or false */ public boolean isPassive() { return skillTemplate.getActivationAttribute() == ActivationAttribute.PASSIVE; }
/** @return the skillId */ public int getSkillId() { return skillTemplate.getSkillId(); }
/** Check all conditions after using skill */ private boolean endCondCheck() { Conditions skillConditions = skillTemplate.getEndConditions(); return skillConditions != null ? skillConditions.validate(this) : true; }
/** Check all conditions before using skill */ private boolean preUsageCheck() { Conditions skillConditions = skillTemplate.getUseconditions(); return skillConditions != null ? skillConditions.validate(this) : true; }
/** Check all conditions before starting cast */ protected boolean preCastCheck() { Conditions skillConditions = skillTemplate.getStartconditions(); return skillConditions != null ? skillConditions.validate(this) : true; }
/** Apply effects and perform actions specified in skill template */ protected void endCast() { if (!effector.isCasting() || isCancelled) return; // if target out of range if (skillTemplate == null) return; // Check if target is out of skill range Properties properties = skillTemplate.getProperties(); if (properties != null && !properties.endCastValidate(this)) { effector.getController().cancelCurrentSkill(); return; } if (!validateEffectedList()) { effector.getController().cancelCurrentSkill(); return; } if (!preUsageCheck()) { return; } effector.setCasting(null); if (this.getSkillTemplate().isDeityAvatar() && effector instanceof Player) { AbyssService.rankerSkillAnnounce((Player) effector, this.getSkillTemplate().getNameId()); } /** try removing item, if its not possible return to prevent exploits */ if (effector instanceof Player && skillMethod == SkillMethod.ITEM) { Item item = ((Player) effector).getInventory().getItemByObjId(this.itemObjectId); if (item == null) return; if (item.getActivationCount() > 1) { item.setActivationCount(item.getActivationCount() - 1); } else { if (!((Player) effector) .getInventory() .decreaseByObjectId(item.getObjectId(), 1, ItemUpdateType.DEC_USE)) return; } } /** Create effects and precalculate result */ int spellStatus = 0; int dashStatus = 0; int resistCount = 0; boolean blockedChain = false; boolean blockedStance = false; final List<Effect> effects = new ArrayList<Effect>(); if (skillTemplate.getEffects() != null) { boolean blockAOESpread = false; for (Creature effected : effectedList) { Effect effect = new Effect(this, effected, 0, itemTemplate); if (effected instanceof Player) { if (effect.getEffectResult() == EffectResult.CONFLICT) blockedStance = true; } // Force RESIST status if AOE spell spread must be blocked if (blockAOESpread) effect.setAttackStatus(AttackStatus.RESIST); effect.initialize(); final int worldId = effector.getWorldId(); final int instanceId = effector.getInstanceId(); effect.setWorldPosition(worldId, instanceId, x, y, z); effects.add(effect); spellStatus = effect.getSpellStatus().getId(); dashStatus = effect.getDashStatus().getId(); // Block AOE propagation if firstTarget resists the spell if ((!blockAOESpread) && (effect.getAttackStatus() == AttackStatus.RESIST) && (isTargetAOE())) blockAOESpread = true; if (effect.getAttackStatus() == AttackStatus.RESIST || effect.getAttackStatus() == AttackStatus.DODGE) { resistCount++; } } if (resistCount == effectedList.size()) { blockedChain = true; blockedPenaltySkill = true; } // exception for point point skills(example Ice Sheet) if (effectedList.isEmpty() && this.isPointPointSkill()) { Effect effect = new Effect(this, null, 0, itemTemplate); effect.initialize(); final int worldId = effector.getWorldId(); final int instanceId = effector.getInstanceId(); effect.setWorldPosition(worldId, instanceId, x, y, z); effects.add(effect); spellStatus = effect.getSpellStatus().getId(); } } if (effector instanceof Player && skillMethod == SkillMethod.CAST) { Player playerEffector = (Player) effector; if (playerEffector.getController().isUnderStance()) { playerEffector.getController().stopStance(); } if (skillTemplate.isStance() && !blockedStance) { playerEffector.getController().startStance(skillTemplate.getSkillId()); } } boolean setCooldowns = true; if (effector instanceof Player) { if (this.isMulticast() && ((Player) effector) .getChainSkills() .getChainCount((Player) effector, this.getSkillTemplate(), this.chainCategory) != 0) { setCooldowns = false; } } // Check Chain Skill Trigger Rate if (CustomConfig.SKILL_CHAIN_TRIGGERRATE) { int chainProb = skillTemplate.getChainSkillProb(); if (this.chainCategory != null && !blockedChain) { this.chainSuccess = Rnd.get(90) < chainProb; } } else { this.chainSuccess = true; } /** set variables for chaincondition check */ if (effector instanceof Player && this.chainSuccess && this.chainCategory != null) { ((Player) effector).getChainSkills().addChainSkill(this.chainCategory, this.isMulticast()); } /** Perform necessary actions (use mp,dp items etc) */ Actions skillActions = skillTemplate.getActions(); if (skillActions != null) { for (Action action : skillActions.getActions()) { if (!action.act(this)) return; } } if (effector instanceof Player) { QuestEnv env = new QuestEnv(effector.getTarget(), (Player) effector, 0, 0); QuestEngine.getInstance().onUseSkill(env, skillTemplate.getSkillId()); } if (setCooldowns) this.setCooldowns(); if (hitTime == 0) applyEffect(effects); else { ThreadPoolManager.getInstance() .schedule( new Runnable() { @Override public void run() { applyEffect(effects); } }, hitTime); } if (skillMethod == SkillMethod.CAST || skillMethod == SkillMethod.ITEM || skillMethod == SkillMethod.CHARGE) sendCastspellEnd(spellStatus, dashStatus, effects); endCondCheck(); if (effector instanceof Npc) SkillAttackManager.afterUseSkill((NpcAI2) ((Npc) effector).getAi2()); }
/** Start casting of skill */ protected void startCast() { int targetObjId = firstTarget != null ? firstTarget.getObjectId() : 0; if (skillMethod == SkillMethod.CAST || skillMethod == SkillMethod.CHARGE) { switch (targetType) { case 0: // PlayerObjectId as Target PacketSendUtility.broadcastPacketAndReceive( effector, new SM_CASTSPELL( effector.getObjectId(), skillTemplate.getSkillId(), skillLevel, targetType, targetObjId, this.duration, skillTemplate.isCharge())); if (effector instanceof Npc && firstTarget instanceof Player) { NpcAI2 ai = (NpcAI2) effector.getAi2(); if (ai.poll(AIQuestion.CAN_SHOUT)) ShoutEventHandler.onCast(ai, firstTarget); } break; case 3: // Target not in sight? PacketSendUtility.broadcastPacketAndReceive( effector, new SM_CASTSPELL( effector.getObjectId(), skillTemplate.getSkillId(), skillLevel, targetType, 0, this.duration, skillTemplate.isCharge())); break; case 1: // XYZ as Target PacketSendUtility.broadcastPacketAndReceive( effector, new SM_CASTSPELL( effector.getObjectId(), skillTemplate.getSkillId(), skillLevel, targetType, x, y, z, this.duration)); break; } } else if (skillMethod == SkillMethod.ITEM && duration > 0) { PacketSendUtility.broadcastPacketAndReceive( effector, new SM_ITEM_USAGE_ANIMATION( effector.getObjectId(), firstTarget.getObjectId(), (this.itemObjectId == 0 ? 0 : this.itemObjectId), itemTemplate.getTemplateId(), this.duration, 0, 0)); } }
/** Penalty success skill */ private void startPenaltySkill() { int penaltySkill = skillTemplate.getPenaltySkillId(); if (penaltySkill == 0) return; SkillEngine.getInstance().applyEffectDirectly(penaltySkill, firstTarget, effector, 0); }
protected void calculateSkillDuration() { // Skills that are not affected by boost casting time duration = 0; if (isCastTimeFixed()) { duration = skillTemplate.getDuration(); return; } duration = effector .getGameStats() .getPositiveReverseStat(StatEnum.BOOST_CASTING_TIME, skillTemplate.getDuration()); switch (skillTemplate.getSubType()) { case SUMMON: duration = effector .getGameStats() .getPositiveReverseStat(StatEnum.BOOST_CASTING_TIME_SUMMON, duration); break; case SUMMONHOMING: duration = effector .getGameStats() .getPositiveReverseStat(StatEnum.BOOST_CASTING_TIME_SUMMONHOMING, duration); break; case SUMMONTRAP: duration = effector .getGameStats() .getPositiveReverseStat(StatEnum.BOOST_CASTING_TIME_TRAP, duration); break; case HEAL: duration = effector .getGameStats() .getPositiveReverseStat(StatEnum.BOOST_CASTING_TIME_HEAL, duration); break; case ATTACK: if (skillTemplate.getType() == SkillType.MAGICAL) { duration = effector .getGameStats() .getPositiveReverseStat(StatEnum.BOOST_CASTING_TIME_ATTACK, duration); } break; } // 70% of base skill duration cap // No cast speed cap for skill Summoning Alacrity I(skillId: 1778) and Nimble Fingers I(skillId: // 2386) if (!effector.getEffectController().hasAbnormalEffect(1778) && !effector.getEffectController().hasAbnormalEffect(2386)) { int baseDurationCap = Math.round(skillTemplate.getDuration() * 0.3f); if (duration < baseDurationCap) { duration = baseDurationCap; } } if (effector instanceof Player) { if (this.isMulticast() && ((Player) effector) .getChainSkills() .getChainCount((Player) effector, this.getSkillTemplate(), this.chainCategory) != 0) { duration = 0; } } if (duration < 0) { duration = 0; } }
public boolean isGroundSkill() { return skillTemplate.isGroundSkill(); }