Skip to content

Commit

Permalink
initial build fixes for BetterJunimosForestry
Browse files Browse the repository at this point in the history
This attempts to fix the BetterJunimosForestry mod to work with Stardew
Valley 1.6, though it is currently build-tested only.

The big changes include:

* switching to string IDs instead of numerical indexes
* fixing many function references
* re-wrote the fruit tree harvest logic entirely
* removed a bunch of references to debris logic that appears to have
  been removed from Stardew Valley 1.6
* Update the target to net6.0, and update the ModBuildConfig and JSON
  references.
* Various other fixes require to get things compiling

Signed-off-by: Jacob Keller <[email protected]>
  • Loading branch information
jacob-keller committed Apr 10, 2024
1 parent 866bddc commit 5104fff
Show file tree
Hide file tree
Showing 13 changed files with 83 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ private static Vector2 GetToolPixelPosition(Vector2 tile) {
return (tile * Game1.tileSize) + new Vector2(Game1.tileSize / 2f);
}

public List<int> RequiredItems() {
public List<string> RequiredItems() {
return new();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public bool IsActionAvailable(GameLocation location, Vector2 pos, Guid guid) {
}

public bool PerformAction(GameLocation location, Vector2 pos, JunimoHarvester junimo, Guid guid) {
var chest = Util.GetHutFromId(guid).output.Value;
var chest = Util.GetHutFromId(guid).GetOutputChest();

var (x, y) = pos;
var up = new Vector2(x, y + 1);
Expand All @@ -57,7 +57,7 @@ public bool PerformAction(GameLocation location, Vector2 pos, JunimoHarvester ju
Vector2[] positions = { up, right, down, left };
foreach (var nextPos in positions) {
if (!Util.IsWithinRadius(location, Util.GetHutFromId(guid), nextPos)) continue;
if (DebrisIndexAtTile(nextPos) > 0) {
if (DebrisIndexAtTile(nextPos) != "") {
junimo.faceDirection(direction);
return MoveDebrisFromTileToChest(nextPos, location, chest);
}
Expand All @@ -67,13 +67,13 @@ public bool PerformAction(GameLocation location, Vector2 pos, JunimoHarvester ju
}

protected bool IsDebrisAtTile(Vector2 tile) {
return DebrisIndexAtTile(tile) > 0;
return DebrisIndexAtTile(tile) != "";
}

protected int DebrisIndexAtTile(Vector2 tile) {
protected string DebrisIndexAtTile(Vector2 tile) {
// Monitor.Log($"IsDebrisAtTile {tile}", LogLevel.Debug);
if (Game1.currentLocation.debris is null) {
return -1;
return "";
}
foreach (Debris d in Game1.currentLocation.debris) {
foreach (Chunk c in d.Chunks) {
Expand All @@ -83,16 +83,12 @@ protected int DebrisIndexAtTile(Vector2 tile) {
// Monitor.Log($" Debris chunks: {d.Chunks.Count} type: {d.debrisType} at {dx},{dy}", LogLevel.Debug);
if (d.item is not null) {
// Monitor.Log($" {d.item.Name} [{d.item.ParentSheetIndex}]", LogLevel.Debug);
return d.item.ParentSheetIndex;
}
else {
// Monitor.Log($" non-item debris [{c.debrisType}]", LogLevel.Debug);
return c.debrisType;
return d.item.ItemId;
}
}
}
}
return 0;
return "";
}

protected bool MoveDebrisFromTileToChest(Vector2 tile, GameLocation farm, Chest chest) {
Expand Down Expand Up @@ -123,20 +119,14 @@ protected bool MoveDebrisFromTileToChest(Vector2 tile, GameLocation farm, Chest
protected void MoveDebrisToChest(Debris d, GameLocation farm, Chest chest) {
foreach (Chunk c in d.Chunks) {
if (d.item is not null) {
SObject item = new SObject(d.item.ParentSheetIndex, 1);
SObject item = new SObject(d.item.ItemId, 1);
Util.AddItemToChest(farm, chest, item);
//Monitor.Log($" MoveDebrisToChest {d.item.Name} [{d.item.ParentSheetIndex}]", LogLevel.Debug);
} else {
SObject item = new SObject(c.debrisType, 1);
if (item.Name != "Error Item") {
Util.AddItemToChest(farm, chest, item);
//Monitor.Log($" MoveDebrisToChest {item.Name} [{c.debrisType}]", LogLevel.Debug);
}
}
}
}

public List<int> RequiredItems() {
public List<string> RequiredItems() {
return new();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private static bool IsHarvestableSeed(TerrainFeature t, string mode)
if (t is not Tree tree) return false;
if (tree.growthStage.Value != 0) return false;
if (mode == Modes.Normal) return false;
if (mode == Modes.Forest && PlantTreesAbility.IsTileInPattern(t.currentTileLocation)) return false;
if (mode == Modes.Forest && PlantTreesAbility.IsTileInPattern(t.Tile)) return false;
return true;
}

Expand All @@ -66,7 +66,7 @@ private static Vector2 GetToolPixelPosition(Vector2 tile)
return tile * Game1.tileSize + new Vector2(Game1.tileSize / 2f);
}

public List<int> RequiredItems()
public List<string> RequiredItems()
{
return new();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace BetterJunimosForestry.Abilities {
public class FertilizeTreesAbility : IJunimoAbility {
private const int tree_fertilizer = 805;
private const string tree_fertilizer = "805";

public string AbilityName() {
return "FertilizeTrees";
Expand All @@ -23,18 +23,18 @@ public bool IsActionAvailable(GameLocation farm, Vector2 pos, Guid guid) {
}

public bool PerformAction(GameLocation farm, Vector2 pos, JunimoHarvester junimo, Guid guid) {
var chest = Util.GetHutFromId(guid).output.Value;
var foundItem = chest.items.FirstOrDefault(item => item is {ParentSheetIndex: tree_fertilizer});
var chest = Util.GetHutFromId(guid).GetOutputChest();
var foundItem = chest.Items.FirstOrDefault(item => item is {ItemId: tree_fertilizer});
if (foundItem == null) return false;

if (farm.terrainFeatures[pos] is not Tree t) return false;
t.fertilize(farm);
t.fertilize();
Util.RemoveItemFromChest(chest, foundItem);
return true;

}

public List<int> RequiredItems() {
public List<string> RequiredItems() {
return new() { tree_fertilizer };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class HarvestDebrisAbility : IJunimoAbility {
private readonly FakeFarmer FakeFarmer = new();
private readonly Pickaxe FakePickaxe = new();
private readonly Axe FakeAxe = new();
private readonly MeleeWeapon Scythe = new(47);
private readonly MeleeWeapon Scythe = new("47");

internal HarvestDebrisAbility(IMonitor Monitor) {
this.Monitor = Monitor;
Expand Down Expand Up @@ -93,7 +93,7 @@ public bool PerformAction(GameLocation location, Vector2 pos, JunimoHarvester ju

if (IsWeed(item)) {
UseToolOnTile(Scythe, nextPos, location);
item.performToolAction(Scythe, location);
item.performToolAction(Scythe);
location.removeObject(nextPos, false);
}

Expand Down Expand Up @@ -123,7 +123,7 @@ private static Vector2 GetToolPixelPosition(Vector2 tile) {
return tile * Game1.tileSize + new Vector2(Game1.tileSize / 2f);
}

public List<int> RequiredItems() {
public List<string> RequiredItems() {
return new();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public string AbilityName() {
}

private static bool IsHarvestableFruitTree(TerrainFeature tf) {
return tf is FruitTree tree && tree.fruitsOnTree.Value > 0;
return tf is FruitTree tree && tree.fruit.Any();
}

public bool IsActionAvailable(GameLocation location, Vector2 pos, Guid guid) {
Expand Down Expand Up @@ -61,40 +61,21 @@ public bool PerformAction(GameLocation location, Vector2 pos, JunimoHarvester ju
return false;
}

/// <summary>Harvest fruit from a FruitTree and update the tree accordingly.</summary>
private static SObject GetFruitFromTree(FruitTree tree) {
if (tree.fruitsOnTree.Value == 0)
return null;

var quality = 0;
if (tree.daysUntilMature.Value <= -112)
quality = 1;
if (tree.daysUntilMature.Value <= -224)
quality = 2;
if (tree.daysUntilMature.Value <= -336)
quality = 4;
if (tree.struckByLightningCountdown.Value > 0)
quality = 0;

tree.fruitsOnTree.Value --;

var result = new SObject(Vector2.Zero, tree.struckByLightningCountdown.Value > 0 ? 382 : tree.indexOfFruit.Value, 1) { Quality = quality };
return result;
}

private static bool HarvestFromTree(Vector2 pos, JunimoHarvester junimo, FruitTree tree) {
//shake the tree without it releasing any fruit
var fruitsOnTree = tree.fruitsOnTree.Value;
tree.fruitsOnTree.Value = 0;
tree.performUseAction(pos, junimo.currentLocation);
tree.fruitsOnTree.Value = fruitsOnTree;
var result = GetFruitFromTree(tree);
if (result == null) return false;
junimo.tryToAddItemToHut(result);
// do nothing if the tree has no item
if (!tree.fruit.Any())
return false;

// take all the item first
foreach (var item in tree.fruit)
junimo.tryToAddItemToHut(item);
tree.fruit.Clear();
// shake the tree after
tree.performUseAction(pos);
return true;
}

public List<int> RequiredItems() {
public List<string> RequiredItems() {
return new();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ protected bool TryHarvestGrass(Grass grass, GameLocation location, Vector2 tile)
return true;
}

public List<int> RequiredItems() {
public List<string> RequiredItems() {
return new();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using StardewModdingAPI;
using StardewValley.Buildings;
using SObject = StardewValley.Object;
using StardewValley.GameData.Crops;

// bits of this are from Tractor Mod; https://github.com/Pathoschild/StardewMods/blob/68628a40f992288278b724984c0ade200e6e4296/TractorMod/Framework/BaseAttachment.cs#L132

Expand All @@ -20,8 +21,8 @@ namespace BetterJunimosForestry.Abilities
public class HoeAroundTreesAbility : IJunimoAbility
{
private readonly IMonitor Monitor;
private static readonly List<int> WildTreeSeeds = new() {292, 309, 310, 311, 891};
private static readonly Dictionary<string, Dictionary<int, bool>> cropSeasons = new();
private static readonly List<string> WildTreeSeeds = new() {"292", "309", "310", "311", "891"};
private static readonly Dictionary<string, Dictionary<string, bool>> cropSeasons = new();
private const int SunflowerSeeds = 431;

internal HoeAroundTreesAbility(IMonitor Monitor)
Expand All @@ -30,7 +31,7 @@ internal HoeAroundTreesAbility(IMonitor Monitor)
var seasons = new List<string> {"spring", "summer", "fall", "winter"};
foreach (string season in seasons)
{
cropSeasons[season] = new Dictionary<int, bool>();
cropSeasons[season] = new Dictionary<string, bool>();
}
}

Expand Down Expand Up @@ -154,7 +155,7 @@ private bool SeedsAvailableToPlantThisTile(GameLocation location, JunimoHut hut,
return false;
}

Chest chest = hut.output.Value;
Chest chest = hut.GetOutputChest();
if (ModEntry.BJApi.GetCropMapForHut(guid) is null)
{
foundItem = PlantableSeed(location, chest);
Expand All @@ -169,8 +170,8 @@ private bool SeedsAvailableToPlantThisTile(GameLocation location, JunimoHut hut,
/// <summary>Get an item from the chest that is a crop seed, plantable in this season</summary>
private Item PlantableSeed(GameLocation location, Chest chest, string cropType = null)
{
List<Item> foundItems = chest.items.ToList().FindAll(item =>
item is {Category: SObject.SeedsCategory} && !WildTreeSeeds.Contains(item.ParentSheetIndex)
List<Item> foundItems = chest.Items.ToList().FindAll(item =>
item is {Category: SObject.SeedsCategory} && !WildTreeSeeds.Contains(item.ItemId)
);

if (cropType == CropTypes.Trellis)
Expand All @@ -194,7 +195,7 @@ private Item PlantableSeed(GameLocation location, Chest chest, string cropType =
continue;
}

var key = foundItem.ParentSheetIndex;
var key = foundItem.ItemId;
try
{
if (cropSeasons[Game1.currentSeason][key])
Expand All @@ -204,37 +205,29 @@ private Item PlantableSeed(GameLocation location, Chest chest, string cropType =
}
catch (KeyNotFoundException)
{
Monitor.Log($"Cache miss: {foundItem.ParentSheetIndex} {Game1.currentSeason}", LogLevel.Trace);
var crop = new Crop(foundItem.ParentSheetIndex, 0, 0);
cropSeasons[Game1.currentSeason][key] = crop.seasonsToGrowIn.Contains(Game1.currentSeason);
Monitor.Log($"Cache miss: {foundItem.ItemId} {Game1.currentSeason}", LogLevel.Trace);
Game1.cropData.TryGetValue(foundItem.ItemId, out CropData cropData);
cropSeasons[Game1.currentSeason][key] = cropData.Seasons.Contains(location.GetSeason());
if (cropSeasons[Game1.currentSeason][key])
{
return foundItem;
}
}

return foundItem;

//
// Crop crop = new Crop(foundItem.ParentSheetIndex, 0, 0);
// if (crop.seasonsToGrowIn.Contains(Game1.currentSeason)) {
// return foundItem;
// }
}

return null;
}

private static bool IsTrellisCrop(Item item)
{
var crop = new Crop(item.ParentSheetIndex, 0, 0);
return crop.raisedSeeds.Value;
Game1.cropData.TryGetValue(item.ItemId, out CropData cropData);
return cropData is not null && cropData.IsRaised;
}

private static bool CanHoeThisTile(GameLocation farm, Vector2 pos)
{
// is this tile plain dirt?
if (farm.isTileOccupied(pos)) return false;
if (farm.IsTileOccupiedBy(pos)) return false;
if (Util.IsOccupied(farm, pos)) return false;
if (!Util.CanBeHoed(farm, pos)) return false;
if (farm.doesTileHaveProperty((int) pos.X, (int) pos.Y, "Diggable", "Back") != null) return true;
Expand Down Expand Up @@ -275,21 +268,11 @@ private static bool UseToolOnTileManual(GameLocation location, Vector2 tileLocat
location.playSound("hoeHit");
}

removeSquareDebrisFromTile(location, (int) tileLocation.X, (int) tileLocation.Y);
location.checkForBuriedItem((int) tileLocation.X, (int) tileLocation.Y, false, false, Game1.player);
return true;
}

private static void removeSquareDebrisFromTile(GameLocation location, int tileX, int tileY)
{
location.debris.Filter(
debris =>
debris.debrisType.Value != Debris.DebrisType.SQUARES
|| (int) (debris.Chunks[0].position.X / 64.0) != tileX
|| debris.chunkFinalYLevel / 64 != tileY);
}

public List<int> RequiredItems()
public List<string> RequiredItems()
{
return new();
}
Expand Down
Loading

0 comments on commit 5104fff

Please sign in to comment.