This commit is contained in:
LadyAliceMargatroid 2024-04-28 14:41:33 -07:00
parent 7a77b79dc5
commit cdadd75ee9
104 changed files with 9416 additions and 0 deletions

View file

@ -0,0 +1,257 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using HarmonyLib;
using Unity.Netcode;
using ScarletMansion.GamePatch.Components;
using DunGen;
using Key = UnityEngine.InputSystem.Key;
using ScarletMansion.Lights;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
namespace ScarletMansion.GamePatch.Managers {
public class AngerManager : MonoBehaviour, IDungeonCompleteReceiver {
public static AngerManager Instance { get; private set; }
//public Dictionary<EnemyAI, int> angeredEnemies;
public int level;
public List<ScarletBedroom> bedrooms;
public List<ScarletDoor> doors;
public List<ScarletLight> lights;
//public KeyboardFloatDebug metal = new KeyboardFloatDebug("metal", 0f, 0f, 1f, 0.1f, Key.Numpad4, Key.Numpad7);
//public KeyboardFloatDebug smooth = new KeyboardFloatDebug("smooth", 0f, 0f, 1f, 0.1f, Key.Numpad6, Key.Numpad9);
void Awake(){
Instance = this;
bedrooms = new List<ScarletBedroom>();
doors = new List<ScarletDoor>();
lights = new List<ScarletLight>();
}
/*
void Update(){
var enabled = 0;
var active = 0;
var total = 0;
foreach(var l in lights){
if (l.enabled) enabled++;
if (l.gameObject.activeInHierarchy) active++;
total++;
}
Plugin.logger.LogInfo($"{enabled}|{active}/{total}");
}
*/
/*
void Update(){
var deltaIntensity = 0;
if (Utility.IfKeyPress(Key.Numpad7)) {
deltaIntensity = 1;
} else if (Utility.IfKeyPress(Key.Numpad4)) {
deltaIntensity = -1;
}
var deltaRange = 0;
if (Utility.IfKeyPress(Key.Numpad9)) {
deltaRange = 1;
} else if (Utility.IfKeyPress(Key.Numpad6)) {
deltaRange = -1;
}
if (deltaIntensity != 0 || deltaRange != 0){
var tile = Utility.GetClosestTileToPlayer();
var lights = tile.GetComponentsInChildren<ScarletLight>();
var localPlayer = StartOfRound.Instance.localPlayerController.transform.position;
var closestLight = lights.OrderBy(t => Vector3.SqrMagnitude(t.transform.position - localPlayer)).FirstOrDefault();
if (closestLight != null) {
closestLight.light.intensity += deltaIntensity * 0.5f;
closestLight.light.range += deltaRange * 0.25f;
Plugin.logger.LogInfo($"{closestLight.light.intensity}, {closestLight.light.range}");
}
}
}
*/
public void Anger(int angerAmount = 1){
Plugin.logger.LogInfo($"Raising anger from {level} to {level + angerAmount}");
var manager = RoundManager.Instance;
manager.minEnemiesToSpawn += angerAmount;
level += angerAmount;
}
public void AddBedroom(ScarletBedroom b){
bedrooms.Add(b);
}
public void AddDoor(ScarletDoor d){
// I want to get only doors that are revelant
foreach(var b in bedrooms){
var dist = Vector3.SqrMagnitude(d.transform.position - b.transform.position);
if (dist < 16f * 16f){
doors.Add(d);
return;
}
}
}
public ScarletBedroom GetBedroomWithPainting(Vector3 basePosition){
ScarletBedroom target = null;
var dist = 1f;
foreach(var b in bedrooms){
var newdist = Vector3.SqrMagnitude(basePosition - b.paintingSpawnTransform.position);
if (newdist < dist){
target = b;
dist = newdist;
}
}
if (target == null){
Plugin.logger.LogError($"There is no close bedroom painting spawn at {basePosition}");
return null;
}
//Plugin.logger.LogInfo($"Closest bedroom painting spawn {dist} away");
return target;
}
public ScarletDoor GetScarletDoor(Vector3 basePosition){
ScarletDoor target = null;
var dist = 1f;
foreach(var b in doors){
var newdist = Vector3.SqrMagnitude(basePosition - b.transform.position);
if (newdist < dist){
target = b;
dist = newdist;
}
}
if (target == null){
Plugin.logger.LogError($"There is no close door spawn at {basePosition}");
return null;
}
//Plugin.logger.LogInfo($"Closest door spawn {dist} away");
return target;
}
public void AddLight(ScarletLight light){
lights.Add(light);
}
public ItemReference[] CreateAngerLoot(int count, System.Random sysRandom){
var roundManager = RoundManager.Instance;
if (!roundManager.IsServer) return null;
//Plugin.logger.LogInfo($"Creating {count} bonus items");
if (count == 0) return new ItemReference[0];
var list = new List<int>();
var scrap = Utility.GetDungeonItems();
foreach(var e in scrap){
list.Add(e.rarity);
}
var bonusItems = new ItemReference[count];
for(var i = 0; i < bonusItems.Length; ++i){
var index = roundManager.GetRandomWeightedIndexList(list, sysRandom);
var item = scrap[index].spawnableItem;
var cost = (int)(sysRandom.Next(item.minValue + 25, item.maxValue + 35) * roundManager.scrapValueMultiplier);
var itemRef = new ItemReference(item, index, cost);
bonusItems[i] = itemRef;
//Plugin.logger.LogInfo($"Created bonus item of {itemRef}");
}
return bonusItems;
}
public void SpawnAngerLoot(ItemReference[] loot, Transform[] spawnTransforms){
var roundManager = RoundManager.Instance;
if (loot == null) {
Plugin.logger.LogError($"Anger loot is empty. SPOOOKY");
return;
}
for(var i = 0; i < loot.Length; ++i){
var item = loot[i];
var pos = spawnTransforms[i].position;
ScarletNetworkParams callParams = new ScarletNetworkParams() { scrapValue = item.value };
ScarletNetworkManager.Instance.CreateScrapItemServerRpc(item.itemId, pos, callParams);
}
}
public void OnDungeonComplete(Dungeon dungeon) {
Anger(PluginConfig.Instance.minIndoorEnemySpawnCountValue);
}
public void TriggerAngerLightBrief(float duration){
foreach(var s in lights){
s.BeginAngry(duration, false);
}
}
public void TriggerAngerLightForever(){
foreach(var s in lights){
s.BeginAngry(0f, true);
}
}
/*
public void Anger(){
level += 1;
var manager = RoundManager.Instance;
var enemies = manager.SpawnedEnemies;
foreach(var e in enemies){
// only inside
if (e.enemyType.isDaytimeEnemy || e.isOutside) continue;
if (!angeredEnemies.ContainsKey(e))
angeredEnemies.Add(e, 0);
}
foreach(var e in angeredEnemies.Keys){
AngerEnemy(e, level - angeredEnemies[e]);
angeredEnemies[e] = level;
}
}
[ClientRpc]
public void AngerEnemyClientRpc(NetworkBehaviourReference enemyRef, int levelOffset){
if (enemyRef.TryGet<EnemyAI>(out var enemy)){
if (levelOffset < 1) return;
var type = enemy.GetType();
if (type == typeof(BlobAI)){
Plugin.logger.LogInfo("Can't anger blob yet");
}
else {
Plugin.logger.LogInfo($"Angering {type} is not yet supported");
}
}
}
public void Remove(EnemyAI enemy){
angeredEnemies.Remove(enemy);
}
*/
}
}

