/**
 * Check state changes related to movement
 */
void BehaviorStandard::checkMove() {

	// dying enemies can't move
	if (e->stats.cur_state == ENEMY_DEAD || e->stats.cur_state == ENEMY_CRITDEAD) return;

	// stunned enemies can't act
	if (e->stats.effects.stun) return;

	// handle not being in combat and (not patrolling waypoints or waiting at waypoint)
	if (!e->stats.hero_ally && !e->stats.in_combat && (e->stats.waypoints.empty() || e->stats.waypoint_pause_ticks > 0) && (!e->stats.wander || e->stats.wander_pause_ticks > 0)) {

		if (e->stats.cur_state == ENEMY_MOVE) {
			e->newState(ENEMY_STANCE);
		}

		// currently enemies only move while in combat or patrolling
		return;
	}

	// clear current space to allow correct movement
	e->map->collider.unblock(e->stats.pos.x, e->stats.pos.y);

	// update direction
	if (e->stats.facing) {
		if (++e->stats.turn_ticks > e->stats.turn_delay) {

			// if blocked, face in pathfinder direction instead
			if (!e->map->collider.line_of_movement(e->stats.pos.x, e->stats.pos.y, e->stats.hero_pos.x, e->stats.hero_pos.y, e->stats.movement_type)) {

				// if a path is returned, target first waypoint
				std::vector<Point> path;

				e->map->collider.compute_path(e->stats.pos, pursue_pos, path, e->stats.movement_type);
				if(!path.empty())
					pursue_pos = path.back();
			}

			if(fleeing)
				e->stats.direction = calcDirection(pursue_pos, e->stats.pos);
			else
				e->stats.direction = calcDirection(e->stats.pos, pursue_pos);
			e->stats.turn_ticks = 0;
		}
	}

	// try to start moving
	if (e->stats.cur_state == ENEMY_STANCE) {
		checkMoveStateStance();
	}

	// already moving
	else if (e->stats.cur_state == ENEMY_MOVE) {
		checkMoveStateMove();
	}

	// if patrolling waypoints and has reached a waypoint, cycle to the next one
	if (!e->stats.waypoints.empty()) {
		Point waypoint = e->stats.waypoints.front();
		Point pos = e->stats.pos;
		// if the patroller is close to the waypoint
		if (abs(waypoint.x - pos.x) < UNITS_PER_TILE/2 && abs(waypoint.y - pos.y) < UNITS_PER_TILE/2) {
			e->stats.waypoints.pop();
			e->stats.waypoints.push(waypoint);
			e->stats.waypoint_pause_ticks = e->stats.waypoint_pause;
		}
	}

	// if a wandering enemy reaches its destination early, reset wander_ticks
	if (e->stats.wander) {
		Point pos = e->stats.pos;
		if (abs(pursue_pos.x - pos.x) < UNITS_PER_TILE/2 && abs(pursue_pos.y - pos.y) < UNITS_PER_TILE/2) {
			e->stats.wander_ticks = 0;
		}
		if (e->stats.wander_ticks == 0 && e->stats.wander_pause_ticks == 0) {
			e->stats.wander_pause_ticks = rand() % 60;
		}
	}

	// re-block current space to allow correct movement
	e->map->collider.block(e->stats.pos.x, e->stats.pos.y, e->stats.hero_ally);

}
Beispiel #2
0
//////////////////////////////////////////////////////////////////////////////
// 뱀파이어 타일 핸들러
//////////////////////////////////////////////////////////////////////////////
void BloodyBreaker::execute(Vampire* pVampire, ZoneCoord_t X, ZoneCoord_t Y, VampireSkillSlot* pVampireSkillSlot, CEffectID_t CEffectID)
	throw(Error)
{
	__BEGIN_TRY

	//cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << "begin " << endl;
	SkillType_t SkillType = getSkillType();

	// Knowledge of Blood 가 있다면 hit bonus 10
	int HitBonus = 0;
	if (pVampire->hasRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_BLOOD ) )
	{
		RankBonus* pRankBonus = pVampire->getRankBonus(RankBonus::RANK_BONUS_KNOWLEDGE_OF_BLOOD);
		Assert(pRankBonus != NULL);

		HitBonus = pRankBonus->getPoint();
	}

	try 
	{
		SkillInput input(pVampire);
		SkillOutput output;
		computeOutput(input, output);

		Dir_t	Dir		= getDirectionToPosition(pVampire->getX(), pVampire->getY(), X, Y);

		// 강제로 knockback시킬 확률
//		bool bForceKnockback = rand()%100 < output.ToHit;

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

		VSRect rect(1, 1, pZone->getWidth()-2, pZone->getHeight()-2);
		if (!rect.ptInRect(X, Y ))
		{
			executeSkillFailException(pVampire, SkillType);
			return;
		}


		GCSkillToTileOK1 _GCSkillToTileOK1;
		GCSkillToTileOK2 _GCSkillToTileOK2;
//		GCSkillToTileOK3 _GCSkillToTileOK3;
//		GCSkillToTileOK4 _GCSkillToTileOK4;
		GCSkillToTileOK5 _GCSkillToTileOK5;
//		GCSkillToTileOK6 _GCSkillToTileOK6;

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

		int  RequiredMP  = decreaseConsumeMP(pVampire, pSkillInfo);
		bool bManaCheck  = hasEnoughMana(pVampire, RequiredMP);
		bool bTimeCheck  = verifyRunTime(pVampireSkillSlot);
		bool bRangeCheck = verifyDistance(pVampire, X, Y, pSkillInfo->getRange());

		if (bManaCheck && bTimeCheck && bRangeCheck )
		{
			// 마나를 떨어뜨린다.
			decreaseMana(pVampire, RequiredMP, _GCSkillToTileOK1);

			// 좌표와 방향을 구한다.
			ZoneCoord_t myX          = pVampire->getX();
			ZoneCoord_t myY          = pVampire->getY();
			Dir_t       dir          = calcDirection(myX, myY, X, Y);

			list<Creature*> cList;

			// knockback 때문에 recursive 하게 데미지를 먹는 경우가 있다.
			// 그래서 제일 먼쪽에 있는 마스크부터 체크한다.
			for (int i = 21; i >= 0; i-- )
			{
				int tileX   = myX + m_pBloodyBreakerMask[Dir][i].x;
				int tileY   = myY + m_pBloodyBreakerMask[Dir][i].y;

				// 현재 타일이 존 내부이고, 안전지대가 아니라면 맞을 가능성이 있다.
				if (rect.ptInRect(tileX, tileY))
				{
					// 타일을 받아온다.
					Tile& tile = pZone->getTile(tileX, tileY);

					list<Creature*> targetList;
					if (tile.hasCreature(Creature::MOVE_MODE_WALKING))
					{
						Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_WALKING);
						targetList.push_back(pCreature);
					}
					if (tile.hasCreature(Creature::MOVE_MODE_FLYING))
					{
						Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_FLYING);
						targetList.push_back(pCreature);
					}
					if (tile.hasCreature(Creature::MOVE_MODE_BURROWING))
					{
						Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_BURROWING);
						targetList.push_back(pCreature);
					}

					list<Creature*>::iterator itr = targetList.begin();
					for(; itr != targetList.end(); itr++)
					{
						Creature* pTargetCreature = (*itr);
						Assert(pTargetCreature != NULL);

						if (!canAttack(pVampire, pTargetCreature )
							|| pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA) )
						{
							continue;
						}

						if (pTargetCreature != pVampire)
						{
							bool bPK             = verifyPK(pVampire, pTargetCreature);
							bool bRaceCheck      = pTargetCreature->isSlayer() || pTargetCreature->isMonster() || pTargetCreature->isOusters();
							bool bZoneLevelCheck = checkZoneLevelToHitTarget(pTargetCreature);
							bool bHitRoll        = false;//HitRoll::isSuccessMagic(pVampire, pSkillInfo, pVampireSkillSlot, HitBonus);

							int EnemyLevel = 0;

							if (pTargetCreature->isSlayer() )
							{
								Slayer* pSlayer = dynamic_cast<Slayer*>(pTargetCreature);
								EnemyLevel = pSlayer->getHighestSkillDomainLevel();
							}
							else if (pTargetCreature->isOusters() )
							{
								Ousters* pOusters = dynamic_cast<Ousters*>(pTargetCreature);
								EnemyLevel = pOusters->getLevel();
							}
							else if (pTargetCreature->isMonster() )
							{
								Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature);
								EnemyLevel = pMonster->getLevel();
							}

							// min : 20, max : 100
							int hitRatio = max(20, 50 + pVampire->getLevel() - EnemyLevel + HitBonus);
							bHitRoll = (rand()%100) < hitRatio;

							if (bPK && bRaceCheck && bZoneLevelCheck && bHitRoll)
							{
								Damage_t Damage = 0;
								bool bForceKnockback = rand() & 1;

								Damage += computeMagicDamage(pTargetCreature, output.Damage, SkillType, true, pVampire);

								ObjectID_t targetObjectID = pTargetCreature->getObjectID();
								cList.push_back(pTargetCreature);

								_GCSkillToTileOK1.addCListElement(targetObjectID);
								_GCSkillToTileOK2.addCListElement(targetObjectID);
								_GCSkillToTileOK5.addCListElement(targetObjectID);

								// 일단 맞는 놈이 받을 패킷은 널 상태로 한 채로, 데미지를 준다.
								setDamage(pTargetCreature, Damage, pVampire, SkillType, NULL, &_GCSkillToTileOK1);
								computeAlignmentChange(pTargetCreature, Damage, pVampire, NULL, &_GCSkillToTileOK1);

								increaseAlignment(pVampire, pTargetCreature, _GCSkillToTileOK1);

								// 크리티컬 히트라면 상대방을 뒤로 물러나게 한다.
								if (bForceKnockback)
								{
									knockbackCreature(pZone, pTargetCreature, pVampire->getX(), pVampire->getY());
								}

								if (pTargetCreature->isDead())
								{
									int exp = computeCreatureExp(pTargetCreature, KILL_EXP);
									shareVampExp(pVampire, exp, _GCSkillToTileOK1);
								}
							}
						}
					}
				}
			}


			// 공격자의 아이템 내구성을 떨어뜨린다.
			decreaseDurability(pVampire, NULL, pSkillInfo, &_GCSkillToTileOK1, NULL);

			_GCSkillToTileOK1.setSkillType(SkillType);
			_GCSkillToTileOK1.setCEffectID(0);
			_GCSkillToTileOK1.setX(X);
			_GCSkillToTileOK1.setY(Y);
			_GCSkillToTileOK1.setRange(dir);
			_GCSkillToTileOK1.setDuration(0);

			_GCSkillToTileOK2.setObjectID(pVampire->getObjectID());
			_GCSkillToTileOK2.setSkillType(SkillType);
			_GCSkillToTileOK2.setX(X);
			_GCSkillToTileOK2.setY(Y);
			_GCSkillToTileOK2.setRange(dir);
			_GCSkillToTileOK2.setDuration(0);

			_GCSkillToTileOK5.setObjectID(pVampire->getObjectID());
			_GCSkillToTileOK5.setSkillType(SkillType);
			_GCSkillToTileOK5.setX(X);
			_GCSkillToTileOK5.setY(Y);
			_GCSkillToTileOK5.setRange(dir);
			_GCSkillToTileOK5.setDuration(0);

			pPlayer->sendPacket(&_GCSkillToTileOK1);

			// 이 기술에 의해 영향을 받는 놈들에게 패킷을 보내줘야 한다.
			for (list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++)
			{
				Creature * pTargetCreature = *itr;
				Assert(pTargetCreature != NULL);

				if (pTargetCreature->isPC())
				{
					_GCSkillToTileOK2.clearList();

					// HP의 변경사항을 패킷에다 기록한다.
					HP_t targetHP = 0;
					if (pTargetCreature->isSlayer())
					{
						targetHP = (dynamic_cast<Slayer*>(pTargetCreature))->getHP(ATTR_CURRENT);
					}
					else if (pTargetCreature->isVampire())
					{
						targetHP = (dynamic_cast<Vampire*>(pTargetCreature))->getHP(ATTR_CURRENT);
					}
					else if (pTargetCreature->isOusters())
					{
						targetHP = (dynamic_cast<Ousters*>(pTargetCreature))->getHP(ATTR_CURRENT);
					}

					_GCSkillToTileOK2.addShortData(MODIFY_CURRENT_HP, targetHP);

					// 아이템의 내구력을 떨어뜨린다.
					decreaseDurability(NULL, pTargetCreature, pSkillInfo, NULL, &_GCSkillToTileOK2);

					// 패킷을 보내준다.
					pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2);
				}
				else if (pTargetCreature->isMonster())
				{
					// 당근 적으로 인식한다.
					Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature);
					pMonster->addEnemy(pVampire);
				}
			}

			cList.push_back(pVampire);

			pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK5 , cList);

			// set Next Run Time
			pVampireSkillSlot->setRunTime(output.Delay);
		}
		else 
		{
			executeSkillFailNormal(pVampire, SkillType, NULL);
		}
	}
	catch (Throwable & t) 
	{
		executeSkillFailException(pVampire, SkillType);
	}

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

	__END_CATCH
}
Beispiel #3
0
void Avatar::handlePower(std::vector<ActionData> &action_queue) {
	bool blocking = false;

	for (unsigned i=0; i<action_queue.size(); i++) {
		ActionData &action = action_queue[i];
		const Power &power = powers->getPower(action.power);

		if (power.new_state == POWSTATE_BLOCK)
			blocking = true;

		if (action.power != 0 && (stats.cooldown_ticks == 0 || action.instant_item)) {
			FPoint target = action.target;

			// check requirements
			if ((stats.cur_state == AVATAR_ATTACK || stats.cur_state == AVATAR_HIT) && !action.instant_item)
				continue;
			if (!stats.canUsePower(power, action.power))
				continue;
			if (power.requires_los && !mapr->collider.line_of_sight(stats.pos.x, stats.pos.y, target.x, target.y))
				continue;
			if (power.requires_empty_target && !mapr->collider.is_empty(target.x, target.y))
				continue;
			if (hero_cooldown[action.power] > 0)
				continue;
			if (!powers->hasValidTarget(action.power, &stats, target))
				continue;

			// automatically target the selected enemy with melee attacks
			if (power.type == POWTYPE_FIXED && power.starting_pos == STARTING_POS_MELEE && enemy_pos.x != -1 && enemy_pos.y != -1) {
				target = enemy_pos;
			}

			// draw a target on the ground if we're attacking
			if (!power.buff && !power.buff_teleport && power.type != POWTYPE_TRANSFORM && power.new_state != POWSTATE_BLOCK) {
				if (target_anim) {
					target_pos = target;
					target_visible = true;
					target_anim->reset();
				}
				lock_cursor = true;
			}
			else {
				curs->setCursor(CURSOR_NORMAL);
			}

			if (power.new_state != POWSTATE_INSTANT) {
				current_power = action.power;
				act_target = target;
				attack_anim = power.attack_anim;
			}

			// is this a power that requires changing direction?
			if (power.face) {
				stats.direction = calcDirection(stats.pos, target);
			}

			switch (power.new_state) {
				case POWSTATE_ATTACK:	// handle attack powers
					stats.cur_state = AVATAR_ATTACK;
					break;

				case POWSTATE_BLOCK:	// handle blocking
					stats.cur_state = AVATAR_BLOCK;
					powers->activate(action.power, &stats, target);
					hero_cooldown[action.power] = power.cooldown;
					stats.refresh_stats = true;
					break;

				case POWSTATE_INSTANT:	// handle instant powers
					powers->activate(action.power, &stats, target);
					hero_cooldown[action.power] = power.cooldown;
					break;
			}
		}
	}

	stats.blocking = blocking;
}
Beispiel #4
0
//////////////////////////////////////////////////////////////////////
//
// ThunderFlash::execute()
//
//////////////////////////////////////////////////////////////////////
void ThunderFlash::execute(Slayer* pSlayer, ZoneCoord_t X, ZoneCoord_t Y, 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);

		// 무장하고 있는 무기가 널이거나, SWORD가 아니라면 사용할 수 없다.
		Item* pItem = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND);
		if (pItem == NULL || pItem->getItemClass() != Item::ITEM_CLASS_SWORD)
		{
			executeSkillFailException(pSlayer, getSkillType());
			//cout << "TID[" << Thread::self() << "]" << getSkillHandlerName() << " end" << endl;
			return;
		}

		bool bIncreaseExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND);

		GCSkillToTileOK1 _GCSkillToTileOK1;
		GCSkillToTileOK2 _GCSkillToTileOK2;
		GCSkillToTileOK5 _GCSkillToTileOK5;

		SkillType_t       SkillType  = pSkillSlot->getSkillType();
		SkillInfo*        pSkillInfo = g_pSkillInfoManager->getSkillInfo(SkillType);
		SkillDomainType_t DomainType = pSkillInfo->getDomainType();
		SkillLevel_t      SkillLevel = pSkillSlot->getExpLevel();

		int  RequiredMP  = (int)pSkillInfo->getConsumeMP();
		bool bManaCheck  = hasEnoughMana(pSlayer, RequiredMP);
		bool bTimeCheck  = verifyRunTime(pSkillSlot);
		bool bRangeCheck = verifyDistance(pSlayer, X, Y, pSkillInfo->getRange());

		// 마나가 있어야 하고, 시간과 거리 체크에 성공하고,
		if (bManaCheck && bTimeCheck && bRangeCheck)
		{
			// MP를 떨어뜨린다.
			decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1);

			// 좌표와 방향을 구한다.
			ZoneCoord_t myX = pSlayer->getX();
			ZoneCoord_t myY = pSlayer->getY();	
			Dir_t       dir = calcDirection(myX, myY, X, Y);

			SkillInput input(pSlayer, pSkillSlot);
			SkillOutput output;
			computeOutput(input, output);

			Damage_t SkillDamage = output.Damage;
			Damage_t Damage      = 0;
			bool     bHit        = false;

			Level_t maxEnemyLevel = 0;
			uint EnemyNum = 0;

			VSRect rect(1, 1, pZone->getWidth()-2, pZone->getHeight()-2);

			list<Creature*> cList;

			for (int count=0; count<4; count++)
			{
				int tileX = X + m_pThunderFlashMask[count].x;
				int tileY = Y + m_pThunderFlashMask[count].y;

				// 현재 타일이 존 내부이고, 안전지대가 아니라면, 맞을 확률이 있다.
				if (rect.ptInRect(tileX, tileY))
				{
					// 타일을 받아온다.
					Tile& tile = pZone->getTile(tileX, tileY);

					list<Creature*> targetList;
					if (tile.hasCreature(Creature::MOVE_MODE_WALKING))
					{
						Creature* pCreature = tile.getCreature(Creature::MOVE_MODE_WALKING);
						targetList.push_back(pCreature);
					}

					list<Creature*>::iterator itr = targetList.begin();
					for(; itr != targetList.end(); itr++)
					{
						Creature* pTargetCreature = (*itr);
						Assert(pTargetCreature != NULL);

						bool bMoveModeCheck  = (pTargetCreature->getMoveMode() == Creature::MOVE_MODE_WALKING) ? true : false;
						bool bHitRoll        = HitRoll::isSuccess(pSlayer, pTargetCreature, SkillLevel/2);
						//bool bCanHit        = canHit(pSlayer, pTargetCreature, SkillType);
						bool bCanHit         = true;
						bool bPK             = verifyPK(pSlayer, pTargetCreature);
						bool bRaceCheck      = pTargetCreature->isSlayer() || pTargetCreature->isNPC();
						bool bZoneLevelCheck = checkZoneLevelToHitTarget(pTargetCreature);

						if (bMoveModeCheck && bHitRoll && bCanHit && bPK && !bRaceCheck && bZoneLevelCheck)
						{
							CheckCrossCounter(pSlayer, pTargetCreature, Damage, pSkillInfo->getRange());

							bool bCriticalHit = false;

							Damage = computeDamage(pSlayer, pTargetCreature, SkillLevel/5, bCriticalHit) + SkillDamage;

							ObjectID_t targetObjectID = pTargetCreature->getObjectID();
							cList.push_back(pTargetCreature);

							_GCSkillToTileOK1.addCListElement(targetObjectID);
							_GCSkillToTileOK2.addCListElement(targetObjectID);
							_GCSkillToTileOK5.addCListElement(targetObjectID);

							// 일단 맞는 놈이 받을 패킷은 널 상태로 한 채로, 데미지를 준다.
							setDamage(pTargetCreature, Damage, pSlayer, SkillType, NULL, &_GCSkillToTileOK1);
							computeAlignmentChange(pTargetCreature, Damage, pSlayer, NULL, &_GCSkillToTileOK1);
							increaseAlignment(pSlayer, pTargetCreature, _GCSkillToTileOK1);

							// 크리티컬 히트라면 상대방을 뒤로 물러나게 한다.
							if (bCriticalHit)
							{
								knockbackCreature(pZone, pTargetCreature, pSlayer->getX(), pSlayer->getY());
							}

							// 슬레이어가 아닐 경우에만 맞은 것으로 간주한다.
							if (!pTargetCreature->isSlayer())
							{
								bHit = true;
								if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel();
								EnemyNum++;
							}
						}
					} //for (; itr != objectList.end(); itr++) 
				} // if (rect.ptInRect(tileX, tileY) && ...
			} // for (int count=0; count<3; count++)

			if (bHit)
			{
				if (bIncreaseExp)
				{
					shareAttrExp(pSlayer, Damage , 8, 1, 1, _GCSkillToTileOK1);
					increaseDomainExp(pSlayer, DomainType, pSkillInfo->getPoint(), _GCSkillToTileOK1, maxEnemyLevel, EnemyNum);
					increaseSkillExp(pSlayer, DomainType,  pSkillSlot, pSkillInfo, _GCSkillToTileOK1);
				}
			}

			// 공격자 아이템 내구성 떨어트림.
			decreaseDurability(pSlayer, NULL, pSkillInfo, &_GCSkillToTileOK1, NULL);

			_GCSkillToTileOK1.setSkillType(SkillType);
			_GCSkillToTileOK1.setCEffectID(CEffectID);
			_GCSkillToTileOK1.setX(X);
			_GCSkillToTileOK1.setY(Y);
			_GCSkillToTileOK1.setRange(dir);
			_GCSkillToTileOK1.setDuration(0);
		
			_GCSkillToTileOK2.setObjectID(pSlayer->getObjectID());
			_GCSkillToTileOK2.setSkillType(SkillType);
			_GCSkillToTileOK2.setX(X);
			_GCSkillToTileOK2.setY(Y);
			_GCSkillToTileOK2.setRange(dir);
			_GCSkillToTileOK2.setDuration(0);
		
			_GCSkillToTileOK5.setObjectID(pSlayer->getObjectID());
			_GCSkillToTileOK5.setSkillType(SkillType);
			_GCSkillToTileOK5.setX(X);
			_GCSkillToTileOK5.setY(Y);
			_GCSkillToTileOK5.setRange(dir);
			_GCSkillToTileOK5.setDuration(0);
		
			pPlayer->sendPacket(&_GCSkillToTileOK1);
		
			// 이 기술에 의해 영향을 받는 놈들에게 패킷을 보내줘야 한다.
			for (list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++)
			{
				Creature * pTargetCreature = *itr;
				Assert(pTargetCreature != NULL);

				if (pTargetCreature->isPC())
				{
					_GCSkillToTileOK2.clearList();

					// HP의 변경사항을 패킷에다 기록한다.
					HP_t targetHP = 0;
					if (pTargetCreature->isSlayer()) targetHP = (dynamic_cast<Slayer*>(pTargetCreature))->getHP(ATTR_CURRENT);
					else if (pTargetCreature->isVampire()) targetHP = (dynamic_cast<Vampire*>(pTargetCreature))->getHP(ATTR_CURRENT);
					_GCSkillToTileOK2.addShortData(MODIFY_CURRENT_HP, targetHP);

					// 아이템의 내구력을 떨어뜨린다.
					decreaseDurability(NULL, pTargetCreature, pSkillInfo, NULL, &_GCSkillToTileOK2);

					// 패킷을 보내준다.
					pTargetCreature->getPlayer()->sendPacket(&_GCSkillToTileOK2);
				}
				else if (pTargetCreature->isMonster())
				{
					// 당근 적으로 인식한다.
					Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature);
					pMonster->addEnemy(pSlayer);
				}
			}

			cList.push_back(pSlayer);

			pZone->broadcastPacket(myX, myY, &_GCSkillToTileOK5 , cList);

			// set Next Run Time
			pSkillSlot->setRunTime(output.Delay);
		} 
		else 
		{
			executeSkillFailNormal(pSlayer, getSkillType(), NULL);
		}
	} 
	catch (Throwable & t) 
	{
		executeSkillFailException(pSlayer, getSkillType());
	}

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

	__END_CATCH
}
Beispiel #5
0
unsigned char calcDirection(const FPoint &src, const FPoint &dst) {
	return calcDirection(src.x, src.y, dst.x, dst.y);
}
/**
 * Check state changes related to movement
 */
