Skip to content
Snippets Groups Projects
llagent.cpp 209 KiB
Newer Older
James Cook's avatar
James Cook committed
/** 
 * @file llagent.cpp
 * @brief LLAgent class implementation
 *
 * $LicenseInfo:firstyear=2001&license=viewergpl$
 * 
 * Copyright (c) 2001-2007, Linden Research, Inc.
 * 
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlife.com/developers/opensource/gplv2
 * 
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at http://secondlife.com/developers/opensource/flossexception
 * 
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 * 
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
James Cook's avatar
James Cook committed
 */

#include "llviewerprecompiledheaders.h"

#include "stdtypes.h"
#include "stdenums.h"

#include "llagent.h" 

#include "llcoordframe.h"
#include "indra_constants.h"
#include "llmath.h"
#include "llcriticaldamp.h"
#include "llfocusmgr.h"
#include "llglheaders.h"
#include "llparcel.h"
#include "llpermissions.h"
#include "llregionhandle.h"
#include "m3math.h"
#include "m4math.h"
#include "message.h"
#include "llquaternion.h"
#include "v3math.h"
#include "v4math.h"
Josh Bell's avatar
Josh Bell committed
#include "llsmoothstep.h"
#include "llsdutil.h"
James Cook's avatar
James Cook committed
//#include "vmath.h"

#include "imageids.h"
#include "llbox.h"
#include "llbutton.h"
#include "llcallingcard.h"
#include "llchatbar.h"
#include "llconsole.h"
#include "lldrawable.h"
#include "llface.h"
#include "llfirstuse.h"
#include "llfloater.h"
#include "llfloateractivespeakers.h"
James Cook's avatar
James Cook committed
#include "llfloateravatarinfo.h"
#include "llfloaterbuildoptions.h"
#include "llfloatercamera.h"
James Cook's avatar
James Cook committed
#include "llfloaterchat.h"
#include "llfloatercustomize.h"
#include "llfloaterdirectory.h"
#include "llfloatergroupinfo.h"
#include "llfloatergroups.h"
#include "llfloatermap.h"
#include "llfloatermute.h"
#include "llfloatersnapshot.h"
#include "llfloatertools.h"
#include "llfloaterworldmap.h"
#include "llgroupmgr.h"
James Cook's avatar
James Cook committed
#include "llhudeffectlookat.h"
#include "llhudmanager.h"
#include "llinventorymodel.h"
#include "llinventoryview.h"
#include "lljoystickbutton.h"
#include "llmenugl.h"
#include "llmorphview.h"
#include "llmoveview.h"
#include "llnotify.h"
#include "llquantize.h"
James Cook's avatar
James Cook committed
#include "llselectmgr.h"
#include "llsky.h"
James Cook's avatar
James Cook committed
#include "llstatusbar.h"
#include "llstartup.h"
James Cook's avatar
James Cook committed
#include "llimview.h"
#include "lltool.h"
#include "lltoolfocus.h"
#include "lltoolgrab.h"
#include "lltoolmgr.h"
#include "lltoolpie.h"
#include "lltoolview.h"
#include "llui.h"			// for make_ui_sound
#include "llurldispatcher.h"
James Cook's avatar
James Cook committed
#include "llviewercamera.h"
#include "llviewerinventory.h"
#include "llviewermenu.h"
#include "llviewernetwork.h"
#include "llviewerobjectlist.h"
#include "llviewerparcelmgr.h"
#include "llviewerparceloverlay.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
#include "llviewerwindow.h"
James Cook's avatar
James Cook committed
#include "llvoavatar.h"
#include "llvoground.h"
#include "llvosky.h"
#include "llwearable.h"
#include "llwearablelist.h"
#include "llworld.h"
#include "llworldmap.h"
#include "pipeline.h"
#include "roles_constants.h"
#include "llviewercontrol.h"
#include "llappviewer.h"
#include "llviewerjoystick.h"
James Cook's avatar
James Cook committed
#include "llfollowcam.h"

extern LLMenuBarGL* gMenuBarView;

//drone wandering constants
const F32 MAX_WANDER_TIME = 20.f;						// seconds
const F32 MAX_HEADING_HALF_ERROR = 0.2f;				// radians
const F32 WANDER_MAX_SLEW_RATE = 2.f * DEG_TO_RAD;		// radians / frame
const F32 WANDER_TARGET_MIN_DISTANCE = 10.f;			// meters

