void CAIPetDummy::CheckCurrentAction(uint32 tick) { m_Tick = tick; //uncharm any pets if time is up if(tick > m_PPet->charmTime && m_PPet->isCharmed) { petutils::DespawnPet(m_PPet->PMaster); return; } switch(m_ActionType) { case ACTION_NONE: break; case ACTION_ROAMING: ActionRoaming(); break; case ACTION_DEATH: ActionDeath(); break; case ACTION_SPAWN: ActionSpawn(); break; case ACTION_FALL: ActionFall(); break; case ACTION_ENGAGE: ActionEngage(); break; case ACTION_ATTACK: ActionAttack(); break; case ACTION_SLEEP: ActionSleep(); break; case ACTION_DISENGAGE: ActionDisengage(); break; case ACTION_MOBABILITY_START: ActionAbilityStart(); break; case ACTION_MOBABILITY_USING: ActionAbilityUsing(); break; case ACTION_MOBABILITY_FINISH: ActionAbilityFinish(); break; case ACTION_MOBABILITY_INTERRUPT: ActionAbilityInterrupt(); break; case ACTION_MAGIC_START: ActionMagicStart(); break; case ACTION_MAGIC_CASTING: ActionMagicCasting(); break; case ACTION_MAGIC_FINISH: ActionMagicFinish(); break; default : DSP_DEBUG_BREAK_IF(true); } }
void CAIAutomatonDummy::CheckCurrentAction(uint32 tick) { m_Tick = tick; CBattleEntity* PSelf = m_PPet; switch (m_ActionType) { case ACTION_NONE: break; case ACTION_ROAMING: ActionRoaming(); break; case ACTION_DEATH: ActionDeath(); break; case ACTION_SPAWN: ActionSpawn(); break; case ACTION_FALL: ActionFall(); break; case ACTION_ENGAGE: ActionEngage(); break; case ACTION_ATTACK: ActionAttack(); break; case ACTION_SLEEP: ActionSleep(); break; case ACTION_DISENGAGE: ActionDisengage(); break; case ACTION_MOBABILITY_START: ActionAbilityStart(); break; case ACTION_MOBABILITY_USING: ActionAbilityUsing(); break; case ACTION_MOBABILITY_FINISH: ActionAbilityFinish(); break; case ACTION_MOBABILITY_INTERRUPT: ActionAbilityInterrupt(); break; case ACTION_MAGIC_START: ActionMagicStart(); break; case ACTION_MAGIC_CASTING: ActionMagicCasting(); break; case ACTION_MAGIC_FINISH: ActionMagicFinish(); break; default: DSP_DEBUG_BREAK_IF(true); } //check if this AI was replaced (the new AI will update if this is the case) if (m_PPet && PSelf->PBattleAI == this) { m_PPet->UpdateEntity(); } }
void CAIUltimateSummon::CheckCurrentAction(uint32 tick) { m_Tick = tick; switch(m_ActionType) { case ACTION_NONE: break; case ACTION_ROAMING: ActionRoaming(); break; case ACTION_DEATH: ActionDeath(); break; case ACTION_SPAWN: ActionSpawn(); break; case ACTION_FALL: ActionFall(); break; case ACTION_ENGAGE: ActionEngage(); break; case ACTION_ATTACK: ActionAttack(); break; case ACTION_SLEEP: ActionSleep(); break; case ACTION_MOBABILITY_START: ActionAbilityStart(); break; case ACTION_MOBABILITY_USING: ActionAbilityUsing(); break; case ACTION_MOBABILITY_FINISH: ActionAbilityFinish(); break; case ACTION_MOBABILITY_INTERRUPT: ActionAbilityInterrupt(); break; default : DSP_DEBUG_BREAK_IF(true); } }
void CAIMobDummy::CheckCurrentAction(uint32 tick) { m_Tick = tick; switch(m_ActionType) { case ACTION_NONE: break; case ACTION_ROAMING: ActionRoaming(); break; case ACTION_ENGAGE: ActionEngage(); break; case ACTION_DISENGAGE: ActionDisengage(); break; case ACTION_FALL: ActionFall(); break; case ACTION_DROPITEMS: ActionDropItems(); break; case ACTION_DEATH: ActionDeath(); break; case ACTION_FADE_OUT: ActionFadeOut(); break; case ACTION_SPAWN: ActionSpawn(); break; case ACTION_ATTACK: ActionAttack(); break; case ACTION_MOBABILITY_START: ActionAbilityStart(); break; case ACTION_MOBABILITY_FINISH: ActionAbilityFinish(); break; case ACTION_MOBABILITY_INTERRUPT: ActionAbilityInterrupt(); break; default : DSP_DEBUG_BREAK_IF(true); } }
void CAIPetDummy::ActionAttack() { if (m_PPet->PMaster == nullptr || m_PPet->PMaster->isDead() || m_PPet->isDead()){ m_ActionType = ACTION_FALL; ActionFall(); return; } //if 2 bsts are in party, make sure their pets cannot fight eachother if (m_PBattleTarget != nullptr && m_PBattleTarget->objtype == TYPE_MOB && m_PBattleTarget->PMaster != nullptr && m_PBattleTarget->PMaster->objtype == TYPE_PC) { m_ActionType = ACTION_DISENGAGE; ActionDisengage(); return; } //wyvern behaviour if (m_PPet->getPetType() == PETTYPE_WYVERN && m_PPet->PMaster->PBattleAI->GetBattleTarget() == nullptr){ m_PBattleTarget = nullptr; } //handle death of target if (m_PBattleTarget == nullptr || m_PBattleTarget->isDead() || m_PBattleTarget->animation == ANIMATION_CHOCOBO) { m_ActionType = ACTION_DISENGAGE; ActionDisengage(); return; } if (m_queueSic && m_PPet->health.tp >= 1000) { // now use my tp move m_queueSic = false; m_MasterCommand = MASTERCOMMAND_SIC; m_ActionType = ACTION_MOBABILITY_START; ActionAbilityStart(); return; } m_PPathFind->LookAt(m_PBattleTarget->loc.p); float currentDistance = distance(m_PPet->loc.p, m_PBattleTarget->loc.p); //go to target if its too far away if (currentDistance > m_PBattleTarget->m_ModelSize && m_PPet->speed != 0) { if (m_PPathFind->PathAround(m_PBattleTarget->loc.p, 2.0f, PATHFLAG_RUN | PATHFLAG_WALLHACK)) { m_PPathFind->FollowPath(); // recalculate currentDistance = distance(m_PPet->loc.p, m_PBattleTarget->loc.p); } } if (currentDistance <= m_PBattleTarget->m_ModelSize) { int32 WeaponDelay = m_PPet->m_Weapons[SLOT_MAIN]->getDelay(); //try to attack if (m_Tick > m_LastActionTime + WeaponDelay){ if (battleutils::IsParalyzed(m_PPet)) { m_PPet->loc.zone->PushPacket(m_PPet, CHAR_INRANGE, new CMessageBasicPacket(m_PPet, m_PBattleTarget, 0, 0, 29)); } else if (battleutils::IsIntimidated(m_PPet, m_PBattleTarget)) { m_PPet->loc.zone->PushPacket(m_PPet, CHAR_INRANGE, new CMessageBasicPacket(m_PPet, m_PBattleTarget, 0, 0, 106)); } else { apAction_t Action; m_PPet->m_ActionList.clear(); Action.ActionTarget = m_PBattleTarget; uint8 numAttacks = battleutils::CheckMultiHits(m_PPet, m_PPet->m_Weapons[SLOT_MAIN]); for (uint8 i = 0; i < numAttacks; i++){ Action.reaction = REACTION_EVADE; Action.speceffect = SPECEFFECT_NONE; Action.animation = 0; Action.param = 0; Action.messageID = 15; Action.knockback = 0; //ShowDebug("pet hp %i and atk %i def %i eva is %i \n",m_PPet->health.hp,m_PPet->ATT(),m_PPet->DEF(),m_PPet->getMod(MOD_EVA)); int32 damage = 0; if (m_PBattleTarget->StatusEffectContainer->HasStatusEffect(EFFECT_PERFECT_DODGE)) { Action.messageID = 32; } else if ((dsprand::GetRandomNumber(100) < battleutils::GetHitRate(m_PPet, m_PBattleTarget)) && !m_PBattleTarget->StatusEffectContainer->HasStatusEffect(EFFECT_ALL_MISS)) { if (battleutils::IsAbsorbByShadow(m_PBattleTarget)) { Action.messageID = 31; Action.param = 1; Action.reaction = REACTION_EVADE; } else { Action.reaction = REACTION_HIT; Action.speceffect = SPECEFFECT_HIT; Action.messageID = 1; bool isCritical = (dsprand::GetRandomNumber(100) < battleutils::GetCritHitRate(m_PPet, m_PBattleTarget, false)); float DamageRatio = battleutils::GetDamageRatio(m_PPet, m_PBattleTarget, isCritical, 0); if (isCritical) { Action.speceffect = SPECEFFECT_CRITICAL_HIT; Action.messageID = 67; } damage = (int32)((m_PPet->GetMainWeaponDmg() + battleutils::GetFSTR(m_PPet, m_PBattleTarget, SLOT_MAIN)) * DamageRatio); } } else { // create enmity even on misses if (m_PBattleTarget->objtype == TYPE_MOB){ CMobEntity* PMob = (CMobEntity*)m_PBattleTarget; PMob->PEnmityContainer->UpdateEnmity(m_PPet, 0, 0); } } if (m_PBattleTarget->objtype == TYPE_PC) { charutils::TrySkillUP((CCharEntity*)m_PBattleTarget, SKILL_EVA, m_PPet->GetMLevel()); } bool isBlocked = (dsprand::GetRandomNumber(100) < battleutils::GetBlockRate(m_PPet, m_PBattleTarget)); if (isBlocked){ Action.reaction = REACTION_BLOCK; } Action.param = battleutils::TakePhysicalDamage(m_PPet, m_PBattleTarget, damage, isBlocked, SLOT_MAIN, 1, nullptr, true, true); if (Action.param < 0) { Action.param = -(Action.param); Action.messageID = 373; } // spike effect if (Action.reaction != REACTION_EVADE && Action.reaction != REACTION_PARRY) { battleutils::HandleEnspell(m_PPet, m_PBattleTarget, &Action, i, m_PPet->m_Weapons[SLOT_MAIN], damage); battleutils::HandleSpikesDamage(m_PPet, m_PBattleTarget, &Action, damage); } m_PPet->m_ActionList.push_back(Action); } m_PPet->loc.zone->PushPacket(m_PPet, CHAR_INRANGE, new CActionPacket(m_PPet)); if (m_PPet->PMaster != nullptr && m_PPet->PMaster->objtype == TYPE_PC && m_PPet->PMaster->PPet != nullptr){ ((CCharEntity*)m_PPet->PMaster)->pushPacket(new CPetSyncPacket((CCharEntity*)m_PPet->PMaster)); } } m_LastActionTime = m_Tick; // Update the targets attacker level.. CMobEntity* Monster = (CMobEntity*)m_PBattleTarget; if (Monster->m_HiPCLvl < ((CCharEntity*)m_PPet->PMaster)->GetMLevel()) Monster->m_HiPCLvl = ((CCharEntity*)m_PPet->PMaster)->GetMLevel(); } } }
void CAIMobDummy::ActionAttack() { m_PBattleTarget = m_PMob->PEnmityContainer->GetHighestEnmity(); if (m_PBattleTarget == NULL) { m_ActionType = ACTION_DISENGAGE; return; } if (m_PBattleTarget->isDead()) { if (m_PMob->m_OwnerID == m_PBattleTarget->id) { m_PMob->m_OwnerID = 0; } m_PMob->PEnmityContainer->Clear(m_PBattleTarget->id); ActionAttack(); return; } m_PMob->loc.p.rotation = getangle(m_PMob->loc.p, m_PBattleTarget->loc.p); if (m_PMob->PParty != NULL) { for (uint16 i = 0; i < m_PMob->PParty->members.size(); ++i) { CMobEntity* PPartyMember = (CMobEntity*)m_PMob->PParty->members[i]; if (PPartyMember->PBattleAI->GetCurrentAction() == ACTION_ROAMING && distance(m_PMob->loc.p, PPartyMember->loc.p) < 10) { PPartyMember->PEnmityContainer->AddBaseEnmity(m_PBattleTarget); } } } if (distance(m_PMob->loc.p, m_PBattleTarget->loc.p) <= m_PMob->m_ModelSize) { if ((m_Tick - m_LastActionTime) > m_PMob->m_Weapons[SLOT_MAIN]->getDelay()) { if (battleutils::IsParalised(m_PMob)) { m_PMob->loc.zone->PushPacket(m_PMob, CHAR_INRANGE, new CMessageBasicPacket(m_PMob,m_PBattleTarget,0,0,29)); } else if (battleutils::IsIntimidated(m_PMob, m_PBattleTarget)) { m_PMob->loc.zone->PushPacket(m_PMob, CHAR_INRANGE, new CMessageBasicPacket(m_PMob,m_PBattleTarget,0,0,106)); } else { if (m_PMob->health.tp > 100 && rand()%100 > 55) { m_ActionType = ACTION_MOBABILITY_START; ActionAbilityStart(); return; } apAction_t Action; m_PMob->m_ActionList.clear(); Action.ActionTarget = m_PBattleTarget; Action.reaction = REACTION_EVADE; Action.speceffect = SPECEFFECT_NONE; Action.animation = 0; Action.param = 0; Action.messageID = 15; Action.flag = 0; uint16 damage = 0; if (m_PBattleTarget->StatusEffectContainer->HasStatusEffect(EFFECT_PERFECT_DODGE)) { Action.messageID = 32; } else if ( rand()%90 < battleutils::GetHitRate(m_PMob, m_PBattleTarget) ) { if (battleutils::IsAbsorbByShadow(m_PBattleTarget)) { Action.messageID = 0; m_PBattleTarget->loc.zone->PushPacket(m_PBattleTarget,CHAR_INRANGE_SELF, new CMessageBasicPacket(m_PBattleTarget,m_PBattleTarget,0,1,31)); } else { Action.reaction = REACTION_HIT; Action.speceffect = SPECEFFECT_HIT; Action.messageID = 1; float DamageRatio = battleutils::GetDamageRatio(m_PMob, m_PBattleTarget); if ( rand()%100 < battleutils::GetCritHitRate(m_PMob, m_PBattleTarget) ) { DamageRatio += 1; DamageRatio = (DamageRatio > 3 ? 3 : DamageRatio); Action.speceffect = SPECEFFECT_CRITICAL_HIT; Action.messageID = 67; } damage = (uint16)((m_PMob->m_Weapons[SLOT_MAIN]->getDamage() + battleutils::GetFSTR(m_PMob, m_PBattleTarget)) * DamageRatio); } } else if (m_PBattleTarget->objtype == TYPE_PC) { charutils::TrySkillUP((CCharEntity*)m_PBattleTarget, SKILL_EVA, m_PMob->GetMLevel()); } Action.param = battleutils::TakePhysicalDamage(m_PMob, m_PBattleTarget, damage); m_PMob->m_ActionList.push_back(Action); m_PMob->PEnmityContainer->UpdateEnmityFromAttack(m_PBattleTarget, Action.param); m_PMob->loc.zone->PushPacket(m_PMob, CHAR_INRANGE, new CActionPacket(m_PMob)); } m_LastActionTime = m_Tick; } } else { battleutils::MoveTo(m_PMob, m_PBattleTarget->loc.p, 2); } m_PMob->loc.zone->PushPacket(m_PMob,CHAR_INRANGE, new CEntityUpdatePacket(m_PMob, ENTITY_UPDATE)); }