/**
 * Sets a creature into the "Flee" state where he runs away from another object.
 *
 * @param env		    Java environment
 * @param self		    class calling this function
 * @param mob	    id of creature to access
 * @param target        target id of creature to flee
 *
 * @return JNI_TRUE if the creature stopped, or false if there was an error
 */
jboolean JNICALL ScriptMethodsActionStatesNamespace::flee(JNIEnv *env, jobject self, jlong mob, jlong target, jfloat minDistance, jfloat maxDistance)
{
	UNREF(self);

	if (mob == 0 || target == 0)
		return JNI_FALSE;

	CreatureObject * object = 0;
	AICreatureController * controller = 0;
	jboolean result=JNI_FALSE;

	if (!JavaLibrary::getObjectController(mob, object, controller))
		return result;

	NetworkId mobId = object->getNetworkId();
	NetworkId targetId(target);

	if(mobId == targetId)
	{
		JavaLibrary::throwInternalScriptError("ScriptMethodsActionStatesNamespace::flee - Creature is trying to flee from itself\n");
		return JNI_FALSE;
	}

	if (controller->flee(NetworkId(target), minDistance, maxDistance))
		result = JNI_TRUE;

	return result;
}
bool CellPermissions::isOnList(PermissionList const &permList, CreatureObject const &who) // static
{
	const int guildId = who.getGuildId();

	// if either their name or their guild is on the list, consider them on the list
	for (PermissionList::const_iterator i = permList.begin(); i != permList.end(); ++i)
	{
		const std::string& name = (*i).getName();

		// objectId
		if (name == who.getNetworkId().getValueString())
			return true;

		// first name
		if (!_stricmp(name.c_str(), Unicode::wideToNarrow(who.getAssignedObjectFirstName()).c_str()))
			return true;

		// guilds
		if (guildId && !_strnicmp(name.c_str(), "Guild:", 6))
		{
			std::string checkStr(Unicode::getTrim((name).substr(6)));
			if (   !_stricmp(checkStr.c_str(), GuildInterface::getGuildAbbrev(guildId).c_str())
			    || !_stricmp(checkStr.c_str(), GuildInterface::getGuildName(guildId).c_str()))
				return true;
		}
	}
	return false;
}
/**
 * Sets a creature into the "Follow" state where he follows someone else around.
 *
 * @param env		    Java environment
 * @param self		    class calling this function
 * @param mob	    id of creature to access
 * @param target        target id of creature to follow
 * @param minDist    closest to get to creature
 * @param maxDist   farthest to get from target
 *
 * @return JNI_TRUE if the creature stopped, or false if there was an error
 */
