Esempio n. 1
0
/*!
	This handles if a character actually tries to walk (NPC & Player)
*/
bool cMovement::Walking( P_CHAR pChar, Q_UINT8 dir, Q_UINT8 sequence )
{
	if ( !pChar )
		return false;

	// Scripting
	if ( pChar->onWalk( dir, sequence ) )
		return false;

	P_PLAYER player = dynamic_cast<P_PLAYER>( pChar );

	// Is the sequence in order ?
	if ( player && player->socket() && !verifySequence( player->socket(), sequence ) )
		return false;

	// If checking for weight is more expensive, shouldn't we check for frozen first?
	if ( pChar->isFrozen() )
	{
		if ( player && player->socket() )
			player->socket()->denyMove( sequence );
		return false;
	}

	// save our original location before we even think about moving
	const Coord oldpos( pChar->pos() );

	// If the Direction we're moving to is different from our current direction
	// We're turning and NOT moving into a specific direction
	// Clear the running flag here (!)
	// If the direction we're moving is already equal to our current direction
	bool running = dir & 0x80;
	dir = dir & 0x7; // Remove all unneeded stuff

	pChar->setRunning( running );

	bool turning = dir != pChar->direction();

	// This happens if we're moving
	if ( !turning )
	{
		// Note: Do NOT use the copy constructor as it'll create a reference
		Coord newCoord = calcCoordFromDir( dir, pChar->pos() );

		// Check if the stamina parameters
		if ( player && !consumeStamina( player, running ) )
		{
			if ( player->socket() )
				player->socket()->denyMove( sequence );
			return false;
		}

		// Check if we're going to collide with characters
		if ( player )
		{
			// Player vs characters
			if ( player->socket() && player->pos().map == 0 && !player->account()->isStaff() )
			{
				// Currently hard-limiting collisions to Felucca; this should be a server option!
				MapCharsIterator charCollisions = MapObjects::instance()->listCharsAtCoord( newCoord );
				for ( P_CHAR them = charCollisions.first(); them; them = charCollisions.next() )
				{
					if ( them == player )
						continue;

					P_PLAYER otherplayer = dynamic_cast<P_PLAYER>( them );
					if ( otherplayer && otherplayer->account()->isStaff() )
						continue; // no collisions against the staff

					if ( wpAbs<SI08>( newCoord.z - them->pos().z ) < P_M_MAX_Z_CLIMB )
					{
						// to push another char we must have maximum stamina
						if ( player->stamina() >= player->maxStamina() )
						{
							player->socket()->clilocMessage( them->isHidden() ? 1019043 : 1019042 );
							player->setStamina( player->stamina() - 10 );
							break;
						}
						else
						{
							player->socket()->denyMove( sequence );
							return false;
						}
					}
				}
			}
		}
		else
		{
			// NPC vs characters
			P_NPC npc = dynamic_cast<P_NPC>( pChar );
			if ( npc && CheckForCharacterAtXYZ( pChar, newCoord ) )
			{
				npc->clearPath();
				return false;
			}
		}

		// Check if the char can move to those new coordinates
		// It is going to automatically calculate the new coords (!)
		if ( !mayWalk( pChar, newCoord ) )
		{
			if ( player && player->socket() )
				player->socket()->denyMove( sequence );
			return false;
		}
		else
		{
			if ( player && player->socket() )
				player->socket()->allowMove( sequence );
		}

		// We moved so let's update our location
		pChar->moveTo( newCoord );
		pChar->setStepsTaken( pChar->stepsTaken() + 1 );
		pChar->setLastMovement( Server::instance()->time() );
		checkStealth( pChar ); // Reveals the user if neccesary
	}
	else
	{
		if ( player && player->socket() )
			player->socket()->allowMove( sequence );
	}

	// do all of the following regardless of whether turning or moving i guess
	// set the player direction to contain only the cardinal direction bits
	pChar->setDirection( dir );

	Coord upperLeft = pChar->pos() - Coord( ( VISRANGE + 1 ), ( VISRANGE + 1 ) );
	Coord lowerRight = pChar->pos() + Coord( ( VISRANGE + 1 ), ( VISRANGE + 1 ) );

	MapCharsIterator ri = MapObjects::instance()->listCharsInRect( upperLeft, lowerRight );
	for ( P_CHAR observer = ri.first(); observer; observer = ri.next() )
	{
		if ( observer == pChar )
			continue;

		bool wasVisible = observer->pos().distance( oldpos ) < VISRANGE; // We were previously in range
		bool isVisible = pChar->dist( observer ) < VISRANGE; // We are now in range

		// If we are a player, send us new characters
		if ( player && player->socket() )
		{
			// Send the observer to us if he was previously not visible and came into range recently
			if ( !wasVisible && isVisible )
			{
				player->socket()->sendChar( observer );
			}
		}

		// Send our movement to the observer
		P_PLAYER otherplayer = dynamic_cast<P_PLAYER>( observer );

		if ( !otherplayer || !otherplayer->socket() )
		{
			continue; // Skip this character, it's a player.
			// TODO: OnSeePlayer, OnLoosePlayer
		}

		if ( wasVisible )
		{
			if ( isVisible )
			{
				otherplayer->socket()->updateChar( pChar ); // We walked inside the visible range
			}
			else
			{
				otherplayer->socket()->removeObject( pChar ); // We walked out of visible range
			}
		}
		else if ( isVisible )
		{
			otherplayer->socket()->sendChar( pChar ); // We walked into visible range
		}
	}

	// If we really moved handle teleporters and new items
	if ( !turning )
	{
		handleItems( pChar, oldpos );
		handleMultis( pChar, oldpos );
		handleTeleporters( pChar, oldpos );
	}

	return true;
}
Esempio n. 2
0
/*!
	This handles if a character actually tries to walk (NPC & Player)
*/
bool cMovement::Walking( P_CHAR pChar, Q_UINT8 dir, Q_UINT8 sequence )
{
	if ( !pChar )
		return false;

	// Scripting
	if ( pChar->onWalk( dir, sequence ) )
		return false;

	/*	if( !isValidDirection( dir ) )
		{
			pChar->setPathNum( pChar->pathnum() + PATHNUM );
			return;
		}*/

	P_PLAYER player = dynamic_cast<P_PLAYER>( pChar );

	// Is the sequence in order ?
	if ( player && player->socket() && !verifySequence( player->socket(), sequence ) )
		return false;

	// If checking for weight is more expensive, shouldn't we check for frozen first?
	if ( pChar->isFrozen() )
	{
		if ( player && player->socket() )
			player->socket()->denyMove( sequence );
		return false;
	}

	// save our original location before we even think about moving
	const Coord_cl oldpos( pChar->pos() );

	// If the Direction we're moving to is different from our current direction
	// We're turning and NOT moving into a specific direction
	// Clear the running flag here (!)
	// If the direction we're moving is already equal to our current direction
	bool running = dir & 0x80;
	dir = dir & 0x7F; // Remove the running flag

	pChar->setRunning(running);

	bool turning = dir != pChar->direction();

	// This happens if we're moving
	if ( !turning )
	{
		// Note: Do NOT use the copy constructor as it'll create a reference
		Coord_cl newCoord = calcCoordFromDir( dir, pChar->pos() );

		// Check if the stamina parameters
		if ( player && !consumeStamina( player, running ) )
		{
			if ( player->socket() )
				player->socket()->denyMove( sequence );
			return false;
		}

		// Check for Characters in our way
		if ( !checkObstacles( pChar, newCoord, running ) )
		{
			if ( player && player->socket() )
				player->socket()->denyMove( sequence );
			return false;
		}

		// Check if the char can move to those new coordinates
		// It is going to automatically calculate the new coords (!)
		if ( !mayWalk( pChar, newCoord ) )
		{
			if ( player && player->socket() )
				player->socket()->denyMove( sequence );
			return false;
		}
		else
		{
			if ( player && player->socket() )
				player->socket()->allowMove( sequence );
		}

		// Check if we're going to collide with characters
		if ( !player && CheckForCharacterAtXYZ( pChar, newCoord ) )
		{
			P_NPC npc = dynamic_cast<P_NPC>( pChar );
			if ( npc )
			{
				npc->clearPath();
			}
			return false;
		}

		// We moved so let's update our location
		pChar->moveTo( newCoord );
		pChar->setStepsTaken( pChar->stepsTaken() + 1 );
		pChar->setLastMovement( Server::instance()->time() );
		checkStealth( pChar ); // Reveals the user if neccesary
	}
	else
	{
		if ( player && player->socket() )
			player->socket()->allowMove( sequence );
	}

	// do all of the following regardless of whether turning or moving i guess
	// set the player direction to contain only the cardinal direction bits
	pChar->setDirection( dir );

	RegionIterator4Chars ri( pChar->pos() );
	for ( ri.Begin(); !ri.atEnd(); ri++ )
	{
		P_CHAR observer = ri.GetData();

		if ( observer == pChar )
		{
			continue;
		}

		unsigned int distance = observer->pos().distance( oldpos );

		// If we are a player, send us new characters
		if ( player && player->socket() )
		{
			if ( distance > player->visualRange() )
			{
				player->socket()->sendChar( observer ); // We were previously out of range.
			}
		}

		// Send our movement to the observer
		P_PLAYER otherplayer = dynamic_cast<P_PLAYER>( observer );

		if ( otherplayer && otherplayer->socket() )
		{
			if ( distance > otherplayer->visualRange() )
			{
				otherplayer->socket()->sendChar( pChar ); // Previously we were out of range
			}
			else
			{
				otherplayer->socket()->updateChar( pChar ); // Previously we were already known
			}
		}
	}

	// If we really moved handle teleporters and new items
	if ( !turning )
	{
		handleItems( pChar, oldpos );
		handleTeleporters( pChar, oldpos );
	}

	return true;
}