Beispiel #1
0
void ZoneGroupManager::outputLoadValue()
	throw(Error)
{
	//------------------------------------------------------------------
	// ZoneGroup load
	//------------------------------------------------------------------
	ofstream file("loadBalance.txt", ios::app);

	VSDateTime current = VSDateTime::currentDateTime();
	file << current.toString() << endl;

	map< ZoneGroupID_t , ZoneGroup* >::const_iterator itr;

	for (itr = m_ZoneGroups.begin() ; itr != m_ZoneGroups.end() ; itr ++) 
	{
		ZoneGroup* pZoneGroup = itr->second;
		file << "[" << (int)pZoneGroup->getZoneGroupID() << "] ";

		const map< ZoneID_t, Zone* >& zones = pZoneGroup->getZones();
		map< ZoneID_t, Zone* >::const_iterator iZone;

		// 각 Zone의 loadValue를 구한다.
		int totalLoad = 0;
		for (iZone=zones.begin(); iZone!=zones.end(); iZone++)
		{
			Zone* pZone = iZone->second;

			int load = pZone->getLoadValue();
			int playerLoad = pZone->getPCCount();

			file << (int)pZone->getZoneID() << "(" << load << ", " << playerLoad << ") ";

			totalLoad += load;
		}

		file << " = " << totalLoad << endl;

	}

	file << endl;
	file.close();
}
Beispiel #2
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 #3
0
//////////////////////////////////////////////////////////////////////////////
// 몬스터 셀프 핸들러
//////////////////////////////////////////////////////////////////////////////
void SummonMonsters::execute(Monster* pMonster)
	throw(Error)
{
	__BEGIN_TRY

	//cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " Begin" << endl;

	//cout << "SummonMonsters" << endl;

	Assert(pMonster != NULL);
	Zone* pZone = pMonster->getZone();
	Assert(pZone != NULL);


	try 
	{
		if (pMonster->isFlag(Effect::EFFECT_CLASS_HIDE))
		{
			//cout << "SummonMonsters: hide" << endl;
			return;
		}
		if (pMonster->isFlag(Effect::EFFECT_CLASS_INVISIBILITY))
		{
			addVisibleCreature(pZone, pMonster, true);
		}

		//GCSkillToSelfOK2 _GCSkillToSelfOK2;

		ZoneCoord_t x = pMonster->getX();
		ZoneCoord_t y = pMonster->getY();

		bool bRangeCheck    = checkZoneLevelToUseSkill(pMonster);
		//bool bMoveModeCheck = pMonster->isWalking();

		if (bRangeCheck)// && bMoveModeCheck)
		{
			//--------------------------------------------------------
			// 주위에 knockback되는맞는 애들을 체크해준다.
			//--------------------------------------------------------
			//SkillInput input(pMonster);
			//SkillOutput output;
			//computeOutput(input, output);

			SUMMON_INFO2 summonInfo;

			bool hasInfo = pMonster->getMonsterSummonInfo(summonInfo);

			if (!hasInfo || summonInfo.pMonsters==NULL)
			{
				//cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End" << endl;
				// 소환할 몹이 없는 경우다. -_-;
				executeSkillFailNormal(pMonster, getSkillType(), NULL);

				// 마스터 레어에서 마스터가 몹을 소환할려고 한 경우
				if (pZone->isMasterLair() && pMonster->isMaster())
				{
					MasterLairManager* pMasterLairManager = pZone->getMasterLairManager();
					Assert(pMasterLairManager!=NULL);

					// 더 이상 소환할게 없다면..
					// 마스터가 직접 나서서 싸워야겠지..
					pMasterLairManager->setMasterReady();
					//cout << "no more SummonMonsters: set MasterReady" << endl;
				}
			}

			if (pMonster->isMaster() && pZone->isMasterLair())
			{
				MasterLairManager* pMasterLairManager = pZone->getMasterLairManager();
				Assert(pMasterLairManager!=NULL);
				// minion combat에서는 지정된 좌표에 소환한다.

				MasterLairInfo* pInfo = g_pMasterLairInfoManager->getMasterLairInfo(pZone->getZoneID());
				Assert(pInfo!=NULL);

				if (!pMasterLairManager->isMasterReady())
				{
					x = pInfo->getSummonX();
					y = pInfo->getSummonY();

					GCSay gcSay;
					gcSay.setObjectID(pMonster->getObjectID());
					gcSay.setColor(MASTER_SAY_COLOR);
					gcSay.setMessage(pInfo->getRandomMasterSummonSay());
					if (!gcSay.getMessage().empty())
						pZone->broadcastPacket(pMonster->getX(), pMonster->getY(), &gcSay);
				}

				// 마스터 레어에서는 소환된 몬스터들이 아템 안 준다.
				// by sigi. 2002.11.21
				summonInfo.hasItem = false;
			}

			summonInfo.scanEnemy = true;
			summonInfo.clanType = SUMMON_INFO::CLAN_TYPE_GROUP;
			summonInfo.clanID = pMonster->getClanType(); // 주인의 clan을 따른다.
			summonInfo.X = x;
			summonInfo.Y = y;
			summonInfo.regenType = REGENTYPE_PORTAL;

			// 몬스터를 존에 추가한다.
			addMonstersToZone(pZone, summonInfo);

			//cout << "SummonMonsters OK" << endl;
			GCSkillToTileOK5 _GCSkillToTileOK5;

			_GCSkillToTileOK5.setObjectID(pMonster->getObjectID());
			_GCSkillToTileOK5.setSkillType(getSkillType());
			_GCSkillToTileOK5.setX(x);
			_GCSkillToTileOK5.setY(y);
			_GCSkillToTileOK5.setDuration( 0);

			pZone->broadcastPacket(x, y,  &_GCSkillToTileOK5);
		}
		else 
		{
			executeSkillFailNormal(pMonster, getSkillType(), NULL);
		}
	} 
	catch(Throwable & t) 
	{
		executeSkillFailException(pMonster, getSkillType());
	}

	__END_CATCH

}
Beispiel #4
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
}
Item* CastleShrineInfoManager::addShrineToZone(ShrineInfo& shrineInfo, ItemType_t itemType )
	throw(Error)
{
	__BEGIN_TRY

	// 성단을 넣을 존을 가져온다.
	Zone* pZone = getZoneByZoneID(shrineInfo.getZoneID());
	Assert(pZone != NULL);

	MonsterCorpse* pShrine = new MonsterCorpse(shrineInfo.getMonsterType(), shrineInfo.getName(), 2);
	Assert(pShrine != NULL);

	pShrine->setShrine(true);
	pShrine->setZone(pZone);

	pZone->getObjectRegistry().registerObject(pShrine);
	shrineInfo.setObjectID(pShrine->getObjectID());

	Item* pItem =  NULL;

/*	if (shrineInfo.getShrineType() == ShrineInfo::SHRINE_GUARD )
	{
		pShrine->setFlag(Effect::EFFECT_CLASS_SHRINE_GUARD);

		EffectShrineGuard* pEffect = new EffectShrineGuard(pShrine);
		pEffect->setShrineID(itemType);
		pEffect->setTick(60 * 10);

		pShrine->getEffectManager().addEffect(pEffect);
	}
	else if (shrineInfo.getShrineType() == ShrineInfo::SHRINE_HOLY )
	{
		pShrine->setFlag(Effect::EFFECT_CLASS_SHRINE_HOLY);

		EffectShrineHoly* pEffect = new EffectShrineHoly(pShrine);
		pEffect->setShrineID(itemType);
		pEffect->setTick(60 * 10);

		pShrine->getEffectManager().addEffect(pEffect);
	}*/

	TPOINT tp = pZone->addItem(pShrine, shrineInfo.getX(), shrineInfo.getY(), true);
	Assert(tp.x != -1);

	// 성의 상징을 추가할 필요가 있다면 추가한다.
	if (shrineInfo.getShrineType() == ShrineInfo::SHRINE_GUARD )
	{
		//if (AddBible[ itemType ] )
		{
			list<OptionType_t> optionNULL;
			pItem = g_pItemFactoryManager->createItem(Item::ITEM_CLASS_CASTLE_SYMBOL, itemType, optionNULL);
			Assert(pItem != NULL);

			char strZoneID[10];
			sprintf(strZoneID, "%d", (int)pZone->getZoneID());

			pZone->registerObject(pItem);
			pItem->create(strZoneID, STORAGE_CORPSE, pShrine->getObjectID(), 0, 0);

			pShrine->addTreasure(pItem);
		}

		// 수호성단이라는걸 표시해둔다.
		pShrine->setFlag(Effect::EFFECT_CLASS_CASTLE_SHRINE_GUARD);

		// 모든 수호성단에 Shield Effect 붙인다
		pShrine->setFlag(Effect::EFFECT_CLASS_SHRINE_SHIELD);

		EffectShrineShield* pEffect = new EffectShrineShield(pShrine);
		pEffect->setShrineID(itemType);
		pEffect->setTick(60 * 10);

		pShrine->getEffectManager().addEffect(pEffect);
	}
	else
	{
		// 성지성단이라는걸 표시해둔다.
		pShrine->setFlag(Effect::EFFECT_CLASS_CASTLE_SHRINE_HOLY);
	}

	// 성단 좌표를 새로 세팅한다.
	shrineInfo.setX(tp.x);
	shrineInfo.setY(tp.y);

	return pItem;

	__END_CATCH
}
Beispiel #6
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);
		}
	} 
