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

}
Beispiel #5
0
//////////////////////////////////////////////////////////////////////////////
// 뱀파이어 인벤토리 핸들러
//////////////////////////////////////////////////////////////////////////////
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
}
Beispiel #6
0
//////////////////////////////////////////////////////////////////////////////
// 뱀파이어 인벤토리 핸들러
//////////////////////////////////////////////////////////////////////////////
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

}
Beispiel #8
0
//////////////////////////////////////////////////////////////////////////////
// 슬레이어 오브젝트 핸들러
//////////////////////////////////////////////////////////////////////////////
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());
			}
Beispiel #9
0
//////////////////////////////////////////////////////////////////////////////
// 슬레이어 오브젝트 핸들러
//////////////////////////////////////////////////////////////////////////////
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);
		}
	} 
Beispiel #10
0
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)
		}