View file

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using DunGen;
using ScarletMansion.DunGenPatch.Doorways;
namespace ScarletMansion.GamePatch.Managers {
public class DoorwayManager : MonoBehaviour {
public static DoorwayManager Instance { get; private set; }
public static ActionList onMainEntranceTeleportSpawnedEvent = new ActionList("onMainEntranceTeleportSpawned");
public List<DoorwayCleanup> doorwayCleanup;
public void Awake(){
Instance = this;
doorwayCleanup = new List<DoorwayCleanup>();
}
public void AddDoorwayCleanup(DoorwayCleanup dw){
doorwayCleanup.Add(dw);
}
public static void onMainEntranceTeleportSpawnedFunction(){
if (Instance && DunGenPatch.Patch.active) {
var doorwayCleanups = Instance.doorwayCleanup;
foreach(var d in doorwayCleanups){
d.Cleanup();
}
}
}
}
}

View file

@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using DunGen;
namespace ScarletMansion {
public class KnightSpawnManager : MonoBehaviour, IDungeonCompleteReceiver {
public static KnightSpawnManager Instance { get; private set; }
public List<KnightSpawnPoint> spawnPoints;
public List<KnightSpawnPoint> unusedSpawnPoints;
public int lastKnightSeenPlayer = -1;
public bool disableNextKnightSpecialSpawn;
void Awake(){
Instance = this;
}
public void OnDungeonComplete(Dungeon dungeon) {
// IDK KNOW IF I CAN TRUST THIS TO BE THE SAME FOR ALL CLIENTS
// but probably
var points = dungeon.GetComponentsInChildren<KnightSpawnPoint>();
spawnPoints = points.ToList();
for(var i = 0; i < spawnPoints.Count; ++i){
spawnPoints[i].index = i;
}
unusedSpawnPoints = points.ToList();
Plugin.logger.LogInfo($"Found {spawnPoints.Count} spawn points for the knight");
}
public int GetSpawnPointIndex(){
if (disableNextKnightSpecialSpawn) {
disableNextKnightSpecialSpawn = true;
return -1;
}
if (unusedSpawnPoints.Count == 0) return -1;
// cause it would be funny
if (lastKnightSeenPlayer >= 0){
var tempitem = spawnPoints[lastKnightSeenPlayer];
if (tempitem.gameObject.activeInHierarchy){
Plugin.logger.LogInfo($"Using the last knight {tempitem.index} that saw a player");
unusedSpawnPoints.Remove(tempitem);
lastKnightSeenPlayer = -1;
return tempitem.index;
}
}
var index = UnityEngine.Random.Range(0, unusedSpawnPoints.Count);
var item = unusedSpawnPoints[index];
unusedSpawnPoints.RemoveAt(index);
return item.index;
}
public Transform GetSpawnPointTransform(int index){
return spawnPoints[index].transform;
}
}
}

