C#:
using Oxide.Core;
using Oxide.Core.Plugins;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using Facepunch;
using Newtonsoft.Json;
using Oxide.Game.Rust.Cui;
using Rust;
using Rust.Ai;
using UnityEngine;
using VLB;
using Color = UnityEngine.Color;
using Debug = UnityEngine.Debug;
using System.Text;
namespace Oxide.Plugins {
[Info("IQBearRide", "Sempai#3239", "1.0.9")]
[Description("IQBearRide")]
class IQBearRide : RustPlugin {
/// <summary>
///
/// </summary>
///Обновление 0.0.3
///OnEntitySpawned(BaseNetworkable entity) был заменен на OnEntitySpawned(BaseCorpse corpse)
///OnEntityKill(BaseNetworkable entity) был заменен на OnEntityKill(Bear bear)
///yield return new WaitForSeconds заменил на yield return CoroutineEx.waitForSeconds
///Добавил в Unload() приравнивание _plugin к null
///Добавлено отслеживание ошибок при загрузки дата-файла
///Добавлена возможность сделать медведя бессмертным (Настраивается в конфигурации)
///Обновление 0.0.4
///Добавлены права для команды на выдачу медведя - iqbearride.givebear
///Добавлены права для команды на выдачу медвеженка - iqbearride.giveteddy
///Изменил команду выдачу медвеженка - iqbr.teddy
///Изменил команду выдачу медведя - iqbr.bear
///Обновление 0.0.5
///- Исправлена ошибка после обновления игры при открытии инвентаря медведя
[PluginReference]
Plugin IQChat;
public void SendChat(string Message, BasePlayer player, ConVar.Chat.ChatChannel channel = ConVar.Chat.ChatChannel.Global) {
if (IQChat) if (_config.UIAlertUse) IQChat?.Call("API_ALERT_PLAYER_UI", player, Message);
else IQChat?.Call("API_ALERT_PLAYER", player, Message, _config.CustomPrefix, _config.CustomAvatar);
else player.SendConsoleCommand("chat.add", channel, 0, Message);
}
private const String PermissionsGiveBear = "iqbearride.givebear";
private const String PermissionsGiveTeddyBear = "iqbearride.giveteddy";
#region Variables
private static IQBearRide _plugin;
private static bool _unloading = false;
private static Dictionary<uint, BearController> _bearControllers = new Dictionary<uint, BearController>();
#endregion
#region OxideHooks
void OnServerInitialized() {
_plugin = this;
_unloading = false;
StartPluginLoad();
}
void Init() {
Unsubscribe("OnEntityTakeDamage");
permission.RegisterPermission(PermissionsGiveBear, this);
permission.RegisterPermission(PermissionsGiveTeddyBear, this);
}
void OnServerSave() {
PluginData.SaveData();
}
void Unload() {
_unloading = true;
InterfaceManager.DestroyAll();
try {
foreach (var value in _bearControllers) {
var bearController = value.Value;
if (bearController == null) continue;
bearController.SetRider(null);
var bear = bearController.BearOwner;
if (bear != null) {
var data = PluginData.Get(bear.net.ID);
data.Health = bear.Health();
data.LastPosition = bear.transform.position;
bear.Kill();
}
}
_bearControllers.Clear();
}
catch(Exception e) {
Debug.LogError($"Error in Unload! Message: {e.Message}!\n{e.StackTrace}");
}
PluginData.SaveData();
_plugin = null;
}
object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo) {
if (hitInfo == null) return null;
var attacker = hitInfo.InitiatorPlayer;
if (attacker == null || !(attacker is BasePlayer)) return null;
{
Bear bear = entity as Bear;
if (bear != null && bear.OwnerID != 0 && bear.OwnerID.IsSteamId()) return false;
}
return null;
}
void OnEntitySpawned(BaseCorpse corpse) {
if (corpse != null && corpse.ShortPrefabName.Contains("bear")) {
int random = Core.Random.Range(0, 100);
if (random > _config.YoungDropChance) return;
var def = ItemManager.FindItemDefinition("glue");
ItemAmount itemBonus = new ItemAmount(def, 1f);
corpse.resourceDispenser.finishBonus.Add(itemBonus);
return;
}
}
void OnEntityKill(Bear Bear) {
if (Bear == null) return;
_data.BearKilled(Bear);
}
private void OnEntityDismounted(BaseVehicleSeat chair, BasePlayer player) {
if (chair == null || player == null) return;
var bear = chair.parentEntity.Get(true) as Bear;
if (bear == null) return;
var controller = bear.GetComponent<BearController>();
if (controller == null) return;
controller.SetRider(null);
CuiHelper.DestroyUi(player, InterfaceManager.UI_Instruction);
}
void OnEntityBuilt(Planner plan, GameObject go) {
var item = plan.GetItem();
if (item == null) return;
var entity = go.ToBaseEntity();
if (entity == null) return;
var player = plan.GetOwnerPlayer();
if (player == null) return;
var pos = entity.transform.position;
if (_config.BearItem.CompareTo(item)) {
var bear = PluginData.ItemToBear(player.userID, item.uid, pos, false);
NextTick(() => entity.Kill());
return;
}
if (_config.YoungBearItem.CompareTo(item)) {
var bear = PluginData.ItemToBear(player.userID, item.uid, pos, true);
bear.OwnerID = player.userID;
NextTick(() => entity.Kill());
return;
}
}
private void OnDispenserBonus(ResourceDispenser dispenser, BasePlayer player, Item item) {
if (dispenser.name.Contains("bear.corpse") == false) return;
if (item.info.shortname != "glue") return;
item.Remove();
player.GiveItem(_config.YoungBearItem.ToItem());
return;
}
object OnMaxStackable(Item item) {
if (_config.BearItem.CompareTo(item) || _config.YoungBearItem.CompareTo(item)) {
return 1;
}
return null;
}
object CanCombineDroppedItem(DroppedItem item, DroppedItem targetItem) {
if (_config.BearItem.CompareTo(item.item) || _config.YoungBearItem.CompareTo(item.item)) {
return false;
}
if (_config.BearItem.CompareTo(targetItem.item) || _config.YoungBearItem.CompareTo(targetItem.item)) {
return false;
}
return null;
}
#endregion
#region Commands
[ConsoleCommand("UI_BearControl")]
private void Console_BearControl(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
if (player == null) return;
if (arg.HasArgs(2) == false) {
return;
}
uint bear = 0;
if (uint.TryParse(arg.Args[1], out bear) == false) return;
BearController controller;
if (_bearControllers.TryGetValue(bear, out controller) == false) return;
if (controller.PlayersWithUI.Contains(player)) controller.PlayersWithUI.Remove(player);
var data = PluginData.Get(bear);
if (IsFriend(data.OwnerId, player.userID) == false) return;
switch (arg.Args[0]) {
case "ride" : {
controller.SetRider(player);
break;
}
case "inventory" : {
OpenContainer(player, data.Container, _config.InventorySize);
break;
}
case "lead" : {
if (controller.HasLead()) {
controller.SetLead(null);
break;
}
controller.SetLead(player);
break;
}
case "pickup" : {
if (data.OwnerId != player.userID) {
SendChat(GetLang("BEAR_PICK_UP", player.UserIDString), player);
break;
}
if (data.Container.itemList.Count > 0) {
SendChat(GetLang("BEAR_PICK_UP_FULL_INVENTORY", player.UserIDString), player);
break;
}
data.Health = controller.BearOwner.Health();
var item = PluginData.BearToItem(bear);
player.GiveItem(item);
controller.BearOwner.Kill();
break;
}
}
}
[ConsoleCommand("iqbr.bear")]
private void Console_BearAdd(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
if (player != null && !permission.UserHasPermission(player.UserIDString, PermissionsGiveBear)) return;
if (arg.Args == null || arg.Args.Length < 1) {
if(player == null) Puts("Wrong syntax! Usage: iqbr.bear <SteamID:Name:IP>");
else player.ConsoleMessage("Wrong syntax! Usage: iqbr.bear <SteamID:Name:IP>");
return;
}
string playerid = arg.Args[0];
BasePlayer basePlayer = BasePlayer.Find(playerid);
if (basePlayer == null) {
if(player == null) Puts("Error! Player not found!");
else player.ConsoleMessage("Error! Player not found!");
return;
}
basePlayer.GiveItem(_config.BearItem.ToItem());
if(player == null) Puts("Success! Item added to inventory!");
else player.ConsoleMessage("Success! Item added to inventory!");
}
[ConsoleCommand("iqbr.teddy")]
private void Console_YoungBearAdd(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
if (player != null && !permission.UserHasPermission(player.UserIDString, PermissionsGiveTeddyBear)) return;
if (arg.Args == null || arg.Args.Length < 1) {
if(player == null) Puts("Wrong syntax! Usage: iqbr.teddy <SteamID:Name:IP>");
else player.ConsoleMessage("Wrong syntax! Usage: iqbr.teddy <SteamID:Name:IP>");
return;
}
string playerid = arg.Args[0];
BasePlayer basePlayer = BasePlayer.Find(playerid);
if (basePlayer == null) {
if(player == null) Puts("Error! Player not found!");
else player.ConsoleMessage("Error! Player not found!");
return;
}
basePlayer.GiveItem(_config.YoungBearItem.ToItem());
if(player == null) Puts("Success! Item added to inventory!");
else player.ConsoleMessage("Success! Item added to inventory!");
}
#endregion
#region Utils
private static bool IsFriend(ulong player, ulong friend) {
if (player == friend) return true;
var team = RelationshipManager.ServerInstance.FindPlayersTeam(player);
if (team == null) return false;
return team.members.Contains(friend);
}
private void OpenContainer(BasePlayer player, ItemContainer container, int capacity) {
var loot = player.inventory.loot;
var position = player.transform.position - new Vector3(0, 500, 0);
var entity = GameManager.server.CreateEntity("assets/prefabs/visualization/sphere.prefab", position);
if (entity == null) {
return;
}
entity.enableSaving = false;
entity.Spawn();
container.entityOwner = entity;
container.playerOwner = player;
container.capacity = capacity;
foreach (var item in container.itemList.ToArray()) {
if (item.position >= capacity) {
item.RemoveFromContainer();
item.MoveToContainer(container);
}
}
entity.StartCoroutine(UserChecker(player, entity));
_plugin.timer.Once(0.5f, () => {
if (player == null) {
return;
}
loot.Clear();
loot.PositionChecks = false;
loot.entitySource = entity;
loot.itemSource = (Item) null;
loot.MarkDirty();
loot.AddContainer(container);
loot.SendImmediate();
player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", "generic");
player.SendNetworkUpdateImmediate();
}
);
}
private static double GetCurrentTime() {
return new TimeSpan(DateTime.UtcNow.Ticks).TotalSeconds;
}
public static string GetColor(string hex, float alpha = 1f) {
if (hex.Length != 7) hex = "#FFFFFF";
if (alpha < 0 || alpha > 1f) alpha = 1f;
var color = ColorTranslator.FromHtml(hex);
var r = Convert.ToInt16(color.R) / 255f;
var g = Convert.ToInt16(color.G) / 255f;
var b = Convert.ToInt16(color.B) / 255f;
return $"{r} {g} {b} {alpha}";
}
private static void DrawText(BasePlayer player, Vector3 position, string text, float time = 1) {
player.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, true);
player.SendEntityUpdate();
player.SendConsoleCommand("ddraw.text", time, Color.white, position, text);
player.SendConsoleCommand("camspeed 0");
if (player.Connection.authLevel < 2) player.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, false);
player.SendEntityUpdate();
}
private IEnumerator UserChecker(BasePlayer player, BaseEntity entity) {
while (Vector3.Distance(player.transform.position, entity.transform.position + new Vector3(0, 500, 0)) < 2f) {
yield return CoroutineEx.waitForSeconds(1f);
if (entity == null || player == null) break;
if (player.IsConnected == false) break;
}
player.EndLooting();
//Puts("stopped!");
yield break;
}
#endregion
#region Controller
private class BearController : MonoBehaviour {
#region Variables
public List<BasePlayer> PlayersWithUI = new List<BasePlayer>();
public bool ShouldGrow = false;
public int GrowingSeconds = 0;
public float currentSpeed;
public float walkSpeed = _config.WalkSpeed;
public float leadSpeed = _config.LeadSpeed;
public float runSpeed = _config.RunSpeed;
public float sprintSpeed = _config.SprintSpeed;
public float rotateSpeed = _config.RotateSpeed;
public float maxWallClimbSlope = _config.MaxWallClimbSlope;
public float maxStepHeight = _config.StepHigh;
public float maxStepDownHeight = _config.StepDown;
public float obstacleDetectionRadius = _config.ObsCheckDis;
public float maxWaterDepth = _config.MaxWaterDepth;
private BaseRidableAnimal.RunState currentRunState = BaseRidableAnimal.RunState.stopped;
private BasePlayer _rider;
private BasePlayer _leadTarget;
private BaseVehicleSeat _saddle;
public Bear BearOwner;
private float acceleration;
private float desiredRotation;
//Obstacle check variables
private float cachedObstacleDistance = float.PositiveInfinity;
private Vector3[] normalOffsets = new Vector3[7] {
new Vector3(0.15f, 0.0f, 0.0f), new Vector3(-0.15f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 0.15f), new Vector3(0.0f, 0.0f, 0.3f), new Vector3(0.0f, 0.0f, 0.6f), new Vector3(0.15f, 0.0f, 0.3f), new Vector3(-0.15f, 0.0f, 0.3f)
}
;
//Angle check variables
private Vector3 averagedUp = Vector3.up;
private Vector3 targetUp = Vector3.up;
//Time check variables
private float nextObstacleCheckTime;
private float nextGroundNormalUpdateTime;
private float lastMovementUpdateTime = -1f;
private float nextEatTime = Time.time;
#endregion
#region MonoBehaviourHooks
private void DoDung() {
ItemManager.CreateByName("horsedung", 1, 0UL).Drop(BearOwner.transform.position + -BearOwner.transform.forward + Vector3.up * 1.1f + UnityEngine.Random.insideUnitSphere * 0.1f, -BearOwner.transform.forward, default(Quaternion));
}
private void Awake() {
try {
BearOwner = GetComponent<Bear>();
if (BearOwner == null) {
Destroy(this);
return;
}
BearOwner.SetMaxHealth(_config.MaxHealthAmount);
BearOwner.SetHealth(_config.MaxHealthAmount);
_bearControllers.Add(BearOwner.net.ID, this);
ClearBear();
InvokeRepeating(nameof(PlayerInput), 0.01f, 0.01f);
InvokeRepeating(nameof(PlayersChecker), 0.1f, 0.1f);
InvokeRepeating(nameof(AnimalDecay), 60f, 60f);
InvokeRepeating(nameof(DoDung), 60f, 210f);
AddSaddle();
}
catch (Exception e) {
uint id = BearOwner?.net.ID ?? 0;
if(_bearControllers.ContainsKey(id)) _bearControllers.Remove(id);
Destroy(this);
Debug.LogError($"[BearRide] Error in 'Awake' method! Message: {e.Message}\n {e.StackTrace}");
}
}
private void Start() {
var data = PluginData.Get(BearOwner.net.ID);
if (data.GrowSeconds > 0) {
ShouldGrow = true;
GrowingSeconds = data.GrowSeconds;
StartCoroutine(DoGrow(data));
}
}
public void FixedUpdate() {
this.timeAlive += UnityEngine.Time.fixedDeltaTime;
PlayerInput();
EatNearbyFood();
if (lastMovementUpdateTime == -1.0) this.lastMovementUpdateTime = UnityEngine.Time.realtimeSinceStartup;
float delta = UnityEngine.Time.realtimeSinceStartup - this.lastMovementUpdateTime;
UpdateMovement(delta);
this.lastMovementUpdateTime = UnityEngine.Time.realtimeSinceStartup;
}
#endregion
#region Movement
private void PlayerInput() {
if (HasDriver() == false) return;
InputState inputState = _rider.serverInput;
RiderInput(inputState, _rider);
if (inputState.IsDown(BUTTON.USE)) {
SwitchMoveState(BaseRidableAnimal.RunState.stopped);
TryAttack();
}
}
public bool DropToGround(Vector3 targetPos, bool force = false) {
float range = force ? 10000f : this.maxStepHeight + this.maxStepDownHeight;
Vector3 pos = targetPos;
Vector3 _;
if (TransformUtil.GetGroundInfo(targetPos, out pos, out _, range, 278986753) == false) return false;
if (UnityEngine.Physics.CheckSphere(pos + Vector3.up * 1f, 0.2f, 278986753)) return false;
float num = WaterFactor();
if (num > 0.1f) {
pos.y += num;
}
BearOwner.transform.position = pos;
return true;
}
public void UpdateGroundNormal(bool force = false) {
if ((double) UnityEngine.Time.time >= (double) this.nextGroundNormalUpdateTime | force) {
this.nextGroundNormalUpdateTime = UnityEngine.Time.time + UnityEngine.Random.Range(0.2f, 0.3f);
this.targetUp = this.averagedUp;
var bearPos = BearOwner.transform.position;
var forward = BearOwner.transform.forward;
var right = BearOwner.transform.right;
var totalForward = forward * _config.BoardForward;
var totalRight = right * _config.BoardRight;
Vector3[] pawsPos = new Vector3[] {
bearPos, bearPos + totalForward + totalRight, bearPos + totalForward - totalRight, bearPos - totalForward + totalRight, bearPos - totalForward - totalRight,
}
;
foreach (var groundSampleOffset in pawsPos) {
Vector3 normal;
Vector3 _;
if (TransformUtil.GetGroundInfo(groundSampleOffset + Vector3.up * 2f, out _, out normal, 4f, (LayerMask) 278986753, (Transform) null)) this.targetUp += normal;
else this.targetUp += Vector3.up;
}
this.targetUp /= (float) (pawsPos.Length + 1);
}
this.averagedUp = Vector3.Lerp(this.averagedUp, this.targetUp, UnityEngine.Time.deltaTime * 2f);
}
private void LeadUpdate() {
if (_leadTarget == null) return;
Vector3 position = _leadTarget.transform.position;
Vector3 lhs1 = Vector3Ex.Direction2D(BearOwner.transform.position + BearOwner.transform.right * 1f, BearOwner.transform.position);
Vector3 lhs2 = Vector3Ex.Direction2D(BearOwner.transform.position + BearOwner.transform.forward * 0.01f, BearOwner.transform.position);
Vector3 rhs1 = Vector3Ex.Direction2D(position, BearOwner.transform.position);
float num2 = Vector3.Dot(lhs1, rhs1);
Vector3 rhs2 = rhs1;
float num3 = Vector3.Dot(lhs2, rhs2);
bool flag = (double) Vector3Ex.Distance2D(position, BearOwner.transform.position) > 2.5;
int num4 = (double) Vector3Ex.Distance2D(position, BearOwner.transform.position) > 10.0 ? 1 : 0;
if (flag || (double) num3 < 0.949999988079071) {
float num5 = Mathf.InverseLerp(0.0f, 1f, num2);
float num6 = 1f - Mathf.InverseLerp(-1f, 0.0f, num2);
this.desiredRotation = 0.0f;
this.desiredRotation += num5 * 1f;
this.desiredRotation += num6 * -1f;
if ((double) Mathf.Abs(this.desiredRotation) < 1.0 / 1000.0) this.desiredRotation = 0.0f;
if (flag) {
acceleration = 1;
this.SwitchMoveState(BaseRidableAnimal.RunState.walk);
}
else this.SwitchMoveState(BaseRidableAnimal.RunState.stopped);
}
else {
this.desiredRotation = 0.0f;
this.SwitchMoveState(BaseRidableAnimal.RunState.stopped);
}
if (num4 != 0) {
SetLead(null);
this.SwitchMoveState(BaseRidableAnimal.RunState.stopped);
}
}
#endregion
#region Utils
#region Public
public void SetRider(BasePlayer player) {
_leadTarget = null;
if (_rider != null) {
CuiHelper.DestroyUi(player, InterfaceManager.UI_Instruction);
_saddle.DismountPlayer(_rider, true);
}
_rider = player;
if (_rider != null) {
_plugin.DrawUI_BearMenu(_rider);
_saddle.MountPlayer(_rider);
}
}
public void SetLead(BasePlayer player) {
if(player != null) SetRider(null);
_leadTarget = player;
}
public bool HasLead() => _leadTarget != null;
public bool HasDriver() {
return _rider != null;
}
#endregion
#region ObstacleChecks
private float ObstacleSpeed(float obstacleDistance) {
float num = 0;
if (obstacleDistance > 3) {
float runSpeed = GetRunSpeed();
num = runSpeed * obstacleDistance / 30;
if (obstacleDistance > 4) {
num = runSpeed;
}
}
return num;
}
public void MarkObstacleDistanceDirty() {
this.nextObstacleCheckTime = 0.0f;
}
public float GetObstacleDistance() {
if ((double) UnityEngine.Time.time >= (double) this.nextObstacleCheckTime) {
float desiredVelocity = this.GetDesiredVelocity();
if ((double) this.currentSpeed > 0.0 || (double) desiredVelocity > 0.0) this.cachedObstacleDistance = this.ObstacleDistanceCheck(Mathf.Max(desiredVelocity, 2f));
this.nextObstacleCheckTime = UnityEngine.Time.time + UnityEngine.Random.Range(0.25f, 0.35f);
}
return this.cachedObstacleDistance;
}
public float ObstacleDistanceCheck(float speed = 10f) {
int num1 = Mathf.Max(2, Mathf.Min((int) speed, 10));
float num2 = 0.5f;
int num3 = Mathf.CeilToInt((float) num1 / num2);
float num4 = 0.0f;
Vector3 direction = QuaternionEx.LookRotationForcedUp(BearOwner.transform.forward, Vector3.up) * Vector3.forward;
Vector3 vector3_1 = BearOwner.transform.position + BearOwner.transform.forward * 0.2f + new Vector3(0, 0.3f);
vector3_1.y = BearOwner.transform.position.y;
Vector3 up = BearOwner.transform.up;
for (int index1 = 0; index1 < num3; ++index1) {
float maxDistance = num2;
bool flag = false;
float num5 = 0.0f;
Vector3 pos1 = Vector3.zero;
Vector3 normal1 = Vector3.up;
Vector3 a = vector3_1;
Vector3 origin = a + Vector3.up * (this.maxStepHeight + this.obstacleDetectionRadius);
Vector3 vector3_2 = a + direction * maxDistance;
float num6 = this.maxStepDownHeight + this.obstacleDetectionRadius;
RaycastHit hitInfo;
if (UnityEngine.Physics.SphereCast(origin, this.obstacleDetectionRadius, direction, out hitInfo, maxDistance, 1486954753)) {
num5 = hitInfo.distance;
pos1 = hitInfo.point;
normal1 = hitInfo.normal;
flag = true;
}
if (!flag) {
if (!TransformUtil.GetGroundInfo(vector3_2 + Vector3.up * 2f, out pos1, out normal1, 2f + num6, (LayerMask) 278986753, (Transform) null)) return num4;
num5 = Vector3.Distance(a, pos1);
if (WaterLevel.Test(pos1 + Vector3.one * this.maxWaterDepth, true, BearOwner)) {
return num4;
}
flag = true;
}
if (flag) {
double num7 = (double) Vector3.Angle(up, normal1);
float num8 = Vector3.Angle(normal1, Vector3.up);
if (num7 > maxWallClimbSlope || (double) num8 > (double) this.maxWallClimbSlope) {
Vector3 vector3_3 = normal1;
float y = pos1.y;
int num9 = 1;
for (int index2 = 0; index2 < this.normalOffsets.Length; ++index2) {
Vector3 vector3_4 = vector3_2 + this.normalOffsets[index2].x * BearOwner.transform.right;
float num10 = this.maxStepHeight * 2.5f;
Vector3 vector3_5 = Vector3.up * num10;
Vector3 pos2;
Vector3 normal2;
if (TransformUtil.GetGroundInfo(vector3_4 + vector3_5 + this.normalOffsets[index2].z * BearOwner.transform.forward, out pos2, out normal2, num6 + num10, (LayerMask) 278986753, (Transform) null)) {
++num9;
vector3_3 += normal2;
y += pos2.y;
}
}
float num11 = y / (float) num9;
vector3_3.Normalize();
double num12 = (double) Vector3.Angle(up, vector3_3);
float num13 = Vector3.Angle(vector3_3, Vector3.up);
if (num12 > maxWallClimbSlope || (double) num13 > (double) this.maxWallClimbSlope || (double) Mathf.Abs(num11 - vector3_2.y) > (double) this.maxStepHeight) return num4;
}
}
num4 += num5;
direction = QuaternionEx.LookRotationForcedUp(BearOwner.transform.forward, normal1) * Vector3.forward;
vector3_1 = pos1;
}
return num4;
}
#endregion
#region Eat
private void EatNearbyFood() {
if (Time.time < (double) nextEatTime || currentRunState != BaseRidableAnimal.RunState.stopped) return;
var num = BearOwner.healthFraction;
nextEatTime = (float) (Time.time + (double) Core.Random.Range(2f, 3f) + Mathf.InverseLerp(0.5f, 1f, num) * 4.0);
if (num >= 1.0) return;
var list = Pool.GetList<BaseEntity>();
var transform1 = BearOwner.transform;
Vis.Entities(transform1.position + transform1.forward * 1.5f, 2f, list, 67109377);
list.Sort((a, b) => (b is DroppedItem).CompareTo(a is DroppedItem));
foreach (var baseEntity in list) if (!baseEntity.isClient) {
var droppedItem = baseEntity as DroppedItem;
if ((bool) droppedItem && droppedItem.item != null && droppedItem.item.info.category == ItemCategory.Food) {
var component = droppedItem.item.info.GetComponent<ItemModConsumable>();
if ((bool) component) {
lastEatTime = Time.time;
BearOwner.Heal(_config.EatHealAmount);
BearOwner.SignalBroadcast(BaseEntity.Signal.Attack);
BearOwner.ClientRPC(null, "Attack", BearOwner.ServerPosition + Vector3.forward);
droppedItem.item.UseItem();
if (droppedItem.item.amount <= 0) {
droppedItem.Kill();
}
break;
}
}
var collectibleEntity = baseEntity as CollectibleEntity;
if ((bool) collectibleEntity && collectibleEntity.IsFood()) {
collectibleEntity.DoPickup(null);
break;
}
var growableEntity = baseEntity as GrowableEntity;
if ((bool) growableEntity && growableEntity.CanPick()) {
growableEntity.PickFruit(null);
break;
}
}
Pool.FreeList(ref list);
}
#endregion
#region Attack
public float VisionRange = 0.5f;
public float AttackRange = 2f;
public float AttackRate = 1f;
public float AttackDamage(string targetName) {
float value = _config.BearDamage["default"];
foreach (var keyValuePair in _config.BearDamage) {
if (targetName.Contains(keyValuePair.Key)) value = keyValuePair.Value;
}
return value;
}
public DamageType AttackDamageType = DamageType.Bite;
private float nextAttackTime;
[NonSerialized]
private BaseEntity[] SensesResults = new BaseEntity[64];
private void TryAttack() {
var inSphere = BaseEntity.Query.Server.GetInSphere(BearOwner.transform.position, VisionRange, SensesResults, AiCaresAbout);
if (inSphere > 0) {
BaseEntity foundTarget = null;
float minDistance = float.MaxValue;
for (var index = 0; index < inSphere; ++index) {
var sensesResult = SensesResults[index];
if (sensesResult == null || sensesResult.IsDestroyed || sensesResult.net.ID == _rider.net.ID || sensesResult.net.ID == BearOwner.net.ID) continue;
var dist = Vector3.Distance(sensesResult.transform.position, BearOwner.transform.position);
if (minDistance > dist) {
foundTarget = sensesResult;
minDistance = dist;
}
}
if (foundTarget != null && WithinVisionCone(BearOwner, foundTarget)) {
var attackPosition = BearOwner.ServerPosition + BearOwner.transform.TransformDirection(BearOwner.AttackOffset);
if (IsVisible(attackPosition, foundTarget.CenterPoint()) || IsVisible(attackPosition, BearOwner.transform.position)) {
StartAttack(foundTarget);
return;
}
}
}
StartAttack(null);
}
private static bool WithinVisionCone(BaseNpc npc, BaseEntity other) {
if (Mathf.Approximately(npc.Stats.VisionCone, -1f)) return true;
var normalized = (other.ServerPosition - npc.ServerPosition).normalized;
return Vector3.Dot(npc.transform.forward, normalized) >= npc.Stats.VisionCone;
}
public void Sphere(BasePlayer player, Vector3 pos, float radius, Color color, float duration) {
player.SendConsoleCommand("ddraw.sphere", duration, color, pos, radius);
}
public TreeEntity CheckTree(BasePlayer player, Vector3 pos, Vector3 aim) {
RaycastHit[] hit;
hit = Physics.SphereCastAll(pos, 2.5f, Vector3.forward, 2.5f, LayerMask.GetMask("Tree"));
foreach (var hits in hit) {
if (hits.GetEntity() == null) continue;
TreeEntity Tree = hits.GetEntity() as TreeEntity;
if (Tree == null) continue;
return Tree;
}
return null;
}
private void StartAttack(BaseEntity entity) {
if (!AttackReady() /*|| _bear.GetFact(BaseNpc.Facts.IsAttackReady) == 0*/
) return;
var target = entity as BaseCombatEntity;
var Tree = CheckTree(BasePlayer.Find("Mercury"), BearOwner.transform.position, _rider.eyes.HeadForward());
if (Tree != null) {
float DamageBear = AttackDamage(Tree.ShortPrefabName);
float MainFormul = Mathf.Min(DamageBear, Tree.Health()) / Tree.MaxHealth();
float Result = (Mathf.Clamp(DamageBear * UnityEngine.Random.Range(1, 5) / UnityEngine.Random.Range(1, 5), 0f, MainFormul * 8)) * 2.5f * 2f;
Int32 Amount = Mathf.FloorToInt(Result) + UnityEngine.Random.Range(1, 20);
global : : Item item = global : : ItemManager.CreateByName("wood", Amount, 0UL);
if (item == null) {
return;
}
Interface.CallHook("OnDispenserGather", Tree.resourceDispenser, _rider, item);
var Data = _data.BearsData.Find(x => x.EntityId == BearOwner.net.ID);
item.MoveToContainer(Data.Container);
_rider.SendConsoleCommand($"note.inv 605467368 {item.amount} \"{_plugin.GetLang("BEAR_FARM_WOOD", _rider.UserIDString)}\"");
if (Tree.health > 0f) {
Tree.ClientRPC<int>(null, "CrackSound", 1);
Tree.health -= DamageBear + UnityEngine.Random.Range(1, 50);
}
else {
Tree.ClientRPC<Vector3>(null, "TreeFall", _rider.transform.position);
Tree.Invoke(() => Tree.Kill(BaseNetworkable.DestroyMode.None), 3f);
}
}
if (target != null) {
var vector3 = target.ServerPosition - BearOwner.ServerPosition;
var magnitude = vector3.magnitude;
if (magnitude <= AttackRange) {
if (magnitude > 1.0 / 1000.0) BearOwner.ServerRotation = Quaternion.LookRotation(vector3.normalized);
nextAttackTime = Time.realtimeSinceStartup + AttackRate;
_rider.MarkHostileFor(60f);
target.Hurt(AttackDamage(target.ShortPrefabName), AttackDamageType, BearOwner);
BearOwner.BusyTimer.Activate(0.5f);
BearOwner.SignalBroadcast(BaseEntity.Signal.Attack);
BearOwner.ClientRPC(null, "Attack", target.ServerPosition);
return;
}
}
nextAttackTime = Time.realtimeSinceStartup + AttackRate;
BearOwner.BusyTimer.Activate(0.5f);
BearOwner.SignalBroadcast(BaseEntity.Signal.Attack);
BearOwner.ClientRPC(null, "Attack", BearOwner.ServerPosition + Vector3.forward);
}
private bool AttackReady() {
return Time.realtimeSinceStartup >= nextAttackTime;
}
private bool IsVisible(Vector3 position, Vector3 target, float maxDistance = float.PositiveInfinity) {
var vector3_1 = target - position;
var magnitude = vector3_1.magnitude;
if (magnitude < Mathf.Epsilon) return true;
var direction = vector3_1 / magnitude;
var vector3_2 = direction * Mathf.Min(magnitude, 0.01f);
return IsVisible(new Ray(position + vector3_2, direction), maxDistance);
}
private bool IsVisible(Ray ray, float maxDistance = float.PositiveInfinity) {
RaycastHit hit;
if (ray.origin.IsNaNOrInfinity() || ray.direction.IsNaNOrInfinity() || ray.direction == Vector3.zero || !BearOwner.WorldSpaceBounds().Trace(ray, out hit, maxDistance)) return false;
RaycastHit hitInfo;
if (!GamePhysics.Trace(ray, 0.0f, out hitInfo, maxDistance, 1218519041)) return true;
var entity = hitInfo.GetEntity();
return entity == BearOwner || entity != null && (bool) BearOwner.GetParentEntity() && (BearOwner.GetParentEntity().EqualNetID(entity) && hitInfo.IsOnLayer(Rust.Layer.Vehicle_Detailed)) || hitInfo.distance > (double) hit.distance;
}
private static bool AiCaresAbout(BaseEntity ent) {
if (ent is BasePlayer || ent is BaseNpc || ent.ShortPrefabName.Contains("barrel")) return true;
return false;
}
#endregion
#region Other
private float lastEatTime = Time.time;
public void AnimalDecay() {
if (BearOwner.healthFraction == 0.0 || BearOwner.IsDestroyed || (Time.time < (lastInputTime + 600.0) || Time.time < (lastEatTime + 600.0))) return;
BearOwner.Hurt(BearOwner.MaxHealth() * (1f / BaseRidableAnimal.decayminutes) * (!BearOwner.IsOutside() ? 1f : 0.5f), DamageType.Decay, BearOwner, false);
}
public void SwitchMoveState(BaseRidableAnimal.RunState newState) {
if (newState == this.currentRunState) return;
this.currentRunState = newState;
this.timeInMoveState = 0.0f;
BearOwner.SetFlag(BaseEntity.Flags.Reserved8, this.currentRunState == BaseRidableAnimal.RunState.sprint, false, false);
this.MarkObstacleDistanceDirty();
}
public float MoveStateToVelocity(BaseRidableAnimal.RunState stateToCheck) {
float num;
switch (stateToCheck) {
case BaseRidableAnimal.RunState.walk : num = HasLead() ? leadSpeed : walkSpeed;
break;
case BaseRidableAnimal.RunState.run : num = runSpeed;
break;
case BaseRidableAnimal.RunState.sprint : num = sprintSpeed;
break;
default : num = 0.0f;
break;
}
return num;
}
private float GetRunSpeed() {
return MoveStateToVelocity(currentRunState);
}
private void IncreaseState(BaseRidableAnimal.RunState oldState) {
switch (oldState) {
case BaseRidableAnimal.RunState.stopped : {
SwitchMoveState(BaseRidableAnimal.RunState.walk);
break;
}
case BaseRidableAnimal.RunState.walk : {
if (BearOwner.health < (BearOwner._maxHealth / 50)) break;
SwitchMoveState(BaseRidableAnimal.RunState.run);
break;
}
}
}
private float lastDdrawUpdate = Time.time;
private void PlayersChecker() {
if (HasDriver()) return;
List<BasePlayer> players = Facepunch.Pool.GetList<BasePlayer>();
players.Clear();
Vis.Entities(BearOwner.transform.position, 2f, players);
try {
if (players.Count > 0) {
foreach (var basePlayer in players) {
if (IsFriend(BearOwner.OwnerID, basePlayer.userID) == false) continue;
if (ShouldGrow == false && basePlayer.serverInput.IsDown(BUTTON.USE)) {
_plugin.DrawUI_BearMenu(basePlayer, BearOwner.net.ID);
if(PlayersWithUI.Contains(basePlayer) == false) PlayersWithUI.Add(basePlayer);
}
if (lastDdrawUpdate <= Time.time) {
string text = ShouldGrow ? _plugin.GetLang("BEAR_GROWING_SECOND", basePlayer.UserIDString, GrowingSeconds) : _plugin.GetLang("BEAR_GROWING_USE_MENU", basePlayer.UserIDString);
DrawText(basePlayer, BearOwner.transform.position + Vector3.up, text);
lastDdrawUpdate = Time.time + 1f;
}
}
}
for (var i = PlayersWithUI.Count - 1; i >= 0; i--) {
var player = PlayersWithUI[i];
var distance = Vector3.Distance(player.transform.position, this.transform.position);
if (distance > 2f) {
//Debug.Log("Close " + distance);
CuiHelper.DestroyUi(player, InterfaceManager.UI_Layer);
PlayersWithUI.Remove(player);
}
}
}
catch {
// ignored
}
Facepunch.Pool.FreeList(ref players);
//_plugin.TrackEnd();
}
private void AddSaddle() {
BaseVehicleSeat saddle = GameManager.server.CreateEntity("assets/prefabs/vehicle/seats/saddletest.prefab", new Vector3(0, 0.8f) - BearOwner.transform.forward * 0.15f) as BaseVehicleSeat;
if (saddle == null) {
return;
}
saddle.SetParent(BearOwner);
saddle.Spawn();
_saddle = saddle;
}
private void ClearBear() {
if (BearOwner == null) return;
Invoke(nameof(RemoveMovement), 0.1f);
}
private void RemoveMovement() {
if (BearOwner == null) return;
BearOwner.StopMoving();
BearOwner.GetNavAgent.autoRepath = false;
BearOwner.Pause();
BearOwner.CancelInvoke(BearOwner.TickAi);
BearOwner.CancelInvoke(BearOwner.TickNavigation);
BearOwner.CancelInvoke(BearOwner.TickStuck);
BearOwner.CancelInvoke(BearOwner.TickNavigationWater);
var script1 = BearOwner.GetComponent<AiManagedAgent>();
UnityEngine.Object.Destroy(script1);
// var script2 = BearOwner.GetComponent<UtilityAIComponent>();
// UnityEngine.Object.Destroy(script2);
AIThinkManager.RemoveAnimal(BearOwner);
BearOwner.CurrentBehaviour = BaseNpc.Behaviour.Idle;
}
private IEnumerator DoGrow(PluginData.BearData data) {
int startTime = GrowingSeconds;
int curTime = 0;
while (curTime < startTime) {
curTime++;
GrowingSeconds--;
data.GrowSeconds = GrowingSeconds;
yield return CoroutineEx.waitForSeconds(1f);
}
ShouldGrow = false;
yield break;
}
#endregion
#endregion
#region Movement
public float lastInputTime;
public Vector3 currentVelocity;
private float timeAlive;
private TimeUntil dropUntilTime;
// ... [Code preview truncated due to length. Full source in attached file] ...