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 CAIPetDummy::ActionEngage() { DSP_DEBUG_BREAK_IF(m_PBattleTarget == nullptr); if (m_PPet->PMaster == nullptr || m_PPet->PMaster->isDead()) { m_ActionType = ACTION_FALL; ActionFall(); return; } if (battleutils::HasClaim(m_PPet, m_PBattleTarget)) { m_PPet->animation = ANIMATION_ATTACK; m_PPet->updatemask |= UPDATE_HP; m_LastActionTime = m_Tick - 1000; TransitionBack(true); } else { m_PPet->animation = ANIMATION_NONE; m_PPet->updatemask |= UPDATE_HP; if (m_PPet->PMaster->objtype == TYPE_PC) { ((CCharEntity*)m_PPet->PMaster)->pushPacket(new CMessageBasicPacket(((CCharEntity*)m_PPet->PMaster), ((CCharEntity*)m_PPet->PMaster), 0, 0, 12)); m_ActionType = ACTION_DISENGAGE; return; } } }
void CAIUltimateSummon::ActionAttack() { if (m_PPet->PMaster == NULL || m_PPet->PMaster->isDead() || m_PPet->isDead() || m_Tick > m_Timer + 10000){ m_ActionType = ACTION_FALL; ActionFall(); return; } //handle death of target if (m_PBattleTarget == NULL || m_PBattleTarget->isDead() || m_PBattleTarget->animation == ANIMATION_CHOCOBO) { m_ActionType = ACTION_ROAMING; ActionRoaming(); return; } m_PPathFind->LookAt(m_PBattleTarget->loc.p); if (m_Tick > m_LastActionTime) { m_ActionType = ACTION_MOBABILITY_START; } m_PPet->loc.zone->PushPacket(m_PPet, CHAR_INRANGE, new CEntityUpdatePacket(m_PPet, ENTITY_UPDATE)); }
void CAICharCharm::CheckCurrentAction(uint32 tick) { m_Tick = tick; CBattleEntity* PSelf = m_PChar; switch (m_ActionType) { case ACTION_NONE: ActionRoaming(); break; case ACTION_ROAMING: ActionRoaming(); break; case ACTION_ATTACK: ActionAttack(); break; case ACTION_ENGAGE: ActionEngage(); break; case ACTION_DISENGAGE: ActionDisengage(); break; case ACTION_FALL: ActionFall(); break; case ACTION_SLEEP: ActionSleep(); break; case ACTION_MAGIC_START: TransitionBack(true); break; case ACTION_RANGED_START: TransitionBack(true); break; case ACTION_ITEM_START: TransitionBack(true); break; case ACTION_CHANGE_TARGET: TransitionBack(true); break; case ACTION_WEAPONSKILL_START: TransitionBack(true); break; case ACTION_JOBABILITY_START: TransitionBack(true); break; case ACTION_RAISE_MENU_SELECTION: TransitionBack(true); break; default: DSP_DEBUG_BREAK_IF(true); } if (m_PChar && PSelf->PBattleAI == this) { m_PChar->UpdateEntity(); } }
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 CAIPetDummy::ActionRoaming() { if( m_PPet->PMaster==NULL || m_PPet->PMaster->isDead()){ m_ActionType = ACTION_FALL; ActionFall(); return; } //wyvern behaviour if(m_PPet->getPetType()==PETTYPE_WYVERN){ if(WyvernIsHealing()){ m_PPathFind->LookAt(m_PPet->PMaster->loc.p); m_PPet->loc.zone->PushPacket(m_PPet, CHAR_INRANGE, new CEntityUpdatePacket(m_PPet, ENTITY_UPDATE)); if(m_PPet->PMaster->objtype == TYPE_PC){ ((CCharEntity*)m_PPet->PMaster)->pushPacket(new CPetSyncPacket((CCharEntity*)m_PPet->PMaster)); } return; } } if(m_PBattleTarget!=NULL){ m_ActionType = ACTION_ENGAGE; ActionEngage(); return; } float currentDistance = distance(m_PPet->loc.p, m_PPet->PMaster->loc.p); // this is broken until pet / mob relationship gets fixed // pets need to extend mob or be a mob because pet has no spell list! if(m_PPet->getPetType() == PETTYPE_AVATAR && m_PPet->m_Family == 104 && m_Tick >= m_LastActionTime + 30000 && currentDistance < PET_ROAM_DISTANCE * 2) { int16 spellID = 108; // define this so action picks it up m_PSpell = spell::GetSpell(spellID); m_PBattleSubTarget = m_PPet->PMaster; m_ActionType = ACTION_MAGIC_START; ActionMagicStart(); return; } if (currentDistance > PET_ROAM_DISTANCE) { if(currentDistance < 35.0f && m_PPathFind->PathAround(m_PPet->PMaster->loc.p, 2.0f, PATHFLAG_RUN | PATHFLAG_WALLHACK)) { m_PPathFind->FollowPath(); } else { m_PPathFind->WarpTo(m_PPet->PMaster->loc.p, PET_ROAM_DISTANCE); } m_PPet->loc.zone->PushPacket(m_PPet, CHAR_INRANGE, new CEntityUpdatePacket(m_PPet, ENTITY_UPDATE)); } }
void CAIPetDummy::ActionSpawn() { if (m_PPet->PMaster == nullptr || m_PPet->PMaster->isDead()){ m_ActionType = ACTION_FALL; ActionFall(); return; } if (m_Tick > m_LastActionTime + 4000) { m_ActionType = ACTION_ROAMING; } }
void CAIUltimateSummon::ActionRoaming() { if (m_PPet->PMaster == NULL || m_PPet->PMaster->isDead() || m_Tick > m_Timer + 10000){ m_ActionType = ACTION_FALL; ActionFall(); return; } if (m_Tick > m_LastActionTime) { m_ActionType = ACTION_MOBABILITY_START; } }
void CAIUltimateSummon::ActionSpawn() { if( m_PPet->PMaster==NULL || m_PPet->PMaster->isDead()){ m_ActionType = ACTION_FALL; ActionFall(); return; } if (m_Tick > m_LastActionTime + 3500) { m_Timer = m_Tick; m_ActionType = ACTION_ROAMING; } }
void CAIPetDummy::ActionRoaming() { if (m_PPet->PMaster == nullptr || m_PPet->PMaster->isDead()){ m_ActionType = ACTION_FALL; ActionFall(); return; } //automaton, wyvern if (m_PPet->getPetType() == PETTYPE_WYVERN || m_PPet->getPetType() == PETTYPE_AUTOMATON){ if (PetIsHealing()){ return; } } if (m_PBattleTarget != nullptr){ m_ActionType = ACTION_ENGAGE; ActionEngage(); return; } float currentDistance = distance(m_PPet->loc.p, m_PPet->PMaster->loc.p); // this is broken until pet / mob relationship gets fixed // pets need to extend mob or be a mob because pet has no spell list! if (m_PPet->getPetType() == PETTYPE_AVATAR && m_PPet->m_Family == 104 && m_Tick >= m_LastActionTime + 30000 && currentDistance < PET_ROAM_DISTANCE * 2) { int16 spellID = 108; // define this so action picks it up SetCurrentSpell(spellID); m_PBattleSubTarget = m_PPet->PMaster; m_ActionType = ACTION_MAGIC_START; ActionMagicStart(); return; } if (currentDistance > PET_ROAM_DISTANCE) { if (currentDistance < 35.0f && m_PPathFind->PathAround(m_PPet->PMaster->loc.p, 2.0f, PATHFLAG_RUN | PATHFLAG_WALLHACK)) { m_PPathFind->FollowPath(); } else if (m_PPet->GetSpeed() > 0) { m_PPathFind->WarpTo(m_PPet->PMaster->loc.p, PET_ROAM_DISTANCE); } } }
void CAIPetDummy::ActionDisengage() { if( m_PPet->PMaster==NULL || m_PPet->PMaster->isDead()){ m_ActionType = ACTION_FALL; ActionFall(); return; } m_PPet->animation = ANIMATION_NONE; m_LastActionTime = m_Tick; m_PBattleTarget = NULL; TransitionBack(); m_PPet->loc.zone->PushPacket(m_PPet, CHAR_INRANGE, new CEntityUpdatePacket(m_PPet, ENTITY_UPDATE)); }
void CAIPetDummy::ActionDisengage() { if (m_PPet->PMaster == nullptr || m_PPet->PMaster->isDead()){ m_ActionType = ACTION_FALL; ActionFall(); return; } m_queueSic = false; m_PPet->animation = ANIMATION_NONE; m_PPet->updatemask |= UPDATE_HP; m_LastActionTime = m_Tick; m_PBattleTarget = nullptr; TransitionBack(); }
void CAIPetDummy::ActionRoaming() { if( m_PPet->PMaster==NULL || m_PPet->PMaster->isDead()){ m_ActionType = ACTION_FALL; ActionFall(); return; } //wyvern behaviour if(m_PPet->getPetType()==PETTYPE_WYVERN){ //see if master is engaged on something, if so, help attack if(m_PPet->PMaster->PBattleAI->GetBattleTarget()!=NULL){ m_PBattleTarget = m_PPet->PMaster->PBattleAI->GetBattleTarget(); } if(WyvernIsHealing()){ m_PPathFind->LookAt(m_PPet->PMaster->loc.p); m_PPet->loc.zone->PushPacket(m_PPet, CHAR_INRANGE, new CEntityUpdatePacket(m_PPet, ENTITY_UPDATE)); if(m_PPet->PMaster->objtype == TYPE_PC){ ((CCharEntity*)m_PPet->PMaster)->pushPacket(new CPetSyncPacket((CCharEntity*)m_PPet->PMaster)); } return; } } if(m_PBattleTarget!=NULL){ m_ActionType = ACTION_ENGAGE; ActionEngage(); return; } float currentDistance = distance(m_PPet->loc.p, m_PPet->PMaster->loc.p); if (currentDistance > PET_ROAM_DISTANCE) { if(currentDistance < 35.0f && m_PPathFind->PathAround(m_PPet->PMaster->loc.p, 2.0f, PATHFLAG_RUN | PATHFLAG_WALLHACK)) { m_PPathFind->FollowPath(); } else { m_PPathFind->WarpTo(m_PPet->PMaster->loc.p, PET_ROAM_DISTANCE); } m_PPet->loc.zone->PushPacket(m_PPet, CHAR_INRANGE, new CEntityUpdatePacket(m_PPet, ENTITY_UPDATE)); } }
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 CAIPetDummy::ActionEngage() { DSP_DEBUG_BREAK_IF(m_PBattleTarget == nullptr); if (m_PPet->PMaster == nullptr || m_PPet->PMaster->isDead()) { m_ActionType = ACTION_FALL; ActionFall(); return; } bool hasClaim = false; if (m_PBattleTarget->m_OwnerID.id == m_PPet->PMaster->id) hasClaim = true; if (m_PBattleTarget->m_OwnerID.id == 0) hasClaim = true; if (m_PPet->PMaster->PParty != nullptr) { // alliance if (m_PPet->PMaster->PParty->m_PAlliance != nullptr) { for (uint8 a = 0; a < m_PPet->PMaster->PParty->m_PAlliance->partyList.size(); ++a) { for (uint8 i = 0; i < m_PPet->PMaster->PParty->m_PAlliance->partyList.at(a)->members.size(); ++i) { if (m_PPet->PMaster->PParty->m_PAlliance->partyList.at(a)->members[i]->id == m_PBattleTarget->m_OwnerID.id) hasClaim = true; } } } else // party for (uint8 i = 0; i < m_PPet->PMaster->PParty->members.size(); ++i) { if (m_PPet->PMaster->PParty->members[i]->id == m_PBattleTarget->m_OwnerID.id) hasClaim = true; } } if (hasClaim) { m_PPet->animation = ANIMATION_ATTACK; m_PPet->updatemask |= UPDATE_HP; m_LastActionTime = m_Tick - 1000; TransitionBack(true); } else { m_PPet->animation = ANIMATION_NONE; m_PPet->updatemask |= UPDATE_HP; if (m_PPet->PMaster->objtype == TYPE_PC) { ((CCharEntity*)m_PPet->PMaster)->pushPacket(new CMessageBasicPacket(((CCharEntity*)m_PPet->PMaster), ((CCharEntity*)m_PPet->PMaster), 0, 0, 12)); m_ActionType = ACTION_DISENGAGE; return; } } }
void CAIUltimateSummon::ActionEngage() { DSP_DEBUG_BREAK_IF(m_PBattleTarget == NULL); if( m_PPet->PMaster==NULL || m_PPet->PMaster->isDead()) { m_ActionType = ACTION_FALL; ActionFall(); return; } bool hasClaim = false; if(m_PBattleTarget->m_OwnerID.id == m_PPet->PMaster->id) hasClaim = true; if(m_PBattleTarget->m_OwnerID.id == 0) hasClaim = true; if(m_PPet->PMaster->PParty != NULL) { // alliance if (m_PPet->PMaster->PParty->m_PAlliance != NULL) { for (uint8 a = 0; a < m_PPet->PMaster->PParty->m_PAlliance->partyList.size(); ++a) { for (uint8 i = 0; i < m_PPet->PMaster->PParty->m_PAlliance->partyList.at(a)->members.size(); ++i) { if (m_PPet->PMaster->PParty->m_PAlliance->partyList.at(a)->members[i]->id == m_PBattleTarget->m_OwnerID.id) hasClaim = true; } } } else // party for (uint8 i = 0; i < m_PPet->PMaster->PParty->members.size(); ++i) { if (m_PPet->PMaster->PParty->members[i]->id == m_PBattleTarget->m_OwnerID.id) hasClaim = true; } } if(hasClaim) { m_PPet->animation = ANIMATION_ATTACK; m_LastActionTime = m_Tick - 1000; TransitionBack(true); m_PPet->loc.zone->PushPacket(m_PPet,CHAR_INRANGE, new CEntityUpdatePacket(m_PPet, ENTITY_UPDATE)); } else { m_PPet->animation = ANIMATION_NONE; if(m_PPet->PMaster->objtype == TYPE_PC) { ((CCharEntity*)m_PPet->PMaster)->pushPacket(new CMessageBasicPacket(((CCharEntity*)m_PPet->PMaster), ((CCharEntity*)m_PPet->PMaster),0,0,12)); m_ActionType = ACTION_ROAMING; return; } } }
void CAIAutomatonDummy::ActionAttack() { if (m_PPet->PMaster == nullptr || m_PPet->PMaster->isDead() || m_PPet->isDead()){ m_ActionType = ACTION_FALL; ActionFall(); return; } //disengage a target that is dead or charmed if ((m_PBattleTarget == nullptr || m_PBattleTarget->isDead() || m_PBattleTarget->animation == ANIMATION_CHOCOBO) || (m_PBattleTarget != nullptr && m_PBattleTarget->objtype == TYPE_MOB && m_PBattleTarget->PMaster != nullptr && m_PBattleTarget->PMaster->objtype == TYPE_PC)) { m_ActionType = ACTION_DISENGAGE; ActionDisengage(); return; } m_PPathFind->LookAt(m_PBattleTarget->loc.p); float currentDistance = distance(m_PPet->loc.p, m_PBattleTarget->loc.p); if (CheckSpellcast()) { m_ActionType = ACTION_MAGIC_START; ActionMagicStart(); return; } else if (CheckTPMove()) { //TODO: check if automaton WS have activation times (don't think so) m_ActionType = ACTION_MOBABILITY_FINISH; ActionAbilityFinish(); return; } else if (CheckRangedAttack()) { //TODO: set ID to ranged attack m_ActionType = ACTION_MOBABILITY_FINISH; ActionAbilityFinish(); m_LastRangedTime = m_Tick; return; } //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 ((WELL512::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 = (WELL512::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()); } if (m_PPet->PMaster && m_PPet->PMaster->objtype == TYPE_PC) { puppetutils::TrySkillUP((CAutomatonEntity*)m_PPet, SKILL_AME, m_PBattleTarget->GetMLevel()); } bool isBlocked = (WELL512::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 CAIPetDummy::ActionAttack() { if( m_PPet->PMaster==NULL || 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 != NULL && m_PBattleTarget->objtype == TYPE_MOB && m_PBattleTarget->PMaster != NULL && 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()==NULL){ m_PBattleTarget = NULL; } //handle death of target if (m_PBattleTarget == NULL || m_PBattleTarget->isDead() || m_PBattleTarget->animation == ANIMATION_CHOCOBO) { m_ActionType = ACTION_DISENGAGE; ActionDisengage(); 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); } } // some reason this doesn't get set on engage? m_PPet->animation = ANIMATION_ATTACK; if(currentDistance <= m_PBattleTarget->m_ModelSize) { //try to attack if((m_Tick - m_LastActionTime) > m_PPet->m_Weapons[SLOT_MAIN]->getDelay()){ if (battleutils::IsParalised(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.flag = 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)); uint16 damage = 0; if (m_PBattleTarget->StatusEffectContainer->HasStatusEffect(EFFECT_PERFECT_DODGE)) { Action.messageID = 32; } else if ( rand()%100 < battleutils::GetHitRate(m_PPet, m_PBattleTarget) ) { if (battleutils::IsAbsorbByShadow(m_PBattleTarget)) { Action.messageID = 0; Action.reaction = REACTION_EVADE; 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; bool isCritical = ( rand()%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 = (uint16)((m_PPet->m_Weapons[SLOT_MAIN]->getDamage() + battleutils::GetFSTR(m_PPet, m_PBattleTarget,SLOT_MAIN)) * DamageRatio); } } if (m_PBattleTarget->objtype == TYPE_PC) { charutils::TrySkillUP((CCharEntity*)m_PBattleTarget, SKILL_EVA, m_PPet->GetMLevel()); } bool isBlocked = (rand()%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, NULL, true); // spike effect if (Action.reaction != REACTION_EVADE && Action.reaction != REACTION_PARRY) { 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 != NULL && m_PPet->PMaster->objtype == TYPE_PC && m_PPet->PMaster->PPet != NULL){ ((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(); } } m_PPet->loc.zone->PushPacket(m_PPet, CHAR_INRANGE, new CEntityUpdatePacket(m_PPet, ENTITY_UPDATE)); }