void BehaviorStandard::checkMove() {

	// dying enemies can't move
	if (e->stats.cur_state == ENEMY_DEAD || e->stats.cur_state == ENEMY_CRITDEAD) return;

	// stunned enemies can't act
	if (e->stats.effects.stun) return;

	// handle not being in combat and (not patrolling waypoints or waiting at waypoint)
	if (!e->stats.hero_ally && !e->stats.in_combat && (e->stats.waypoints.empty() || e->stats.waypoint_pause_ticks > 0) && (!e->stats.wander || e->stats.wander_pause_ticks > 0)) {

		if (e->stats.cur_state == ENEMY_MOVE) {
			e->newState(ENEMY_STANCE);
		}

		// currently enemies only move while in combat or patrolling
		return;
	}

	// clear current space to allow correct movement
	mapr->collider.unblock(e->stats.pos.x, e->stats.pos.y);

	// update direction
	if (e->stats.facing) {
		if (++e->stats.turn_ticks > e->stats.turn_delay) {

			// if blocked, face in pathfinder direction instead
			if (!mapr->collider.line_of_movement(e->stats.pos.x, e->stats.pos.y, pc->stats.pos.x, pc->stats.pos.y, e->stats.movement_type)) {

				// if a path is returned, target first waypoint

				bool recalculate_path = false;

				//if theres no path, it needs to be calculated
				if(path.empty())
					recalculate_path = true;

				//if the target moved more than 1 tile away, recalculate
				if(calcDist(map_to_collision(prev_target), map_to_collision(pursue_pos)) > 1)
					recalculate_path = true;

				//if a collision ocurred then recalculate
				if(collided)
					recalculate_path = true;

				//add a 5% chance to recalculate on every frame. This prevents reclaulating lots of entities in the same frame
				chance_calc_path += 5;

				if(percentChance(chance_calc_path))
					recalculate_path = true;

				//dont recalculate if we were blocked and no path was found last time
				//this makes sure that pathfinding calculation is not spammed when the target is unreachable and the entity is as close as its going to get
				if(!path_found && collided && !percentChance(chance_calc_path))
					recalculate_path = false;
				else//reset the collision flag only if we dont want the cooldown in place
					collided = false;

				prev_target = pursue_pos;

				// target first waypoint
				if(recalculate_path) {
					chance_calc_path = -100;
					path.clear();
					path_found = mapr->collider.compute_path(e->stats.pos, pursue_pos, path, e->stats.movement_type);
				}

				if(!path.empty()) {
					pursue_pos = path.back();

					//if distance to node is lower than a tile size, the node is going to be passed and can be removed
					if(calcDist(e->stats.pos, pursue_pos) <= 64)
						path.pop_back();
				}
			}
			else {
				path.clear();
			}

			if(fleeing)
				e->stats.direction = calcDirection(pursue_pos, e->stats.pos);
			else
				e->stats.direction = calcDirection(e->stats.pos, pursue_pos);
			e->stats.turn_ticks = 0;
		}
	}

	// try to start moving
	if (e->stats.cur_state == ENEMY_STANCE) {
		checkMoveStateStance();
	}

	// already moving
	else if (e->stats.cur_state == ENEMY_MOVE) {
		checkMoveStateMove();
	}

	// if patrolling waypoints and has reached a waypoint, cycle to the next one
	if (!e->stats.waypoints.empty()) {
		FPoint waypoint = e->stats.waypoints.front();
		FPoint pos = e->stats.pos;
		// if the patroller is close to the waypoint
		if (fabs(waypoint.x - pos.x) < 0.5 && fabs(waypoint.y - pos.y) < 0.5) {
			e->stats.waypoints.pop();
			e->stats.waypoints.push(waypoint);
			e->stats.waypoint_pause_ticks = e->stats.waypoint_pause;
		}
	}

	// if a wandering enemy reaches its destination early, reset wander_ticks
	if (e->stats.wander) {
		FPoint pos = e->stats.pos;
		if (fabs(pursue_pos.x - pos.x) < 0.5 && fabs(pursue_pos.y - pos.y) < 0.5) {
			e->stats.wander_ticks = 0;
		}
		if (e->stats.wander_ticks == 0 && e->stats.wander_pause_ticks == 0) {
			e->stats.wander_pause_ticks = rand() % 60;
		}
	}

	// re-block current space to allow correct movement
	mapr->collider.block(e->stats.pos.x, e->stats.pos.y, e->stats.hero_ally);

}
Beispiel #7
0
//////////////////////////////////////////////////////////////////////////////
// 슬레이어 타일 핸들러 - AR이나 SMG를 들고 있을 경우
//////////////////////////////////////////////////////////////////////////////
void MoleShot::ARSMGexecute(Slayer* pSlayer, ZoneCoord_t X, ZoneCoord_t Y, SkillSlot* pSkillSlot, CEffectID_t CEffectID)
	throw(Error)
{
	__BEGIN_TRY

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

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

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

		GCSkillToTileOK1 _GCSkillToTileOK1;
		GCSkillToTileOK2 _GCSkillToTileOK2;
		GCSkillToTileOK3 _GCSkillToTileOK3;
		GCSkillToTileOK4 _GCSkillToTileOK4;
		GCSkillToTileOK5 _GCSkillToTileOK5;

		SkillInfo*        pSkillInfo = g_pSkillInfoManager->getSkillInfo(getSkillType());
		SkillDomainType_t DomainType = pSkillInfo->getDomainType();
		Level_t 	      SkillLevel = pSkillSlot->getExpLevel();

		Item* pWeapon = pSlayer->getWearItem(Slayer::WEAR_RIGHTHAND);
		Assert(pWeapon != NULL);

		bool bIncreaseExp = pSlayer->isRealWearingEx(Slayer::WEAR_RIGHTHAND);
 
		int  RequiredMP   = (int)pSkillInfo->getConsumeMP();
		bool bManaCheck   = hasEnoughMana(pSlayer, RequiredMP);
		bool bTimeCheck   = verifyRunTime(pSkillSlot);
		bool bRangeCheck  = verifyDistance(pSlayer, X, Y, pWeapon->getRange());
		bool bBulletCheck = (getRemainBullet(pWeapon) > 0) ? true : false;

		// 총알 숫자는 무조건 떨어뜨린다.
		Bullet_t RemainBullet = 0;
		if (bBulletCheck)
		{
			decreaseBullet(pWeapon);
			// 한발쓸때마다 저장할 필요 없다. by sigi. 2002.5.9
			// pWeapon->save(pSlayer->getName(), STORAGE_GEAR, 0, Slayer::WEAR_RIGHTHAND, 0);
			RemainBullet = getRemainBullet(pWeapon);
		}

		// 데미지, 투힛 보너스, 좌표와 방향을 구한다.
		int         ToHitBonus    = 0;
		int         DamageBonus   = 0;
		int         ToHitPenalty  = 0;
		int         DamagePenalty = 0;
		ZoneCoord_t myX           = pSlayer->getX();
		ZoneCoord_t myY           = pSlayer->getY();	
		Dir_t       dir           = calcDirection(myX, myY, X, Y);
		bool        bHit          = false; // 한번이라도 맞았는가를 저장하기 위한 변수
		Damage_t    Damage        = 0;     // 마지막으로 입힌 데미지를 저장하기 위한 변수

		// AR이나 SMG일 경우에는 2부터 시작해서 4까지의 splash 데미지를 입힌다.
		int Splash = 1 + pSkillSlot->getExpLevel()/30 + 1;

		if (bManaCheck && bTimeCheck && bRangeCheck && bBulletCheck)
		{
			decreaseMana(pSlayer, RequiredMP, _GCSkillToTileOK1);

			SkillInput input(pSlayer, pSkillSlot);
			SkillOutput output;
			computeOutput(input, output);

			// 음수 값이 돌아온다.
			ToHitPenalty  = getPercentValue(pSlayer->getToHit(), output.ToHit);

			list<Creature*> cList;
			list<Creature*> creatureList;
			getSplashVictims(pZone, X, Y, Creature::CREATURE_CLASS_MAX, creatureList, Splash);

			Level_t maxEnemyLevel = 0;
			uint EnemyNum = 0;

			list<Creature*>::iterator itr = creatureList.begin();
			for (; itr != creatureList.end(); itr++)
			{
				Creature* pTargetCreature = (*itr);
				Assert(pTargetCreature != NULL);

				ToHitBonus  = computeArmsWeaponToHitBonus(pWeapon, myX, myY, pTargetCreature->getX(), pTargetCreature->getY());
				DamageBonus = computeArmsWeaponDamageBonus(pWeapon, myX, myY, pTargetCreature->getX(), pTargetCreature->getY());

				bool bInvokerCheck   = (pTargetCreature->getObjectID() == pSlayer->getObjectID()) ? true : false;
				bool bRaceCheck      = pTargetCreature->isSlayer() || pTargetCreature->isNPC();
				bool bHitRoll        = HitRoll::isSuccess(pSlayer, pTargetCreature, ToHitPenalty + ToHitBonus);
				bool bPK             = verifyPK(pSlayer, pTargetCreature);
				bool bZoneLevelCheck = checkZoneLevelToHitTarget(pTargetCreature);

				if (pTargetCreature->isFlag(Effect::EFFECT_CLASS_NO_DAMAGE )
					|| pTargetCreature->isFlag(Effect::EFFECT_CLASS_COMA )
				)
				{
					bHitRoll = false;
				}

				if (!bInvokerCheck && !bRaceCheck && bHitRoll && bPK && bZoneLevelCheck)
				{
					bool bCriticalHit = false;

					// 데미지를 계산해서 페널티를 가한다.
					// 보너스는 멀티샷 페널티 때문에 음수가 될 수도 있다.
					Damage        = computeDamage(pSlayer, pTargetCreature, SkillLevel/5, bCriticalHit);
					DamagePenalty = getPercentValue(Damage, output.Damage);
					Damage        = max(0, Damage + DamagePenalty + DamageBonus);

					// 메인 타겟을 제외하고는, 스플래시 데미지를 입는데,
					// 스플래시 데미지는 일반 데미지의 50%다.
					if (pTargetCreature->getX() != X || pTargetCreature->getY() != Y)
					{
						Damage = Damage/2;
					}

					// 소드웨이브와는 달리 크로스 카운터 체크는 하지 않는다.
					ObjectID_t targetObjectID = pTargetCreature->getObjectID();
					cList.push_back(pTargetCreature);
					_GCSkillToTileOK1.addCListElement(targetObjectID);
					_GCSkillToTileOK2.addCListElement(targetObjectID);
					_GCSkillToTileOK5.addCListElement(targetObjectID);
							
					setDamage(pTargetCreature, Damage, pSlayer, getSkillType(), NULL, &_GCSkillToTileOK1);
					computeAlignmentChange(pTargetCreature, Damage, pSlayer, NULL, &_GCSkillToTileOK1);

					// 크리티컬 히트라면 상대방을 뒤로 물러나게 한다.
					if (bCriticalHit)
					{
						knockbackCreature(pZone, pTargetCreature, pSlayer->getX(), pSlayer->getY());
					}

					// 슬레이어가 아닐 경우에만 맞춘 걸로 간주한다.
					if (!pTargetCreature->isSlayer())
					{
						bHit = true;
						if (maxEnemyLevel < pTargetCreature->getLevel() ) maxEnemyLevel = pTargetCreature->getLevel();
						EnemyNum++;
					}
				}
			}

			if (bHit)
			{
				if (bIncreaseExp)
				{
					increaseDomainExp(pSlayer, DomainType , pSkillInfo->getPoint(), _GCSkillToTileOK1, maxEnemyLevel, EnemyNum);
					shareAttrExp(pSlayer, Damage , 1, 8, 1, _GCSkillToTileOK1);
				}
				increaseSkillExp(pSlayer, DomainType,  pSkillSlot, pSkillInfo, _GCSkillToTileOK1);
			}

			_GCSkillToTileOK1.addShortData(MODIFY_BULLET, RemainBullet);

			decreaseDurability(pSlayer, NULL, pSkillInfo, &_GCSkillToTileOK1, NULL);

			_GCSkillToTileOK1.setSkillType(getSkillType());
			_GCSkillToTileOK1.setCEffectID(CEffectID);
			_GCSkillToTileOK1.setX(X);
			_GCSkillToTileOK1.setY(Y);
			_GCSkillToTileOK1.setRange(dir);
			_GCSkillToTileOK1.setDuration(0);
		
			_GCSkillToTileOK2.setObjectID(pSlayer->getObjectID());
			_GCSkillToTileOK2.setSkillType(getSkillType());
			_GCSkillToTileOK2.setX(X);
			_GCSkillToTileOK2.setY(Y);
			_GCSkillToTileOK2.setRange(dir);
			_GCSkillToTileOK2.setDuration(0);

			_GCSkillToTileOK3.setObjectID(pSlayer->getObjectID());
			_GCSkillToTileOK3.setSkillType(getSkillType());
			_GCSkillToTileOK3.setX(X);
			_GCSkillToTileOK3.setY(Y);

			_GCSkillToTileOK4.setSkillType(getSkillType());
			_GCSkillToTileOK4.setX(X);
			_GCSkillToTileOK4.setY(Y);
			_GCSkillToTileOK4.setDuration(0);
			_GCSkillToTileOK4.setRange(dir);
		
			_GCSkillToTileOK5.setObjectID(pSlayer->getObjectID());
			_GCSkillToTileOK5.setSkillType(getSkillType());
			_GCSkillToTileOK5.setX(X);
			_GCSkillToTileOK5.setY(Y);
			_GCSkillToTileOK5.setRange(dir);
			_GCSkillToTileOK5.setDuration(0);
			
			pPlayer->sendPacket(&_GCSkillToTileOK1);
		
			// 이 기술에 의해 영향을 받는 놈들에게 패킷을 보내줘야 한다.
			for(list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); itr++)
			{
				Creature* pTargetCreature = *itr;
				Assert(pTargetCreature != NULL);

				if (pTargetCreature->isPC())
				{
					_GCSkillToTileOK2.clearList();

					HP_t targetHP = 0;
					if (pTargetCreature->isSlayer())
					{
						targetHP = (dynamic_cast<Slayer*>(pTargetCreature))->getHP();
					}
					else if (pTargetCreature->isVampire())
					{
						targetHP = (dynamic_cast<Vampire*>(pTargetCreature))->getHP();
					}

					_GCSkillToTileOK2.addShortData(MODIFY_CURRENT_HP, targetHP);

					// 아이템의 내구력을 떨어뜨린다.
					decreaseDurability(NULL, pTargetCreature, pSkillInfo, NULL, &_GCSkillToTileOK2);

					// 패킷을 보내준다.
					Player* pPlayer = pTargetCreature->getPlayer();
					Assert(pPlayer != NULL);
					pPlayer->sendPacket(&_GCSkillToTileOK2);
				}
				else if (pTargetCreature->isMonster())
				{
					// 당근 적으로 인식한다.
					Monster* pMonster = dynamic_cast<Monster*>(pTargetCreature);
					pMonster->addEnemy(pSlayer);
				}
			}

			cList.push_back(pSlayer);

			cList = pZone->broadcastSkillPacket(myX, myY, X, Y, &_GCSkillToTileOK5, cList);

			pZone->broadcastPacket(myX, myY,  &_GCSkillToTileOK3 , cList);
			pZone->broadcastPacket(X, Y,  &_GCSkillToTileOK4 , cList);

			pSkillSlot->setRunTime(output.Delay);
		} 
		else 
		{
			executeSkillFailNormalWithGun(pSlayer, getSkillType(), NULL, RemainBullet);
		}
	} 
	catch (Throwable & t) 
	{
		executeSkillFailException(pSlayer, getSkillType());
	}

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

	__END_CATCH
}
Beispiel #8
0
/**
 * Apply basic power info to a new hazard.
 *
 * This can be called several times to combine powers.
 * Typically done when a base power can be modified by equipment
 * (e.g. ammo type affects the traits of powers that shoot)
 *
 * @param power_index The activated power ID
 * @param src_stats The StatBlock of the power activator
 * @param target Aim position in map coordinates
 * @param haz A newly-initialized hazard
 */
