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 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 ProtectionFromAcid::execute(Slayer* pSlayer, ObjectID_t TargetObjectID, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pTargetCreature = pZone->getCreature(TargetObjectID); //Assert(pTargetCreature != NULL); // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || !pTargetCreature->isSlayer() ) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK5 _GCSkillToObjectOK5; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_PROTECTION_FROM_ACID); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { // 마나를 줄인다. decreaseMana(pSlayer, RequiredMP, _GCSkillToObjectOK1); // 경험치를 올려준다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1); shareAttrExp(pSlayer, ExpUp, 1, 1, 8, _GCSkillToObjectOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToObjectOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToObjectOK1); // 이펙트의 효과와 지속시간을 계산한다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; input.TargetType = SkillInput::TARGET_OTHER; computeOutput(input, output); // 이펙트를 생성해서 붙인다. EffectProtectionFromAcid* pEPFP = new EffectProtectionFromAcid (pTargetCreature); Assert(pEPFP != NULL); pEPFP->setDeadline(output.Duration); pEPFP->setResist(output.Damage); pTargetCreature->addEffect(pEPFP); pTargetCreature->setFlag(Effect::EFFECT_CLASS_PROTECTION_FROM_ACID); if (pTargetCreature->isSlayer()) { Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature); SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->addModifyInfo(prev, _GCSkillToObjectOK1); } else { Assert(false); } // 패킷을 준비해서 보낸다. _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(output.Duration); _GCSkillToObjectOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration (output.Duration); _GCSkillToObjectOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToObjectOK5.setSkillType(SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration (output.Duration); // Send Packet pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pSlayer != pTargetCreature && pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } list<Creature*> cList; cList.push_back(pSlayer); cList.push_back(pTargetCreature); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &_GCSkillToObjectOK5 , cList); // 이펙트가 붙었다고 알려준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pTargetCreature->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_PROTECTION_FROM_ACID); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), pTargetCreature); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
void SimpleCureSkill::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); // 슬레이어 외에는 치료할 수가 없다. // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL || pTargetCreature->isSlayer() == false) { executeSkillFailException(pSlayer, param.SkillType); return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; GCSkillToObjectOK4 _GCSkillToObjectOK4; GCSkillToObjectOK5 _GCSkillToObjectOK5; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(param.SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); bool bHPCheck = false; // 체력이 닳거나, 흡혈을 당한 상태여야 한다. Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature); Assert(pTargetSlayer != NULL); EffectBloodDrain* pEffectBloodDrain = NULL; if (pTargetSlayer->getHP(ATTR_CURRENT) < pTargetSlayer->getHP(ATTR_MAX)) { bHPCheck = true; } if (pTargetSlayer->isFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN)) { Effect* pEffect = pTargetSlayer->findEffect(Effect::EFFECT_CLASS_BLOOD_DRAIN); pEffectBloodDrain = dynamic_cast<EffectBloodDrain*>(pEffect); Assert(pEffectBloodDrain != NULL); if (pEffectBloodDrain->getLevel() < param.Level) bHPCheck = true; } int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, pTargetCreature, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); if (bHPCheck && bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && pTargetCreature->isAlive()) { decreaseMana(pSlayer, RequiredMP, _GCSkillToObjectOK1); uint HealPoint = param.SkillDamage; // 흡혈당한 상태라면 흡혈 상태를 날려준다. if (pEffectBloodDrain != NULL && pEffectBloodDrain->getLevel() < param.Level) { // 흡혈 아르바이트를 방지하기 위한 후유증 이펙트를 붙여준다. if (pTargetSlayer->isFlag(Effect::EFFECT_CLASS_AFTERMATH)) { Effect* pEffect = pTargetSlayer->findEffect(Effect::EFFECT_CLASS_AFTERMATH); EffectAftermath* pEffectAftermath = dynamic_cast<EffectAftermath*>(pEffect); pEffectAftermath->setDeadline(5*600); // 5분 동안 지속된다. } else { EffectAftermath* pEffectAftermath = new EffectAftermath(pTargetSlayer); pEffectAftermath->setDeadline(5*600); // 5분 동안 지속된다. pTargetSlayer->addEffect(pEffectAftermath); pTargetSlayer->setFlag(Effect::EFFECT_CLASS_AFTERMATH); pEffectAftermath->create(pTargetSlayer->getName()); } pEffectBloodDrain->destroy(pTargetSlayer->getName()); pTargetSlayer->deleteEffect(Effect::EFFECT_CLASS_BLOOD_DRAIN); SLAYER_RECORD prev; pTargetSlayer->getSlayerRecord(prev); pTargetSlayer->initAllStat(); pTargetSlayer->sendRealWearingInfo(); pTargetSlayer->addModifyInfo(prev, _GCSkillToObjectOK2); GCRemoveEffect gcRemoveEffect; gcRemoveEffect.setObjectID(pTargetSlayer->getObjectID()); gcRemoveEffect.addEffectList((EffectID_t)Effect::EFFECT_CLASS_BLOOD_DRAIN); pZone->broadcastPacket(pTargetSlayer->getX(), pTargetSlayer->getY(), &gcRemoveEffect); } // 다른 사람을 치료한다. HP_t CurrentHP = pTargetSlayer->getHP(ATTR_CURRENT); HP_t MaxHP = pTargetSlayer->getHP(ATTR_MAX); // 실제 회복 수치를 계산한다. int RealHealPoint = 0; if(CurrentHP + HealPoint <= MaxHP ) { RealHealPoint = max((unsigned int)0, HealPoint); } else { RealHealPoint = max(0, MaxHP - CurrentHP); } // 경험치를 올려준다. shareAttrExp(pSlayer, HealPoint , param.STRMultiplier, param.DEXMultiplier, param.INTMultiplier, _GCSkillToObjectOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToObjectOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToObjectOK1); CurrentHP = min((int)(MaxHP), (int)(CurrentHP + HealPoint)); pTargetSlayer->setHP(CurrentHP, ATTR_CURRENT); // 치료가 되었으니 HP를 브로드캐스팅한다. GCStatusCurrentHP gcStatusCurrentHP; gcStatusCurrentHP.setObjectID(TargetObjectID); gcStatusCurrentHP.setCurrentHP (CurrentHP); pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &gcStatusCurrentHP); _GCSkillToObjectOK2.addShortData(MODIFY_CURRENT_HP, CurrentHP); ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); _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.setSkillType(param.SkillType); _GCSkillToObjectOK5.setTargetObjectID (TargetObjectID); _GCSkillToObjectOK5.setDuration (0); pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } 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 }