void CGUseMessageItemFromInventoryHandler::executeEventTree(CGUseMessageItemFromInventory* pPacket, Player* pPlayer)
	throw(ProtocolException, Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __GAME_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	// 상위 함수에서 에러 체크를 많이 했기 때문에,
	// 에러 체크를 대폭 축소한다.
	GamePlayer*     pGamePlayer  = dynamic_cast<GamePlayer*>(pPlayer);
	Creature*       pCreature    = pGamePlayer->getCreature();
	PlayerCreature* pPC          = dynamic_cast<PlayerCreature*>(pCreature);
	Inventory*      pInventory   = pPC->getInventory();
	Zone*           pZone        = pPC->getZone();
	CoordInven_t    InvenX       = pPacket->getX();
	CoordInven_t    InvenY       = pPacket->getY();
	Item*           pItem        = pInventory->getItem(InvenX, InvenY);
	ObjectID_t      ItemObjectID = pItem->getObjectID();
	MonsterType_t	MType		 = 0;

	int				time		 = 0;

	switch (pItem->getItemType() )
	{
		case 12:
			MType = 482;
			time = g_pVariableManager->getVariable(CHRISTMAS_TREE_DECAY_TIME ) / 10;
			break;
		case 26:
			MType = 650;
			time = 21600;
			break;
		case 27:
			MType = 650;
			time = 43200;
			break;
		case 28:
			MType = 650;
			time = 86400;
			break;
		default:
			{
				filelog("EventTree.log", "이상한 아템을 썼다. : %s 가 %d", pPC->getName().c_str(), pItem->getItemType());
				GCCannotUse _GCCannotUse;
				_GCCannotUse.setObjectID(pPacket->getObjectID());
				pGamePlayer->sendPacket(&_GCCannotUse);
			}
			return;
	}

	// 타일에 스킬을 쓰는 것이라고 보고 쓸 수 있는지를 체크한다.
	// 안전지대에서는 사용할 수 없다.
	// 쓸 수 있는 아이템 타입인지 왁인한다. ItemType 이 12인 것만 사용할 수 있다.
	// 근처에(플레이어 주위의 5x5타일 이내) 다른 트리가 있다면 사용할 수 없다.
	if (!isAbleToUseTileSkill(pCreature )
		|| pZone->isMasterLair()
		|| ItemObjectID != pPacket->getObjectID()
		|| checkCorpse(pZone, MType, pPC->getX() - 2, pPC->getY() - 2, pPC->getX() + 2, pPC->getY() + 2 )
		)
	{
		GCCannotUse _GCCannotUse;
		_GCCannotUse.setObjectID(pPacket->getObjectID());
		pGamePlayer->sendPacket(&_GCCannotUse);
		return;
	}

	// 성이면 성주 길드원만 쓸 수 있다.
	if (!pPC->isGOD() )
	{
		if (pZone->isCastle() )
		{
			if (!g_pCastleInfoManager->isCastleMember(pZone->getZoneID(), pPC ) )
			{
				GCCannotUse _GCCannotUse;
				_GCCannotUse.setObjectID(pPacket->getObjectID());
				pGamePlayer->sendPacket(&_GCCannotUse);
				return;
			}
		}
		// 성이 아닌 곳의 안전지대에선 절대 못 쓴다.
		else if (pZone->getZoneLevel(pCreature->getX(), pCreature->getY()) & SAFE_ZONE)
		{
			GCCannotUse _GCCannotUse;
			_GCCannotUse.setObjectID(pPacket->getObjectID());
			pGamePlayer->sendPacket(&_GCCannotUse);
			return;
		}
	}

/*	// 트리를 존에 추가한다. (트리는 몬스터 시체를 이용한다)
    MonsterCorpse* pMonsterCorpse = new MonsterCorpse(482, pPacket->getMessage(), 2); 
    Assert(pMonsterCorpse!=NULL); 
 
    pZone->getObjectRegistry().registerObject(pMonsterCorpse); 
 
    // 생성된 시체를 존에 추가한다. 
	int delayTime = g_pVariableManager->getVariable(CHRISTMAS_TREE_DECAY_TIME); // by sigi. 2002.12.17
	TPOINT pt = pZone->addItem(pMonsterCorpse, pPC->getX(), pPC->getY(), true, delayTime);	// 6시간 뒤에 트리(시체)가 사라진다.
	if (pt.x == -1)*/
	if (!createBulletinBoard(pZone, pPC->getX(), pPC->getY(), MType, pPacket->getMessage(), 
				VSDateTime::currentDateTime().addSecs(time ) ) )
	{
		GCCannotUse _GCCannotUse;
		_GCCannotUse.setObjectID(pPacket->getObjectID());
		pGamePlayer->sendPacket(&_GCCannotUse);

		return;
	}

	// 사용한 아이템이므로 지워준다.
	pInventory->deleteItem(InvenX, InvenY);
	pItem->destroy();
	SAFE_DELETE(pItem);

	// 아이템을 사용했다고 클라이언트에 알린다.
	GCUseOK gcUseOK;
	pGamePlayer->sendPacket(&gcUseOK);

	//pZone->broadcastPacket(pCreature->getX(), pCreature->getY(), &gcAddEffectToTile);

#endif
    __END_DEBUG_EX __END_CATCH
}
Beispiel #8
0
//---------------------------------------------------------------------------
// make Balanced LoadInfo
//---------------------------------------------------------------------------
//
// bForce : balacing할 필요가 없다고 판단되는 경우에도 
//          강제로 ZoneGroup을 balancing할 경우에 사용된다.
//
// Zone마다의 10초간의 loop 처리 회수를 load값으로 한다.
// 계산에 편의를 위해서 실제 load는 다음과 같의 정의한다.
//
//     load = (loadLimit - load)*loadMultiplier;
//
//---------------------------------------------------------------------------
bool 	ZoneGroupManager::makeBalancedLoadInfo(LOAD_INFOS& loadInfos, bool bForce)
	throw(Error)
{
	const int maxGroup  		= m_ZoneGroups.size();	// zoneGroup 수
	//const int loadMultiplier 	= 5;					// load 가중치 - 느린 애들을 더 느리다...라고 하기 위한 것.
	const int loadLimit 		= 500;					// load 값 제한 - sleep에 의해서 제한돼서 루프 처리회수 500이 최고다.
	const int stableLoad 		= 120;					// 안정적인 load - 이 정도면 balancing이 필요없다고 생각되는 수준
	//const int minLoadGap 		= 20 * loadMultiplier;	// load balancing을 하기 위한 load 차이 - 최고~최저의 차이가 일정 값 이상이어야지 balancing이 의미있다.
	const int minLoadGap 		= 20;	// load balancing을 하기 위한 load 차이 - 최고~최저의 차이가 일정 값 이상이어야지 balancing이 의미있다.
	const int averageLoadPercent = 90;					// 한 group의 load % 제한. 100으로 해도 되겠지만 90정도가 괜찮은거 같다.

	int i;

	//LOAD_INFOS 	loadInfos;
	GROUPS		groups;

	map< ZoneGroupID_t , ZoneGroup* >::const_iterator itr;

	// 전체 load
	int totalLoad = 0;


	//------------------------------------------------------------------
	// ZoneGroup마다 loadValue 조사 
	//------------------------------------------------------------------
	int maxLoadValue = 0;
	int minLoadValue = loadLimit;
	for (itr = m_ZoneGroups.begin() ; itr != m_ZoneGroups.end() ; itr ++) 
	{
		ZoneGroup* pZoneGroup = itr->second;

		const map< ZoneID_t, Zone* >& zones = pZoneGroup->getZones();
		map< ZoneID_t, Zone* >::const_iterator iZone;

		// 각 Zone의 loadValue를 구한다.
		for (iZone=zones.begin(); iZone!=zones.end(); iZone++)
		{
			Zone* pZone = iZone->second;

			int load = pZone->getLoadValue();
			load = min(load, loadLimit);

			// 10~500
			maxLoadValue = max(maxLoadValue, load);
			minLoadValue = min(minLoadValue, load);

			// 숫자 적은게 느린 거다.
			// 계산의 편의를 위해서 숫자를 뒤집?는다. --> 큰 숫자 부하가 큰 걸로 바꾼다.
			// player숫자를 부하가중치로 사용한다.
			// playerLoad = 1 ~ 20정도?
			int playerLoad = pZone->getPCCount()/10;
			playerLoad = max(1, playerLoad);
			//load = (loadLimit - load)*loadMultiplier;	// 부하 가중치
			load = (loadLimit - load)*playerLoad;	// 부하 가중치

			LoadInfo* pInfo = new LoadInfo;
			pInfo->id 			= pZone->getZoneID();
			pInfo->oldGroupID 	= itr->first;
			pInfo->groupID 		= -1;
			pInfo->load 		= load;

			// 부하와 zoneID로 이루어진 key
			DWORD key = (load << 8) | pInfo->id;

			loadInfos[key] = pInfo;

			totalLoad += load;
		}
	}

	//------------------------------------------------------------------
	//
	// balancing이 필요한지 확인
	//
	//------------------------------------------------------------------
	if (!bForce)
	{
		int loadBoundary = stableLoad;
		//int loadBoundary = (loadLimit - stableLoad ) * loadMultiplier;

		// 부하 한계 수치보다 작거나
		// min~max 부하 수치 차이가 일정수치 이하이면
		// load balancing할 필요가 없다.
		//if (maxLoad <= loadBoundary
		if (minLoadValue >= loadBoundary
			|| maxLoadValue-minLoadValue <= minLoadGap)
		{

			// load를 다시 조사해야 한다.
			for (itr = m_ZoneGroups.begin() ; itr != m_ZoneGroups.end() ; itr ++) 
			{
				ZoneGroup* pZoneGroup = itr->second;

				// loadValue를 초기화 시켜준다.
				const map< ZoneID_t, Zone* >& zones = pZoneGroup->getZones();
				map< ZoneID_t, Zone* >::const_iterator iZone;

				// 각 Zone의 loadValue를 구한다.
				for (iZone=zones.begin(); iZone!=zones.end(); iZone++)
				{
					Zone* pZone = iZone->second;

					pZone->initLoadValue();
				}
			}

			return false;
		}
	}

	// 평균 load
	//int avgLoad = totalLoad / maxGroups;
	// average를 90%로 잡은 경우
	int avgLoad = totalLoad * averageLoadPercent / maxGroup / 100;

	// 새로운 그룹의 load를 계산하기 위해서
	groups.reserve(maxGroup);
	for (i=0; i<maxGroup; i++)
	{
		groups[i] = 0;
	}

	// balancing하기 전의 상태 출력
	//outputLoadValue();

	//------------------------------------------------------------------
	//
	// load balancing
	//
	// 약간의 변화를 준? FirstFit 사용.
	//------------------------------------------------------------------
	LOAD_INFOS::const_iterator iInfo = loadInfos.begin();

	int index = 0;

	for (; iInfo!=loadInfos.end(); iInfo++)
	{
		LoadInfo* pInfo = iInfo->second;

		// 들어갈 새 group을 찾는다.
		int newGroupID = -1;
		for (int k=0; k<maxGroup; k++)
		{
			int groupLoad = groups[index];

			if (groupLoad+pInfo->load <= avgLoad)
			{
				newGroupID = index;	

				if (++index>=maxGroup) index = 0;

				break;
			}

			if (++index>=maxGroup) index = 0;
		}

		// 적절한 group을 못 찾았으면 젤 값이 적은 group에 넣는다.
		if (newGroupID==-1)
		{
			newGroupID = 0;
			for (int k=1; k<maxGroup; k++)
			{
				if (groups[k] < groups[newGroupID])
				{
					newGroupID = k;
				}
			}
		}

		// newGroupID에다가 Info를 추가한다.
		pInfo->groupID = newGroupID + 1;		// 1을 증가시켜줘야 한다. -_-;
		groups[newGroupID] += pInfo->load;
	}

	return true;
}