// Autopilot constants
const F32 AUTOPILOT_HEADING_HALF_ERROR = 10.f * DEG_TO_RAD;	// radians
const F32 AUTOPILOT_MAX_SLEW_RATE = 1.f * DEG_TO_RAD;		// radians / frame
const F32 AUTOPILOT_STOP_DISTANCE = 2.f;					// meters
const F32 AUTOPILOT_HEIGHT_ADJUST_DISTANCE = 8.f;			// meters
const F32 AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND = 1.f;	// meters
const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS = 1.5f;		// seconds

// face editing constants
const LLVector3d FACE_EDIT_CAMERA_OFFSET(0.4f, -0.05f, 0.07f);
const LLVector3d FACE_EDIT_TARGET_OFFSET(0.f, 0.f, 0.05f);

// Mousewheel camera zoom
const F32 MIN_ZOOM_FRACTION = 0.25f;
const F32 INITIAL_ZOOM_FRACTION = 1.f;
const F32 MAX_ZOOM_FRACTION = 8.f;
const F32 METERS_PER_WHEEL_CLICK = 1.f;

const F32 MAX_TIME_DELTA = 1.f;

const F32 CAMERA_ZOOM_HALF_LIFE = 0.07f;	// seconds
const F32 FOV_ZOOM_HALF_LIFE = 0.07f;	// seconds

const F32 CAMERA_FOCUS_HALF_LIFE = 0.f;//0.02f;
const F32 CAMERA_LAG_HALF_LIFE = 0.25f;
const F32 MIN_CAMERA_LAG = 0.5f;
const F32 MAX_CAMERA_LAG = 5.f;

const F32 CAMERA_COLLIDE_EPSILON = 0.1f;
const F32 MIN_CAMERA_DISTANCE = 0.1f;
const F32 AVATAR_ZOOM_MIN_X_FACTOR = 0.55f;
const F32 AVATAR_ZOOM_MIN_Y_FACTOR = 0.7f;
const F32 AVATAR_ZOOM_MIN_Z_FACTOR = 1.15f;

const F32 MAX_CAMERA_DISTANCE_FROM_AGENT = 50.f;

const F32 MAX_CAMERA_SMOOTH_DISTANCE = 50.0f;
James Cook's avatar
James Cook committed
const F32 HEAD_BUFFER_SIZE = 0.3f;
const F32 CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP = 0.2f;

const F32 LAND_MIN_ZOOM = 0.15f;
const F32 AVATAR_MIN_ZOOM = 0.5f;
const F32 OBJECT_MIN_ZOOM = 0.02f;

const F32 APPEARANCE_MIN_ZOOM = 0.39f;
const F32 APPEARANCE_MAX_ZOOM = 8.f;

// fidget constants
const F32 MIN_FIDGET_TIME = 8.f; // seconds
const F32 MAX_FIDGET_TIME = 20.f; // seconds

const S32 MAX_NUM_CHAT_POSITIONS = 10;
const F32 GROUND_TO_AIR_CAMERA_TRANSITION_TIME = 0.5f;
const F32 GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME = 0.5f;

const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f;

const F32 MAX_FOCUS_OFFSET = 20.f;

const F32 OBJECT_EXTENTS_PADDING = 0.5f;

const F32 MIN_RADIUS_ALPHA_SIZZLE = 0.5f;

const F64 CHAT_AGE_FAST_RATE = 3.0;

const S32 MAX_WEARABLES_PER_LAYERSET = 7;

const EWearableType WEARABLE_BAKE_TEXTURE_MAP[BAKED_TEXTURE_COUNT][MAX_WEARABLES_PER_LAYERSET] = 
{
	{ WT_SHAPE,	WT_SKIN,	WT_HAIR,	WT_INVALID,	WT_INVALID,	WT_INVALID,		WT_INVALID    },	// TEX_HEAD_BAKED
	{ WT_SHAPE, WT_SKIN,	WT_SHIRT,	WT_JACKET,	WT_GLOVES,	WT_UNDERSHIRT,	WT_INVALID	  },	// TEX_UPPER_BAKED
	{ WT_SHAPE, WT_SKIN,	WT_PANTS,	WT_SHOES,	WT_SOCKS,	WT_JACKET,		WT_UNDERPANTS },	// TEX_LOWER_BAKED
	{ WT_EYES,	WT_INVALID,	WT_INVALID,	WT_INVALID,	WT_INVALID,	WT_INVALID,		WT_INVALID    },	// TEX_EYES_BAKED
	{ WT_SKIRT,	WT_INVALID,	WT_INVALID,	WT_INVALID,	WT_INVALID,	WT_INVALID,		WT_INVALID    }		// TEX_SKIRT_BAKED
};

