Beispiel #1
0
bool BloodDrain::executeMonster(Monster* pMonster, Creature* pEnemy)
	throw(Error)
{
	__BEGIN_TRY

	bool isMaster    = pMonster->isMaster()
#ifdef __UNDERWORLD__
	|| pMonster->isUnderworld() || pMonster->getMonsterType() == 599
#endif
	;

	// 죽었으면 흡혈 못하고..
	// 마스터는 아무나 다 빤다 - -;
	// 대상이 죽었으면 못 빤다.
	if (pMonster->isDead()
		|| pMonster->isFlag(Effect::EFFECT_CLASS_COMA)
		|| !pMonster->isEnemyToAttack(pEnemy) && !isMaster
		|| pEnemy->isDead() || pEnemy->isFlag(Effect::EFFECT_CLASS_COMA))
	{
		return false;
	}

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

	GCBloodDrainOK1 _GCBloodDrainOK1;
	GCBloodDrainOK2 _GCBloodDrainOK2;
	GCBloodDrainOK3 _GCBloodDrainOK3;

	// 마스터는 체력 100% 라도 문다.
	int HPMultiplier = (isMaster? 1 : 3);	// 현재 HP가 1/1,  1/3
	bool bHitRoll    = HitRoll::isSuccessBloodDrain(pMonster, pEnemy, HPMultiplier);
	bool bCanHit     = canHit(pMonster, pEnemy, SKILL_BLOOD_DRAIN);
	// 마스터는 거리에 관계없이 문다~
	bool bRangeCheck = isMaster || verifyDistance(pMonster, pEnemy, 1);

	// 흡혈 면역 상태. by sigi. 2002.9.13
	bool bEffected = pEnemy->isFlag(Effect::EFFECT_CLASS_IMMUNE_TO_BLOOD_DRAIN);

	if (bHitRoll && bCanHit && bRangeCheck && !bEffected)
	{
		if (pEnemy->isSlayer())
		{
			// Set EffectBloodDrain
			// 마스터면 안건다.
			if (!isMaster)
			{
				EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pEnemy);
				pEffectBloodDrain->setLevel(pMonster->getLevel());
				pEffectBloodDrain->setDeadline(BLOODDRAIN_DURATION);	// 게임시간으로 3일 정도
				pEnemy->addEffect(pEffectBloodDrain);
				pEffectBloodDrain->create(pEnemy->getName());
				_GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN);

				pEnemy->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN);

				Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pEnemy);
				SLAYER_RECORD prev;
				pTargetSlayer->getSlayerRecord(prev);
				pTargetSlayer->initAllStat();
				pTargetSlayer->sendRealWearingInfo();
				pTargetSlayer->addModifyInfo(prev, _GCBloodDrainOK2);
			}

			// 로그를 남긴다.
			//log(LOG_BLOODDRAINED, pEnemy->getName(), "게임 내의 몬스터");
		}
		// 아우스터즈의 경우엔..... -_-; 제한시간 없는 이펙트를 생성한다. 엄밀히 말해 제한시간이 없는 건 아니지만..
