CBattleEntity* CTargetFind::getValidTarget(uint16 actionTargetID, uint8 validTargetFlags) { DSP_DEBUG_BREAK_IF(actionTargetID == 0); CBattleEntity* PTarget = (CBattleEntity*)m_PBattleEntity->loc.zone->GetEntity(actionTargetID, TYPE_MOB | TYPE_PC | TYPE_PET); if (PTarget == NULL) { return NULL; } if (validTargetFlags & TARGET_ENEMY) { if (!PTarget->isDead()) { if (PTarget->objtype == TYPE_MOB || (PTarget->objtype == TYPE_PC && ((CCharEntity*)PTarget)->m_PVPFlag)) { return PTarget; } } } if (PTarget->objtype == TYPE_PC) { if ((validTargetFlags & TARGET_SELF) && PTarget->targid == m_PBattleEntity->targid) { return PTarget; } if (validTargetFlags & TARGET_PLAYER) { return PTarget; } if ((validTargetFlags & TARGET_PLAYER_PARTY) && (m_PBattleEntity->PParty != NULL && m_PBattleEntity->PParty == PTarget->PParty)) { return PTarget; } if ((validTargetFlags & TARGET_PLAYER_PARTY_PIANISSIMO) && (m_PBattleEntity->StatusEffectContainer->HasStatusEffect(EFFECT_PIANISSIMO)) && (m_PBattleEntity->PParty != NULL && m_PBattleEntity->PParty == PTarget->PParty)) { return PTarget; } if ((validTargetFlags & TARGET_PLAYER_DEAD) && PTarget->isDead()) { return PTarget; } return NULL; } return NULL; }
uint8 CEnmityContainer::GetHighestTH() { CBattleEntity* PEntity = nullptr; uint8 THLvl = 0; for (auto it = m_EnmityList.cbegin(); it != m_EnmityList.cend(); ++it) { const EnmityObject_t& PEnmityObject = it->second; PEntity = PEnmityObject.PEnmityOwner; if (PEntity != nullptr && !PEntity->isDead() && IsWithinEnmityRange(PEntity) && PEnmityObject.maxTH > THLvl) THLvl = PEnmityObject.maxTH; } return THLvl; }
uint8 CEnmityContainer::GetHighestTH() { CBattleEntity* PEntity = nullptr; uint8 THLvl = 0; for (EnmityList_t::iterator it = m_EnmityList.begin(); it != m_EnmityList.end(); ++it) { EnmityObject_t* PEnmityObject = it->second; PEntity = PEnmityObject->PEnmityOwner; if (PEntity != nullptr && !PEntity->isDead() && IsWithinEnmityRange(PEntity) && PEnmityObject->maxTH > THLvl) THLvl = PEnmityObject->maxTH; } return THLvl; }
CBattleEntity* CTargetFind::getValidTarget(uint16 actionTargetID, uint8 validTargetFlags) { CBattleEntity* PTarget = (CBattleEntity*)m_PBattleEntity->GetEntity(actionTargetID, TYPE_MOB | TYPE_PC | TYPE_PET); if (PTarget == nullptr) { return nullptr; } if (PTarget->ValidTarget(m_PBattleEntity, validTargetFlags)) { return PTarget; } return nullptr; }
CBattleEntity* CEnmityContainer::GetHighestEnmity() { if (m_EnmityList.empty()) { return nullptr; } uint32 HighestEnmity = 0; auto highest = m_EnmityList.end(); bool active = false; for (auto it = m_EnmityList.begin(); it != m_EnmityList.end(); ++it) { const EnmityObject_t& PEnmityObject = it->second; uint32 Enmity = PEnmityObject.CE + PEnmityObject.VE; if (Enmity >= HighestEnmity && ((PEnmityObject.active == active) || (PEnmityObject.active && !active))) { auto POwner = PEnmityObject.PEnmityOwner; if (!POwner || (POwner->allegiance != m_EnmityHolder->allegiance)) { active = PEnmityObject.active; HighestEnmity = Enmity; highest = it; } } } CBattleEntity* PEntity = nullptr; if (highest != m_EnmityList.end()) { PEntity = highest->second.PEnmityOwner; if (!PEntity) { PEntity = zoneutils::GetChar(highest->first); } if (!PEntity || PEntity->getZone() != m_EnmityHolder->getZone() || PEntity->PInstance != m_EnmityHolder->PInstance) { m_EnmityList.erase(highest); PEntity = GetHighestEnmity(); } } return PEntity; }
CPartyDefinePacket::CPartyDefinePacket(CParty* PParty) { this->type = 0xC8; this->size = 0x7C; //party is an alliance do the double loop if (PParty != NULL) { if (PParty->m_PAlliance!= NULL) { uint8 offset = 0; for (uint8 a = 0; a < PParty->m_PAlliance->partyList.size(); ++a) { for (uint8 i = 0; i < PParty->m_PAlliance->partyList.at(a)->members.size(); ++i) { CBattleEntity* PChar = PParty->m_PAlliance->partyList.at(a)->members.at(i); WBUFL(data,12*offset+(0x08)-4) = PChar->id; WBUFW(data,12*offset+(0x0C)-4) = PChar->targid; WBUFW(data,12*offset+(0x0E)-4) = PChar->PParty->GetMemberFlags(PChar); WBUFW(data,12*offset+(0x10)-4) = PChar->getZone(); offset++; } } } else //regular party { DSP_DEBUG_BREAK_IF(PParty->members.size() > 6); for (uint8 i = 0; i < PParty->members.size(); ++i) { CBattleEntity* PChar = PParty->members.at(i); WBUFL(data,12*i+(0x08)-4) = PChar->id; WBUFW(data,12*i+(0x0C)-4) = PChar->targid; WBUFW(data,12*i+(0x0E)-4) = PChar->PParty->GetMemberFlags(PChar); WBUFW(data,12*i+(0x10)-4) = PChar->getZone(); } } } }
void CAIPetDummy::ActionAbilityStart() { if (m_PPet->StatusEffectContainer->HasPreventActionEffect()) { return; } if (m_PPet->objtype == TYPE_MOB && m_PPet->PMaster->objtype == TYPE_PC) { if (m_MasterCommand == MASTERCOMMAND_SIC && m_PPet->health.tp >= 1000 && m_PBattleTarget != nullptr) { m_MasterCommand = MASTERCOMMAND_NONE; CMobEntity* PMob = (CMobEntity*)m_PPet->PMaster->PPet; std::vector<CMobSkill*> MobSkills = battleutils::GetMobSkillsByFamily(PMob->m_Family); if (MobSkills.size() > 0) { int maxSearch = 10; // keep looking for an ability until one is valid do { SetCurrentMobSkill(MobSkills.at(dsprand::GetRandomNumber(MobSkills.size()))); } while (luautils::OnMobSkillCheck(m_PBattleTarget, m_PPet, GetCurrentMobSkill()) != 0 && maxSearch--); // could not find skill if (maxSearch == 0) { TransitionBack(true); return; } preparePetAbility(m_PBattleTarget); return; } return; } } if (m_PPet->getPetType() == PETTYPE_JUG_PET){ if (m_MasterCommand == MASTERCOMMAND_SIC && m_PPet->health.tp >= 1000 && m_PBattleTarget != nullptr){ //choose random tp move m_MasterCommand = MASTERCOMMAND_NONE; if (m_PPet->PetSkills.size() > 0){ SetCurrentMobSkill(m_PPet->PetSkills.at(dsprand::GetRandomNumber(m_PPet->PetSkills.size()))); preparePetAbility(m_PBattleTarget); return; } } } else if (m_PPet->getPetType() == PETTYPE_AVATAR){ for (int i = 0; i < m_PPet->PetSkills.size(); i++){ if (m_PPet->PetSkills[i]->getAnimationTime() == m_MasterCommand){ SetCurrentMobSkill(m_PPet->PetSkills[i]); m_MasterCommand = MASTERCOMMAND_NONE; preparePetAbility(m_PPet); return; } } m_MasterCommand = MASTERCOMMAND_NONE; } else if (m_PPet->getPetType() == PETTYPE_WYVERN){ WYVERNTYPE wyverntype = m_PPet->getWyvernType(); if (m_MasterCommand == MASTERCOMMAND_ELEMENTAL_BREATH && (wyverntype == WYVERNTYPE_MULTIPURPOSE || wyverntype == WYVERNTYPE_OFFENSIVE)){ m_MasterCommand = MASTERCOMMAND_NONE; //offensive or multipurpose wyvern if (m_PBattleTarget != nullptr){ //prepare elemental breaths int skip = dsprand::GetRandomNumber(6); int hasSkipped = 0; for (int i = 0; i < m_PPet->PetSkills.size(); i++){ if (m_PPet->PetSkills[i]->getValidTargets() == TARGET_ENEMY){ if (hasSkipped == skip){ SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } else{ hasSkipped++; } } } preparePetAbility(m_PBattleTarget); return; } } else if (m_MasterCommand == MASTERCOMMAND_HEALING_BREATH && (wyverntype == WYVERNTYPE_DEFENSIVE || wyverntype == WYVERNTYPE_MULTIPURPOSE)) { m_MasterCommand = MASTERCOMMAND_NONE; m_PBattleSubTarget = nullptr; //TODO: CHECK FOR STATUS EFFECTS FOR REMOVE- BREATH (higher priority than healing breaths) // if(m_PPet->PMaster->PParty==nullptr){//solo with master-kun CItemArmor* masterHeadItem = ((CCharEntity*)(m_PPet->PMaster))->getEquip(SLOT_HEAD); uint16 masterHead = masterHeadItem ? masterHeadItem->getID() : 0; // Determine what the required HP percentage will need to be // at or under in order for healing breath to activate. uint8 requiredHPP = 0; if (((CCharEntity*)(m_PPet->PMaster))->objtype == TYPE_PC && (masterHead == 12519 || masterHead == 15238)) { //Check for player & AF head, or +1 if (wyverntype == WYVERNTYPE_DEFENSIVE) { //healer wyvern requiredHPP = 50; } else if (wyverntype == WYVERNTYPE_MULTIPURPOSE) { //hybrid wyvern requiredHPP = 33; } } else { if (wyverntype == WYVERNTYPE_DEFENSIVE) { //healer wyvern requiredHPP = 33; } else if (wyverntype == WYVERNTYPE_MULTIPURPOSE) { //hybrid wyvern requiredHPP = 25; } } // Only attempt to find a target if there is an HP percentage to calculate. if (requiredHPP) { CBattleEntity* master = m_PPet->PMaster; // Check the master first. if (master->GetHPP() <= requiredHPP) { m_PBattleSubTarget = master; } // Otherwise if this is a healer wyvern, and the member is in a party // check all of the party members who qualify. else if (wyverntype == WYVERNTYPE_DEFENSIVE && master->PParty != nullptr) { master->ForParty([this, requiredHPP](CBattleEntity* PTarget){ if (PTarget->GetHPP() <= requiredHPP) { m_PBattleSubTarget = PTarget; } }); } } if (m_PBattleSubTarget != nullptr){ //target to heal //get highest breath for wyverns level m_PMobSkill = nullptr; for (int i = 0; i < m_PPet->PetSkills.size(); i++){ if (m_PPet->PetSkills[i]->getValidTargets() == TARGET_PLAYER_PARTY){ if (m_PPet->PetSkills[i]->getID() == 638 && m_PPet->PMaster->GetMLevel() < 20){ //can only using hb1 SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } else if (m_PPet->PetSkills[i]->getID() == 639 && m_PPet->PMaster->GetMLevel() < 40){ //can only using hb2 SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } else if (m_PPet->PetSkills[i]->getID() == 640 && m_PPet->PMaster->GetMLevel() >= 40){ //can only using hb3 SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } } } preparePetAbility(m_PBattleSubTarget); return; } } } TransitionBack(true); }
void CMagicState::CharOnTarget(apAction_t* action, int16 ce, int16 ve) { if(m_PEntity->objtype != TYPE_PC) { return; } CBattleEntity* PTarget = action->ActionTarget; bool enmityApplied = false; if (m_PEntity->StatusEffectContainer->HasStatusEffect(EFFECT_TRANQUILITY) && m_PSpell->getSpellGroup() == SPELLGROUP_WHITE) { m_PEntity->addModifier(MOD_ENMITY, -m_PEntity->StatusEffectContainer->GetStatusEffect(EFFECT_TRANQUILITY)->GetPower()); } if (m_PEntity->StatusEffectContainer->HasStatusEffect(EFFECT_EQUANIMITY) && m_PSpell->getSpellGroup() == SPELLGROUP_BLACK) { m_PEntity->addModifier(MOD_ENMITY, -m_PEntity->StatusEffectContainer->GetStatusEffect(EFFECT_EQUANIMITY)->GetPower()); } if (PTarget->objtype == TYPE_MOB && PTarget->allegiance != m_PEntity->allegiance) { if (PTarget->isDead()) { ((CMobEntity*)PTarget)->m_DropItemTime = m_PSpell->getAnimationTime(); } ((CMobEntity*)PTarget)->m_OwnerID.id = m_PEntity->id; ((CMobEntity*)PTarget)->m_OwnerID.targid = m_PEntity->targid; ((CMobEntity*)PTarget)->PEnmityContainer->UpdateEnmity(m_PEntity, ce, ve); enmityApplied = true; } else if (PTarget->allegiance == m_PEntity->allegiance) { battleutils::GenerateInRangeEnmity(m_PEntity, ce, ve); enmityApplied = true; } if (m_PEntity->StatusEffectContainer->HasStatusEffect(EFFECT_TRANQUILITY) && m_PSpell->getSpellGroup() == SPELLGROUP_WHITE) { m_PEntity->delModifier(MOD_ENMITY, -m_PEntity->StatusEffectContainer->GetStatusEffect(EFFECT_TRANQUILITY)->GetPower()); if (enmityApplied) m_PEntity->StatusEffectContainer->DelStatusEffect(EFFECT_TRANQUILITY); } if (m_PEntity->StatusEffectContainer->HasStatusEffect(EFFECT_EQUANIMITY) && m_PSpell->getSpellGroup() == SPELLGROUP_BLACK) { m_PEntity->delModifier(MOD_ENMITY, -m_PEntity->StatusEffectContainer->GetStatusEffect(EFFECT_EQUANIMITY)->GetPower()); if (enmityApplied) m_PEntity->StatusEffectContainer->DelStatusEffect(EFFECT_EQUANIMITY); } if(action->param > 0 && m_PSpell->dealsDamage() && m_PSpell->getSpellGroup() == SPELLGROUP_BLUE && m_PEntity->StatusEffectContainer->HasStatusEffect(EFFECT_CHAIN_AFFINITY) && ((CBlueSpell*)m_PSpell)->getPrimarySkillchain() != 0) { SUBEFFECT effect = battleutils::GetSkillChainEffect(PTarget, (CBlueSpell*)m_PSpell); if (effect != SUBEFFECT_NONE) { uint16 skillChainDamage = battleutils::TakeSkillchainDamage(m_PEntity, PTarget, action->param); action->addEffectParam = skillChainDamage; action->addEffectMessage = 287 + effect; action->additionalEffect = effect; } if (m_PEntity->StatusEffectContainer->HasStatusEffect(EFFECT_SEKKANOKI) || m_PEntity->StatusEffectContainer->HasStatusEffect(EFFECT_MEIKYO_SHISUI)) { m_PEntity->health.tp = (m_PEntity->health.tp > 1000 ? m_PEntity->health.tp - 1000 : 0); } else { m_PEntity->health.tp = 0; } m_PEntity->StatusEffectContainer->DelStatusEffectSilent(EFFECT_CHAIN_AFFINITY); } }
CBattleEntity* CTargetFind::getValidTarget(uint16 actionTargetID, uint8 validTargetFlags) { DSP_DEBUG_BREAK_IF(actionTargetID == 0); CBattleEntity* PTarget = (CBattleEntity*)m_PBattleEntity->GetEntity(actionTargetID, TYPE_MOB | TYPE_PC | TYPE_PET); if (PTarget == nullptr) { return nullptr; } if (PTarget->objtype == TYPE_PC) { if ((validTargetFlags & TARGET_SELF) && PTarget->targid == m_PBattleEntity->targid) { return PTarget; } if (validTargetFlags & TARGET_PLAYER) { return PTarget; } if ((validTargetFlags & TARGET_PLAYER_PARTY) && (m_PBattleEntity->PParty != nullptr && m_PBattleEntity->PParty == PTarget->PParty)) { return PTarget; } if ((validTargetFlags & TARGET_PLAYER_PARTY_PIANISSIMO) && (m_PBattleEntity->StatusEffectContainer->HasStatusEffect(EFFECT_PIANISSIMO)) && (m_PBattleEntity->PParty != nullptr && m_PBattleEntity->PParty == PTarget->PParty)) { return PTarget; } if ((validTargetFlags & TARGET_PLAYER_DEAD) && PTarget->isDead()) { return PTarget; } return nullptr; } if (PTarget->objtype == TYPE_MOB) { if (validTargetFlags & TARGET_PLAYER_DEAD && ((CMobEntity*)PTarget)->m_Behaviour & BEHAVIOUR_RAISABLE && PTarget->isDead()) { return PTarget; } if (validTargetFlags & TARGET_NPC) { if (PTarget->allegiance == m_PBattleEntity->allegiance && (PTarget == m_PBattleEntity || !(((CMobEntity*)PTarget)->m_Behaviour & BEHAVIOUR_NOHELP))) { return PTarget; } } } if (validTargetFlags & TARGET_ENEMY) { if (!PTarget->isDead()) { if (PTarget->allegiance == (m_PBattleEntity->allegiance % 2 == 0 ? m_PBattleEntity->allegiance + 1 : m_PBattleEntity->allegiance - 1)) { return PTarget; } } } return nullptr; }
bool CAutomatonController::TryHeal(const CurrentManeuvers& maneuvers) { if (!PAutomaton->PMaster || m_healCooldown == 0s || m_Tick <= m_LastHealTime + (m_healCooldown - std::chrono::seconds(PAutomaton->getMod(Mod::AUTO_HEALING_DELAY)))) return false; float threshold = 0; switch (maneuvers.light) // Light -> Higher healing threshold { case 1: threshold = 40; break; case 2: threshold = 50; break; case 3: threshold = 75; break; default: threshold = 30; break; } threshold = dsp_cap(threshold + PAutomaton->getMod(Mod::AUTO_HEALING_THRESHOLD), 30, 90); CBattleEntity* PCastTarget = nullptr; bool haveHate = false; EnmityList_t* enmityList; auto PMob = dynamic_cast<CMobEntity*>(PTarget); if (PMob) { enmityList = PMob->PEnmityContainer->GetEnmityList(); auto masterEnmity_obj = enmityList->find(PAutomaton->PMaster->id); auto selfEnmity_obj = enmityList->find(PAutomaton->id); if (masterEnmity_obj == enmityList->end()) haveHate = true; else if (selfEnmity_obj == enmityList->end()) haveHate = false; else { uint16 selfEnmity = selfEnmity_obj->second.CE + selfEnmity_obj->second.VE; uint16 masterEnmity = masterEnmity_obj->second.CE + masterEnmity_obj->second.VE; haveHate = selfEnmity > masterEnmity ? true : false; } } // Prioritize hate if (haveHate) { if (PAutomaton->GetHPP() <= 50) // Automaton only heals itself when <= 50% PCastTarget = PAutomaton; else if (PAutomaton->PMaster->GetHPP() <= threshold && distance(PAutomaton->loc.p, PAutomaton->PMaster->loc.p) < 20) PCastTarget = PAutomaton->PMaster; } else { if (PAutomaton->PMaster->GetHPP() <= threshold) PCastTarget = PAutomaton->PMaster; else if (PAutomaton->GetHPP() <= 50) // Automaton only heals itself when <= 50% PCastTarget = PAutomaton; } if (maneuvers.light && !PCastTarget && PAutomaton->getHead() == HEAD_SOULSOOTHER && PAutomaton->PMaster->PParty) // Light + Soulsoother head -> Heal party { if (PMob) { uint16 highestEnmity = 0; for (uint8 i = 0; i < PAutomaton->PMaster->PParty->members.size(); ++i) { CBattleEntity* member = PAutomaton->PMaster->PParty->members.at(i); if (member->id != PAutomaton->PMaster->id) { auto enmity_obj = enmityList->find(member->id); if (enmity_obj != enmityList->end() && highestEnmity < enmity_obj->second.CE + enmity_obj->second.VE && member->GetHPP() <= threshold && distance(PAutomaton->loc.p, PAutomaton->PMaster->loc.p) < 20) { highestEnmity = enmity_obj->second.CE + enmity_obj->second.VE; PCastTarget = member; } } } } else { for (uint8 i = 0; i < PAutomaton->PMaster->PParty->members.size(); ++i) { CBattleEntity* member = PAutomaton->PMaster->PParty->members.at(i); if (member->id != PAutomaton->PMaster->id && distance(PAutomaton->loc.p, PAutomaton->PMaster->loc.p) < 20) { if (member->GetHPP() <= threshold) { PCastTarget = member; break; } } } } } // This might be wrong if (PCastTarget) { float missinghp = PCastTarget->GetMaxHP() - PCastTarget->health.hp; if (missinghp > 850 && Cast(PCastTarget->targid, SpellID::Cure_VI )) return true; else if (missinghp > 600 && Cast(PCastTarget->targid, SpellID::Cure_V)) return true; else if (missinghp > 350 && Cast(PCastTarget->targid, SpellID::Cure_IV)) return true; else if (missinghp > 190 && Cast(PCastTarget->targid, SpellID::Cure_III)) return true; else if (missinghp > 120 && Cast(PCastTarget->targid, SpellID::Cure_II)) return true; else if (Cast(PCastTarget->targid, SpellID::Cure)) return true; } return false; }