const LLUUID BAKED_TEXTURE_HASH[BAKED_TEXTURE_COUNT] = 
{
	LLUUID("18ded8d6-bcfc-e415-8539-944c0f5ea7a6"),
	LLUUID("338c29e3-3024-4dbb-998d-7c04cf4fa88f"),
	LLUUID("91b4a2c7-1b1a-ba16-9a16-1f8f8dcc1c3f"),
	LLUUID("b2cf28af-b840-1071-3c6a-78085d8128b5"),
	LLUUID("ea800387-ea1a-14e0-56cb-24f2022f969a")
};

James Cook's avatar
James Cook committed
//
// Statics
//
BOOL LLAgent::sDebugDisplayTarget = FALSE;

const F32 LLAgent::TYPING_TIMEOUT_SECS = 5.f;

std::map<std::string, std::string> LLAgent::sTeleportErrorMessages;
std::map<std::string, std::string> LLAgent::sTeleportProgressMessages;
James Cook's avatar
James Cook committed
class LLAgentFriendObserver : public LLFriendObserver
{
public:
	LLAgentFriendObserver() {}
	virtual ~LLAgentFriendObserver() {}
	virtual void changed(U32 mask);
};

void LLAgentFriendObserver::changed(U32 mask)
{
	// if there's a change we're interested in.
	if((mask & (LLFriendObserver::POWERS)) != 0)
	{
		gAgent.friendsChanged();
	}
}

// ************************************************************
// Enabled this definition to compile a 'hacked' viewer that
// locally believes the end user has godlike powers.
// #define HACKED_GODLIKE_VIEWER
// For a toggled version, see viewer.h for the
// TOGGLE_HACKED_GODLIKE_VIEWER define, instead.
// ************************************************************

// Constructors and Destructors

// JC - Please try to make this order match the order in the header
// file.  Otherwise it's hard to find variables that aren't initialized.
//-----------------------------------------------------------------------------
// LLAgent()
//-----------------------------------------------------------------------------
LLAgent::LLAgent()
:	mDrawDistance( DEFAULT_FAR_PLANE ),
Josh Bell's avatar
Josh Bell committed

	mDoubleTapRunTimer(),
	mDoubleTapRunMode(DOUBLETAP_NONE),

	mbAlwaysRun(false),
	mbRunning(false),

James Cook's avatar
James Cook committed
	mAccess(SIM_ACCESS_PG),
	mGroupPowers(0),
	mGroupID(),
	//mGroupInsigniaID(),
	mMapOriginX(0),
	mMapOriginY(0),
	mMapWidth(0),
	mMapHeight(0),
	mLookAt(NULL),
	mPointAt(NULL),
	mInitialized(FALSE),
	mNumPendingQueries(0),
	mForceMouselook(FALSE),
	mTeleportState( TELEPORT_NONE ),
	mRegionp(NULL),

	mAgentOriginGlobal(),
	mPositionGlobal(),

	mDistanceTraveled(0),
	mLastPositionGlobal(LLVector3d::zero),

	mAvatarObject(NULL),

	mRenderState(0),
	mTypingTimer(),

	mCameraMode( CAMERA_MODE_THIRD_PERSON ),
	mLastCameraMode( CAMERA_MODE_THIRD_PERSON ),
	mViewsPushed(FALSE),

	mShowAvatar(TRUE),
James Cook's avatar
James Cook committed
	mCameraAnimating( FALSE ),
	mAnimationCameraStartGlobal(),
	mAnimationFocusStartGlobal(),
	mAnimationTimer(),
	mAnimationDuration(0.33f),
	mCameraFOVZoomFactor(0.f),
	mCameraCurrentFOVZoomFactor(0.f),
	mCameraFocusOffset(),
	mCameraOffsetDefault(),
//	mCameraOffsetNorm(),
	mCameraCollidePlane(),
	mCurrentCameraDistance(2.f),		// meters, set in init()
	mTargetCameraDistance(2.f),
	mCameraZoomFraction(1.f),			// deprecated
	mThirdPersonHeadOffset(0.f, 0.f, 1.f),
	mSitCameraEnabled(FALSE),
James Cook's avatar
James Cook committed
	mFocusOnAvatar(TRUE),
	mFocusGlobal(),
	mFocusTargetGlobal(),
	mFocusObject(NULL),
	mFocusObjectOffset(),
	mFocusDotRadius( 0.1f ),			// meters
	mTrackFocusObject(TRUE),
Josh Bell's avatar
Josh Bell committed
	mCameraSmoothingLastPositionGlobal(),
	mCameraSmoothingLastPositionAgent(),
	mCameraSmoothingStop(FALSE),
James Cook's avatar
James Cook committed

	mFrameAgent(),

	mCrouching(FALSE),
	mIsBusy(FALSE),

	// movement keys below

	mControlFlags(0x00000000),
	mbFlagsDirty(FALSE),
	mbFlagsNeedReset(FALSE),

	mbJump(FALSE),

	mAutoPilot(FALSE),
	mAutoPilotFlyOnStop(FALSE),
	mAutoPilotTargetGlobal(),
	mAutoPilotStopDistance(1.f),
	mAutoPilotUseRotation(FALSE),
	mAutoPilotTargetFacing(LLVector3::zero),
	mAutoPilotTargetDist(0.f),
	mAutoPilotFinishedCallback(NULL),
	mAutoPilotCallbackData(NULL),
	

	mEffectColor(0.f, 1.f, 1.f, 1.f),
	mHaveHomePosition(FALSE),
	mHomeRegionHandle( 0 ),
	mNearChatRadius(CHAT_NORMAL_RADIUS / 2.f),
James Cook's avatar
James Cook committed
	mGodLevel( GOD_NOT ),


	mNextFidgetTime(0.f),
	mCurrentFidget(0),
	mFirstLogin(FALSE),
	mGenderChosen(FALSE),
	mAgentWearablesUpdateSerialNum(0),
	mWearablesLoaded(FALSE),
	mTextureCacheQueryID(0),
	mAppearanceSerialNum(0)
{

	U32 i;
	for (i = 0; i < TOTAL_CONTROLS; i++)
	{
		mControlsTakenCount[i] = 0;
		mControlsTakenPassedOnCount[i] = 0;
	}

	// Initialize movement keys
	mAtKey				= 0;	// Either 1, 0, or -1... indicates that movement-key is pressed
	mWalkKey			= 0;	// like AtKey, but causes less forward thrust
	mLeftKey			= 0;
	mUpKey				= 0;
	mYawKey				= 0.f;
	mPitchKey			= 0;

	mOrbitLeftKey		= 0.f;
	mOrbitRightKey		= 0.f;
	mOrbitUpKey			= 0.f;
	mOrbitDownKey		= 0.f;
	mOrbitInKey			= 0.f;
	mOrbitOutKey		= 0.f;

	mPanUpKey			= 0.f;
	mPanDownKey			= 0.f;
	mPanLeftKey			= 0.f;
	mPanRightKey		= 0.f;
	mPanInKey			= 0.f;
	mPanOutKey			= 0.f;

	mActiveCacheQueries = new S32[BAKED_TEXTURE_COUNT];
	for (i = 0; i < (U32)BAKED_TEXTURE_COUNT; i++)
	{
		mActiveCacheQueries[i] = 0;
	}

	//Ventrella
	mCameraUpVector = LLVector3::z_axis;// default is straight up 
	mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
	//end ventrella
James Cook's avatar
James Cook committed
}

