diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 285dcb00967a2d1c971d215dbfcccedc759d1c9f..7be7feab4c82219705df38a3722e6cef80b4ff40 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -672,6 +672,13 @@ void LLAgent::moveLeftNudge(S32 direction)
 //-----------------------------------------------------------------------------
 void LLAgent::moveUp(S32 direction)
 {
+// [RLVa:KB] - Checked: RLVa-2.2
+	if ( (!RlvActions::canJump()) && (direction > 0) && (!getFlying()) )
+	{
+		return;
+	}
+// [/Sl:KB]
+
 	mMoveTimer.reset();
 	LLFirstUse::notMoving(false);
 
@@ -735,8 +742,11 @@ void LLAgent::movePitch(F32 mag)
 // Does this parcel allow you to fly?
 BOOL LLAgent::canFly()
 {
-// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0d) | Modified: RLVa-1.0.0c
-	if (gRlvHandler.hasBehaviour(RLV_BHVR_FLY)) return FALSE;
+// [RLVa:KB] - Checked: RLVa-1.0
+	if (!RlvActions::canFly())
+	{
+		return FALSE;
+	}
 // [/RLVa:KB]
 	if (isGodlike()) return TRUE;
 
@@ -786,8 +796,8 @@ void LLAgent::setFlying(BOOL fly)
 
 	if (fly)
 	{
-// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0d) | Modified: RLVa-1.0.0c
-		if (gRlvHandler.hasBehaviour(RLV_BHVR_FLY))
+// [RLVa:KB] - Checked: RLVa-1.0
+		if (!RlvActions::canFly())
 		{
 			return;
 		}
diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp
index 74207b96a75775e32947a46bd6bfc9dfd02e27fd..355945dbc0f1ad4fb6f72e501ca888f4d45d0ac8 100644
--- a/indra/newview/rlvactions.cpp
+++ b/indra/newview/rlvactions.cpp
@@ -295,6 +295,21 @@ bool RlvActions::autoAcceptTeleportRequest(const LLUUID& idRequester)
 	return ((idRequester.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTPREQUEST, idRequester))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTPREQUEST));
 }
 
+bool RlvActions::canFly()
+{
+	return (!gRlvHandler.getCurrentCommand()) ? !gRlvHandler.hasBehaviour(RLV_BHVR_FLY) : !gRlvHandler.hasBehaviourExcept(RLV_BHVR_FLY, gRlvHandler.getCurrentObject());
+}
+
+bool RlvActions::canFly(const LLUUID& idRlvObjExcept)
+{
+	return !gRlvHandler.hasBehaviourExcept(RLV_BHVR_FLY, idRlvObjExcept);
+}
+
+bool RlvActions::canJump()
+{
+	return !gRlvHandler.hasBehaviour(RLV_BHVR_JUMP);
+}
+
 // ============================================================================
 // Teleporting
 //
diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h
index afafa726b8f93510a7109429166469a59de3d931..90b1069f6bd27487233e6a058860efef9795b4df 100644
--- a/indra/newview/rlvactions.h
+++ b/indra/newview/rlvactions.h
@@ -176,6 +176,18 @@ public:
 	 */
 	static bool autoAcceptTeleportRequest(const LLUUID& idRequester);
 
+	/*
+	 * Returns true if the user can fly
+	 * (NOTE: the parameter-less overload takes the currently executing command into account)
+	 */
+	static bool canFly();
+	static bool canFly(const LLUUID& idRlvObjExcept);
+
+	/*
+	 * Returns true if the user can jump
+	 */
+	static bool canJump();
+
 	// ===========
 	// Teleporting
 	// ===========
diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h
index 29cc03a9136a9d80f6d4293e17935b2c113e4f05..056e0303de8810630dfd629452a6c9df28e161a8 100644
--- a/indra/newview/rlvdefines.h
+++ b/indra/newview/rlvdefines.h
@@ -163,6 +163,7 @@ enum ERlvBehaviour {
 	RLV_BHVR_TOUCHALL,				// "touchall"
 	RLV_BHVR_TOUCHME,				// "touchme"
 	RLV_BHVR_FLY,					// "fly"
+	RLV_BHVR_JUMP,                  // "jump"
 	RLV_BHVR_SETGROUP,				// "setgroup"
 	RLV_BHVR_UNSIT,					// "unsit"
 	RLV_BHVR_SIT,					// "sit"
diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp
index d998375444d7249acc5b98fbbbe26ccf06dcd261..13a2f9513830cfd0568bd95a896b6afee616f1d4 100644
--- a/indra/newview/rlvhandler.cpp
+++ b/indra/newview/rlvhandler.cpp
@@ -2391,6 +2391,23 @@ ERlvCmdRet RlvForceHandler<RLV_BHVR_DETACHME>::onCommand(const RlvCommand& rlvCm
 	return RLV_RET_SUCCESS;
 }
 
+// Handles: @fly:[true|false]=force
+template<> template<>
+ERlvCmdRet RlvForceHandler<RLV_BHVR_FLY>::onCommand(const RlvCommand& rlvCmd)
+{
+	bool fForceFly = true;
+	if ( (rlvCmd.hasOption()) && (!RlvCommandOptionHelper::parseOption<bool>(rlvCmd.getOption(), fForceFly)) )
+		return RLV_RET_FAILED_OPTION;
+
+	if ( (fForceFly) && (!RlvActions::canFly(rlvCmd.getObjectID())) )
+		return RLV_RET_FAILED_LOCK;
+
+	if (fForceFly != (bool)gAgent.getFlying())
+		gAgent.setFlying(fForceFly);
+
+	return RLV_RET_SUCCESS;
+}
+
 // Handles: @remattach[:<folder|attachpt|attachgroup>]=force
 template<> template<>
 ERlvCmdRet RlvForceRemAttachHandler::onCommand(const RlvCommand& rlvCmd)
diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp
index 8dbfc6921593de88658188692edd17042a013ab6..144d0242a5c7113ce5921ca649ac8761f56a8276 100644
--- a/indra/newview/rlvhelper.cpp
+++ b/indra/newview/rlvhelper.cpp
@@ -104,6 +104,7 @@ RlvBehaviourDictionary::RlvBehaviourDictionary()
 	addModifier(RLV_BHVR_FARTOUCH, RLV_MODIFIER_FARTOUCHDIST, new RlvBehaviourModifier("Fartouch Distance", RLV_MODIFIER_FARTOUCH_DEFAULT, true, new RlvBehaviourModifierCompMin));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("fly", RLV_BHVR_FLY));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("interact", RLV_BHVR_INTERACT, RlvBehaviourInfo::BHVR_EXTENDED));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("jump", RLV_BHVR_JUMP));
 	addEntry(new RlvBehaviourInfo("notify",					RLV_BHVR_NOTIFY,				RLV_TYPE_ADDREM));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("permissive", RLV_BHVR_PERMISSIVE));
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("recvchat", RLV_BHVR_RECVCHAT, RlvBehaviourInfo::BHVR_STRICT));
@@ -255,6 +256,7 @@ RlvBehaviourDictionary::RlvBehaviourDictionary()
 	//
 	addEntry(new RlvBehaviourInfo("adjustheight",			RLV_BHVR_ADJUSTHEIGHT,			RLV_TYPE_FORCE));
 	addEntry(new RlvForceProcessor<RLV_BHVR_DETACHME>("detachme"));
+	addEntry(new RlvForceProcessor<RLV_BHVR_FLY>("fly"));
 	addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOCUS>("setcam_focus", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
 	addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_EYEOFFSET, RlvForceCamEyeFocusOffsetHandler>("setcam_eyeoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
 	addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOCUSOFFSET, RlvForceCamEyeFocusOffsetHandler>("setcam_focusoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
@@ -699,6 +701,25 @@ bool RlvCommandOptionHelper::parseOption<int>(const std::string& strOption, int&
 	return true;
 }
 
+template<>
+bool RlvCommandOptionHelper::parseOption<bool>(const std::string& strOption, bool& fOption)
+{
+	try
+	{
+		// Try and parse it as a number first
+		int nOption = std::stoi(strOption);
+		fOption = (bool)nOption;
+		return (nOption == 0) || (nOption == 1);
+	}
+	catch (const std::invalid_argument&)
+	{
+		// Then try and parse it as true/false
+		std::istringstream ss(strOption);
+		ss >> std::boolalpha >> fOption;
+		return !ss.fail();
+	}
+}
+
 template<>
 bool RlvCommandOptionHelper::parseOption<float>(const std::string& strOption, float& nOption)
 {