////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void Restore::execute(Slayer* pSlayer, ObjectID_t TargetObjectID, SkillSlot* pSkillSlot, CEffectID_t CEffectID) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; //cout << "Restore2 Start" << endl; Assert(pSlayer != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pSlayer->getPlayer(); Zone* pZone = pSlayer->getZone(); Assert(pPlayer != NULL); Assert(pZone != NULL); Creature* pFromCreature = pZone->getCreature(TargetObjectID); // 뱀파이어만 건드릴 수가 있다. // NoSuch제거. by sigi. 2002.5.2 if (pFromCreature==NULL || !pFromCreature->isVampire()) { executeSkillFailException(pSlayer, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } GCSkillToObjectOK1 _GCSkillToObjectOK1; // 스킬 쓴 넘에게... GCMorph1 _GCMorph1; // 변신 당사자에게.. GCMorphSlayer2 _GCMorphSlayer2; // 변신 구경꾼들에게.. SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); bool bRangeCheck = verifyDistance(pSlayer, pFromCreature, pSkillInfo->getRange()); bool bHitRoll = true; if (bRangeCheck && bHitRoll) { ////////////////////////////////////////////////////////////////////// // 각종 존 레벨 정보를 삭제해야 한다. ////////////////////////////////////////////////////////////////////// // 파티 초대 중이라면 정보를 삭제해 준다. PartyInviteInfoManager* pPIIM = pZone->getPartyInviteInfoManager(); Assert(pPIIM != NULL); pPIIM->cancelInvite(pFromCreature); // 파티 관련 정보를 삭제해 준다. int PartyID = pFromCreature->getPartyID(); if (PartyID != 0) { // 먼저 로컬에서 삭제하고... LocalPartyManager* pLPM = pZone->getLocalPartyManager(); Assert(pLPM != NULL); pLPM->deletePartyMember(PartyID, pFromCreature); // 글로벌에서도 삭제해 준다. deleteAllPartyInfo(pFromCreature); } // 트레이드 중이었다면 트레이드 관련 정보를 삭제해준다. TradeManager* pTM = pZone->getTradeManager(); Assert(pTM != NULL); pTM->cancelTrade(pFromCreature); ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// Slayer* pNewSlayer = new Slayer; Vampire* pVampire = dynamic_cast<Vampire*>(pFromCreature); // DB에서 혹시 남아있을 지 모르는 흡혈 정보를 삭제해준다. Statement* pStmt = NULL; BEGIN_DB { pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement(); StringStream sql; sql << "DELETE FROM EffectBloodDrain WHERE OwnerID = '" + pFromCreature->getName() + "'"; pStmt->executeQuery(sql.toString()); SAFE_DELETE(pStmt); } END_DB(pStmt) pNewSlayer->setName(pFromCreature->getName()); // 크리쳐 안의 플레이어 포인터와 플레이어 안의 크리쳐 포인터를 갱신한다. Player* pFromPlayer = pFromCreature->getPlayer(); pNewSlayer->setPlayer(pFromPlayer); GamePlayer* pFromGamePlayer = dynamic_cast<GamePlayer*>(pFromPlayer); pFromGamePlayer->setCreature(pNewSlayer); pNewSlayer->setZone(pZone); pNewSlayer->load(); pNewSlayer->setObjectID(pFromCreature->getObjectID()); pNewSlayer->setMoveMode(Creature::MOVE_MODE_WALKING); ZoneCoord_t x = pFromCreature->getX(); ZoneCoord_t y = pFromCreature->getY(); Dir_t dir = pFromCreature->getDir(); Tile& tile = pZone->getTile(x, y); // 곧 pFromCreature 즉, 원래의 뱀파이어 객체는 지워질 것이므로, // PCFinder에 들어가 있는 값은 쓰레기 값이 될 것이다. // 그러므로 뱀파이어 포인터를 지워주고, 새로운 슬레이어 포인터를 더한다. g_pPCFinder->deleteCreature(pFromCreature->getName()); g_pPCFinder->addCreature(pNewSlayer); // 길드 현재 접속 멤버 리스트에서 삭제한다. if (pVampire->getGuildID() != 0 ) g_pGuildManager->getGuild(pVampire->getGuildID() )->deleteCurrentMember(pVampire->getName()); // 인벤토리 교체. Inventory* pInventory = pVampire->getInventory(); pNewSlayer->setInventory(pInventory); pVampire->setInventory(NULL); // 보관함 교체 pNewSlayer->deleteStash(); pNewSlayer->setStash(pVampire->getStash()); pNewSlayer->setStashNum(pVampire->getStashNum()); pNewSlayer->setStashStatus(false); pVampire->setStash(NULL); /* // 가비지 교체 while (true) { Item* pGarbage = pVampire->popItemFromGarbage(); // 더 이상 없다면 브레이크... if (pGarbage == NULL) break; pNewSlayer->addItemToGarbage(pGarbage); } */ // 플래그 셋 교체 pNewSlayer->deleteFlagSet(); pNewSlayer->setFlagSet(pVampire->getFlagSet()); pVampire->setFlagSet(NULL); Item* pItem = NULL; _TPOINT point; // 입고 있는 아이템들을 인벤토리 또는 바닥으로 옮긴다. for(int part = 0; part < (int)Vampire::VAMPIRE_WEAR_MAX; part++) { pItem = pVampire->getWearItem((Vampire::WearPart)part); if (pItem != NULL) { // 먼저 기어에서 삭제하고... pVampire->deleteWearItem((Vampire::WearPart)part); // 인벤토리에 자리가 있으면 인벤토리에 더하고... if (pInventory->getEmptySlot(pItem, point)) { pInventory->addItem(point.x, point.y, pItem); pItem->save(pNewSlayer->getName(), STORAGE_INVENTORY, 0, point.x, point.y); } // 자리가 없으면 바닥에 떨어뜨린다. else { ZoneCoord_t ZoneX = pVampire->getX(); ZoneCoord_t ZoneY = pVampire->getY(); TPOINT pt; pt = pZone->addItem(pItem, ZoneX , ZoneY); if (pt.x != -1) { pItem->save("", STORAGE_ZONE, pZone->getZoneID(), pt.x, pt.y); } else { pItem->destroy(); SAFE_DELETE(pItem); } } } } pItem = pVampire->getExtraInventorySlotItem(); if (pItem != NULL) { pVampire->deleteItemFromExtraInventorySlot(); // 인벤토리에 자리가 있으면 인벤토리에 더하고... if (pInventory->getEmptySlot(pItem, point)) { pInventory->addItem(point.x, point.y, pItem); pItem->save(pNewSlayer->getName(), STORAGE_INVENTORY, 0, point.x, point.y); } // 자리가 없으면 바닥에 떨어뜨린다. else { TPOINT pt; ZoneCoord_t ZoneX = pVampire->getX(); ZoneCoord_t ZoneY = pVampire->getY(); pt = pZone->addItem(pItem, ZoneX , ZoneY); if (pt.x != -1) { pItem->save("", STORAGE_ZONE, pZone->getZoneID(), pt.x, pt.y); } else { pItem->destroy(); SAFE_DELETE(pItem); } } } // 뱀파이어 가지고 있던 돈을 슬레이어로 옮겨준다. pNewSlayer->setGoldEx(pVampire->getGold()); // 스킬 정보를 전송한다. pNewSlayer->sendSlayerSkillInfo(); _GCMorph1.setPCInfo2(pNewSlayer->getSlayerInfo2()); _GCMorph1.setInventoryInfo(pNewSlayer->getInventoryInfo()); _GCMorph1.setGearInfo(pNewSlayer->getGearInfo()); _GCMorph1.setExtraInfo(pNewSlayer->getExtraInfo()); _GCMorphSlayer2.setSlayerInfo(pNewSlayer->getSlayerInfo3()); pFromPlayer->sendPacket(&_GCMorph1); //pFromGamePlayer->deleteEvent(Event::EVENT_CLASS_REGENERATION); pZone->broadcastPacket(x, y, &_GCMorphSlayer2, pNewSlayer); // 타일 및 존에서 기존 뱀파이어를 삭제하고, 새로운 슬레이어를 더한다. tile.deleteCreature(pFromCreature->getObjectID()); pZone->deletePC(pFromCreature); TPOINT pt = findSuitablePosition(pZone, x, y, Creature::MOVE_MODE_WALKING); Tile& newtile = pZone->getTile(pt.x, pt.y); newtile.addCreature(pNewSlayer); pNewSlayer->setXYDir(pt.x, pt.y, dir); pZone->addPC(pNewSlayer); pNewSlayer->tinysave("Race='SLAYER'"); SAFE_DELETE(pFromCreature); // 시야 update.. pZone->updateHiddenScan(pNewSlayer); _GCSkillToObjectOK1.setSkillType(SkillType); _GCSkillToObjectOK1.setCEffectID(CEffectID); _GCSkillToObjectOK1.setTargetObjectID(TargetObjectID); _GCSkillToObjectOK1.setDuration(0); pPlayer->sendPacket(&_GCSkillToObjectOK1); pSkillSlot->setRunTime(0); EffectRestore* pEffectRestore = new EffectRestore(pNewSlayer); pEffectRestore->setDeadline(60*60*24*7*10); // 7일 pNewSlayer->addEffect(pEffectRestore); pNewSlayer->setFlag(Effect::EFFECT_CLASS_RESTORE); pEffectRestore->create(pNewSlayer->getName()); } else { executeSkillFailNormal(pSlayer, getSkillType(), pFromCreature); } }
////////////////////////////////////////////////////////////////////////////// // 아우스터즈 타일 핸들러 ////////////////////////////////////////////////////////////////////////////// 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 }