jboolean JNICALL ScriptMethodsActionStatesNamespace::followOffset(JNIEnv *env, jobject self, jlong mob, jlong target, jobject offset)
{
	UNREF(self);

	if (mob == 0 || target == 0)
		return JNI_FALSE;

	CreatureObject * object = 0;
	AICreatureController * controller = 0;
	jboolean result=JNI_FALSE;

	if (!JavaLibrary::getObjectController(mob, object, controller))
		return result;

	Vector location;
	NetworkId cell;
	ScriptConversion::convert(offset, location, cell, object->getPosition_w());

	NetworkId mobId = object->getNetworkId();
	NetworkId targetId(target);

	if(mobId == targetId)
	{
		JavaLibrary::throwInternalScriptError("ScriptMethodsActionStatesNamespace::followOffset - Creature is trying to follow itself\n");
		return JNI_FALSE;
	}

	if (controller->follow(NetworkId(target), location))
		result = JNI_TRUE;

	return result;
}
void MoveSimManager::checkApplySimulation (CreatureObject & creature)
{
	if (!ConfigServerGame::getMoveSimEnabled ())
		return;

	int isMoveSim = 0;
	if (creature.getObjVars ().getItem (ObjVars::moveSim, isMoveSim) && isMoveSim != 0)
	{
		const NetworkId & id = creature.getNetworkId ();
		int isPlayer = 0;
		if (creature.getObjVars ().getItem (ObjVars::moveSimPlayer, isPlayer))
			creature.setPlayerControlled (isPlayer != 0);
		
		Vector pos_w;
		if (!creature.getObjVars ().getItem (ObjVars::moveSimPosX, pos_w.x))
			WARNING (true, ("MoveSimManager no x from objvar for [%s]", id.getValueString ().c_str ()));
		
		if (!creature.getObjVars ().getItem (ObjVars::moveSimPosZ, pos_w.z))
			WARNING (true, ("MoveSimManager no z from objvar for [%s]", id.getValueString ().c_str ()));
		
		float radius = 0.0f;
		if (!creature.getObjVars ().getItem (ObjVars::moveSimRadius, radius))
			WARNING (true, ("MoveSimManager no radius from objvar for [%s]", id.getValueString ().c_str ()));
		
		MoveSimController * const msc = new MoveSimController (&creature, pos_w, radius);
		creature.setController (msc);
		creature.scheduleForAlter ();
		
		if (std::find (s_moveSimCreatures.begin (), s_moveSimCreatures.end (), id) != s_moveSimCreatures.end())
			s_moveSimCreatures.push_back (id);

		REPORT_LOG_PRINT (true, ("MoveSimManager [%ld] applied simulation to [%s]\n", GameServer::getInstance ().getProcessId (), id.getValueString ().c_str ()));
	}
}
	/**
	* Adds a value to a creature's mental state.
	*
	* @param env		    Java environment
	* @param self		    class calling this function
	* @param mob	    id of creature to access
	* @param mentalState		mental state we are interested in
	* @param value			value to add to the mental state
	*
	* @return true on success, false on fail
*/
jboolean JNICALL ScriptMethodsMentalStatesNamespace::addToMentalStateTowardClampBehavior(JNIEnv *env, jobject self, jlong mob, jlong target, jint mentalState, jfloat value, jint behavior)
{
	UNREF(self);

	if (target == 0 || mentalState < 0 || mentalState >= MentalStates::NumberOfMentalStates)
		return JNI_FALSE;

	CreatureObject * creature = 0;
	if (!JavaLibrary::getObject(mob, creature))
		return JNI_FALSE;

	NetworkId targetId(target);
	if (!targetId)
		return JNI_FALSE;

	MentalStates::Value current = creature->getMentalStateToward(targetId, static_cast<MentalStates::Enumerator>(mentalState));

	LOGC(ConfigServerGame::isAiLoggingEnabled(), "debug_ai", ("ScriptMethodsMentalStates::addToMentalStateTowardClampBehavior() %s->%s state(%s) value(%.0f+%.0f) behavior(%s)", creature->getNetworkId().getValueString().c_str(), targetId.getValueString().c_str(), CreatureObject::getMentalStateString(mentalState), current, value, CreatureObject::getBehaviorString(behavior)));

	creature->setMentalStateTowardClampBehavior(targetId,
		static_cast<MentalStates::Enumerator>(mentalState),
		static_cast<MentalStates::Value>(current + value),
		static_cast<Behaviors::Enumerator>(behavior));

	return JNI_TRUE;
}	// JavaLibrary::addToMentalState
void GroupMissionCriticalObjectsBuilderNamespace::buildGroupMissionCriticalObjects(CreatureObject const & creatureObject, CreatureObject::GroupMissionCriticalObjectSet & groupMissionCriticalObjects)
{
	CreatureObject::MissionCriticalObjectSet const & missionCriticalObjects = creatureObject.getMissionCriticalObjects();
	for (CreatureObject::MissionCriticalObjectSet::const_iterator missionCriticalObjectsIter = missionCriticalObjects.begin(); missionCriticalObjectsIter != missionCriticalObjects.end(); ++missionCriticalObjectsIter)
		groupMissionCriticalObjects.insert(std::make_pair(creatureObject.getNetworkId(), *missionCriticalObjectsIter));
}
bool CreatureObject::mountCreature(CreatureObject &mountObject)
{
	//-- Ensure mounts are enabled.
	if (!ConfigServerGame::getMountsEnabled())
	{
		LOG(cs_mountInfoChannelName, ("CreatureObject::mountCreature() called on rider object id=[%s] when mounts are disabled, ignoring call.", getNetworkId().getValueString().c_str()));
		return false;
	}

	//-- Ensure we (the rider) are not already mounted.
	if (getState(States::RidingMount))
	{
		DEBUG_FATAL(true, ("mountCreature(): rider id=[%s] template=[%s] is already riding a mount.", getNetworkId().getValueString().c_str(), getObjectTemplateName()));
		return false;
	}

	//-- Ensure the mount is mountable.
	if (!mountObject.isMountable())
	{
		DEBUG_FATAL(true, ("mountCreature(): specified mountObject id=[%s] template=[%s] is not mountable.", mountObject.getNetworkId().getValueString().c_str(), mountObject.getObjectTemplateName()));
		return false;
	}

	//-- Ensure both the mount and the rider are authoritative on this server.
	//   (They should be by design of how this function gets called.)
	if (!isAuthoritative() || !mountObject.isAuthoritative())
	{
		DEBUG_WARNING(true, ("mountCreature(): rider id=[%s] or mount id=[%s] was not authoritative on this server, mounting aborted.", getNetworkId().getValueString().c_str(), mountObject.getNetworkId().getValueString().c_str()));
		return false;
	}

	//-- Reject if the player is not in the world cell
	if (!isInWorldCell())
	{
		DEBUG_WARNING(true, ("mountCreature(): rider id=[%s] is not in the world cell, mounting aborted.", getNetworkId().getValueString().c_str()));
		return false;
	}

	//-- Reject if the mount is not in the world cell
	if (!mountObject.isInWorldCell())
	{
		DEBUG_WARNING(true, ("mountCreature(): mount id=[%s] is not in the world cell, mounting aborted.", mountObject.getNetworkId().getValueString().c_str()));
		return false;
	}

	// ... set the new mount-related states on the rider and mount.  This is necessary
	//     so that I can efficiently handle CreatureObject::onContainerTransferComplete,
	//     which is called before transferItemToSlottedContainer() completes.
	setState(States::RidingMount, true);
	mountObject.setState(States::MountedCreature, true);
	
	Container::ContainerErrorCode errorCode = Container::CEC_Success;
	bool transferSuccess = false;

	// transfer into the first available slot

	int const maxSlots = getSaddleSeatingCapacity(&mountObject);

	for (int i = 0; i < maxSlots; ++i)
	{
		if (ContainerInterface::canTransferToSlot(mountObject, *this, s_riderSlotId[i], NULL, errorCode))
		{
			transferSuccess = ContainerInterface::transferItemToSlottedContainer(mountObject, *this, s_riderSlotId[i], NULL, errorCode);

			if ((transferSuccess) && (errorCode == Container::CEC_Success))
			{
				break;
			}
		}
	}
	
	DEBUG_FATAL(transferSuccess && (errorCode != Container::CEC_Success), ("mountCreature(): transferItemToSlottedContainer() returned success but container error code returned error %d.", static_cast<int>(errorCode)));

	if (!transferSuccess)
	{
		// Clear these states so that the objects are not in a funky bad state.
		setState(States::RidingMount, false);

		if (mountObject.getPrimaryMountingRider() == 0)
		{
			// clear state if empty mount
			mountObject.setState(States::MountedCreature, false);
		}

		return transferSuccess;
	}

	//-- Take the rider out of CollisionWorld.
	// @todo: add all object non-auto-delta change info to another function
	//        that can be called via controller message to proxies, end baselines
	//        on proxies and from here.
	if (isInWorld())
		CollisionWorld::removeObject(this);

	CollisionProperty *const collisionProperty = getCollisionProperty();
	if (collisionProperty)
		collisionProperty->setDisableCollisionWorldAddRemove(true);

	//-- Set the mount's AlterScheduler phase to 1 so that it gets an alter after the rider.
	//   The rider will count on this so that the rider can update the mount's server position
	//   prior to the mount getting altered that frame.
	AlterScheduler::setObjectSchedulePhase(mountObject, 1);

	//-- Tell rider to update movement info so it pulls walk/run speed from the mount.
	updateMovementInfo();
	
	//-- Indicate transfer success.
	return transferSuccess;
}
void MoveSimManager::start (const NetworkId & userId, int numNpcToSpawn, int numPcToSpawn, float radius, float moveSpeed)
{
	if (!ConfigServerGame::getMoveSimEnabled ())
		return;

	const ServerObject * const player = safe_cast<ServerObject *>(NetworkIdManager::getObjectById (userId));

	if (!player)
		return;

	float halfMapWidth = 1000.0f;
	TerrainObject * const terrainObject = TerrainObject::getInstance ();	
	if (terrainObject)
	{
		//- subtract a 512 meter invalid band around the edge of the map
		halfMapWidth = (terrainObject->getMapWidthInMeters () * 0.5f) - 512.0f;
	}

	const Vector & player_pos_w = player->getPosition_w ();

	const int numToSpawn = numPcToSpawn + numNpcToSpawn;

	const float randomRadiusArea = std::min (halfMapWidth * 2.0f, radius * 0.7f);
	for (int i = 0; i < numToSpawn; ++i)
	{
		Vector pos = player_pos_w;
		pos.x += Random::randomReal (-randomRadiusArea, randomRadiusArea);
		pos.z += Random::randomReal (-randomRadiusArea, randomRadiusArea);

		pos.x = std::min (halfMapWidth, std::max (-halfMapWidth, pos.x));
		pos.z = std::min (halfMapWidth, std::max (-halfMapWidth, pos.z));

		float angle = Random::randomReal (0.0f, PI * 2.0f);

		Transform tr;
		tr.setPosition_p(pos);
		tr.yaw_l(angle);

		CreatureObject * creature = 0;
		
		if (numPcToSpawn-- > 0)
		{
			creature = dynamic_cast<CreatureObject *>(ServerWorld::createNewObject(templateName_pc, tr, 0, false));
			creature->setPlayerControlled (true);
			ServerWorld::createNewObject (ConfigServerGame::getPlayerObjectTemplate (), *creature, false);
		}
		else
		{
			creature = dynamic_cast<CreatureObject *>(ServerWorld::createNewObject(templateName_npc, tr, 0, false));
		}

		if (!creature)
			return;

		creature->addToWorld ();

		const float naturalRunSpeed = safe_cast<const SharedCreatureObjectTemplate *>(creature->getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_run);
		const float moveScale = moveSpeed / naturalRunSpeed;

		creature->setMovementScale (moveScale);

		MoveSimController * const msc = new MoveSimController (creature, player_pos_w, radius);
		creature->setController (msc);

		creature->scheduleForAlter ();

		setCreatureObjVars (*creature, player_pos_w, radius);

		s_moveSimCreatures.push_back (creature->getNetworkId ());
	}
}