void PowerManager::initHazard(int power_index, StatBlock *src_stats, Point target, Hazard *haz) {

	//the hazard holds the statblock of its source
	haz->src_stats = src_stats;

	// Hazard attributes based on power source
	haz->crit_chance = src_stats->crit;
	haz->accuracy = src_stats->accuracy;
	
	// Hazard damage depends on equipped weapons and the power's optional damage_multiplier
	if (powers[power_index].base_damage == BASE_DAMAGE_MELEE) {
		haz->dmg_min = src_stats->dmg_melee_min;
		haz->dmg_max = src_stats->dmg_melee_max;
	}
	else if (powers[power_index].base_damage == BASE_DAMAGE_RANGED) {
		haz->dmg_min = src_stats->dmg_ranged_min;
		haz->dmg_max = src_stats->dmg_ranged_max;
	}
	else if (powers[power_index].base_damage == BASE_DAMAGE_MENT) {
		haz->dmg_min = src_stats->dmg_ment_min;
		haz->dmg_max = src_stats->dmg_ment_max;
	}
	//apply the multiplier
	haz->dmg_min = ceil(haz->dmg_min * powers[power_index].damage_multiplier / 100.0);
	haz->dmg_max = ceil(haz->dmg_max * powers[power_index].damage_multiplier / 100.0);
	
	// Only apply stats from powers that are not defaults
	// If we do this, we can init with multiple power layers
	// (e.g. base spell plus weapon type)
	
	if (powers[power_index].gfx_index != -1) {
		haz->sprites = gfx[powers[power_index].gfx_index];
	}
	if (powers[power_index].rendered) {
		haz->rendered = powers[power_index].rendered;
	}
	if (powers[power_index].lifespan != 0) {
		haz->lifespan = powers[power_index].lifespan;
	}
	if (powers[power_index].frame_loop != 1) {
		haz->frame_loop = powers[power_index].frame_loop;
	}
	if (powers[power_index].frame_duration != 1) {
		haz->frame_duration = powers[power_index].frame_duration;
	}
	if (powers[power_index].frame_size.x != 0) {
		haz->frame_size.x = powers[power_index].frame_size.x;
	}
	if (powers[power_index].frame_size.y != 0) {
		haz->frame_size.y = powers[power_index].frame_size.y;
	}
	if (powers[power_index].frame_offset.x != 0) {
		haz->frame_offset.x = powers[power_index].frame_offset.x;
	}
	if (powers[power_index].frame_offset.y != 0) {
		haz->frame_offset.y = powers[power_index].frame_offset.y;
	}
	if (powers[power_index].directional) {
		haz->direction = calcDirection(src_stats->pos.x, src_stats->pos.y, target.x, target.y);
	}
	else if (powers[power_index].visual_random != 0) {
		haz->visual_option = rand() % powers[power_index].visual_random;
	}
	else if (powers[power_index].visual_option != 0) {
		haz->visual_option = powers[power_index].visual_option;
	}
	haz->floor = powers[power_index].floor;
	if (powers[power_index].speed > 0) {
		haz->base_speed = powers[power_index].speed;
	}
	if (powers[power_index].complete_animation) {
		haz->complete_animation = true;
	}
	
	// combat traits
	if (powers[power_index].no_attack) {
		haz->active = false;
	}
	if (powers[power_index].multitarget) {
		haz->multitarget = true;
	}
	if (powers[power_index].active_frame != -1) {
		haz->active_frame = powers[power_index].active_frame;
	}
	if (powers[power_index].radius != 0) {
		haz->radius = powers[power_index].radius;
	}
	if (powers[power_index].trait_armor_penetration) {
		haz->trait_armor_penetration = true;
	}
	haz->trait_crits_impaired = powers[power_index].trait_crits_impaired;
	if (powers[power_index].trait_elemental) {
		haz->trait_elemental = powers[power_index].trait_elemental;
	}
	
	// status effect durations
	// durations stack when combining powers (e.g. base power and weapon/ammo type)
	haz->bleed_duration += powers[power_index].bleed_duration;
	haz->stun_duration += powers[power_index].stun_duration;
	haz->slow_duration += powers[power_index].slow_duration;
	haz->immobilize_duration += powers[power_index].immobilize_duration;
	// steal effects
	haz->hp_steal += powers[power_index].hp_steal;
	haz->mp_steal += powers[power_index].mp_steal;
	
	// hazard starting position
	if (powers[power_index].starting_pos == STARTING_POS_SOURCE) {
		haz->pos.x = (float)src_stats->pos.x;
		haz->pos.y = (float)src_stats->pos.y;
	}
	else if (powers[power_index].starting_pos == STARTING_POS_TARGET) {
		haz->pos.x = (float)target.x;
		haz->pos.y = (float)target.y;	
	}
	else if (powers[power_index].starting_pos == STARTING_POS_MELEE) {
		haz->pos = calcVector(src_stats->pos, src_stats->direction, src_stats->melee_range);
	}
	
	// pre/post power effects
	if (powers[power_index].post_power != -1) {
		haz->post_power = powers[power_index].post_power;
	}
	if (powers[power_index].wall_power != -1) {
		haz->wall_power = powers[power_index].wall_power;
	}
	
	// if equipment has special powers, apply it here (if it hasn't already been applied)
	if (!haz->equipment_modified && powers[power_index].allow_power_mod) {
		if (powers[power_index].base_damage == BASE_DAMAGE_MELEE && src_stats->melee_weapon_power != -1) {
			haz->equipment_modified = true;
			initHazard(src_stats->melee_weapon_power, src_stats, target, haz);
		}
		else if (powers[power_index].base_damage == BASE_DAMAGE_MENT && src_stats->mental_weapon_power != -1) {
			haz->equipment_modified = true;
			initHazard(src_stats->mental_weapon_power, src_stats, target, haz);
		}
		else if (powers[power_index].base_damage == BASE_DAMAGE_RANGED && src_stats->ranged_weapon_power != -1) {
			haz->equipment_modified = true;
			initHazard(src_stats->ranged_weapon_power, src_stats, target, haz);
		}		
	}
}
Beispiel #9
0
void Creep::update(float deltaTime)
{
    m_fStateTime += deltaTime;
    
    m_healthBarFrame = m_health * 16 / m_maxHealth - 1;
    m_healthBarFrame = m_healthBarFrame < 0 ? 0 : m_healthBarFrame;
    
    m_timeToShowHealthBar -= deltaTime;
    
    if (FlagUtil::isFlagSet(m_creepCondition, ELECTRIFIED))
    {
        if (m_electrifiedTime > 0)
        {
            m_electrifiedTime -= deltaTime;
        }
        else
        {
            m_creepCondition = FlagUtil::removeFlag(m_creepCondition, ELECTRIFIED);
            m_speed = m_initialSpeed;
            
            if (FlagUtil::isFlagSet(m_creepCondition, FROZEN))
            {
                m_speed /= 3;
            }
        }
    }
    
    if (FlagUtil::isFlagSet(m_creepCondition, POISONED))
    {
        if (m_poisonedTime > 0)
        {
            bool isFrozen = FlagUtil::isFlagSet(m_creepCondition, FROZEN);
            
            m_poisonedTime -= deltaTime;
            m_poisonTime += deltaTime;
            
            while (m_poisonTime > TIME_FOR_POISON_DAMAGE)
            {
                m_poisonTime -= TIME_FOR_POISON_DAMAGE;
                takeDamage(m_poisonDamage, Damage_Type::ACID);
            }
            
            if (m_isGrowingDueToPoison)
            {
                m_fWidth += deltaTime * (isFrozen ? 0.1f : 0.5f);
                m_fHeight += deltaTime * (isFrozen ? 0.1f : 0.5f);
                if (m_fWidth > m_maxSize)
                {
                    m_fWidth = m_maxSize;
                    m_fHeight = m_maxSize;
                    m_isGrowingDueToPoison = false;
                }
            }
            else
            {
                m_fWidth -= deltaTime * (isFrozen ? 0.1f : 0.5f);
                m_fHeight -= deltaTime * (isFrozen ? 0.1f : 0.5f);
                if (m_fWidth < m_halfSize)
                {
                    m_fWidth = m_halfSize;
                    m_fHeight = m_halfSize;
                    m_isGrowingDueToPoison = true;
                }
            }
        }
        else
        {
            m_creepCondition = FlagUtil::removeFlag(m_creepCondition, POISONED);
            m_fWidth = m_defaultSize;
            m_fHeight = m_defaultSize;
        }
        
        resetBounds(m_fWidth * SIZE_TO_BOUNDS_RATIO, m_fHeight * SIZE_TO_BOUNDS_RATIO);
    }
    
    if (FlagUtil::isFlagSet(m_creepCondition, FROZEN))
    {
        if (m_frozenTime > 0)
        {
            m_frozenTime -= deltaTime;
            m_fRed += m_frozenRecoveryRate * deltaTime;
            m_fGreen = m_fRed;
        }
        else
        {
            thaw();
        }
    }
    else if (FlagUtil::isFlagSet(m_creepCondition, ON_FIRE))
    {
        if (m_burnTime > 0)
        {
            m_burnTime -= deltaTime;
        }
        else
        {
            m_creepCondition = FlagUtil::removeFlag(m_creepCondition, ON_FIRE);
            m_creepCondition = FlagUtil::setFlag(m_creepCondition, FIRE_RECOVERY);
        }
    }
    else if (FlagUtil::isFlagSet(m_creepCondition, FIRE_RECOVERY))
    {
        m_fRed += 1.5f * deltaTime;
        m_fGreen = m_fRed;
        m_fBlue = m_fRed;
        
        if (m_fRed > 1)
        {
            m_creepCondition = FlagUtil::removeFlag(m_creepCondition, FIRE_RECOVERY);
            resetColor();
        }
    }
    
    m_deltaX = m_velocity->getX() * deltaTime;
    m_deltaY = m_velocity->getY() * deltaTime;
    m_position->add(m_deltaX, m_deltaY);
    m_direction = calcDirection();
    updateBounds();
}
Beispiel #10
0
void Gps::update()
{
	float angle = 0.0;  /* 4msecごとの車体角度の変化量 (度) */
	float radius = 0.0; /* 4msecごとの車体の描く円の半径 */
	float el = 0.0; /* 4msec間のエンコーダー値の変化量(left) */
	float er = 0.0; /* 4msec間のエンコーダー値の変化量(right) */
	float currEl = 0.0; /* 現在のエンコーダー値(left) */
	float currEr = 0.0; /* 現在のエンコーダー値(right) */
	timeCounter++;
	
		
/*********   値取得   *********/
	/* エンコーダー値を取得 */
	motorL.setCount();
	motorR.setCount();
	currEl = motorL.getCount();
	currEr = motorR.getCount();
	
	/* 4msec間のエンコーダー値の変化量を計算 */
	el = currEl - prevEl;
	er = currEr - prevEr;
/********* 値取得終了 *********/
	
/********* 座標計算 ***********/
	angle = calcAngle(el, er); /* 曲がった角度を計算 */
	
	radius = calcRadius(el, angle); /* 走行体の描く円の半径を計算 */
	
	calcCoordinates(angle, radius, el); /* 座標の更新 */
	
	calcDirection(angle); /* 現在向いている方向の更新 */
/********* 座標計算終了 *******/

/******* prevEl,Erの更新 ******/
	prevEl = currEl;
	prevEr = currEr;
/**** prevEl,Erの更新の終了****/
	
/************ 座標補正 *****************/
	//lcd.clear();
	//lcd.putf("d", );
	//lcd .disp();
	/*
	if(timeCounter%50 !=0)
	{	
		xHistory += mXCoordinate;
		yHistory += mYCoordinate;
		mDirectionHistory += mDirection;
	}
	else
	{
		xHistory = (xHistory+mXCoordinate)/timeCounter;
		yHistory = (yHistory + mYCoordinate)/timeCounter;
		mDirectionHistory = (mDirectionHistory + mDirection)/timeCounter;
		if(!gAngleTraceFlag)
			adjustPosition(xHistory, yHistory, mDirectionHistory);
		xHistory = 0;
		yHistory = 0;
		mDirectionHistory = 0;
		timeCounter = 0;

	}
	*/
	prevEl = currEl;
	prevEr = currEr;
}