bool CAttack::CheckAnticipated() { CStatusEffect* effect = m_victim->StatusEffectContainer->GetStatusEffect(EFFECT_THIRD_EYE, 0); if (effect == nullptr) { return false; } //power stores how many times this effect has anticipated auto pastAnticipations = effect->GetPower(); if (pastAnticipations > 7) { //max 7 anticipates! m_victim->StatusEffectContainer->DelStatusEffect(EFFECT_THIRD_EYE); return false; } bool hasSeigan = m_victim->StatusEffectContainer->HasStatusEffect(EFFECT_SEIGAN, 0); if (!hasSeigan && pastAnticipations == 0) { m_victim->StatusEffectContainer->DelStatusEffect(EFFECT_THIRD_EYE); m_anticipated = true; return true; } else if (!hasSeigan) { m_victim->StatusEffectContainer->DelStatusEffect(EFFECT_THIRD_EYE); return false; } else { //do have seigan, decay anticipations correctly (guesstimated) //5-6 anticipates is a 'lucky' streak, going to assume 15% decay per proc, with a 100% base w/ Seigan if (dsprand::GetRandomNumber(100) < (100 - (pastAnticipations * 15) + m_victim->getMod(Mod::THIRD_EYE_ANTICIPATE_RATE))) { //increment power and don't remove effect->SetPower(effect->GetPower() + 1); //chance to counter - 25% base if (dsprand::GetRandomNumber(100) < 25 + m_victim->getMod(Mod::THIRD_EYE_COUNTER_RATE)) { if (m_victim->PAI->IsEngaged()) { m_isCountered = true; m_isCritical = (dsprand::GetRandomNumber(100) < battleutils::GetCritHitRate(m_victim, m_attacker, false)); } } m_anticipated = true; return true; } m_victim->StatusEffectContainer->DelStatusEffect(EFFECT_THIRD_EYE); return false; } return false; }
void CStatusEffectContainer::LoadStatusEffects() { DSP_DEBUG_BREAK_IF(m_POwner->objtype != TYPE_PC); const int8* Query = "SELECT " "effectid," "icon," "power," "tick," "duration," "subid," "subpower," "tier " "FROM char_effects " "WHERE charid = %u;"; int32 ret = Sql_Query(SqlHandle, Query, m_POwner->id); std::vector<CStatusEffect*> PEffectList; if (ret != SQL_ERROR && Sql_NumRows(SqlHandle) != 0) { while (Sql_NextRow(SqlHandle) == SQL_SUCCESS) { CStatusEffect* PStatusEffect = new CStatusEffect( (EFFECT)Sql_GetUIntData(SqlHandle, 0), (uint16)Sql_GetUIntData(SqlHandle, 1), (uint16)Sql_GetUIntData(SqlHandle, 2), (uint32)Sql_GetUIntData(SqlHandle, 3), (uint32)Sql_GetUIntData(SqlHandle, 4), (uint16)Sql_GetUIntData(SqlHandle, 5), (uint16)Sql_GetUIntData(SqlHandle, 6), (uint16)Sql_GetUIntData(SqlHandle, 7)); PEffectList.push_back(PStatusEffect); // load shadows left if (PStatusEffect->GetStatusID() == EFFECT_COPY_IMAGE) { m_POwner->setModifier(MOD_UTSUSEMI, PStatusEffect->GetPower()); } else if (PStatusEffect->GetStatusID() == EFFECT_BLINK) { m_POwner->setModifier(MOD_BLINK, PStatusEffect->GetPower()); } } } for (auto&& PStatusEffect : PEffectList) { AddStatusEffect(PStatusEffect); } m_POwner->UpdateHealth(); // после загрузки эффектов пересчитываем максимальное количество HP/MP }
void CStatusEffectContainer::SaveStatusEffects() { DSP_DEBUG_BREAK_IF(m_POwner->objtype != TYPE_PC); Sql_Query(SqlHandle,"DELETE FROM char_effects WHERE charid = %u", m_POwner->id); for (uint32 i = 0; i < m_StatusEffectList.size(); ++i) { CStatusEffect* PStatusEffect = m_StatusEffectList.at(i); if (PStatusEffect->GetDuration() != 0) { const int8* Query = "INSERT INTO char_effects (charid, effectid, icon, power, tick, duration, subid, subpower, tier) VALUES(%u,%u,%u,%u,%u,%u,%u,%u,%u);"; // save power of utsusemi and blink if(PStatusEffect->GetStatusID() == EFFECT_COPY_IMAGE){ PStatusEffect->SetPower(m_POwner->getMod(MOD_UTSUSEMI)); } else if(PStatusEffect->GetStatusID() == EFFECT_BLINK){ PStatusEffect->SetPower(m_POwner->getMod(MOD_BLINK)); } else if(PStatusEffect->GetStatusID() == EFFECT_STONESKIN){ PStatusEffect->SetPower(m_POwner->getMod(MOD_STONESKIN)); } Sql_Query(SqlHandle, Query, m_POwner->id, PStatusEffect->GetStatusID(), PStatusEffect->GetIcon(), PStatusEffect->GetPower(), PStatusEffect->GetTickTime() / 1000, (PStatusEffect->GetDuration() + PStatusEffect->GetStartTime() - gettick()) / 1000, PStatusEffect->GetSubID(), PStatusEffect->GetSubPower(), PStatusEffect->GetTier()); } } }
/************************************************************************ * * * ????????? ??????? ????????? * * * ************************************************************************/ void CStatusEffectContainer::LoadStatusEffects() { DSP_DEBUG_BREAK_IF(m_POwner->objtype != TYPE_PC); const int8* Query = "SELECT " "effectid," "icon," "power," "tick," "duration," "subid," "subpower," "tier " "FROM char_effects " "WHERE charid = %u;"; int32 ret = Sql_Query(SqlHandle, Query, m_POwner->id); if( ret != SQL_ERROR && Sql_NumRows(SqlHandle) != 0) { while(Sql_NextRow(SqlHandle) == SQL_SUCCESS) { CStatusEffect* PStatusEffect = new CStatusEffect( (EFFECT)Sql_GetUIntData(SqlHandle,0), (uint16)Sql_GetUIntData(SqlHandle,1), (uint16)Sql_GetUIntData(SqlHandle,2), (uint32)Sql_GetUIntData(SqlHandle,3), (uint32)Sql_GetUIntData(SqlHandle,4), (uint16)Sql_GetUIntData(SqlHandle,5), (uint16)Sql_GetUIntData(SqlHandle,6), (uint16)Sql_GetUIntData(SqlHandle,7)); AddStatusEffect(PStatusEffect); // load shadows left if(PStatusEffect->GetStatusID() == EFFECT_COPY_IMAGE){ m_POwner->setModifier(MOD_UTSUSEMI, PStatusEffect->GetPower()); } else if(PStatusEffect->GetStatusID() == EFFECT_BLINK){ m_POwner->setModifier(MOD_BLINK, PStatusEffect->GetPower()); } } } m_POwner->UpdateHealth(); // ????? ???????? ???????? ????????????? ???????????? ?????????? HP/MP }
void CStatusEffectContainer::SaveStatusEffects(bool logout) { DSP_DEBUG_BREAK_IF(m_POwner->objtype != TYPE_PC); Sql_Query(SqlHandle, "DELETE FROM char_effects WHERE charid = %u", m_POwner->id); for (uint16 i = 0; i < m_StatusEffectList.size(); ++i) { CStatusEffect* PStatusEffect = m_StatusEffectList.at(i); if (logout && PStatusEffect->GetFlag() & EFFECTFLAG_LOGOUT) continue; auto realduration = std::chrono::milliseconds(PStatusEffect->GetDuration()) + PStatusEffect->GetStartTime() - server_clock::now(); if (realduration > 0s) { const int8* Query = "INSERT INTO char_effects (charid, effectid, icon, power, tick, duration, subid, subpower, tier) VALUES(%u,%u,%u,%u,%u,%u,%u,%u,%u);"; // save power of utsusemi and blink if (PStatusEffect->GetStatusID() == EFFECT_COPY_IMAGE) { PStatusEffect->SetPower(m_POwner->getMod(MOD_UTSUSEMI)); } else if (PStatusEffect->GetStatusID() == EFFECT_BLINK) { PStatusEffect->SetPower(m_POwner->getMod(MOD_BLINK)); } else if (PStatusEffect->GetStatusID() == EFFECT_STONESKIN) { PStatusEffect->SetPower(m_POwner->getMod(MOD_STONESKIN)); } uint32 tick = PStatusEffect->GetTickTime() == 0 ? 0 : PStatusEffect->GetTickTime() / 1000; uint32 duration = PStatusEffect->GetDuration() == 0 ? 0 : std::chrono::duration_cast<std::chrono::seconds>(realduration).count(); Sql_Query(SqlHandle, Query, m_POwner->id, PStatusEffect->GetStatusID(), PStatusEffect->GetIcon(), PStatusEffect->GetPower(), tick, duration, PStatusEffect->GetSubID(), PStatusEffect->GetSubPower(), PStatusEffect->GetTier()); } } }
bool CStatusEffectContainer::CanGainStatusEffect(EFFECT statusEffect, uint16 power) { // check for immunities first switch(statusEffect){ case EFFECT_SLEEP: case EFFECT_SLEEP_II: case EFFECT_LULLABY: if(m_POwner->hasImmunity(IMMUNITY_SLEEP)) return false; break; case EFFECT_WEIGHT: if(m_POwner->hasImmunity(IMMUNITY_GRAVITY)) return false; break; case EFFECT_BIND: if(m_POwner->hasImmunity(IMMUNITY_BIND)) return false; break; case EFFECT_STUN: if(m_POwner->hasImmunity(IMMUNITY_STUN)) return false; break; case EFFECT_SILENCE: if(m_POwner->hasImmunity(IMMUNITY_SILENCE)) return false; break; case EFFECT_PARALYSIS: if(m_POwner->hasImmunity(IMMUNITY_PARALYZE)) return false; break; case EFFECT_BLINDNESS: if(m_POwner->hasImmunity(IMMUNITY_BLIND)) return false; break; case EFFECT_SLOW: if(m_POwner->hasImmunity(IMMUNITY_SLOW)) return false; break; case EFFECT_POISON: if(m_POwner->hasImmunity(IMMUNITY_POISON)) return false; break; case EFFECT_ELEGY: if(m_POwner->hasImmunity(IMMUNITY_ELEGY)) return false; break; case EFFECT_REQUIEM: if(m_POwner->hasImmunity(IMMUNITY_REQUIEM)) return false; break; } // make sure pets can't be charmed if((statusEffect == EFFECT_CHARM || statusEffect == EFFECT_CHARM_II) && m_POwner->PMaster != nullptr) { return false; } CStatusEffect* PStatusEffect; // check if a status effect blocks this EFFECT blockId = effects::EffectsParams[statusEffect].BlockId; if(blockId != 0 && HasStatusEffect(blockId)){ return false; } // check if negative is strong enough to stop this EFFECT negativeId = effects::EffectsParams[statusEffect].NegativeId; if(negativeId != 0){ PStatusEffect = GetStatusEffect(negativeId); if(PStatusEffect != nullptr){ if(statusEffect == EFFECT_HASTE && PStatusEffect->GetStatusID() == EFFECT_SLOW && PStatusEffect->GetSubPower() == 1) { // slow i remote return true; } // new status effect must be stronger return power >= PStatusEffect->GetPower(); } } PStatusEffect = GetStatusEffect(statusEffect); // check overwrite if(PStatusEffect != nullptr){ uint16 currentPower = PStatusEffect->GetPower(); EFFECTOVERWRITE overwrite = effects::EffectsParams[statusEffect].Overwrite; if(overwrite == EFFECTOVERWRITE_ALWAYS || overwrite == EFFECTOVERWRITE_IGNORE){ return true; } if(overwrite == EFFECTOVERWRITE_NEVER){ return false; } if(overwrite == EFFECTOVERWRITE_EQUAL_HIGHER){ if(power >= currentPower){ return true; } } else if(overwrite == EFFECTOVERWRITE_HIGHER){ // overwrite only if higher if(power > currentPower){ return true; } } return false; } return true; }
CStatusEffect* CStatusEffectContainer::StealStatusEffect() { std::vector<uint16> dispelableList; for (uint16 i = 0; i < m_StatusEffectList.size(); ++i) { if (m_StatusEffectList.at(i)->GetFlag() & EFFECTFLAG_DISPELABLE && m_StatusEffectList.at(i)->GetDuration() > 0) { dispelableList.push_back(i); } } if (!dispelableList.empty()) { uint16 rndIdx = WELL512::GetRandomNumber(dispelableList.size()); uint16 effectIndex = dispelableList.at(rndIdx); CStatusEffect* oldEffect = m_StatusEffectList.at(effectIndex); //make a copy CStatusEffect* EffectCopy = new CStatusEffect(oldEffect->GetStatusID(), oldEffect->GetIcon(), oldEffect->GetPower(), oldEffect->GetTickTime()/1000, oldEffect->GetDuration()/1000); RemoveStatusEffect(effectIndex); return EffectCopy; } return 0; }
bool CAutomatonController::TryTPMove() { if (PAutomaton->health.tp >= 1000) { const auto& FamilySkills = battleutils::GetMobSkillList(PAutomaton->m_Family); std::vector<CMobSkill*> validSkills; //load the skills that the automaton has access to with it's skill SKILLTYPE skilltype = SKILL_AME; if (PAutomaton->getFrame() == FRAME_SHARPSHOT) skilltype = SKILL_ARA; for (auto skillid : FamilySkills) { auto PSkill = battleutils::GetMobSkill(skillid); if (PSkill && PAutomaton->GetSkill(skilltype) > PSkill->getParam() && PSkill->getParam() != -1 && distance(PAutomaton->loc.p, PTarget->loc.p) < PSkill->getRadius()) { validSkills.push_back(PSkill); } } int16 currentSkill = -1; CMobSkill* PWSkill = nullptr; int8 currentManeuvers = -1; bool attemptChain = (PAutomaton->getMod(Mod::AUTO_TP_EFFICIENCY) != 0); if (attemptChain) { CStatusEffect* PSCEffect = PTarget->StatusEffectContainer->GetStatusEffect(EFFECT_SKILLCHAIN, 0); if (PSCEffect) { std::list<SKILLCHAIN_ELEMENT> resonanceProperties; if (PSCEffect->GetTier() == 0) { if (PSCEffect->GetStartTime() + 3s < m_Tick) { if (PSCEffect->GetPower()) { CWeaponSkill* PWeaponSkill = battleutils::GetWeaponSkill(PSCEffect->GetPower()); resonanceProperties.push_back((SKILLCHAIN_ELEMENT)PWeaponSkill->getPrimarySkillchain()); resonanceProperties.push_back((SKILLCHAIN_ELEMENT)PWeaponSkill->getSecondarySkillchain()); resonanceProperties.push_back((SKILLCHAIN_ELEMENT)PWeaponSkill->getTertiarySkillchain()); } else { CBlueSpell* oldSpell = (CBlueSpell*)spell::GetSpell(static_cast<SpellID>(PSCEffect->GetSubPower())); resonanceProperties.push_back((SKILLCHAIN_ELEMENT)oldSpell->getPrimarySkillchain()); resonanceProperties.push_back((SKILLCHAIN_ELEMENT)oldSpell->getSecondarySkillchain()); } } } else { resonanceProperties.push_back((SKILLCHAIN_ELEMENT)PSCEffect->GetPower()); } for (auto PSkill : validSkills) { if (PSkill->getParam() > currentSkill) { std::list<SKILLCHAIN_ELEMENT> skillProperties; skillProperties.push_back((SKILLCHAIN_ELEMENT)PSkill->getPrimarySkillchain()); skillProperties.push_back((SKILLCHAIN_ELEMENT)PSkill->getSecondarySkillchain()); skillProperties.push_back((SKILLCHAIN_ELEMENT)PSkill->getTertiarySkillchain()); if (battleutils::FormSkillchain(resonanceProperties, skillProperties) != SC_NONE) { currentManeuvers = 1; currentSkill = PSkill->getParam(); PWSkill = PSkill; } } } } } if (!attemptChain || (currentManeuvers == -1 && PAutomaton->PMaster && PAutomaton->PMaster->health.tp < PAutomaton->getMod(Mod::AUTO_TP_EFFICIENCY))) { for (auto PSkill : validSkills) { int8 maneuvers = luautils::OnMobAutomatonSkillCheck(PTarget, PAutomaton, PSkill); if (maneuvers > -1 && (maneuvers > currentManeuvers || (maneuvers == currentManeuvers && PSkill->getParam() > currentSkill))) { currentManeuvers = maneuvers; currentSkill = PSkill->getParam(); PWSkill = PSkill; } } } // No WS was chosen (waiting on master's TP to skillchain probably) if (currentManeuvers == -1) return false; if (PWSkill) return MobSkill(PTarget->targid, PWSkill->getID()); } return false; }