New item SnowGlobe

And a bunch of fixes
This commit is contained in:
LadyAliceMargatroid 2024-07-18 17:32:29 -07:00
parent 69b2bc24cf
commit faa391c309
9 changed files with 337 additions and 18 deletions

View File

@ -140,7 +140,8 @@ namespace ScarletMansion {
{ "Deco. crystal", () => PluginConfig.Instance.crystalWeightValue }, { "Deco. crystal", () => PluginConfig.Instance.crystalWeightValue },
{ "Shattered deco. crystal", () => PluginConfig.Instance.crystalBrokenWeightValue }, { "Shattered deco. crystal", () => PluginConfig.Instance.crystalBrokenWeightValue },
{ "Demonic painting", () => 0 }, { "Demonic painting", () => 0 },
{ "Maid's knife", () => 0 } { "Maid's knife", () => 0 },
{ "Doll Snow Globe", () => PluginConfig.Instance.snowGlobeWeightValue }
}; };
@ -186,7 +187,7 @@ namespace ScarletMansion {
dungeon = Load<DungeonFlow>("SDMLevel"); dungeon = Load<DungeonFlow>("SDMLevel");
networkObjectList = Load<NetworkObjectListScriptableObject>("SDMList"); networkObjectList = Load<NetworkObjectListScriptableObject>("SDMList");
entranceAudioClip = Load<AudioClip>("entrance"); entranceAudioClip = Load<AudioClip>("entrance_ogg");
knight = new Enemy( knight = new Enemy(
Load<GameObject>("NET_KnightEnemy"), Load<GameObject>("NET_KnightEnemy"),
@ -209,9 +210,21 @@ namespace ScarletMansion {
globalItems = new List<GlobalItem>(); globalItems = new List<GlobalItem>();
scrapItems = new List<ScrapItem>(); scrapItems = new List<ScrapItem>();
foreach(var i in networkObjectList.items){ foreach(var i in networkObjectList.items){
var entry = new GlobalItem(i);
globalItems.Add(entry);
Items.RegisterItem(i);
Plugin.logger.LogInfo($"Global Item {i.itemName} registered");
}
foreach(var i in networkObjectList.scrapItems) {
var entry = new ScrapItem(i, GetItemRarityFunction(i)); var entry = new ScrapItem(i, GetItemRarityFunction(i));
scrapItems.Add(entry); scrapItems.Add(entry);
globalItems.Add(entry); globalItems.Add(entry);
Items.RegisterScrap(i, 0, Levels.LevelTypes.None);
NetworkPrefabs.RegisterNetworkPrefab(i.spawnPrefab);
Plugin.logger.LogInfo($"Scrap Item {i.itemName} registered");
} }
flashlight = new Flashlight("Pro Flashlight", 0); flashlight = new Flashlight("Pro Flashlight", 0);
@ -224,6 +237,7 @@ namespace ScarletMansion {
public static Func<int> GetItemRarityFunction(Item item){ public static Func<int> GetItemRarityFunction(Item item){
var name = item.itemName; var name = item.itemName;
if (itemRarityTable.ContainsKey(name)){ if (itemRarityTable.ContainsKey(name)){
return itemRarityTable[name]; return itemRarityTable[name];
} }

View File

@ -48,6 +48,7 @@ namespace ScarletMansion.GamePatch {
[HarmonyPrefix] [HarmonyPrefix]
public static void StartOfRound_Start(ref StartOfRound __instance) { public static void StartOfRound_Start(ref StartOfRound __instance) {
ScarletYukariTrigger.audioClipIndex = -1; ScarletYukariTrigger.audioClipIndex = -1;
PlayerAnimatorStateHelper.ClearAnimators();
__instance.StartCoroutine(WaitForNetworkObject(__instance, CreateNetworkManager)); __instance.StartCoroutine(WaitForNetworkObject(__instance, CreateNetworkManager));
@ -110,7 +111,6 @@ namespace ScarletMansion.GamePatch {
} }
private static void FixParticleSystemMaterial(ParticleSystemRenderer toFixParticleSystem, ParticleSystemRenderer copyParticleSystem) { private static void FixParticleSystemMaterial(ParticleSystemRenderer toFixParticleSystem, ParticleSystemRenderer copyParticleSystem) {
Debug.Log(copyParticleSystem.name);
toFixParticleSystem.sharedMaterial = copyParticleSystem.sharedMaterial; toFixParticleSystem.sharedMaterial = copyParticleSystem.sharedMaterial;
} }
@ -212,18 +212,19 @@ namespace ScarletMansion.GamePatch {
itemToFix.itemIcon = itemReference.itemIcon; itemToFix.itemIcon = itemReference.itemIcon;
itemToFix.grabSFX = itemReference.grabSFX; itemToFix.grabSFX = itemReference.grabSFX;
itemToFix.dropSFX = itemReference.dropSFX; itemToFix.dropSFX = itemReference.dropSFX;
itemToFix.pocketSFX = itemReference.pocketSFX;
} }
var magClass = itemsList.FirstOrDefault(i => i.name.ToLowerInvariant() == "magnifyingglass"); var magClass = itemsList.FirstOrDefault(i => i.name.ToLowerInvariant() == "magnifyingglass");
if (GameReadNullCheck(magClass, "magnifyingglass", "Item will have missing image and sound assets")) { if (GameReadNullCheck(magClass, "magnifyingglass", "Item will have missing image and sound assets")) {
QuickItemFix(Assets.scrapItems[0].item, magClass); QuickItemFix(Assets.scrapItems[0].item, magClass);
QuickItemFix(Assets.scrapItems[1].item, magClass); QuickItemFix(Assets.scrapItems[1].item, magClass);
QuickItemFix(Assets.scrapItems[4].item, magClass);
} }
var paintClass = itemsList.FirstOrDefault(i => i.name.ToLowerInvariant() == "fancypainting"); var paintClass = itemsList.FirstOrDefault(i => i.name.ToLowerInvariant() == "fancypainting");
if (GameReadNullCheck(paintClass, "fancypainting", "Item will have missing image and sound assets")){ if (GameReadNullCheck(paintClass, "fancypainting", "Item will have missing image and sound assets")){
QuickItemFix(Assets.scrapItems[2].item, magClass); QuickItemFix(Assets.scrapItems[2].item, paintClass);
} }
void UpdateFlashlight(Assets.Flashlight flashlight, string search, int fixIndex){ void UpdateFlashlight(Assets.Flashlight flashlight, string search, int fixIndex){
@ -311,6 +312,27 @@ namespace ScarletMansion.GamePatch {
UpdateFlashlight(Assets.flashlightBB, "flashlight", 3); UpdateFlashlight(Assets.flashlightBB, "flashlight", 3);
} }
var keyItem = round.allItemsList.itemsList.FirstOrDefault(i => i.name.ToLowerInvariant() == "key");
if (GameReadNullCheck(keyItem, "key", "Item will have missing image and sound assets")){
var scarletPrefab = Assets.networkObjectList.toFixGameObjects[5];
var scarletKey = scarletPrefab.GetComponent<GrabbableObject>().itemProperties;
QuickItemFix(scarletKey, keyItem);
var keyPrefab = keyItem.spawnPrefab;
scarletPrefab.GetComponent<MeshFilter>().sharedMesh = keyPrefab.GetComponent<MeshFilter>().sharedMesh;
var mats = keyPrefab.GetComponent<MeshRenderer>().sharedMaterials;
mats = mats.Select(m => {
var n = new Material(m);
n.color = Color.red;
return n;
}).ToArray();
scarletPrefab.GetComponent<MeshRenderer>().sharedMaterials = mats;
Assets.dungeonExtended.OverrideKeyPrefab = scarletPrefab;
}
} catch (Exception e) { } catch (Exception e) {
Plugin.logger.LogError("Error when reading base game's item list. Pretty big error I would say"); Plugin.logger.LogError("Error when reading base game's item list. Pretty big error I would say");
Plugin.logger.LogError(e); Plugin.logger.LogError(e);

View File

@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace ScarletMansion.GamePatch.Items {
public class PlayerAnimatorStateHelper {
private Animator animator;
private AnimatorStateInfo currentStateInfo;
private float currentAnimationTime;
private bool isCrouching;
private bool isJumping;
private bool isWalking;
private bool isSprinting;
private RuntimeAnimatorController originalAnimatorController;
public PlayerAnimatorStateHelper(Animator animator) {
this.animator = animator;
this.originalAnimatorController = animator.runtimeAnimatorController;
}
private static Dictionary<ulong, PlayerAnimatorStateHelper> animatorStateHelpers;
public static PlayerAnimatorStateHelper TryAddAnimator(ulong id, Animator animator){
if (!animatorStateHelpers.TryGetValue(id, out var v)) {
v = new PlayerAnimatorStateHelper(animator);
animatorStateHelpers.Add(id, v);
}
return v;
}
public static void ClearAnimators(){
animatorStateHelpers = new Dictionary<ulong, PlayerAnimatorStateHelper>();
}
//We need to Save the important states due to how unity handles switching animator overrides (So stupid)
public void SaveAnimatorStates() {
if (animator != null) {
isCrouching = animator.GetBool("crouching");
isJumping = animator.GetBool("Jumping");
isWalking = animator.GetBool("Walking");
isSprinting = animator.GetBool("Sprinting");
currentStateInfo = animator.GetCurrentAnimatorStateInfo(0);
currentAnimationTime = currentStateInfo.normalizedTime;
//Debug.Log("Saved Animator States - Crouching: " + isCrouching +
// ", Jumping: " + isJumping +
// ", Walking: " + isWalking +
// ", Sprinting: " + isSprinting +
// ", State: " + currentStateInfo.fullPathHash +
// ", Time: " + currentAnimationTime);
}
}
//We need to Restore the important states due to how unity handles switching animator overrides
public void RestoreAnimatorStates() {
if (animator != null) {
animator.Play(currentStateInfo.fullPathHash, 0, currentAnimationTime);
animator.SetBool("crouching", isCrouching);
animator.SetBool("Jumping", isJumping);
animator.SetBool("Walking", isWalking);
animator.SetBool("Sprinting", isSprinting);
//Debug.Log("Restored Animator States - Crouching: " + isCrouching +
// ", Jumping: " + isJumping +
// ", Walking: " + isWalking +
// ", Sprinting: " + isSprinting +
// ", State: " + currentStateInfo.fullPathHash +
// ", Time: " + currentAnimationTime);
}
}
public void RestoreOriginalAnimatorController() {
if (animator != null) {
animator.runtimeAnimatorController = originalAnimatorController;
RestoreAnimatorStates();
}
}
public class AnimationClipOverrides : List<KeyValuePair<AnimationClip, AnimationClip>> {
public AnimationClipOverrides(int capacity) : base(capacity) {}
public AnimationClip this[string name] {
get => this.Find(x => x.Key.name.Equals(name)).Value;
set {
int index = this.FindIndex(x => x.Key.name.Equals(name));
if (index != -1) this[index] = new KeyValuePair<AnimationClip, AnimationClip>(this[index].Key, value);
}
}
public override string ToString() {
var items = this.Select(d => {
var keyValue = d.Key ? d.Key.name : "NULL";
var vValue = d.Value ? d.Value.name : "NULL";
return $"{keyValue}: {vValue}";
});
return string.Join(", ", items);
}
}
public void SetAnimatorOverrideController(AnimatorOverrideController overrideController, string originalAnimationClipName, AnimationClip overrideAnimationClip) {
if (animator != null) {
overrideController.runtimeAnimatorController = originalAnimatorController;
var clipOverrides = new AnimationClipOverrides(overrideController.overridesCount);
overrideController.GetOverrides(clipOverrides);
clipOverrides[originalAnimationClipName] = overrideAnimationClip;
overrideController.ApplyOverrides(clipOverrides);
animator.runtimeAnimatorController = overrideController;
RestoreAnimatorStates();
}
}
public RuntimeAnimatorController GetOriginalAnimatorController() {
return originalAnimatorController;
}
}
}

View File

@ -81,7 +81,7 @@ namespace ScarletMansion.GamePatch.Items
public void HitKnife(bool cancel = false) { public void HitKnife(bool cancel = false) {
if (previousPlayerHeldBy == null) { if (previousPlayerHeldBy == null) {
Debug.LogError("Previousplayerheldby is null on this client when HitShovel is called."); Plugin.logger.LogError("Previousplayerheldby is null on this client when HitShovel is called.");
return; return;
} }
previousPlayerHeldBy.activatingItem = false; previousPlayerHeldBy.activatingItem = false;
@ -134,7 +134,7 @@ namespace ScarletMansion.GamePatch.Items
flag2 = true; flag2 = true;
} }
catch (Exception arg) { catch (Exception arg) {
Debug.Log($"Exception caught when hitting object with shovel from player #{previousPlayerHeldBy.playerClientId}: {arg}"); Plugin.logger.LogError($"Exception caught when hitting object with shovel from player #{previousPlayerHeldBy.playerClientId}: {arg}");
} }
} }
} }
@ -187,7 +187,10 @@ namespace ScarletMansion.GamePatch.Items
player.activatingItem = true; player.activatingItem = true;
yield return new WaitForSeconds(0.25f); yield return new WaitForSeconds(0.25f);
player.DamagePlayer(PluginConfig.Instance.maidKnifeSelfDamageValue, true, true, CauseOfDeath.Stabbing); var dmg = PluginConfig.Instance.maidKnifeSelfDamageValue;
var realDmg = Mathf.Max(dmg, Mathf.RoundToInt(player.health * (dmg / 100f)));
player.DamagePlayer(realDmg, true, true, CauseOfDeath.Stabbing);
bloodParticle.Play(withChildren: true); bloodParticle.Play(withChildren: true);
RoundManager.PlayRandomClip(knifeAudio, hitSFX); RoundManager.PlayRandomClip(knifeAudio, hitSFX);
@ -220,7 +223,7 @@ namespace ScarletMansion.GamePatch.Items
if (maidReference.TryGet<MaidVariant>(out var maid)){ if (maidReference.TryGet<MaidVariant>(out var maid)){
parentMaid = maid; parentMaid = maid;
} else { } else {
Debug.LogWarning($"Could not get parent maid for scarlet maid. Spooky I guess"); Plugin.logger.LogWarning($"Could not get parent maid for scarlet maid. Spooky I guess");
} }
} }

View File

@ -0,0 +1,149 @@
using GameNetcodeStuff;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace ScarletMansion.GamePatch.Items {
public class ScarletSnowGlobe : GrabbableObject {
[Header("Activation")]
public bool activated;
public GameObject mainLightGameObject;
public ParticleSystem snowParticleSystem;
public ParticleSystemRenderer snowRenderer;
public AudioSource musicAS;
[Header("Extra")]
public Transform prefabPivot;
public ScanNodeProperties scanNode;
public AnimatorOverrideController SnowGlobeOverride;
public string SnowGlobeOriginalHoldClipName;
public AnimationClip SnowGlobeOverrideHoldClip;
[System.Serializable]
public class SnowGlobeType {
public string name;
public GameObject prefab;
}
public SnowGlobeType[] types;
public SnowGlobeType currentType;
public override void Start() {
base.Start();
StartCoroutine(WaitForScrapValue());
}
public override void Update() {
base.Update();
if (musicAS.isPlaying) {
var lerp = musicAS.time / musicAS.clip.length;
var spinRot = lerp * 5f * 360f;
//var pingRot = Mathf.PingPong(lerp * 95f / 8f, 11.875f / 32f) * (64f / 11.875f) - 1f;
prefabPivot.localRotation = Quaternion.Euler(90f + spinRot, 90f, -90f);
} else {
prefabPivot.localRotation = Quaternion.Euler(90f, 90f, -90f);
}
}
public IEnumerator WaitForScrapValue(){
while (scrapValue == 0) yield return null;
var index = scrapValue % types.Length;
currentType = types[index];
Instantiate(currentType.prefab, prefabPivot);
scanNode.headerText = $"{currentType.name} Snow Globe";
}
private PlayerAnimatorStateHelper GetAnimator(PlayerControllerB player) {
if (player != null && player.playerBodyAnimator != null) {
return PlayerAnimatorStateHelper.TryAddAnimator(player.actualClientId, player.playerBodyAnimator);
}
return null;
}
public override void EquipItem() {
base.EquipItem();
var animator = GetAnimator(playerHeldBy);
if (animator != null) {
animator.SaveAnimatorStates();
animator.SetAnimatorOverrideController(SnowGlobeOverride, SnowGlobeOriginalHoldClipName, SnowGlobeOverrideHoldClip);
Plugin.logger.LogInfo("Animator override set for player: " + playerHeldBy.playerBodyAnimator.gameObject.name);
}
// Coming from pocketing since this is also called when using inventory
ToggleParticleRenderer(true);
}
public override void PocketItem() {
var animator = GetAnimator(playerHeldBy);
if (animator != null) {
animator.SaveAnimatorStates();
animator.RestoreOriginalAnimatorController();
Plugin.logger.LogInfo("Animator restored for player: " + playerHeldBy.playerBodyAnimator.gameObject.name);
}
base.PocketItem();
// Disable Particles renderer
ToggleParticleRenderer(false);
}
public override void DiscardItem() {
var animator = GetAnimator(playerHeldBy);
if (animator != null) {
animator.SaveAnimatorStates();
animator.RestoreOriginalAnimatorController();
Plugin.logger.LogInfo("Animator restored for player: " + playerHeldBy.playerBodyAnimator.gameObject.name);
}
base.DiscardItem();
}
public override void ItemActivate(bool used, bool buttonDown = true) {
base.ItemActivate(used, buttonDown);
if (!activated) {
musicAS.volume = 0.2f;
StartCoroutine(ActivateSnowGlobeCoroutine());
activated = true;
}
}
public IEnumerator ActivateSnowGlobeCoroutine() {
yield return new WaitForEndOfFrame();
yield return ToggleSnowGlobeCoroutine(true);
yield return new WaitUntil(() => !musicAS.isPlaying);
yield return ToggleSnowGlobeCoroutine(false);
yield return new WaitForSeconds(2f);
activated = false;
}
IEnumerator ToggleSnowGlobeCoroutine(bool toggle, float delay = 0.2f) {
ToggleParticles(toggle);
ToggleMusic(toggle);
yield return new WaitForSeconds(delay);
mainLightGameObject.SetActive(toggle);
}
void ToggleParticles(bool toggle) {
if (toggle) snowParticleSystem.Play();
else snowParticleSystem.Stop();
}
void ToggleMusic(bool toggle) {
if (toggle) musicAS.Play();
else musicAS.Stop();
}
void ToggleParticleRenderer(bool toggle) {
snowRenderer.enabled = toggle;
}
}
}

View File

@ -21,6 +21,7 @@ namespace ScarletMansion {
[Header("To Fix With InitPatch")] [Header("To Fix With InitPatch")]
public List<GameObject> toFixGameObjects; public List<GameObject> toFixGameObjects;
public List<Item> items; public List<Item> items;
public List<Item> scrapItems;
[Header("DunGen")] [Header("DunGen")]
public TileSet mayorRegularTileset; public TileSet mayorRegularTileset;

View File

@ -32,7 +32,7 @@ namespace ScarletMansion {
public class Plugin : BaseUnityPlugin { public class Plugin : BaseUnityPlugin {
public const string modGUID = "ImoutoSama.ScarletMansion"; public const string modGUID = "ImoutoSama.ScarletMansion";
private const string modName = "Scarlet Mansion"; private const string modName = "Scarlet Mansion";
private const string modVersion = "1.3.18"; private const string modVersion = "1.3.21";
public readonly Harmony harmony = new Harmony(modGUID); public readonly Harmony harmony = new Harmony(modGUID);
@ -92,6 +92,7 @@ namespace ScarletMansion {
sdmLevelMatchProperties.planetNames.Add(new StringWithRarity("Dine", 300)); sdmLevelMatchProperties.planetNames.Add(new StringWithRarity("Dine", 300));
sdmLevelMatchProperties.planetNames.Add(new StringWithRarity("Rend", 300)); sdmLevelMatchProperties.planetNames.Add(new StringWithRarity("Rend", 300));
sdmLevelMatchProperties.planetNames.Add(new StringWithRarity("Titan", 69)); sdmLevelMatchProperties.planetNames.Add(new StringWithRarity("Titan", 69));
sdmLevelMatchProperties.planetNames.Add(new StringWithRarity("Sanguine", 900));
var extendedContent = new List<ExtendedContent>(); var extendedContent = new List<ExtendedContent>();
@ -125,16 +126,9 @@ namespace ScarletMansion {
PatchedContent.RegisterExtendedMod(extendedMod); PatchedContent.RegisterExtendedMod(extendedMod);
//
Assets.extendedMod = extendedMod; Assets.extendedMod = extendedMod;
Assets.dungeonExtended = extendedDungeon; Assets.dungeonExtended = extendedDungeon;
foreach(var i in Assets.scrapItems){
Items.RegisterScrap(i.item, 0, Levels.LevelTypes.None);
NetworkPrefabs.RegisterNetworkPrefab(i.item.spawnPrefab);
}
extendedDungeon.DungeonEvents.onBeforeDungeonGenerate.AddListener(GeneratePathPatch.GeneratePatch); extendedDungeon.DungeonEvents.onBeforeDungeonGenerate.AddListener(GeneratePathPatch.GeneratePatch);
DoorwayManager.onMainEntranceTeleportSpawnedEvent.AddEvent("DoorwayCleanup", DoorwayManager.onMainEntranceTeleportSpawnedFunction); DoorwayManager.onMainEntranceTeleportSpawnedEvent.AddEvent("DoorwayCleanup", DoorwayManager.onMainEntranceTeleportSpawnedFunction);
} }

View File

@ -244,6 +244,15 @@ namespace ScarletMansion {
new AcceptableValueRange<int>(0, 999) new AcceptableValueRange<int>(0, 999)
); );
public static ConfigEntryBundle<int> snowGlobeWeight = new ConfigEntryBundle<int>(
dungeonLootPrefix,
"Doll Snow Globe Weight",
40,
"The doll snow globe's spawn weight. Calculating spawn chance (%) is difficult as the total scrap weight for each moon varies from ~600 to ~850.",
null,
new AcceptableValueRange<int>(0, 999)
);
public static ConfigEntryBundle<int> maidKnifeSelfDamage = new ConfigEntryBundle<int>( public static ConfigEntryBundle<int> maidKnifeSelfDamage = new ConfigEntryBundle<int>(
dungeonLootPrefix, dungeonLootPrefix,
"Maid Knife Feed Damage", "Maid Knife Feed Damage",
@ -256,6 +265,7 @@ namespace ScarletMansion {
public float lootMultiplierValue; public float lootMultiplierValue;
public int crystalWeightValue; public int crystalWeightValue;
public int crystalBrokenWeightValue; public int crystalBrokenWeightValue;
public int snowGlobeWeightValue;
public int maidKnifeSelfDamageValue; public int maidKnifeSelfDamageValue;
// enemies // enemies

View File

@ -204,9 +204,11 @@
<Compile Include="GamePatch\InitPatch.cs" /> <Compile Include="GamePatch\InitPatch.cs" />
<Compile Include="GamePatch\Items\FlandreCrystal.cs" /> <Compile Include="GamePatch\Items\FlandreCrystal.cs" />
<Compile Include="GamePatch\Items\IScarletItem.cs" /> <Compile Include="GamePatch\Items\IScarletItem.cs" />
<Compile Include="GamePatch\Items\PlayerAnimatorStateHelper.cs" />
<Compile Include="GamePatch\Items\ScarletFlashlight.cs" /> <Compile Include="GamePatch\Items\ScarletFlashlight.cs" />
<Compile Include="GamePatch\Items\ScarletKnife.cs" /> <Compile Include="GamePatch\Items\ScarletKnife.cs" />
<Compile Include="GamePatch\Items\ScarletPainting.cs" /> <Compile Include="GamePatch\Items\ScarletPainting.cs" />
<Compile Include="GamePatch\Items\ScarletSnowGlobe.cs" />
<Compile Include="GamePatch\JesterAIPatch.cs" /> <Compile Include="GamePatch\JesterAIPatch.cs" />
<Compile Include="GamePatch\LoadAssetsIntoLevelPatch.cs" /> <Compile Include="GamePatch\LoadAssetsIntoLevelPatch.cs" />
<Compile Include="GamePatch\Managers\AngerManager.cs" /> <Compile Include="GamePatch\Managers\AngerManager.cs" />