// Requires gSavedSettings to be initialized.
//-----------------------------------------------------------------------------
// init()
//-----------------------------------------------------------------------------
void LLAgent::init()
{
	mDrawDistance = gSavedSettings.getF32("RenderFarClip");

	// *Note: this is where LLViewerCamera::getInstance() used to be constructed.
James Cook's avatar
James Cook committed

	LLViewerCamera::getInstance()->setView(DEFAULT_FIELD_OF_VIEW);
James Cook's avatar
James Cook committed
	// Leave at 0.1 meters until we have real near clip management
	LLViewerCamera::getInstance()->setNear(0.1f);
	LLViewerCamera::getInstance()->setFar(mDrawDistance);			// if you want to change camera settings, do so in camera.h
	LLViewerCamera::getInstance()->setAspect( gViewerWindow->getDisplayAspectRatio() );		// default, overridden in LLViewerWindow::reshape
	LLViewerCamera::getInstance()->setViewHeightInPixels(768);			// default, overridden in LLViewerWindow::reshape
James Cook's avatar
James Cook committed

	setFlying( gSavedSettings.getBOOL("FlyingAtExit") );

	mCameraFocusOffsetTarget = LLVector4(gSavedSettings.getVector3("CameraOffsetBuild"));
	mCameraOffsetDefault = gSavedSettings.getVector3("CameraOffsetDefault");
//	mCameraOffsetNorm = mCameraOffsetDefault;
James Cook's avatar
James Cook committed
	mCameraCollidePlane.clearVec();
	mCurrentCameraDistance = mCameraOffsetDefault.magVec();
	mTargetCameraDistance = mCurrentCameraDistance;
	mCameraZoomFraction = 1.f;
	mTrackFocusObject = gSavedSettings.getBOOL("TrackFocusObject");

//	LLDebugVarMessageBox::show("Camera Lag", &CAMERA_FOCUS_HALF_LIFE, 0.5f, 0.01f);

	mEffectColor = gSavedSettings.getColor4("EffectColor");
	
	mInitialized = TRUE;
}

//-----------------------------------------------------------------------------
// cleanup()
//-----------------------------------------------------------------------------
void LLAgent::cleanup()
{
	setSitCamera(LLUUID::null);
	mAvatarObject = NULL;
	mLookAt = NULL;
	mPointAt = NULL;
	mRegionp = NULL;
	setFocusObject(NULL);
}

//-----------------------------------------------------------------------------
// LLAgent()
//-----------------------------------------------------------------------------
LLAgent::~LLAgent()
{
	cleanup();

	delete [] mActiveCacheQueries;
	mActiveCacheQueries = NULL;

	// *Note: this is where LLViewerCamera::getInstance() used to be deleted.
James Cook's avatar
James Cook committed
}

