////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// 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 }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// 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 BackStab::execute(Ousters* pOusters, ObjectID_t TargetObjectID, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL ) { executeSkillFailException(pOusters, getSkillType()); return; } SIMPLE_SKILL_INPUT param; param.SkillType = getSkillType(); // param.SkillDamage = output.Damage; bool bCritical = false; if (HitRoll::isSuccessBackStab(pOusters ) ) { double ratio = (1.0 + (2 * input.SkillLevel / 30.0 )); param.SkillDamage = (short unsigned int)(max(1, Random(pWeapon->getMinDamage(), pWeapon->getMaxDamage() ) ) * ratio); if (input.SkillLevel == 30 ) param.SkillDamage = (short unsigned int)(param.SkillDamage * 1.1); bCritical = true; } else { param.SkillDamage = 0; } param.Delay = 0; param.ItemClass = Item::ITEM_CLASS_OUSTERS_CHAKRAM; param.STRMultiplier = 0; param.DEXMultiplier = 0; param.INTMultiplier = 0; param.bMagicHitRoll = false; param.bMagicDamage = false; param.bAdd = true; if (input.SkillLevel < 15 ) param.Grade = 0; else if (input.SkillLevel < 30 ) param.Grade = 1; else param.Grade = 2; SIMPLE_SKILL_OUTPUT result; g_SimpleMeleeSkill.execute(pOusters, TargetObjectID, pOustersSkillSlot, param, result, CEffectID); if (bCritical && result.bSuccess ) { GCAddEffect gcAddEffect; gcAddEffect.setObjectID(TargetObjectID); if (param.Grade == 0 ) gcAddEffect.setEffectID(Effect::EFFECT_CLASS_BACK_STAB); else if (param.Grade == 1 ) gcAddEffect.setEffectID(Effect::EFFECT_CLASS_BACK_STAB_2); else gcAddEffect.setEffectID(Effect::EFFECT_CLASS_BACK_STAB_3); gcAddEffect.setDuration(0); Zone* pZone = pOusters->getZone(); if (pZone != NULL ) { Creature* pCreature = pZone->getCreature(TargetObjectID); if (pCreature != NULL ) { pZone->broadcastPacket(pCreature->getX(), pCreature->getY(), &gcAddEffect); } } } __END_CATCH }
ExecStreamResult SortedAggExecStream::execute(ExecStreamQuantum const &quantum) { int keyComp; ExecStreamResult rc; /* Perform EOS processing first, since there can be a result tuple which is not produced yet. */ if (pInAccessor->getState() == EXECBUF_EOS) { if (!prevTupleValid) { state = STATE_DONE; } // no more input is coming if (state == STATE_DONE) { // already produced output pOutAccessor->markEOS(); return EXECRC_EOS; } if (state == STATE_ACCUMULATING) { // compute final output and get ready to write it computeOutput(); state = STATE_PRODUCING; } // attempt to write output bool success = pOutAccessor->produceTuple(outputTuple); if (success) { state = STATE_DONE; // let precheckConduitBuffers below return EOS for us } else { return EXECRC_BUF_OVERFLOW; } } else if (state == STATE_PRODUCING) { rc = produce(); if (rc != EXECRC_YIELD) { return rc; } } /* Check buffer state. If it is in a good state(EXECRC_YIELD, i.e. not in any abnormal state and is not empty), process the tuples from the buffer. */ rc = precheckConduitBuffers(); if (rc != EXECRC_YIELD) { return rc; } /* Iterate through all the INPUT tuples. In this method, quantum represents unit of input data. */ for (uint nTuples = 0; nTuples < quantum.nTuplesMax; ++nTuples) { if (!pInAccessor->demandData()) { return EXECRC_BUF_UNDERFLOW; } assert(state == STATE_ACCUMULATING); pInAccessor->unmarshalTuple(inputTuple); if (prevTupleValid) { keyComp = compareGroupByKeys(); assert(keyComp <= 0); if (keyComp == 0) { // continue reading rows and computing aggregates // for this group updateAccumulator(); pInAccessor->consumeTuple(); } else { // ready to produce an output row below computeOutput(); state = STATE_PRODUCING; } } else { /* first tuple read so nothing to compare it to yet, but still need to record group by key and compute aggregates for that first row. */ prevTupleValid = true; copyPrevGroupByKey(); updateAccumulator(); pInAccessor->consumeTuple(); } if (state == STATE_PRODUCING) { rc = produce(); if (rc != EXECRC_YIELD) { return rc; } } } return EXECRC_YIELD; }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 ////////////////////////////////////////////////////////////////////////////// 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 Light::execute(Slayer* pSlayer, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_LIGHT); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); // 기술이 유지되는 시간은 숙련도에 따라서 달라진다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); Sight_t CurrentSight = pSlayer->getSight(); Sight_t oldSight = CurrentSight; // 혹시라도 옛날 이펙트가 남아있다면 삭제한다. if (pSlayer->isEffect(Effect::EFFECT_CLASS_LIGHT)) { EffectLight* pOldEffectLight = (EffectLight*)pSlayer->findEffect(Effect::EFFECT_CLASS_LIGHT); CurrentSight = pOldEffectLight->getOldSight(); pSlayer->deleteEffect(Effect::EFFECT_CLASS_LIGHT); } // 이펙트를 만들어 붙인다. EffectLight* pEffectLight = new EffectLight (pSlayer); pEffectLight->setDeadline(output.Duration); pEffectLight->setOldSight(CurrentSight); pSlayer->setFlag(Effect::EFFECT_CLASS_LIGHT); pSlayer->addEffect(pEffectLight); //pEffectLight->create(pSlayer->getName()); // 시야처리.. Sight_t MinSight = pSkillInfo->getMinDamage(); Sight_t MaxSight = pSkillInfo->getMaxDamage(); Sight_t NewSight = MinSight + (MaxSight - MinSight)* SkillLevel / 100; // 시야 변경에 따른 오브젝트 가감 패킷을 보낸다. pZone->updateScan(pSlayer, oldSight, NewSight); pSlayer->setSight(NewSight); if (NewSight != oldSight) _GCSkillToSelfOK1.addShortData(MODIFY_VISION, NewSight); _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); // EXP UP! SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1)* 2; shareAttrExp(pSlayer, ExpUp, 1, 1, 8, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); // Send Packet pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &_GCSkillToSelfOK2 , pSlayer); // 이펙트가 붙었다고 알려준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pSlayer->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_LIGHT); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch(Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 아우스터즈 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// 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 }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 타일 핸들러 // 뱀파이어가 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 BloodyWall::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; Assert(pVampire != NULL); Assert(pVampireSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pVampireSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); // 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(); } int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = verifyDistance(pVampire, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) bTileCheck = true; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck) { decreaseMana(pVampire, RequiredMP, _GCSkillToTileOK1); // 이펙트의 지속시간을 계산한다. SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); Dir_t Dir = getDirectionToPosition(myX, myY, X, Y); list<Creature*> cList; // denier list for (int i=0; i<5; i++) { POINT& pt = m_BloodyWallMask[Dir][i]; int tileX = X+pt.x; int tileY = Y+pt.y; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); if (tile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION )!=NULL ) continue; // 현재 타일에다 이펙트를 추가할 수 있다면... if (tile.canAddEffect()) { // 같은 effect가 있으면 지운다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_BLOODY_WALL); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID);// fix me } // 이펙트 클래스를 생성한다. EffectBloodyWall* pEffect = new EffectBloodyWall(pZone , tileX, tileY); pEffect->setCasterName(pVampire->getName()); pEffect->setCasterID(pVampire->getObjectID()); pEffect->setClan(Creature::CREATURE_CLASS_VAMPIRE, pVampire->getClanType()); pEffect->setDamage(output.Damage); pEffect->setDeadline(output.Duration); pEffect->setLevel(pVampire->getINT()); pEffect->setNextTime(0); pEffect->setTick(output.Tick); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); const list<Object*>& oList = tile.getObjectList(); for(list<Object*>::const_iterator itr = oList.begin(); itr != oList.end(); itr++) { Object* pTarget = *itr; Creature* pTargetCreature = NULL; if (pTarget->getObjectClass() == Object::OBJECT_CLASS_CREATURE && ((pTargetCreature = dynamic_cast<Creature*>(pTarget))->isSlayer() || pTargetCreature->isOusters() ) && !checkZoneLevelToHitTarget(pTargetCreature ) ) { cList.push_back(pTargetCreature); _GCSkillToTileOK2.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); pEffect->affect(pTargetCreature); } // pEffect->affect(pTarget); } } } } _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(Dir); _GCSkillToTileOK2.setObjectID(pVampire->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Dir); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, BLOODY_WALL_SIGHT); _GCSkillToTileOK3.setObjectID(pVampire->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setRange(Dir); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK5.setObjectID(pVampire->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(Dir); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(Dir); //_GCSkillToTileOK6.addShortData(MODIFY_VISION, BLOODY_WALL_SIGHT); for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; if (canSee(pTargetCreature, pVampire)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pVampire); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pVampire); // watcherList에서 cList에 속하지 않고, caster(pVampire)를 볼 수 없는 경우는 // OK4를 보내고.. cList에 추가한다. for(list<Creature*>::const_iterator itr = watcherList.begin(); itr != watcherList.end(); itr++) { bool bBelong = false; for(list<Creature*>::const_iterator tItr = cList.begin(); tItr != cList.end(); tItr++) if (*itr == *tItr) bBelong = true; Creature* pWatcher = (*itr); if (bBelong == false && canSee(pWatcher, pVampire) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (!pWatcher->isPC()) { //cout << "BloodyWall : 왓처 리스트가 PC가 아닙니다." << endl; GCSkillFailed1 _GCSkillFailed1; _GCSkillFailed1.setSkillType(getSkillType()); pVampire->getPlayer()->sendPacket(&_GCSkillFailed1); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } pWatcher->getPlayer()->sendPacket(&_GCSkillToTileOK4); cList.push_back(*itr); } } cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList, false); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pVampireSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 아우스터즈 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void Prominence::execute(Ousters* pOusters, ZoneCoord_t X, ZoneCoord_t Y, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); BYTE Grade = 0; if (pOustersSkillSlot->getExpLevel() < 15 ) Grade = 0; else if (pOustersSkillSlot->getExpLevel() < 30 ) Grade = 1; else Grade = 2; try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pOustersSkillSlot->getSkillType(), Grade); return; } GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); // 데미지와 지속 시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel()/3; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, X, Y, output.Range); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) { Tile& tile = pZone->getTile(X, Y); if (tile.canAddEffect()) bTileCheck = true; } if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToTileOK1); int oX, oY; for (oX = X - 1 ; oX <= X + 1 ; ++oX ) for (oY = Y - 1 ; oY <= Y + 1 ; ++oY ) { if (!rect.ptInRect(oX, oY)) continue; Tile& tile = pZone->getTile(oX, oY); if (!tile.canAddEffect()) continue; // 머시 그라운드 있음 추가 못한당. if (tile.getEffect(Effect::EFFECT_CLASS_MERCY_GROUND) != NULL ) continue; if (tile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION) ) continue; // 같은 이펙트가 이미 존재한다면 삭제한다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_PROMINENCE); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID); } checkMine(pZone, oX, oY); // 이펙트 오브젝트를 생성한다. EffectProminence* pEffect = new EffectProminence(pZone, oX, oY); pEffect->setUserObjectID(pOusters->getObjectID()); pEffect->setDeadline(output.Duration); pEffect->setNextTime(0); pEffect->setTick(output.Tick); pEffect->setDamage(output.Damage); pEffect->setLevel(pOustersSkillSlot->getExpLevel()); if (Grade > 0 ) { if (Grade == 1 ) pEffect->setSendEffectClass(Effect::EFFECT_CLASS_PROMINENCE_2); else pEffect->setSendEffectClass(Effect::EFFECT_CLASS_PROMINENCE_3); } // 타일에 붙은 이펙트는 OID를 받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); // 존 및 타일에다가 이펙트를 추가한다. pZone->addEffect(pEffect); tile.addEffect(pEffect); GCAddEffectToTile gcAddEffect; gcAddEffect.setXY(oX, oY); gcAddEffect.setEffectID(pEffect->getSendEffectClass()); gcAddEffect.setObjectID(pEffect->getObjectID()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(oX, oY, &gcAddEffect, pOusters); } ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setGrade(Grade); _GCSkillToTileOK3.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK3.setGrade(Grade); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK4.setGrade(Grade); _GCSkillToTileOK5.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setGrade(Grade); pPlayer->sendPacket(&_GCSkillToTileOK1); list<Creature*> cList; cList.push_back(pOusters); cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL, Grade); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType(), Grade); //cout << t.toString() << endl; } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 몬스터 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// void EnergyDrop::execute(Monster* pMonster, ZoneCoord_t X, ZoneCoord_t Y) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; EffectEnergyDrop * pEffect = NULL; EffectEnergyDrop * pEffect2 = NULL; try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = SKILL_ENERGY_DROP; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pMonster->getX(); ZoneCoord_t myY = pMonster->getY(); bool bRangeCheck = verifyDistance(pMonster, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pMonster, pSkillInfo); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if(rect.ptInRect(X, Y)) { Tile& tile = pZone->getTile(X, Y); if (tile.canAddEffect()) bTileCheck = true; } if (bRangeCheck && bHitRoll && bTileCheck) { // calculate damage and duration time SkillInput input(pMonster); SkillOutput output; computeOutput(input, output); 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); } // 이펙트 오브젝트를 생성해서 타일에 붙인다. pEffect = new EffectEnergyDrop(pZone, X, Y); 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->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; Creature* pTargetCreature; list<Creature*> cList; cList.push_back(pMonster); int oX, oY; for(oX = -2; oX <= 2; oX++) for(oY = -2; oY <= 2; oY++) { int tileX = X+oX; int tileY = Y+oY; EffectEnergyDrop * pTempEffect = NULL; if(oX == 2 || oX == -2 || oY == 2 || oY == -2 ) pTempEffect = pEffect2; else pTempEffect = pEffect; 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); if(pTargetCreature != NULL) { if(pTargetCreature->isPC()) { if(pTempEffect->affectCreature(pTargetCreature, false) == true) { Player* pTargetPlayer = pTargetCreature->getPlayer(); bEffected = true; bool bCanSee = canSee(pTargetCreature, pMonster); _GCSkillToTileOK1.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); cList.push_back(pTargetCreature); if (bCanSee) { // 공격을 당한 사람에게 _GCSkillToTileOK2.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Range); pTargetPlayer->sendPacket(&_GCSkillToTileOK2); } } } } // if(pTargetCreature!= NULL) } // 기술을 쓴 사람만 볼 수 있는 사람들에게 _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(myX); _GCSkillToTileOK3.setY(myY); //_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(pMonster->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setRange(Range); // 기술을 쓸 사람과 당한 사람을 모두 볼 수 있는 사람들에게 broadcasing cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); // 기술을 쓴 사람을 볼 수 있는 사람들에게 broadcasting pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3, cList); // 기술을 당한 사람을 볼 수 있는 사람들에게 broadcasting pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4, cList); } else { executeSkillFailNormal(pMonster, getSkillType(), NULL); } SAFE_DELETE(pEffect); SAFE_DELETE(pEffect2); } catch(Throwable& t) { SAFE_DELETE(pEffect); SAFE_DELETE(pEffect2); executeSkillFailException(pMonster, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
void Mephisto::execute(Vampire* pVampire) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayerself)" << endl; Assert(pVampire != NULL); if(!pVampire->hasSkill(SKILL_MEPHISTO) ) return; try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); int oX, oY; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); for(oX = -4; oX <= 4; oX++) for(oY = -4; oY <= 4; oY++) { int tileX = myX+oX; int tileY = myY+oY; if (!rect.ptInRect(tileX, tileY)) continue; // 타일 위에! 뱀파이어가 있는지 본다! Tile& tile = pZone->getTile(tileX, tileY); Creature * pTargetCreature = NULL; if(tile.hasCreature(Creature::MOVE_MODE_WALKING)) pTargetCreature = tile.getCreature(Creature::MOVE_MODE_WALKING); if(pTargetCreature != NULL && pTargetCreature != pVampire && pTargetCreature->isVampire() ) { bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_MEPHISTO); if(bEffected ) continue; Vampire* pTargetVampire= dynamic_cast<Vampire*>(pTargetCreature); // 스킬 레벨에 따라 데미지 보너스가 달라진다. SkillInput input(pVampire); SkillOutput output; input.SkillLevel = pVampire->getSTR()+pVampire->getDEX()+pVampire->getINT(); input.DomainLevel = pVampire->getLevel(); computeOutput(input, output); // 이펙트 클래스를 만들어 붙인다. EffectMephisto* pEffect = new EffectMephisto(pTargetVampire); pEffect->setDeadline(output.Duration); pEffect->setBonus(output.Damage); pTargetVampire->addEffect(pEffect); pTargetVampire->setFlag(Effect::EFFECT_CLASS_MEPHISTO); // 이로 인하여 바뀌는 능력치를 보낸다. VAMPIRE_RECORD prev; pTargetVampire->getVampireRecord(prev); pTargetVampire->initAllStat(); pTargetVampire->sendRealWearingInfo(); pTargetVampire->sendModifyInfo(prev); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } else { Assert(false); } // 이펙트가 붙었다고 알려준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pTargetVampire->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_MEPHISTO); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pTargetVampire->getX(), pTargetVampire->getY(), &gcAddEffect); } } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayerself)" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void Mephisto::execute(Vampire* pVampire, VampireSkillSlot* pVampireSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayerself)" << endl; Assert(pVampire != NULL); Assert(pVampireSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pVampireSkillSlot->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 = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pVampire); bool bHitRoll = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus); bool bEffected = pVampire->isFlag(Effect::EFFECT_CLASS_MEPHISTO); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pVampire, RequiredMP, _GCSkillToSelfOK1); // 스킬 레벨에 따라 데미지 보너스가 달라진다. SkillInput input(pVampire); SkillOutput output; input.SkillLevel = pVampire->getSTR()+pVampire->getDEX()+pVampire->getINT(); input.DomainLevel = pVampire->getLevel(); computeOutput(input, output); // 이펙트 클래스를 만들어 붙인다. EffectMephisto* pEffect = new EffectMephisto(pVampire); pEffect->setDeadline(output.Duration); pEffect->setBonus(output.Damage); pVampire->addEffect(pEffect); pVampire->setFlag(Effect::EFFECT_CLASS_MEPHISTO); // 이로 인하여 바뀌는 능력치를 보낸다. VAMPIRE_RECORD prev; pVampire->getVampireRecord(prev); pVampire->initAllStat(); pVampire->sendRealWearingInfo(); pVampire->sendModifyInfo(prev); // 패킷을 만들어 보낸다. _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pVampire->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(pVampire->getX(), pVampire->getY(), &_GCSkillToSelfOK2, pVampire); // 이펙트가 붙었다고 알려준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pVampire->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_MEPHISTO); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pVampire->getX(), pVampire->getY(), &gcAddEffect); // set Next Run Time pVampireSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayerself)" << endl; __END_CATCH }
void Mephisto::execute(Vampire* pVampire, ObjectID_t TargetObjectID, VampireSkillSlot* pVampireSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayerself)" << 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); // NoSuch제거. by sigi. 2002.5.2 if (pTargetCreature==NULL) { executeSkillFailException(pVampire, getSkillType()); return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; GCSkillToObjectOK2 _GCSkillToObjectOK2; GCSkillToObjectOK3 _GCSkillToObjectOK3; SkillType_t SkillType = pVampireSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pVampireSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pVampire); bool bHitRoll = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot); bool bEffected = pTargetCreature->isFlag(Effect::EFFECT_CLASS_MEPHISTO); ZoneCoord_t myX = pVampire->getX(); ZoneCoord_t myY = pVampire->getY(); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected && pTargetCreature->isVampire() ) { Vampire* pTargetVampire= dynamic_cast<Vampire*>(pTargetCreature); ZoneCoord_t X = pTargetVampire->getX(); ZoneCoord_t Y = pTargetVampire->getY(); decreaseMana(pVampire, RequiredMP, _GCSkillToObjectOK1); // 스킬 레벨에 따라 데미지 보너스가 달라진다. SkillInput input(pVampire); SkillOutput output; input.SkillLevel = pVampire->getSTR()+pVampire->getDEX()+pVampire->getINT(); input.DomainLevel = pVampire->getLevel(); computeOutput(input, output); // 이펙트 클래스를 만들어 붙인다. EffectMephisto* pEffect = new EffectMephisto(pTargetVampire); pEffect->setDeadline(output.Duration); pEffect->setBonus(output.Damage); pTargetVampire->addEffect(pEffect); pTargetVampire->setFlag(Effect::EFFECT_CLASS_MEPHISTO); // 이로 인하여 바뀌는 능력치를 보낸다. VAMPIRE_RECORD prev; pTargetVampire->getVampireRecord(prev); pTargetVampire->initAllStat(); pTargetVampire->sendRealWearingInfo(); pTargetVampire->sendModifyInfo(prev); // 패킷을 만들어 보낸다. _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setDuration(output.Duration); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK2.setSkillType(SkillType); _GCSkillToObjectOK2.setDuration(output.Duration); _GCSkillToObjectOK3.setObjectID(pVampire->getObjectID()); _GCSkillToObjectOK3.setSkillType(SkillType); _GCSkillToObjectOK3.setTargetXY (X, Y); pPlayer->sendPacket(&_GCSkillToObjectOK1); if (pTargetCreature->isPC()) { Player* pTargetPlayer = pTargetCreature->getPlayer(); Assert(pTargetPlayer != NULL); _GCSkillToObjectOK2.setObjectID(pVampire->getObjectID()); pTargetPlayer->sendPacket(&_GCSkillToObjectOK2); } else { Assert(false); } list<Creature *> cList; cList.push_back(pTargetCreature); cList.push_back(pVampire); pZone->broadcastPacket(myX, myY, &_GCSkillToObjectOK3, cList); // 이펙트가 붙었다고 알려준다. GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pTargetVampire->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_MEPHISTO); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pTargetVampire->getX(), pTargetVampire->getY(), &gcAddEffect); // set Next Run Time pVampireSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayerself)" << endl; __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 BloodyWall::execute(Monster* pMonster, ZoneCoord_t X, ZoneCoord_t Y) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pMonster != NULL); try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = SKILL_BLOODY_WALL; SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pMonster->getX(); ZoneCoord_t myY = pMonster->getY(); // 마스터는 무조건~~ bool bRangeCheck = pMonster->isMaster() #ifdef __UNDERWORLD__ || pMonster->isUnderworld() || pMonster->getMonsterType() == 599 #endif || verifyDistance(pMonster, X, Y, pSkillInfo->getRange()); bool bHitRoll = pMonster->isMaster() #ifdef __UNDERWORLD__ || pMonster->isUnderworld() || pMonster->getMonsterType() == 599 #endif || HitRoll::isSuccessMagic(pMonster, pSkillInfo); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) bTileCheck = true; if (bRangeCheck && bHitRoll && bTileCheck) { // 이펙트의 지속시간을 계산한다. SkillInput input(pMonster); SkillOutput output; computeOutput(input, output); //Range_t Range = 3; Dir_t Dir = getDirectionToPosition(myX, myY, X, Y); list<Creature*> cList; // denier list for (int i=0; i<5; i++) { POINT& pt = m_BloodyWallMask[Dir][i]; int tileX = X+pt.x; int tileY = Y+pt.y; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); // 현재 타일에다 이펙트를 추가할 수 있다면... if (tile.canAddEffect()) { // 같은 effect가 있으면 지운다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_BLOODY_WALL); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID);// fix me } // 이펙트 클래스를 생성한다. EffectBloodyWall* pEffect = new EffectBloodyWall(pZone , tileX, tileY); pEffect->setCasterName(pMonster->getName()); pEffect->setCasterID(pMonster->getObjectID()); pEffect->setClan(Creature::CREATURE_CLASS_MONSTER, pMonster->getClanType()); pEffect->setDamage(output.Damage); pEffect->setDeadline(output.Duration); pEffect->setLevel(pMonster->getINT()); pEffect->setNextTime(0); pEffect->setTick(output.Tick); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); GCAddEffectToTile gcAE; gcAE.setObjectID(pEffect->getObjectID()); gcAE.setEffectID(pEffect->getSendEffectClass()); gcAE.setDuration(output.Duration); gcAE.setXY(tileX, tileY); pZone->broadcastPacket(tileX, tileY, &gcAE); const list<Object*>& oList = tile.getObjectList(); for(list<Object*>::const_iterator itr = oList.begin(); itr != oList.end(); itr++) { Object* pTarget = *itr; Creature* pTargetCreature = NULL; if (pTarget->getObjectClass() == Object::OBJECT_CLASS_CREATURE && ((pTargetCreature = dynamic_cast<Creature*>(pTarget))->isSlayer() || pTargetCreature->isOusters() ) ) { cList.push_back(pTargetCreature); _GCSkillToTileOK2.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); pEffect->affect(pTargetCreature); } //pEffect->affectObject(pTarget, false); } } } } _GCSkillToTileOK2.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Dir); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, BLOODY_WALL_SIGHT); _GCSkillToTileOK3.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setRange(Dir); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK5.setObjectID(pMonster->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(Dir); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(Dir); //_GCSkillToTileOK6.addShortData(MODIFY_VISION, BLOODY_WALL_SIGHT); for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; if (canSee(pTargetCreature, pMonster)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } cList.push_back(pMonster); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pMonster); // watcherList에서 cList에 속하지 않고, caster(pMonster)를 볼 수 없는 경우는 // OK4를 보내고.. cList에 추가한다. for(list<Creature*>::const_iterator itr = watcherList.begin(); itr != watcherList.end(); itr++) { bool bBelong = false; for(list<Creature*>::const_iterator tItr = cList.begin(); tItr != cList.end(); tItr++) if (*itr == *tItr) bBelong = true; Creature* pWatcher = (*itr); if (bBelong == false && canSee(pWatcher, pMonster) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (!pWatcher->isPC()) { //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } pWatcher->getPlayer()->sendPacket(&_GCSkillToTileOK4); cList.push_back(*itr); } } cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList, false); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); } else { executeSkillFailNormal(pMonster, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pMonster, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void MindControl::execute(Slayer* pSlayer, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayerself)" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_MIND_CONTROL); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // 이펙트를 만들어 붙인다. EffectMindControl* pEffect = new EffectMindControl(pSlayer); pEffect->setDeadline(output.Duration); pEffect->setDefenseBonus(output.Damage); pEffect->setToHitBonus(output.Damage); pSlayer->setFlag(Effect::EFFECT_CLASS_MIND_CONTROL); pSlayer->addEffect(pEffect); // 이펙트를 붙였으니, 능력치를 재계산한다. SLAYER_RECORD prev; pSlayer->getSlayerRecord(prev); pSlayer->initAllStat(); pSlayer->sendRealWearingInfo(); pSlayer->addModifyInfo(prev, _GCSkillToSelfOK1); // 경험치를 올려준다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1); shareAttrExp(pSlayer, ExpUp, 1, 8, 1, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(myX, myY, &_GCSkillToSelfOK2, pSlayer); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pSlayer->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_MIND_CONTROL); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(myX, myY, &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayerself)" << endl; __END_CATCH }
void SwordOfThor::execute(Slayer * pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot * pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY // cout << "(x,y)=" << X << "," << Y << endl; Zone* pZone = pSlayer->getZone(); Assert(pZone!=NULL); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); SIMPLE_SKILL_INPUT param; param.SkillType = getSkillType(); param.SkillDamage = output.Damage; param.Delay = output.Delay; param.ItemClass = Item::ITEM_CLASS_SWORD; param.STRMultiplier = 8; param.DEXMultiplier = 1; param.INTMultiplier = 1; param.bMagicHitRoll = false; param.bMagicDamage = false; param.bAdd = false; param.bExpForTotalDamage = false; for (int i=-2; i<=2; ++i ) for (int j=-2; j<=2; ++j ) { param.addMask(i, j, 100); } SIMPLE_SKILL_OUTPUT result; // 목표위치+4방향 /* param.addMask(0 + dir_advance[dir][0], 0 + dir_advance[dir][1], 100); param.addMask(-1 + dir_advance[dir][0], -1 + dir_advance[dir][1], 100); param.addMask(0 + dir_advance[dir][0], -1 + dir_advance[dir][1], 100); param.addMask(1 + dir_advance[dir][0], -1 + dir_advance[dir][1], 100); param.addMask(-1 + dir_advance[dir][0], 0 + dir_advance[dir][1], 100); param.addMask(1 + dir_advance[dir][0], 0 + dir_advance[dir][1], 100); param.addMask(-1 + dir_advance[dir][0], 1 + dir_advance[dir][1], 100); param.addMask(0 + dir_advance[dir][0], 1 + dir_advance[dir][1], 100); param.addMask(1 + dir_advance[dir][0], 1 + dir_advance[dir][1], 100);*/ g_SimpleTileMissileSkill.execute(pSlayer, X, Y, pSkillSlot, param, result); if (result.bSuccess ) { for (int i=-2; i<=2; ++i ) for (int j=-2; j<=2; ++j ) { ZoneCoord_t tx = X+i; ZoneCoord_t ty = Y+j; if (!isValidZoneCoord(pZone, tx, ty) ) continue; Tile& rTile = pZone->getTile(tx, ty); if (!rTile.canAddEffect() ) continue; EffectSwordOfThor* pEffect = new EffectSwordOfThor(pZone, tx, ty); pEffect->setLevel(input.SkillLevel); pEffect->setDeadline(output.Duration); pZone->registerObject(pEffect); if (i != 0 || j != 0 ) pEffect->setBroadcastingEffect(false); else { GCAddEffectToTile gcAE; gcAE.setEffectID(pEffect->getSendEffectClass()); gcAE.setXY(tx, ty); gcAE.setObjectID(pEffect->getObjectID()); gcAE.setDuration(output.Duration); pZone->broadcastPacket(tx, ty, &gcAE); // cout << tx << ", " << ty << " Effect broadcast" << endl; } pZone->addEffect(pEffect); rTile.addEffect(pEffect); // cout << tx << ", " << ty << " add Effect" << endl; } } __END_CATCH }
void DestructionSpear::execute(Ousters* pOusters, ZoneCoord_t X, ZoneCoord_t Y, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY Zone* pZone = pOusters->getZone(); Assert(pZone != NULL); /* Creature* pTargetCreature = pZone->getCreature(TargetObjectID); if (pTargetCreature==NULL || !canAttack(pOusters, pTargetCreature ) || pTargetCreature->isNPC()) { executeSkillFailException(pOusters, getSkillType()); return; }*/ /* if (pTargetCreature->isSlayer() ) { Slayer* pSlayer = dynamic_cast<Slayer*>(pTargetCreature); targetLevel = pSlayer->getHighestSkillDomainLevel(); } else { targetLevel = pTargetCreature->getLevel(); }*/ SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL ) { executeSkillFailException(pOusters, getSkillType()); return; } SIMPLE_SKILL_INPUT param; param.SkillType = getSkillType(); param.SkillDamage = output.Damage; param.Delay = output.Delay; param.ItemClass = Item::ITEM_CLASS_OUSTERS_CHAKRAM; param.STRMultiplier = 0; param.DEXMultiplier = 0; param.INTMultiplier = 0; param.bMagicHitRoll = false; param.bMagicDamage = false; param.bAdd = true; SIMPLE_SKILL_OUTPUT result; int offset = 0; OustersSkillSlot* pMastery = pOusters->hasSkill(SKILL_DESTRUCTION_SPEAR_MASTERY); if (pMastery != NULL ) { offset = 1; if (pMastery->getExpLevel() <= 15 ) param.SkillDamage = min(70,param.SkillDamage + 10 + pMastery->getExpLevel()/3); else param.SkillDamage = min(90,param.SkillDamage + 10 + pMastery->getExpLevel()/2); param.Grade=4; } for (int i=-offset; i<=offset; ++i ) for (int j=-offset; j<=offset; ++j ) param.addMask(i, j, 100); g_SimpleTileMissileSkill.execute(pOusters, X, Y, pOustersSkillSlot, param, result, CEffectID); list<Creature*>::iterator itr = result.targetCreatures.begin(); for (; itr != result.targetCreatures.end() ; ++itr ) { Creature* pTargetCreature = *itr; if (pTargetCreature->getX() == X && pTargetCreature->getY() == Y ) { GCModifyInformation gcMI, gcAttackerMI; Damage_t damage = computeElementalCombatSkill(pOusters, pTargetCreature, gcAttackerMI); if (damage != 0 ) { ::setDamage(pTargetCreature, damage, pOusters, SKILL_DESTRUCTION_SPEAR, &gcMI, &gcAttackerMI); if (pTargetCreature->isPC() ) pTargetCreature->getPlayer()->sendPacket(&gcMI); if (pTargetCreature->isDead()) { int exp = computeCreatureExp(pTargetCreature, 70, pOusters); shareOustersExp(pOusters, exp, gcAttackerMI); } pOusters->getPlayer()->sendPacket(&gcAttackerMI); } } if (!pTargetCreature->isFlag(Effect::EFFECT_CLASS_DESTRUCTION_SPEAR ) && result.bSuccess ) { int targetLevel = pTargetCreature->getLevel(); int ratio = 0; if (input.SkillLevel <= 15 ) { ratio = max(20, min(80, (int)(pOusters->getLevel() + (input.SkillLevel * 8.0 / 3.0) - targetLevel ) )); } else { ratio = max(20, min(80, (int)(pOusters->getLevel() + 20.0 + (input.SkillLevel * 4.0 / 3.0) - targetLevel ) )); } if (rand() % 100 < ratio ) { EffectDestructionSpear* pEffect = new EffectDestructionSpear(pTargetCreature); Assert(pEffect != NULL); pEffect->setDamage(2 + (input.SkillLevel/3 )); pEffect->setNextTime(20); pEffect->setCasterID(pOusters->getObjectID()); pEffect->setDeadline(output.Duration); if (pTargetCreature->getX() == X && pTargetCreature->getY() == Y ) pEffect->setSteal(true); pTargetCreature->setFlag(Effect::EFFECT_CLASS_DESTRUCTION_SPEAR); pTargetCreature->addEffect(pEffect); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pTargetCreature->getObjectID()); gcAddEffect.setEffectID(pEffect->getSendEffectClass()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &gcAddEffect); } } } __END_CATCH }
// ###################################################################### Image<float> DirectFeedChannel::getOutput() { ASSERT(itsInputTime == itsPyrTime); if (!itsOutputCache.initialized()) computeOutput(); return itsOutputCache; }
////////////////////////////////////////////////////////////////////////////// // 몬스터 셀프 핸들러 ////////////////////////////////////////////////////////////////////////////// void IceWave::execute(Monster* pMonster, ZoneCoord_t X, ZoneCoord_t Y) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pMonster != NULL); try { Zone* pZone = pMonster->getZone(); Assert(pZone != NULL); if (pMonster->isFlag(Effect::EFFECT_CLASS_HIDE)) { //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } if (pMonster->isFlag(Effect::EFFECT_CLASS_INVISIBILITY)) { addVisibleCreature(pZone, pMonster, true); } int dx = (rand()%7)-3; int dy = (rand()%7)-3; X -= min((int)X, dx); Y -= min((int)Y, dy); if (X > pZone->getWidth() ) X = pZone->getWidth()-1; if (Y > pZone->getHeight() ) Y = pZone->getHeight()-1; pZone->moveFastMonster(pMonster, pMonster->getX(), pMonster->getY(), X, Y, getSkillType()); ZoneCoord_t x = pMonster->getX(); ZoneCoord_t y = pMonster->getY(); bool bRangeCheck = checkZoneLevelToUseSkill(pMonster); bool bMoveModeCheck = pMonster->isWalking(); if (bRangeCheck && bMoveModeCheck) { //-------------------------------------------------------- // 주위에 knockback되는맞는 애들을 체크해준다. //-------------------------------------------------------- SkillInput input(pMonster); SkillOutput output; computeOutput(input, output); SIMPLE_SKILL_INPUT param; param.SkillType = getSkillType(); param.SkillDamage = output.Damage; param.Delay = output.Delay; param.ItemClass = Item::ITEM_CLASS_MAX; param.STRMultiplier = 0; param.DEXMultiplier = 0; param.INTMultiplier = 0; param.bMagicHitRoll = true; param.bMagicDamage = true; param.bAdd = false; SIMPLE_SKILL_OUTPUT result; for (int i=0; i<8; ++i ) { for (int j=0; j<3; ++j ) { int ox = pMonster->getX() + dirMoveMask[i].x * j * 3 + dirMoveMask[i].x * 2; int oy = pMonster->getY() + dirMoveMask[i].y * j * 3 + dirMoveMask[i].y * 2; GCAddEffectToTile gcAE; gcAE.setXY(ox, oy); gcAE.setEffectID(Effect::EFFECT_CLASS_ICICLE_AUGER_LARGE); gcAE.setDuration(15); pMonster->getZone()->broadcastPacket(ox, oy, &gcAE); } } for (int i=0; i<193; i++) { if ((abs((int)x - (int)m_pIceWaveMask[i].x) <= 2) && (abs((int)y - (int)m_pIceWaveMask[i].y) <= 2)) param.addMask(m_pIceWaveMask[i].x, m_pIceWaveMask[i].y, 80); else param.addMask(m_pIceWaveMask[i].x, m_pIceWaveMask[i].y, 100); } // 강제로 맞는 애들을 knockback 시킨다. bool bForceKnockback = false; g_SimpleTileMeleeSkill.execute(pMonster, x, y, param, result, 0, bForceKnockback); } else { executeSkillFailNormal(pMonster, getSkillType(), NULL); } } catch(Throwable & t) { executeSkillFailException(pMonster, 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 SummonGroundElemental::execute(Ousters* pOusters, ZoneCoord_t X, ZoneCoord_t Y, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); BYTE Grade = 0; if (pOustersSkillSlot->getExpLevel() < 15 ) Grade = 0; else if (pOustersSkillSlot->getExpLevel() < 30 ) Grade = 1; else Grade = 2; try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_WRISTLET || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND)) { executeSkillFailException(pOusters, pOustersSkillSlot->getSkillType(), Grade); return; } GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); // 데미지와 지속 시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); int RequiredMP = (int)pSkillInfo->getConsumeMP() + pOustersSkillSlot->getExpLevel()/3; bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = verifyDistance(pOusters, X, Y, pSkillInfo->getRange()); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); // if (rect.ptInRect(X, Y)) // { // Tile& tile = pZone->getTile(X, Y); // if (tile.canAddEffect()) bTileCheck = true; // } TPOINT pt = findSuitablePosition(pZone, X, Y, Creature::MOVE_MODE_WALKING); if (pt.x == -1 ) { bTileCheck = false; } else { bTileCheck = true; for (int oX = pt.x - 2 ; oX <= pt.x + 2 ; ++oX ) for (int oY = pt.y - 2 ; oY <= pt.y + 2 ; ++oY ) { if (!rect.ptInRect(oX, oY ) ) continue; if (pZone->getTile(oX, oY).getEffect(Effect::EFFECT_CLASS_GROUND_ELEMENTAL_AURA ) != NULL ) { bTileCheck = false; break; } } } if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToTileOK1); int oX, oY; /* HP = 200 + (S_level * 10) Defense = 50 + (S_level * 2) Protection = 20 + (S_level * 2) Poison Resistance = 70% Acid Resistance = 60% Curse Resistance = 100% Blood Resistance = 50% Regen = 1 HP per 1 sec */ Monster* pGroundElemental = new Monster(GROUND_ELEMENTAL_TYPE); pGroundElemental->setName("대지 정령"); pGroundElemental->setHP(1000 + input.SkillLevel * 100); pGroundElemental->setHP(1000 + input.SkillLevel * 100, ATTR_MAX); pGroundElemental->setDefense(0); pGroundElemental->setProtection(0); pGroundElemental->setResist(MAGIC_DOMAIN_POISON, 0); pGroundElemental->setResist(MAGIC_DOMAIN_ACID, 0); pGroundElemental->setResist(MAGIC_DOMAIN_CURSE, 0); pGroundElemental->setResist(MAGIC_DOMAIN_BLOOD, 0); pGroundElemental->setFlag(Effect::EFFECT_CLASS_IMMUNE_TO_CURSE); pGroundElemental->removeFlag(Effect::EFFECT_CLASS_HIDE); pGroundElemental->setMoveMode(Creature::MOVE_MODE_WALKING); // 무뇌정령 pGroundElemental->setBrain(NULL); pZone->addCreature(pGroundElemental, X, Y, 2); X = pGroundElemental->getX(); Y = pGroundElemental->getY(); //cout << pGroundElemental->toString() << " 을 " << X << ", " << Y << " 에 불러냈습니다." << endl; EffectGroundElemental* pCreatureEffect = new EffectGroundElemental(pGroundElemental); pCreatureEffect->setDeadline(output.Duration); pGroundElemental->setFlag(pCreatureEffect->getEffectClass()); pGroundElemental->addEffect(pCreatureEffect); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pGroundElemental->getObjectID()); gcAddEffect.setEffectID(pCreatureEffect->getSendEffectClass()); pZone->broadcastPacket(X, Y, &gcAddEffect); // addSimpleCreatureEffect(pGroundElemental, Effect::EFFECT_CLASS_GROUND_ELEMENTAL_CENTER); // for (int i = 0; i < m_MaskIndex[Grade]; ++i ) for (oX = X - 2 ; oX <= X + 2 ; ++oX ) for (oY = Y - 2 ; oY <= Y + 2 ; ++oY ) { // oX = m_ElementalMask[Grade][i].x; // oY = m_ElementalMask[Grade][i].y; if (!rect.ptInRect(oX, oY)) continue; if (oX == X && oY == Y ) continue; Tile& tile = pZone->getTile(oX, oY); if (!tile.canAddEffect()) continue; if (tile.getEffect(Effect::EFFECT_CLASS_TRYING_POSITION) ) continue; // 같은 이펙트가 이미 존재한다면 삭제한다. Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_GROUND_ELEMENTAL_AURA); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID); } // 이펙트 오브젝트를 생성한다. EffectSummonGroundElemental* pEffect = new EffectSummonGroundElemental(pZone, oX, oY); pEffect->setDeadline(output.Duration); // 타일에 붙은 이펙트는 OID를 받아야 한다. ObjectRegistry & objectregister = pZone->getObjectRegistry(); objectregister.registerObject(pEffect); // 존 및 타일에다가 이펙트를 추가한다. pZone->addEffect(pEffect); tile.addEffect(pEffect); GCAddEffectToTile gcAddEffect; gcAddEffect.setXY(oX, oY); gcAddEffect.setEffectID(pEffect->getSendEffectClass()); gcAddEffect.setObjectID(pEffect->getObjectID()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(oX, oY, &gcAddEffect); } ZoneCoord_t myX = pOusters->getX(); ZoneCoord_t myY = pOusters->getY(); _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setGrade(Grade); _GCSkillToTileOK3.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK3.setGrade(Grade); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK4.setGrade(Grade); _GCSkillToTileOK5.setObjectID(pOusters->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK5.setGrade(Grade); pPlayer->sendPacket(&_GCSkillToTileOK1); list<Creature*> cList; cList.push_back(pOusters); cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL, Grade); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType(), Grade); //cout << t.toString() << endl; } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end " << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void ProtectionFromBlood::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_BLOOD); 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); // 이펙트를 생성해서 붙인다. EffectProtectionFromBlood* pEPFP = new EffectProtectionFromBlood (pTargetCreature); Assert(pEPFP != NULL); pEPFP->setDeadline(output.Duration); pEPFP->setResist(output.Damage); pTargetCreature->addEffect(pEPFP); pTargetCreature->setFlag(Effect::EFFECT_CLASS_PROTECTION_FROM_BLOOD); 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_BLOOD); 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 CrossGuard::execute(Ousters* pOusters, OustersSkillSlot* pOustersSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin(slayer)" << endl; Assert(pOusters != NULL); Assert(pOustersSkillSlot != NULL); BYTE Grade = 0; if (pOustersSkillSlot->getExpLevel() < 15 ) Grade = 0; else if (pOustersSkillSlot->getExpLevel() < 30 ) Grade = 1; else Grade = 2; try { Player* pPlayer = pOusters->getPlayer(); Zone* pZone = pOusters->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Item* pWeapon = pOusters->getWearItem(Ousters::WEAR_RIGHTHAND); if (pWeapon == NULL || pWeapon->getItemClass() != Item::ITEM_CLASS_OUSTERS_CHAKRAM || !pOusters->isRealWearingEx(Ousters::WEAR_RIGHTHAND) ) { executeSkillFailException(pOusters, getSkillType(), Grade); return; } GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pOustersSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); //SkillDomainType_t DomainType = pSkillInfo->getDomainType(); //SkillLevel_t SkillLevel = pOustersSkillSlot->getExpLevel(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pOusters, RequiredMP); bool bTimeCheck = verifyRunTime(pOustersSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pOusters); bool bHitRoll = HitRoll::isSuccessMagic(pOusters, pSkillInfo, pOustersSkillSlot); bool bEffected = pOusters->isFlag(Effect::EFFECT_CLASS_CROSS_GUARD); bool bSatisfyRequire = pOusters->satisfySkillRequire(pSkillInfo); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected && bSatisfyRequire) { decreaseMana(pOusters, RequiredMP, _GCSkillToSelfOK1); // 지속 시간을 계산한다. SkillInput input(pOusters, pOustersSkillSlot); SkillOutput output; computeOutput(input, output); // 이팩트 클래스를 만들어 붙인다. EffectCrossGuard* pEffect = new EffectCrossGuard(pOusters); pEffect->setDeadline(output.Duration); pEffect->setBonus(output.Damage); pOusters->addEffect(pEffect); pOusters->setFlag(Effect::EFFECT_CLASS_CROSS_GUARD); OUSTERS_RECORD prev; pOusters->getOustersRecord(prev); pOusters->initAllStat(); pOusters->addModifyInfo(prev, _GCSkillToSelfOK1); _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK1.setGrade(Grade); _GCSkillToSelfOK2.setObjectID(pOusters->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); _GCSkillToSelfOK2.setGrade(Grade); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(pOusters->getX(), pOusters->getY(), &_GCSkillToSelfOK2, pOusters); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pOusters->getObjectID()); gcAddEffect.setEffectID(pEffect->getEffectClass()); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pOusters->getX(), pOusters->getY(), &gcAddEffect); pOustersSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pOusters, getSkillType(), NULL, Grade); } } catch (Throwable & t) { executeSkillFailException(pOusters, getSkillType(), Grade); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(slayer)" << endl; __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 Berserker::execute(Slayer* pSlayer, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); // 무장하고 있는 무기가 널이거나, 도가 아니라면 사용할 수 없다. Item* pItem = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND); if (pItem == NULL || pItem->getItemClass() != Item::ITEM_CLASS_BLADE) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } bool bIncreaseDomainExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND); GCSkillToSelfOK1 _GCSkillToSelfOK1; GCSkillToSelfOK2 _GCSkillToSelfOK2; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillDomainType_t DomainType = pSkillInfo->getDomainType(); ZoneCoord_t X = pSlayer->getX(); ZoneCoord_t Y = pSlayer->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); // 차징 파워랑 동시에 사용할 수 없다. bool bEffected = pSlayer->isFlag(Effect::EFFECT_CLASS_BERSERKER) || pSlayer->isFlag(Effect::EFFECT_CLASS_CHARGING_POWER); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && !bEffected) { decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // by sigi. 2002.12.3 // by 홍창. 2002.12.6 // int DefensePenalty = 35 - pSkillSlot->getExpLevel()*2/13; // % // int ProtectionPenalty = 25 - pSkillSlot->getExpLevel()*2/13; // % int DefensePenalty = 25 - pSkillSlot->getExpLevel()*2/13; // % int ProtectionPenalty = 20 - pSkillSlot->getExpLevel()*2/13; // % // 이펙트 클래스를 만들어 붙인다. EffectBerserker* pEffect = new EffectBerserker(pSlayer); pEffect->setDeadline(output.Duration); pEffect->setDefensePenalty(DefensePenalty); pEffect->setProtectionPenalty(ProtectionPenalty); pEffect->setToHitBonus(output.ToHit); pEffect->setDamageBonus(output.Damage); pSlayer->addEffect(pEffect); pSlayer->setFlag(Effect::EFFECT_CLASS_BERSERKER); // 이로 인하여 바뀌는 능력치를 보낸다. SLAYER_RECORD prev; pSlayer->getSlayerRecord(prev); pSlayer->initAllStat(); pSlayer->sendRealWearingInfo(); pSlayer->sendModifyInfo(prev); // 경험치를 올린다. SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10*(Grade+1); if (bIncreaseDomainExp ) { shareAttrExp(pSlayer, ExpUp, 8, 1, 1, _GCSkillToSelfOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1); // increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1); } _GCSkillToSelfOK1.setSkillType(SkillType); _GCSkillToSelfOK1.setCEffectID(CEffectID); _GCSkillToSelfOK1.setDuration(output.Duration); _GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToSelfOK2.setSkillType(SkillType); _GCSkillToSelfOK2.setDuration(output.Duration); pPlayer->sendPacket(&_GCSkillToSelfOK1); pZone->broadcastPacket(X, Y, &_GCSkillToSelfOK2, pSlayer); GCAddEffect gcAddEffect; gcAddEffect.setObjectID(pSlayer->getObjectID()); gcAddEffect.setEffectID(Effect::EFFECT_CLASS_BERSERKER); gcAddEffect.setDuration(output.Duration); pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcAddEffect); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void 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 }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 타일 핸들러 - SG를 들고 있을 경우 ////////////////////////////////////////////////////////////////////////////// void MoleShot::SGexecute(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; // 마지막으로 입힌 데미지를 저장하기 위한 변수 // SG일 경우에는 4부터 시작해서 9까지의 splash 데미지를 입힌다. int Splash = 3 + pSkillSlot->getExpLevel()/10 + 1; if (bManaCheck && bTimeCheck && bRangeCheck && bBulletCheck) { decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); // output.ToHit값이 음수이기 때문에, %값이 음수로 돌아온다. 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 (!canAttack(pSlayer, pTargetCreature ) || 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); increaseAlignment(pSlayer, pTargetCreature, _GCSkillToTileOK1); // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bCriticalHit) { knockbackCreature(pZone, pTargetCreature, myX, myY); } // 슬레이어 아닌 경우에만 hit한 걸로 간주한다. if (!pTargetCreature->isSlayer()) { bHit = true; if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel(); EnemyNum++; } } } if (bHit) { if (bIncreaseExp) { shareAttrExp(pSlayer, Damage , 1, 8, 1, _GCSkillToTileOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToTileOK1, maxEnemyLevel, EnemyNum); 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(); } else if (pTargetCreature->isOusters()) { targetHP = (dynamic_cast<Ousters*>(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 Sanctuary::execute(Slayer* pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToTileOK1 _GCSkillToTileOK1; GCSkillToTileOK2 _GCSkillToTileOK2; GCSkillToTileOK3 _GCSkillToTileOK3; GCSkillToTileOK4 _GCSkillToTileOK4; GCSkillToTileOK5 _GCSkillToTileOK5; GCSkillToTileOK6 _GCSkillToTileOK6; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange()) && checkZoneLevelToUseSkill(pSlayer); bool bHitRoll = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot); bool bTileCheck = false; VSRect rect(0, 0, pZone->getWidth()-1, pZone->getHeight()-1); if (rect.ptInRect(X, Y)) bTileCheck = true; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bTileCheck) { // 이펙트의 지속시간을 계산한다. SkillInput input(pSlayer, pSkillSlot); SkillOutput output; computeOutput(input, output); Range_t Range = 3; int oX, oY; list<Creature*> cList; // denier list ObjectRegistry & objectregister = pZone->getObjectRegistry(); // 일단 이미 sanctuary가 있는지 검색한다. for(oY = -1; oY <= 1; oY++) for(oX = -1; oX <= 1; oX++) { int tileX = X+oX; int tileY = Y+oY; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); if (tile.canAddEffect()) { Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_SANCTUARY); // 이미 있다면 // 기술 실패다. if (pOldEffect != NULL) { executeSkillFailNormal(pSlayer, getSkillType(), NULL); return; } } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); return; } } } // 실패하면 마나가 줄면 안 되므로 여기서 줄여준다. decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1); for(oY = -1; oY <= 1; oY++) for(oX = -1; oX <= 1; oX++) { int tileX = X+oX; int tileY = Y+oY; if (rect.ptInRect(tileX, tileY)) { Tile& tile = pZone->getTile(tileX, tileY); // 현재 타일에다 이펙트를 추가할 수 있다면... //if (tile.canAddEffect()) // 위에서 체크했다. { // 같은 effect가 있으면 지운다. // 위에서 체크했다. /* Effect* pOldEffect = tile.getEffect(Effect::EFFECT_CLASS_SANCTUARY); if (pOldEffect != NULL) { ObjectID_t effectID = pOldEffect->getObjectID(); pZone->deleteEffect(effectID);// fix me } */ // 이펙트 클래스를 생성한다. EffectSanctuary* pEffect = new EffectSanctuary(pZone , tileX, tileY, X, Y); pEffect->setDeadline(output.Duration); pEffect->setLevel(pSlayer->getINT()); pEffect->setDuration(output.Duration); pEffect->setStartTime(); // Tile에 붙이는 Effect는 ObjectID를 등록받아야 한다. objectregister.registerObject(pEffect); pZone->addEffect(pEffect); tile.addEffect(pEffect); if (oX==0 && oY==0) { GCAddEffectToTile gcAddEffectToTile; gcAddEffectToTile.setEffectID(pEffect->getEffectClass()); gcAddEffectToTile.setObjectID(pEffect->getObjectID()); gcAddEffectToTile.setXY(X, Y); gcAddEffectToTile.setDuration(output.Duration); pZone->broadcastPacket(X, Y, &gcAddEffectToTile, pSlayer); } const list<Object*>& oList = tile.getObjectList(); for(list<Object*>::const_iterator itr = oList.begin(); itr != oList.end(); itr++) { Object* pTarget = *itr; //Creature* pTargetCreature = NULL; //if (pTarget->getObjectClass() == Object::OBJECT_CLASS_CREATURE) { // pTargetCreature = dynamic_cast<Creature*>(pTarget); // 이펙트 클래스를 생성한다. /* EffectSanctuary* pEffect = new EffectSanctuary(pZone , tileX, tileY, X, Y); pEffect->setDeadline(output.Duration); pEffect->setLevel(pSlayer->getINT()); pEffect->setDuration(output.Duration); pEffect->setStartTime(); // 캐릭터에 붙는다. 못 움직이게 할려고.. objectregister.registerObject(pEffect); pTargetCreature->getEffectManager()->addEffect(pEffect); pZone->addEffect(pEffect); */ } /* && (pTargetCreature = dynamic_cast<Creature*>(pTarget))->isSlayer()) { cList.push_back(pTargetCreature); _GCSkillToTileOK2.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK4.addCListElement(pTargetCreature->getObjectID()); _GCSkillToTileOK5.addCListElement(pTargetCreature->getObjectID()); } */ pEffect->affectObject(pTarget, false); } } } } // client에서는 effect생성되는 시간이 있어서 // 타이밍 맞출려면.. 시간을 좀 빼줘야 한다. -_-; output.Duration -= 20; // 2초 뺀다. _GCSkillToTileOK1.setSkillType(SkillType); _GCSkillToTileOK1.setCEffectID(CEffectID); _GCSkillToTileOK1.setX(X); _GCSkillToTileOK1.setY(Y); _GCSkillToTileOK1.setDuration(output.Duration); _GCSkillToTileOK1.setRange(Range); _GCSkillToTileOK2.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK2.setSkillType(SkillType); _GCSkillToTileOK2.setX(X); _GCSkillToTileOK2.setY(Y); _GCSkillToTileOK2.setDuration(output.Duration); _GCSkillToTileOK2.setRange(Range); //_GCSkillToTileOK2.addShortData(MODIFY_VISION, SANCTUARY_SIGHT); _GCSkillToTileOK3.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK3.setSkillType(SkillType); _GCSkillToTileOK3.setX(X); _GCSkillToTileOK3.setY(Y); _GCSkillToTileOK4.setSkillType(SkillType); _GCSkillToTileOK4.setX(X); _GCSkillToTileOK4.setY(Y); _GCSkillToTileOK4.setRange(Range); _GCSkillToTileOK4.setDuration(output.Duration); _GCSkillToTileOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToTileOK5.setSkillType(SkillType); _GCSkillToTileOK5.setX(X); _GCSkillToTileOK5.setY(Y); _GCSkillToTileOK5.setRange(Range); _GCSkillToTileOK5.setDuration(output.Duration); _GCSkillToTileOK6.setOrgXY(myX, myY); _GCSkillToTileOK6.setSkillType(SkillType); _GCSkillToTileOK6.setX(X); _GCSkillToTileOK6.setY(Y); _GCSkillToTileOK6.setDuration(output.Duration); _GCSkillToTileOK6.setRange(Range); //_GCSkillToTileOK6.addShortData(MODIFY_VISION, SANCTUARY_SIGHT); // EXP UP! SkillDomainType_t DomainType = pSkillInfo->getDomainType(); SkillGrade Grade = g_pSkillInfoManager->getGradeByDomainLevel(pSlayer->getSkillDomainLevel(DomainType)); Exp_t ExpUp = 10* (Grade + 1); shareAttrExp(pSlayer, ExpUp, 1, 1, 8, _GCSkillToTileOK1); increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToTileOK1); increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToTileOK1); for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++) { Creature* pTargetCreature = *itr; if (canSee(pTargetCreature, pSlayer)) pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2); else pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK6); } pPlayer->sendPacket(&_GCSkillToTileOK1); cList.push_back(pSlayer); list<Creature*> watcherList = pZone->getWatcherList(myX, myY, pSlayer); // watcherList에서 cList에 속하지 않고, caster(pSlayer)를 볼 수 없는 경우는 // OK4를 보내고.. cList에 추가한다. for(list<Creature*>::const_iterator itr = watcherList.begin(); itr != watcherList.end(); itr++) { bool bBelong = false; for(list<Creature*>::const_iterator tItr = cList.begin(); tItr != cList.end(); tItr++) if (*itr == *tItr) bBelong = true; Creature* pWatcher = (*itr); if (bBelong == false && canSee(pWatcher, pSlayer) == false) { //Assert(pWatcher->isPC()); // 당연 PC다.. Zone::getWatcherList는 PC만 return한다 if (!pWatcher->isPC()) { //cout << "Sanctuary : 왓처 리스트가 PC가 아닙니다." << endl; GCSkillFailed1 _GCSkillFailed1; _GCSkillFailed1.setSkillType(getSkillType()); pSlayer->getPlayer()->sendPacket(&_GCSkillFailed1); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } pWatcher->getPlayer()->sendPacket(&_GCSkillToTileOK4); cList.push_back(*itr); } } cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList, false); pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK3 , cList); pZone->broadcastPacket(X, Y, &_GCSkillToTileOK4 , cList); pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pSlayer, getSkillType(), NULL); } } catch (Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }