////////////////////////////////////////////////////////////////////////////// // 뱀파이어 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void BloodyBreaker::execute(Vampire* pVampire, ZoneCoord_t X, ZoneCoord_t Y, VampireSkillSlot* pVampireSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; SkillType_t SkillType = getSkillType(); // Knowledge of Blood 가 있다면 hit bonus 10 int HitBonus = 0; if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_BLOOD ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_BLOOD); Assert(pRankBonus != NULL); HitBonus = pRankBonus->getPoint(); } try { SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); Dir_t Dir = getDirectionToPosition(pVampire->getX(), pVampire->getY(), X, Y); // 강제로 knockback시킬 확률 // bool bForceKnockback = rand()%100 < output.ToHit; Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); VSRect rect(1, 1, pZone->getWidth()-2, pZone->getHeight()-2); if (!rect.ptInRect(X, Y )) { executeSkillFailException(pVampire, SkillType); return; } GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; // GCSkillToTileOK3 _GCSkillToTileOK3; // GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; // GCSkillToTileOK6 _GCSkillToTileOK6; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = verifyDistance(pVampire, X, Y, pSkillInfo->getRange()); if (bManaCheck && bTimeCheck && bRangeCheck ) { // 마나를 떨어뜨린다. decreaseMana(pVampire, RequiredMP, _GCSkillToTileOK1); // 좌표와 방향을 구한다. ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); Dir_t dir = calcDirection(myX, myY, X, Y); list<Creature*> cList; // knockback 때문에 recursive 하게 데미지를 먹는 경우가 있다. // 그래서 제일 먼쪽에 있는 마스크부터 체크한다. for (int i = 21; i >= 0; i-- ) { int tileX = myX + m_pBloodyBreakerMask[Dir][i].x; int tileY = myY + m_pBloodyBreakerMask[Dir][i].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); } 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 (!canAttack(pVampire, pTargetCreature ) || pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA) ) { continue; } if (pTargetCreature != pVampire) { bool bPK = verifyPK(pVampire, pTargetCreature); bool bRaceCheck = pTargetCreature->isSlayer() || pTargetCreature->isMonster() || pTargetCreature->isOusters(); bool bZoneLevelCheck = checkZoneLevelToHitTarget(pTargetCreature); bool bHitRoll = false;//HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus); int EnemyLevel = 0; if (pTargetCreature->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pTargetCreature); EnemyLevel = pSlayer->getHighestSkillDomainLevel(); } else if (pTargetCreature->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pTargetCreature); EnemyLevel = pOusters->getLevel(); } else if (pTargetCreature->isMonster() ) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); EnemyLevel = pMonster->getLevel(); } // min : 20, max : 100 int hitRatio = max(20, 50 + pVampire->getLevel() - EnemyLevel + HitBonus); bHitRoll = (rand()%100) < hitRatio; if (bPK && bRaceCheck && bZoneLevelCheck && bHitRoll) { Damage_t Damage = 0; bool bForceKnockback = rand() & 1; Damage += computeMagicDamage(pTargetCreature, output.Damage, SkillType, true, pVampire); ObjectID_t targetObjectID = pTargetCreature->getObjectID(); cList.push_back(pTargetCreature); _GCSkillToTileOK1.addCListElement(targetObjectID); _GCSkillToTileOK2.addCListElement(targetObjectID); _GCSkillToTileOK5.addCListElement(targetObjectID); // 일단 맞는 놈이 받을 패킷은 널 상태로 한 채로, 데미지를 준다. setDamage(pTargetCreature, Damage, pVampire, SkillType, NULL, &_GCSkillToTileOK1); computeAlignmentChange(pTargetCreature, Damage, pVampire, NULL, &_GCSkillToTileOK1); increaseAlignment(pVampire, pTargetCreature, _GCSkillToTileOK1); // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bForceKnockback) { knockbackCreature(pZone, pTargetCreature, pVampire->getX(), pVampire->getY()); } if (pTargetCreature->isDead()) { int exp = computeCreatureExp(pTargetCreature, KILL_EXP); shareVampExp(pVampire, exp, _GCSkillToTileOK1); } } } } } } // 공격자의 아이템 내구성을 떨어뜨린다. decreaseDurability(pVampire, NULL, pSkillInfo, &_GCSkillToTileOK1, NULL); _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(0); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setRange(dir); _GCSkillToTileOK1.setDuration(0); _GCSkillToTileOK2.setObjectID(pVampire->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setRange(dir); _GCSkillToTileOK2.setDuration(0); _GCSkillToTileOK5.setObjectID(pVampire->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); } else if (pTargetCreature->isOusters()) { targetHP = (dynamic_cast<Ousters*>(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(pVampire); } } cList.push_back(pVampire); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK5 , cList); // set Next Run Time pVampireSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, SkillType, NULL); } } catch (Throwable & t) { executeSkillFailException(pVampire, SkillType); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void BlitzSliding::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 // NPC는 공격할 수가 없다. if (pTargetCreature==NULL || pTargetCreature->isNPC()) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } bool bIncreaseDomainExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND); // 무장하고 있는 무기가 널이거나, 검이 아니라면 기술을 사용할 수 없다. Item* pItem = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND); if (pItem == NULL) { executeSkillFailException(pSlayer, 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); 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, computeSkillRange(pSkillSlot, pSkillInfo)); bool bHitRoll = HitRoll::isSuccess(pSlayer, pTargetCreature, SkillLevel/2); bool bCanHit = canHit(pSlayer, pTargetCreature, SkillType); bool bPK = verifyPK(pSlayer, pTargetCreature); bool bEffected = pSlayer->hasRelicItem(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bCanHit && bPK && !bEffected ) { // 빠르게 PC를 움직여준다. if (pZone->moveFastPC(pSlayer, pSlayer->getX(), pSlayer->getY(), pTargetCreature->getX(), pTargetCreature->getY(), getSkillType())) { decreaseMana(pSlayer, RequiredMP, _GCSkillToObjectOK1); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); bool bCriticalHit = false; // 데미지를 준다. Damage_t BasicDamage = computeDamage(pSlayer, pTargetCreature, SkillLevel/5, bCriticalHit); Damage_t Damage = BasicDamage + output.Damage; setDamage(pTargetCreature, Damage, pSlayer, SkillType, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pSlayer, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); decreaseDurability(pSlayer, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK2); // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bCriticalHit) { knockbackCreature(pZone, pTargetCreature, pSlayer->getX(), pSlayer->getY()); } if (!pTargetCreature->isSlayer()) { if (bIncreaseDomainExp ) { shareAttrExp(pSlayer, Damage, 8, 1, 1, _GCSkillToObjectOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToObjectOK1, pTargetCreature->getLevel()); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToObjectOK1); } increaseAlignment(pSlayer, pTargetCreature, _GCSkillToObjectOK1); } /* if (!pTargetCreature->isFlag(Effect::EFFECT_CLASS_DECREASE_HP ) ) { EffectDecreaseHP* pEffect = new EffectDecreaseHP(pTargetCreature); pEffect->setPoint(BasicDamage + output.Damage); pEffect->setUserObjectID(pSlayer->getObjectID()); pEffect->setDeadline(10); pTargetCreature->setFlag(Effect::EFFECT_CLASS_DECREASE_HP); pTargetCreature->addEffect(pEffect); }*/ EffectBlazeWalk* pEffect = new EffectBlazeWalk(pTargetCreature); pEffect->setPoint(BasicDamage + output.Damage); pEffect->setUserObjectID(pSlayer->getObjectID()); pEffect->setAttackNum(1); pEffect->setNextTime(10); pEffect->setSkillType(SKILL_BLITZ_SLIDING); pTargetCreature->setFlag(Effect::EFFECT_CLASS_BLAZE_WALK); pTargetCreature->addEffect(pEffect); // 패킷을 준비하고 보낸다. _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(getSkillType()); _GCSkillToObjectOK3.setTargetXY(pTargetCreature->getX(), pTargetCreature->getY()); _GCSkillToObjectOK4.setSkillType(getSkillType()); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setSkillType(getSkillType()); _GCSkillToObjectOK5.setDuration(0); 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); } list<Creature*> cList; cList.push_back(pSlayer); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(pSlayer->getX(), pSlayer->getY(), pTargetCreature->getX(), pTargetCreature->getY(), &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &_GCSkillToObjectOK4 , cList); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), pTargetCreature); } } else { executeSkillFailNormal(pSlayer, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << 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 SimpleMissileSkill::execute( Monster* pMonster, Creature* pEnemy, const SIMPLE_SKILL_INPUT& param, SIMPLE_SKILL_OUTPUT& result, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY Assert(pMonster != NULL); Assert(pEnemy != NULL); try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); if (pMonster->isFlag(Effect::EFFECT_CLASS_HIDE)) { return; } if (pMonster->isFlag(Effect::EFFECT_CLASS_INVISIBILITY)) { addVisibleCreature(pZone, pMonster, true); } result.pTargetCreature = pEnemy; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(param.SkillType); bool bCriticalHit = false; Damage_t Damage = 0; if (param.bAdd) { // 파라미터로 전달된 데미지 값이 더해지는 데미지라면, // 일반 데미지를 계산 후, 데미지를 더해야 한다. // 파라미터로 전달된 데미지 값이 직접적으로 쓰이는 데미지라면, // 이 부분까지 들어오지 않으므로, 밑의 부분까지 0으로 전달된다. Damage += computeDamage(pMonster, pEnemy, 0, bCriticalHit); } if (param.bMagicDamage) { // 만일 스킬 데미지가 마법 데미지라면, 마법 데미지 계산 함수를 이용해 계산을 해준다. Damage += computeMagicDamage(pEnemy, param.SkillDamage, param.SkillType); } else { Damage += param.SkillDamage; } bool bRangeCheck = verifyDistance(pMonster, pEnemy, pSkillInfo->getRange()); bool bHitRoll = false; bool bCanHit = canHit(pMonster, pEnemy, param.SkillType); if (param.bMagicHitRoll) { bHitRoll = HitRoll::isSuccessMagic(pMonster, pSkillInfo); } else { bHitRoll = HitRoll::isSuccess(pMonster, pEnemy); } Coord_t vampX = pMonster->getX(); Coord_t vampY = pMonster->getY(); Coord_t targetX = pEnemy->getX(); Coord_t targetY = pEnemy->getY(); // 공격성공률 검증. if (bRangeCheck && bHitRoll && bCanHit) { bool bCanSeeCaster = canSee(pEnemy, pMonster); // 데미지를 가하고, 아이템 내구도를 떨어뜨린다. if (bCanSeeCaster) { setDamage(pEnemy, Damage, pMonster, param.SkillType, &_GCSkillToObjectOK2); decreaseDurability(pMonster, pEnemy, pSkillInfo, NULL, &_GCSkillToObjectOK2); } else { setDamage(pEnemy, Damage, pMonster, param.SkillType, &_GCSkillToObjectOK6); decreaseDurability(pMonster, pEnemy, pSkillInfo, NULL, &_GCSkillToObjectOK6); } _GCSkillToObjectOK2.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK2.setSkillType(param.SkillType); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK2.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK3.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK3.setSkillType(param.SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK4.setSkillType(param.SkillType); _GCSkillToObjectOK4.setTargetObjectID(pEnemy->getObjectID()); _GCSkillToObjectOK5.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(pEnemy->getObjectID()); _GCSkillToObjectOK5.setSkillType(param.SkillType); _GCSkillToObjectOK5.setDuration(0); _GCSkillToObjectOK6.setXY(vampX, vampY); _GCSkillToObjectOK6.setSkillType(param.SkillType); _GCSkillToObjectOK6.setDuration(0); _GCSkillToObjectOK6.setXY(vampX, vampY); if (pEnemy->isPC()) { Player* pTargetPlayer = pEnemy->getPlayer(); Assert(pTargetPlayer != NULL); if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else if (pEnemy->isMonster()) { Monster* pTargetMonster = dynamic_cast<Monster*>(pEnemy); pTargetMonster->addEnemy(pMonster); } list<Creature*> cList; cList.push_back(pMonster); cList.push_back(pEnemy); cList = pZone->broadcastSkillPacket(vampX, vampY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(vampX, vampY, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); result.bSuccess = true; } else { executeSkillFailNormal(pMonster, param.SkillType, pEnemy); } } catch (Throwable & t) { executeSkillFailException(pMonster, param.SkillType); } __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void BloodDrain::execute(Vampire* pVampire, ObjectID_t TargetObjectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(vampire)" << endl; Assert(pVampire != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NPC는 공격할 수가 없다. // 면역 상태. by sigi. 2002.9.13 // 무적상태 체크. by sigi.2002.9.5 // 죽은 애는 피 빨 수 없다. by Sequoia.2003. 3. 20 if (pTargetCreature==NULL // NoSuch 제거. by sigi. 2002.5.2 || pTargetCreature->isNPC() || pTargetCreature->isFlag(Effect::EFFECT_CLASS_IMMUNE_TO_BLOOD_DRAIN) || !canAttack(pVampire, pTargetCreature ) || pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA) || pTargetCreature->isDead() ) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(vampire)" << endl; return; } GCBloodDrainOK1 _GCBloodDrainOK1; GCBloodDrainOK2 _GCBloodDrainOK2; GCBloodDrainOK3 _GCBloodDrainOK3; Timeval CurrentTime; getCurrentTime(CurrentTime); bool bHitRoll = HitRoll::isSuccessBloodDrain(pVampire, pTargetCreature); bool bCanHit = canHit(pVampire, pTargetCreature, SKILL_BLOOD_DRAIN); bool bTimeCheck = CurrentTime.tv_sec > 1 ? true : false; bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, 2); bool bPK = verifyPK(pVampire, pTargetCreature); if (bHitRoll && bCanHit && bTimeCheck && bRangeCheck && bPK) { // 슬레이어일 경우에만 이펙트 오브젝트를 생성한다. if (pTargetCreature->isSlayer()) { EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pTargetCreature); pEffectBloodDrain->setLevel(pVampire->getLevel()); pEffectBloodDrain->setDeadline(BLOODDRAIN_DURATION); // 3일?? pTargetCreature->addEffect(pEffectBloodDrain); pEffectBloodDrain->create(pTargetCreature->getName()); _GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN); // 타겟이 뭐든 플래그는 건다. pTargetCreature->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature); SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->sendRealWearingInfo(); pTargetSlayer->addModifyInfo(prev, _GCBloodDrainOK2); // 로그를 남긴다. //log(LOG_BLOODDRAINED, pTargetCreature->getName(), pVampire->getName()); } // 아우스터즈의 경우엔..... -_-; 제한시간 없는 이펙트를 생성한다. 엄밀히 말해 제한시간이 없는 건 아니지만.. // else if (pTargetCreature->isOusters() ) // { // EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pTargetCreature); // pEffectBloodDrain->setLevel(pVampire->getLevel()); // pTargetCreature->addEffect(pEffectBloodDrain); // pEffectBloodDrain->create(pTargetCreature->getName()); // _GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN); // // // 타겟이 뭐든 플래그는 건다. // pTargetCreature->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); // // Sight_t oldSight = pTargetCreature->getSight(); // Sight_t newSight = pTargetCreature->getEffectedSight(); // // if (oldSight != newSight ) // { // pTargetCreature->setSight(newSight); // pZone->updateScan(pTargetCreature, oldSight, pTargetCreature->getSight()); // _GCBloodDrainOK2.addShortData(MODIFY_VISION, pTargetCreature->getSight()); // // GCChangeDarkLight gcChangeDarkLight; // gcChangeDarkLight.setDarkLevel(15); // gcChangeDarkLight.setLightLevel(newSight); // pTargetCreature->getPlayer()->sendPacket(&gcChangeDarkLight); // } // } // 타겟이 뭐든 플래그는 건다. pTargetCreature->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); // 올릴 경험치량을 계산한다. Exp_t Exp = computeCreatureExp(pTargetCreature, BLOODDRAIN_EXP); int targetLevel = 0; int targetMaxHP = 0; // 페임을 올려준다. if (pTargetCreature->isSlayer()) { //increaseFame(pVampire, Exp); Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature); targetLevel = pTargetSlayer->getHighestSkillDomainLevel(); targetMaxHP = pTargetSlayer->getHP(ATTR_MAX); } else if (pTargetCreature->isVampire()) { //increaseFame(pVampire, Exp); Vampire* pTargetVampire = dynamic_cast<Vampire*>(pTargetCreature); targetLevel = pTargetVampire->getLevel(); targetMaxHP = pTargetVampire->getHP(ATTR_MAX); } else if (pTargetCreature->isOusters()) { //increaseFame(pOusters, Exp); Ousters* pTargetOusters = dynamic_cast<Ousters*>(pTargetCreature); targetLevel = pTargetOusters->getLevel(); targetMaxHP = pTargetOusters->getHP(ATTR_MAX); } else if (pTargetCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); Timeval NextTurn = pMonster->getNextTurn(); Timeval DelayTurn; DelayTurn.tv_sec = 4; DelayTurn.tv_usec = 500000; pMonster->addAccuDelay(DelayTurn); pMonster->addEnemy(pVampire); targetLevel = pMonster->getLevel(); targetMaxHP = pMonster->getHP(ATTR_MAX); } shareVampExp(pVampire, Exp, _GCBloodDrainOK1); // 흡혈을 하게 되면 흡혈한 사람의 체력이 올라간다. // Mephisto이펙트가 걸려있으면 HP는 안 올라간다. if (!pVampire->isFlag(Effect::EFFECT_CLASS_MEPHISTO)) { HP_t HealPoint = (Exp==0? computeBloodDrainHealPoint(pTargetCreature, BLOODDRAIN_EXP) : Exp); HP_t CurrentHP = pVampire->getHP(); HP_t MaxHP = pVampire->getHP(ATTR_MAX); HP_t NewHP = min((int)MaxHP , (int)CurrentHP + (int)HealPoint); // 은 데미지 관련 처리를 해 준다. Silver_t newSilverDamage = max(0, (int)pVampire->getSilverDamage()-(int)HealPoint); pVampire->saveSilverDamage(newSilverDamage); _GCBloodDrainOK1.addShortData(MODIFY_SILVER_DAMAGE, newSilverDamage); // 뱀파이어의 HP를 세팅한다. pVampire->setHP(NewHP); GCStatusCurrentHP gcStatusCurrentHP; gcStatusCurrentHP.setObjectID(pVampire->getObjectID()); gcStatusCurrentHP.setCurrentHP(NewHP); pZone->broadcastPacket(pVampire->getX(), pVampire->getY(), &gcStatusCurrentHP, pVampire); _GCBloodDrainOK1.addShortData(MODIFY_CURRENT_HP, NewHP); } // 흡혈을 당한 애는 HP가 줄어든다. // 대상이 내 레벨보다 높다면.. MaxHP의 10~15% damage // by sigi. 2002.9.14 int drainDamage = 0; int myLevel = pVampire->getLevel(); if (targetLevel > myLevel) { drainDamage = targetMaxHP * (rand()%6+10) / 100; } else { // 레벨 5차이마다 1%씩 더~ int damagePercent = min(30, (rand()%6+10+(myLevel-targetLevel))); drainDamage = targetMaxHP * damagePercent / 100; } if (drainDamage > 0) { //decreaseHP(pZone, pTargetCreature, drainDamage, pVampire->getObjectID()); EffectDecreaseHP* pEffect = new EffectDecreaseHP(pTargetCreature); pEffect->setPoint(drainDamage); pEffect->setDeadline(20); // 2초 후 pEffect->setUserObjectID(pVampire->getObjectID()); pTargetCreature->addEffect(pEffect); pTargetCreature->setFlag(Effect::EFFECT_CLASS_DECREASE_HP); } pVampire->getGQuestManager()->blooddrain(); // 흡혈시에도 성향 바뀜 // by sigi. 2002.12.16 // EffectDecreaseHP에서 HP가 닳아서 0이 되어야하는 경우가 있어서 // EffectDecreaseHP::unaffect()로 옮긴다. //computeAlignmentChange(pTargetCreature, drainDamage, pVampire, NULL, &_GCBloodDrainOK1); _GCBloodDrainOK1.setObjectID(TargetObjectID); _GCBloodDrainOK3.setObjectID(pVampire->getObjectID()); _GCBloodDrainOK3.setTargetObjectID (TargetObjectID); pPlayer->sendPacket(&_GCBloodDrainOK1); if (pTargetCreature != NULL && pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); if (pTargetPlayer != NULL) { _GCBloodDrainOK2.setObjectID(pVampire->getObjectID()); // _GCBloodDrainOK2.addLongData(MODIFY_DURATION, BLOODDRAIN_DURATION); pTargetPlayer->sendPacket(&_GCBloodDrainOK2); } } list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pVampire); pZone->broadcastPacket(pVampire->getX(), pVampire->getY(), &_GCBloodDrainOK3 , cList); } else { executeSkillFailNormal(pVampire, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(vampire)" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void Death::execute(Vampire* pVampire, ObjectID_t TargetObjectID, VampireSkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pVampire != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NPC는 공격할 수 없다. // 저주 면역. by sigi. 2002.9.13 // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || pTargetCreature->isFlag(Effect::EFFECT_CLASS_IMMUNE_TO_CURSE) || !canAttack(pVampire, pTargetCreature ) || pTargetCreature->isNPC()) { executeSkillFailException(pVampire, 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); // Knowledge of Curse 가 있다면 hit bonus 10 int HitBonus = 0; if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_CURSE ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_CURSE); Assert(pRankBonus != NULL); HitBonus = pRankBonus->getPoint(); } int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessVampireCurse(pSkillInfo->getLevel(), pTargetCreature->getResist(MAGIC_DOMAIN_CURSE)); bool bHitRoll2 = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pSkillSlot, HitBonus); bool bCanHit = canHit(pVampire, pTargetCreature, SkillType); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_DEATH); bool bPK = verifyPK(pVampire, pTargetCreature); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bHitRoll2 && bCanHit && !bEffected && bPK) { decreaseMana(pVampire, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pVampire); SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); // pTargetCreature가 저주마법을 반사하는 경우 if (CheckReflection(pVampire, pTargetCreature, getSkillType())) { pTargetCreature = (Creature*)pVampire; TargetObjectID = pVampire->getObjectID(); } Resist_t resist = pTargetCreature->getResist(MAGIC_DOMAIN_CURSE); if ((resist*10/3) > output.Duration ) output.Duration=0; else output.Duration -= resist*10/3; if (output.Duration < 20 ) output.Duration = 20; // 이펙트 오브젝트를 생성해 붙인다. EffectDeath* pEffect = new EffectDeath(pTargetCreature); pEffect->setDeadline(output.Duration); pEffect->setLevel(pSkillInfo->getLevel()/2); pEffect->setResistPenalty(output.Damage); pTargetCreature->addEffect(pEffect); pTargetCreature->setFlag(Effect::EFFECT_CLASS_DEATH); // 능력치를 계산해서 보내준다. if (pTargetCreature->isSlayer()) { Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature); if (bCanSeeCaster) { SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->addModifyInfo(prev, _GCSkillToObjectOK2); } else { SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->addModifyInfo(prev, _GCSkillToObjectOK6); } } else if (pTargetCreature->isVampire()) { Vampire* pTargetVampire = dynamic_cast<Vampire*>(pTargetCreature); VAMPIRE_RECORD prev; pTargetVampire->getVampireRecord(prev); pTargetVampire->initAllStat(); if (bCanSeeCaster) { pTargetVampire->addModifyInfo(prev, _GCSkillToObjectOK2); } else { pTargetVampire->addModifyInfo(prev, _GCSkillToObjectOK6); } } else if (pTargetCreature->isOusters()) { Ousters* pTargetOusters = dynamic_cast<Ousters*>(pTargetCreature); OUSTERS_RECORD prev; pTargetOusters->getOustersRecord(prev); pTargetOusters->initAllStat(); if (bCanSeeCaster) { pTargetOusters->addModifyInfo(prev, _GCSkillToObjectOK2); } else { pTargetOusters->addModifyInfo(prev, _GCSkillToObjectOK6); } } else if (pTargetCreature->isMonster()) { Monster* pTargetMonster = dynamic_cast<Monster*>(pTargetCreature); pTargetMonster->initAllStat(); } else Assert(false); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(output.Duration); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(output.Duration); _GCSkillToObjectOK3.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY (targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK4.setDuration(output.Duration); _GCSkillToObjectOK5.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration(output.Duration); _GCSkillToObjectOK6.setXY(myX, myY); _GCSkillToObjectOK6.setSkillType(SkillType); _GCSkillToObjectOK6.setDuration(output.Duration); if (bCanSeeCaster) // 10은 땜빵 수치다. { computeAlignmentChange(pTargetCreature, 10, pVampire, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); } else // 10은 땜빵 수치다. { computeAlignmentChange(pTargetCreature, 10, pVampire, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); } list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pVampire); 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); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); if (pTargetPlayer == NULL) { //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else if (pTargetCreature->isMonster()) { Monster* pTargetMonster = dynamic_cast<Monster*>(pTargetCreature); pTargetMonster->addEnemy(pVampire); } GCAddEffect gcAddEffect; gcAddEffect.setObjectID(TargetObjectID); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_DEATH); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(targetX, targetY, &gcAddEffect); //cout << pTargetCreature->getName() << "에게 Death를 " << output.Duration << " duration 동안 건다." << endl; pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << 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 LarSlash::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는 공격할 수가 없다. // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || pTargetCreature->isNPC()) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } // 무장하고 있는 무기가 널이거나, 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); GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK5 _GCSkillToObjectOK5; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); bool bCriticalHit = false; // 기본 데미지에 스킬 데미지를 더한다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); Damage_t Damage = computeDamage(pSlayer, pTargetCreature, SkillLevel/5, bCriticalHit); Damage += output.Damage; int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = (rand()%10)?HitRoll::isSuccess(pSlayer, pTargetCreature, SkillLevel / 2):(true); bool bCanHit = canHit(pSlayer, pTargetCreature, SkillType); bool bPK = verifyPK(pSlayer, pTargetCreature); // 마나가 있어야 하고, 시간과 거리 체크에 성공하고, // hitroll에 성공하고, 크로스 카운터가 걸려있지 않다면, 성공이다. if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bCanHit && bPK) { CheckCrossCounter(pSlayer, pTargetCreature, Damage, pSkillInfo->getRange()); decreaseMana(pSlayer, RequiredMP, _GCSkillToObjectOK1); // Exp_t Point = pSkillInfo->getPoint(); // 데미지를 주고, 내구도를 떨어뜨린다. setDamage(pTargetCreature, Damage, pSlayer, SkillType, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pSlayer, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); decreaseDurability(pSlayer, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK2); // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bCriticalHit) { knockbackCreature(pZone, pTargetCreature, pSlayer->getX(), pSlayer->getY()); } // 타겟이 슬레이어가 아닌 경우에만 경험치를 올려준다. if (!pTargetCreature->isSlayer()) { if (bIncreaseExp) { shareAttrExp(pSlayer, Damage, 8, 1, 1, _GCSkillToObjectOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToObjectOK1, pTargetCreature->getLevel()); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToObjectOK1); } increaseAlignment(pSlayer, pTargetCreature, _GCSkillToObjectOK1); } // 패킷을 준비하고, 보낸다. _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); _GCSkillToObjectOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration(0); 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); } list< Creature*> cList; cList.push_back(pSlayer); cList.push_back(pTargetCreature); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &_GCSkillToObjectOK5, 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 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 DarkBluePoison::execute(Monster* pMonster, Creature* pEnemy) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pMonster != NULL); Assert(pEnemy != NULL); try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillType_t SkillType = SKILL_DARKBLUE_POISON; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); bool bRangeCheck = verifyDistance(pMonster, pEnemy, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pMonster, pSkillInfo); bool bEffected = pEnemy->isFlag(Effect::EFFECT_CLASS_DARKBLUE_POISON); ZoneCoord_t vampX = pMonster->getX(); ZoneCoord_t vampY = pMonster->getY(); ZoneCoord_t targetX = pEnemy->getX(); ZoneCoord_t targetY = pEnemy->getY(); if (bRangeCheck && bHitRoll && !bEffected) { bool bCanSeeCaster = canSee(pEnemy, pMonster); SkillInput input(pMonster); SkillOutput output; computeOutput(input, output); Damage_t Damage = computeMagicDamage(pEnemy, output.Damage, SkillType); // 이펙트 오브젝트를 생성해서 붙인다. EffectDarkBluePoison* pEffectDarkBluePoison = new EffectDarkBluePoison(pEnemy); pEffectDarkBluePoison->setDamage(Damage); pEffectDarkBluePoison->setLevel(pSkillInfo->getLevel()/2); pEffectDarkBluePoison->setDeadline(output.Duration); pEffectDarkBluePoison->setTick(output.Tick); pEffectDarkBluePoison->setNextTime(0); pEnemy->addEffect(pEffectDarkBluePoison); pEnemy->setFlag(Effect::EFFECT_CLASS_DARKBLUE_POISON); // 이펙트가 붙었으니, 붙었다고 브로드캐스팅해준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pEnemy->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_DARKBLUE_POISON); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(targetX, targetY, &gcAddEffect); if (bCanSeeCaster) { decreaseDurability(pMonster, pEnemy, pSkillInfo, NULL, &_GCSkillToObjectOK2); } else { decreaseDurability(pMonster, pEnemy, pSkillInfo, NULL, &_GCSkillToObjectOK6); } _GCSkillToObjectOK2.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(output.Duration); _GCSkillToObjectOK3.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(pEnemy->getObjectID()); _GCSkillToObjectOK5.setObjectID(pMonster->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(pEnemy->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setDuration(output.Duration); _GCSkillToObjectOK6.setXY(vampX, vampY); _GCSkillToObjectOK6.setSkillType(SkillType); _GCSkillToObjectOK6.setDuration(output.Duration); if (pEnemy->isPC()) { Player* pTargetPlayer = pEnemy->getPlayer(); if (pTargetPlayer == NULL) { //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else { Monster* pTargetMonster = dynamic_cast<Monster*>(pEnemy); pTargetMonster->addEnemy(pMonster); } list<Creature*> cList; cList.push_back(pMonster); cList.push_back(pEnemy); cList = pZone->broadcastSkillPacket(vampX, vampY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(vampX, vampY, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); } else { executeSkillFailNormal(pMonster, getSkillType(), pEnemy); } } catch(Throwable & t) { executeSkillFailException(pMonster, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void DarkBluePoison::execute(Vampire* pVampire, ObjectID_t TargetObjectID, VampireSkillSlot* pVampireSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pVampire != NULL); Assert(pVampireSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->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(pVampire, pTargetCreature ) || pTargetCreature->isNPC()) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillType_t SkillType = pVampireSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); // Knowledge of Poison 이 있다면 hit bonus 10 int HitBonus = 0; if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_POISON ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_POISON); Assert(pRankBonus != NULL); HitBonus = pRankBonus->getPoint(); } int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_DARKBLUE_POISON); ZoneCoord_t vampX = pVampire->getX(); ZoneCoord_t vampY = pVampire->getY(); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pVampire, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pVampire); SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); Damage_t Damage = computeMagicDamage(pTargetCreature, output.Damage, SkillType, true, pVampire); // 아우스터즈는 절반의 시간만 받는다. if (pTargetCreature->isOusters() ) output.Duration/=2; // 이펙트 오브젝트를 생성해서 붙인다. EffectDarkBluePoison* pEffectDarkBluePoison = new EffectDarkBluePoison(pTargetCreature); pEffectDarkBluePoison->setDamage(Damage); pEffectDarkBluePoison->setLevel(pSkillInfo->getLevel()/2); pEffectDarkBluePoison->setDeadline(output.Duration); pEffectDarkBluePoison->setTick(output.Tick); pEffectDarkBluePoison->setNextTime(0); pTargetCreature->addEffect(pEffectDarkBluePoison); pTargetCreature->setFlag(Effect::EFFECT_CLASS_DARKBLUE_POISON); // 이펙트가 붙었으니, 붙었다고 브로드캐스팅해준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pTargetCreature->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_DARKBLUE_POISON); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(targetX, targetY, &gcAddEffect); if (bCanSeeCaster) { decreaseDurability(pVampire, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK2); } else { decreaseDurability(pVampire, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK6); } _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(output.Duration); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(output.Duration); _GCSkillToObjectOK3.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setDuration(output.Duration); _GCSkillToObjectOK6.setXY(vampX, vampY); _GCSkillToObjectOK6.setSkillType(SkillType); _GCSkillToObjectOK6.setDuration(output.Duration); pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pVampire); } list<Creature*> cList; cList.push_back(pVampire); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(vampX, vampY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(vampX, vampY, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); pVampireSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), pTargetCreature); } } catch(Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void Paralyze::execute(Vampire* pVampire, ObjectID_t TargetObjectID, VampireSkillSlot* pVampireSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pVampire != NULL); Assert(pVampireSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); SkillType_t SkillType = pVampireSkillSlot->getSkillType(); // NPC는 공격할 수가 없다. // 면역이거나. by sigi. 2002.9.13 // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || pTargetCreature->isFlag(Effect::EFFECT_CLASS_IMMUNE_TO_PARALYZE) || !canAttack(pVampire, pTargetCreature ) || pTargetCreature->isNPC()) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); // Knowledge of Curse 가 있다면 hit bonus 10 int HitBonus = 0; if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_CURSE ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_CURSE); Assert(pRankBonus != NULL); HitBonus = pRankBonus->getPoint(); } Tile& rTile = pZone->getTile(pTargetCreature->getX(), pTargetCreature->getY()); int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessVampireCurse(pSkillInfo->getLevel(), pTargetCreature->getResist(MAGIC_DOMAIN_CURSE)); bool bHitRoll2 = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus); bool bCanHit = canHit(pVampire, pTargetCreature, SkillType); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_PARALYZE) || rTile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION)!=NULL; bool bPK = verifyPK(pVampire, pTargetCreature); ZoneCoord_t vampX = pVampire->getX(); ZoneCoord_t vampY = pVampire->getY(); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); //if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bHitRoll2 && bCanHit && !bEffected && bPK) if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bHitRoll2 && bCanHit && !bEffected && bPK && pTargetCreature->getCompetence() == 3) { decreaseMana(pVampire, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pVampire); SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); // Wisdom of Silence 이 있다면 지속시간 20% 증가 if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_WISDOM_OF_SILENCE ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_WISDOM_OF_SILENCE); Assert(pRankBonus != NULL); output.Duration += getPercentValue(output.Duration, pRankBonus->getPoint()); } // pTargetCreature가 저주마법을 반사하는 경우 if (CheckReflection(pVampire, pTargetCreature, getSkillType())) { pTargetCreature = (Creature*)pVampire; TargetObjectID = pVampire->getObjectID(); } Resist_t resist = pTargetCreature->getResist(MAGIC_DOMAIN_CURSE); if (resist > output.Duration ) resist = output.Duration; output.Duration -= resist; if (output.Duration < 20 ) output.Duration = 20; // 이펙트 오브젝트를 생성해서 붙인다. EffectParalyze* pEffectParalyze = new EffectParalyze(pTargetCreature); pEffectParalyze->setLevel(pSkillInfo->getLevel()/2); // pEffectParalyze->setDefensePenalty(output.Damage); pEffectParalyze->setDeadline(output.Duration); pTargetCreature->addEffect(pEffectParalyze); pTargetCreature->setFlag(Effect::EFFECT_CLASS_PARALYZE); if (pTargetCreature->isFlag(Effect::EFFECT_CLASS_BURNING_SOL_CHARGE_1 ) ) { Effect* pEffect = pTargetCreature->findEffect(Effect::EFFECT_CLASS_BURNING_SOL_CHARGE_1); if (pEffect != NULL ) pEffect->setDeadline(0); } // 저주에 걸리면 디펜스가 떨어진다. // 디펜스 페널티가 없어짐. 2002.05.09 - by bezz /* if (pTargetCreature->isSlayer()) { Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature); SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->addModifyInfo(prev, _GCSkillToObjectOK2); } else if (pTargetCreature->isVampire()) { Vampire* pTargetVampire = dynamic_cast<Vampire*>(pTargetCreature); VAMPIRE_RECORD prev; pTargetVampire->getVampireRecord(prev); pTargetVampire->initAllStat(); pTargetVampire->addModifyInfo(prev, _GCSkillToObjectOK2); } else if (pTargetCreature->isMonster()) { Monster* pTargetMonster = dynamic_cast<Monster*>(pTargetCreature); pTargetMonster->initAllStat(); } else Assert(false); */ // 이펙트가 붙었다는 것을 브로드캐스팅해준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pTargetCreature->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_PARALYZE); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(targetX, targetY, &gcAddEffect); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(output.Duration); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(output.Duration); _GCSkillToObjectOK3.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setDuration(output.Duration); _GCSkillToObjectOK6.setXY(vampX, vampY); _GCSkillToObjectOK6.setSkillType(SkillType); _GCSkillToObjectOK6.setDuration(output.Duration); if (bCanSeeCaster) // 10은 땜빵 수치다. { computeAlignmentChange(pTargetCreature, 10, pVampire, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); } else // 10은 땜빵 수치다. { computeAlignmentChange(pTargetCreature, 10, pVampire, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); } pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else { Monster* pTargetMonster = dynamic_cast<Monster*>(pTargetCreature); pTargetMonster->addEnemy(pVampire); } list<Creature*> cList; cList.push_back(pVampire); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(vampX, vampY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(vampX, vampY, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); pVampireSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), pTargetCreature); } } catch(Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void BiteOfDeath::execute(Vampire* pVampire, ObjectID_t TargetObjectID, VampireSkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pVampire != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NPC는 공격할 수 없다. // 저주 면역. by sigi. 2002.9.13 // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !canAttack(pVampire, pTargetCreature ) || pTargetCreature->isNPC() || !pVampire->isFlag(Effect::EFFECT_CLASS_TRANSFORM_TO_WERWOLF) || pTargetCreature->isDead() || pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA)) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillType_t SkillType = getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessBloodDrain(pVampire, pTargetCreature); bool bCanHit = canHit(pVampire, pTargetCreature, SkillType); bool bPK = verifyPK(pVampire, pTargetCreature); bool bMaster = false; if (pTargetCreature->isMonster() ) { Monster* pTargetMonster = dynamic_cast<Monster*>(pTargetCreature); Assert(pTargetMonster != NULL); if (pTargetMonster->isMaster() #ifdef __UNDERWORLD__ || pTargetMonster->isUnderworld() || pTargetMonster->getMonsterType() == 599 #endif ) { bMaster = true; } } ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); if (bManaCheck && bRangeCheck && bHitRoll && bCanHit && bPK && !bMaster) { decreaseMana(pVampire, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pVampire); Exp_t Exp = computeCreatureExp(pTargetCreature, BLOODDRAIN_EXP + KILL_EXP); shareVampExp(pVampire, Exp, _GCSkillToObjectOK1); if (!pVampire->isFlag(Effect::EFFECT_CLASS_MEPHISTO)) { HP_t HealPoint = (Exp==0? computeBloodDrainHealPoint(pTargetCreature, BLOODDRAIN_EXP) : Exp); HP_t CurrentHP = pVampire->getHP(); HP_t MaxHP = pVampire->getHP(ATTR_MAX); HP_t NewHP = min((int)MaxHP , (int)CurrentHP + (int)HealPoint); // 은 데미지 관련 처리를 해 준다. Silver_t newSilverDamage = max(0, (int)pVampire->getSilverDamage()-(int)HealPoint); pVampire->saveSilverDamage(newSilverDamage); _GCSkillToObjectOK1.addShortData(MODIFY_SILVER_DAMAGE, newSilverDamage); // 뱀파이어의 HP를 세팅한다. pVampire->setHP(NewHP); GCStatusCurrentHP gcStatusCurrentHP; gcStatusCurrentHP.setObjectID(pVampire->getObjectID()); gcStatusCurrentHP.setCurrentHP(NewHP); pZone->broadcastPacket(pVampire->getX(), pVampire->getY(), &gcStatusCurrentHP, pVampire); _GCSkillToObjectOK1.addShortData(MODIFY_CURRENT_HP, NewHP); } // 타겟 쥑여뿐다. if (pTargetCreature->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pTargetCreature); pSlayer->setHP(0); } else if (pTargetCreature->isVampire() ) { Vampire* pTargetVampire = dynamic_cast<Vampire*>(pTargetCreature); pTargetVampire->setHP(0); } else if (pTargetCreature->isOusters() ) { Ousters* pOusters = dynamic_cast<Ousters*>(pTargetCreature); pOusters->setHP(0); } else if (pTargetCreature->isMonster() ) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); HP_t decreaseHP = pMonster->getHP(); pMonster->setHP(0); increaseFame(pVampire, decreaseHP); _GCSkillToObjectOK1.addLongData(MODIFY_FAME, pVampire->getFame()); } else Assert(false); affectKillCount(pVampire, pTargetCreature); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK3.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY (targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK6.setXY(myX, myY); _GCSkillToObjectOK6.setSkillType(SkillType); if (bCanSeeCaster) // 10은 땜빵 수치다. { computeAlignmentChange(pTargetCreature, 10, pVampire, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); } else // 10은 땜빵 수치다. { computeAlignmentChange(pTargetCreature, 10, pVampire, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); } list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pVampire); 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); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); if (pTargetPlayer == NULL) { //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else if (pTargetCreature->isMonster()) { Monster* pTargetMonster = dynamic_cast<Monster*>(pTargetCreature); pTargetMonster->addEnemy(pVampire); } } else { executeSkillFailNormal(pVampire, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 타일 핸들러 // 뱀파이어가 Energy Drop Skill을 Tile에 사용했을때 사용하는 Handler ////////////////////////////////////////////////////////////////////////////// void EnergyDrop::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; EffectEnergyDrop * pEffect = NULL; EffectEnergyDrop * pEffect2 = 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); 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 = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); 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; } if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck) { decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); // calculate damage and duration time SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // Holy Smashing 이 있다면 데미지 10% 증가 if (pSlayer->hasRankBonus(RankBonus::RANK_BONUS_HOLY_SMASHING ) ) { RankBonus* pRankBonus = pSlayer->getRankBonus(RankBonus::RANK_BONUS_HOLY_SMASHING); Assert(pRankBonus != NULL); output.Damage += pRankBonus->getPoint(); } Range_t Range = 3; // 기존에 같은 이펙트가 타일에 있다면 지우고 새로 설정한다. Tile& tile = pZone->getTile(X, Y); Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_ENERGY_DROP); if(pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID); } // 이펙트 오브젝트를 생성해서 타일에 붙인다. //cout << "make EffectObject to Tile" << X << " " << Y << endl; pEffect = new EffectEnergyDrop(pZone, X, Y); pEffect->setUserObjectID(pSlayer->getObjectID()); // pEffect->setCasterName(pSlayer->getName()); // pEffect->setPartyID(pSlayer->getPartyID()); pEffect->setDeadline(output.Duration); pEffect->setNextTime(0); pEffect->setTick(output.Tick); pEffect->setDamage(output.Damage); pEffect->setLevel(pSkillInfo->getLevel()/2); // //ObjectRegistry& objectregister = pZone->getObjectRegistry(); //objectregister.registerObject(pEffect); // // //pZone->addEffect(pEffect); //tile.addEffect(pEffect); // 이펙트 오브젝트를 생성해서 타일에 붙인다. pEffect2 = new EffectEnergyDrop(pZone, X, Y); pEffect2->setUserObjectID(pSlayer->getObjectID()); pEffect2->setDeadline(output.Duration); pEffect2->setNextTime(0); pEffect2->setTick(output.Tick); pEffect2->setDamage(output.Damage * 30 / 100); pEffect2->setLevel(pSkillInfo->getLevel()/2); // 이펙트 범위내의 모든 Creature에게 effect를 붙여준다. // Slayer가 기술을 사용한 경우 같은 Slayer에게는 // 해당하지 않는다. bool bEffected = false; bool bHit = false; Creature* pTargetCreature; list<Creature*> cList; cList.push_back(pSlayer); int oX, oY; Level_t maxEnemyLevel = 0; uint EnemyNum = 0; 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); if (!tile.canAddEffect()) continue; pTargetCreature = NULL; if(tile.hasCreature(Creature::MOVE_MODE_WALKING)) pTargetCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); EffectEnergyDrop * pTempEffect = NULL; if(oX == 2 || oX == -2 || oY == 2 || oY == -2 ) pTempEffect = pEffect2; else pTempEffect = pEffect; if(pTargetCreature != NULL && canAttack(pSlayer, pTargetCreature )) { if(pTargetCreature->isVampire()||pTargetCreature->isOusters()) { if(pTempEffect->affectCreature(pTargetCreature, false) == true) { //cout << "EnergyDrop to Slayer Success" << endl; Player* pTargetPlayer = pTargetCreature->getPlayer(); bEffected = true; bHit = true; if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel(); EnemyNum++; bool bCanSee = canSee(pTargetCreature, pSlayer); _GCSkillToTileOK1.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); cList.push_back(pTargetCreature); if (bCanSee) { // 공격을 당한 사람에게 _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Range); pTargetPlayer->sendPacket(&_GCSkillToTileOK2); } } else { //cout << "EnergyDrop to Vampire fail" << endl; } } else if(pTargetCreature->isMonster()) { if(pTempEffect->affectCreature(pTargetCreature, false) == true) { //cout << "EnergyDrop to Monster Success" << endl; bHit = true; if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel(); EnemyNum++; Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pSlayer); // 마지막 때린 애가 슬레이어라고 설정한다. by sigi. 2002.6.21 pMonster->setLastHitCreatureClass(Creature::CREATURE_CLASS_SLAYER); } else { //cout << "EnergyDrop to Monster Falis" << endl; } } } // if(pTargetCreature!= NULL) } if(bHit) { //cout << "Skill Succesfully Attacked(" << output.Damage << ")" << endl; shareAttrExp(pSlayer, output.Damage, 1, 1, 8, _GCSkillToTileOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToTileOK1, maxEnemyLevel, EnemyNum); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToTileOK1); } // 기술을 사용한 사람들에게 _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(Range); // 기술을 쓴 사람만 볼 수 있는 사람들에게 _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); //_GCSkillToTileOK3.setDuration(output.Duration); //_GCSkillToTileOK3.setRange(Range); // 기술을 당한 사람만 볼 수 있는 사람들에게 _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK4.setRange(Range); //기술을 쓴 사람과 당한 사람을 모두 볼 수 있는 사람들에게 _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setRange(Range); // 기술을 사용한 사람에게 packet 전달 pPlayer->sendPacket(&_GCSkillToTileOK1); // 기술을 쓸 사람과 당한 사람을 모두 볼 수 있는 사람들에게 broadcasing // broadcasting후 5번OK를 받은 사람을 기록한다. // 여기에 기록된 사람은 차후 broadcasting에서 제외된다. cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); // 기술을 쓴 사람을 볼 수 있는 사람들에게 broadcasting pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3, cList); // 기술을 당한 사람을 볼 수 있는 사람들에게 broadcasting pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4, cList); // 기술 delay setting pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } SAFE_DELETE(pEffect); SAFE_DELETE(pEffect2); } catch(Throwable& t) { SAFE_DELETE(pEffect); SAFE_DELETE(pEffect2); executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __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 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 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 WildWolf::execute(Vampire* pVampire, ObjectID_t TargetObjectID, VampireSkillSlot* pVampireSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY Assert(pVampire != NULL); Assert(pVampireSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); if (pTargetCreature==NULL ) { Item* pTargetItem = pZone->getItem(TargetObjectID); if (pTargetItem == NULL || pTargetItem->getItemClass() != Item::ITEM_CLASS_CORPSE ) { executeSkillFailException(pVampire, getSkillType()); return; } eatCorpse(pVampire, pTargetItem, pVampireSkillSlot); return; } // NPC는 공격할 수가 없다. // NoSuch제거. by sigi. 2002.5.2 if (!canAttack(pVampire, pTargetCreature ) || pTargetCreature->isNPC() ) { executeSkillFailException(pVampire, getSkillType()); return; } if (pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA ) ) { eatComaCreature(pVampire, pTargetCreature); return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK5 _GCSkillToObjectOK5; SkillType_t SkillType = pVampireSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); Range_t Range = pSkillInfo->getRange(); int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, Range); bool bHitRoll = HitRoll::isSuccess(pVampire, pTargetCreature); bool bCanHit = canHit(pVampire, pTargetCreature, getSkillType()); bool bPK = verifyPK(pVampire, pTargetCreature); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bCanHit && bPK) { SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); Damage_t Damage = output.Damage; bool bCriticalHit = false; Damage += computeDamage(pVampire, pTargetCreature, 0, bCriticalHit); // 마나를 깍는다. decreaseMana(pVampire, RequiredMP, _GCSkillToObjectOK1); EffectSetAfire* pEffect = new EffectSetAfire(pTargetCreature); pEffect->setDamage(Damage); pEffect->setTick(3); pEffect->setNextTime(3); pEffect->setTimes(3); pEffect->setCasterOID(pVampire->getObjectID()); pTargetCreature->addEffect(pEffect); increaseAlignment(pVampire, pTargetCreature, _GCSkillToObjectOK1); // 패킷을 보낸다. _GCSkillToObjectOK1.setSkillType(getSkillType()); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK2.setSkillType(getSkillType()); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK5.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setSkillType(getSkillType()); pPlayer->sendPacket(&_GCSkillToObjectOK1); Player* pTargetPlayer = NULL; if (pTargetCreature->isPC()) { pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } else { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pVampire); } list<Creature*> cList; cList.push_back(pVampire); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(pVampire->getX(), pVampire->getY(), pTargetCreature->getX(), pTargetCreature->getY(), &_GCSkillToObjectOK5, cList); pVampireSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), pTargetCreature); } } catch(Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } __END_CATCH }
void SimpleMissileSkill::execute( Vampire* pVampire, ObjectID_t TargetObjectID, VampireSkillSlot* pVampireSkillSlot, const SIMPLE_SKILL_INPUT& param, SIMPLE_SKILL_OUTPUT& result, CEffectID_t CEffectID, int HitBonus) throw(Error) { __BEGIN_TRY Assert(pVampire != NULL); Assert(pVampireSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->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(pVampire, pTargetCreature ) || pTargetCreature->isNPC()) { executeSkillFailException(pVampire, param.SkillType); return; } result.pTargetCreature = pTargetCreature; GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; GCSkillToObjectOK6 _GCSkillToObjectOK6; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(param.SkillType); bool bCriticalHit = false; Damage_t Damage = 0; if (param.bAdd) { // 파라미터로 전달된 데미지 값이 더해지는 데미지라면, // 일반 데미지를 계산 후, 데미지를 더해야 한다. // 파라미터로 전달된 데미지 값이 직접적으로 쓰이는 데미지라면, // 이 부분까지 들어오지 않으므로, 밑의 부분까지 0으로 전달된다. Damage += computeDamage(pVampire, pTargetCreature, 0, bCriticalHit); } if (param.bMagicDamage) { // 만일 스킬 데미지가 마법 데미지라면, 마법 데미지 계산 함수를 이용해 계산을 해준다. Damage += computeMagicDamage(pTargetCreature, param.SkillDamage, param.SkillType, true, pVampire); } else { Damage += param.SkillDamage; } int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = false; bool bCanHit = canHit(pVampire, pTargetCreature, param.SkillType); bool bPK = verifyPK(pVampire, pTargetCreature); if (param.bMagicHitRoll) { bHitRoll = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus); } else { bHitRoll = HitRoll::isSuccess(pVampire, pTargetCreature); } ZoneCoord_t vampX = pVampire->getX(); ZoneCoord_t vampY = pVampire->getY(); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bCanHit && bPK) { decreaseMana(pVampire, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pVampire); // 데미지를 가하고, 아이템 내구도를 떨어뜨린다. if (bCanSeeCaster) { setDamage(pTargetCreature, Damage, pVampire, param.SkillType, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pVampire, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); decreaseDurability(pVampire, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK2); } else { setDamage(pTargetCreature, Damage, pVampire, param.SkillType, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); computeAlignmentChange(pTargetCreature, Damage, pVampire, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); decreaseDurability(pVampire, pTargetCreature, pSkillInfo, &_GCSkillToObjectOK1, &_GCSkillToObjectOK6); } // 상대가 죽었다면 경험치를 좀 올려준다. if (pTargetCreature->isDead()) { int exp = computeCreatureExp(pTargetCreature, KILL_EXP); shareVampExp(pVampire, exp, _GCSkillToObjectOK1); } increaseAlignment(pVampire, pTargetCreature, _GCSkillToObjectOK1); _GCSkillToObjectOK1.setSkillType(param.SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK2.setSkillType(param.SkillType); _GCSkillToObjectOK2.setDuration(0); _GCSkillToObjectOK3.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK3.setSkillType(param.SkillType); _GCSkillToObjectOK3.setTargetXY(targetX, targetY); _GCSkillToObjectOK4.setSkillType(param.SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK5.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK5.setSkillType(param.SkillType); _GCSkillToObjectOK6.setXY(vampX, vampY); _GCSkillToObjectOK6.setSkillType(param.SkillType); _GCSkillToObjectOK6.setDuration(0); 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(pVampire); } list<Creature*> cList; cList.push_back(pVampire); cList.push_back(pTargetCreature); cList = pZone->broadcastSkillPacket(vampX, vampY, targetX, targetY, &_GCSkillToObjectOK5, cList); pZone->broadcastPacket(vampX, vampY, &_GCSkillToObjectOK3 , cList); pZone->broadcastPacket(targetX, targetY, &_GCSkillToObjectOK4 , cList); pVampireSkillSlot->setRunTime(param.Delay); result.bSuccess = true; } else { executeSkillFailNormal(pVampire, param.SkillType, pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pVampire, param.SkillType); } __END_CATCH }
void CGTameMonsterHandler::execute (CGTameMonster* pPacket , Player* pPlayer) throw(Error) { __BEGIN_TRY #ifdef __GAME_SERVER__ GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Assert(pGamePlayer != NULL); PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pGamePlayer->getCreature()); Assert(pPC != NULL); Zone* pZone = pPC->getZone(); Assert(pZone != NULL); Monster* pMonster = dynamic_cast<Monster*>(pZone->getCreature(pPacket->getObjectID() )); if (pMonster == NULL ) return; Item* pItem = pPC->getExtraInventorySlotItem(); if (pItem == NULL || pItem->getItemClass() != Item::ITEM_CLASS_PET_FOOD || pItem->getNum() != 1 ) return; PetFoodInfo* pPetFoodInfo = dynamic_cast<PetFoodInfo*>(g_pPetFoodInfoManager->getItemInfo(pItem->getItemType() )); Assert(pPetFoodInfo != NULL); Inventory* pInventory = pPC->getInventory(); if (pInventory == NULL ) return; ItemType_t petType = PET_COMMON; PetItem* pPetItem = dynamic_cast<PetItem*>(g_pItemFactoryManager->createItem(Item::ITEM_CLASS_PET_ITEM, petType, list<OptionType_t>() )); Assert(pPetItem != NULL); _TPOINT pt; if (!pInventory->getEmptySlot(pPetItem, pt ) ) { GCCannotUse gcCannotUse; pGamePlayer->sendPacket(&gcCannotUse); SAFE_DELETE(pPetItem); return; } pPC->deleteItemFromExtraInventorySlot(); GCDeleteInventoryItem gcDI; gcDI.setObjectID(pItem->getObjectID()); pGamePlayer->sendPacket(&gcDI); pItem->destroy(); SAFE_DELETE(pItem); /* * 여기서 뭔가 확인을 해야 한다. */ int ratio = rand()%100; if (g_pVariableManager->getVariable(PET_DAY_EVENT) != 0 ) { ratio = 100; } // 공용 펫만 꼬실 수 있다. PetTypeInfo* pPetTypeInfo = PetTypeInfoManager::getInstance()->getPetTypeInfo(petType); if (pPetTypeInfo == NULL || pPetTypeInfo->getOriginalMonsterType() != pMonster->getMonsterType() || ratio >= pPetFoodInfo->getTameRatio() ) { //cout << "꼬시기 실패 : " << ratio << endl; SAFE_DELETE(pPetItem); pMonster->addEnemy(pPC); return; } pZone->deleteCreature(pMonster, pMonster->getX(), pMonster->getY()); SAFE_DELETE(pMonster); /* * 여기서 해당 펫의 정보를 가져와야 된다. */ PetInfo* pPetInfo = new PetInfo; pPetInfo->setPetType(petType); pPetInfo->setPetLevel(0); pPetInfo->setPetCreatureType(pPetTypeInfo->getPetCreatureType(0)); pPetInfo->setPetAttr(0xff); pPetInfo->setPetExp(0); pPetInfo->setPetAttrLevel(0); pPetInfo->setFoodType(pPetFoodInfo->getItemType()); pPetInfo->setGamble(0); pPetInfo->setCutHead(0); pPetInfo->setPetHP(pPetFoodInfo->getPetHP()); pPetInfo->setFeedTime(VSDateTime::currentDateTime()); // 양방향 링크 pPetItem->setPetInfo(pPetInfo); pPetInfo->setPetItem(pPetItem); pZone->registerObject(pPetItem); pInventory->addItem(pPetItem, pt); Assert(pt.x != -1); pPetItem->create(pPC->getName(), STORAGE_INVENTORY, 0, pt.x, pt.y); // TraceLog 를 남긴다. remainTraceLog(pPetItem, "GOD", pPC->getName(), ITEM_LOG_CREATE, DETAIL_PICKUP); GCCreateItem gcCreateItem; makeGCCreateItem(&gcCreateItem, pPetItem, pt.x, pt.y); pGamePlayer->sendPacket(&gcCreateItem); //pPetItem->whenPCTake(pPC); pPC->getGQuestManager()->tamePet(pPetInfo); addOlympicStat(pPC, 9); #endif __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 }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 타일 핸들러 - 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 EffectSpiritGuard::affect(Creature* pCastCreature) throw(Error) { __BEGIN_TRY Assert(pCastCreature != NULL); if (!pCastCreature->isSlayer() ) return; Player* pPlayer = dynamic_cast<Player*>(pCastCreature->getPlayer()); Assert(pPlayer != NULL); Slayer* pSlayer = dynamic_cast<Slayer*>(pCastCreature); Assert(pSlayer != NULL); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SKILL_SPIRIT_GUARD); if (pSkillInfo == NULL ) { return; } GCModifyInformation gcAttackerMI; Zone* pZone = pCastCreature->getZone(); Assert(pZone != NULL); VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); ZoneCoord_t Cx = pCastCreature->getX(); ZoneCoord_t Cy = pCastCreature->getY(); bool isHit = false; Level_t maxEnemyLevel = 0; uint EnemyNum = 0; for (int x=-1; x<=1; x++ ) { for (int y=-1; y<=1; y++ ) { if (x == 0 && y == 0 ) continue; int X = Cx + x; int Y = Cy + y; if (!rect.ptInRect(X, Y ) ) continue; // 타일안에 존재하는 오브젝트를 가져온다. Tile& tile = pZone->getTile(X, Y); if(tile.hasCreature(Creature::MOVE_MODE_WALKING) ) { Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); Assert(pCreature != NULL); // 자신은 맞지 않는다. 무적도 안 맞는다. 슬레이어도 안 맞느다. // 안전지대 체크 // 2003.1.10 by bezz, Sequoia if (pCreature == m_pTarget || !canAttack(pCastCreature, pCreature ) || pCreature->isFlag(Effect::EFFECT_CLASS_COMA ) || pCreature->isSlayer() || pCreature->isNPC() || !checkZoneLevelToHitTarget(pCreature) ) { continue; } isHit = true; if (maxEnemyLevel < pCreature->getLevel() ) maxEnemyLevel = pCreature->getLevel(); EnemyNum++; if (pCreature->isVampire() || pCreature->isOusters() ) { // Vampire* pVampire = dynamic_cast<Vampire*>(pCreature); GCModifyInformation gcMI; ::setDamage(pCreature, m_Damage, pCastCreature, SKILL_SPIRIT_GUARD, &gcMI, &gcAttackerMI); pCreature->getPlayer()->sendPacket(&gcMI); // 맞는 동작을 보여준다. GCSkillToObjectOK2 gcSkillToObjectOK2; gcSkillToObjectOK2.setObjectID(1); // 의미 없다. gcSkillToObjectOK2.setSkillType(SKILL_ATTACK_MELEE); gcSkillToObjectOK2.setDuration(0); pCreature->getPlayer()->sendPacket(&gcSkillToObjectOK2); } else if (pCreature->isMonster() ) { Monster* pMonster = dynamic_cast<Monster*>(pCreature); ::setDamage(pMonster, m_Damage, pCastCreature, SKILL_SPIRIT_GUARD, NULL, &gcAttackerMI); pMonster->addEnemy(pCastCreature); } else Assert(false); GCSkillToObjectOK4 gcSkillToObjectOK4; gcSkillToObjectOK4.setSkillType(SKILL_ATTACK_MELEE); gcSkillToObjectOK4.setTargetObjectID(pCreature->getObjectID()); gcSkillToObjectOK4.setDuration(0); pZone->broadcastPacket(X, Y, &gcSkillToObjectOK4, pCreature); } } } if (isHit ) { SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillSlot* pSkillSlot = pSlayer->getSkill(SKILL_SPIRIT_GUARD); if (pSkillSlot != NULL ) { increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), gcAttackerMI, maxEnemyLevel, EnemyNum); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, gcAttackerMI); } } setNextTime(m_Delay); __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 }
bool BloodDrain::executeMonster(Monster* pMonster, Creature* pEnemy) throw(Error) { __BEGIN_TRY bool isMaster = pMonster->isMaster() #ifdef __UNDERWORLD__ || pMonster->isUnderworld() || pMonster->getMonsterType() == 599 #endif ; // 죽었으면 흡혈 못하고.. // 마스터는 아무나 다 빤다 - -; // 대상이 죽었으면 못 빤다. if (pMonster->isDead() || pMonster->isFlag(Effect::EFFECT_CLASS_COMA) || !pMonster->isEnemyToAttack(pEnemy) && !isMaster || pEnemy->isDead() || pEnemy->isFlag(Effect::EFFECT_CLASS_COMA)) { return false; } Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); GCBloodDrainOK1 _GCBloodDrainOK1; GCBloodDrainOK2 _GCBloodDrainOK2; GCBloodDrainOK3 _GCBloodDrainOK3; // 마스터는 체력 100% 라도 문다. int HPMultiplier = (isMaster? 1 : 3); // 현재 HP가 1/1, 1/3 bool bHitRoll = HitRoll::isSuccessBloodDrain(pMonster, pEnemy, HPMultiplier); bool bCanHit = canHit(pMonster, pEnemy, SKILL_BLOOD_DRAIN); // 마스터는 거리에 관계없이 문다~ bool bRangeCheck = isMaster || verifyDistance(pMonster, pEnemy, 1); // 흡혈 면역 상태. by sigi. 2002.9.13 bool bEffected = pEnemy->isFlag(Effect::EFFECT_CLASS_IMMUNE_TO_BLOOD_DRAIN); if (bHitRoll && bCanHit && bRangeCheck && !bEffected) { if (pEnemy->isSlayer()) { // Set EffectBloodDrain // 마스터면 안건다. if (!isMaster) { EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pEnemy); pEffectBloodDrain->setLevel(pMonster->getLevel()); pEffectBloodDrain->setDeadline(BLOODDRAIN_DURATION); // 게임시간으로 3일 정도 pEnemy->addEffect(pEffectBloodDrain); pEffectBloodDrain->create(pEnemy->getName()); _GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN); pEnemy->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pEnemy); SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->sendRealWearingInfo(); pTargetSlayer->addModifyInfo(prev, _GCBloodDrainOK2); } // 로그를 남긴다. //log(LOG_BLOODDRAINED, pEnemy->getName(), "게임 내의 몬스터"); } // 아우스터즈의 경우엔..... -_-; 제한시간 없는 이펙트를 생성한다. 엄밀히 말해 제한시간이 없는 건 아니지만.. // else if (pEnemy->isOusters() && !isMaster ) // { // EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pEnemy); // pEffectBloodDrain->setLevel(pMonster->getLevel()); // pEnemy->addEffect(pEffectBloodDrain); // pEffectBloodDrain->create(pEnemy->getName()); // _GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN); // // pEnemy->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); // // Sight_t oldSight = pEnemy->getSight(); // Sight_t newSight = pEnemy->getEffectedSight(); // // if (oldSight != newSight ) // { // pEnemy->setSight(newSight); // pZone->updateScan(pEnemy, oldSight, pEnemy->getSight()); // _GCBloodDrainOK2.addShortData(MODIFY_VISION, pEnemy->getSight()); // // GCChangeDarkLight gcChangeDarkLight; // gcChangeDarkLight.setDarkLevel(15); // gcChangeDarkLight.setLightLevel(newSight); // pEnemy->getPlayer()->sendPacket(&gcChangeDarkLight); // } // } _GCBloodDrainOK3.setObjectID(pMonster->getObjectID()); _GCBloodDrainOK3.setTargetObjectID (pEnemy->getObjectID()); // 타겟이 뭐든 플래그는 건다. // 마스터면 안건다. if (!isMaster) { pEnemy->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); } if (pEnemy != NULL && pEnemy->isPC()) { Player* pTargetPlayer = pEnemy->getPlayer(); if (pTargetPlayer != NULL) { _GCBloodDrainOK2.setObjectID(pMonster->getObjectID()); if (!isMaster) { // _GCBloodDrainOK2.addLongData(MODIFY_DURATION, BLOODDRAIN_DURATION); } pTargetPlayer->sendPacket(&_GCBloodDrainOK2); } } // target int targetLevel = 0; int targetMaxHP = 0; if (pEnemy->isSlayer()) { Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pEnemy); targetLevel = pTargetSlayer->getHighestSkillDomainLevel(); targetMaxHP = pTargetSlayer->getHP(ATTR_MAX); } else if (pEnemy->isVampire()) { Vampire* pTargetVampire = dynamic_cast<Vampire*>(pEnemy); targetLevel = pTargetVampire->getLevel(); targetMaxHP = pTargetVampire->getHP(ATTR_MAX); } else if (pEnemy->isOusters()) { Ousters* pTargetOusters = dynamic_cast<Ousters*>(pEnemy); targetLevel = pTargetOusters->getLevel(); targetMaxHP = pTargetOusters->getHP(ATTR_MAX); } else if (pEnemy->isMonster()) { Monster* pEnemyMonster = dynamic_cast<Monster*>(pEnemy); // 흡혈당하는 몬스터한테 딜레이 걸어준다. Timeval DelayTurn; DelayTurn.tv_sec = 4; DelayTurn.tv_usec = 500000; pEnemyMonster->addAccuDelay(DelayTurn); if ((pMonster->isMaster() #ifdef __UNDERWORLD__ || pMonster->isUnderworld() || pMonster->getMonsterType() == 599 #endif ) && pMonster->getClanType()==pEnemyMonster->getClanType()) { // 같은 clan의 마스터이면 피 상납이라고 볼 수 있을까 -_-; } else { pEnemyMonster->addEnemy(pMonster); } targetLevel = pEnemyMonster->getLevel(); targetMaxHP = pEnemyMonster->getHP(ATTR_MAX); } // 자신이나 상대방 중.. HP가 많은 쪽의 15~25% HP_t maxHP = max((int)pMonster->getHP(ATTR_MAX), targetMaxHP); HP_t drainHP = maxHP*(rand()%11+15)/100; // 15~25% // 한번에 1000이상 안 찬다. if (pMonster->getMonsterType() >= 717 ) drainHP = min((int)drainHP, 2000); else drainHP = min((int)drainHP, 1000); // 몬스터의 HP를 올려준다. HP_t CurrentHP = pMonster->getHP(); HP_t MaxHP = pMonster->getHP(ATTR_MAX); HP_t NewHP = min((int)MaxHP , (int)CurrentHP + (int)drainHP); // 뱀파이어의 HP를 세팅한다. pMonster->setHP(NewHP); GCStatusCurrentHP gcStatusCurrentHP; gcStatusCurrentHP.setObjectID(pMonster->getObjectID()); gcStatusCurrentHP.setCurrentHP(NewHP); pZone->broadcastPacket(pMonster->getX(), pMonster->getY(), &gcStatusCurrentHP); // 흡혈 당한 애의 HP를 줄인다. // 대상이 내 레벨보다 높다면.. MaxHP의 10~15% damage // by sigi. 2002.9.14 int drainDamage = 0; int myLevel = pMonster->getLevel(); if (targetLevel > myLevel) { drainDamage = targetMaxHP * (rand()%6+10) / 100; } else { // 레벨 5차이마다 1%씩 더~ int damagePercent = min(30, (rand()%6+10+(myLevel-targetLevel))); drainDamage = targetMaxHP * damagePercent / 100; } if (drainDamage > 0) { //decreaseHP(pZone, pEnemy, drainDamage); EffectDecreaseHP* pEffect = new EffectDecreaseHP(pEnemy); pEffect->setPoint(drainDamage); pEffect->setDeadline(20); // 2초 후 pEffect->setUserObjectID(pMonster->getObjectID()); pEnemy->addEffect(pEffect); pEnemy->setFlag(Effect::EFFECT_CLASS_DECREASE_HP); } // 흡혈 모습 보이게.. list<Creature *> cList; cList.push_back(pEnemy); cList.push_back(pMonster); pZone->broadcastPacket(pMonster->getX(), pMonster->getY(), &_GCBloodDrainOK3 , cList); // 흡혈 성공 return true; } __END_CATCH return false; }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void Hallucination::execute(Vampire* pVampire, ObjectID_t TargetObjectID, VampireSkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pVampire != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->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(pVampire, pTargetCreature ) || pTargetCreature->isFlag(Effect::EFFECT_CLASS_IMMUNE_TO_HALLUCINATION) || pTargetCreature->isNPC() ) { executeSkillFailException(pVampire, 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); int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessVampireCurse(pSkillInfo->getLevel(), pTargetCreature->getResist(MAGIC_DOMAIN_CURSE)); bool bHitRoll2 = HitRoll::isSuccessHallucination(pVampire, pTargetCreature); bool bCanHit = canHit(pVampire, pTargetCreature, SkillType); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_HALLUCINATION); bool bPK = verifyPK(pVampire, pTargetCreature); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bHitRoll2 && bCanHit && !bEffected && bPK) { decreaseMana(pVampire, RequiredMP, _GCSkillToObjectOK1); bool bCanSeeCaster = canSee(pTargetCreature, pVampire); SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); // pTargetCreature가 저주마법을 반사하는 경우 if (CheckReflection(pVampire, pTargetCreature, getSkillType())) { pTargetCreature = (Creature*)pVampire; TargetObjectID = pVampire->getObjectID(); } // 이펙트 오브젝트를 생성해 붙인다. EffectHallucination* pEffect = new EffectHallucination(pTargetCreature); pEffect->setDeadline(output.Duration); pEffect->setLevel(pSkillInfo->getLevel()/2); pTargetCreature->addEffect(pEffect); pTargetCreature->setFlag(Effect::EFFECT_CLASS_HALLUCINATION); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(output.Duration); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(output.Duration); _GCSkillToObjectOK3.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY (targetX, targetY); _GCSkillToObjectOK4.setSkillType(SkillType); _GCSkillToObjectOK4.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK4.setDuration(output.Duration); _GCSkillToObjectOK5.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration(output.Duration); _GCSkillToObjectOK6.setXY(myX, myY); _GCSkillToObjectOK6.setSkillType(SkillType); _GCSkillToObjectOK6.setDuration(output.Duration); if (bCanSeeCaster) // 10은 땜빵 수치다. { computeAlignmentChange(pTargetCreature, 10, pVampire, &_GCSkillToObjectOK2, &_GCSkillToObjectOK1); } else // 10은 땜빵 수치다. { computeAlignmentChange(pTargetCreature, 10, pVampire, &_GCSkillToObjectOK6, &_GCSkillToObjectOK1); } list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pVampire); 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); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); if (pTargetPlayer == NULL) { //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } if (bCanSeeCaster) pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); else pTargetPlayer->sendPacket(&_GCSkillToObjectOK6); } else if (pTargetCreature->isMonster()) { Monster* pTargetMonster = dynamic_cast<Monster*>(pTargetCreature); pTargetMonster->addEnemy(pVampire); } GCAddEffect gcAddEffect; gcAddEffect.setObjectID(TargetObjectID); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_HALLUCINATION); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(targetX, targetY, &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }