示例#1
0
void CMagicState::FinishSpell()
{
    DSP_DEBUG_BREAK_IF(m_PSpell == NULL);
	DSP_DEBUG_BREAK_IF(m_PEntity->PBattleAI->GetCurrentAction() != ACTION_MAGIC_FINISH);

	CSpell* PSpellCopy = new CSpell(*m_PSpell);

	luautils::OnSpellPrecast(m_PEntity, PSpellCopy);

	SpendCost(PSpellCopy);
	SetRecast(m_PSpell);

	// remove effects based on spell cast first
    int16 effectFlags = EFFECTFLAG_INVISIBLE | EFFECTFLAG_MAGIC_BEGIN;

	if (PSpellCopy->canTargetEnemy())
    {
    	effectFlags |= EFFECTFLAG_DETECTABLE;
    }

    m_PEntity->StatusEffectContainer->DelStatusEffectsByFlag(effectFlags);

    m_PTargetFind->reset();
    m_PEntity->m_ActionList.clear();

    // setup special targeting flags
    // can this spell target the dead?

    uint8 flags = FINDFLAGS_NONE;
	if (PSpellCopy->getValidTarget() & TARGET_PLAYER_DEAD)
    {
        flags |= FINDFLAGS_DEAD;
    }
	if (PSpellCopy->getFlag() & SPELLFLAG_HIT_ALL)
	{
		flags |= FINDFLAGS_HIT_ALL;
	}
	uint8 aoeType = battleutils::GetSpellAoEType(m_PEntity, PSpellCopy);

	if (aoeType == SPELLAOE_RADIAL) {
		float distance = spell::GetSpellRadius(PSpellCopy, m_PEntity);

        m_PTargetFind->findWithinArea(m_PTarget, AOERADIUS_TARGET, distance, flags);

    }
    else if (aoeType == SPELLAOE_CONAL)
    {
        //TODO: actual radius calculation
		float radius = spell::GetSpellRadius(PSpellCopy, m_PEntity);

        m_PTargetFind->findWithinCone(m_PTarget, radius, 45, flags);
	}
	else
	{
		// only add target
		m_PTargetFind->findSingleTarget(m_PTarget, flags);
	}

    uint16 totalTargets = m_PTargetFind->m_targets.size();

	PSpellCopy->setTotalTargets(totalTargets);

	apAction_t action;
	action.ActionTarget = m_PTarget;
	action.reaction   = REACTION_NONE;
	action.speceffect = SPECEFFECT_NONE;
	action.animation  = PSpellCopy->getAnimationID();
	action.param      = 0;
	action.messageID  = 0;

	uint16 msg = 0;
    int16 ce = 0;
    int16 ve = 0;

	for (std::vector<CBattleEntity*>::iterator it = m_PTargetFind->m_targets.begin() ; it != m_PTargetFind->m_targets.end(); ++it)
	{

        CBattleEntity* PTarget = *it;

        action.ActionTarget = PTarget;

		ce = PSpellCopy->getCE();
		ve = PSpellCopy->getVE();

        // take all shadows
		if (PSpellCopy->canTargetEnemy() && aoeType > 0)
        {
        	PTarget->StatusEffectContainer->DelStatusEffect(EFFECT_BLINK);
        	PTarget->StatusEffectContainer->DelStatusEffect(EFFECT_COPY_IMAGE);
        }

        // TODO: this is really hacky and should eventually be moved into lua
		if (PSpellCopy->canHitShadow() && aoeType == SPELLAOE_NONE && battleutils::IsAbsorbByShadow(PTarget))
        {
        	// take shadow
        	msg = 31;
        	action.param = 1;
            ve = 0;
            ce = 0;
        }
        else
        {
			action.param = luautils::OnSpellCast(m_PEntity, PTarget, PSpellCopy);

            // remove effects from damage
			if (PSpellCopy->canTargetEnemy() && action.param > 0 && m_PSpell->dealsDamage())
            {
                PTarget->StatusEffectContainer->DelStatusEffectsByFlag(EFFECTFLAG_DAMAGE);
            }

            if(msg == 0)
            {
				msg = PSpellCopy->getMessage();
            }
            else
            {
				msg = PSpellCopy->getAoEMessage();
            }

        }

        action.messageID = msg;

		if (PSpellCopy->getID() != 305) //I hate to do this, but there really is no other spell like Odin
            CharOnTarget(&action, ce, ve);

        m_PEntity->m_ActionList.push_back(action);
    }

    CharAfterFinish();

    m_PEntity->StatusEffectContainer->DelStatusEffectsByFlag(EFFECTFLAG_MAGIC_END);

    DSP_DEBUG_BREAK_IF(m_PEntity->PBattleAI->GetCurrentAction() != ACTION_MAGIC_FINISH);
	m_PEntity->loc.zone->PushPacket(m_PEntity, CHAR_INRANGE_SELF, new CActionPacket(m_PEntity));

	delete PSpellCopy;

	Clear();
}
示例#2
0
void TryLearningSpells(CCharEntity* PChar, CMobEntity* PMob) {

	if (PMob->m_UsedSkillIds.size() == 0) { // minor optimisation.
		return;
	}

	// prune the learnable blue spells
	std::vector<CSpell*> PLearnableSpells;
	for (std::map<uint16, uint16>::iterator i=PMob->m_UsedSkillIds.begin(); i != PMob->m_UsedSkillIds.end(); ++i) {
		CSpell* PSpell = spell::GetSpellByMonsterSkillId(i->first);
		if (PSpell != NULL) {
			PLearnableSpells.push_back(PSpell);
		}
	}

	if (PLearnableSpells.size() == 0) {
		return;
	}

	std::vector<CCharEntity*> PBlueMages;

	// populate PBlueMages
	if (PChar->PParty != NULL) {
        for (uint8 i = 0; i < PChar->PParty->members.size(); i++) {
			if (PChar->PParty->members[i]->GetMJob() == JOB_BLU && PChar->PParty->members[i]->objtype == TYPE_PC) {
				PBlueMages.push_back((CCharEntity*)PChar->PParty->members[i]);
			}
		}
	}
	else if (PChar->GetMJob() == JOB_BLU) {
		PBlueMages.push_back(PChar);
	}

	// loop through the list of BLUs and see if they can learn.
	for (int i=0; i<PBlueMages.size(); i++) {
		CCharEntity* PBlueMage = PBlueMages[i];

		if (PBlueMage->isDead()) { // too dead to learn
			continue;
		}

		if (distance(PBlueMage->loc.p, PMob->loc.p) > 100) { // too far away to learn
			continue;
		}

		for (int spell=0; spell<PLearnableSpells.size(); spell++) {
			CSpell* PSpell = PLearnableSpells[spell];

			if (charutils::hasSpell(PBlueMage, PSpell->getID())) {
				continue;
			}

			uint8 learnableLevel = PSpell->getJob(JOB_BLU);
			if (learnableLevel > 0 && learnableLevel < PBlueMage->GetMLevel()+7) { // TODO: Use blue magic skill check rather than level
				if (rand()%100 < 33) {
					if (charutils::addSpell(PBlueMage, PSpell->getID())) {
						PBlueMage->pushPacket(new CMessageBasicPacket(PBlueMage, PBlueMage, PSpell->getID(), 0, MSGBASIC_LEARNS_SPELL));
						charutils::SaveSpells(PBlueMage);
						PBlueMage->pushPacket(new CCharSpellsPacket(PBlueMage));
					}
				}
				break; // only one attempt at learning a spell, regardless of learn or not.
			}
		}

	}
}
示例#3
0
void TryLearningSpells(CCharEntity* PChar, CMobEntity* PMob) {

	if (PMob->m_UsedSkillIds.size() == 0) { // minor optimisation.
		return;
	}

	// prune the learnable blue spells
	std::vector<CSpell*> PLearnableSpells;
	for (std::map<uint16, uint16>::iterator i=PMob->m_UsedSkillIds.begin(); i != PMob->m_UsedSkillIds.end(); ++i) {
		CSpell* PSpell = spell::GetSpellByMonsterSkillId(i->first);
		if (PSpell != nullptr) {
			PLearnableSpells.push_back(PSpell);
		}
	}

	if (PLearnableSpells.size() == 0) {
		return;
	}

	std::vector<CCharEntity*> PBlueMages;

	// populate PBlueMages
	if (PChar->PParty != nullptr) {
        for (uint8 i = 0; i < PChar->PParty->members.size(); i++) {
			if (PChar->PParty->members[i]->GetMJob() == JOB_BLU && PChar->PParty->members[i]->objtype == TYPE_PC) {
				PBlueMages.push_back((CCharEntity*)PChar->PParty->members[i]);
			}
		}
	}
	else if (PChar->GetMJob() == JOB_BLU) {
		PBlueMages.push_back(PChar);
	}

	// loop through the list of BLUs and see if they can learn.
	for (size_t i = 0; i < PBlueMages.size(); i++) {
		CCharEntity* PBlueMage = PBlueMages[i];

		if (PBlueMage->isDead()) { // too dead to learn
			continue;
		}

		if (distance(PBlueMage->loc.p, PMob->loc.p) > 100) { // too far away to learn
			continue;
		}

		for (size_t spell = 0; spell < PLearnableSpells.size(); spell++) {
			CSpell* PSpell = PLearnableSpells[spell];

			if (charutils::hasSpell(PBlueMage, static_cast<uint16>(PSpell->getID()))) {
				continue;
			}

            // get the skill cap for the spell level
            auto skillLvlForSpell = battleutils::GetMaxSkill(SKILL_BLUE_MAGIC, JOB_BLU, PSpell->getJob(JOB_BLU));
            // get player skill level with bonus from gear
            auto playerSkillLvl = PBlueMage->GetSkill(SKILL_BLUE_MAGIC);

            // make sure the difference between spell skill and player is at most 31 points
            if (playerSkillLvl >= skillLvlForSpell - 31)
            {
                // TODO: check for blue learning bonus and adjust base percent
                if (dsprand::GetRandomNumber(100) < 33) {
					if (charutils::addSpell(PBlueMage, static_cast<uint16>(PSpell->getID()))) {
						PBlueMage->pushPacket(new CMessageBasicPacket(PBlueMage, PBlueMage, static_cast<uint16>(PSpell->getID()), 0, MSGBASIC_LEARNS_SPELL));
						charutils::SaveSpell(PBlueMage, static_cast<uint16>(PSpell->getID()));
						PBlueMage->pushPacket(new CCharSpellsPacket(PBlueMage));
					}
				}
				break; // only one attempt at learning a spell, regardless of learn or not.
			}
		}

	}
}