void CGTradeAddItemHandler::executeOusters (CGTradeAddItem* pPacket , Player* pPlayer) throw(ProtocolException , Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ // 상위 함수에서 에러를 검사했기 때문에, // 여기서는 포인터가 널인지를 검사하지 않는다. ObjectID_t TargetOID = pPacket->getTargetObjectID(); ObjectID_t ItemOID = pPacket->getItemObjectID(); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Creature* pPC = pGamePlayer->getCreature(); Zone* pZone = pPC->getZone(); PlayerCreature* pTargetPC = dynamic_cast<PlayerCreature*>(pZone->getCreature(TargetOID)); // NoSuch제거. by sigi. 2002.5.2 if (pTargetPC==NULL) return; Ousters* pSender = dynamic_cast<Ousters*>(pPC); TradeManager* pTradeManager = pZone->getTradeManager(); Assert(pTradeManager != NULL); // 교환 대상에 추가할 아이템의 포인터를 얻어낸다. CoordInven_t X, Y; Inventory* pInventory = pSender->getInventory(); Item* pItem = pInventory->findItemOID(ItemOID, X, Y); // 추가할 아이템이 없다면 당연히 더 이상 처리가 불가능 // Relic은 교환할 수 없다. if (pItem == NULL || !canTrade(pItem ) || pSender->getStore()->hasItem(pItem) || (pItem->getItemClass() == Item::ITEM_CLASS_SUB_INVENTORY && hasItemWithItemClass(pTargetPC, Item::ITEM_CLASS_SUB_INVENTORY ) ) ) { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_ADD_ITEM); return; } // //#ifdef __XMAS_EVENT_CODE__ // 녹색 선물 상자인 경우에는, 상대방에게 적색 선물 상자가 없는지 검사한 후, // 인증 패킷을 보내줘야 한다. if (pItem->getItemClass() == Item::ITEM_CLASS_EVENT_GIFT_BOX) { PlayerCreature* pReceiver = dynamic_cast<PlayerCreature*>(pTargetPC); Item* pExtraSlotItem = pReceiver->getExtraInventorySlotItem(); if (pItem->getItemType() == 0) { Inventory* pTargetInventory = pReceiver->getInventory(); if (pTargetInventory->hasRedGiftBox()) { // 적색 선물 상자를 가지고 있다면 더할 수 없다. 리턴시킨다. GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_FAIL); pPlayer->sendPacket(&gcTradeVerify); return; } else if (pExtraSlotItem != NULL) { if (pExtraSlotItem->getItemClass() == Item::ITEM_CLASS_EVENT_GIFT_BOX && pExtraSlotItem->getItemType() == 1) { GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_FAIL); pPlayer->sendPacket(&gcTradeVerify); return; } } else { // 적색 선물 상자를 가지고 있지 않다면, 걍 넘어간다. GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_OK); pPlayer->sendPacket(&gcTradeVerify); } } else if (pItem->getItemType() == 1) { // 적색 선물 상자는 교환 품목이 될 수 없다. GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_FAIL); pPlayer->sendPacket(&gcTradeVerify); return; } } //#endif // TradeInfo* pInfo1 = pTradeManager->getTradeInfo(pSender->getName()); TradeInfo* pInfo2 = pTradeManager->getTradeInfo(pTargetPC->getName()); list<Item*> tradeList1 = pInfo1->getItemList(); if (pItem->getItemClass() == Item::ITEM_CLASS_EVENT_GIFT_BOX && pItem->getItemType() > 1 && pItem->getItemType() < 6) { for (list<Item*>::iterator itr = tradeList1.begin(); itr != tradeList1.end(); itr++) { Item* pTradeItem = (*itr); if (pTradeItem->getItemClass() == Item::ITEM_CLASS_EVENT_GIFT_BOX && pTradeItem->getItemType() > 1 && pTradeItem->getItemType() < 6) { GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_FAIL); pPlayer->sendPacket(&gcTradeVerify); return; } } GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_OK); pPlayer->sendPacket(&gcTradeVerify); } else if (pItem->getItemClass() == Item::ITEM_CLASS_EVENT_GIFT_BOX && pItem->getItemType() >= 6) { GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_OK); pPlayer->sendPacket(&gcTradeVerify); } // TradeManager에 교환 대상으로서 아이템을 더한다. //Assert(pInfo1->addItem(pItem)); pInfo1->addItem(pItem); // 현재 OK를 누른 상태라면, 클라이언트에게 인증 패킷을 보내줘야 한다. if (pInfo1->getStatus() == TRADE_FINISH) { //cout << "CGTradeRemoveItem [" << pSender->getName() << "]의 상태가 TRADE_FINISH이므로, 인증 패킷을 보내준다." << endl; // 인증 패킷을 날려준다. GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_ADD_ITEM_WHEN_ACCEPT); pPlayer->sendPacket(&gcTradeVerify); } else { //cout << "CGTradeRemoveItem [" << pSender->getName() << "]의 상태가 TRADE_FINISH가 아니므로, 인증 패킷 날리지 않는다." << endl; } // 아이템을 더하거나 뺄 경우, 상태가 TRADE_FINISH라면 // TRADE_TRADING으로 바꿔줘야 한다. pInfo1->setStatus(TRADE_TRADING); pInfo2->setStatus(TRADE_TRADING); // 상대방에게 날려줄 아이템 정보를 구성한다. GCTradeAddItem gcTradeAddItem; makeGCTradeAddItemPacket(&gcTradeAddItem, pSender->getObjectID(), pItem, X, Y); // 상대방에게 교환할 아이템 정보를 날려준다. Player* pTargetPlayer = pTargetPC->getPlayer(); pTargetPlayer->sendPacket(&gcTradeAddItem); #endif __END_DEBUG_EX __END_CATCH }
void CGTradeMoneyHandler::executeOusters (CGTradeMoney* pPacket , Player* pPlayer) throw(ProtocolException , Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ // 상위 함수에서 검사를 했기 때문에, // 여기서는 포인터가 널인지를 검사하지 않는다. ObjectID_t TargetOID = pPacket->getTargetObjectID(); Gold_t Amount = pPacket->getAmount(); BYTE Code = pPacket->getCode(); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Creature* pPC = pGamePlayer->getCreature(); Zone* pZone = pPC->getZone(); Creature* pTargetPC = pZone->getCreature(TargetOID); // NoSuch제거. by sigi. 2002.5.2 if (pTargetPC==NULL) return; Ousters* pSender = dynamic_cast<Ousters*>(pPC); Ousters* pReceiver = dynamic_cast<Ousters*>(pTargetPC); Player* pTargetPlayer = pTargetPC->getPlayer(); Gold_t finalAmount = Amount; Gold_t margin = 0; GCTradeMoney gcTradeMoney; GCTradeVerify gcTradeVerify; TradeManager* pTradeManager = pZone->getTradeManager(); Assert(pTradeManager != NULL); // 교환 상태가 맞는지 체크를 해봐야한다. TradeInfo* pInfo1 = pTradeManager->getTradeInfo(pSender->getName()); TradeInfo* pInfo2 = pTradeManager->getTradeInfo(pReceiver->getName()); // 인벤토리에서 돈을 덜어, 교환창에다 더한다. if (Code == CG_TRADE_MONEY_INCREASE) { // 교환창에다 더할 액수보다 많은 돈을 가지고 있어야 한다. if (pSender->getGold() >= Amount) { // 돈을 받는 쪽이 맥스를 초과하게 된다면, 일부만 넣어줘야 한다. // 현재 교환 예정인 돈도 더해서 계산. by sigi. 2003.1.8 Gold_t receiverGold = pReceiver->getGold() + pInfo1->getGold(); if (receiverGold + Amount > MAX_MONEY) { margin = receiverGold + Amount - MAX_MONEY; finalAmount = finalAmount - margin; } // 인벤토리에서 돈을 빼고, 교환창에다 더한다. pSender->setGold(pSender->getGold() - finalAmount); pInfo1->setGold(pInfo1->getGold() + finalAmount); // 현재 OK를 누른 상태라면, 클라이언트에게 인증 패킷을 보내줘야 한다. if (pInfo1->getStatus() == TRADE_FINISH) { // 인증 패킷을 날려준다. gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_MONEY_INCREASE); pPlayer->sendPacket(&gcTradeVerify); } // 아이템을 더하거나 뺄 경우, 상태를 변환해줘야 한다. pInfo1->setStatus(TRADE_TRADING); pInfo2->setStatus(TRADE_TRADING); // 돈을 올린 당사자에게 실제로 인벤토리에서 // 빠진 금액이 얼마인지 보내준다. gcTradeMoney.setTargetObjectID(TargetOID); gcTradeMoney.setCode(GC_TRADE_MONEY_INCREASE_RESULT); gcTradeMoney.setAmount(finalAmount); pPlayer->sendPacket(&gcTradeMoney); // 상대방에게 바뀐 정보를 보내준다. gcTradeMoney.setTargetObjectID(pSender->getObjectID()); gcTradeMoney.setCode(GC_TRADE_MONEY_INCREASE); gcTradeMoney.setAmount(finalAmount); pTargetPlayer->sendPacket(&gcTradeMoney); } else { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_INCREASE_MONEY); return; } } // 교환창에서 돈을 덜어, 인벤토리에다가 더한다. else if (Code == CG_TRADE_MONEY_DECREASE) { // 인벤토리에다 더할 액수보다 교환창에 있는 돈이 많아야 한다. if (pInfo1->getGold() >= Amount) { // 돈이 맥스를 초과하게 된다면, 일부만 뺄 수 있다. Gold_t senderGold = pSender->getGold() + pInfo2->getGold(); if (senderGold + Amount > MAX_MONEY) { margin = senderGold + Amount - MAX_MONEY; finalAmount = finalAmount - margin; } // 인벤토리에다가 돈을 더하고, 교환창에서 돈을 뺀다. pSender->setGold(pSender->getGold() + finalAmount); pInfo1->setGold(pInfo1->getGold() - finalAmount); // 현재 OK를 누른 상태라면, 클라이언트에게 인증 패킷을 보내줘야 한다. if (pInfo1->getStatus() == TRADE_FINISH) { // 인증 패킷을 날려준다. gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_MONEY_DECREASE); pPlayer->sendPacket(&gcTradeVerify); } // 아이템을 더하거나 뺄 경우, 상태를 변환해줘야 한다. pInfo1->setStatus(TRADE_TRADING); pInfo2->setStatus(TRADE_TRADING); // 돈을 올린 당사자에게 실제로 인벤토리에다 // 더한 금액이 얼마인지 보내준다. gcTradeMoney.setTargetObjectID(TargetOID); gcTradeMoney.setCode(GC_TRADE_MONEY_DECREASE_RESULT); gcTradeMoney.setAmount(finalAmount); pPlayer->sendPacket(&gcTradeMoney); // 상대방에게 바뀐 정보를 보내준다. gcTradeMoney.setTargetObjectID(pSender->getObjectID()); gcTradeMoney.setCode(GC_TRADE_MONEY_DECREASE); gcTradeMoney.setAmount(finalAmount); pTargetPlayer->sendPacket(&gcTradeMoney); } else { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_DECREASE_MONEY); return; } } #endif __END_DEBUG_EX __END_CATCH }
void CGTradeAddItemHandler::execute (CGTradeAddItem* pPacket , Player* pPlayer) throw(ProtocolException , Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ Assert(pPacket != NULL); Assert(pPlayer != NULL); ObjectID_t TargetOID = pPacket->getTargetObjectID(); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Creature* pPC = pGamePlayer->getCreature(); Assert(pPC != NULL); Zone* pZone = pPC->getZone(); Assert(pZone != NULL); TradeManager* pTradeManager = pZone->getTradeManager(); Assert(pTradeManager != NULL); // 교환을 원하는 상대방을 존에서 찾아본다. Creature* pTargetPC = NULL; /* try { pTargetPC = pZone->getCreature(TargetOID); } catch (NoSuchElementException) { pTargetPC = NULL; } */ // NoSuch제거. by sigi. 2002.5.2 pTargetPC = pZone->getCreature(TargetOID); // 교환 상대가 없다면 에러다. if (pTargetPC == NULL) { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_TARGET_NOT_EXIST); return; } // 교환 상대가 사람이 아니거나, 같은 종족이 아니라면 에러다. if (!pTargetPC->isPC() || !isSameRace(pTargetPC, pPC)) { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_RACE_DIFFER); return; } // 둘 다 안전 지대에 있는지 체크를 한다. if (!isInSafeZone(pPC) || !isInSafeZone(pTargetPC)) { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_NOT_SAFE); return; } // 오토바이를 타고 있다면 에러다. if (pPC->isSlayer() && pTargetPC->isSlayer()) { Slayer* pSlayer1 = dynamic_cast<Slayer*>(pPC); Slayer* pSlayer2 = dynamic_cast<Slayer*>(pTargetPC); if (pSlayer1->hasRideMotorcycle() || pSlayer2->hasRideMotorcycle()) { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_MOTORCYCLE); return; } } if (pPC->isOusters() && pTargetPC->isOusters()) { Ousters* pOusters1 = dynamic_cast<Ousters*>(pPC); Ousters* pOusters2 = dynamic_cast<Ousters*>(pTargetPC); if (pOusters1->isFlag(Effect::EFFECT_CLASS_SUMMON_SYLPH) || pOusters2->isFlag(Effect::EFFECT_CLASS_SUMMON_SYLPH) ) { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_MOTORCYCLE); return; } } // 둘이서 교환을 하고 있는 상태가 아니라면 에러다. if (!pTradeManager->isTrading(pPC, pTargetPC)) { pTradeManager->cancelTrade(pPC); executeError(pPacket, pPlayer, GC_TRADE_ERROR_CODE_NOT_TRADING); return; } if (pPC->isSlayer()) executeSlayer(pPacket, pPlayer); else if (pPC->isVampire()) executeVampire(pPacket, pPlayer); else if (pPC->isOusters()) executeOusters(pPacket, pPlayer); else throw ProtocolException("CGTradeAddItemHandler::execute() : 알 수 없는 플레이어 크리쳐"); #endif __END_DEBUG_EX __END_CATCH }
void CGAddMouseToInventoryHandler::execute(CGAddMouseToInventory* pPacket , Player* pPlayer) throw(ProtocolException, Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ Assert(pPacket != NULL); Assert(pPlayer != NULL); try { GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Assert(pGamePlayer != NULL); Creature* pCreature = pGamePlayer->getCreature(); Assert(pCreature != NULL); Assert(pCreature->isPC()); PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pCreature); Assert(pPC != NULL); Zone* pZone = pPC->getZone(); Assert(pZone != NULL); Inventory* pInventory = pPC->getInventory(); Assert(pInventory != NULL); Item* pItem = pPC->getExtraInventorySlot()->getItem(); bool Success = false; if (pItem == NULL) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } int invenID = 0; /* Commenting the SubInventory stuff, since it's not supported by the client we use SubInventory* pInventoryItem = NULL; int invenID = 0; if (pPacket->getInventoryItemObjectID() != 0 ) { // cout << "서브 인벤토리에 넣기 : " << pPacket->getInventoryItemObjectID() << endl; CoordInven_t X, Y; pInventoryItem = dynamic_cast<SubInventory*>(pInventory->findItemOID(pPacket->getInventoryItemObjectID(), X, Y )); TradeManager* pTradeManager = pZone->getTradeManager(); Assert(pTradeManager != NULL); if (pInventoryItem == NULL || pItem->getItemClass() == Item::ITEM_CLASS_SUB_INVENTORY || pTradeManager->hasTradeInfo(pPC->getName()) ) { // cout << "근데 서브 인벤토리가 없다." <<endl; GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } pInventory = pInventoryItem->getInventory(); invenID = pInventoryItem->getItemID(); } */ //Item::ItemClass itemClass = pItem->getItemClass(); //ItemType_t itemType = pItem->getItemType(); ObjectID_t itemObjectID = pItem->getObjectID(); CoordInven_t InvenX = pPacket->getInvenX(); CoordInven_t InvenY = pPacket->getInvenY(); if (InvenX >= pInventory->getWidth() || InvenY >= pInventory->getHeight() || itemObjectID != pPacket->getObjectID() || !pInventory->canAdding(InvenX, InvenY, pItem)) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } TPOINT pt; pt.x = 99; pt.y = 99; // 넣을려는 Inventory Slot의 Item을 받아온다. Item* pPrevItem = pInventory->searchItem(InvenX, InvenY , pItem, pt); // 그 장소에 아이템이 있다면 if (pPrevItem != NULL) { bool bisSame = true; // 아이템 클래스가 같을때 숫자를 올려 주고 마우스에 있는 것은 없앤다. if (canStack(pItem, pPrevItem)) { int MaxStack = ItemMaxStack[pItem->getItemClass()]; VolumeWidth_t ItemWidth = pItem->getVolumeWidth(); VolumeHeight_t ItemHeight = pItem->getVolumeHeight(); VolumeWidth_t InvenWidth = pInventory->getWidth(); VolumeWidth_t InvenHeight= pInventory->getHeight(); if ((InvenX + ItemWidth <= InvenWidth) && (InvenY + ItemHeight <= InvenHeight)) { for (int x = InvenX; x < (InvenX + ItemWidth); x++) { for (int y = InvenY; y < (InvenY + ItemHeight); y++) { if (pInventory->hasItem(x, y)) { if(pInventory->getItem(x,y) != pPrevItem ) { bisSame = false; break; } } else { bisSame = false; break; } } } } // 들어갈 아이템과 들어있는 아이템의 좌표가 꼭 일치 한다면? if(bisSame) { // 숫자가 9개를 넘으면 9개 될때까지만 Add 하고 나머지는 마우스에 달아둔다. if (pItem->getNum() + pPrevItem->getNum() > MaxStack) { ItemNum_t CurrentNum = pPrevItem->getNum(); ItemNum_t AddNum = pItem->getNum(); ItemNum_t NewNum = AddNum + CurrentNum - MaxStack; pPrevItem->setNum(MaxStack); pItem->setNum(NewNum); pInventory->increaseNum(MaxStack - CurrentNum); pInventory->increaseWeight(pItem->getWeight()* (MaxStack - CurrentNum)); //pPrevItem->save(pPC->getName(), STORAGE_INVENTORY, 0, InvenX, InvenY); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=%d, X=%d, Y=%d", MaxStack, STORAGE_INVENTORY, invenID, InvenX, InvenY); pPrevItem->tinysave(pField); //pItem->save(pPC->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Num=%d, Storage=%d", NewNum, STORAGE_EXTRASLOT); pItem->tinysave(pField); Success = true; } else { pPC->deleteItemFromExtraInventorySlot(); pPrevItem->setNum(pPrevItem->getNum() + pItem->getNum()); pInventory->increaseNum(pItem->getNum()); pInventory->increaseWeight(pItem->getWeight()* pItem->getNum()); //pPrevItem->save(pPC->getName(), STORAGE_INVENTORY, 0, InvenX, InvenY); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=%u, X=%d, Y=%d", pPrevItem->getNum(), STORAGE_INVENTORY, invenID, InvenX, InvenY); pPrevItem->tinysave(pField); pItem->destroy(); SAFE_DELETE(pItem); Success = true; } if (g_pVariableManager->getVariable(NETMARBLE_CARD_EVENT) != 0 && pPrevItem->getItemClass() == Item::ITEM_CLASS_MOON_CARD && pPrevItem->getItemType() == 2 && pPrevItem->getNum() == 99) { GCNoticeEvent gcNE; gcNE.setCode(NOTICE_EVENT_NETMARBLE_CARD_FULL); pGamePlayer->sendPacket(&gcNE); //cout << "gcNE sent" << endl; } if (pPrevItem->getItemClass() == Item::ITEM_CLASS_LUCKY_BAG && pPrevItem->getItemType() == 3 && pPrevItem->getNum() == 50 ) { GCDeleteInventoryItem gcDI; gcDI.setObjectID(pPrevItem->getObjectID()); pGamePlayer->sendPacket(&gcDI); pInventory->deleteItem(pPrevItem->getObjectID()); pPrevItem->destroy(); SAFE_DELETE(pPrevItem); Item* pNewItem = g_pItemFactoryManager->createItem(Item::ITEM_CLASS_EVENT_ITEM, 28, list<OptionType_t>()); pZone->registerObject(pNewItem); if (!pInventory->addItem(pt.x, pt.y, pNewItem) ) return; pNewItem->create(pPC->getName(), STORAGE_INVENTORY, 0, pt.x, pt.y); if (pNewItem != NULL ) { GCCreateItem gcCI; makeGCCreateItem(&gcCI, pNewItem, pt.x, pt.y); pGamePlayer->sendPacket(&gcCI); } } } else { pInventory->deleteItem(pPrevItem->getObjectID()); pPC->deleteItemFromExtraInventorySlot(); pPC->addItemToExtraInventorySlot(pPrevItem); pInventory->addItem(InvenX , InvenY , pItem); //pPrevItem->save(pPC->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d", STORAGE_EXTRASLOT); pPrevItem->tinysave(pField); //pItem->save(pPC->getName(), STORAGE_INVENTORY, 0, InvenX, InvenY); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Storage=%d, StorageID=%u, X=%d, Y=%d", STORAGE_INVENTORY, invenID, InvenX, InvenY); pItem->tinysave(pField); Success = true; } } else {// 아이템 클래스가 다르거나, 쌓이는 아이템이 아니라면. pInventory->deleteItem(pPrevItem->getObjectID()); pPC->deleteItemFromExtraInventorySlot(); pPC->addItemToExtraInventorySlot(pPrevItem); pInventory->addItem(InvenX , InvenY , pItem); //pPrevItem->save(pPC->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d", STORAGE_EXTRASLOT); pPrevItem->tinysave(pField); //pItem->save(pPC->getName(), STORAGE_INVENTORY, 0, InvenX, InvenY); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Storage=%d, StorageID=%u, X=%d, Y=%d", STORAGE_INVENTORY, invenID, InvenX, InvenY); pItem->tinysave(pField); Success = true; } } else { // 그 장소에 아이템이 없다면. //cout << "prevItem is NULL" << endl; // Inventory에 특정 아이템을 넣는다. pInventory->addItem(InvenX , InvenY , pItem); // 넣기에 성공하면 마우스에 달려있는 아이템을 없앤다. pPC->deleteItemFromExtraInventorySlot(); //pItem->save(pPC->getName(), STORAGE_INVENTORY, 0, InvenX, InvenY); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d, StorageID=%u, X=%d, Y=%d", STORAGE_INVENTORY, invenID, InvenX, InvenY); pItem->tinysave(pField); Success = true; } if (Success) { TradeManager* pTradeManager = pZone->getTradeManager(); TradeInfo* pInfo = pTradeManager->getTradeInfo(pCreature->getName()); if (pInfo != NULL && pInfo->getStatus() == TRADE_FINISH) { GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_MOUSE_TO_INVENTORY_OK); pPlayer->sendPacket(&gcTradeVerify); } // 트리 조각일 경우 if (pItem != NULL && pItem->getItemClass() == Item::ITEM_CLASS_EVENT_TREE) { ItemType_t itemtype = pItem->getItemType(); // 크리스마스 트리 조각이면 if (itemtype <= 11) { // 크리스마스 트리 조각이 맞춰지는지 본다. TPOINT pt = checkEventPuzzle(pPC, InvenX, InvenY, 0); if (pt.x != -1 && pt.y != -1 ) { // 맞춰진 트리 조각을 지운다. deleteInventoryItem(pInventory, pt.x, pt.y, pt.x + 2, pt.y + 3); // 트리를 생성한다. list<OptionType_t> optionType; Item* pTreeItem = g_pItemFactoryManager->createItem(Item::ITEM_CLASS_EVENT_TREE, 12, optionType); pZone->getObjectRegistry().registerObject(pTreeItem); pInventory->addItem(pt.x, pt.y, pTreeItem); pTreeItem->create(pPC->getName(), STORAGE_INVENTORY, invenID, pt.x, pt.y); // 클라이언트에 트리가 만들어졌다는 걸 알린다. GCCreateItem gcCreateItem; makeGCCreateItem(&gcCreateItem, pTreeItem, pt.x, pt.y); pGamePlayer->sendPacket(&gcCreateItem); } } // 크리스마스 트리 조각이면 else if (itemtype > 12 && itemtype <= 24) { // 크리스마스 트리 조각이 맞춰지는지 본다. TPOINT pt = checkEventPuzzle(pPC, InvenX, InvenY, 13); if (pt.x != -1 && pt.y != -1) { // 맞춰진 트리 조각을 지운다. deleteInventoryItem(pInventory, pt.x, pt.y, pt.x + 2, pt.y + 3); // 트리를 생성한다. list<OptionType_t> optionType; Item* pTreeItem = g_pItemFactoryManager->createItem(Item::ITEM_CLASS_EVENT_TREE, 25, optionType); pTreeItem->setQuestItem(); pZone->getObjectRegistry().registerObject(pTreeItem); pInventory->addItem(pt.x, pt.y, pTreeItem); pTreeItem->create(pPC->getName(), STORAGE_INVENTORY, invenID, pt.x, pt.y); // 클라이언트에 트리가 만들어졌다는 걸 알린다. GCCreateItem gcCreateItem; makeGCCreateItem(&gcCreateItem, pTreeItem, pt.x, pt.y); pGamePlayer->sendPacket(&gcCreateItem); } } // 크리스마스 트리 조각이면 else if (itemtype > 28 && itemtype <= 40) { // 크리스마스 트리 조각이 맞춰지는지 본다. TPOINT pt = checkEventPuzzle(pPC, InvenX, InvenY, 29); if (pt.x != -1 && pt.y != -1) { // 맞춰진 트리 조각을 지운다. deleteInventoryItem(pInventory, pt.x, pt.y, pt.x + 2, pt.y + 3); // 트리를 생성한다. list<OptionType_t> optionType; Item* pTreeItem = g_pItemFactoryManager->createItem(Item::ITEM_CLASS_EVENT_TREE, 41, optionType); pTreeItem->setQuestItem(); pZone->getObjectRegistry().registerObject(pTreeItem); pInventory->addItem(pt.x, pt.y, pTreeItem); pTreeItem->create(pPC->getName(), STORAGE_INVENTORY, invenID, pt.x, pt.y); // 클라이언트에 트리가 만들어졌다는 걸 알린다. GCCreateItem gcCreateItem; makeGCCreateItem(&gcCreateItem, pTreeItem, pt.x, pt.y); pGamePlayer->sendPacket(&gcCreateItem); } } } } else { //cout << "cannot add" << endl; GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); } } catch (Throwable & t) {} #endif // __GAME_SERVER__ __END_DEBUG_EX __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 인벤토리 핸들러 ////////////////////////////////////////////////////////////////////////////// void BloodyTunnel::execute(Vampire* pVampire, ObjectID_t InvenObjectID, ObjectID_t InventoryItemObjectID, CoordInven_t X, CoordInven_t Y, CoordInven_t TargetX, CoordInven_t TargetY, VampireSkillSlot* pSkillSlot) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pVampire != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Inventory* pInventory = pVampire->getInventory(); Assert(pPlayer != NULL); Assert(pZone != NULL); Assert(pInventory!= NULL); // 전쟁 존이라면 BloodyTunnel를 사용할 수 없다. // 일단은 ZoneID로 가는데.. ZoneInfo에 넣도록 해야한다. ///* //if (pZone->getZoneID()==1122 || pZone->getZoneID()==1123) // 이벤트 경기장/OX 막기. by sigi. 2002.8.31 //int zoneID = pZone->getZoneID(); //if (zoneID==1005 || zoneID==1006) if (pZone->isNoPortalZone() || pZone->isMasterLair() || pZone->isCastle() || pZone->isHolyLand()) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } //*/ SubInventory* pInventoryItem = NULL; int invenID = 0; if (InventoryItemObjectID != 0 ) { //cout << "서브 인벤토리에서 사용 : " << InventoryItemObjectID << endl; CoordInven_t X, Y; pInventoryItem = dynamic_cast<SubInventory*>(pInventory->findItemOID(InventoryItemObjectID, X, Y )); TradeManager* pTradeManager = pZone->getTradeManager(); Assert(pTradeManager != NULL); if (pInventoryItem == NULL || pTradeManager->hasTradeInfo(pVampire->getName()) ) { //cout << "근데 서브 인벤토리가 없다." <<endl; executeSkillFailException(pVampire, getSkillType()); return; } pInventory = pInventoryItem->getInventory(); invenID = pInventoryItem->getItemID(); } Item* pItem = pInventory->getItem(X, Y); // 아이템이 없거나, 뱀파이어 포탈 아이템이 아니거나, OID가 틀리다면 기술 사용 불가 if (pItem == NULL || pItem->getItemClass() != Item::ITEM_CLASS_VAMPIRE_PORTAL_ITEM || pItem->getObjectID() != InvenObjectID) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } VampirePortalItem* pVampirePortalItem = dynamic_cast<VampirePortalItem*>(pItem); Assert(pVampirePortalItem != NULL); // 뱀파이어 포탈 아이템에 기록된 위치가 없을 경우에는 실패다. ZoneID_t zoneid = pVampirePortalItem->getZoneID(); ZoneCoord_t tx = pVampirePortalItem->getX(); ZoneCoord_t ty = pVampirePortalItem->getY(); if (zoneid == 0) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } // 얻어온 목표 존과 좌표를 검증한다. Zone* pTargetZone = getZoneByZoneID(zoneid); // 아담의 성지와 다른 존과는 연결되지 않는다. if (pZone->isHolyLand() != pTargetZone->isHolyLand()) { executeSkillFailException(pVampire, getSkillType()); return; } //cout << "타겟 존 포인터 획득 성공" << endl; VSRect* pRect = pTargetZone->getOuterRect(); if (!pRect->ptInRect(tx, ty)) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } //cout << "좌표 검증 성공" << endl; GCSkillToInventoryOK1 _GCSkillToInventoryOK1; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pVampire); //bool bHitRoll = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pSkillSlot); bool bHitRoll = true; if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll) { decreaseMana(pVampire, RequiredMP, _GCSkillToInventoryOK1); SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); // 각각의 존에다가 포탈을 더한다. ZONE_COORD s_coord; ZONE_COORD t_coord; s_coord.id = pZone->getZoneID(); s_coord.x = pVampire->getX(); s_coord.y = pVampire->getY(); t_coord.id = pTargetZone->getZoneID(); t_coord.x = tx; t_coord.y = ty; pZone->addVampirePortal(s_coord.x, s_coord.y, pVampire, t_coord); pTargetZone->addVampirePortal(t_coord.x, t_coord.y, pVampire, s_coord); _GCSkillToInventoryOK1.setSkillType(SkillType); _GCSkillToInventoryOK1.setObjectID(InvenObjectID); _GCSkillToInventoryOK1.setCEffectID(0); _GCSkillToInventoryOK1.setDuration(0); pPlayer->sendPacket(&_GCSkillToInventoryOK1); // 차지 수를 줄인다. pVampirePortalItem->setCharge(pVampirePortalItem->getCharge()-1); if (pVampirePortalItem->getCharge() > 0) { // 아직 차지가 남았다면 살려둔다. pVampirePortalItem->save(pVampire->getName(), STORAGE_INVENTORY, invenID, X, Y); } else { // 포탈 아이템의 차지가 다 소모되었다면 삭제시킨다. pInventory->deleteItem(X, Y); pVampirePortalItem->destroy(); // 아이템 포인터 자체가 지워지고, NULL이 되면, // 이펙트 내부에서의 아이템 포인터도 NULL이 되겠지... SAFE_DELETE(pVampirePortalItem); } pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), NULL); } } catch(Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 뱀파이어 인벤토리 핸들러 ////////////////////////////////////////////////////////////////////////////// void TransformToWolf::execute(Vampire* pVampire, ObjectID_t InvenObjectID, ObjectID_t InventoryItemObjectID, CoordInven_t X, CoordInven_t Y, CoordInven_t TargetX, CoordInven_t TargetY, VampireSkillSlot* pSkillSlot) throw(Error) { __BEGIN_TRY //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl; Assert(pVampire != NULL); Assert(pSkillSlot != NULL); try { Player* pPlayer = pVampire->getPlayer(); Zone* pZone = pVampire->getZone(); Inventory* pInventory = pVampire->getInventory(); Assert(pPlayer != NULL); Assert(pZone != NULL); Assert(pInventory!= NULL); SubInventory* pInventoryItem = NULL; int invenID = 0; if (InventoryItemObjectID != 0 ) { //cout << "서브 인벤토리에서 사용 : " << InventoryItemObjectID << endl; CoordInven_t X, Y; pInventoryItem = dynamic_cast<SubInventory*>(pInventory->findItemOID(InventoryItemObjectID, X, Y )); TradeManager* pTradeManager = pZone->getTradeManager(); Assert(pTradeManager != NULL); if (pInventoryItem == NULL || pTradeManager->hasTradeInfo(pVampire->getName()) ) { //cout << "근데 서브 인벤토리가 없다." <<endl; executeSkillFailException(pVampire, getSkillType()); return; } pInventory = pInventoryItem->getInventory(); invenID = pInventoryItem->getItemID(); } Item* pItem = pInventory->getItem(X, Y); Assert(pItem != NULL); // 적당한 아이템이 아니라면 당연히 변신할 수 없다. // PK존에서는 변신할 수 없다. if (pItem->getItemClass() != Item::ITEM_CLASS_VAMPIRE_ETC || pItem->getItemType() != 0 || pVampire->hasRelicItem() || g_pPKZoneInfoManager->isPKZone(pZone->getZoneID() ) || pVampire->isFlag(Effect::EFFECT_CLASS_REFINIUM_TICKET ) || GDRLairManager::Instance().isGDRLairZone(pZone->getZoneID()) ) { executeSkillFailException(pVampire, getSkillType()); //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; return; } GCSkillToInventoryOK1 _GCSkillToInventoryOK1; SkillType_t SkillType = pSkillSlot->getSkillType(); SkillInfo* pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType); ZoneCoord_t x = pVampire->getX(); ZoneCoord_t y = pVampire->getY(); // Knowledge of Innate 가 있다면 hit bonus 10 int HitBonus = 0; if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_INNATE ) ) { RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_INNATE); Assert(pRankBonus != NULL); HitBonus = pRankBonus->getPoint(); } int RequiredMP = decreaseConsumeMP(pVampire, pSkillInfo); bool bManaCheck = hasEnoughMana(pVampire, RequiredMP); bool bTimeCheck = verifyRunTime(pSkillSlot); bool bRangeCheck = checkZoneLevelToUseSkill(pVampire); bool bHitRoll = HitRoll::isSuccessMagic(pVampire, pSkillInfo, pSkillSlot, HitBonus); bool bMoveModeCheck = pVampire->isWalking(); bool bEffected = pVampire->isFlag(Effect::EFFECT_CLASS_TRANSFORM_TO_WOLF) || pVampire->isFlag(Effect::EFFECT_CLASS_HAS_FLAG) || pVampire->isFlag(Effect::EFFECT_CLASS_HAS_SWEEPER); if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bMoveModeCheck && !bEffected) { decreaseMana(pVampire, RequiredMP, _GCSkillToInventoryOK1); SkillInput input(pVampire); SkillOutput output; computeOutput(input, output); // 이펙트 클래스를 만들어 붙인다. EffectTransformToWolf* pEffectTTW = new EffectTransformToWolf(pVampire); pEffectTTW->setDeadline(999999999); pVampire->addEffect(pEffectTTW); pVampire->setFlag(Effect::EFFECT_CLASS_TRANSFORM_TO_WOLF); // 이로 인해서 변하는 능력치들을 보내준다. VAMPIRE_RECORD prev; pVampire->getVampireRecord(prev); pVampire->initAllStat(); pVampire->addModifyInfo(prev, _GCSkillToInventoryOK1); _GCSkillToInventoryOK1.setSkillType(SkillType); _GCSkillToInventoryOK1.setCEffectID(0); _GCSkillToInventoryOK1.setDuration(0); pPlayer->sendPacket(&_GCSkillToInventoryOK1); // 뱀파이어 대신 늑대를 더하라고 알려준다. GCAddWolf gcAddWolf; gcAddWolf.setObjectID(pVampire->getObjectID()); gcAddWolf.setName(pVampire->getName()); gcAddWolf.setXYDir(x, y, pVampire->getDir()); gcAddWolf.setItemType(pItem->getItemType()); gcAddWolf.setCurrentHP(pVampire->getHP()); gcAddWolf.setMaxHP(pVampire->getHP(ATTR_MAX)); gcAddWolf.setGuildID(pVampire->getGuildID()); pZone->broadcastPacket(x, y, &gcAddWolf, pVampire); decreaseItemNum(pItem, pInventory, pVampire->getName(), STORAGE_INVENTORY, invenID, X, Y); if (pVampire->getPetInfo() != NULL ) { pVampire->setPetInfo(NULL); sendPetInfo(dynamic_cast<GamePlayer*>(pVampire->getPlayer()), true); } pSkillSlot->setRunTime(output.Delay); } else { executeSkillFailNormal(pVampire, getSkillType(), NULL); } } catch(Throwable & t) { executeSkillFailException(pVampire, getSkillType()); } //cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl; __END_CATCH }
void CGAddInventoryToMouseHandler::execute(CGAddInventoryToMouse* pPacket , Player* pPlayer) throw(ProtocolException, Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Assert(pGamePlayer != NULL); Creature* pCreature = pGamePlayer->getCreature(); Assert(pCreature != NULL); PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pCreature); Assert(pPC != NULL); Zone* pZone = pPC->getZone(); Assert(pZone != NULL); if (pPC->getStore()->isOpen() ) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } CoordInven_t InvenX = pPacket->getX(); CoordInven_t InvenY = pPacket->getY(); ObjectID_t ItemOID = pPacket->getObjectID(); Inventory* pInventory = pPC->getInventory(); Assert(pInventory != NULL); int invenID = 0; /* Commenting the SubInventory stuff, since it's not supported by the client we use SubInventory* pInventoryItem = NULL; int invenID = 0; if (pPacket->getInventoryItemObjectID() != 0 ) { CoordInven_t X, Y; pInventoryItem = dynamic_cast<SubInventory*>(pInventory->findItemOID(pPacket->getInventoryItemObjectID(), X, Y )); if (pInventoryItem == NULL ) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } pInventory = pInventoryItem->getInventory(); invenID = pInventoryItem->getItemID(); } */ // 인벤토리 좌표를 넘어가면 곤란하다... if (InvenX >= pInventory->getWidth() || InvenY >= pInventory->getHeight()) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } Item* pItem = pInventory->getItem(InvenX, InvenY); Item* pExtraSlotItem = pPC->getExtraInventorySlotItem(); if (pPC->getStore()->hasItem(pItem ) ) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } // 더하고자 하는 아이템이 없거나, 이미 마우스에 뭔가가 붙어있다면 // 들 수 없다. if (pItem == NULL || pExtraSlotItem != NULL) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } // 일반적인 아이템 마우스 더하기 루틴 if (ItemOID != 0) { // OID가 일치하지 않으면 곤란하다... if (pItem->getObjectID() != ItemOID) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } pInventory->deleteItem(pItem->getObjectID()); pPC->addItemToExtraInventorySlot(pItem); //pItem->save(pPC->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d, StorageID=0", STORAGE_EXTRASLOT); pItem->tinysave(pField); TradeManager* pTradeManager = pZone->getTradeManager(); TradeInfo* pInfo = pTradeManager->getTradeInfo(pCreature->getName()); if (pInfo != NULL && pInfo->getStatus() == TRADE_FINISH) { GCTradeVerify gcTradeVerify; gcTradeVerify.setCode(GC_TRADE_VERIFY_CODE_INVENTORY_TO_MOUSE_OK); pPlayer->sendPacket(&gcTradeVerify); } } // 겹치는 아이템 분리하기 루틴 else { // 겹치는 아이템이 아니거나, 현재 숫자가 2 미만이라면 분리할 수 없다. if (!isStackable(pItem) || pItem->getNum() < 2 || (pItem->getItemClass() == Item::ITEM_CLASS_MOON_CARD && pItem->getItemType() == 2 && pItem->getNum() == 99) || pPC->getStore()->hasItem(pItem) ) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } // 기존의 아이템을 바탕으로 같은 아이템을 생성한다. Item::ItemClass IClass = pItem->getItemClass(); ItemType_t IType = pItem->getItemType(); const list<OptionType_t>& OType = pItem->getOptionTypeList(); Item* pNewItem = g_pItemFactoryManager->createItem(IClass, IType, OType); Assert(pNewItem != NULL); // 마우스에다 더할 아이템은 기존의 OID를 가져가고, // 인벤토리에 남을 아이템은 새로운 OID를 받아야 한다. Zone* pZone = pPC->getZone(); Assert(pZone != NULL); ObjectRegistry& OR = pZone->getObjectRegistry(); OR.registerObject(pNewItem); // 인벤토리에 남아있는 아이템의 숫자는 원래 숫자에서 1을 뺀 숫자가 된다. // 기존의 아이템은 마우스로 옮겨졌으므로, 숫자가 1이 된다. // 인벤토리에서 마우스로 옮겨진 아이템을 삭제하고, // 새로 생성된 아이템을 더한다. pInventory->deleteItem(pItem->getObjectID()); pPC->addItemToExtraInventorySlot(pItem); int NewNum = pItem->getNum() - 1; pNewItem->setNum(NewNum); pItem->setNum(1); pInventory->addItem(InvenX, InvenY, pNewItem); // 달라진 위치 정보를 세이브한다... //pItem->save(pPC->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=0", 1, STORAGE_EXTRASLOT); pItem->tinysave(pField); pNewItem->create(pPC->getName(), STORAGE_INVENTORY, invenID, InvenX, InvenY); //pNewItem->setNum(NewNum); // 위에서 했는데 또 하네. -_-; //pNewItem->save(pPC->getName(), STORAGE_INVENTORY, 0, InvenX, InvenY); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Num=%d, Storage=%d, StorageID=%u", NewNum, STORAGE_INVENTORY, invenID); pNewItem->tinysave(pField); // 클라이언트에게는 GCCreateItem 패킷을 이용해 // 인벤토리에 새로이(?) 생성된 아이템에 대한 정보를 보내준다. GCCreateItem gcCreateItem; gcCreateItem.setObjectID(pNewItem->getObjectID()); gcCreateItem.setItemClass((BYTE)pNewItem->getItemClass()); gcCreateItem.setItemType(pNewItem->getItemType()); gcCreateItem.setOptionType(pNewItem->getOptionTypeList()); gcCreateItem.setDurability(pNewItem->getDurability()); gcCreateItem.setSilver(pNewItem->getSilver()); gcCreateItem.setEnchantLevel(pNewItem->getEnchantLevel()); gcCreateItem.setItemNum(pNewItem->getNum()); gcCreateItem.setInvenX(InvenX); gcCreateItem.setInvenY(InvenY); pPlayer->sendPacket(&gcCreateItem); } #endif // __GAME_SERVER__ __END_DEBUG_EX __END_CATCH }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// void Restore::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* 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) { dropRelicToZone(pFromCreature); dropFlagToZone(pFromCreature); ////////////////////////////////////////////////////////////////////// // 각종 존 레벨 정보를 삭제해야 한다. ////////////////////////////////////////////////////////////////////// // 파티 초대 중이라면 정보를 삭제해 준다. 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); // load하면 load한 zone에서 objectID를 받으므로 다시 설정한다. by sigi. 2002.6.4 pNewSlayer->load(); pNewSlayer->setZone(pZone); pNewSlayer->setObjectID(pFromCreature->getObjectID()); //pZone->getObjectRegistry().registerObject(pNewSlayer); 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 ) { Guild* pGuild = g_pGuildManager->getGuild(pVampire->getGuildID()); if (pGuild != NULL ) { pGuild->deleteCurrentMember(pVampire->getName()); GSGuildMemberLogOn gsGuildMemberLogOn; gsGuildMemberLogOn.setGuildID(pGuild->getID()); gsGuildMemberLogOn.setName(pVampire->getName()); gsGuildMemberLogOn.setLogOn(false); g_pSharedServerManager->sendPacket(&gsGuildMemberLogOn); Statement* pStmt = NULL; // 디비에 업데이트 한다. BEGIN_DB { pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement(); pStmt->executeQuery("UPDATE GuildMember SET LogOn = 0 WHERE Name = '%s'", pVampire->getName().c_str()); } END_DB(pStmt) } else filelog("GuildMissing.log", "[NoSuchGuild] GuildID : %d, Name : %s\n", (int)pVampire->getGuildID(), pVampire->getName().c_str()); }
////////////////////////////////////////////////////////////////////////////// // 슬레이어 오브젝트 핸들러 ////////////////////////////////////////////////////////////////////////////// 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 EventMorph::activate () throw(Error) { __BEGIN_TRY __BEGIN_DEBUG Assert(m_pGamePlayer != NULL); Creature* pFromCreature = m_pGamePlayer->getCreature(); Assert(pFromCreature->isSlayer()); if (m_pGamePlayer->getPlayerStatus() != GPS_NORMAL) { // 플레이어의 상태가 WAITING_FOR_CG_READY인데, morph가 // activate되어 밑의 존에서 크리쳐를 지우는 부분에서 에러가 throw되어 // 서버가 죽는 버그가 있었다. 정확히 어떻게 해서 CG_READY상태에서 // 이벤트가 activate되는지는 모르겠으나, GamePlayer의 // EventManager 자체를 GPS_NORMAL일 때만 돌아가게 하면, // Resurrect가 되지 않으니 주의하길 바란다. 결국 GamePlayer 내부에서 // 체크를 하기가 곤란하기 때문에 이 부분에서, 처리한다. StringStream msg; msg << "EventMorph::activate() : GamePlayer의 상태가 GPS_NORMAL이 아닙니다." << "PlayerID[" << m_pGamePlayer->getID() << "]" << "CreatureName[" << pFromCreature->getName() << "]"; filelog("EventMorphError.log", "%s", msg.toString().c_str()); return; } pFromCreature->removeFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN); Zone* pZone = pFromCreature->getZone(); // 만일 Restore 이펙트가 걸려있다면 변신이 되지 않는다. if (pFromCreature->isFlag(Effect::EFFECT_CLASS_RESTORE)) { return; } dropRelicToZone(pFromCreature); dropFlagToZone(pFromCreature); dropSweeperToZone(pFromCreature); ////////////////////////////////////////////////////////////////////// // 각종 존 레벨 정보를 삭제해야 한다. ////////////////////////////////////////////////////////////////////// // 파티 초대 중이라면 정보를 삭제해 준다. PartyInviteInfoManager* pPIIM = pZone->getPartyInviteInfoManager(); Assert(pPIIM != NULL); pPIIM->cancelInvite(pFromCreature); // 파티 관련 정보를 삭제해 준다. uint 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); ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// Vampire* pVampire = new Vampire(); GCMorph1 gcEventMorph1; // 변신 당사자에게.. GCMorphVampire2 gcEventMorphVampire2; // 변신 구경꾼들에게.. pVampire->setName(pFromCreature->getName()); ObjectID_t fromObjectID = pFromCreature->getObjectID(); pVampire->setObjectID(fromObjectID); Player* pPlayer = pFromCreature->getPlayer(); dynamic_cast<GamePlayer*>(pPlayer)->setCreature(pVampire); pVampire->setPlayer(pPlayer); pVampire->setZone(pZone); pVampire->load(); Coord_t x = pFromCreature->getX(), y = pFromCreature->getY(); Dir_t dir = pFromCreature->getDir(); pVampire->setXYDir(x, y, dir); pVampire->setMoveMode(pFromCreature->getMoveMode()); // slayer to vampire Slayer* pSlayer = dynamic_cast<Slayer*>(pFromCreature); // 뱀파이어로 변신할때 Creature Pointer가 달라지므로... // 원래 등록 되어있던 포인터는 개가 된다... // 따라서 새로운 Creature Pointer를 등록해줘야 한다. g_pPCFinder->deleteCreature(pFromCreature->getName()); g_pPCFinder->addCreature(pVampire); // 길드 현재 접속 리스트에서 삭제한다. if (pSlayer->getGuildID() != 99 ) { Guild* pGuild = g_pGuildManager->getGuild(pSlayer->getGuildID()); if (pGuild != NULL ) { pGuild->deleteCurrentMember(pSlayer->getName()); GSGuildMemberLogOn gsGuildMemberLogOn; gsGuildMemberLogOn.setGuildID(pGuild->getID()); gsGuildMemberLogOn.setName(pSlayer->getName()); gsGuildMemberLogOn.setLogOn(false); g_pSharedServerManager->sendPacket(&gsGuildMemberLogOn); Statement* pStmt = NULL; // 디비에 업데이트 한다. BEGIN_DB { pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement(); pStmt->executeQuery("UPDATE GuildMember SET LogOn = 0 WHERE Name = '%s'", pSlayer->getName().c_str()); } END_DB(pStmt) }