View file

@ -0,0 +1,55 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
/*
namespace ScarletMansion {
public static class ScarletLightingManager {
public static ScarletLighting[] lights;
public static void Init(){
lights = UnityEngine.Object.FindObjectsOfType<ScarletLighting>();
}
public static void Clean(){
lights = null;
}
public static void UpdateLights(float modifier){
if (lights == null) return;
try {
foreach(var l in lights){
l.UpdateLight(modifier);
}
} catch (Exception e){
Plugin.logger.LogError("UpdateLights found a weird error, we just aborting");
Plugin.logger.LogError(e.ToString());
lights = null;
}
}
public static void DisableLights(){
if (lights == null) return;
try {
foreach(var l in lights){
l.DisableLights();
}
} catch (Exception e){
Plugin.logger.LogError("DisableLights found a weird error, we just aborting");
Plugin.logger.LogError(e.ToString());
lights = null;
}
}
}
}
*/

View file

@ -0,0 +1,409 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Unity.Netcode;
using GameNetcodeStuff;
using ScarletMansion.GamePatch.Items;
using ScarletMansion.GamePatch;
namespace ScarletMansion {
public struct ScarletNetworkParams : INetworkSerializeByMemcpy {
public int scrapValue;
public int specialValue;
}
public class ItemReference {
public Item item;
public int itemId;
public int value;
public ItemReference(Item item, int itemId, int value){
this.item = item;
this.itemId = itemId;
this.value = value;
}
public override string ToString() {
var itemString = item ? item.name : "NULL";
return $"{itemString}:{itemId} ({value})";
}
}
public class EnemyReference {
public EnemyType enemy;
public int index;
public EnemyReference(EnemyType enemy, int index){
this.enemy = enemy;
this.index = index;
}
public override string ToString() {
var enemyString = enemy ? enemy.name : "NULL";
return $"{enemyString}:{index}";
}
}
public class EnemyReferenceSpawnLogic : EnemyReference {
public enum SpawnLogic { None, Special };
public SpawnLogic logic;
public EnemyReferenceSpawnLogic(EnemyType enemy, int index, SpawnLogic logic) : base(enemy, index) {
this.logic = logic;
}
public void ApplySpawnLogic(){
if (logic == SpawnLogic.None) return;
var enemyName = enemy.name.ToLowerInvariant();
if (enemyName == "knight")
KnightSpawnManager.Instance.disableNextKnightSpecialSpawn = true;
else if (enemyName == "jester")
JesterAIPatch.active = true;
}
public override string ToString() {
var b = base.ToString();
return $"{b} [{logic.ToString()}]";
}
}
public class ScarletNetworkManager : NetworkBehaviour {
public static ScarletNetworkManager Instance { get; private set; }
void Awake(){
Instance = this;
}
[ServerRpc(RequireOwnership = false)]
public void DestroyPlayerItemInSlotServerRpc(NetworkBehaviourReference playerRef, int itemSlot, ServerRpcParams callParams = default(ServerRpcParams)){
if (playerRef.TryGet<PlayerControllerB>(out var player)){
Plugin.logger.LogInfo($"P{player.OwnerClientId}, S{callParams.Receive.SenderClientId}");
DestroyPlayerItemInSlotClientRpc(playerRef, itemSlot);
return;
}
Plugin.logger.LogError($"Error trying to get player script (SERVERRPC)");
}
[ClientRpc]
public void DestroyPlayerItemInSlotClientRpc(NetworkBehaviourReference playerRef, int itemSlot){
if (playerRef.TryGet<PlayerControllerB>(out var player) && !player.IsOwner){
player.DestroyPlayerItemInSlot_SDM(itemSlot);
return;
}
if (player == null)
Plugin.logger.LogError($"Error trying to get player script (CLIENTRPC)");
}
[ServerRpc(RequireOwnership = false)]
public void CreateItemServerRpc(int itemId, Vector3 position, ScarletNetworkParams callParams = default(ScarletNetworkParams)){
CreateItem(itemId, false, position, null, callParams);
}
[ServerRpc(RequireOwnership = false)]
public void CreateItemServerRpc(int itemId, Vector3 position, NetworkBehaviourReference playerRef, ScarletNetworkParams callParams = default(ScarletNetworkParams)){
playerRef.TryGet<PlayerControllerB>(out var player);
CreateItem(itemId, false, position, player, callParams);
}
[ServerRpc(RequireOwnership = false)]
public void CreateScrapItemServerRpc(int itemId, Vector3 position, ScarletNetworkParams callParams = default(ScarletNetworkParams)){
CreateItem(itemId, true, position, null, callParams);
}
[ServerRpc(RequireOwnership = false)]
public void CreateScrapItemServerRpc(int itemId, Vector3 position, NetworkBehaviourReference playerRef, ScarletNetworkParams callParams = default(ScarletNetworkParams)){
playerRef.TryGet<PlayerControllerB>(out var player);
CreateItem(itemId, true, position, player, callParams);
}
private void CreateItem(int itemId, bool fromScrapArray, Vector3 position, PlayerControllerB player, ScarletNetworkParams callParams = default(ScarletNetworkParams)){
GameObject prefab;
if (fromScrapArray) {
prefab = Utility.GetDungeonItems()[itemId].spawnableItem.spawnPrefab;
} else {
prefab = StartOfRound.Instance.allItemsList.itemsList[itemId].spawnPrefab;
}
var comp = CreateGrabbableObject(prefab, player, position);
StartCoroutine(WaitForEndOfFrameToUpdateItemInitialProperities(comp));
UpdateItemFallingProperites(comp, position);
UpdateItemElevator(comp, player);
var scarletItem = comp as IScarletItem;
if (scarletItem != null) scarletItem.UpdateSpecialProperties(callParams.specialValue);
var scrapValue = callParams.scrapValue;
if (scrapValue > 0) {
UpdateItemValueProperties(comp, scrapValue);
}
comp.NetworkObject.Spawn(false);
if (player == null) CreateItemClientRpc(comp, position, callParams);
else CreateItemClientRpc(comp, position, player, callParams);
}
[ClientRpc]
public void CreateItemClientRpc(NetworkBehaviourReference itemRef, Vector3 position, ScarletNetworkParams callParams = default(ScarletNetworkParams)){
if (IsServer) return;
StartCoroutine(WaitForItem(itemRef, (c) => CreateItem(c, position, null, callParams)));
}
[ClientRpc]
public void CreateItemClientRpc(NetworkBehaviourReference itemRef, Vector3 position, NetworkBehaviourReference playerRef, ScarletNetworkParams callParams = default(ScarletNetworkParams)){
if (IsServer) return;
StartCoroutine(WaitForItemAndPlayer(itemRef, playerRef, (c, p) => CreateItem(c, position, p, callParams)));
}
private IEnumerator WaitForItem(NetworkBehaviourReference itemRef, Action<GrabbableObject> action){
var t = Time.realtimeSinceStartup + 8f;
GrabbableObject comp;
while(!itemRef.TryGet(out comp)){
yield return null;
if (Time.realtimeSinceStartup > t) {
Plugin.logger.LogError("Failed to find network object (ITEM)");
yield break;
}
}
yield return new WaitForEndOfFrame();
action.Invoke(comp);
}
private IEnumerator WaitForItemAndPlayer(NetworkBehaviourReference itemRef, NetworkBehaviourReference playerRef, Action<GrabbableObject, PlayerControllerB> action){
var t = Time.realtimeSinceStartup + 8f;
GrabbableObject comp;
while(!itemRef.TryGet(out comp)){
yield return null;
if (Time.realtimeSinceStartup > t) {
Plugin.logger.LogError("Failed to find network object (ITEM)");
yield break;
}
}
PlayerControllerB player;
while(!playerRef.TryGet(out player)){
yield return null;
if (Time.realtimeSinceStartup > t) {
Plugin.logger.LogError("Failed to find network object (PLAYER)");
yield break;
}
}
yield return new WaitForEndOfFrame();
action.Invoke(comp, player);
}
private void CreateItem(GrabbableObject item, Vector3 position, PlayerControllerB player, ScarletNetworkParams callParams = default(ScarletNetworkParams)) {
UpdateItemFallingProperites(item, position);
UpdateItemElevator(item, player);
var scarletItem = item as IScarletItem;
if (scarletItem != null) scarletItem.UpdateSpecialProperties(callParams.specialValue);
var scrapValue = callParams.scrapValue;
if (scrapValue > 0) {
UpdateItemValueProperties(item, scrapValue);
}
}
private GrabbableObject CreateGrabbableObject(GameObject prefab, PlayerControllerB player, Vector3 position) {
var parent = GetItemSpawnTransform(player);
var gameObject = GameObject.Instantiate(prefab, position, Quaternion.identity, parent);
return gameObject.GetComponent<GrabbableObject>();
}
private Transform GetItemSpawnTransform(PlayerControllerB player) {
if (((player != null && player.isInElevator) || StartOfRound.Instance.inShipPhase) && RoundManager.Instance.spawnedScrapContainer != null) {
return RoundManager.Instance.spawnedScrapContainer;
}
return StartOfRound.Instance.elevatorTransform;
}
private IEnumerator WaitForEndOfFrameToUpdateItemInitialProperities(GrabbableObject comp) {
yield return new WaitForEndOfFrame();
UpdateItemInitialProperites(comp);
}
private void UpdateItemInitialProperites(GrabbableObject comp) {
comp.reachedFloorTarget = false;
comp.hasHitGround = false;
comp.fallTime = 0f;
}
private void UpdateItemFallingProperites(GrabbableObject comp, Vector3 position) {
comp.startFallingPosition = position;
comp.targetFloorPosition = comp.GetItemFloorPosition(position);
}
private void UpdateItemValueProperties(GrabbableObject comp, int value) {
comp.SetScrapValue(value);
RoundManager.Instance.totalScrapValueInLevel += value;
}
private void UpdateItemElevator(GrabbableObject comp, PlayerControllerB player){
if (player != null && player.isInHangarShipRoom) {
player.SetItemInElevator(true, true, comp);
}
}
}
public static class ScarletNetworkManagerUtility {
public static int GetFlashlightId(FlashlightItem flashlightItem){
var flashlight = Assets.GetFlashlight(flashlightItem.itemProperties);
if (flashlight != null) return flashlight.itemId;
return -1;
}
public static bool CreateFlashlight(PlayerControllerB player, FlashlightItem flashLight, FlandreCrystal crystal){
var color = crystal.colorIndex;
var position = crystal.transform.position + Vector3.up * 0.25f;
var id = GetFlashlightId(flashLight);
var scrapValue = crystal.scrapValue;
var flashlightValue = scrapValue;
var nextCrystal = crystal.targetTransformation;
if (nextCrystal) {
flashlightValue = Mathf.RoundToInt(flashlightValue * 0.5f);
}
if (id == -1) {
var flashString = flashLight ? flashLight.itemProperties.itemName : "NULL";
Plugin.logger.LogError($"Failed to find a corresponding flashlight for {flashString}");
return false;
}
player.DestroyPlayerItemAndSync_SDM(flashLight);
player.DestroyPlayerItemAndSync_SDM(crystal);
ScarletNetworkParams callParams = new ScarletNetworkParams() { scrapValue = flashlightValue, specialValue = color};
ScarletNetworkManager.Instance.CreateItemServerRpc(id, position, player, callParams);
if (nextCrystal) {
var brokenCrystal = Assets.GetGlobalItem(nextCrystal);
if (brokenCrystal == null) {
Plugin.logger.LogError($"Failed to find a corresponding global item for {nextCrystal.itemName}");
return true;
}
var brokenCrystalId= brokenCrystal.itemId;
if (brokenCrystalId == -1) {
Plugin.logger.LogError($"Failed to find a corresponding id for {nextCrystal.itemName}");
return true;
}
var colorLength = FlandreCrystal.colorVariants.Length;
var nextScrapColorValue = scrapValue % colorLength;
var nextScrapValue = flashlightValue - (flashlightValue % colorLength) + nextScrapColorValue;
ScarletNetworkParams nextCallParams = new ScarletNetworkParams() { scrapValue = nextScrapValue};
ScarletNetworkManager.Instance.CreateItemServerRpc(brokenCrystalId, position, player, nextCallParams);
}
return true;
}
public static void DestroyPlayerItemAndSync_SDM(this PlayerControllerB player, GrabbableObject obj){
if (!player.IsOwner) return;
var itemSlots = player.ItemSlots;
for(var i = 0; i < itemSlots.Length; ++i){
if (itemSlots[i] == obj) {
DestroyPlayerItemInSlotAndSync_SDM(player, i);
return;
}
}
var grabObjString = obj ? obj.itemProperties.itemName : "NULL";
Plugin.logger.LogError($"Player {player.playerUsername}:{player.actualClientId} tried to destroy item {grabObjString} which is empty or not owned by player");
}
public static void DestroyPlayerItemInSlotAndSync_SDM(this PlayerControllerB player, int itemSlot){
if (!player.IsOwner) return;
var itemSlots = player.ItemSlots;
if (itemSlot >= itemSlots.Length || itemSlots[itemSlot] == null) {
Plugin.logger.LogError($"Player {player.playerUsername}:{player.actualClientId} tried to destroy item in slot {itemSlot} which is empty or overflowed");
return;
}
player.timeSinceSwitchingSlots = 0f;
player.DestroyPlayerItemInSlot_SDM(itemSlot);
ScarletNetworkManager.Instance.DestroyPlayerItemInSlotServerRpc(player, itemSlot);
}
public static void DestroyPlayerItemInSlot_SDM(this PlayerControllerB player, int itemSlot){
// base game does this
// better safe and slow then sorry
if (GameNetworkManager.Instance.localPlayerController == null || NetworkManager.Singleton == null || NetworkManager.Singleton.ShutdownInProgress) return;
Plugin.logger.LogInfo($"Destroying player {player.playerUsername}:{player.actualClientId}'s item in slot {itemSlot}");
var heldObj = player.currentlyHeldObjectServer;
var heldObjString = heldObj ? heldObj.itemProperties.itemName : "NULL";
var grabObj = player.ItemSlots[itemSlot];
var grabObjString = grabObj ? grabObj.itemProperties.itemName : "NULL";
Plugin.logger.LogInfo($"Held item {player.currentItemSlot}:{heldObjString}");
Plugin.logger.LogInfo($"Target item {itemSlot}:{grabObjString}");
// fix weight and values
player.carryWeight -= Mathf.Clamp(grabObj.itemProperties.weight - 1f, 0f, 10f);
RoundManager.Instance.totalScrapValueInLevel -= grabObj.scrapValue;
// destroy radar
if (grabObj.radarIcon) {
GameObject.Destroy(grabObj.radarIcon.gameObject);
}
// fix character animations and UI
// if target item is the same as held item
if (player.isHoldingObject) {
if (player.currentItemSlot == itemSlot) {
player.isHoldingObject = false;
player.twoHanded = false;
if (player.IsOwner) {
player.playerBodyAnimator.SetBool("cancelHolding", true);
player.playerBodyAnimator.SetTrigger("Throw");
HUDManager.Instance.holdingTwoHandedItem.enabled = false;
HUDManager.Instance.ClearControlTips();
player.activatingItem = false;
}
}
if (heldObj != null && heldObj == grabObj) {
if (player.IsOwner) {
player.SetSpecialGrabAnimationBool(false, heldObj);
}
player.currentlyHeldObjectServer = null;
}
}
// no matter what, we need these to be called
if (player.IsOwner) {
HUDManager.Instance.itemSlotIcons[itemSlot].enabled = false;
grabObj.DiscardItemOnClient();
}
player.ItemSlots[itemSlot] = null;
if (player.IsServer) grabObj.NetworkObject.Despawn(true);
}
}
}