//		else if (pEnemy->isOusters() && !isMaster )
//		{
//			EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pEnemy);
//			pEffectBloodDrain->setLevel(pMonster->getLevel());
//			pEnemy->addEffect(pEffectBloodDrain);
//			pEffectBloodDrain->create(pEnemy->getName());
//			_GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN);
//
//			pEnemy->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN);
//
//			Sight_t oldSight = pEnemy->getSight();
//			Sight_t newSight = pEnemy->getEffectedSight();
//
//			if (oldSight != newSight )
//			{
//				pEnemy->setSight(newSight);
//				pZone->updateScan(pEnemy, oldSight, pEnemy->getSight());
//				_GCBloodDrainOK2.addShortData(MODIFY_VISION, pEnemy->getSight());
//
//				GCChangeDarkLight gcChangeDarkLight;
//				gcChangeDarkLight.setDarkLevel(15);
//				gcChangeDarkLight.setLightLevel(newSight);
//				pEnemy->getPlayer()->sendPacket(&gcChangeDarkLight);
//			}
//		}


		_GCBloodDrainOK3.setObjectID(pMonster->getObjectID());
		_GCBloodDrainOK3.setTargetObjectID (pEnemy->getObjectID());

		// 타겟이 뭐든 플래그는 건다.
		// 마스터면 안건다.
		if (!isMaster)
		{
			pEnemy->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN);
		}

		if (pEnemy != NULL && pEnemy->isPC()) 
		{
			Player* pTargetPlayer = pEnemy->getPlayer();
			if (pTargetPlayer != NULL) 
			{ 
				_GCBloodDrainOK2.setObjectID(pMonster->getObjectID());
	
				if (!isMaster)
				{
					// _GCBloodDrainOK2.addLongData(MODIFY_DURATION, BLOODDRAIN_DURATION);
				}
				pTargetPlayer->sendPacket(&_GCBloodDrainOK2);
			}
		}

		// target
		int targetLevel = 0;
		int targetMaxHP = 0;

		if (pEnemy->isSlayer()) 
		{
			Slayer* pTargetSlayer  = dynamic_cast<Slayer*>(pEnemy);
			targetLevel = pTargetSlayer->getHighestSkillDomainLevel();
			targetMaxHP = pTargetSlayer->getHP(ATTR_MAX);
		}
		else if (pEnemy->isVampire()) 
		{
			Vampire* pTargetVampire  = dynamic_cast<Vampire*>(pEnemy);
			targetLevel = pTargetVampire->getLevel();
			targetMaxHP = pTargetVampire->getHP(ATTR_MAX);
		}
		else if (pEnemy->isOusters()) 
		{
			Ousters* pTargetOusters  = dynamic_cast<Ousters*>(pEnemy);
			targetLevel = pTargetOusters->getLevel();
			targetMaxHP = pTargetOusters->getHP(ATTR_MAX);
		}
		else if (pEnemy->isMonster())
		{
			Monster* pEnemyMonster = dynamic_cast<Monster*>(pEnemy);

			// 흡혈당하는 몬스터한테 딜레이 걸어준다.
			Timeval DelayTurn;
			DelayTurn.tv_sec = 4;
			DelayTurn.tv_usec = 500000;
			pEnemyMonster->addAccuDelay(DelayTurn);

			if ((pMonster->isMaster()
#ifdef __UNDERWORLD__
				|| pMonster->isUnderworld() || pMonster->getMonsterType() == 599 
#endif
			)
				&& pMonster->getClanType()==pEnemyMonster->getClanType())
			{
				// 같은 clan의 마스터이면 피 상납이라고 볼 수 있을까 -_-;
			}
			else
			{
				pEnemyMonster->addEnemy(pMonster);
			}

			targetLevel = pEnemyMonster->getLevel();
			targetMaxHP = pEnemyMonster->getHP(ATTR_MAX);
		}

		// 자신이나 상대방 중.. HP가 많은 쪽의 15~25%
		HP_t maxHP = max((int)pMonster->getHP(ATTR_MAX), targetMaxHP);
		HP_t drainHP = maxHP*(rand()%11+15)/100; // 15~25%

		// 한번에 1000이상 안 찬다.
		if (pMonster->getMonsterType() >= 717 )
			drainHP = min((int)drainHP, 2000);
		else
			drainHP = min((int)drainHP, 1000);

		// 몬스터의 HP를 올려준다.
		HP_t CurrentHP = pMonster->getHP();
		HP_t MaxHP	   = pMonster->getHP(ATTR_MAX);
		HP_t NewHP     = min((int)MaxHP , (int)CurrentHP + (int)drainHP);

		// 뱀파이어의 HP를 세팅한다.
		pMonster->setHP(NewHP);

		GCStatusCurrentHP gcStatusCurrentHP;
		gcStatusCurrentHP.setObjectID(pMonster->getObjectID());
		gcStatusCurrentHP.setCurrentHP(NewHP);
		pZone->broadcastPacket(pMonster->getX(), pMonster->getY(), &gcStatusCurrentHP);

		// 흡혈 당한 애의 HP를 줄인다.
		// 대상이 내 레벨보다 높다면.. MaxHP의 10~15% damage
		// by sigi. 2002.9.14
		int drainDamage = 0;
		int myLevel = pMonster->getLevel();

		if (targetLevel > myLevel)
		{
			drainDamage = targetMaxHP * (rand()%6+10) / 100;
		}
		else
		{
			// 레벨 5차이마다 1%씩 더~
			int damagePercent = min(30, (rand()%6+10+(myLevel-targetLevel)));
			drainDamage = targetMaxHP * damagePercent / 100;
		}
		
		if (drainDamage > 0)
		{
			//decreaseHP(pZone, pEnemy, drainDamage);
			EffectDecreaseHP* pEffect = new EffectDecreaseHP(pEnemy);
			pEffect->setPoint(drainDamage);
			pEffect->setDeadline(20);	// 2초 후
			pEffect->setUserObjectID(pMonster->getObjectID());
			pEnemy->addEffect(pEffect);
			pEnemy->setFlag(Effect::EFFECT_CLASS_DECREASE_HP);
		}

		// 흡혈 모습 보이게..
		list<Creature *> cList;
		cList.push_back(pEnemy);
		cList.push_back(pMonster);
		pZone->broadcastPacket(pMonster->getX(), pMonster->getY(), &_GCBloodDrainOK3 , cList);

		// 흡혈 성공
		return true;
	}

	__END_CATCH

	return false;
}
Beispiel #2
0
//////////////////////////////////////////////////////////////////////////////
// 뱀파이어 오브젝트 핸들러
//////////////////////////////////////////////////////////////////////////////
void BloodDrain::execute(Vampire* pVampire, ObjectID_t TargetObjectID)
	throw(Error)
{
	__BEGIN_TRY

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

	Assert(pVampire != NULL);

	try 
	{
		Player* pPlayer = pVampire->getPlayer();
		Zone* pZone = pVampire->getZone();
		Assert(pPlayer != NULL);
		Assert(pZone != NULL);

		Creature* pTargetCreature = pZone->getCreature(TargetObjectID);
		//Assert(pTargetCreature != NULL);

		// NPC는 공격할 수가 없다.
		// 면역 상태. by sigi. 2002.9.13
		// 무적상태 체크. by sigi.2002.9.5
		// 죽은 애는 피 빨 수 없다. by Sequoia.2003. 3. 20
		if (pTargetCreature==NULL		// NoSuch 제거. by sigi. 2002.5.2
			|| pTargetCreature->isNPC()
			|| pTargetCreature->isFlag(Effect::EFFECT_CLASS_IMMUNE_TO_BLOOD_DRAIN)
			|| !canAttack(pVampire, pTargetCreature )
			|| pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA)
			|| pTargetCreature->isDead()
		)
		{
			executeSkillFailException(pVampire, getSkillType());
			//cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " End(vampire)" << endl;
			return;
		}

		GCBloodDrainOK1 _GCBloodDrainOK1;
		GCBloodDrainOK2 _GCBloodDrainOK2;
		GCBloodDrainOK3 _GCBloodDrainOK3;

		Timeval CurrentTime;
		getCurrentTime(CurrentTime);

		bool bHitRoll    = HitRoll::isSuccessBloodDrain(pVampire, pTargetCreature);
		bool bCanHit     = canHit(pVampire, pTargetCreature, SKILL_BLOOD_DRAIN);
		bool bTimeCheck  = CurrentTime.tv_sec > 1 ? true : false;
		bool bRangeCheck = verifyDistance(pVampire, pTargetCreature, 2);
		bool bPK         = verifyPK(pVampire, pTargetCreature);

		if (bHitRoll && bCanHit && bTimeCheck && bRangeCheck && bPK)
		{
			// 슬레이어일 경우에만 이펙트 오브젝트를 생성한다.
			if (pTargetCreature->isSlayer())
			{
				EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pTargetCreature);
				pEffectBloodDrain->setLevel(pVampire->getLevel());
				pEffectBloodDrain->setDeadline(BLOODDRAIN_DURATION);	// 3일??
				pTargetCreature->addEffect(pEffectBloodDrain);
				pEffectBloodDrain->create(pTargetCreature->getName());
				_GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN);

				// 타겟이 뭐든 플래그는 건다.
				pTargetCreature->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN);

				Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature);
				SLAYER_RECORD prev;
				pTargetSlayer->getSlayerRecord(prev);
				pTargetSlayer->initAllStat();
				pTargetSlayer->sendRealWearingInfo();
				pTargetSlayer->addModifyInfo(prev, _GCBloodDrainOK2);

				// 로그를 남긴다.
				//log(LOG_BLOODDRAINED, pTargetCreature->getName(), pVampire->getName());
			}
			// 아우스터즈의 경우엔..... -_-; 제한시간 없는 이펙트를 생성한다. 엄밀히 말해 제한시간이 없는 건 아니지만..
