make item spawn commands more robust
This commit is contained in:
parent
08dc846195
commit
be79a04206
|
@ -57,6 +57,8 @@ For modders:
|
||||||
* Updated SMAPI/game version map.
|
* Updated SMAPI/game version map.
|
||||||
* Fixes:
|
* Fixes:
|
||||||
* Fixed mods needing to load custom `Map` assets before the game accesses them (SMAPI will now do so automatically).
|
* Fixed mods needing to load custom `Map` assets before the game accesses them (SMAPI will now do so automatically).
|
||||||
|
* Fixed Console Commands not including upgraded tools in item commands.
|
||||||
|
* Fixed Console Commands' item commands failing if a mod adds invalid item data.
|
||||||
* Fixed Save Backup not pruning old backups if they're uncompressed.
|
* Fixed Save Backup not pruning old backups if they're uncompressed.
|
||||||
* Fixed issues when a farmhand reconnects before the game notices they're disconnected.
|
* Fixed issues when a farmhand reconnects before the game notices they're disconnected.
|
||||||
* Fixed 'received message' logs shown in non-developer mode.
|
* Fixed 'received message' logs shown in non-developer mode.
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using StardewModdingAPI.Mods.ConsoleCommands.Framework.ItemData;
|
using StardewModdingAPI.Mods.ConsoleCommands.Framework.ItemData;
|
||||||
using StardewValley;
|
using StardewValley;
|
||||||
|
@ -22,176 +25,228 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Get all spawnable items.</summary>
|
/// <summary>Get all spawnable items.</summary>
|
||||||
|
[SuppressMessage("ReSharper", "AccessToModifiedClosure", Justification = "TryCreate invokes the lambda immediately.")]
|
||||||
public IEnumerable<SearchableItem> GetAll()
|
public IEnumerable<SearchableItem> GetAll()
|
||||||
{
|
{
|
||||||
// get tools
|
IEnumerable<SearchableItem> GetAllRaw()
|
||||||
yield return new SearchableItem(ItemType.Tool, ToolFactory.axe, ToolFactory.getToolFromDescription(ToolFactory.axe, 0));
|
|
||||||
yield return new SearchableItem(ItemType.Tool, ToolFactory.hoe, ToolFactory.getToolFromDescription(ToolFactory.hoe, 0));
|
|
||||||
yield return new SearchableItem(ItemType.Tool, ToolFactory.pickAxe, ToolFactory.getToolFromDescription(ToolFactory.pickAxe, 0));
|
|
||||||
yield return new SearchableItem(ItemType.Tool, ToolFactory.wateringCan, ToolFactory.getToolFromDescription(ToolFactory.wateringCan, 0));
|
|
||||||
yield return new SearchableItem(ItemType.Tool, ToolFactory.fishingRod, ToolFactory.getToolFromDescription(ToolFactory.fishingRod, 0));
|
|
||||||
yield return new SearchableItem(ItemType.Tool, this.CustomIDOffset, new MilkPail()); // these don't have any sort of ID, so we'll just assign some arbitrary ones
|
|
||||||
yield return new SearchableItem(ItemType.Tool, this.CustomIDOffset + 1, new Shears());
|
|
||||||
yield return new SearchableItem(ItemType.Tool, this.CustomIDOffset + 2, new Pan());
|
|
||||||
yield return new SearchableItem(ItemType.Tool, this.CustomIDOffset + 3, new Wand());
|
|
||||||
|
|
||||||
// clothing
|
|
||||||
foreach (int id in Game1.clothingInformation.Keys)
|
|
||||||
yield return new SearchableItem(ItemType.Clothing, id, new Clothing(id));
|
|
||||||
|
|
||||||
// wallpapers
|
|
||||||
for (int id = 0; id < 112; id++)
|
|
||||||
yield return new SearchableItem(ItemType.Wallpaper, id, new Wallpaper(id) { Category = SObject.furnitureCategory });
|
|
||||||
|
|
||||||
// flooring
|
|
||||||
for (int id = 0; id < 40; id++)
|
|
||||||
yield return new SearchableItem(ItemType.Flooring, id, new Wallpaper(id, isFloor: true) { Category = SObject.furnitureCategory });
|
|
||||||
|
|
||||||
// equipment
|
|
||||||
foreach (int id in Game1.content.Load<Dictionary<int, string>>("Data\\Boots").Keys)
|
|
||||||
yield return new SearchableItem(ItemType.Boots, id, new Boots(id));
|
|
||||||
foreach (int id in Game1.content.Load<Dictionary<int, string>>("Data\\hats").Keys)
|
|
||||||
yield return new SearchableItem(ItemType.Hat, id, new Hat(id));
|
|
||||||
foreach (int id in Game1.objectInformation.Keys)
|
|
||||||
{
|
{
|
||||||
if (id >= Ring.ringLowerIndexRange && id <= Ring.ringUpperIndexRange)
|
// get tools
|
||||||
yield return new SearchableItem(ItemType.Ring, id, new Ring(id));
|
for (int quality = Tool.stone; quality <= Tool.iridium; quality++)
|
||||||
}
|
|
||||||
|
|
||||||
// weapons
|
|
||||||
foreach (int id in Game1.content.Load<Dictionary<int, string>>("Data\\weapons").Keys)
|
|
||||||
{
|
|
||||||
Item weapon = (id >= 32 && id <= 34)
|
|
||||||
? (Item)new Slingshot(id)
|
|
||||||
: new MeleeWeapon(id);
|
|
||||||
yield return new SearchableItem(ItemType.Weapon, id, weapon);
|
|
||||||
}
|
|
||||||
|
|
||||||
// furniture
|
|
||||||
foreach (int id in Game1.content.Load<Dictionary<int, string>>("Data\\Furniture").Keys)
|
|
||||||
{
|
|
||||||
if (id == 1466 || id == 1468)
|
|
||||||
yield return new SearchableItem(ItemType.Furniture, id, new TV(id, Vector2.Zero));
|
|
||||||
else
|
|
||||||
yield return new SearchableItem(ItemType.Furniture, id, new Furniture(id, Vector2.Zero));
|
|
||||||
}
|
|
||||||
|
|
||||||
// craftables
|
|
||||||
foreach (int id in Game1.bigCraftablesInformation.Keys)
|
|
||||||
yield return new SearchableItem(ItemType.BigCraftable, id, new SObject(Vector2.Zero, id));
|
|
||||||
|
|
||||||
// secret notes
|
|
||||||
foreach (int id in Game1.content.Load<Dictionary<int, string>>("Data\\SecretNotes").Keys)
|
|
||||||
{
|
|
||||||
SObject note = new SObject(79, 1);
|
|
||||||
note.name = $"{note.name} #{id}";
|
|
||||||
yield return new SearchableItem(ItemType.Object, this.CustomIDOffset + id, note);
|
|
||||||
}
|
|
||||||
|
|
||||||
// objects
|
|
||||||
foreach (int id in Game1.objectInformation.Keys)
|
|
||||||
{
|
|
||||||
if (id == 79)
|
|
||||||
continue; // secret note handled above
|
|
||||||
if (id >= Ring.ringLowerIndexRange && id <= Ring.ringUpperIndexRange)
|
|
||||||
continue; // handled separated
|
|
||||||
|
|
||||||
SObject item = new SObject(id, 1);
|
|
||||||
yield return new SearchableItem(ItemType.Object, id, item);
|
|
||||||
|
|
||||||
// fruit products
|
|
||||||
if (item.Category == SObject.FruitsCategory)
|
|
||||||
{
|
{
|
||||||
// wine
|
yield return this.TryCreate(ItemType.Tool, ToolFactory.axe, () => ToolFactory.getToolFromDescription(ToolFactory.axe, quality));
|
||||||
SObject wine = new SObject(348, 1)
|
yield return this.TryCreate(ItemType.Tool, ToolFactory.hoe, () => ToolFactory.getToolFromDescription(ToolFactory.hoe, quality));
|
||||||
{
|
yield return this.TryCreate(ItemType.Tool, ToolFactory.pickAxe, () => ToolFactory.getToolFromDescription(ToolFactory.pickAxe, quality));
|
||||||
Name = $"{item.Name} Wine",
|
yield return this.TryCreate(ItemType.Tool, ToolFactory.wateringCan, () => ToolFactory.getToolFromDescription(ToolFactory.wateringCan, quality));
|
||||||
Price = item.Price * 3
|
if (quality != Tool.iridium)
|
||||||
};
|
yield return this.TryCreate(ItemType.Tool, ToolFactory.fishingRod, () => ToolFactory.getToolFromDescription(ToolFactory.fishingRod, quality));
|
||||||
wine.preserve.Value = SObject.PreserveType.Wine;
|
}
|
||||||
wine.preservedParentSheetIndex.Value = item.ParentSheetIndex;
|
yield return this.TryCreate(ItemType.Tool, this.CustomIDOffset, () => new MilkPail()); // these don't have any sort of ID, so we'll just assign some arbitrary ones
|
||||||
yield return new SearchableItem(ItemType.Object, this.CustomIDOffset * 2 + id, wine);
|
yield return this.TryCreate(ItemType.Tool, this.CustomIDOffset + 1, () => new Shears());
|
||||||
|
yield return this.TryCreate(ItemType.Tool, this.CustomIDOffset + 2, () => new Pan());
|
||||||
|
yield return this.TryCreate(ItemType.Tool, this.CustomIDOffset + 3, () => new Wand());
|
||||||
|
|
||||||
// jelly
|
// wallpapers
|
||||||
SObject jelly = new SObject(344, 1)
|
for (int id = 0; id < 112; id++)
|
||||||
{
|
yield return this.TryCreate(ItemType.Wallpaper, id, () => new Wallpaper(id) { Category = SObject.furnitureCategory });
|
||||||
Name = $"{item.Name} Jelly",
|
|
||||||
Price = 50 + item.Price * 2
|
// flooring
|
||||||
};
|
for (int id = 0; id < 40; id++)
|
||||||
jelly.preserve.Value = SObject.PreserveType.Jelly;
|
yield return this.TryCreate(ItemType.Flooring, id, () => new Wallpaper(id, isFloor: true) { Category = SObject.furnitureCategory });
|
||||||
jelly.preservedParentSheetIndex.Value = item.ParentSheetIndex;
|
|
||||||
yield return new SearchableItem(ItemType.Object, this.CustomIDOffset * 3 + id, jelly);
|
// equipment
|
||||||
|
foreach (int id in Game1.content.Load<Dictionary<int, string>>("Data\\Boots").Keys)
|
||||||
|
yield return this.TryCreate(ItemType.Boots, id, () => new Boots(id));
|
||||||
|
foreach (int id in Game1.content.Load<Dictionary<int, string>>("Data\\hats").Keys)
|
||||||
|
yield return this.TryCreate(ItemType.Hat, id, () => new Hat(id));
|
||||||
|
foreach (int id in Game1.objectInformation.Keys)
|
||||||
|
{
|
||||||
|
if (id >= Ring.ringLowerIndexRange && id <= Ring.ringUpperIndexRange)
|
||||||
|
yield return this.TryCreate(ItemType.Ring, id, () => new Ring(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// vegetable products
|
// weapons
|
||||||
else if (item.Category == SObject.VegetableCategory)
|
foreach (int id in Game1.content.Load<Dictionary<int, string>>("Data\\weapons").Keys)
|
||||||
{
|
{
|
||||||
// juice
|
yield return this.TryCreate(ItemType.Weapon, id, () => (id >= 32 && id <= 34)
|
||||||
SObject juice = new SObject(350, 1)
|
? (Item)new Slingshot(id)
|
||||||
{
|
: new MeleeWeapon(id)
|
||||||
Name = $"{item.Name} Juice",
|
);
|
||||||
Price = (int)(item.Price * 2.25d)
|
|
||||||
};
|
|
||||||
juice.preserve.Value = SObject.PreserveType.Juice;
|
|
||||||
juice.preservedParentSheetIndex.Value = item.ParentSheetIndex;
|
|
||||||
yield return new SearchableItem(ItemType.Object, this.CustomIDOffset * 4 + id, juice);
|
|
||||||
|
|
||||||
// pickled
|
|
||||||
SObject pickled = new SObject(342, 1)
|
|
||||||
{
|
|
||||||
Name = $"Pickled {item.Name}",
|
|
||||||
Price = 50 + item.Price * 2
|
|
||||||
};
|
|
||||||
pickled.preserve.Value = SObject.PreserveType.Pickle;
|
|
||||||
pickled.preservedParentSheetIndex.Value = item.ParentSheetIndex;
|
|
||||||
yield return new SearchableItem(ItemType.Object, this.CustomIDOffset * 5 + id, pickled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// flower honey
|
// furniture
|
||||||
else if (item.Category == SObject.flowersCategory)
|
foreach (int id in Game1.content.Load<Dictionary<int, string>>("Data\\Furniture").Keys)
|
||||||
{
|
{
|
||||||
// get honey type
|
if (id == 1466 || id == 1468)
|
||||||
SObject.HoneyType? type = null;
|
yield return this.TryCreate(ItemType.Furniture, id, () => new TV(id, Vector2.Zero));
|
||||||
switch (item.ParentSheetIndex)
|
else
|
||||||
|
yield return this.TryCreate(ItemType.Furniture, id, () => new Furniture(id, Vector2.Zero));
|
||||||
|
}
|
||||||
|
|
||||||
|
// craftables
|
||||||
|
foreach (int id in Game1.bigCraftablesInformation.Keys)
|
||||||
|
yield return this.TryCreate(ItemType.BigCraftable, id, () => new SObject(Vector2.Zero, id));
|
||||||
|
|
||||||
|
// secret notes
|
||||||
|
foreach (int id in Game1.content.Load<Dictionary<int, string>>("Data\\SecretNotes").Keys)
|
||||||
|
{
|
||||||
|
yield return this.TryCreate(ItemType.Object, this.CustomIDOffset + id, () =>
|
||||||
{
|
{
|
||||||
case 376:
|
SObject note = new SObject(79, 1);
|
||||||
type = SObject.HoneyType.Poppy;
|
note.name = $"{note.name} #{id}";
|
||||||
break;
|
return note;
|
||||||
case 591:
|
});
|
||||||
type = SObject.HoneyType.Tulip;
|
}
|
||||||
break;
|
|
||||||
case 593:
|
// objects
|
||||||
type = SObject.HoneyType.SummerSpangle;
|
foreach (int id in Game1.objectInformation.Keys)
|
||||||
break;
|
{
|
||||||
case 595:
|
if (id == 79)
|
||||||
type = SObject.HoneyType.FairyRose;
|
continue; // secret note handled above
|
||||||
break;
|
if (id >= Ring.ringLowerIndexRange && id <= Ring.ringUpperIndexRange)
|
||||||
case 597:
|
continue; // handled separated
|
||||||
type = SObject.HoneyType.BlueJazz;
|
|
||||||
break;
|
// spawn main item
|
||||||
case 421: // sunflower standing in for all other flowers
|
SObject item;
|
||||||
type = SObject.HoneyType.Wild;
|
{
|
||||||
break;
|
SearchableItem main = this.TryCreate(ItemType.Object, id, () => new SObject(id, 1));
|
||||||
|
yield return main;
|
||||||
|
item = main?.Item as SObject;
|
||||||
|
}
|
||||||
|
if (item == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// fruit products
|
||||||
|
if (item.Category == SObject.FruitsCategory)
|
||||||
|
{
|
||||||
|
// wine
|
||||||
|
yield return this.TryCreate(ItemType.Object, this.CustomIDOffset * 2 + id, () =>
|
||||||
|
{
|
||||||
|
SObject wine = new SObject(348, 1)
|
||||||
|
{
|
||||||
|
Name = $"{item.Name} Wine",
|
||||||
|
Price = item.Price * 3
|
||||||
|
};
|
||||||
|
wine.preserve.Value = SObject.PreserveType.Wine;
|
||||||
|
wine.preservedParentSheetIndex.Value = item.ParentSheetIndex;
|
||||||
|
return wine;
|
||||||
|
});
|
||||||
|
|
||||||
|
// jelly
|
||||||
|
yield return this.TryCreate(ItemType.Object, this.CustomIDOffset * 3 + id, () =>
|
||||||
|
{
|
||||||
|
SObject jelly = new SObject(344, 1)
|
||||||
|
{
|
||||||
|
Name = $"{item.Name} Jelly",
|
||||||
|
Price = 50 + item.Price * 2
|
||||||
|
};
|
||||||
|
jelly.preserve.Value = SObject.PreserveType.Jelly;
|
||||||
|
jelly.preservedParentSheetIndex.Value = item.ParentSheetIndex;
|
||||||
|
return jelly;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// yield honey
|
// vegetable products
|
||||||
if (type != null)
|
else if (item.Category == SObject.VegetableCategory)
|
||||||
{
|
{
|
||||||
SObject honey = new SObject(Vector2.Zero, 340, item.Name + " Honey", false, true, false, false)
|
// juice
|
||||||
|
yield return this.TryCreate(ItemType.Object, this.CustomIDOffset * 4 + id, () =>
|
||||||
{
|
{
|
||||||
Name = "Wild Honey"
|
SObject juice = new SObject(350, 1)
|
||||||
};
|
{
|
||||||
honey.honeyType.Value = type;
|
Name = $"{item.Name} Juice",
|
||||||
|
Price = (int)(item.Price * 2.25d)
|
||||||
|
};
|
||||||
|
juice.preserve.Value = SObject.PreserveType.Juice;
|
||||||
|
juice.preservedParentSheetIndex.Value = item.ParentSheetIndex;
|
||||||
|
return juice;
|
||||||
|
});
|
||||||
|
|
||||||
if (type != SObject.HoneyType.Wild)
|
// pickled
|
||||||
|
yield return this.TryCreate(ItemType.Object, this.CustomIDOffset * 5 + id, () =>
|
||||||
{
|
{
|
||||||
honey.Name = $"{item.Name} Honey";
|
SObject pickled = new SObject(342, 1)
|
||||||
honey.Price += item.Price * 2;
|
{
|
||||||
|
Name = $"Pickled {item.Name}",
|
||||||
|
Price = 50 + item.Price * 2
|
||||||
|
};
|
||||||
|
pickled.preserve.Value = SObject.PreserveType.Pickle;
|
||||||
|
pickled.preservedParentSheetIndex.Value = item.ParentSheetIndex;
|
||||||
|
return pickled;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// flower honey
|
||||||
|
else if (item.Category == SObject.flowersCategory)
|
||||||
|
{
|
||||||
|
// get honey type
|
||||||
|
SObject.HoneyType? type = null;
|
||||||
|
switch (item.ParentSheetIndex)
|
||||||
|
{
|
||||||
|
case 376:
|
||||||
|
type = SObject.HoneyType.Poppy;
|
||||||
|
break;
|
||||||
|
case 591:
|
||||||
|
type = SObject.HoneyType.Tulip;
|
||||||
|
break;
|
||||||
|
case 593:
|
||||||
|
type = SObject.HoneyType.SummerSpangle;
|
||||||
|
break;
|
||||||
|
case 595:
|
||||||
|
type = SObject.HoneyType.FairyRose;
|
||||||
|
break;
|
||||||
|
case 597:
|
||||||
|
type = SObject.HoneyType.BlueJazz;
|
||||||
|
break;
|
||||||
|
case 421: // sunflower standing in for all other flowers
|
||||||
|
type = SObject.HoneyType.Wild;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// yield honey
|
||||||
|
if (type != null)
|
||||||
|
{
|
||||||
|
yield return this.TryCreate(ItemType.Object, this.CustomIDOffset * 5 + id, () =>
|
||||||
|
{
|
||||||
|
SObject honey = new SObject(Vector2.Zero, 340, item.Name + " Honey", false, true, false, false)
|
||||||
|
{
|
||||||
|
Name = "Wild Honey"
|
||||||
|
};
|
||||||
|
honey.honeyType.Value = type;
|
||||||
|
|
||||||
|
if (type != SObject.HoneyType.Wild)
|
||||||
|
{
|
||||||
|
honey.Name = $"{item.Name} Honey";
|
||||||
|
honey.Price += item.Price * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return honey;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
yield return new SearchableItem(ItemType.Object, this.CustomIDOffset * 5 + id, honey);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return GetAllRaw().Where(p => p != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Private methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Create a searchable item if valid.</summary>
|
||||||
|
/// <param name="type">The item type.</param>
|
||||||
|
/// <param name="id">The unique ID (if different from the item's parent sheet index).</param>
|
||||||
|
/// <param name="createItem">Create an item instance.</param>
|
||||||
|
private SearchableItem TryCreate(ItemType type, int id, Func<Item> createItem)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new SearchableItem(type, id, createItem());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null; // if some item data is invalid, just don't include it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue