Example #1
0
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;
}