//			else if (pTargetCreature->isOusters() )
//			{
//				EffectBloodDrain* pEffectBloodDrain = new EffectBloodDrain(pTargetCreature);
//				pEffectBloodDrain->setLevel(pVampire->getLevel());
//				pTargetCreature->addEffect(pEffectBloodDrain);
//				pEffectBloodDrain->create(pTargetCreature->getName());
//				_GCBloodDrainOK2.addShortData(MODIFY_EFFECT_STAT, Effect::EFFECT_CLASS_BLOOD_DRAIN);
//
//				// 타겟이 뭐든 플래그는 건다.
//				pTargetCreature->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN);
//
//				Sight_t oldSight = pTargetCreature->getSight();
//				Sight_t newSight = pTargetCreature->getEffectedSight();
//
//				if (oldSight != newSight )
//				{
//					pTargetCreature->setSight(newSight);
//					pZone->updateScan(pTargetCreature, oldSight, pTargetCreature->getSight());
//					_GCBloodDrainOK2.addShortData(MODIFY_VISION, pTargetCreature->getSight());
//
//					GCChangeDarkLight gcChangeDarkLight;
//					gcChangeDarkLight.setDarkLevel(15);
//					gcChangeDarkLight.setLightLevel(newSight);
//					pTargetCreature->getPlayer()->sendPacket(&gcChangeDarkLight);
//				}
//			}

			// 타겟이 뭐든 플래그는 건다.
			pTargetCreature->setFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN);
			
			// 올릴 경험치량을 계산한다.
			Exp_t Exp = computeCreatureExp(pTargetCreature, BLOODDRAIN_EXP);

			int targetLevel = 0;
			int targetMaxHP = 0;
			// 페임을 올려준다.
			if (pTargetCreature->isSlayer()) 
			{
				//increaseFame(pVampire, Exp);
				Slayer* pTargetSlayer  = dynamic_cast<Slayer*>(pTargetCreature);
				targetLevel = pTargetSlayer->getHighestSkillDomainLevel();
				targetMaxHP = pTargetSlayer->getHP(ATTR_MAX);
			}
			else if (pTargetCreature->isVampire()) 
			{
				//increaseFame(pVampire, Exp);
				Vampire* pTargetVampire  = dynamic_cast<Vampire*>(pTargetCreature);
				targetLevel = pTargetVampire->getLevel();
				targetMaxHP = pTargetVampire->getHP(ATTR_MAX);
			}
			else if (pTargetCreature->isOusters()) 
			{
				//increaseFame(pOusters, Exp);
				Ousters* pTargetOusters  = dynamic_cast<Ousters*>(pTargetCreature);
				targetLevel = pTargetOusters->getLevel();
				targetMaxHP = pTargetOusters->getHP(ATTR_MAX);
			}
			else if (pTargetCreature->isMonster())
			{
				Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature);

				Timeval NextTurn = pMonster->getNextTurn();
				Timeval DelayTurn;
				DelayTurn.tv_sec = 4;
				DelayTurn.tv_usec = 500000;
				pMonster->addAccuDelay(DelayTurn);
				pMonster->addEnemy(pVampire);

				targetLevel = pMonster->getLevel();
				targetMaxHP = pMonster->getHP(ATTR_MAX);
			}

			shareVampExp(pVampire, Exp, _GCBloodDrainOK1);

			// 흡혈을 하게 되면 흡혈한 사람의 체력이 올라간다.
			// Mephisto이펙트가 걸려있으면 HP는 안 올라간다.
			if (!pVampire->isFlag(Effect::EFFECT_CLASS_MEPHISTO))
			{
				HP_t HealPoint = (Exp==0? computeBloodDrainHealPoint(pTargetCreature, BLOODDRAIN_EXP) : Exp);
				HP_t CurrentHP = pVampire->getHP();
				HP_t MaxHP	   = pVampire->getHP(ATTR_MAX);
				HP_t NewHP     = min((int)MaxHP , (int)CurrentHP + (int)HealPoint);

				// 은 데미지 관련 처리를 해 준다.
				Silver_t newSilverDamage = max(0, (int)pVampire->getSilverDamage()-(int)HealPoint);
				pVampire->saveSilverDamage(newSilverDamage);
				_GCBloodDrainOK1.addShortData(MODIFY_SILVER_DAMAGE, newSilverDamage);

				// 뱀파이어의 HP를 세팅한다.
				pVampire->setHP(NewHP);

				GCStatusCurrentHP gcStatusCurrentHP;
				gcStatusCurrentHP.setObjectID(pVampire->getObjectID());
				gcStatusCurrentHP.setCurrentHP(NewHP);
				pZone->broadcastPacket(pVampire->getX(), pVampire->getY(), &gcStatusCurrentHP, pVampire);

				_GCBloodDrainOK1.addShortData(MODIFY_CURRENT_HP, NewHP);
			}

			// 흡혈을 당한 애는 HP가 줄어든다.
			// 대상이 내 레벨보다 높다면.. MaxHP의 10~15% damage
			// by sigi. 2002.9.14
			int drainDamage = 0;
			int myLevel = pVampire->getLevel();

			if (targetLevel > myLevel)
			{
				drainDamage = targetMaxHP * (rand()%6+10) / 100;
			}
			else
			{
				// 레벨 5차이마다 1%씩 더~
				int damagePercent = min(30, (rand()%6+10+(myLevel-targetLevel)));
				drainDamage = targetMaxHP * damagePercent / 100;
			}
			
			if (drainDamage > 0)
			{
				//decreaseHP(pZone, pTargetCreature, drainDamage, pVampire->getObjectID()); 
				EffectDecreaseHP* pEffect = new EffectDecreaseHP(pTargetCreature);
				pEffect->setPoint(drainDamage);
				pEffect->setDeadline(20);	// 2초 후
				pEffect->setUserObjectID(pVampire->getObjectID());
				pTargetCreature->addEffect(pEffect);
				pTargetCreature->setFlag(Effect::EFFECT_CLASS_DECREASE_HP);
			}

			pVampire->getGQuestManager()->blooddrain();

			// 흡혈시에도 성향 바뀜
			// by sigi. 2002.12.16
			// EffectDecreaseHP에서 HP가 닳아서 0이 되어야하는 경우가 있어서 
			// EffectDecreaseHP::unaffect()로 옮긴다.
			//computeAlignmentChange(pTargetCreature, drainDamage, pVampire, NULL, &_GCBloodDrainOK1);

			_GCBloodDrainOK1.setObjectID(TargetObjectID);

			_GCBloodDrainOK3.setObjectID(pVampire->getObjectID());
			_GCBloodDrainOK3.setTargetObjectID (TargetObjectID);

			pPlayer->sendPacket(&_GCBloodDrainOK1);

			if (pTargetCreature != NULL && pTargetCreature->isPC()) 
			{
				Player* pTargetPlayer = pTargetCreature->getPlayer();

				if (pTargetPlayer != NULL) 
				{ 
					_GCBloodDrainOK2.setObjectID(pVampire->getObjectID());
//					_GCBloodDrainOK2.addLongData(MODIFY_DURATION, BLOODDRAIN_DURATION);
					pTargetPlayer->sendPacket(&_GCBloodDrainOK2);
				}
			}

			list<Creature *> cList;
			cList.push_back(pTargetCreature);
			cList.push_back(pVampire);
			pZone->broadcastPacket(pVampire->getX(), pVampire->getY(),  &_GCBloodDrainOK3 , cList);
		}
		else 
		{
			executeSkillFailNormal(pVampire, getSkillType(), pTargetCreature);
		}
	} 
	catch (Throwable & t) 
	{
		executeSkillFailException(pVampire, getSkillType());
	}

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

	__END_CATCH

}
Beispiel #3
0
void SimpleCureSkill::execute(Slayer* pSlayer, SkillSlot* pSkillSlot, 
	const SIMPLE_SKILL_INPUT& param, SIMPLE_SKILL_OUTPUT& result,
	CEffectID_t CEffectID)
	throw(Error)
{
	__BEGIN_TRY

	Assert(pSlayer != NULL);
	Assert(pSkillSlot != NULL);

	try 
	{
		Player* pPlayer = pSlayer->getPlayer();
		Zone* pZone = pSlayer->getZone();

		GCSkillToSelfOK1 _GCSkillToSelfOK1;
		GCSkillToSelfOK2 _GCSkillToSelfOK2;

		SkillInfo*        pSkillInfo = g_pSkillInfoManager->getSkillInfo(param.SkillType);
		SkillDomainType_t DomainType = pSkillInfo->getDomainType();

		int  RequiredMP  = (int)pSkillInfo->getConsumeMP();
		bool bManaCheck  = hasEnoughMana(pSlayer, RequiredMP);
		bool bTimeCheck  = verifyRunTime(pSkillSlot);
		bool bRangeCheck = checkZoneLevelToUseSkill(pSlayer);
		bool bHitRoll    = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot);
		bool bHPCheck    = false;

		EffectBloodDrain* pEffectBloodDrain = NULL;
		
		if (pSlayer->getHP(ATTR_CURRENT) < pSlayer->getHP(ATTR_MAX))
		{
			bHPCheck = true;
		}
		if (pSlayer->isFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN))
		{
			Effect* pEffect = pSlayer->findEffect(Effect::EFFECT_CLASS_BLOOD_DRAIN);
			pEffectBloodDrain = dynamic_cast<EffectBloodDrain*>(pEffect);
			Assert(pEffectBloodDrain != NULL);
				
			if (pEffectBloodDrain->getLevel() < param.Level) bHPCheck = true;
		}

		if (bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && bHPCheck && pSlayer->isAlive())
		{
			decreaseMana(pSlayer, RequiredMP, _GCSkillToSelfOK1);

			uint HealPoint = param.SkillDamage;

			// 흡혈당한 상태라면 흡혈 상태를 날려준다.
			if (pEffectBloodDrain != NULL && pEffectBloodDrain->getLevel() < param.Level)
			{
				// 흡혈 아르바이트를 방지하기 위한 후유증 이펙트를 붙여준다.
				if (pSlayer->isFlag(Effect::EFFECT_CLASS_AFTERMATH))
				{
					Effect* pEffect = pSlayer->findEffect(Effect::EFFECT_CLASS_AFTERMATH);
					EffectAftermath* pEffectAftermath = dynamic_cast<EffectAftermath*>(pEffect);
					pEffectAftermath->setDeadline(5*600); // 5분 동안 지속된다.
				}
				else
				{
					EffectAftermath* pEffectAftermath = new EffectAftermath(pSlayer);
					pEffectAftermath->setDeadline(5*600); // 5분 동안 지속된다.
					pSlayer->addEffect(pEffectAftermath);
					pSlayer->setFlag(Effect::EFFECT_CLASS_AFTERMATH);
					pEffectAftermath->create(pSlayer->getName());
				}

				pEffectBloodDrain->destroy(pSlayer->getName());
				pSlayer->deleteEffect(Effect::EFFECT_CLASS_BLOOD_DRAIN);

				SLAYER_RECORD prev;
				pSlayer->getSlayerRecord(prev);
				pSlayer->initAllStat();
				pSlayer->sendRealWearingInfo();
				pSlayer->addModifyInfo(prev, _GCSkillToSelfOK1);

				GCRemoveEffect gcRemoveEffect;
				gcRemoveEffect.setObjectID(pSlayer->getObjectID());
				gcRemoveEffect.addEffectList((EffectID_t)Effect::EFFECT_CLASS_BLOOD_DRAIN);
				pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcRemoveEffect);
			}
		
			// HP를 세팅한다.
			HP_t CurrentHP = pSlayer->getHP(ATTR_CURRENT);
			HP_t MaxHP     = pSlayer->getHP(ATTR_MAX);

			// 실제 회복 수치를 계산한다.
			int RealHealPoint = 0;
			if(CurrentHP + HealPoint <= MaxHP ) {
				RealHealPoint = max((unsigned int)0, HealPoint);
			} else {
				RealHealPoint = max(0, MaxHP - CurrentHP);
			}

			// 경험치를 올려준다.
			shareAttrExp(pSlayer, RealHealPoint, param.STRMultiplier, param.DEXMultiplier, param.INTMultiplier, _GCSkillToSelfOK1);
			increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToSelfOK1);
			increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToSelfOK1);

			CurrentHP = min((int)MaxHP, (int)(CurrentHP + HealPoint));
			pSlayer->setHP(CurrentHP , ATTR_CURRENT);

			// HP를 브로드캐스팅한다.
			GCStatusCurrentHP gcStatusCurrentHP;
			gcStatusCurrentHP.setObjectID(pSlayer->getObjectID());
			gcStatusCurrentHP.setCurrentHP (CurrentHP);
			pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcStatusCurrentHP);
			
			ZoneCoord_t myX = pSlayer->getX();
			ZoneCoord_t myY = pSlayer->getY();

			_GCSkillToSelfOK1.setSkillType(param.SkillType);
			_GCSkillToSelfOK1.setCEffectID(CEffectID);
			_GCSkillToSelfOK1.setDuration(0);
			
			_GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID());
			_GCSkillToSelfOK2.setSkillType(param.SkillType);
			_GCSkillToSelfOK2.setDuration (0);

			// Send Packet
			pPlayer->sendPacket(&_GCSkillToSelfOK1);

			pZone->broadcastPacket(myX, myY, &_GCSkillToSelfOK2, pSlayer);

			pSkillSlot->setRunTime(param.Delay);

			result.bSuccess = true;
		} 
		else 
		{
			executeSkillFailNormal(pSlayer, param.SkillType, NULL);
		}
	} 
	catch(Throwable & t)  
	{
		executeSkillFailException(pSlayer, param.SkillType);
	}

	__END_CATCH
}
void EffectCureCriticalWounds::affect(Creature* pCreature)
	throw(Error)
{
	__BEGIN_TRY

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

	GCSkillToSelfOK1 _GCSkillToSelfOK1;
	GCSkillToSelfOK2 _GCSkillToSelfOK2;

	int X = pCreature->getX();
	int Y = pCreature->getY();
	Exp_t ExpUp = 0;
	bool bCured = false;

	for(int oY = -2; oY <= 2; oY++)
	for(int oX = -2; oX <= 2; oX++)
	{
		int tileX = X+oX;
		int tileY = Y+oY;

		if (isValidZoneCoord(pZone, tileX, tileY))
		{
			Tile& tile = pZone->getTile(tileX, tileY);

			if (tile.hasCreature(Creature::MOVE_MODE_WALKING ) ) 
			{
				const list<Object*>& oList = tile.getObjectList();
				for(list<Object*>::const_iterator itr = oList.begin(); itr != oList.end(); itr++) 
				{
					Object* pTarget = *itr;
					Creature* pTargetCreature = NULL;
					if (pTarget->getObjectClass() == Object::OBJECT_CLASS_CREATURE 
						&& (pTargetCreature = dynamic_cast<Creature*>(pTarget))->isSlayer()) 
					{
						Assert(pTargetCreature != NULL);
						HP_t RemainHP = 0;

						if (pTargetCreature->isSlayer() && !pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA) ) 
						{
							Slayer* pSlayer = dynamic_cast<Slayer*>(pTargetCreature);
							HP_t CurrentHP = pSlayer->getHP(ATTR_CURRENT);
							HP_t MaxHP = pSlayer->getHP(ATTR_MAX);

							if (pTargetCreature->isFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN))
							{
								ExpUp++;
								Effect* pEffect = pSlayer->findEffect(Effect::EFFECT_CLASS_BLOOD_DRAIN);
								EffectBloodDrain * pEffectBloodDrain = dynamic_cast<EffectBloodDrain*>(pEffect);

								Assert(pEffectBloodDrain != NULL);

								if (pEffectBloodDrain->getLevel() < CriticalBloodDrainLevel ) {

									// 흡혈 아르바이트를 방지하기 위한 후유증 이펙트를 붙여준다.
									if (pSlayer->isFlag(Effect::EFFECT_CLASS_AFTERMATH))
									{
										Effect* pEffect = pSlayer->findEffect(Effect::EFFECT_CLASS_AFTERMATH);
										EffectAftermath* pEffectAftermath = dynamic_cast<EffectAftermath*>(pEffect);
										pEffectAftermath->setDeadline(5*600); // 5분 동안 지속된다.
									}
									else
									{
										EffectAftermath* pEffectAftermath = new EffectAftermath(pSlayer);
										pEffectAftermath->setDeadline(5*600); // 5분 동안 지속된다.
										pSlayer->addEffect(pEffectAftermath);
										pSlayer->setFlag(Effect::EFFECT_CLASS_AFTERMATH);
										pEffectAftermath->create(pSlayer->getName());
									}

									pEffectBloodDrain->destroy(pSlayer->getName());
									pSlayer->deleteEffect(Effect::EFFECT_CLASS_BLOOD_DRAIN);

									bCured = true;

									SLAYER_RECORD prev;
									pSlayer->getSlayerRecord(prev);
									pSlayer->initAllStat();
									pSlayer->sendRealWearingInfo();
									pSlayer->sendModifyInfo(prev);

									GCRemoveEffect gcRemoveEffect;
									gcRemoveEffect.setObjectID(pSlayer->getObjectID());
									gcRemoveEffect.addEffectList((EffectID_t)Effect::EFFECT_CLASS_BLOOD_DRAIN);
									pZone->broadcastPacket(pSlayer->getX(), pSlayer->getY(), &gcRemoveEffect);

								}
							}

							if(CurrentHP < MaxHP ) {
								ExpUp++;
								bCured = true;

								RemainHP = min(CurrentHP + m_Point,(int)MaxHP);
								pSlayer->setHP(RemainHP, ATTR_CURRENT);

								GCModifyInformation gcMI;
								gcMI.addShortData(MODIFY_CURRENT_HP, RemainHP);
								pSlayer->getPlayer()->sendPacket(&gcMI);

								_GCSkillToSelfOK1.setSkillType(SKILL_CURE_EFFECT);
								_GCSkillToSelfOK1.setDuration(0);
								pSlayer->getPlayer()->sendPacket(&_GCSkillToSelfOK1);
							
								_GCSkillToSelfOK2.setObjectID(pSlayer->getObjectID());
								_GCSkillToSelfOK2.setSkillType(SKILL_CURE_EFFECT);
								_GCSkillToSelfOK2.setDuration(0);
								pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &_GCSkillToSelfOK2, pTargetCreature);

								Zone* pZone = pTargetCreature->getZone();
								GCStatusCurrentHP gcStatusCurrentHP;
								gcStatusCurrentHP.setObjectID(pTargetCreature->getObjectID());
								gcStatusCurrentHP.setCurrentHP(RemainHP);
								pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &gcStatusCurrentHP);
							}
						} 
					}
				}	
			}
		}	
	}

	SkillInfo * pSkillInfo = g_pSkillInfoManager->getSkillInfo(SKILL_CURE_CRITICAL_WOUNDS);

	if(pSkillInfo != NULL && bCured ) {
		SkillSlot * pSkillSlot = ((Slayer*)pCreature)->hasSkill(SKILL_CURE_CRITICAL_WOUNDS);
		if(pSkillSlot != NULL ) {
			Slayer * pCastSlayer = dynamic_cast<Slayer*>(pCreature);
			GCModifyInformation gcMI;
			SkillDomainType_t DomainType = pSkillInfo->getDomainType();
			// 경험치를 올려준다.
			shareAttrExp(pCastSlayer, ExpUp, 1 , 1 , 8, gcMI);
			increaseDomainExp(pCastSlayer, DomainType, ExpUp, gcMI);
			increaseSkillExp(pCastSlayer, DomainType, pSkillSlot, pSkillInfo, gcMI);
			pCastSlayer->getPlayer()->sendPacket(&gcMI);
		}
	}

	//cout << "EffectCureCriticalWounds " << "affect BEGIN" << endl;
	setNextTime(m_Delay);
	//cout << "EffectCureCriticalWounds " << "affect END" << endl;

	__END_CATCH
}
Beispiel #5
0
void SimpleCureSkill::execute(Slayer* pSlayer, ObjectID_t TargetObjectID, SkillSlot* pSkillSlot, 
	const SIMPLE_SKILL_INPUT& param, SIMPLE_SKILL_OUTPUT& result,
	CEffectID_t CEffectID) 
	throw(Error)
{
	__BEGIN_TRY

	Assert(pSlayer != NULL);
	Assert(pSkillSlot != NULL);

	try 
	{
		Player* pPlayer = pSlayer->getPlayer();
		Zone* pZone = pSlayer->getZone();
		Assert(pPlayer != NULL);
		Assert(pZone != NULL);

		Creature* pTargetCreature = pZone->getCreature(TargetObjectID);
		//Assert(pTargetCreature != NULL);

		// 슬레이어 외에는 치료할 수가 없다.
		// NoSuch제거. by sigi. 2002.5.2
		if (pTargetCreature==NULL
			|| pTargetCreature->isSlayer() == false)
		{
			executeSkillFailException(pSlayer, param.SkillType);
			return;
		}

		GCSkillToObjectOK1 _GCSkillToObjectOK1;
		GCSkillToObjectOK2 _GCSkillToObjectOK2;
		GCSkillToObjectOK3 _GCSkillToObjectOK3;
		GCSkillToObjectOK4 _GCSkillToObjectOK4;
		GCSkillToObjectOK5 _GCSkillToObjectOK5;

		SkillInfo*        pSkillInfo = g_pSkillInfoManager->getSkillInfo(param.SkillType);
		SkillDomainType_t DomainType = pSkillInfo->getDomainType();

		bool bHPCheck = false;

		// 체력이 닳거나, 흡혈을 당한 상태여야 한다.
		Slayer* pTargetSlayer = dynamic_cast<Slayer*>(pTargetCreature);
		Assert(pTargetSlayer != NULL);

		EffectBloodDrain* pEffectBloodDrain = NULL;

		if (pTargetSlayer->getHP(ATTR_CURRENT) < pTargetSlayer->getHP(ATTR_MAX))
		{
			bHPCheck = true;
		}
		if (pTargetSlayer->isFlag(Effect::EFFECT_CLASS_BLOOD_DRAIN))
		{
			Effect* pEffect = pTargetSlayer->findEffect(Effect::EFFECT_CLASS_BLOOD_DRAIN);
			pEffectBloodDrain = dynamic_cast<EffectBloodDrain*>(pEffect);
			Assert(pEffectBloodDrain != NULL);

			if (pEffectBloodDrain->getLevel() < param.Level) bHPCheck = true;
		}

		int  RequiredMP  = (int)pSkillInfo->getConsumeMP();
		bool bManaCheck  = hasEnoughMana(pSlayer, RequiredMP);
		bool bTimeCheck  = verifyRunTime(pSkillSlot);
		bool bRangeCheck = verifyDistance(pSlayer, pTargetCreature, pSkillInfo->getRange());
		bool bHitRoll    = HitRoll::isSuccessMagic(pSlayer, pSkillInfo, pSkillSlot);

		if (bHPCheck && bManaCheck && bTimeCheck && bRangeCheck && bHitRoll && pTargetCreature->isAlive())
		{
			decreaseMana(pSlayer, RequiredMP, _GCSkillToObjectOK1);

			uint HealPoint = param.SkillDamage;

			// 흡혈당한 상태라면 흡혈 상태를 날려준다.
			if (pEffectBloodDrain != NULL && pEffectBloodDrain->getLevel() < param.Level)
			{
				// 흡혈 아르바이트를 방지하기 위한 후유증 이펙트를 붙여준다.
				if (pTargetSlayer->isFlag(Effect::EFFECT_CLASS_AFTERMATH))
				{
					Effect* pEffect = pTargetSlayer->findEffect(Effect::EFFECT_CLASS_AFTERMATH);
					EffectAftermath* pEffectAftermath = dynamic_cast<EffectAftermath*>(pEffect);
					pEffectAftermath->setDeadline(5*600); // 5분 동안 지속된다.
				}
				else
				{
					EffectAftermath* pEffectAftermath = new EffectAftermath(pTargetSlayer);
					pEffectAftermath->setDeadline(5*600); // 5분 동안 지속된다.
					pTargetSlayer->addEffect(pEffectAftermath);
					pTargetSlayer->setFlag(Effect::EFFECT_CLASS_AFTERMATH);
					pEffectAftermath->create(pTargetSlayer->getName());
				}


				pEffectBloodDrain->destroy(pTargetSlayer->getName());
				pTargetSlayer->deleteEffect(Effect::EFFECT_CLASS_BLOOD_DRAIN);

				SLAYER_RECORD prev;
				pTargetSlayer->getSlayerRecord(prev);
				pTargetSlayer->initAllStat();
				pTargetSlayer->sendRealWearingInfo();
				pTargetSlayer->addModifyInfo(prev, _GCSkillToObjectOK2);

				GCRemoveEffect gcRemoveEffect;
				gcRemoveEffect.setObjectID(pTargetSlayer->getObjectID());
				gcRemoveEffect.addEffectList((EffectID_t)Effect::EFFECT_CLASS_BLOOD_DRAIN);
				pZone->broadcastPacket(pTargetSlayer->getX(), pTargetSlayer->getY(), &gcRemoveEffect);
			}

			// 다른 사람을 치료한다.
			HP_t CurrentHP = pTargetSlayer->getHP(ATTR_CURRENT);
			HP_t MaxHP     = pTargetSlayer->getHP(ATTR_MAX);

			// 실제 회복 수치를 계산한다.
			int RealHealPoint = 0;
			if(CurrentHP + HealPoint <= MaxHP ) {
				RealHealPoint = max((unsigned int)0, HealPoint);
			} else {
				RealHealPoint = max(0, MaxHP - CurrentHP);
			}

			// 경험치를 올려준다.
			shareAttrExp(pSlayer, HealPoint , param.STRMultiplier, param.DEXMultiplier, param.INTMultiplier, _GCSkillToObjectOK1);
			increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToObjectOK1);
			increaseSkillExp(pSlayer, DomainType, pSkillSlot, pSkillInfo, _GCSkillToObjectOK1);

			CurrentHP = min((int)(MaxHP), (int)(CurrentHP + HealPoint));
			pTargetSlayer->setHP(CurrentHP, ATTR_CURRENT);
		
			// 치료가 되었으니 HP를 브로드캐스팅한다.
			GCStatusCurrentHP gcStatusCurrentHP;
			gcStatusCurrentHP.setObjectID(TargetObjectID);
			gcStatusCurrentHP.setCurrentHP (CurrentHP);
			pZone->broadcastPacket(pTargetCreature->getX(), pTargetCreature->getY(), &gcStatusCurrentHP);

			_GCSkillToObjectOK2.addShortData(MODIFY_CURRENT_HP, CurrentHP);
			
			ZoneCoord_t myX     = pSlayer->getX();
			ZoneCoord_t myY     = pSlayer->getY();
			ZoneCoord_t targetX = pTargetCreature->getX();
			ZoneCoord_t targetY = pTargetCreature->getY();

			_GCSkillToObjectOK1.setSkillType(param.SkillType);
			_GCSkillToObjectOK1.setCEffectID(CEffectID);
			_GCSkillToObjectOK1.setTargetObjectID(TargetObjectID);
			_GCSkillToObjectOK1.setDuration(0);

			_GCSkillToObjectOK2.setObjectID(pSlayer->getObjectID());
			_GCSkillToObjectOK2.setSkillType(param.SkillType);
			_GCSkillToObjectOK2.setDuration (0);

			_GCSkillToObjectOK3.setObjectID(pSlayer->getObjectID());
			_GCSkillToObjectOK3.setSkillType(param.SkillType);
			_GCSkillToObjectOK3.setTargetXY(targetX, targetY);

			_GCSkillToObjectOK4.setSkillType(param.SkillType);
			_GCSkillToObjectOK4.setTargetObjectID(TargetObjectID);
			
			_GCSkillToObjectOK5.setObjectID(pSlayer->getObjectID());
			_GCSkillToObjectOK5.setSkillType(param.SkillType);
			_GCSkillToObjectOK5.setTargetObjectID (TargetObjectID);
			_GCSkillToObjectOK5.setDuration (0);

			pPlayer->sendPacket(&_GCSkillToObjectOK1);

			if (pTargetCreature->isPC()) 
			{
				Player* pTargetPlayer = pTargetCreature->getPlayer();
				Assert(pTargetPlayer != NULL);
				pTargetPlayer->sendPacket(&_GCSkillToObjectOK2);
			}
			
			list<Creature*> cList;
			cList.push_back(pSlayer);
			cList.push_back(pTargetCreature);

			cList = pZone->broadcastSkillPacket(myX, myY, targetX, targetY, &_GCSkillToObjectOK5, cList);

			pZone->broadcastPacket(myX, myY,  &_GCSkillToObjectOK3 , cList);
			pZone->broadcastPacket(targetX, targetY,  &_GCSkillToObjectOK4 , cList);
			
			pSkillSlot->setRunTime(param.Delay);

			result.bSuccess = true;
		} 
		else 
		{
			executeSkillFailNormal(pSlayer, param.SkillType, pTargetCreature);
		}
	} 
	catch(Throwable & t)  
	{
		executeSkillFailException(pSlayer, param.SkillType);
	}

	__END_CATCH
}