////////////////////////////////////////////////////////////////////////////// // 아우스터즈 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void MagnumSpear::execute(Ousters* pOusters, ObjectID_t TargetObjectID, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pOustersSkillSlot->getSkillType()); return; } Creature* pTargetCreature = pZone->getCreature(TargetObjectID); SkillType_t SkillType = pOustersSkillSlot->getSkillType(); // NPC는 공격할 수가 없다. if (pTargetCreature==NULL || !canAttack(pOusters, pTargetCreature ) || pTargetCreature->isNPC()) { executeSkillFailException(pOusters, SkillType); return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); int HitBonus = 0; /* if (pOusters->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_ACID ) ) { RankBonus* pRankBonus = pOusters->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_ACID); Assert(pRankBonus != NULL); HitBonus = pRankBonus->getPoint(); } */ int RequiredMP = (int)(pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel()/3); bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot, HitBonus); bool bCanHit = canHit(pOusters, pTargetCreature, SkillType); bool bPK = verifyPK(pOusters, pTargetCreature); bool bEffect = pTargetCreature->isFlag(Effect::EFFECT_CLASS_MAGNUM_SPEAR); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bCanHit && bPK && !bEffect) { ZoneCoord_t oustX = pOusters->getX(); ZoneCoord_t oustY = pOusters->getY(); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); decreaseMana(pOusters, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pOusters); SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); Damage_t Damage = output.Damage; OustersSkillSlot* pMastery = pOusters->hasSkill(SKILL_MAGNUM_SPEAR_MASTERY); if (pMastery != NULL ) { Damage += (pMastery->getExpLevel() * 5 / 3 ) + 15; } else { bool dummy; computeCriticalBonus(pOusters, getSkillType(), Damage, dummy); } EffectMagnumSpear* pEffect = new EffectMagnumSpear(pTargetCreature); pEffect->setDamage(computeOustersMagicDamage(pOusters, pTargetCreature, Damage, SKILL_MAGNUM_SPEAR )); int spearNum = 2; if (pOustersSkillSlot->getExpLevel() <= 15 ) spearNum = 2; else if (pOustersSkillSlot->getExpLevel() < 30 ) spearNum = 4; else if (pOustersSkillSlot->getExpLevel() == 30 ) spearNum = 6; int Grade = spearNum/2 - 1; if (pMastery != NULL ) { spearNum = 1; Grade = 4; output.Delay = 20; } pEffect->setTimes(spearNum); pEffect->setTick(5); pEffect->setNextTime(5); pEffect->setCasterOID(pOusters->getObjectID()); pTargetCreature->addEffect(pEffect); pTargetCreature->setFlag(pEffect->getEffectClass()); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); _GCSkillToObjectOK1.setGrade(Grade); _GCSkillToObjectOK2.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK2.setGrade(Grade); _GCSkillToObjectOK3.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK3.setGrade(Grade); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK4.setGrade(Grade); _GCSkillToObjectOK5.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setGrade(Grade); _GCSkillToObjectOK6.setXY(oustX, oustY); _GCSkillToObjectOK6.setSkillType(SkillType); _GCSkillToObjectOK6.setDuration(0); _GCSkillToObjectOK6.setGrade(Grade); pPlayer->sendPacket(&_GCSkillToObjectOK1); Player* pTargetPlayer = NULL; if (pTargetCreature->isPC()) { pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pOusters); } list<Creature*> cList; cList.push_back(pOusters); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(oustX, oustY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(oustX, oustY, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType()); } __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void Sacrifice::execute(Slayer* pSlayer, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); ZoneCoord_t X = pSlayer->getX(); ZoneCoord_t Y = pSlayer->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_SACRIFICE); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // 이펙트 클래스를 만들어 붙인다. EffectSacrifice* pEffect = new EffectSacrifice(pSlayer); pEffect->setDeadline(output.Duration); pSlayer->addEffect(pEffect); pSlayer->setFlag(Effect::EFFECT_CLASS_SACRIFICE); // 경험치를 올린다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10*(Grade+1); shareAttrExp(pSlayer, ExpUp , 1, 1, 8, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(0); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(0); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(X, Y, &_GCSkillToSelfOK2, pSlayer); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pSlayer->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_SACRIFICE); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void AirShield::execute(Slayer* pSlayer, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayer)" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); // 무장하고 있는 무기가 널이거나, 도가 아니라면 사용할 수 없다. Item* pItem = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND); if (pItem == NULL || pItem->getItemClass() != Item::ITEM_CLASS_BLADE) { executeSkillFailException(pSlayer, getSkillType()); return; } bool bIncreaseDomainExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_AIR_SHIELD_1); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); // 지속 시간을 계산한다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // 이팩트 클래스를 만들어 붙인다. EffectAirShield* pEffect = new EffectAirShield(pSlayer); pEffect->setDeadline(output.Duration); pEffect->setLevel(SkillLevel); pEffect->setDamage(output.Damage); pSlayer->addEffect(pEffect); pSlayer->setFlag(Effect::EFFECT_CLASS_AIR_SHIELD_1); // 경험치를 올린다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1); if (bIncreaseDomainExp ) { shareAttrExp(pSlayer, ExpUp, 8, 1, 1, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); // increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); } _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(0); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(0); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &_GCSkillToSelfOK2, pSlayer); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pSlayer->getObjectID()); gcAddEffect.setEffectID(pEffect->getClientEffectClass()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayer)" << endl; __END_CATCH }
void SimpleMissileSkill::execute( Slayer* pSlayer, ObjectID_t TargetObjectID, SkillSlot* pSkillSlot, const SIMPLE_SKILL_INPUT& param, SIMPLE_SKILL_OUTPUT& result, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NPC는 공격할 수가 없다. // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !canAttack(pSlayer, pTargetCreature ) || pTargetCreature->isNPC()) { executeSkillFailException(pSlayer, param.SkillType); return; } result.pTargetCreature = pTargetCreature; GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(param.SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); bool bCriticalHit = false; Damage_t Damage = 0; if (param.bAdd) { // 파라미터로 전달된 데미지 값이 더해지는 데미지라면, // 일반 데미지를 계산 후, 데미지를 더해야 한다. // 파라미터로 전달된 데미지 값이 직접적으로 쓰이는 데미지라면, // 이 부분까지 들어오지 않으므로, 밑의 부분까지 0으로 전달된다. Damage += computeDamage(pSlayer, pTargetCreature, SkillLevel/5, bCriticalHit); } if (param.bMagicDamage) { // 만일 스킬 데미지가 마법 데미지라면, 마법 데미지 계산 함수를 이용해 계산을 해준다. Damage += computeMagicDamage(pTargetCreature, param.SkillDamage, param.SkillType); } else { Damage += param.SkillDamage; } ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = false; bool bPK = verifyPK(pSlayer, pTargetCreature); if (param.bMagicHitRoll) { bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); } else { bHitRoll = HitRoll::isSuccess(pSlayer, pTargetCreature, SkillLevel/2); } if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bPK) { decreaseMana(pSlayer, RequiredMP, _GCSkillToObjectOK1); // 데미지를 가하고, 내구도를 떨어뜨린다. setDamage(pTargetCreature, Damage, pSlayer, param.SkillType, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pSlayer, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); decreaseDurability(pSlayer, pTargetCreature, NULL, &_GCSkillToObjectOK1, &_GCSkillToObjectOK2); // 타겟이 슬레이어가 아닌 경우에만 경험치를 올려준다. if (!pTargetCreature->isSlayer()) { shareAttrExp(pSlayer, Damage , param.STRMultiplier, param.DEXMultiplier, param.INTMultiplier, _GCSkillToObjectOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToObjectOK1, pTargetCreature->getLevel()); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToObjectOK1); increaseAlignment(pSlayer, pTargetCreature, _GCSkillToObjectOK1); } _GCSkillToObjectOK1.setSkillType(param.SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); _GCSkillToObjectOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK2.setSkillType(param.SkillType); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK3.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK3.setSkillType(param.SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK4.setSkillType(param.SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setSkillType(param.SkillType); _GCSkillToObjectOK5.setDuration(0); // Send Packet pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } else if (pTargetCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pSlayer); } list<Creature*> cList; cList.push_back(pSlayer); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(myX, myY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); pSkillSlot->setRunTime(param.Delay); result.bSuccess = true; } else { executeSkillFailNormal(pSlayer, param.SkillType, pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pSlayer, param.SkillType); } __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void DivineSpirits::execute(Ousters* pOusters, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayer)" << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); //SkillDomainType_t DomainType = pSkillInfo->getDomainType(); //SkillLevel_t SkillLevel = pOustersSkillSlot->getExpLevel(); int RequiredMP = pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pOusters); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bEffected = pOusters->isFlag(Effect::EFFECT_CLASS_DIVINE_SPIRITS); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToSelfOK1); // 지속 시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); // 이팩트 클래스를 만들어 붙인다. EffectDivineSpirits* pEffect = new EffectDivineSpirits(pOusters); pEffect->setDeadline(output.Duration); pEffect->setBonus(output.Damage); pOusters->addEffect(pEffect); pOusters->setFlag(Effect::EFFECT_CLASS_DIVINE_SPIRITS); // OUSTERS_RECORD prev; // pOusters->getOustersRecord(prev); // pOusters->initAllStat(); // pOusters->addModifyInfo(prev, _GCSkillToSelfOK1); _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pOusters->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(pOusters->getX(), pOusters->getY(), &_GCSkillToSelfOK2, pOusters); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pOusters->getObjectID()); gcAddEffect.setEffectID(pEffect->getEffectClass()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pOusters->getX(), pOusters->getY(), &gcAddEffect, pOusters); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayer)" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void RemoveCurse::execute(Slayer* pSlayer, ObjectID_t TargetObjectID, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // 슬레이어 외에는 치료할 수 없다. // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || pTargetCreature->isSlayer() == false) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); // by sigi. 2002.12.3 SkillLevel_t SkillLevel = pSlayer->getINT()/2; //pSkillSlot->getExpLevel(); bool bDoom = false; bool bParalyze = false; bool bSeduction = false; // by sigi. 2002.12.3 //bool bHallucination = false; bool bDeath = false; bool bEffected = false; // 아무 저주나 걸려 있으면 켠다. EffectDoom* pEffectDoom = NULL; EffectParalyze* pEffectParalyze = NULL; EffectSeduction* pEffectSeduction = NULL; // by sigi. 2002.12.3 //EffectHallucination* pEffectHallucination = NULL; EffectDeath* pEffectDeath = NULL; if (pTargetCreature->isEffect(Effect::EFFECT_CLASS_DOOM)) { pEffectDoom = (EffectDoom*)pTargetCreature->findEffect(Effect::EFFECT_CLASS_DOOM); Assert(pEffectDoom != NULL); bDoom = HitRoll::isSuccessRemoveCurse(45, SkillLevel, 20, pEffectDoom->getLevel()/4); bEffected = true; } if (pTargetCreature->isEffect(Effect::EFFECT_CLASS_PARALYZE)) { pEffectParalyze = (EffectParalyze*)pTargetCreature->findEffect(Effect::EFFECT_CLASS_PARALYZE); Assert(pEffectParalyze != NULL); bParalyze = HitRoll::isSuccessRemoveCurse(45, SkillLevel, 10, pEffectParalyze->getLevel()/4); bEffected = true; } if (pTargetCreature->isEffect(Effect::EFFECT_CLASS_SEDUCTION)) { pEffectSeduction = (EffectSeduction*)pTargetCreature->findEffect(Effect::EFFECT_CLASS_SEDUCTION); Assert(pEffectSeduction != NULL); bSeduction = HitRoll::isSuccessRemoveCurse(45, SkillLevel, 30, pEffectSeduction->getLevel()/4); bEffected = true; } // by sigi. 2002.12.3 // if (pTargetCreature->isEffect(Effect::EFFECT_CLASS_HALLUCINATION)) // { // pEffectHallucination = (EffectHallucination*)pTargetCreature->findEffect(Effect::EFFECT_CLASS_HALLUCINATION); //// Assert(pEffectHallucination != NULL); // // bHallucination = HitRoll::isSuccessRemoveCurse(45, SkillLevel, 40, pEffectHallucination->getLevel()/4); // bEffected = true; // } if (pTargetCreature->isEffect(Effect::EFFECT_CLASS_DEATH)) { pEffectDeath = (EffectDeath*)pTargetCreature->findEffect(Effect::EFFECT_CLASS_DEATH); Assert(pEffectDeath != NULL); bDeath = HitRoll::isSuccessRemoveCurse(45, SkillLevel, 50, pEffectDeath->getLevel()/4); bEffected = true; } int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, pTargetCreature, pSkillInfo->getRange()); // 마나가 있고, 시간이 됐고, 거리가 적당하며, // 저주가 하나라도 걸려있어야 한다. if (bManaCheck && bTimeCheck && bRangeCheck && bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToObjectOK1); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // 각각의 저주를 삭제하고, // 패킷에다 이펙트 삭제하라고 더한다. GCRemoveEffect gcRemoveEffect; gcRemoveEffect.setObjectID(pTargetCreature->getObjectID()); if (bDoom) { pEffectDoom->setDeadline(0); pTargetCreature->removeFlag(Effect::EFFECT_CLASS_DOOM); gcRemoveEffect.addEffectList(Effect::EFFECT_CLASS_DOOM); } if (bParalyze) { pEffectParalyze->setDeadline(0); pTargetCreature->removeFlag(Effect::EFFECT_CLASS_PARALYZE); gcRemoveEffect.addEffectList(Effect::EFFECT_CLASS_PARALYZE); } if (bSeduction) { pEffectSeduction->setDeadline(0); pTargetCreature->removeFlag(Effect::EFFECT_CLASS_SEDUCTION); gcRemoveEffect.addEffectList(Effect::EFFECT_CLASS_SEDUCTION); } // by sigi. 2002.12.3 // if (bHallucination) // { // pEffectHallucination->setDeadline(0); // pTargetCreature->removeFlag(Effect::EFFECT_CLASS_HALLUCINATION); // gcRemoveEffect.addEffectList(Effect::EFFECT_CLASS_HALLUCINATION); // } if (bDeath) { pEffectDeath->setDeadline(0); pTargetCreature->removeFlag(Effect::EFFECT_CLASS_DEATH); gcRemoveEffect.addEffectList(Effect::EFFECT_CLASS_DEATH); } // 경험치를 올린다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10*(Grade+1); shareAttrExp(pSlayer, ExpUp, 1, 1, 8, _GCSkillToObjectOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToObjectOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToObjectOK1); // 패킷을 만들어 보낸다. ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); _GCSkillToObjectOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration (0); _GCSkillToObjectOK3.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration (0); pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } pZone->broadcastPacket(targetX, targetY, &gcRemoveEffect); list< Creature*> cList; cList.push_back(pSlayer); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(myX, myY, targetX, targetY, &_GCSkillToObjectOK5 , cList); pZone->broadcastPacket(myX, myY, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), pTargetCreature); } } catch(Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 ////////////////////////////////////////////////////////////////////////////// void HolyArmor::execute(Slayer * pSlayer, SkillSlot * pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); // 무장하고 있는 무기가 널이거나, 검이 아니라면 기술을 쓸 수 없다. /* Item* pWeapon = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_SWORD) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; }*/ GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); ZoneCoord_t X = pSlayer->getX(); ZoneCoord_t Y = pSlayer->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP) && pSlayer->getHP() > 100; bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_HOLY_ARMOR); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); pSlayer->setHP(pSlayer->getHP()-100); _GCSkillToSelfOK1.addShortData(MODIFY_CURRENT_HP, pSlayer->getHP()); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // 이펙트 클래스를 만들어 붙인다. EffectHolyArmor* pEffect = new EffectHolyArmor(pSlayer); pEffect->setDeadline(output.Duration); pEffect->setDefBonus(output.Damage); pSlayer->addEffect(pEffect); pSlayer->setFlag(Effect::EFFECT_CLASS_HOLY_ARMOR); // 이로 인하여 바뀌는 능력치를 보낸다. SLAYER_RECORD prev; pSlayer->getSlayerRecord(prev); pSlayer->initAllStat(); pSlayer->sendRealWearingInfo(); pSlayer->sendModifyInfo(prev); // 경험치를 올린다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10*(Grade+1); shareAttrExp(pSlayer, ExpUp, 1, 1, 8, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); // 패킷을 만들어 보낸다. _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pSlayer->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_HOLY_ARMOR); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(X, Y, &gcAddEffect); // Send Packet pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(X, Y, &_GCSkillToSelfOK2, pSlayer); pSkillSlot->setRunTime(output.Delay); uint PartyID = pSlayer->getPartyID(); if (PartyID != 0) { LocalPartyManager* pLPM = pZone->getLocalPartyManager(); pLPM->shareHolyArmor(PartyID, pSlayer, output.Damage, input.SkillLevel); } } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); //cout << t.toString() << endl; } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
void Flare::execute(Slayer* pSlayer, ObjectID_t TargetObjectID, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NPC이거나, 슬레이어에게는 Flare를 쓸 수가 없다. // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || pTargetCreature->isNPC() || pTargetCreature->isSlayer()) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessFlare(pTargetCreature, SkillLevel) && canAttack(pSlayer, pTargetCreature); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_FLARE); //if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected && pTargetCreature->getCompetence() == 3) { decreaseMana(pSlayer, RequiredMP, _GCSkillToObjectOK1); // 지속 시간을 계산한다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // 이펙트 클래스를 만들어 붙인다. EffectFlare* pEffect = new EffectFlare(pTargetCreature); //pEffect->setOldSight(13); pEffect->setOldSight(pTargetCreature->getSight()); // 제거할때 level체크하기 위햇서.by sigi. 2002.6.21 pEffect->setLevel(pSkillInfo->getLevel()); pEffect->setDeadline(output.Duration); pTargetCreature->setFlag(Effect::EFFECT_CLASS_FLARE); pTargetCreature->addEffect(pEffect); // 이펙트를 적용시킨다. pEffect->affect(pTargetCreature); // 경험치를 올린다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1); shareAttrExp(pSlayer, ExpUp, 1, 1, 8, _GCSkillToObjectOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToObjectOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToObjectOK1); // 패킷을 준비한다. ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); _GCSkillToObjectOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.addShortData(MODIFY_VISION, FLARE_SIGHT); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK3.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY (targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK4.setDuration(0); _GCSkillToObjectOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration(0); list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pSlayer); cList = pZone->broadcastSkillPacket(myX, myY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToObjectOK3, cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4, cList); pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } else { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pSlayer); } GCAddEffect gcAddEffect; gcAddEffect.setObjectID(TargetObjectID); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_FLARE); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(targetX, targetY, &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void Liberty::execute(Ousters* pOusters, ObjectID_t TargetObjectID, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pOustersSkillSlot->getSkillType()); return; } Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !pTargetCreature->isOusters()) { executeSkillFailException(pOusters, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } Ousters* pTargetOusters = dynamic_cast<Ousters*>(pTargetCreature); GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK5 _GCSkillToObjectOK5; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel()/3; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, pTargetCreature, pSkillInfo->getRange()) && canHit(pOusters, pTargetCreature, SkillType, pOustersSkillSlot->getExpLevel()); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); bool bHPCheck = pTargetOusters->isFlag(Effect::EFFECT_CLASS_PARALYZE); int Ratio = 0; EffectParalyze* pEffect = dynamic_cast<EffectParalyze*>(pTargetOusters->findEffect(Effect::EFFECT_CLASS_PARALYZE )); if (pEffect != NULL ) { if (pOustersSkillSlot->getExpLevel() <= 15 ) { Ratio = (int)((pOusters->getLevel() + (pOustersSkillSlot->getExpLevel() * 8.0 / 3.0 ) ) - pEffect->getLevel()); } else { Ratio = (int)((pOusters->getLevel() + 20 + (pOustersSkillSlot->getExpLevel() * 4.0 / 3.0 ) ) - pEffect->getLevel()); if (pOustersSkillSlot->getExpLevel() == 30 ) Ratio = (int)(Ratio * 1.1); } } bool bHitRoll2 = (rand()%100) < Ratio; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bHitRoll2 && bSatisfyRequire && bHPCheck) { // 마나를 줄인다. decreaseMana(pOusters, RequiredMP, _GCSkillToObjectOK1); // 이펙트의 효과와 지속시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; input.TargetType = SkillInput::TARGET_OTHER; computeOutput(input, output); pEffect->setDeadline(0); // 패킷을 준비해서 보낸다. _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK2.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK5.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); // Send Packet pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pOusters != pTargetCreature && pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } list<Creature*> cList; cList.push_back(pOusters); cList.push_back(pTargetCreature); pZone->broadcastPacket(pOusters->getX(), pOusters->getY(), &_GCSkillToObjectOK5 , cList); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void Revealer::execute(Slayer* pSlayer, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_REVEALER); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); // 기술이 유지되는 시간은 숙련도에 따라서 달라진다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // 이펙트 오브젝트를 생성해서 붙인다. EffectRevealer* pEffectRevealer = new EffectRevealer (pSlayer); pEffectRevealer->setSkillLevel(pSkillSlot->getExpLevel()); pEffectRevealer->setDeadline(output.Duration); pSlayer->addEffect(pEffectRevealer); pSlayer->setFlag(Effect::EFFECT_CLASS_REVEALER); // 이 이펙트가 붙음으로써, 안 보이던 것이 보인다. pZone->updateMineScan(pSlayer); //pZone->updateInvisibleScan(pSlayer); pZone->updateHiddenScan(pSlayer); // 경험치를 올린다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1)* 2; shareAttrExp(pSlayer, ExpUp, 1, 8, 1, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); // increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &_GCSkillToSelfOK2, pSlayer); // 이펙트가 붙었다고 알려준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pSlayer->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_REVEALER); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcAddEffect); pSkillSlot->setRunTime(output.Delay); uint PartyID = pSlayer->getPartyID(); if (PartyID != 0) { LocalPartyManager* pLPM = pZone->getLocalPartyManager(); pLPM->shareRevealer(PartyID, pSlayer, output.Duration); } } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch(Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void MagicElusion::execute(Slayer* pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange()) && checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagicElusion(pSlayer); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) bTileCheck = true; // 이펙트의 지속시간을 계산한다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck) { decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); Range_t Range = 2; int oX, oY; list<Creature*> cList; // denier list ObjectRegistry & objectregister = pZone->getObjectRegistry(); // 일단 이미 sanctuary가 있는지 검색한다. for(oY = -1; oY <= 1; oY++) for(oX = -1; oX <= 1; oX++) { int tileX = X+oX; int tileY = Y+oY; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); if (tile.canAddEffect()) { Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_MAGIC_ELUSION); // 이미 있다면 // 기술 실패다. if (pOldEffect != NULL) { executeSkillFailNormal(pSlayer, getSkillType(), NULL); return; } } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); return; } } } for(oY = -1; oY <= 1; oY++) for(oX = -1; oX <= 1; oX++) { int tileX = X+oX; int tileY = Y+oY; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); // 이펙트 클래스를 생성한다. EffectMagicElusion* pEffect = new EffectMagicElusion(pZone , tileX, tileY); pEffect->setDeadline(output.Duration); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); if (oX==0 && oY==0) { pEffect->setBroadcastingEffect(true); GCAddEffectToTile gcAddEffectToTile; gcAddEffectToTile.setEffectID(pEffect->getEffectClass()); gcAddEffectToTile.setObjectID(pEffect->getObjectID()); gcAddEffectToTile.setXY(X, Y); gcAddEffectToTile.setDuration(output.Duration); pZone->broadcastPacket(X, Y, &gcAddEffectToTile, pSlayer); } else { // 가운데 이펙트가 아니면 브로드캐스팅해주지 않는다. pEffect->setBroadcastingEffect(false); } const list<Object*>& oList = tile.getObjectList(); for(list<Object*>::const_iterator itr = oList.begin(); itr != oList.end(); itr++) { Object* pTarget = *itr; if (pTarget->getObjectClass() == Object::OBJECT_CLASS_CREATURE ) { Creature* pCreature = dynamic_cast<Creature*>(pTarget); Assert(pCreature != NULL); if (pCreature->isVampire() ) { Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); Assert(pVampire != NULL); GCModifyInformation gcMI; ::setDamage(pVampire, output.Damage, pSlayer, pSkillSlot->getSkillType(), &gcMI); pVampire->getPlayer()->sendPacket(&gcMI); cList.push_back(pCreature); } else if (pCreature->isMonster() ) { ::setDamage(pCreature, output.Damage, pSlayer, pSkillSlot->getSkillType()); } } } } } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(Range); _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Range); _GCSkillToTileOK3.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setRange(Range); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(Range); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(Range); for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; if (canSee(pTargetCreature, pSlayer)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pSlayer); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pSlayer); // watcherList에서 cList에 속하지 않고, caster(pSlayer)를 볼 수 없는 경우는 // OK4를 보내고.. cList에 추가한다. for(list<Creature*>::const_iterator itr = watcherList.begin(); itr != watcherList.end(); itr++) { bool bBelong = false; for(list<Creature*>::const_iterator tItr = cList.begin(); tItr != cList.end(); tItr++) if (*itr == *tItr) bBelong = true; Creature* pWatcher = (*itr); if (bBelong == false && canSee(pWatcher, pSlayer) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (pWatcher->isPC()) { pWatcher->getPlayer()->sendPacket(&_GCSkillToTileOK4); cList.push_back(*itr); } } } cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList, false); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } if (bTimeCheck ) pSkillSlot->setRunTime(output.Delay); } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 타일 핸들러 - AR이나 SMG를 들고 있을 경우 ////////////////////////////////////////////////////////////////////////////// void MoleShot::ARSMGexecute(Slayer* pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " SGexecute Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(getSkillType()); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); Level_t SkillLevel = pSkillSlot->getExpLevel(); Item* pWeapon = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND); Assert(pWeapon != NULL); bool bIncreaseExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, X, Y, pWeapon->getRange()); bool bBulletCheck = (getRemainBullet(pWeapon) > 0) ? true : false; // 총알 숫자는 무조건 떨어뜨린다. Bullet_t RemainBullet = 0; if (bBulletCheck) { decreaseBullet(pWeapon); // 한발쓸때마다 저장할 필요 없다. by sigi. 2002.5.9 // pWeapon->save(pSlayer->getName(), STORAGE_GEAR, 0, Slayer::WEAR_RIGHTHAND, 0); RemainBullet = getRemainBullet(pWeapon); } // 데미지, 투힛 보너스, 좌표와 방향을 구한다. int ToHitBonus = 0; int DamageBonus = 0; int ToHitPenalty = 0; int DamagePenalty = 0; ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); Dir_t dir = calcDirection(myX, myY, X, Y); bool bHit = false; // 한번이라도 맞았는가를 저장하기 위한 변수 Damage_t Damage = 0; // 마지막으로 입힌 데미지를 저장하기 위한 변수 // AR이나 SMG일 경우에는 2부터 시작해서 4까지의 splash 데미지를 입힌다. int Splash = 1 + pSkillSlot->getExpLevel()/30 + 1; if (bManaCheck && bTimeCheck && bRangeCheck && bBulletCheck) { decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // 음수 값이 돌아온다. ToHitPenalty = getPercentValue(pSlayer->getToHit(), output.ToHit); list<Creature*> cList; list<Creature*> creatureList; getSplashVictims(pZone, X, Y, Creature::CREATURE_CLASS_MAX, creatureList, Splash); Level_t maxEnemyLevel = 0; uint EnemyNum = 0; list<Creature*>::iterator itr = creatureList.begin(); for (; itr != creatureList.end(); itr++) { Creature* pTargetCreature = (*itr); Assert(pTargetCreature != NULL); ToHitBonus = computeArmsWeaponToHitBonus(pWeapon, myX, myY, pTargetCreature->getX(), pTargetCreature->getY()); DamageBonus = computeArmsWeaponDamageBonus(pWeapon, myX, myY, pTargetCreature->getX(), pTargetCreature->getY()); bool bInvokerCheck = (pTargetCreature->getObjectID() == pSlayer->getObjectID()) ? true : false; bool bRaceCheck = pTargetCreature->isSlayer() || pTargetCreature->isNPC(); bool bHitRoll = HitRoll::isSuccess(pSlayer, pTargetCreature, ToHitPenalty + ToHitBonus); bool bPK = verifyPK(pSlayer, pTargetCreature); bool bZoneLevelCheck = checkZoneLevelToHitTarget(pTargetCreature); if (pTargetCreature->isFlag(Effect::EFFECT_CLASS_NO_DAMAGE ) || pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA ) ) { bHitRoll = false; } if (!bInvokerCheck && !bRaceCheck && bHitRoll && bPK && bZoneLevelCheck) { bool bCriticalHit = false; // 데미지를 계산해서 페널티를 가한다. // 보너스는 멀티샷 페널티 때문에 음수가 될 수도 있다. Damage = computeDamage(pSlayer, pTargetCreature, SkillLevel/5, bCriticalHit); DamagePenalty = getPercentValue(Damage, output.Damage); Damage = max(0, Damage + DamagePenalty + DamageBonus); // 메인 타겟을 제외하고는, 스플래시 데미지를 입는데, // 스플래시 데미지는 일반 데미지의 50%다. if (pTargetCreature->getX() != X || pTargetCreature->getY() != Y) { Damage = Damage/2; } // 소드웨이브와는 달리 크로스 카운터 체크는 하지 않는다. ObjectID_t targetObjectID = pTargetCreature->getObjectID(); cList.push_back(pTargetCreature); _GCSkillToTileOK1.addCListElement(targetObjectID); _GCSkillToTileOK2.addCListElement(targetObjectID); _GCSkillToTileOK5.addCListElement(targetObjectID); setDamage(pTargetCreature, Damage, pSlayer, getSkillType(), NULL, &_GCSkillToTileOK1); computeAlignmentChange(pTargetCreature, Damage, pSlayer, NULL, &_GCSkillToTileOK1); // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bCriticalHit) { knockbackCreature(pZone, pTargetCreature, pSlayer->getX(), pSlayer->getY()); } // 슬레이어가 아닐 경우에만 맞춘 걸로 간주한다. if (!pTargetCreature->isSlayer()) { bHit = true; if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel(); EnemyNum++; } } } if (bHit) { if (bIncreaseExp) { increaseDomainExp(pSlayer, DomainType , pSkillInfo->getPoint(), _GCSkillToTileOK1, maxEnemyLevel, EnemyNum); shareAttrExp(pSlayer, Damage , 1, 8, 1, _GCSkillToTileOK1); } increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToTileOK1); } _GCSkillToTileOK1.addShortData(MODIFY_BULLET, RemainBullet); decreaseDurability(pSlayer, NULL, pSkillInfo, &_GCSkillToTileOK1, NULL); _GCSkillToTileOK1.setSkillType(getSkillType()); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setRange(dir); _GCSkillToTileOK1.setDuration(0); _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(getSkillType()); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setRange(dir); _GCSkillToTileOK2.setDuration(0); _GCSkillToTileOK3.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK3.setSkillType(getSkillType()); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(getSkillType()); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(0); _GCSkillToTileOK4.setRange(dir); _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(getSkillType()); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(dir); _GCSkillToTileOK5.setDuration(0); pPlayer->sendPacket(&_GCSkillToTileOK1); // 이 기술에 의해 영향을 받는 놈들에게 패킷을 보내줘야 한다. for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; Assert(pTargetCreature != NULL); if (pTargetCreature->isPC()) { _GCSkillToTileOK2.clearList(); HP_t targetHP = 0; if (pTargetCreature->isSlayer()) { targetHP = (dynamic_cast<Slayer*>(pTargetCreature))->getHP(); } else if (pTargetCreature->isVampire()) { targetHP = (dynamic_cast<Vampire*>(pTargetCreature))->getHP(); } _GCSkillToTileOK2.addShortData(MODIFY_CURRENT_HP, targetHP); // 아이템의 내구력을 떨어뜨린다. decreaseDurability(NULL, pTargetCreature, pSkillInfo, NULL, &_GCSkillToTileOK2); // 패킷을 보내준다. Player* pPlayer = pTargetCreature->getPlayer(); Assert(pPlayer != NULL); pPlayer->sendPacket(&_GCSkillToTileOK2); } else if (pTargetCreature->isMonster()) { // 당근 적으로 인식한다. Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pSlayer); } } cList.push_back(pSlayer); cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormalWithGun(pSlayer, getSkillType(), NULL, RemainBullet); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " SGexecute End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 ////////////////////////////////////////////////////////////////////////////// void JabbingVein::execute (Slayer* pSlayer, ObjectID_t TargetObjectID, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY __BEGIN_DEBUG //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !canAttack(pSlayer, pTargetCreature ) || pTargetCreature->isNPC()) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } GCAttackArmsOK1 _GCAttackArmsOK1; GCAttackArmsOK2 _GCAttackArmsOK2; GCAttackArmsOK3 _GCAttackArmsOK3; GCAttackArmsOK4 _GCAttackArmsOK4; GCAttackArmsOK5 _GCAttackArmsOK5; // 들고 있는 무기가 없거나, 총 계열 무기가 아니라면 기술을 쓸 수 없다. // 총 계열 무기 중에서도 SG나 SR은 JabbingVein를 쓸 수가 없다. // SG, SR 도 이제 쓸 수 있다. // 2003. 1. 14 by bezz Item* pWeapon = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND); if (pWeapon == NULL || isArmsWeapon(pWeapon) == false ) // pWeapon->getItemClass() == Item::ITEM_CLASS_SG || // pWeapon->getItemClass() == Item::ITEM_CLASS_SR) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } bool bIncreaseExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND); SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; if (pTargetCreature->isPC() ) { input.TargetType = SkillInput::TARGET_PC; } else { input.TargetType = SkillInput::TARGET_MONSTER; } computeOutput(input, output); // 페널티 값을 계산한다. int ToHitPenalty = getPercentValue(pSlayer->getToHit(), output.ToHit); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, pTargetCreature, pWeapon->getRange()); bool bBulletCheck = (getRemainBullet(pWeapon) > 0) ? true : false; bool bHitRoll = HitRoll::isSuccess(pSlayer, pTargetCreature, ToHitPenalty); bool bPK = verifyPK(pSlayer, pTargetCreature); // 총알 숫자는 무조건 떨어뜨린다. Bullet_t RemainBullet = 0; if (bBulletCheck) { // 총알 숫자를 떨어뜨리고, 저장하고, 남은 총알 숫자를 받아온다. decreaseBullet(pWeapon); // 한발쓸때마다 저장할 필요 없다. by sigi. 2002.5.9 //pWeapon->save(pSlayer->getName(), STORAGE_GEAR, 0, Slayer::WEAR_RIGHTHAND, 0); RemainBullet = getRemainBullet(pWeapon); } if (bManaCheck && bTimeCheck && bRangeCheck && bBulletCheck && bHitRoll && bPK) { //cout << pSlayer->getName().c_str() << " Attack OK" << endl; decreaseMana(pSlayer, RequiredMP, _GCAttackArmsOK1); _GCAttackArmsOK5.setSkillSuccess(true); _GCAttackArmsOK1.setSkillSuccess(true); bool bCriticalHit = false; // 데미지를 계산하고, quickfire 페널티를 가한다. // output.Damage가 음수이기 때문에, %값을 구해 더하면 결국 빼는 것이 된다. int Damage = computeDamage(pSlayer, pTargetCreature, SkillLevel/5, bCriticalHit); Damage += getPercentValue(Damage, output.Damage); Damage = max(0, Damage); //cout << "JabbingVeinDamage:" << Damage << endl; // 데미지를 세팅한다. setDamage(pTargetCreature, Damage, pSlayer, SkillType, &_GCAttackArmsOK2, &_GCAttackArmsOK1); computeAlignmentChange(pTargetCreature, Damage, pSlayer, &_GCAttackArmsOK2, &_GCAttackArmsOK1); bool bAffect = true; if (pTargetCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); if (pMonster->isMaster() ) bAffect = false; } if (bAffect && !pTargetCreature->isFlag(Effect::EFFECT_CLASS_JABBING_VEIN) && rand()%100 < output.Range ) { EffectJabbingVein* pEffect = new EffectJabbingVein(pTargetCreature); pEffect->setDeadline(output.Duration); pTargetCreature->addEffect(pEffect); pTargetCreature->setFlag(pEffect->getEffectClass()); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pTargetCreature->getObjectID()); gcAddEffect.setEffectID(pEffect->getSendEffectClass()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &gcAddEffect); } // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bCriticalHit) { knockbackCreature(pZone, pTargetCreature, pSlayer->getX(), pSlayer->getY()); } if(!pTargetCreature->isSlayer() ) { if (bIncreaseExp) { shareAttrExp(pSlayer, Damage , 1, 8, 1, _GCAttackArmsOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCAttackArmsOK1, pTargetCreature->getLevel()); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCAttackArmsOK1); } increaseAlignment(pSlayer, pTargetCreature, _GCAttackArmsOK1); } //} if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); if (pTargetPlayer != NULL) { _GCAttackArmsOK2.setObjectID(getSkillType()); _GCAttackArmsOK2.setObjectID(pSlayer->getObjectID()); pTargetPlayer->sendPacket(&_GCAttackArmsOK2); } } else if (pTargetCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pSlayer); } // 공격자와 상대의 아이템 내구성 떨어트림. decreaseDurability(pSlayer, pTargetCreature, NULL, &_GCAttackArmsOK1, &_GCAttackArmsOK2); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); _GCAttackArmsOK1.setSkillType(getSkillType()); _GCAttackArmsOK1.setObjectID(TargetObjectID); _GCAttackArmsOK1.setBulletNum(RemainBullet); _GCAttackArmsOK3.setSkillType(getSkillType()); _GCAttackArmsOK3.setObjectID(pSlayer->getObjectID()); _GCAttackArmsOK3.setTargetXY (targetX, targetY); _GCAttackArmsOK4.setSkillType(getSkillType()); _GCAttackArmsOK4.setTargetObjectID (TargetObjectID); _GCAttackArmsOK5.setSkillType(getSkillType()); _GCAttackArmsOK5.setObjectID(pSlayer->getObjectID()); _GCAttackArmsOK5.setTargetObjectID (TargetObjectID); pPlayer->sendPacket(&_GCAttackArmsOK1); list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pSlayer); cList = pZone->broadcastSkillPacket(myX, myY, targetX, targetY, &_GCAttackArmsOK5, cList); pZone->broadcastPacket(myX, myY, &_GCAttackArmsOK3, cList); pZone->broadcastPacket(targetX, targetY, &_GCAttackArmsOK4, cList); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormalWithGun(pSlayer, getSkillType(), pTargetCreature, RemainBullet); //cout << pSlayer->getName().c_str() << " Fail : " // << (int)bManaCheck << (int)bTimeCheck << (int)bRangeCheck // << (int)bBulletCheck << (int)bHitRoll << (int)bPK << endl; } } catch (Throwable &t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_DEBUG __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 아우스터즈 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void SummonGroundElemental::execute(Ousters* pOusters, ZoneCoord_t X, ZoneCoord_t Y, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); BYTE Grade = 0; if (pOustersSkillSlot->getExpLevel() < 15 ) Grade = 0; else if (pOustersSkillSlot->getExpLevel() < 30 ) Grade = 1; else Grade = 2; try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pOustersSkillSlot->getSkillType(), Grade); return; } GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); // 데미지와 지속 시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel()/3; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); // if (rect.ptInRect(X, Y)) // { // Tile& tile = pZone->getTile(X, Y); // if (tile.canAddEffect()) bTileCheck = true; // } TPOINT pt = findSuitablePosition(pZone, X, Y, Creature::MOVE_MODE_WALKING); if (pt.x == -1 ) { bTileCheck = false; } else { bTileCheck = true; for (int oX = pt.x - 2 ; oX <= pt.x + 2 ; ++oX ) for (int oY = pt.y - 2 ; oY <= pt.y + 2 ; ++oY ) { if (!rect.ptInRect(oX, oY ) ) continue; if (pZone->getTile(oX, oY).getEffect(Effect::EFFECT_CLASS_GROUND_ELEMENTAL_AURA ) != NULL ) { bTileCheck = false; break; } } } if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToTileOK1); int oX, oY; /* HP = 200 + (S_level * 10) Defense = 50 + (S_level * 2) Protection = 20 + (S_level * 2) Poison Resistance = 70% Acid Resistance = 60% Curse Resistance = 100% Blood Resistance = 50% Regen = 1 HP per 1 sec */ Monster* pGroundElemental = new Monster(GROUND_ELEMENTAL_TYPE); pGroundElemental->setName("대지 정령"); pGroundElemental->setHP(1000 + input.SkillLevel * 100); pGroundElemental->setHP(1000 + input.SkillLevel * 100, ATTR_MAX); pGroundElemental->setDefense(0); pGroundElemental->setProtection(0); pGroundElemental->setResist(MAGIC_DOMAIN_POISON, 0); pGroundElemental->setResist(MAGIC_DOMAIN_ACID, 0); pGroundElemental->setResist(MAGIC_DOMAIN_CURSE, 0); pGroundElemental->setResist(MAGIC_DOMAIN_BLOOD, 0); pGroundElemental->setFlag(Effect::EFFECT_CLASS_IMMUNE_TO_CURSE); pGroundElemental->removeFlag(Effect::EFFECT_CLASS_HIDE); pGroundElemental->setMoveMode(Creature::MOVE_MODE_WALKING); // 무뇌정령 pGroundElemental->setBrain(NULL); pZone->addCreature(pGroundElemental, X, Y, 2); X = pGroundElemental->getX(); Y = pGroundElemental->getY(); //cout << pGroundElemental->toString() << " 을 " << X << ", " << Y << " 에 불러냈습니다." << endl; EffectGroundElemental* pCreatureEffect = new EffectGroundElemental(pGroundElemental); pCreatureEffect->setDeadline(output.Duration); pGroundElemental->setFlag(pCreatureEffect->getEffectClass()); pGroundElemental->addEffect(pCreatureEffect); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pGroundElemental->getObjectID()); gcAddEffect.setEffectID(pCreatureEffect->getSendEffectClass()); pZone->broadcastPacket(X, Y, &gcAddEffect); // addSimpleCreatureEffect(pGroundElemental, Effect::EFFECT_CLASS_GROUND_ELEMENTAL_CENTER); // for (int i = 0; i < m_MaskIndex[Grade]; ++i ) for (oX = X - 2 ; oX <= X + 2 ; ++oX ) for (oY = Y - 2 ; oY <= Y + 2 ; ++oY ) { // oX = m_ElementalMask[Grade][i].x; // oY = m_ElementalMask[Grade][i].y; if (!rect.ptInRect(oX, oY)) continue; if (oX == X && oY == Y ) continue; Tile& tile = pZone->getTile(oX, oY); if (!tile.canAddEffect()) continue; if (tile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION) ) continue; // 같은 이펙트가 이미 존재한다면 삭제한다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_GROUND_ELEMENTAL_AURA); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID); } // 이펙트 오브젝트를 생성한다. EffectSummonGroundElemental* pEffect = new EffectSummonGroundElemental(pZone, oX, oY); pEffect->setDeadline(output.Duration); // 타일에 붙은 이펙트는 OID를 받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); // 존 및 타일에다가 이펙트를 추가한다. pZone->addEffect(pEffect); tile.addEffect(pEffect); GCAddEffectToTile gcAddEffect; gcAddEffect.setXY(oX, oY); gcAddEffect.setEffectID(pEffect->getSendEffectClass()); gcAddEffect.setObjectID(pEffect->getObjectID()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(oX, oY, &gcAddEffect); } ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setGrade(Grade); _GCSkillToTileOK3.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK3.setGrade(Grade); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK4.setGrade(Grade); _GCSkillToTileOK5.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setGrade(Grade); pPlayer->sendPacket(&_GCSkillToTileOK1); list<Creature*> cList; cList.push_back(pOusters); cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL, Grade); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType(), Grade); //cout << t.toString() << endl; } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void GroundBless::execute(Ousters* pOusters, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayer)" << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pOustersSkillSlot->getSkillType()); return; } GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); //SkillDomainType_t DomainType = pSkillInfo->getDomainType(); //SkillLevel_t SkillLevel = pOustersSkillSlot->getExpLevel(); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel()/2; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pOusters); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bEffected = pOusters->isFlag(Effect::EFFECT_CLASS_GROUND_BLESS); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToSelfOK1); // 지속 시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; input.STR = pOusters->getSTR(ATTR_BASIC); input.DEX = pOusters->getDEX(ATTR_BASIC); input.INTE = pOusters->getINT(ATTR_BASIC); computeOutput(input, output); // 이팩트 클래스를 만들어 붙인다. EffectGroundBless* pEffect = new EffectGroundBless(pOusters); pEffect->setDeadline(output.Duration); pEffect->setBonus(output.Damage); pOusters->addEffect(pEffect); pOusters->setFlag(Effect::EFFECT_CLASS_GROUND_BLESS); pOusters->initAllStatAndSend(); _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pOusters->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(pOusters->getX(), pOusters->getY(), &_GCSkillToSelfOK2, pOusters); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pOusters->getObjectID()); gcAddEffect.setEffectID(pEffect->getEffectClass()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pOusters->getX(), pOusters->getY(), &gcAddEffect); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayer)" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////// // // ThunderFlash::execute() // ////////////////////////////////////////////////////////////////////// void ThunderFlash::execute(Slayer* pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); // 무장하고 있는 무기가 널이거나, SWORD가 아니라면 사용할 수 없다. Item* pItem = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND); if (pItem == NULL || pItem->getItemClass() != Item::ITEM_CLASS_SWORD) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end" << endl; return; } bool bIncreaseExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK5 _GCSkillToTileOK5; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange()); // 마나가 있어야 하고, 시간과 거리 체크에 성공하고, if (bManaCheck && bTimeCheck && bRangeCheck) { // MP를 떨어뜨린다. decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); // 좌표와 방향을 구한다. ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); Dir_t dir = calcDirection(myX, myY, X, Y); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); Damage_t SkillDamage = output.Damage; Damage_t Damage = 0; bool bHit = false; Level_t maxEnemyLevel = 0; uint EnemyNum = 0; VSRect rect(1, 1, pZone->getWidth()-2, pZone->getHeight()-2); list<Creature*> cList; for (int count=0; count<4; count++) { int tileX = X + m_pThunderFlashMask[count].x; int tileY = Y + m_pThunderFlashMask[count].y; // 현재 타일이 존 내부이고, 안전지대가 아니라면, 맞을 확률이 있다. if (rect.ptInRect(tileX, tileY)) { // 타일을 받아온다. Tile& tile = pZone->getTile(tileX, tileY); list<Creature*> targetList; if (tile.hasCreature(Creature::MOVE_MODE_WALKING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); targetList.push_back(pCreature); } list<Creature*>::iterator itr = targetList.begin(); for(; itr != targetList.end(); itr++) { Creature* pTargetCreature = (*itr); Assert(pTargetCreature != NULL); bool bMoveModeCheck = (pTargetCreature->getMoveMode() == Creature::MOVE_MODE_WALKING) ? true : false; bool bHitRoll = HitRoll::isSuccess(pSlayer, pTargetCreature, SkillLevel/2); //bool bCanHit = canHit(pSlayer, pTargetCreature, SkillType); bool bCanHit = true; bool bPK = verifyPK(pSlayer, pTargetCreature); bool bRaceCheck = pTargetCreature->isSlayer() || pTargetCreature->isNPC(); bool bZoneLevelCheck = checkZoneLevelToHitTarget(pTargetCreature); if (bMoveModeCheck && bHitRoll && bCanHit && bPK && !bRaceCheck && bZoneLevelCheck) { CheckCrossCounter(pSlayer, pTargetCreature, Damage, pSkillInfo->getRange()); bool bCriticalHit = false; Damage = computeDamage(pSlayer, pTargetCreature, SkillLevel/5, bCriticalHit) + SkillDamage; ObjectID_t targetObjectID = pTargetCreature->getObjectID(); cList.push_back(pTargetCreature); _GCSkillToTileOK1.addCListElement(targetObjectID); _GCSkillToTileOK2.addCListElement(targetObjectID); _GCSkillToTileOK5.addCListElement(targetObjectID); // 일단 맞는 놈이 받을 패킷은 널 상태로 한 채로, 데미지를 준다. setDamage(pTargetCreature, Damage, pSlayer, SkillType, NULL, &_GCSkillToTileOK1); computeAlignmentChange(pTargetCreature, Damage, pSlayer, NULL, &_GCSkillToTileOK1); increaseAlignment(pSlayer, pTargetCreature, _GCSkillToTileOK1); // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bCriticalHit) { knockbackCreature(pZone, pTargetCreature, pSlayer->getX(), pSlayer->getY()); } // 슬레이어가 아닐 경우에만 맞은 것으로 간주한다. if (!pTargetCreature->isSlayer()) { bHit = true; if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel(); EnemyNum++; } } } //for (; itr != objectList.end(); itr++) } // if (rect.ptInRect(tileX, tileY) && ... } // for (int count=0; count<3; count++) if (bHit) { if (bIncreaseExp) { shareAttrExp(pSlayer, Damage , 8, 1, 1, _GCSkillToTileOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToTileOK1, maxEnemyLevel, EnemyNum); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToTileOK1); } } // 공격자 아이템 내구성 떨어트림. decreaseDurability(pSlayer, NULL, pSkillInfo, &_GCSkillToTileOK1, NULL); _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setRange(dir); _GCSkillToTileOK1.setDuration(0); _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setRange(dir); _GCSkillToTileOK2.setDuration(0); _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(dir); _GCSkillToTileOK5.setDuration(0); pPlayer->sendPacket(&_GCSkillToTileOK1); // 이 기술에 의해 영향을 받는 놈들에게 패킷을 보내줘야 한다. for (list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature * pTargetCreature = *itr; Assert(pTargetCreature != NULL); if (pTargetCreature->isPC()) { _GCSkillToTileOK2.clearList(); // HP의 변경사항을 패킷에다 기록한다. HP_t targetHP = 0; if (pTargetCreature->isSlayer()) targetHP = (dynamic_cast<Slayer*>(pTargetCreature))->getHP(ATTR_CURRENT); else if (pTargetCreature->isVampire()) targetHP = (dynamic_cast<Vampire*>(pTargetCreature))->getHP(ATTR_CURRENT); _GCSkillToTileOK2.addShortData(MODIFY_CURRENT_HP, targetHP); // 아이템의 내구력을 떨어뜨린다. decreaseDurability(NULL, pTargetCreature, pSkillInfo, NULL, &_GCSkillToTileOK2); // 패킷을 보내준다. pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); } else if (pTargetCreature->isMonster()) { // 당근 적으로 인식한다. Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pSlayer); } } cList.push_back(pSlayer); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK5 , cList); // set Next Run Time pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 아우스터즈 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void ChargingAttack::execute(Ousters * pOusters, ObjectID_t TargetObjectID, OustersSkillSlot * pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NoSuch제거. by sigi. 2002.5.2 // NPC는 공격할 수가 없다. if (pTargetCreature==NULL || pTargetCreature->isNPC()) { executeSkillFailException(pOusters, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } // 무장하고 있는 무기가 널이거나, 검이 아니라면 기술을 사용할 수 없다. Item* pItem = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pItem == NULL) { executeSkillFailException(pOusters, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillLevel_t SkillLevel = pOustersSkillSlot->getExpLevel(); SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, pTargetCreature, output.Range); bool bHitRoll = HitRoll::isSuccess(pOusters, pTargetCreature, SkillLevel/2); bool bCanHit = canHit(pOusters, pTargetCreature, SkillType) && canAttack(pOusters, pTargetCreature); bool bPK = verifyPK(pOusters, pTargetCreature); bool bEffected = pOusters->hasRelicItem() || pOusters->isFlag(Effect::EFFECT_CLASS_HAS_FLAG) || pOusters->isFlag(Effect::EFFECT_CLASS_HAS_SWEEPER); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bCanHit && bPK && !bEffected ) { // 빠르게 PC를 움직여준다. if (pZone->moveFastPC(pOusters, pOusters->getX(), pOusters->getY(), pTargetCreature->getX(), pTargetCreature->getY(), getSkillType())) { decreaseMana(pOusters, RequiredMP, _GCSkillToObjectOK1); bool bCriticalHit = false; // 데미지를 준다. Damage_t Damage = computeDamage(pOusters, pTargetCreature, 0, bCriticalHit) + output.Damage; setDamage(pTargetCreature, Damage, pOusters, SkillType, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pOusters, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); decreaseDurability(pOusters, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK2); // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bCriticalHit) { knockbackCreature(pZone, pTargetCreature, pOusters->getX(), pOusters->getY()); } if (pTargetCreature->isDead()) { int exp = computeCreatureExp(pTargetCreature, 100, pOusters); shareOustersExp(pOusters, exp, _GCSkillToObjectOK1); } // 패킷을 준비하고 보낸다. _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); pPlayer->sendPacket(&_GCSkillToObjectOK1); _GCSkillToObjectOK2.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(0); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } else { Monster * pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pOusters); } pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), pTargetCreature); } } else { executeSkillFailNormal(pOusters, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void RefusalEther::execute(Ousters* pOusters, ZoneCoord_t X, ZoneCoord_t Y, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); BYTE Grade = 0; if (pOustersSkillSlot->getExpLevel() < 15 ) Grade = 0; else if (pOustersSkillSlot->getExpLevel() < 30 ) Grade = 1; else Grade = 2; try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pOustersSkillSlot->getSkillType(), Grade); return; } GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); // 이펙트의 지속시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel()/3; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) bTileCheck = true; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToTileOK1); list<Creature*> cList; for (int ox = X-output.Range; ox <= X+output.Range; ++ox ) for (int oy = Y-output.Range; oy <= Y+output.Range; ++oy ) { if (!rect.ptInRect(ox,oy) ) continue; Tile& rTile = pZone->getTile(ox,oy); EffectDarkness* pEffect = dynamic_cast<EffectDarkness*>(rTile.getEffect(Effect::EFFECT_CLASS_DARKNESS)); int ratio = 0; if (pEffect != NULL ) { if (input.SkillLevel <= 15 ) { ratio = (int)(pOusters->getLevel() + (input.SkillLevel * 8.0 / 3.0 ) - pEffect->getLevel()); } else { ratio = (int)(pOusters->getLevel() + 20 + (input.SkillLevel * 4.0 / 3.0 ) - pEffect->getLevel()); if (input.SkillLevel == 30 ) ratio = (int)(ratio * 1.1); } ratio = max(20, ratio); } else { continue; } bool bHitRoll2 = (rand()%100) < ratio; if (bHitRoll2) { pZone->deleteEffect(pEffect->getObjectID()); Creature* pTargetCreature = NULL; if (rTile.hasCreature(Creature::MOVE_MODE_WALKING)) pTargetCreature = rTile.getCreature(Creature::MOVE_MODE_WALKING); GCDeleteEffectFromTile gcDeleteEffectFromTile; gcDeleteEffectFromTile.setXY(ox, oy); gcDeleteEffectFromTile.setObjectID(pEffect->getObjectID()); gcDeleteEffectFromTile.setEffectID(Effect::EFFECT_CLASS_DARKNESS); pZone->broadcastPacket(ox, oy, &gcDeleteEffectFromTile); if (pTargetCreature != NULL && pTargetCreature->isPC() && pTargetCreature->getObjectID() != pOusters->getObjectID() ) cList.push_back(pTargetCreature); } } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(0); _GCSkillToTileOK1.setGrade(Grade); _GCSkillToTileOK2.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(0); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, ICE_FIELD_SIGHT); _GCSkillToTileOK2.setGrade(Grade); _GCSkillToTileOK3.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK3.setGrade(Grade); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setRange(0); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK4.setGrade(Grade); _GCSkillToTileOK5.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(0); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setGrade(Grade); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(0); //_GCSkillToTileOK6.addShortData(MODIFY_VISION, ICE_FIELD_SIGHT); _GCSkillToTileOK6.setGrade(Grade); pPlayer->sendPacket(&_GCSkillToTileOK1); list<Creature*>::iterator itr = cList.begin(); list<Creature*>::iterator endItr = cList.end(); for (; itr != endItr ; ++itr ) { if ((*itr)->isPC() ) { (*itr)->getPlayer()->sendPacket(&_GCSkillToTileOK2); } } cList.push_back(pOusters); cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList, false); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL, Grade); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType(), Grade); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 ////////////////////////////////////////////////////////////////////////////// void InstallTurret::execute(Slayer * pSlayer, SkillSlot * pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND); if (pWeapon == NULL || !isArmsWeapon(pWeapon) || pSlayer->hasRelicItem()) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } bool bIncreaseDomainExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); ZoneCoord_t X = pSlayer->getX(); ZoneCoord_t Y = pSlayer->getY(); Tile& rTile = pZone->getTile(X,Y); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_INSTALL_TURRET); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); EffectInstallTurret* pEffect = new EffectInstallTurret(pSlayer); pEffect->setDeadline(output.Duration); pEffect->setDamage(output.Damage); pEffect->setDefense(output.ToHit); //cout << "Turret Duration : " << output.Duration << endl; //cout << "Turret Delay : " << output.Delay << endl; pSlayer->setFlag(pEffect->getEffectClass()); pSlayer->addEffect(pEffect); GCAddEffect gcAE; gcAE.setObjectID(pSlayer->getObjectID()); gcAE.setDuration(output.Duration); gcAE.setEffectID(pEffect->getSendEffectClass()); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcAE); SLAYER_RECORD prev; pSlayer->getSlayerRecord(prev); pSlayer->initAllStat(); pSlayer->sendRealWearingInfo(); pSlayer->addModifyInfo(prev, _GCSkillToSelfOK1); // 패킷을 만들어 보낸다. _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); // Send Packet pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(X, Y, &_GCSkillToSelfOK2, pSlayer); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); //cout << t.toString() << endl; } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void MindControl::execute(Slayer* pSlayer, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayerself)" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_MIND_CONTROL); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // 이펙트를 만들어 붙인다. EffectMindControl* pEffect = new EffectMindControl(pSlayer); pEffect->setDeadline(output.Duration); pEffect->setDefenseBonus(output.Damage); pEffect->setToHitBonus(output.Damage); pSlayer->setFlag(Effect::EFFECT_CLASS_MIND_CONTROL); pSlayer->addEffect(pEffect); // 이펙트를 붙였으니, 능력치를 재계산한다. SLAYER_RECORD prev; pSlayer->getSlayerRecord(prev); pSlayer->initAllStat(); pSlayer->sendRealWearingInfo(); pSlayer->addModifyInfo(prev, _GCSkillToSelfOK1); // 경험치를 올려준다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1); shareAttrExp(pSlayer, ExpUp, 1, 8, 1, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(myX, myY, &_GCSkillToSelfOK2, pSlayer); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pSlayer->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_MIND_CONTROL); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(myX, myY, &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayerself)" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void ProtectionFromAcid::execute(Slayer* pSlayer, ObjectID_t TargetObjectID, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !pTargetCreature->isSlayer() ) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK5 _GCSkillToObjectOK5; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_PROTECTION_FROM_ACID); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { // 마나를 줄인다. decreaseMana(pSlayer, RequiredMP, _GCSkillToObjectOK1); // 경험치를 올려준다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1); shareAttrExp(pSlayer, ExpUp, 1, 1, 8, _GCSkillToObjectOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToObjectOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToObjectOK1); // 이펙트의 효과와 지속시간을 계산한다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; input.TargetType = SkillInput::TARGET_OTHER; computeOutput(input, output); // 이펙트를 생성해서 붙인다. EffectProtectionFromAcid* pEPFP = new EffectProtectionFromAcid (pTargetCreature); Assert(pEPFP != NULL); pEPFP->setDeadline(output.Duration); pEPFP->setResist(output.Damage); pTargetCreature->addEffect(pEPFP); pTargetCreature->setFlag(Effect::EFFECT_CLASS_PROTECTION_FROM_ACID); if (pTargetCreature->isSlayer()) { Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature); SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->addModifyInfo(prev, _GCSkillToObjectOK1); } else { Assert(false); } // 패킷을 준비해서 보낸다. _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(output.Duration); _GCSkillToObjectOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration (output.Duration); _GCSkillToObjectOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration (output.Duration); // Send Packet pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pSlayer != pTargetCreature && pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } list<Creature*> cList; cList.push_back(pSlayer); cList.push_back(pTargetCreature); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &_GCSkillToObjectOK5 , cList); // 이펙트가 붙었다고 알려준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pTargetCreature->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_PROTECTION_FROM_ACID); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
void InstallMine::execute(Slayer* pSlayer, ObjectID_t, CoordInven_t X, CoordInven_t Y, CoordInven_t TargetX, CoordInven_t TargetY, SkillSlot* pSkillSlot) throw(Error) { __BEGIN_TRY Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToInventoryOK1 _GCSkillToInventoryOK1; // GCSkillToTileOK1 _GCSkillToTileOK1; // GCSkillToTileOK5 _GCSkillToTileOK5; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo * pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); // 명중률. //ToHit_t ToHit = pSlayer->getToHit(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); ZoneCoord_t slayerX = pSlayer->getX(), slayerY = pSlayer->getY(); bool bInstallAction = false; Mine* pMine = NULL; Inventory * pInventory = pSlayer->getInventory(); Assert(pInventory != NULL); if(bManaCheck && bTimeCheck &&bRangeCheck ) { // mine을 찾는다. Item* pItem = pInventory->getItem(X, Y); if(pItem != NULL && pItem->getItemClass() == Item::ITEM_CLASS_MINE) { bInstallAction = true; pMine = dynamic_cast<Mine*>(pItem); } } // 기술의 성패를 따진다. if (bInstallAction ) { //Range_t Range = 1; GCSkillToInventoryOK1 _GCSkillToInventoryOK1; // GCSkillToInventoryOK5 _GCSkillToInventoryOK5; ItemInfo* pItemInfo = g_pItemInfoManager->getItemInfo(Item::ITEM_CLASS_MINE, pMine->getItemType()); Damage_t MinDamage = pItemInfo->getMinDamage(); Damage_t MaxDamage = pItemInfo->getMaxDamage(); Damage_t RealDamage = MinDamage + (max (0, ((int)MaxDamage * (int)SkillLevel / 100 ) - MinDamage )); Mine * pInstallMine = new Mine(); ObjectRegistry& OR = pZone->getObjectRegistry(); OR.registerObject(pInstallMine); Assert(pInstallMine != NULL); pInstallMine->setItemType(pMine->getItemType()); pInstallMine->setDir(TargetX); pInstallMine->setDamage(RealDamage); pInstallMine->setInstallerName(pSlayer->getName()); pInstallMine->setInstallerPartyID(pSlayer->getPartyID()); pInstallMine->setFlag(Effect::EFFECT_CLASS_INSTALL); // 아이템 사라지는게 3분인거 때문에 지뢰도 사라졌는데.. // 10분으로 고정. by sigi. 2002.11.3 TPOINT pt = pZone->addItem(pInstallMine, slayerX, slayerY, true, 6000); // EXP up Exp_t Point = pSkillInfo->getPoint(); shareAttrExp(pSlayer, 100, 1, 8, 1, _GCSkillToInventoryOK1); increaseDomainExp(pSlayer, SKILL_DOMAIN_GUN, Point, _GCSkillToInventoryOK1); increaseSkillExp(pSlayer, SKILL_DOMAIN_GUN, pSkillSlot, pSkillInfo, _GCSkillToInventoryOK1); decreaseMana(pSlayer, RequiredMP, _GCSkillToInventoryOK1); decreaseItemNum(pMine, pInventory, pSlayer->getName(), STORAGE_INVENTORY, 0, X, Y); _GCSkillToInventoryOK1.setObjectID(pInstallMine->getObjectID()); _GCSkillToInventoryOK1.setSkillType(SkillType); _GCSkillToInventoryOK1.setCEffectID(0); _GCSkillToInventoryOK1.setX(X); _GCSkillToInventoryOK1.setY(Y); _GCSkillToInventoryOK1.setDuration(0); /* _GCSkillToInventoryOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToInventoryOK5.setSkillType(SkillType); _GCSkillToInventoryOK5.setX(X); _GCSkillToInventoryOK5.setY(Y); _GCSkillToInventoryOK5.setRange(Range); _GCSkillToInventoryOK5.setDuration(0); */ pPlayer->sendPacket(&_GCSkillToInventoryOK1); // mine을 볼 수 없게 된 자들에게는 삭제 addInstalledMine(pZone, pInstallMine, pt.x, pt.y); // pZone->broadcastPacket(slayerX, slayerY, &_GCSkillToInventoryOK5, pSlayer); // cout << "Run Skill : " << (int)SkillType << endl; // Set NextTime pSkillSlot->setRunTime(); } else { GCSkillFailed1 _GCSkillFailed1; GCSkillFailed2 _GCSkillFailed2; executeSkillFailException(pSlayer, getSkillType()); } } catch(Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } __END_CATCH }
void SimpleMissileSkill::execute( Ousters* pOusters, ObjectID_t TargetObjectID, OustersSkillSlot* pOustersSkillSlot, const SIMPLE_SKILL_INPUT& param, SIMPLE_SKILL_OUTPUT& result, CEffectID_t CEffectID, int HitBonus) throw(Error) { __BEGIN_TRY Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); // NPC는 공격할 수가 없다. // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !canAttack(pOusters, pTargetCreature ) || pTargetCreature->isNPC() ) { executeSkillFailException(pOusters, param.SkillType, param.Grade); return; } result.pTargetCreature = pTargetCreature; GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; if (param.ItemClass != Item::ITEM_CLASS_MAX) { Item* pItem = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pItem == NULL || pItem->getItemClass() != param.ItemClass || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, param.SkillType, param.Grade); return; } } SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(param.SkillType); bool bCriticalHit = false; Damage_t Damage = 0; if (param.bAdd) { // 파라미터로 전달된 데미지 값이 더해지는 데미지라면, // 일반 데미지를 계산 후, 데미지를 더해야 한다. // 파라미터로 전달된 데미지 값이 직접적으로 쓰이는 데미지라면, // 이 부분까지 들어오지 않으므로, 밑의 부분까지 0으로 전달된다. Damage += computeDamage(pOusters, pTargetCreature, 0, bCriticalHit); } if (param.bMagicDamage) { // 만일 스킬 데미지가 마법 데미지라면, 마법 데미지 계산 함수를 이용해 계산을 해준다. // Damage += computeMagicDamage(pTargetCreature, param.SkillDamage, param.SkillType, true); Damage += computeOustersMagicDamage(pOusters, pTargetCreature, param.SkillDamage, param.SkillType); } else { Damage += param.SkillDamage; } computeCriticalBonus(pOusters, param.SkillType, Damage, bCriticalHit); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = false; bool bCanHit = canHit(pOusters, pTargetCreature, param.SkillType); bool bPK = verifyPK(pOusters, pTargetCreature); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); if (param.bMagicHitRoll) { bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot, HitBonus); } else { bHitRoll = HitRoll::isSuccess(pOusters, pTargetCreature); } ZoneCoord_t X = pOusters->getX(); ZoneCoord_t Y = pOusters->getY(); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bCanHit && bPK && bSatisfyRequire ) { decreaseMana(pOusters, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pOusters); if (bCanSeeCaster) { setDamage(pTargetCreature, Damage, pOusters, param.SkillType, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pOusters, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); decreaseDurability(pOusters, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK2); } else { setDamage(pTargetCreature, Damage, pOusters, param.SkillType, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pOusters, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); decreaseDurability(pOusters, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK6); } if (pTargetCreature->isDead()) { int exp = computeCreatureExp(pTargetCreature, 100, pOusters); shareOustersExp(pOusters, exp, _GCSkillToObjectOK1); } increaseAlignment(pOusters, pTargetCreature, _GCSkillToObjectOK1); _GCSkillToObjectOK1.setSkillType(param.SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); _GCSkillToObjectOK1.setGrade(param.Grade); _GCSkillToObjectOK2.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK2.setSkillType(param.SkillType); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK2.setGrade(param.Grade); _GCSkillToObjectOK3.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK3.setSkillType(param.SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK3.setGrade(param.Grade); _GCSkillToObjectOK4.setSkillType(param.SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK4.setGrade(param.Grade); _GCSkillToObjectOK5.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setSkillType(param.SkillType); _GCSkillToObjectOK5.setGrade(param.Grade); _GCSkillToObjectOK6.setXY(X, Y); _GCSkillToObjectOK6.setSkillType(param.SkillType); _GCSkillToObjectOK6.setDuration(0); _GCSkillToObjectOK6.setGrade(param.Grade); pPlayer->sendPacket(&_GCSkillToObjectOK1); Player* pTargetPlayer = NULL; if (pTargetCreature->isPC()) { pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pOusters); } list<Creature*> cList; cList.push_back(pOusters); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(X, Y, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(X, Y, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); pOustersSkillSlot->setRunTime(param.Delay); result.bSuccess = true; } else { executeSkillFailNormal(pOusters, param.SkillType, pTargetCreature, param.Grade); } } catch (Throwable & t) { executeSkillFailException(pOusters, param.SkillType, param.Grade); } __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void TurnUndead::execute(Slayer * pSlayer, SkillSlot * pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; // Slayer Object Assertion Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Zone* pZone = pSlayer->getZone(); Assert(pZone != NULL); Player* pPlayer = pSlayer->getPlayer(); Assert(pPlayer != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); ZoneCoord_t X = pSlayer->getX(); ZoneCoord_t Y = pSlayer->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange()) && checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); // calculate damage and duration time SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); bool bHit = false; Level_t maxEnemyLevel = 0; uint EnemyNum = 0; int oX, oY; for(oX = -2; oX <= 2; oX++) for(oY = -2; oY <= 2; oY++) { int tileX = X+oX; int tileY = Y+oY; if (oX == 0 && oY == 0 ) continue; if (!rect.ptInRect(tileX, tileY)) continue; Tile& tile = pZone->getTile(tileX, tileY); // 타일에 있는 크리처들을 리스트로 만든다. list<Creature*> targetList; if(tile.hasCreature(Creature::MOVE_MODE_WALKING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); targetList.push_back(pCreature); } if(tile.hasCreature(Creature::MOVE_MODE_FLYING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_FLYING); targetList.push_back(pCreature); } if(tile.hasCreature(Creature::MOVE_MODE_BURROWING)) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_BURROWING); targetList.push_back(pCreature); } list<Creature*>::iterator itr = targetList.begin(); for (; itr != targetList.end(); itr++ ) { Creature* pTargetCreature = (*itr); Assert(pTargetCreature != NULL); if(checkZoneLevelToHitTarget(pTargetCreature ) && !pTargetCreature->isSlayer() && !pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA) && canAttack(pSlayer, pTargetCreature ) ) { if(pTargetCreature->isVampire() || pTargetCreature->isOusters()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); bHit = true; // 데미지를 적용시킨다. GCModifyInformation gcMI; ::setDamage(pTargetCreature, output.Damage, pSlayer, pSkillSlot->getSkillType(), &gcMI); // HP 가 변했다고 당사자에게 보낸다. pTargetPlayer->sendPacket(&gcMI); GCSkillToObjectOK2 gcSkillToObjectOK2; gcSkillToObjectOK2.setObjectID(1); // 의미 없다. gcSkillToObjectOK2.setSkillType(SKILL_ATTACK_MELEE); gcSkillToObjectOK2.setDuration(0); } else if(pTargetCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); bHit = true; ::setDamage(pMonster, output.Damage, pSlayer, pSkillSlot->getSkillType()); pMonster->addEnemy(pSlayer); } else { continue; } if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel(); EnemyNum++; GCSkillToObjectOK4 gcSkillToObjectOK4; gcSkillToObjectOK4.setTargetObjectID(pTargetCreature->getObjectID()); gcSkillToObjectOK4.setSkillType(SKILL_ATTACK_MELEE); gcSkillToObjectOK4.setDuration(0); pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &gcSkillToObjectOK4); // 성향을 올린다. increaseAlignment(pSlayer, pTargetCreature, _GCSkillToSelfOK1); } } } if(bHit) { //cout << "Skill Succesfully Attacked(" << output.Damage << ")" << endl; shareAttrExp(pSlayer, output.Damage, 1, 1, 8, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1, maxEnemyLevel, EnemyNum); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); } // 패킷을 만들어 보낸다. _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(0); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(0); // 기술을 사용한 사람에게 packet 전달 pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(X, Y, &_GCSkillToSelfOK2, pSlayer); // 기술 delay setting pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch(Throwable& t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 ////////////////////////////////////////////////////////////////////////////// void Eternity::execute(Slayer * pSlayer, SkillSlot * pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); ZoneCoord_t X = pSlayer->getX(); ZoneCoord_t Y = pSlayer->getY(); Tile& rTile = pZone->getTile(pSlayer->getX(), pSlayer->getY()); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = pSlayer->isFlag(Effect::EFFECT_CLASS_COMA ) && HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_ETERNITY) || rTile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION)!=NULL; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { Effect* pComa = pSlayer->findEffect(Effect::EFFECT_CLASS_COMA); if (pComa == NULL ) { executeSkillFailException(pSlayer, getSkillType()); return; } SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); // 이펙트 클래스를 만들어 붙인다. EffectEternity* pEffect = new EffectEternity(pSlayer); pEffect->setDeadline(output.Duration); pEffect->setHPPenalty(output.Damage); pEffect->setBroadcastingEffect(false); // pSlayer->addEffect(pEffect); pSlayer->setFlag(Effect::EFFECT_CLASS_ETERNITY); pZone->registerObject(pEffect); pZone->addEffect(pEffect); pComa->setDeadline(output.Duration + 10); //11초. 스킬 발동 전에 부활위치로 튕기는거 방지 // 경험치를 올린다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10*(Grade+1); shareAttrExp(pSlayer, ExpUp, 1, 1, 8, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); // 패킷을 만들어 보낸다. _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); // Send Packet pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(X, Y, &_GCSkillToSelfOK2, pSlayer); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } pSkillSlot->setRunTime(20); //2초 } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); //cout << t.toString() << endl; } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void ChargingPower::execute(Slayer* pSlayer, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayerself)" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); // 무장하고 있는 무기가 널이거나, 도가 아니라면 사용할 수 없다. Item* pItem = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND); if (pItem == NULL || pItem->getItemClass() != Item::ITEM_CLASS_BLADE) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayerself)" << endl; return; } bool bIncreaseExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); // 버서커랑 동시에 사용할 수 없다. bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_CHARGING_POWER) || pSlayer->isFlag(Effect::EFFECT_CLASS_BERSERKER); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); // 스킬 레벨에 따라 데미지 보너스가 달라진다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // 이펙트 클래스를 만들어 붙인다. EffectChargingPower* pEffect = new EffectChargingPower(pSlayer); pEffect->setDeadline(output.Duration); pEffect->setDamageBonus(output.Damage); pSlayer->addEffect(pEffect); pSlayer->setFlag(Effect::EFFECT_CLASS_CHARGING_POWER); // 이로 인하여 바뀌는 능력치를 보낸다. SLAYER_RECORD prev; pSlayer->getSlayerRecord(prev); pSlayer->initAllStat(); pSlayer->sendRealWearingInfo(); pSlayer->sendModifyInfo(prev); // 경험치를 올린다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10*(Grade+1); if (bIncreaseExp ) { shareAttrExp(pSlayer, ExpUp, 8, 1, 1, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); // increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); } // 패킷을 만들어 보낸다. _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &_GCSkillToSelfOK2, pSlayer); // 이펙트가 붙었다고 알려준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pSlayer->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_CHARGING_POWER); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcAddEffect); // set Next Run Time pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayerself)" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////// // // Visible::execute() // ////////////////////////////////////////////////////////////////////// void Visible::execute(Slayer * pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot * pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { // Player를 받아온다. Player * pPlayer = pSlayer->getPlayer(); // Zone을 받아온다. Zone * pZone = pSlayer->getZone(); SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo * pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); // 기술의 레벨을 받아온다. //SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); //SkillDomainType_t DomainType = pSkillInfo->getDomainType(); VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange()); bool bHit = false; // 기술성공률 검증. if (bManaCheck && bTimeCheck && bRangeCheck) { SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; Coord_t myX = pSlayer->getX(), myY = pSlayer->getY(); Dir_t dir = calcDirection(myX, myY, X, Y); list<Creature*> cList; int oX, oY; for(oX = -2; oX <= 2; oX++) for(oY = -2; oY <= 2; oY++) { int tileX = X+oX; int tileY = Y+oY; if (!rect.ptInRect(tileX, tileY)) continue; Tile& tile = pZone->getTile(tileX, tileY); Creature * pTargetCreature = NULL; if(tile.hasCreature(Creature::MOVE_MODE_WALKING)) pTargetCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); if(pTargetCreature != NULL) { if(pTargetCreature->isPC()) { bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_INVISIBILITY); if(bHitRoll && bEffected ) { // 주위에 GCAddXXX를 보내고, effect manager에서 effect를 삭제하고, GCRemoveEffect를 보낸다. addVisibleCreature(pZone, pTargetCreature, true); _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setRange(dir); _GCSkillToTileOK2.setDuration(0); Player * pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToTileOK2); cList.push_back(pTargetCreature); bHit = true; } } } // if(pTargetCreature!= NULL) } decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); // EXP UP! Exp_t Point = pSkillInfo->getPoint(); if(bHit ) { shareAttrExp(pSlayer, Point, 1, 1, 8, _GCSkillToTileOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToTileOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToTileOK1); } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setRange(dir); _GCSkillToTileOK1.setDuration(0); _GCSkillToTileOK3.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(0); _GCSkillToTileOK4.setRange(dir); _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(dir); _GCSkillToTileOK5.setDuration(0); // Send Packet pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pSlayer); cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X , Y , &_GCSkillToTileOK4 , cList); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch(Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
void GroundBless::execute(Ousters* pOusters, ObjectID_t TargetObjectID, OustersSkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pOusters != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pSkillSlot->getSkillType()); return; } Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NPC는 공격할 수 없다. // 저주 면역. by sigi. 2002.9.13 // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !pTargetCreature->isOusters() ) { executeSkillFailException(pOusters, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillInput input(pOusters, pSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pSkillSlot->getExpLevel()/2; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pOusters, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pSkillSlot); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_GROUND_BLESS); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pOusters); // 이펙트 오브젝트를 생성해 붙인다. EffectGroundBless* pEffect = new EffectGroundBless(pTargetCreature); pEffect->setDeadline(output.Duration); pEffect->setBonus(output.Damage); pTargetCreature->addEffect(pEffect); pTargetCreature->setFlag(Effect::EFFECT_CLASS_GROUND_BLESS); Ousters* pTargetOusters = dynamic_cast<Ousters*>(pTargetCreature); if (pTargetOusters != NULL ) pTargetOusters->initAllStatAndSend(); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(output.Duration); _GCSkillToObjectOK2.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(output.Duration); _GCSkillToObjectOK3.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY (targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK4.setDuration(output.Duration); _GCSkillToObjectOK5.setObjectID(pOusters->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration(output.Duration); _GCSkillToObjectOK6.setXY(myX, myY); _GCSkillToObjectOK6.setSkillType(SkillType); _GCSkillToObjectOK6.setDuration(output.Duration); list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pOusters); cList = pZone->broadcastSkillPacket(myX, myY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToObjectOK3, cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4, cList); // Send Packet pPlayer->sendPacket(&_GCSkillToObjectOK1); Player* pTargetPlayer = pTargetCreature->getPlayer(); if (pTargetPlayer != NULL ) { if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } GCAddEffect gcAddEffect; gcAddEffect.setObjectID(TargetObjectID); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_GROUND_BLESS); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(targetX, targetY, &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void IceField::execute(Ousters* pOusters, ZoneCoord_t X, ZoneCoord_t Y, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pOustersSkillSlot->getSkillType()); return; } GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); // 이펙트의 지속시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel(); bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) bTileCheck = true; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToTileOK1); int grade = 0; if (input.SkillLevel <= 10 ) grade = 0; else if (input.SkillLevel <= 20 ) grade = 1; else if (input.SkillLevel < 30 ) grade = 2; else grade = 3; list<Creature*> cList; // denier list for (int i=0; i<m_MaskNum[grade]; i++) { POINT& pt = m_IceFieldMask[grade][i]; int tileX = X+pt.x; int tileY = Y+pt.y; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); if (tile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION) ) continue; // 현재 타일에다 이펙트를 추가할 수 있다면... if (tile.canAddEffect()) { // 같은 effect가 있으면 지운다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_ICE_FIELD); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID);// fix me } // 이펙트 클래스를 생성한다. EffectIceField* pEffect = new EffectIceField(pZone , tileX, tileY); pEffect->setCasterName(pOusters->getName()); pEffect->setCasterID(pOusters->getObjectID()); pEffect->setDeadline(output.Duration); pEffect->setDuration(output.Range); pEffect->setNextTime(0); pEffect->setTick(output.Tick); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); const list<Object*>& oList = tile.getObjectList(); for(list<Object*>::const_iterator itr = oList.begin(); itr != oList.end(); itr++) { Object* pTarget = *itr; Creature* pTargetCreature = NULL; if (pTarget->getObjectClass() == Object::OBJECT_CLASS_CREATURE && ((pTargetCreature = dynamic_cast<Creature*>(pTarget))->isSlayer() || pTargetCreature->isVampire() ) && !checkZoneLevelToHitTarget(pTargetCreature ) ) { cList.push_back(pTargetCreature); _GCSkillToTileOK2.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); pEffect->affect(pTargetCreature); } // pEffect->affect(pTarget); } } } } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(grade); _GCSkillToTileOK2.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(grade); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, ICE_FIELD_SIGHT); _GCSkillToTileOK3.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setRange(grade); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK5.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(grade); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(grade); //_GCSkillToTileOK6.addShortData(MODIFY_VISION, ICE_FIELD_SIGHT); for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; if (canSee(pTargetCreature, pOusters)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pOusters); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pOusters); // watcherList에서 cList에 속하지 않고, caster(pOusters)를 볼 수 없는 경우는 // OK4를 보내고.. cList에 추가한다. for(list<Creature*>::const_iterator itr = watcherList.begin(); itr != watcherList.end(); itr++) { bool bBelong = false; for(list<Creature*>::const_iterator tItr = cList.begin(); tItr != cList.end(); tItr++) if (*itr == *tItr) bBelong = true; Creature* pWatcher = (*itr); if (bBelong == false && canSee(pWatcher, pOusters) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (!pWatcher->isPC()) { //cout << "IceField : 왓처 리스트가 PC가 아닙니다." << endl; // GCSkillFailed1 _GCSkillFailed1; // _GCSkillFailed1.setSkillType(getSkillType()); // pOusters->getPlayer()->sendPacket(&_GCSkillFailed1); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; // return; continue; } pWatcher->getPlayer()->sendPacket(&_GCSkillToTileOK4); cList.push_back(*itr); } } cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList, false); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void Light::execute(Slayer* pSlayer, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_LIGHT); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); // 기술이 유지되는 시간은 숙련도에 따라서 달라진다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); Sight_t CurrentSight = pSlayer->getSight(); Sight_t oldSight = CurrentSight; // 혹시라도 옛날 이펙트가 남아있다면 삭제한다. if (pSlayer->isEffect(Effect::EFFECT_CLASS_LIGHT)) { EffectLight* pOldEffectLight = (EffectLight*)pSlayer->findEffect(Effect::EFFECT_CLASS_LIGHT); CurrentSight = pOldEffectLight->getOldSight(); pSlayer->deleteEffect(Effect::EFFECT_CLASS_LIGHT); } // 이펙트를 만들어 붙인다. EffectLight* pEffectLight = new EffectLight (pSlayer); pEffectLight->setDeadline(output.Duration); pEffectLight->setOldSight(CurrentSight); pSlayer->setFlag(Effect::EFFECT_CLASS_LIGHT); pSlayer->addEffect(pEffectLight); //pEffectLight->create(pSlayer->getName()); // 시야처리.. Sight_t MinSight = pSkillInfo->getMinDamage(); Sight_t MaxSight = pSkillInfo->getMaxDamage(); Sight_t NewSight = MinSight + (MaxSight - MinSight)* SkillLevel / 100; // 시야 변경에 따른 오브젝트 가감 패킷을 보낸다. pZone->updateScan(pSlayer, oldSight, NewSight); pSlayer->setSight(NewSight); if (NewSight != oldSight) _GCSkillToSelfOK1.addShortData(MODIFY_VISION, NewSight); _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); // EXP UP! SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1)* 2; shareAttrExp(pSlayer, ExpUp, 1, 1, 8, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); // Send Packet pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &_GCSkillToSelfOK2 , pSlayer); // 이펙트가 붙었다고 알려준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pSlayer->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_LIGHT); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch(Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }