CAbilityState::CAbilityState(CBattleEntity* PEntity, uint16 targid, uint16 abilityid) : CState(PEntity, targid), m_PEntity(PEntity) { CAbility* PAbility = ability::GetAbility(abilityid); if (!PAbility) { throw CStateInitException(std::make_unique<CMessageBasicPacket>(m_PEntity, m_PEntity, 0, 0, MSGBASIC_UNABLE_TO_USE_JA)); } auto PTarget = m_PEntity->IsValidTarget(m_targid, PAbility->getValidTarget(), m_errorMsg); if (!PTarget || m_errorMsg) { throw CStateInitException(std::move(m_errorMsg)); } SetTarget(PTarget->targid); m_PAbility = std::make_unique<CAbility>(*PAbility); m_castTime = PAbility->getCastTime(); if (m_castTime > 0s) { action_t action; action.id = PEntity->id; action.actiontype = ACTION_WEAPONSKILL_START; auto& list = action.getNewActionList(); list.ActionTargetID = PTarget->id; auto& actionTarget = list.getNewActionTarget(); actionTarget.reaction = (REACTION)24; actionTarget.animation = 121; actionTarget.messageID = 326; actionTarget.param = PAbility->getID() + 16; PEntity->loc.zone->PushPacket(PEntity, CHAR_INRANGE_SELF, new CActionPacket(action)); } m_PEntity->PAI->EventHandler.triggerListener("ABILITY_START", m_PEntity, PAbility); }
CMagicState::CMagicState(CBattleEntity* PEntity, uint16 targid, uint16 spellid, uint8 flags) : CState(PEntity, targid), m_PEntity(PEntity), m_PSpell(nullptr) { CSpell* PSpell = spell::GetSpell(spellid); m_PSpell = PSpell->clone(); if (!m_PSpell) { throw CStateInitException(std::make_unique<CMessageBasicPacket>(m_PEntity, m_PEntity, m_PSpell->getID(), 0, MSGBASIC_CANNOT_CAST_SPELL)); } auto PTarget = m_PEntity->IsValidTarget(m_targid, m_PSpell->getValidTarget(), m_errorMsg); if (!PTarget || m_errorMsg) { throw CStateInitException(std::move(m_errorMsg)); } if (!CanCastSpell(PTarget)) { throw CStateInitException(std::move(m_errorMsg)); } auto errorMsg = luautils::OnMagicCastingCheck(m_PEntity, PTarget, GetSpell()); if (errorMsg) { throw CStateInitException(std::make_unique<CMessageBasicPacket>(m_PEntity, PTarget, m_PSpell->getID(), 0, errorMsg == 1 ? MSGBASIC_CANNOT_CAST_SPELL : errorMsg)); } m_flags = flags; m_castTime = std::chrono::milliseconds(battleutils::CalculateSpellCastTime(m_PEntity, GetSpell())); m_startPos = m_PEntity->loc.p; action_t action; action.id = m_PEntity->id; action.spellgroup = m_PSpell->getSpellGroup(); action.actiontype = ACTION_MAGIC_START; actionList_t& actionList = action.getNewActionList(); actionList.ActionTargetID = PTarget->id; actionTarget_t& actionTarget = actionList.getNewActionTarget(); actionTarget.reaction = REACTION_NONE; actionTarget.speceffect = SPECEFFECT_NONE; actionTarget.animation = 0; actionTarget.param = m_PSpell->getID(); actionTarget.messageID = 327; // starts casting m_PEntity->PAI->EventHandler.triggerListener("MAGIC_START", m_PEntity, m_PSpell.get(), &action); //TODO: weaponskill lua object m_PEntity->loc.zone->PushPacket(m_PEntity, CHAR_INRANGE_SELF, new CActionPacket(action)); }
CMobSkillState::CMobSkillState(CMobEntity* PEntity, uint16 targid, uint16 wsid) : CState(PEntity, targid), m_PEntity(PEntity) { auto skill = battleutils::GetMobSkill(wsid); if (!skill) { throw CStateInitException(nullptr); } if (m_PEntity->StatusEffectContainer->HasStatusEffect({EFFECT_AMNESIA, EFFECT_IMPAIRMENT})) { throw CStateInitException(nullptr); } auto PTarget = m_PEntity->IsValidTarget(m_targid, skill->getValidTargets(), m_errorMsg); if (!PTarget || m_errorMsg) { throw CStateInitException(std::move(m_errorMsg)); } m_PSkill = std::make_unique<CMobSkill>(*skill); m_castTime = std::chrono::milliseconds(m_PSkill->getActivationTime()); if (m_castTime > 0s) { action_t action; action.id = m_PEntity->id; action.actiontype = ACTION_MOBABILITY_START; actionList_t& actionList = action.getNewActionList(); actionList.ActionTargetID = PTarget->id; actionTarget_t& actionTarget = actionList.getNewActionTarget(); actionTarget.reaction = REACTION_NONE; actionTarget.speceffect = SPECEFFECT_NONE; actionTarget.animation = 0; actionTarget.param = m_PSkill->getID(); actionTarget.messageID = 43; m_PEntity->loc.zone->PushPacket(m_PEntity, CHAR_INRANGE, new CActionPacket(action)); } m_PEntity->PAI->EventHandler.triggerListener("WEAPONSKILL_STATE_ENTER", m_PEntity, m_PSkill->getID()); SpendCost(); }
CRangeState::CRangeState(CCharEntity* PEntity, uint16 targid) : CState(PEntity, targid), m_PEntity(PEntity) { auto PTarget = m_PEntity->IsValidTarget(m_targid, TARGET_ENEMY, m_errorMsg); if (!PTarget || m_errorMsg) { throw CStateInitException(std::move(m_errorMsg)); } if (!CanUseRangedAttack(PTarget)) { throw CStateInitException(std::move(m_errorMsg)); } auto delay = m_PEntity->GetRangedWeaponDelay(false); delay = battleutils::GetSnapshotReduction(m_PEntity, delay); if (charutils::hasTrait(m_PEntity, TRAIT_RAPID_SHOT)) { auto chance {m_PEntity->getMod(Mod::RAPID_SHOT) + m_PEntity->PMeritPoints->GetMeritValue(MERIT_RAPID_SHOT_RATE, m_PEntity)}; if (dsprand::GetRandomNumber(100) < chance) { //reduce delay by 10%-50% delay = delay * (10 - dsprand::GetRandomNumber(1, 6)) / 10.f; m_rapidShot = true; } } m_aimTime = std::chrono::milliseconds(delay); m_startPos = m_PEntity->loc.p; action_t action; action.id = m_PEntity->id; action.actiontype = ACTION_RANGED_START; actionList_t& actionList = action.getNewActionList(); actionList.ActionTargetID = PTarget->id; actionTarget_t& actionTarget = actionList.getNewActionTarget(); actionTarget.animation = ANIMATION_RANGED; m_PEntity->PAI->EventHandler.triggerListener("RANGE_START", m_PEntity, &action); m_PEntity->loc.zone->PushPacket(m_PEntity, CHAR_INRANGE_SELF, new CActionPacket(action)); }
CWeaponSkillState::CWeaponSkillState(CBattleEntity* PEntity, uint16 targid, uint16 wsid) : CState(PEntity, targid), m_PEntity(PEntity) { auto skill = battleutils::GetWeaponSkill(wsid); if (!skill) { throw CStateInitException(std::make_unique<CMessageBasicPacket>(PEntity, PEntity, 0, 0, MSGBASIC_CANNOT_USE_WS)); } auto target_flags = battleutils::isValidSelfTargetWeaponskill(wsid) ? TARGET_SELF : TARGET_ENEMY; auto PTarget = m_PEntity->IsValidTarget(m_targid, target_flags, m_errorMsg); if (!PTarget || m_errorMsg) { throw CStateInitException(std::move(m_errorMsg)); } if (!m_PEntity->PAI->TargetFind->canSee(&PTarget->loc.p)) { throw CStateInitException(std::make_unique<CMessageBasicPacket>(m_PEntity, PTarget, 0, 0, MSGBASIC_CANNOT_PERFORM_ACTION)); } m_PSkill = std::make_unique<CWeaponSkill>(*skill); //m_castTime = std::chrono::milliseconds(m_PSkill->getActivationTime()); action_t action; action.id = m_PEntity->id; action.actiontype = ACTION_WEAPONSKILL_START; actionList_t& actionList = action.getNewActionList(); actionList.ActionTargetID = PTarget->id; actionTarget_t& actionTarget = actionList.getNewActionTarget(); actionTarget.reaction = REACTION_NONE; actionTarget.speceffect = SPECEFFECT_NONE; actionTarget.animation = 0; actionTarget.param = m_PSkill->getID(); actionTarget.messageID = 43; m_PEntity->loc.zone->PushPacket(m_PEntity, CHAR_INRANGE_SELF, new CActionPacket(action)); }
CAttackState::CAttackState(CBattleEntity* PEntity, uint16 targid) : CState(PEntity, targid), m_PEntity(PEntity) { PEntity->SetBattleTargetID(targid); PEntity->SetBattleStartTime(server_clock::now()); UpdateTarget(); if (!GetTarget() || m_errorMsg) { PEntity->SetBattleTargetID(0); throw CStateInitException(std::move(m_errorMsg)); } if (PEntity->PAI->PathFind) { PEntity->PAI->PathFind->Clear(); } }
CItemState::CItemState(CCharEntity* PEntity, uint16 targid, uint8 loc, uint8 slotid) : CState(PEntity, targid), m_PEntity(PEntity), m_location(loc), m_slot(slotid), m_PItem(nullptr) { auto PItem = dynamic_cast<CItemUsable*>(m_PEntity->getStorage(loc)->GetItem(slotid)); m_PItem = PItem; if (m_PItem && m_PItem->isType(ITEM_USABLE)) { if (m_PItem->isType(ITEM_ARMOR)) { // check if this item is equipped bool found = false; for (auto equipslot = 0; equipslot < 18; ++equipslot) { if (m_PEntity->getEquip((SLOTTYPE)equipslot) == m_PItem && m_PItem->getCurrentCharges() > 0) { found = true; break; } } if (!found) m_PItem = nullptr; } else if (m_PItem->isSubType(ITEM_LOCKED)) { m_PItem = nullptr; } } if (!m_PItem) { throw CStateInitException(std::make_unique<CMessageBasicPacket>(m_PEntity, m_PEntity, 0, 0, 56)); } auto PTarget = m_PEntity->IsValidTarget(targid, m_PItem->getValidTarget(), m_errorMsg); auto error = luautils::OnItemCheck(PTarget, m_PItem); if (!PTarget || m_errorMsg) { throw CStateInitException(std::move(m_errorMsg)); } if (error || m_PEntity->StatusEffectContainer->HasPreventActionEffect()) { auto param = m_PItem->getFlag() & ITEM_FLAG_SCROLL ? m_PItem->getSubID() : m_PItem->getID(); throw CStateInitException(std::make_unique<CMessageBasicPacket>(m_PEntity, m_PEntity, param, 0, error == -1 ? 56 : error)); } m_PEntity->UContainer->SetType(UCONTAINER_USEITEM); m_PEntity->UContainer->SetItem(0, m_PItem); UpdateTarget(m_targid); m_startPos = m_PEntity->loc.p; m_castTime = std::chrono::milliseconds(m_PItem->getActivationTime()); m_animationTime = std::chrono::milliseconds(PItem->getAnimationTime()); action_t action; action.id = m_PEntity->id; action.actiontype = ACTION_ITEM_START; actionList_t& actionList = action.getNewActionList(); actionList.ActionTargetID = PTarget->id; actionTarget_t& actionTarget = actionList.getNewActionTarget(); actionTarget.reaction = REACTION_NONE; actionTarget.speceffect = SPECEFFECT_NONE; actionTarget.animation = 0; actionTarget.param = m_PItem->getID(); actionTarget.messageID = 28; actionTarget.knockback = 0; m_PEntity->PAI->EventHandler.triggerListener("ITEM_START", PTarget, m_PItem, &action); m_PEntity->loc.zone->PushPacket(m_PEntity, CHAR_INRANGE_SELF, new CActionPacket(action)); m_PItem->setSubType(ITEM_LOCKED); m_PEntity->pushPacket(new CInventoryAssignPacket(m_PItem, INV_NOSELECT)); m_PEntity->pushPacket(new CInventoryFinishPacket()); }