void InstallMine::execute(Slayer* pSlayer, ObjectID_t, CoordInven_t X, CoordInven_t Y, CoordInven_t TargetX, CoordInven_t TargetY, SkillSlot* pSkillSlot) throw(Error) { __BEGIN_TRY Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); GCSkillToInventoryOK1 _GCSkillToInventoryOK1; // GCSkillToTileOK1 _GCSkillToTileOK1; // GCSkillToTileOK5 _GCSkillToTileOK5; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo * pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); SkillLevel_t SkillLevel = pSkillSlot->getExpLevel(); // 명중률. //ToHit_t ToHit = pSlayer->getToHit(); int RequiredMP = (int)pSkillInfo->getConsumeMP(); bool bManaCheck = hasEnoughMana(pSlayer, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer); ZoneCoord_t slayerX = pSlayer->getX(), slayerY = pSlayer->getY(); bool bInstallAction = false; Mine* pMine = NULL; Inventory * pInventory = pSlayer->getInventory(); Assert(pInventory != NULL); if(bManaCheck && bTimeCheck &&bRangeCheck ) { // mine을 찾는다. Item* pItem = pInventory->getItem(X, Y); if(pItem != NULL && pItem->getItemClass() == Item::ITEM_CLASS_MINE) { bInstallAction = true; pMine = dynamic_cast<Mine*>(pItem); } } // 기술의 성패를 따진다. if (bInstallAction ) { //Range_t Range = 1; GCSkillToInventoryOK1 _GCSkillToInventoryOK1; // GCSkillToInventoryOK5 _GCSkillToInventoryOK5; ItemInfo* pItemInfo = g_pItemInfoManager->getItemInfo(Item::ITEM_CLASS_MINE, pMine->getItemType()); Damage_t MinDamage = pItemInfo->getMinDamage(); Damage_t MaxDamage = pItemInfo->getMaxDamage(); Damage_t RealDamage = MinDamage + (max (0, ((int)MaxDamage * (int)SkillLevel / 100 ) - MinDamage )); Mine * pInstallMine = new Mine(); ObjectRegistry& OR = pZone->getObjectRegistry(); OR.registerObject(pInstallMine); Assert(pInstallMine != NULL); pInstallMine->setItemType(pMine->getItemType()); pInstallMine->setDir(TargetX); pInstallMine->setDamage(RealDamage); pInstallMine->setInstallerName(pSlayer->getName()); pInstallMine->setInstallerPartyID(pSlayer->getPartyID()); pInstallMine->setFlag(Effect::EFFECT_CLASS_INSTALL); // 아이템 사라지는게 3분인거 때문에 지뢰도 사라졌는데.. // 10분으로 고정. by sigi. 2002.11.3 TPOINT pt = pZone->addItem(pInstallMine, slayerX, slayerY, true, 6000); // EXP up Exp_t Point = pSkillInfo->getPoint(); shareAttrExp(pSlayer, 100, 1, 8, 1, _GCSkillToInventoryOK1); increaseDomainExp(pSlayer, SKILL_DOMAIN_GUN, Point, _GCSkillToInventoryOK1); increaseSkillExp(pSlayer, SKILL_DOMAIN_GUN, pSkillSlot, pSkillInfo, _GCSkillToInventoryOK1); decreaseMana(pSlayer, RequiredMP, _GCSkillToInventoryOK1); decreaseItemNum(pMine, pInventory, pSlayer->getName(), STORAGE_INVENTORY, 0, X, Y); _GCSkillToInventoryOK1.setObjectID(pInstallMine->getObjectID()); _GCSkillToInventoryOK1.setSkillType(SkillType); _GCSkillToInventoryOK1.setCEffectID(0); _GCSkillToInventoryOK1.setX(X); _GCSkillToInventoryOK1.setY(Y); _GCSkillToInventoryOK1.setDuration(0); /* _GCSkillToInventoryOK5.setObjectID(pSlayer->getObjectID()); _GCSkillToInventoryOK5.setSkillType(SkillType); _GCSkillToInventoryOK5.setX(X); _GCSkillToInventoryOK5.setY(Y); _GCSkillToInventoryOK5.setRange(Range); _GCSkillToInventoryOK5.setDuration(0); */ pPlayer->sendPacket(&_GCSkillToInventoryOK1); // mine을 볼 수 없게 된 자들에게는 삭제 addInstalledMine(pZone, pInstallMine, pt.x, pt.y); // pZone->broadcastPacket(slayerX, slayerY, &_GCSkillToInventoryOK5, pSlayer); // cout << "Run Skill : " << (int)SkillType << endl; // Set NextTime pSkillSlot->setRunTime(); } else { GCSkillFailed1 _GCSkillFailed1; GCSkillFailed2 _GCSkillFailed2; executeSkillFailException(pSlayer, getSkillType()); } } catch(Throwable & t) { executeSkillFailException(pSlayer, getSkillType()); } __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 ////////////////////////////////////////////////////////////////////////////// void DoubleShot::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; } bool bIncreaseDomainExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND); GCAttackArmsOK1 _GCAttackArmsOK1; GCAttackArmsOK2 _GCAttackArmsOK2; GCAttackArmsOK3 _GCAttackArmsOK3; GCAttackArmsOK4 _GCAttackArmsOK4; GCAttackArmsOK5 _GCAttackArmsOK5; // 들고 있는 무기가 없거나, 총 계열 무기가 아니라면 기술을 쓸 수 없다. // 총 계열 무기 중에서도 SG나 SR은 DoubleShot를 쓸 수가 없다. // SR, SG 도 이제 쓸수 있다. // 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; } 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; 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) { 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 << "DoubleShotDamage:" << Damage << endl; // 데미지를 세팅한다. setDamage(pTargetCreature, Damage, pSlayer, SkillType, &_GCAttackArmsOK2, &_GCAttackArmsOK1); computeAlignmentChange(pTargetCreature, Damage, pSlayer, &_GCAttackArmsOK2, &_GCAttackArmsOK1); // 공격자와 상대의 아이템 내구성 떨어트림. // 밑에 있던걸 이쪽으로 옮겼다. by sigi. 2002.5.13 decreaseDurability(pSlayer, pTargetCreature, NULL, &_GCAttackArmsOK1, &_GCAttackArmsOK2); // 크리티컬 히트라면 상대방을 뒤로 물러나게 한다. if (bCriticalHit) { knockbackCreature(pZone, pTargetCreature, pSlayer->getX(), pSlayer->getY()); } /* // 80% 확률로만 능력치가 상승한다. // 상대방이 슬레이어가 아닐 경우에만 경험치가 상승한다. if (Random(1, 100) < 80 && !pTargetCreature->isSlayer()) { */ if(!pTargetCreature->isSlayer() ) { if (bIncreaseDomainExp ) { 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(pSlayer->getObjectID()); pTargetPlayer->sendPacket(&_GCAttackArmsOK2); } } else if (pTargetCreature->isMonster()) { Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature); pMonster->addEnemy(pSlayer); } ZoneCoord_t targetX = pTargetCreature->getX(); ZoneCoord_t targetY = pTargetCreature->getY(); ZoneCoord_t myX = pSlayer->getX(); ZoneCoord_t myY = pSlayer->getY(); _GCAttackArmsOK1.setObjectID(TargetObjectID); _GCAttackArmsOK1.setBulletNum(RemainBullet); _GCAttackArmsOK3.setObjectID(pSlayer->getObjectID()); _GCAttackArmsOK3.setTargetXY (targetX, targetY); _GCAttackArmsOK4.setTargetObjectID (TargetObjectID); _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); } } catch (Throwable &t) { executeSkillFailException(pSlayer, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_DEBUG __END_CATCH }