int response(UOXSOCKET s, P_CHAR pPlayer, char* SpeechUpr)
{
	char *comm=SpeechUpr;

    if (strstr( comm, "#EMPTY") && online(currchar[s]) && !pPlayer->dead && pPlayer->isGM())
	{ // restricted to GMs for now. It's too powerful (Duke, 5.6.2001)
		target(s, 0, 1, 0, 71, "Select container to empty:");
		return 1;
	}

    if (!online(DEREF_P_CHAR(pPlayer)) || pPlayer->dead)
		return 0;

	P_CHAR pc;
	cRegion::RegionIterator4Chars ri(pPlayer->pos);
	for (ri.Begin(); (pc=ri.GetData()) != ri.End(); ri++)
	{
		if (pc->isPlayer())		// only npcs will respond automagically, players still have to do that themselves ;)
			continue;
		if (pPlayer->dist(pc) > 16)	// at least they should be on the screen
			continue;
		if (pPlayer->isSameAs(pc))	// not talking to ourselves
			continue;
		
		if (StableSpeech(pc, comm, pPlayer, s))
			return 1;
		
		if (UnStableSpeech(pc, comm, pPlayer, s))
			return 1;
		
		if (ShieldSpeech(pc, comm, pPlayer, s))
			return 1;
		
		if (QuestionSpeech(pc, comm, pPlayer, s))
			return 1;
		
		if (PackupSpeech(pc, comm, pPlayer, s))
			return 1;
		
		if (TriggerSpeech(pc, comm, pPlayer, s))
			return 1;
		
		if (EscortSpeech(pc, comm, pPlayer, s))
			return 1;
		
		if (BankerSpeech(pc, comm, pPlayer, s))
			return 1;
		
		if (TrainerSpeech(pc, comm, pPlayer, s))
			return 1;
		
		if (PetCommand(pc, comm, pPlayer, s))
			return 1;
		
		if (VendorSpeech(pc, comm, pPlayer, s))
			return 1;
	}
	
	return 0;
}
	virtual void handleResponse( cUOSocket *socket, const gumpChoice_st& choice )
	{
		P_PLAYER player = socket->player();

		if( !player )
			return;

		P_CHAR pChar = FindCharBySerial( choice.button );

		if( !pChar || pChar->dist( player ) > 32 )
			return;

		// Start the refresh-timer
		// Start the wearoff-timer
		player->setTrackingTime( uiCurrentTime + ( 30 * MY_CLOCKS_PER_SEC ) );
		TempEffects::instance()->insert( new cRefreshTracking( player->serial(), choice.button ) );
	}
/*!
	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;
}
Beispiel #4
0
// check if something is attacking us
P_CHAR Action_Defend::findAttacker()
{

	if ( !m_ai )
	{
		return 0;
	}

	P_CHAR attacker = m_npc->attackTarget();
	unsigned int distance = ~0;

	// check our current target
	if ( attacker && validTarget( m_npc, attacker ) )
	{
		m_ai->setcurrentVictimSer( attacker->serial() );
		return attacker;
	}

	// check our current victim
	attacker = m_ai->currentVictim();
	if ( !attacker )
	{
		m_ai->setcurrentVictimSer( INVALID_SERIAL );
	}

	// is it still valid?
	if ( attacker && invalidTarget( m_npc, attacker ) )
	{
		attacker = 0;
		m_ai->setcurrentVictimSer( INVALID_SERIAL );
		m_npc->fight( 0 );
	}

	if ( m_ai->getnextVictimCheck() < Server::instance()->time() )
	{
		// Don't switch if we can hit it...
		if ( !attacker || attacker->dist( m_npc ) > 1 )
		{

			// Search for attackers in our list of current fights
			QPtrList<cFightInfo> fights = m_npc->fights();
			for ( cFightInfo*info = fights.first(); info; info = fights.next() )
			{

				//are they attacking us?
				P_CHAR victim = info->victim();
				if ( victim == m_npc )
				{
					victim = info->attacker();
				}

				// We don't already attack the target, right?
				if ( victim != attacker  )
				{
					// See if it's a target we want
					unsigned int dist = m_npc->dist( victim );
					if ( dist < distance && validTarget( m_npc, victim, dist ) )
					{
						attacker = victim;
						distance = dist;
					}
				}
			}

			// we found someone attacking us, so let's defend!
			if ( attacker )
			{
				m_ai->setcurrentVictimSer( attacker->serial() );
				m_npc->fight( attacker );
			}
		}

		m_ai->setnextVictimCheck( Server::instance()->time() + 1500 );
	}

	return attacker;
}
Beispiel #5
0
void Action_Wander::execute()
{
	m_npc->fight(0);

	// If the next wandertype hasn't come yet.
	if (m_npc->nextMoveTime() > uiCurrentTime) {
		return;
	}
	m_npc->setNextMoveTime();

	switch( m_npc->wanderType() )
	{
	case enFreely:
	{
		UINT8 dir = m_npc->direction();
		if( RandomNum(0, 100) < 20 )
			dir = RandomNum( 0, 7 );

		m_npc->setDirection( dir );
		Movement::instance()->Walking( m_npc, dir, 0xFF );
		break;
	}
	case enRectangle:
	{
		// get any point out of the rectangle and calculate the direction to it
		UINT16 rndx = RandomNum( m_npc->wanderX1(), m_npc->wanderX2() );
		UINT16 rndy = RandomNum( m_npc->wanderY1(), m_npc->wanderY2() );
		
		UINT8 dir = m_npc->pos().direction( Coord_cl( rndx, rndy ) );
		m_npc->setDirection( dir );
		Movement::instance()->Walking( m_npc, dir, 0xFF );
		break;
	}
	case enCircle:
	{
		Coord_cl pos = m_npc->pos();
		pos.x = m_npc->wanderX1();
		pos.y = m_npc->wanderY1();
		// get any point within the circle and calculate the direction to it
		// first a random distance which can be max. the length of the radius
		float rnddist = (float)RandomNum( 1, m_npc->wanderRadius() );
		// now get a point on this circle around the m_npc
		float rndphi = (float)RandomNum( 0, 100 ) / 100.0f * 2.0f * 3.14159265358979323846f;
		pos.x = pos.x + (INT16)floor( cos( rndphi ) * rnddist );
		pos.y = pos.y + (INT16)floor( sin( rndphi ) * rnddist );

		UINT8 dir = m_npc->pos().direction( pos );
		m_npc->setDirection( dir );
		Movement::instance()->Walking( m_npc, dir, 0xFF );
		break;	
	}
	case enFollowTarget:
	{
		if( SrvParams->pathfind4Follow() )
		{
			P_CHAR pTarget = m_npc->wanderFollowTarget();
			if( pTarget )
			{
				movePath( pTarget->pos() );
			}
			if( pTarget->dist( m_npc ) > 3 )
				m_npc->setAICheckTime( uiCurrentTime + (float)m_npc->aiCheckInterval() * 0.0005f * MY_CLOCKS_PER_SEC );
		}
		else
		{
			P_CHAR pTarget = m_npc->wanderFollowTarget();
			if( pTarget )
			{
				moveTo( pTarget->pos() );
			}
		}
		break;
	}
	case enDestination:
	{
		movePath( m_npc->wanderDestination() );
		break;
	}
	}
}