// Change camera back to third person, stop the autopilot,
// deselect stuff, etc.
//-----------------------------------------------------------------------------
// resetView()
//-----------------------------------------------------------------------------
void LLAgent::resetView(BOOL reset_camera, BOOL change_camera)
James Cook's avatar
James Cook committed
{
	if (mAutoPilot)
	{
		stopAutoPilot(TRUE);
	}

	if (!gNoRender)
	{
		LLSelectMgr::getInstance()->unhighlightAll();
James Cook's avatar
James Cook committed

		// By popular request, keep land selection while walking around. JC
		// LLViewerParcelMgr::getInstance()->deselectLand();
James Cook's avatar
James Cook committed

		// force deselect when walking and attachment is selected
		// this is so people don't wig out when their avatar moves without animating
		if (LLSelectMgr::getInstance()->getSelection()->isAttachment())
			LLSelectMgr::getInstance()->deselectAll();
James Cook's avatar
James Cook committed
		// Hide all popup menus
		gMenuHolder->hideMenus();
	if (change_camera && !gSavedSettings.getBOOL("FreezeTime"))
	{
		changeCameraToDefault();
		
		if (LLViewerJoystick::getInstance()->getOverrideCamera())
		{
			handle_toggle_flycam();
		}

		// reset avatar mode from eventual residual motion
		if (LLToolMgr::getInstance()->inBuildMode())
		{
			LLViewerJoystick::getInstance()->moveAvatar(true);
		}

		gFloaterTools->close();
		
		gViewerWindow->showCursor();

		// Switch back to basic toolset
		LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
	}


James Cook's avatar
James Cook committed
	if (reset_camera && !gSavedSettings.getBOOL("FreezeTime"))
	{
		if (!gViewerWindow->getLeftMouseDown() && cameraThirdPerson())
		{
			// leaving mouse-steer mode
			LLVector3 agent_at_axis = getAtAxis();
			agent_at_axis -= projected_vec(agent_at_axis, getReferenceUpVector());
James Cook's avatar
James Cook committed
			gAgent.resetAxes(lerp(getAtAxis(), agent_at_axis, LLCriticalDamp::getInterpolant(0.3f)));
		}

		setFocusOnAvatar(TRUE, ANIMATE);
	}

// Handle any actions that need to be performed when the main app gains focus
// (such as through alt-tab).
//-----------------------------------------------------------------------------
// onAppFocusGained()
//-----------------------------------------------------------------------------
void LLAgent::onAppFocusGained()
{
	if (CAMERA_MODE_MOUSELOOK == mCameraMode)
	{
		changeCameraToDefault();
		LLToolMgr::getInstance()->clearSavedTool();
James Cook's avatar
James Cook committed
void LLAgent::ageChat()
{
	if (mAvatarObject)
	{
		// get amount of time since I last chatted
		F64 elapsed_time = (F64)mAvatarObject->mChatTimer.getElapsedTimeF32();
		// add in frame time * 3 (so it ages 4x)
		mAvatarObject->mChatTimer.setAge(elapsed_time + (F64)gFrameDTClamped * (CHAT_AGE_FAST_RATE - 1.0));
	}
}

// Allow camera to be moved somewhere other than behind avatar.
//-----------------------------------------------------------------------------
// unlockView()
//-----------------------------------------------------------------------------
void LLAgent::unlockView()
{
	if (getFocusOnAvatar())
	{
		if (mAvatarObject)
		{
			setFocusGlobal( LLVector3d::zero, mAvatarObject->mID );
		}
		setFocusOnAvatar(FALSE, FALSE);	// no animation
	}
}


//-----------------------------------------------------------------------------
// moveAt()
//-----------------------------------------------------------------------------
Steven Bennetts's avatar
Steven Bennetts committed
void LLAgent::moveAt(S32 direction, bool reset)
James Cook's avatar
James Cook committed
{
	// age chat timer so it fades more quickly when you are intentionally moving
	ageChat();

	setKey(direction, mAtKey);

	if (direction > 0)
	{
		setControlFlags(AGENT_CONTROL_AT_POS | AGENT_CONTROL_FAST_AT);
	}
	else if (direction < 0)
	{
		setControlFlags(AGENT_CONTROL_AT_NEG | AGENT_CONTROL_FAST_AT);
	}

Steven Bennetts's avatar
Steven Bennetts committed
	if (reset)
	{
		resetView();
	}
James Cook's avatar
James Cook committed
}

//-----------------------------------------------------------------------------
// moveAtNudge()
//-----------------------------------------------------------------------------
void LLAgent::moveAtNudge(S32 direction)
{
	// age chat timer so it fades more quickly when you are intentionally moving
	ageChat();

	setKey(direction, mWalkKey);

	if (direction > 0)
	{
		setControlFlags(AGENT_CONTROL_NUDGE_AT_POS);
	}
	else if (direction < 0)
	{
		setControlFlags(AGENT_CONTROL_NUDGE_AT_NEG);
	}

	resetView();
}

//-----------------------------------------------------------------------------
// moveLeft()
//-----------------------------------------------------------------------------
void LLAgent::moveLeft(S32 direction)
{
	// age chat timer so it fades more quickly when you are intentionally moving
	ageChat();

	setKey(direction, mLeftKey);

	if (direction > 0)
	{
		setControlFlags(AGENT_CONTROL_LEFT_POS | AGENT_CONTROL_FAST_LEFT);
	}
	else if (direction < 0)
	{
		setControlFlags(AGENT_CONTROL_LEFT_NEG | AGENT_CONTROL_FAST_LEFT);
	}

	resetView();
}

//-----------------------------------------------------------------------------
// moveLeftNudge()
//-----------------------------------------------------------------------------
void LLAgent::moveLeftNudge(S32 direction)
{
	// age chat timer so it fades more quickly when you are intentionally moving
	ageChat();

	setKey(direction, mLeftKey);

	if (direction > 0)
	{
		setControlFlags(AGENT_CONTROL_NUDGE_LEFT_POS);
	}
	else if (direction < 0)
	{
		setControlFlags(AGENT_CONTROL_NUDGE_LEFT_NEG);
	}

	resetView();
}

//-----------------------------------------------------------------------------
// moveUp()
//-----------------------------------------------------------------------------
void LLAgent::moveUp(S32 direction)
{
	// age chat timer so it fades more quickly when you are intentionally moving
	ageChat();

	setKey(direction, mUpKey);

	if (direction > 0)
	{
		setControlFlags(AGENT_CONTROL_UP_POS | AGENT_CONTROL_FAST_UP);
	}
	else if (direction < 0)
	{
		setControlFlags(AGENT_CONTROL_UP_NEG | AGENT_CONTROL_FAST_UP);
	}

	resetView();
}

//-----------------------------------------------------------------------------
// moveYaw()
//-----------------------------------------------------------------------------
Steven Bennetts's avatar
Steven Bennetts committed
void LLAgent::moveYaw(F32 mag, bool reset_view)
James Cook's avatar
James Cook committed
{
	mYawKey = mag;

	if (mag > 0)
	{
		setControlFlags(AGENT_CONTROL_YAW_POS);
	}
	else if (mag < 0)
	{
		setControlFlags(AGENT_CONTROL_YAW_NEG);
	}

Steven Bennetts's avatar
Steven Bennetts committed
    if (reset_view)
	{
        resetView();
	}
James Cook's avatar
James Cook committed
}

//-----------------------------------------------------------------------------
// movePitch()
//-----------------------------------------------------------------------------
void LLAgent::movePitch(S32 direction)
{
	setKey(direction, mPitchKey);

	if (direction > 0)
	{
		setControlFlags(AGENT_CONTROL_PITCH_POS );
	}
	else if (direction < 0)
	{
		setControlFlags(AGENT_CONTROL_PITCH_NEG);
	}
}


// Does this parcel allow you to fly?
BOOL LLAgent::canFly()
{
	if (isGodlike()) return TRUE;

	LLViewerRegion* regionp = getRegion();
	if (regionp && regionp->getBlockFly()) return FALSE;
	
	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
James Cook's avatar
James Cook committed
	if (!parcel) return FALSE;

	// Allow owners to fly on their own land.
	if (LLViewerParcelMgr::isParcelOwnedByAgent(parcel, GP_LAND_ALLOW_FLY))
	{
		return TRUE;
	}

	return parcel->getAllowFly();
}


//-----------------------------------------------------------------------------
// setFlying()
//-----------------------------------------------------------------------------
void LLAgent::setFlying(BOOL fly)
{
	if (mAvatarObject.notNull())
	{
		if(mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_STANDUP) != mAvatarObject->mSignaledAnimations.end())
		{
			return;
		}

		// don't allow taking off while sitting
		if (fly && mAvatarObject->mIsSitting)
		{
			return;
		}
	}

	if (fly)
	{
		BOOL was_flying = getFlying();
		if (!canFly() && !was_flying)
James Cook's avatar
James Cook committed
		{
			// parcel doesn't let you start fly
			// gods can always fly
			// and it's OK if you're already flying
			make_ui_sound("UISndBadKeystroke");
			return;
James Cook's avatar
James Cook committed
		}
		if( !was_flying )
		{
			LLViewerStats::getInstance()->incStat(LLViewerStats::ST_FLY_COUNT);
James Cook's avatar
James Cook committed
		}
		setControlFlags(AGENT_CONTROL_FLY);
		gSavedSettings.setBOOL("FlyBtnState", TRUE);
	}
	else
	{
		clearControlFlags(AGENT_CONTROL_FLY);
		gSavedSettings.setBOOL("FlyBtnState", FALSE);
	}
	mbFlagsDirty = TRUE;
}


// UI based mechanism of setting fly state
//-----------------------------------------------------------------------------
// toggleFlying()
//-----------------------------------------------------------------------------
void LLAgent::toggleFlying()
{
	BOOL fly = !(mControlFlags & AGENT_CONTROL_FLY);

	setFlying( fly );
	resetView();
}


//-----------------------------------------------------------------------------
// setRegion()
//-----------------------------------------------------------------------------
void LLAgent::setRegion(LLViewerRegion *regionp)
{
	llassert(regionp);
	if (mRegionp != regionp)
	{
		// std::string host_name;
		// host_name = regionp->getHost().getHostName();
James Cook's avatar
James Cook committed

		std::string ip = regionp->getHost().getString();
James Cook's avatar
James Cook committed
		llinfos << "Moving agent into region: " << regionp->getName()
				<< " located at " << ip << llendl;
		if (mRegionp)
		{
			// We've changed regions, we're now going to change our agent coordinate frame.
			mAgentOriginGlobal = regionp->getOriginGlobal();
			LLVector3d agent_offset_global = mRegionp->getOriginGlobal();

			LLVector3 delta;
			delta.setVec(regionp->getOriginGlobal() - mRegionp->getOriginGlobal());

			setPositionAgent(getPositionAgent() - delta);

			LLVector3 camera_position_agent = LLViewerCamera::getInstance()->getOrigin();
			LLViewerCamera::getInstance()->setOrigin(camera_position_agent - delta);
James Cook's avatar
James Cook committed

			// Update all of the regions.
			LLWorld::getInstance()->updateAgentOffset(agent_offset_global);
James Cook's avatar
James Cook committed

			// Hack to keep sky in the agent's region, otherwise it may get deleted - DJS 08/02/02
			// *TODO: possibly refactor into gSky->setAgentRegion(regionp)? -Brad
James Cook's avatar
James Cook committed
			if (gSky.mVOSkyp)
			{
				gSky.mVOSkyp->setRegion(regionp);
			}
			if (gSky.mVOGroundp)
			{
				gSky.mVOGroundp->setRegion(regionp);
			}

		}
		else
		{
			// First time initialization.
			// We've changed regions, we're now going to change our agent coordinate frame.
			mAgentOriginGlobal = regionp->getOriginGlobal();

			LLVector3 delta;
			delta.setVec(regionp->getOriginGlobal());

			setPositionAgent(getPositionAgent() - delta);
			LLVector3 camera_position_agent = LLViewerCamera::getInstance()->getOrigin();
			LLViewerCamera::getInstance()->setOrigin(camera_position_agent - delta);
James Cook's avatar
James Cook committed

			// Update all of the regions.
			LLWorld::getInstance()->updateAgentOffset(mAgentOriginGlobal);
James Cook's avatar
James Cook committed
		}
	}
	mRegionp = regionp;

	// Must shift hole-covering water object locations because local
	// coordinate frame changed.
	LLWorld::getInstance()->updateWaterObjects();
James Cook's avatar
James Cook committed

	// keep a list of regions we've been too
	// this is just an interesting stat, logged at the dataserver
	// we could trake this at the dataserver side, but that's harder
	U64 handle = regionp->getHandle();
	mRegionsVisited.insert(handle);
	LLSelectMgr::getInstance()->updateSelectionCenter();
James Cook's avatar
James Cook committed
}


//-----------------------------------------------------------------------------
// getRegion()
//-----------------------------------------------------------------------------
LLViewerRegion *LLAgent::getRegion() const
{
	return mRegionp;
}


const LLHost& LLAgent::getRegionHost() const
{
	if (mRegionp)
	{
		return mRegionp->getHost();
	}
	else
	{
		return LLHost::invalid;
	}
}

//-----------------------------------------------------------------------------
// getSLURL()
// returns empty() if getRegion() == NULL
//-----------------------------------------------------------------------------
std::string LLAgent::getSLURL() const
{
	std::string slurl;
	LLViewerRegion *regionp = getRegion();
	if (regionp)
	{
		LLVector3d agentPos = getPositionGlobal();
		S32 x = llround( (F32)fmod( agentPos.mdV[VX], (F64)REGION_WIDTH_METERS ) );
		S32 y = llround( (F32)fmod( agentPos.mdV[VY], (F64)REGION_WIDTH_METERS ) );
		S32 z = llround( (F32)agentPos.mdV[VZ] );
		slurl = LLURLDispatcher::buildSLURL(regionp->getName(), x, y, z);
	}
	return slurl;
}
James Cook's avatar
James Cook committed

//-----------------------------------------------------------------------------
// inPrelude()
//-----------------------------------------------------------------------------
BOOL LLAgent::inPrelude()
{
	return mRegionp && mRegionp->isPrelude();
}


//-----------------------------------------------------------------------------
// canManageEstate()
//-----------------------------------------------------------------------------

BOOL LLAgent::canManageEstate() const
{
	return mRegionp && mRegionp->canManageEstate();
}
James Cook's avatar
James Cook committed
//-----------------------------------------------------------------------------
// sendMessage()
//-----------------------------------------------------------------------------
void LLAgent::sendMessage()
{
	if (gDisconnected)
	{
		llwarns << "Trying to send message when disconnected!" << llendl;
		return;
	}
	if (!mRegionp)
	{
		llerrs << "No region for agent yet!" << llendl;
	}
	gMessageSystem->sendMessage(mRegionp->getHost());
}


//-----------------------------------------------------------------------------
// sendReliableMessage()
//-----------------------------------------------------------------------------
void LLAgent::sendReliableMessage()
{
	if (gDisconnected)
	{
		lldebugs << "Trying to send message when disconnected!" << llendl;
James Cook's avatar
James Cook committed
		return;
	}
	if (!mRegionp)
	{