private static void breakStone_Postfix(GameLocation __instance, ref bool __result, int indexOfStone, int x, int y, Farmer who, Random r) { SMonitor.Log($"Checking for custom ore in stone {indexOfStone}"); CustomOreNode node = customOreNodesList.Find(n => n.parentSheetIndex == indexOfStone); if (node == null) { return; } SMonitor.Log($"Got custom ore in stone {indexOfStone}"); OreLevelRange gotRange = null; foreach (OreLevelRange range in node.oreLevelRanges) { if (IsInRange(range, __instance, false)) { gotRange = range; break; } } if (gotRange == null) { SMonitor.Log($"No range for {indexOfStone}!", LogLevel.Warn); return; } int addedOres = who.professions.Contains(18) ? 1 : 0; SMonitor.Log($"custom node has {node.dropItems.Count} potential items."); foreach (DropItem item in node.dropItems) { if (Game1.random.NextDouble() < item.dropChance * gotRange.dropChanceMult / 100) { SMonitor.Log($"dropping item {item.itemIdOrName}"); if (!int.TryParse(item.itemIdOrName, out int itemId)) { foreach (KeyValuePair <int, string> kvp in Game1.objectInformation) { if (kvp.Value.StartsWith(item.itemIdOrName + "/")) { itemId = kvp.Key; break; } } } Game1.createMultipleObjectDebris(itemId, x, y, addedOres + (int)Math.Round(r.Next(item.minAmount, (Math.Max(item.minAmount + 1, item.maxAmount + 1)) + ((r.NextDouble() < who.LuckLevel / 100f) ? item.luckyAmount : 0) + ((r.NextDouble() < who.MiningLevel / 100f) ? item.minerAmount : 0)) * gotRange.dropMult), who.UniqueMultiplayerID, __instance); } } int experience = (int)Math.Round(node.exp * gotRange.expMult); who.gainExperience(3, experience); __result = experience > 0; }
/// <summary>Edit a matched asset.</summary> /// <param name="asset">A helper which encapsulates metadata about an asset and enables changes to it.</param> public void Edit <T>(IAssetData asset) { if (asset.AssetNameEquals("Maps/springobjects") && CustomOreNodes.Count > 0) { var editor = asset.AsImage(); int extension = (Config.SpriteSheetOffsetRows * 16) + ((CustomOreNodes.Count / (editor.Data.Width / 16) + 1) * 16); editor.ExtendImage(minWidth: editor.Data.Width, minHeight: SpringObjectsHeight + extension); SMonitor.Log($"extended springobjects by {extension}"); for (int i = 0; i < CustomOreNodes.Count; i++) { CustomOreNode node = CustomOreNodes[i]; SMonitor.Log($"Patching springobjects with {node.spritePath}"); Texture2D customTexture; customTexture = node.texture; int x = (i % (editor.Data.Width / 16)) * 16; int y = SpringObjectsHeight + (Config.SpriteSheetOffsetRows * 16) + (i / (editor.Data.Width / 16)) * 16; editor.PatchImage(customTexture, sourceArea: new Rectangle(node.spriteX, node.spriteY, node.spriteW, node.spriteH), targetArea: new Rectangle(x, y, 16, 16)); SMonitor.Log($"patched springobjects with {node.spritePath}"); } } else if (asset.AssetNameEquals("Data/ObjectInformation")) { var editor = asset.AsDictionary <int, string>(); for (int i = 0; i < CustomOreNodes.Count; i++) { editor.Data[i + 816] = $"Stone/0/15/Basic/Stone/{CustomOreNodes[i].nodeDesc}"; } } }
private static void Object_Prefix(ref int parentSheetIndex, string Givenname) { if (Environment.StackTrace.Contains("chooseStoneType")) { return; } if (Givenname == "Stone" || parentSheetIndex == 294 || parentSheetIndex == 295) { float currentChance = 0; for (int i = 0; i < customOreNodesList.Count; i++) { CustomOreNode node = customOreNodesList[i]; OreLevelRange gotRange = null; foreach (OreLevelRange range in node.oreLevelRanges) { if (range.minLevel < 1) { gotRange = range; break; } } if (gotRange == null) { continue; } currentChance += node.spawnChance * gotRange.spawnChanceMult; if (Game1.random.NextDouble() < currentChance / 100f) { int index = node.parentSheetIndex; parentSheetIndex = index; break; } } } }
private void GameLoop_GameLaunched(object sender, StardewModdingAPI.Events.GameLaunchedEventArgs e) { CustomOreNodes.Clear(); CustomOreData data; try { data = Helper.Content.Load <CustomOreData>("custom_ore_nodes.json", ContentSource.ModFolder); foreach (string nodeInfo in data.nodes) { CustomOreNode node = new CustomOreNode(nodeInfo); if (node.spriteType == "mod") { node.texture = Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.ModFolder); } else { node.texture = this.Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent); } CustomOreNodes.Add(node); } Monitor.Log($"Got {CustomOreNodes.Count} ores from mod", LogLevel.Debug); } catch (Exception ex) { SMonitor.Log("custom_ore_nodes.json error." + ex, LogLevel.Debug); } foreach (IContentPack contentPack in this.Helper.ContentPacks.GetOwned()) { try { this.Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}"); data = contentPack.ReadJsonFile <CustomOreData>("custom_ore_nodes.json"); foreach (string nodeInfo in data.nodes) { CustomOreNode node = new CustomOreNode(nodeInfo); if (node.spriteType == "mod") { node.texture = contentPack.LoadAsset <Texture2D>(node.spritePath); } else { node.texture = Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent); } CustomOreNodes.Add(node); } Monitor.Log($"Got {data.nodes.Count} ores from content pack {contentPack.Manifest.Name}", LogLevel.Debug); } catch { SMonitor.Log($"custom_ore_nodes.json file not found in content pack {contentPack.Manifest.Name}", LogLevel.Debug); } } Monitor.Log($"Got {CustomOreNodes.Count} ores total", LogLevel.Debug); Helper.Content.InvalidateCache("Maps/springobjects"); }
private static void breakStone_Postfix(GameLocation __instance, ref bool __result, int indexOfStone, int x, int y, Farmer who, Random r) { SMonitor.Log($"Checking for custom ore in stone {indexOfStone}"); int firstIndex = FirstIndex + (Config.SpriteSheetOffsetRows * SpringObjectsWidth / 16); if (indexOfStone - firstIndex < 0 || indexOfStone - firstIndex >= CustomOreNodes.Count) { return; } CustomOreNode node = CustomOreNodes[indexOfStone - firstIndex]; OreLevelRange gotRange = null; foreach (OreLevelRange range in node.oreLevelRanges) { if ((range.minLevel < 1 && !(__instance is MineShaft)) || (range.minLevel > 0 && __instance is MineShaft && ((__instance as MineShaft).mineLevel <= range.maxLevel))) { gotRange = range; break; } } if (gotRange == null) { return; } int addedOres = who.professions.Contains(18) ? 1 : 0; SMonitor.Log($"custom node has {node.dropItems.Count} potential items."); foreach (DropItem item in node.dropItems) { if (Game1.random.NextDouble() < item.dropChance * gotRange.dropChanceMult / 100) { SMonitor.Log($"dropping item {item.itemIdOrName}"); if (!int.TryParse(item.itemIdOrName, out int itemId)) { foreach (KeyValuePair <int, string> kvp in Game1.objectInformation) { if (kvp.Value.StartsWith(item.itemIdOrName + "/")) { itemId = kvp.Key; break; } } } Game1.createMultipleObjectDebris(itemId, x, y, addedOres + (int)Math.Round(r.Next(item.minAmount, (Math.Max(item.minAmount + 1, item.maxAmount + 1)) + ((r.NextDouble() < (double)((float)who.LuckLevel / 100f)) ? item.luckyAmount : 0) + ((r.NextDouble() < (double)((float)who.MiningLevel / 100f)) ? item.minerAmount : 0)) * gotRange.dropMult), who.uniqueMultiplayerID, __instance); } } int experience = (int)Math.Round(node.exp * gotRange.expMult); who.gainExperience(3, experience); __result = experience > 0; }
private static void chooseStoneType_Postfix(MineShaft __instance, ref Object __result, Vector2 tile) { if (__result == null || __result.parentSheetIndex == null) { return; } List <int> ores = new List <int>() { 765, 764, 290, 751 }; if (!ores.Contains(__result.ParentSheetIndex)) { float totalChance = 0; for (int i = 0; i < CustomOreNodes.Count; i++) { CustomOreNode node = CustomOreNodes[i]; if (node.minLevel > -1 && __instance.mineLevel < node.minLevel || node.maxLevel > -1 && __instance.mineLevel > node.maxLevel) { continue; } totalChance += node.spawnChance; } double ourChance = Game1.random.NextDouble() * 100; if (ourChance < totalChance) { // SMonitor.Log($"Chance of custom ore: {ourChance}%"); float cumulativeChance = 0f; for (int i = 0; i < CustomOreNodes.Count; i++) { CustomOreNode node = CustomOreNodes[i]; if (node.minLevel > -1 && __instance.mineLevel < node.minLevel || node.maxLevel > -1 && __instance.mineLevel > node.maxLevel) { continue; } cumulativeChance += node.spawnChance; if (ourChance < cumulativeChance) { SMonitor.Log($"Displaying custom ore \"{node.nodeDesc}\": {cumulativeChance}% / {ourChance}% (rolled)"); int index = (SpringObjectsHeight / 16 * SpringObjectsWidth / 16) + (Config.SpriteSheetOffsetRows * SpringObjectsWidth / 16) + i; //SMonitor.Log($"Displaying stone at index {index}", LogLevel.Debug); __result = new Object(tile, index, "Stone", true, false, false, false) { MinutesUntilReady = node.durability }; //SMonitor.Log(__result.DisplayName); return; } } } } }
private static bool Object_draw_Prefix(Object __instance, SpriteBatch spriteBatch, int x, int y, float alpha = 1f) { CustomOreNode node = customOreNodesList.Find(n => n.parentSheetIndex == __instance.ParentSheetIndex); if (node == null) { return(true); } if (__instance.Fragility != 2) { spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, new Vector2(x * 64 + 32, y * 64 + 51 + 4)), new Rectangle?(Game1.shadowTexture.Bounds), Color.White * alpha, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f, SpriteEffects.None, __instance.getBoundingBox(new Vector2(x, y)).Bottom / 15000f); } Vector2 position3 = Game1.GlobalToLocal(Game1.viewport, new Vector2(x * 64 + 32 + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), y * 64 + 32 + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0))); Rectangle?sourceRectangle2 = new Rectangle(node.spriteX, node.spriteY, node.spriteW, node.spriteH); Color color2 = Color.White * alpha; float rotation2 = 0f; Vector2 origin2 = new Vector2(8f, 8f); Vector2 vector2 = __instance.scale; spriteBatch.Draw(node.texture, position3, sourceRectangle2, color2, rotation2, origin2, (__instance.scale.Y > 1f) ? __instance.getScale().Y : 4f, __instance.Flipped ? SpriteEffects.FlipHorizontally : SpriteEffects.None, (__instance.isPassable() ? __instance.getBoundingBox(new Vector2(x, y)).Top : __instance.getBoundingBox(new Vector2(x, y)).Bottom) / 10000f); return(false); }
private static void chooseStoneType_Postfix(MineShaft __instance, ref Object __result, Vector2 tile) { if (__result == null || __result.parentSheetIndex == null) { return; } List <int> ores = new List <int>() { 765, 764, 290, 751 }; if (!ores.Contains(__result.ParentSheetIndex)) { for (int i = 0; i < CustomOreNodes.Count; i++) { CustomOreNode node = CustomOreNodes[i]; if (node.minLevel > -1 && __instance.mineLevel < node.minLevel || node.maxLevel > -1 && __instance.mineLevel > node.maxLevel) { continue; } if (Game1.random.NextDouble() < node.spawnChance / 100f) { int index = (SpringObjectsHeight / 16 * SpringObjectsWidth / 16) + (Config.SpriteSheetOffsetRows * SpringObjectsWidth / 16) + i; SMonitor.Log($"Displaying stone at index {index}", LogLevel.Debug); __result = new Object(tile, index, "Stone", true, false, false, false) { MinutesUntilReady = node.durability }; SMonitor.Log(__result.DisplayName); return; } } } }
private static void Object_Prefix(ref int parentSheetIndex, ref string Givenname) { if (Environment.StackTrace.Contains("chooseStoneType")) { return; } if (Givenname == "Stone" || parentSheetIndex == 294 || parentSheetIndex == 295) { for (int i = 0; i < CustomOreNodes.Count; i++) { CustomOreNode node = CustomOreNodes[i]; if (node.minLevel > 0) { continue; } if (Game1.random.NextDouble() < node.spawnChance / 100f) { int index = (SpringObjectsHeight / 16 * SpringObjectsWidth / 16) + (Config.SpriteSheetOffsetRows * SpringObjectsWidth / 16) + i; parentSheetIndex = index; break; } } } }
private static void chooseStoneType_Postfix(MineShaft __instance, ref Object __result, Vector2 tile) { if (__result == null) { return; } int difficulty = __instance.mineLevel > 120 ? Game1.netWorldState.Value.SkullCavesDifficulty : Game1.netWorldState.Value.MinesDifficulty; List <int> ores = new List <int>() { 765, 764, 290, 751 }; if (!ores.Contains(__result.ParentSheetIndex)) { float totalChance = 0; for (int i = 0; i < customOreNodesList.Count; i++) { CustomOreNode node = customOreNodesList[i]; foreach (OreLevelRange range in node.oreLevelRanges) { if ((range.minLevel < 1 || __instance.mineLevel >= range.minLevel) && (range.maxLevel < 1 || __instance.mineLevel <= range.maxLevel) && (range.minDifficulty <= difficulty) && (range.maxDifficulty < 0 || range.maxDifficulty >= difficulty)) { totalChance += node.spawnChance * range.spawnChanceMult; break; } } } double ourChance = Game1.random.NextDouble() * 100; if (ourChance < totalChance) { // SMonitor.Log($"Chance of custom ore: {ourChance}%"); float cumulativeChance = 0f; for (int i = 0; i < customOreNodesList.Count; i++) { CustomOreNode node = customOreNodesList[i]; OreLevelRange gotRange = null; foreach (OreLevelRange range in node.oreLevelRanges) { if (IsInRange(range, __instance, true)) { gotRange = range; break; } } if (gotRange == null) { continue; } cumulativeChance += node.spawnChance * gotRange.spawnChanceMult; if (ourChance < cumulativeChance) { SMonitor.Log($"Switching to custom ore \"{node.nodeDesc}\": {cumulativeChance}% / {ourChance}% (rolled)"); int index = node.parentSheetIndex; //SMonitor.Log($"Displaying stone at index {index}", LogLevel.Debug); __result = new Object(tile, index, "Stone", true, false, false, false) { MinutesUntilReady = node.durability }; return; } } } } }
private void ReloadOreData(bool first = false) { customOreNodesList.Clear(); CustomOreData data; int id = 42424000; Dictionary <int, int> existingPSIs = new Dictionary <int, int>(); CustomOreConfig conf = Helper.Data.ReadJsonFile <CustomOreConfig>("ore_config.json") ?? new CustomOreConfig(); foreach (KeyValuePair <int, int> psi in conf.parentSheetIndexes) { existingPSIs[psi.Value] = psi.Key; } foreach (IContentPack contentPack in Helper.ContentPacks.GetOwned()) { conf = contentPack.ReadJsonFile <CustomOreConfig>("ore_config.json") ?? new CustomOreConfig(); foreach (KeyValuePair <int, int> psi in conf.parentSheetIndexes) { existingPSIs[psi.Value] = psi.Key; } } try { if (File.Exists(Path.Combine(Helper.DirectoryPath, "custom_ore_nodes.json"))) { int add = 0; try { data = Helper.Content.Load <CustomOreData>("custom_ore_nodes.json", ContentSource.ModFolder); } catch { var tempData = Helper.Content.Load <CustomOreDataOld>("custom_ore_nodes.json", ContentSource.ModFolder); data = new CustomOreData(); for (int i = 0; i < tempData.nodes.Count; i++) { data.nodes.Add(new CustomOreNode(tempData.nodes[i])); } if (first) { Monitor.Log($"Rewriting custom_ore_nodes.json", LogLevel.Debug); Helper.Data.WriteJsonFile("custom_ore_nodes.json", data); } } conf = Helper.Data.ReadJsonFile <CustomOreConfig>("ore_config.json") ?? new CustomOreConfig(); foreach (object nodeObj in data.nodes) { CustomOreNode node = (CustomOreNode)nodeObj; if (node.spriteType == "mod") { node.texture = Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.ModFolder); } else { node.texture = Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent); } if (conf.parentSheetIndexes.ContainsKey(add)) { node.parentSheetIndex = conf.parentSheetIndexes[add]; } else { while (existingPSIs.ContainsKey(id)) { id++; } node.parentSheetIndex = id++; } conf.parentSheetIndexes[add] = node.parentSheetIndex; customOreNodesList.Add(node); add++; } if (first) { Monitor.Log($"Got {customOreNodesList.Count} ores from mod", LogLevel.Debug); Helper.Data.WriteJsonFile("ore_config.json", conf); } } else { SMonitor.Log("No custom_ore_nodes.json in mod directory."); } } catch (Exception ex) { SMonitor.Log("Error processing custom_ore_nodes.json: " + ex, LogLevel.Error); } foreach (IContentPack contentPack in Helper.ContentPacks.GetOwned()) { try { int add = 0; conf = contentPack.ReadJsonFile <CustomOreConfig>("ore_config.json") ?? new CustomOreConfig(); if (first) { Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}"); } try { data = contentPack.ReadJsonFile <CustomOreData>("custom_ore_nodes.json"); } catch (Exception ex) { Monitor.Log($"exception {ex}", LogLevel.Error); var tempData = contentPack.ReadJsonFile <CustomOreDataOld>("custom_ore_nodes.json"); data = new CustomOreData(); for (int i = 0; i < tempData.nodes.Count; i++) { data.nodes.Add(new CustomOreNode(tempData.nodes[i])); } if (first) { Monitor.Log($"Rewriting custom_ore_nodes.json", LogLevel.Debug); contentPack.WriteJsonFile("custom_ore_nodes.json", data); } } foreach (CustomOreNode node in data.nodes) { if (node.spriteType == "mod") { node.texture = contentPack.LoadAsset <Texture2D>(node.spritePath); } else { node.texture = Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent); } if (conf.parentSheetIndexes.ContainsKey(add)) { node.parentSheetIndex = conf.parentSheetIndexes[add]; } else { while (existingPSIs.ContainsKey(id)) { id++; } node.parentSheetIndex = id++; } conf.parentSheetIndexes[add] = node.parentSheetIndex; customOreNodesList.Add(node); add++; } if (first) { Monitor.Log($"Got {data.nodes.Count} ores from content pack {contentPack.Manifest.Name}", LogLevel.Debug); contentPack.WriteJsonFile("ore_config.json", conf); } } catch (Exception ex) { SMonitor.Log($"Error processing custom_ore_nodes.json in content pack {contentPack.Manifest.Name} {ex}", LogLevel.Error); } } if (first) { Monitor.Log($"Got {customOreNodesList.Count} ores total", LogLevel.Debug); } }
private void GameLoop_GameLaunched(object sender, StardewModdingAPI.Events.GameLaunchedEventArgs e) { CustomOreNodes.Clear(); CustomOreData data; Dictionary <string, Texture2D> gameTextures = new Dictionary <string, Texture2D>(); try { if (File.Exists(Path.Combine(Helper.DirectoryPath, "custom_ore_nodes.json"))) { Dictionary <string, Texture2D> modTextures = new Dictionary <string, Texture2D>(); data = Helper.Content.Load <CustomOreData>("custom_ore_nodes.json", ContentSource.ModFolder); foreach (string nodeInfo in data.nodes) { try { CustomOreNode node = new CustomOreNode(nodeInfo); if (node.spriteType == "mod") { if (!modTextures.ContainsKey(node.spritePath)) { modTextures.Add(node.spritePath, Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.ModFolder)); } node.texture = modTextures[node.spritePath]; } else { if (!gameTextures.ContainsKey(node.spritePath)) { gameTextures.Add(node.spritePath, Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent)); } node.texture = gameTextures[node.spritePath]; } CustomOreNodes.Add(node); } catch (Exception ex) { SMonitor.Log($"Error parsing node {nodeInfo}: {ex}", LogLevel.Error); } } Monitor.Log($"Got {CustomOreNodes.Count} ores from mod", LogLevel.Debug); } else { SMonitor.Log("No custom_ore_nodes.json in mod directory."); } } catch (Exception ex) { SMonitor.Log("Error processing custom_ore_nodes.json: " + ex, LogLevel.Error); } foreach (IContentPack contentPack in Helper.ContentPacks.GetOwned()) { try { Dictionary <string, Texture2D> modTextures = new Dictionary <string, Texture2D>(); Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}"); data = contentPack.ReadJsonFile <CustomOreData>("custom_ore_nodes.json"); foreach (string nodeInfo in data.nodes) { try { CustomOreNode node = new CustomOreNode(nodeInfo); if (node.spriteType == "mod") { if (!modTextures.ContainsKey(node.spritePath)) { modTextures.Add(node.spritePath, contentPack.LoadAsset <Texture2D>(node.spritePath)); } node.texture = modTextures[node.spritePath]; } else { if (!gameTextures.ContainsKey(node.spritePath)) { gameTextures.Add(node.spritePath, Helper.Content.Load <Texture2D>(node.spritePath, ContentSource.GameContent)); } node.texture = gameTextures[node.spritePath]; } CustomOreNodes.Add(node); } catch (Exception ex) { SMonitor.Log($"Error parsing node {nodeInfo}: {ex}", LogLevel.Error); } } Monitor.Log($"Got {data.nodes.Count} ores from content pack {contentPack.Manifest.Name}", LogLevel.Debug); } catch (Exception ex) { SMonitor.Log($"Error processing custom_ore_nodes.json in content pack {contentPack.Manifest.Name} {ex}", LogLevel.Error); } } Monitor.Log($"Got {CustomOreNodes.Count} ores total", LogLevel.Debug); Helper.Content.InvalidateCache("Maps/springobjects"); }