Skip to content

Commit

Permalink
add item query to make all variants for sale
Browse files Browse the repository at this point in the history
  • Loading branch information
Mushymato committed Oct 29, 2024
1 parent 5c9cce6 commit 0b38197
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 73 deletions.
51 changes: 47 additions & 4 deletions TrinketTinker/Extras/ItemQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ namespace TrinketTinker.Extras
{
public static class ItemQuery
{
public static readonly string CreateTrinketQuery = $"{ModEntry.ModId}_CREATE_TRINKET";
public static readonly string ItemQuery_CREATE_TRINKET = $"{ModEntry.ModId}_CREATE_TRINKET";
public static readonly string ItemQuery_CREATE_TRINKET_ALL_VARIANTS = $"{ModEntry.ModId}_CREATE_TRINKET_ALL_VARIANTS";
private const string RANDOM = "R";
private const string ALL = "A";

/// <summary>
/// Get a int value from argument at index.
Expand All @@ -32,7 +34,7 @@ private static bool TryGetOptionalOrRandom(string[] array, int index, int maxVal
}

/// <summary>
/// mushymato.TrinketTinker_CREATE_TRINKET UnqualifiedId Level? Variant?
/// mushymato.TrinketTinker_CREATE_TRINKET UnqualifiedId [Level] [Variant]<br/>
/// Creates a new trinket item. If the trinket has tinker data, set level and variant.
/// If level="R", roll a random level
/// If variant="R", roll a random variant
Expand All @@ -41,10 +43,10 @@ private static bool TryGetOptionalOrRandom(string[] array, int index, int maxVal
/// <param name="arguments"></param>
/// <param name="context"></param>
/// <param name="avoidRepeat"></param>
/// <param name="avoidItemIds"></param>
/// <param name="avoidItemIds">ignored</param>
/// <param name="logError"></param>
/// <returns></returns>
public static IEnumerable<ItemQueryResult> CreateTrinket(string key, string arguments, ItemQueryContext context, bool avoidRepeat, HashSet<string> avoidItemIds, Action<string, string> logError)
public static IEnumerable<ItemQueryResult> CREATE_TRINKET(string key, string arguments, ItemQueryContext context, bool avoidRepeat, HashSet<string> avoidItemIds, Action<string, string> logError)
{
string[] array = ItemQueryResolver.Helpers.SplitArguments(arguments);
if (!ArgUtility.TryGet(array, 0, out string trinketId, out string error1, allowBlank: false, "string trinketId"))
Expand All @@ -65,5 +67,46 @@ public static IEnumerable<ItemQueryResult> CreateTrinket(string key, string argu
}
return ItemQueryResolver.Helpers.ErrorResult(key, arguments, logError, $"No trinket with id {trinketId}.");
}

/// <summary>
/// mushymato.TrinketTinker_CREATE_TRINKET_ALL_VARIANTS UnqualifiedId [Level]<br/>
/// If the trinket has trinket tinker data, create one of each variant.
/// If level="R", roll a random level and apply it to every created trinket.
/// </summary>
/// <param name="key"></param>
/// <param name="arguments"></param>
/// <param name="context"></param>
/// <param name="avoidRepeat"></param>
/// <param name="avoidItemIds">ignored</param>
/// <param name="logError"></param>
/// <returns></returns>
public static IEnumerable<ItemQueryResult> CREATE_TRINKET_ALL_VARIANTS(string key, string arguments, ItemQueryContext context, bool avoidRepeat, HashSet<string> avoidItemIds, Action<string, string> logError)
{
string[] array = ItemQueryResolver.Helpers.SplitArguments(arguments);
if (!ArgUtility.TryGet(array, 0, out string trinketId, out string error1, allowBlank: false, "string trinketId"))
return ItemQueryResolver.Helpers.ErrorResult(key, arguments, logError, error1);

TrinketDataDefinition trinketDataDefinition = (TrinketDataDefinition)ItemRegistry.GetTypeDefinition(ItemRegistry.type_trinket);
if (trinketDataDefinition.GetData(trinketId) is not ParsedItemData trinketData)
return ItemQueryResolver.Helpers.ErrorResult(key, arguments, logError, $"No trinket with id {trinketId}.");
Trinket trinket = (Trinket)trinketDataDefinition.CreateItem(trinketData);
if (trinket.GetEffect() is not TrinketTinkerEffect effect)
return ItemQueryResolver.Helpers.ErrorResult(key, arguments, logError, $"Not a TrinketTinker trinket.");
if (effect.MaxVariant == 0)
return ItemQueryResolver.Helpers.ErrorResult(key, arguments, logError, $"Trinket has no variants.");

TryGetOptionalOrRandom(array, 1, effect.MaxLevel, context, out int level);

List<ItemQueryResult> createdTrinkets = [];
for (int variant = 0; variant < effect.MaxVariant; variant++)
{
effect = (TrinketTinkerEffect)trinket.GetEffect();
effect.SetLevel(trinket, level);
effect.SetVariant(trinket, variant);
createdTrinkets.Add(new ItemQueryResult(trinket));
trinket = (Trinket)trinket.getOne();
}
return createdTrinkets;
}
}
}
22 changes: 3 additions & 19 deletions TrinketTinker/ModEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,9 @@ private void OnGameLaunched(object? sender, GameLaunchedEventArgs e)
TriggerActionManager.RegisterTrigger(RaiseTriggerAbility.TriggerEventName);

// Add item query for creating a trinket with specific level and variant
ItemQueryResolver.Register(ItemQuery.CreateTrinketQuery, ItemQuery.CreateTrinket);

// FIXME: spacecore doesn't support trinkets atm, perhaps send PR
// Add extra equipment slots
// if (Helper.ModRegistry.IsLoaded("spacechase0.SpaceCore") &&
// Helper.ModRegistry.GetApi<Integration.ISpaceCoreApi>("spacechase0.SpaceCore") is Integration.ISpaceCoreApi SC)
// {
// foreach (int i in Enumerable.Range(1, 3))
// {
// SC.RegisterEquipmentSlot(
// ModManifest,
// $"{ModId}_ExtraTrinketSlot_{i}",
// (item) => item == null || item is Trinket,
// () => $"Extra Trinket {i}",
// Game1.menuTexture,
// Game1.getSourceRectForStandardTileSheet(Game1.menuTexture, 70)
// );
// }
// }
ItemQueryResolver.Register(ItemQuery.ItemQuery_CREATE_TRINKET, ItemQuery.CREATE_TRINKET);
// Add item query for creating all variants of a trinket
ItemQueryResolver.Register(ItemQuery.ItemQuery_CREATE_TRINKET_ALL_VARIANTS, ItemQuery.CREATE_TRINKET_ALL_VARIANTS);
}

private static void OnAssetRequested(object? sender, AssetRequestedEventArgs e)
Expand Down
12 changes: 6 additions & 6 deletions TrinketTinker/Models/TinkerData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@ public sealed class TinkerData
{
/// <summary>Trinket stat minimum level, this added to the internal level value that is based on size of <see cref="Abilities"/></summary>
public int MinLevel { get; set; } = 1;
/// <summary>GSQ conditions for locking variants.</summary>
public List<string?> VariantUnlockConditions = [];
/// <summary>List of variants</summary>
public List<VariantData> Variants { get; set; } = [];
/// <summary>List of motions</summary>
public List<MotionData> Motions { get; set; } = [];
/// <summary>Shim for case of just 1 motion</summary>
public MotionData? Motion
{
Expand All @@ -21,9 +17,13 @@ public MotionData? Motion
Motions.Insert(0, value);
}
}
/// <summary>GSQ conditions for locking abilities.</summary>
public List<string?> AbilityUnlockConditions = [];
/// <summary>List of motions</summary>
public List<MotionData> Motions { get; set; } = [];
/// <summary>List of abilities</summary>
public List<List<AbilityData>> Abilities { get; set; } = [];
/// <summary>GSQ conditions for locking variants.</summary>
public List<string?> VariantUnlockConditions = [];
/// <summary>GSQ conditions for locking abilities.</summary>
public List<string?> AbilityUnlockConditions = [];
}
}
52 changes: 39 additions & 13 deletions [CP] Sinister Servants/data/angry_roger_shop.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,41 +104,67 @@
"category_trinket"
],
"Items": [
{
"Id": "(TR){{ModId}}_Spider",
"TradeItemId": "(O)769",
"TradeItemAmount": 200,
"ItemId": "(TR){{ModId}}_Spider",
},
{
"Id": "(TR){{ModId}}_DustSpirit",
"TradeItemId": "(O)382",
"TradeItemAmount": 300,
"ItemId": "(TR){{ModId}}_DustSpirit",
},
{
"Id": "(TR){{ModId}}_Stick",
"TradeItemId": "(O)388",
"TradeItemAmount": 999,
"ItemId": "(TR){{ModId}}_Stick"
},
// Normal: can only buy first variant of skull/bat/snek
{
"Id": "(TR){{ModId}}_Skull",
"TradeItemId": "(O)881",
"TradeItemAmount": 200,
"ItemId": "(TR){{ModId}}_Skull",
"Condition": "!SEASON_DAY fall 27"
},
{
"Id": "(TR){{ModId}}_Bat",
"TradeItemId": "(O)767",
"TradeItemAmount": 200,
"ItemId": "(TR){{ModId}}_Bat",
"Condition": "!SEASON_DAY fall 27"
},
{
"Id": "(TR){{ModId}}_Stick",
"TradeItemId": "(O)388",
"TradeItemAmount": 999,
"ItemId": "(TR){{ModId}}_Stick",
"Id": "(TR){{ModId}}_Snek",
"TradeItemId": "(O)226",
"TradeItemAmount": 77,
"ItemId": "(TR){{ModId}}_Snek",
"Condition": "!SEASON_DAY fall 27"
},
// Secret: during spirit's eve, all variants of skull/bat/snek can be directly purchased
{
"Id": "(TR){{ModId}}_DustSpirit",
"TradeItemId": "(O)382",
"TradeItemAmount": 300,
"ItemId": "(TR){{ModId}}_DustSpirit",
"Id": "(TR){{ModId}}_Skull_fall_27",
"TradeItemId": "(O)881",
"TradeItemAmount": 200,
"ItemId": "mushymato.TrinketTinker_CREATE_TRINKET_ALL_VARIANTS {{ModId}}_Skull",
"Condition": "SEASON_DAY fall 27"
},
{
"Id": "(TR){{ModId}}_Spider",
"TradeItemId": "(O)769",
"Id": "(TR){{ModId}}_Bat",
"TradeItemId": "(O)767",
"TradeItemAmount": 200,
"ItemId": "(TR){{ModId}}_Spider",
"ItemId": "mushymato.TrinketTinker_CREATE_TRINKET_ALL_VARIANTS {{ModId}}_Bat",
"Condition": "SEASON_DAY fall 27"
},
{
"Id": "(TR){{ModId}}_Snek",
"Id": "(TR){{ModId}}_Snek_fall_27",
"TradeItemId": "(O)226",
"TradeItemAmount": 77,
"ItemId": "(TR){{ModId}}_Snek",
"ItemId": "mushymato.TrinketTinker_CREATE_TRINKET_ALL_VARIANTS {{ModId}}_Snek",
"Condition": "SEASON_DAY fall 27"
},
{
"Id": "(TR){{ModId}}_TrinketColorizer",
Expand Down
35 changes: 29 additions & 6 deletions guide/1-Tinker.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,34 @@ When a `mushymato.TrinketTinker/Tinker` entry exists, the `TrinketEffectClass` w
| `Motion` | [MotionData](3-Motion.md) | _empty_ | Defines how the companion moves, setting this is shortcut for having a single item in `Motions`. |
| `Motions` | [List\<MotionData\>](3-Motion.md) | _empty_ | Defines how the companion moves. |
| `Abilities` | [List\<List\<AbilityData\>\>](4-Ability.md) | _empty_ | Defines what effects are activated, and when. Each list in the list of lists represents 1 ability level. |
| `VariantUnlockConditions` | List<string> | _empty_ | List of [game state queries](https://stardewvalleywiki.com/Modding:Game_state_queries) that determine how many variants are unlocked. |
| `AbilityUnlockConditions` | List<string> | _empty_ | List of [game state queries](https://stardewvalleywiki.com/Modding:Game_state_queries) that determine how many abilities are unlocked. |

## Notes

- Technically all fields here are optional, but in that case there'd be little point to using this framework at all.
- To display a companion, at least 1 Variant and 1 Motion must be defined.
- To have the trinket do things, at least 1 list of abilities must be defined.
- At the moment, there's no reason to have more than 1 Motion, but this may change in the future.
- Trinkets are created with a random level, rather than the minimum level.
### This is a lot of stuff, what do I need to define?

Technically all fields here are optional, but in that case there'd be little point to using this framework at all. To display a companion, at least 1 Variant and 1 Motion must be defined. To have the trinket do things, at least 1 list of abilities must be defined.

At the moment, there's no reason to have more than 1 Motion so just setting `Motion` is sufficient, but this may change in the future.

Trinkets are created with the first variant and at minimum level. The item query [mushymato.TrinketTinker_CREATE_TRINKET](6-Item%20Queries.md) is needed to create trinket at other variants/levels.

### Unlock Conditions

`VariantUnlockConditions` and `AbilityUnlockConditions` can prevent the player from rolling variants or abilities above a certain level using [game state queries](https://stardewvalleywiki.com/Modding:Game_state_queries). This only affects rerolling level and variants on the [anvil](https://stardewvalleywiki.com/Anvil) and [colorizer](7-Trinket%20Colorizer.md).

Example usage with 4 abilities (lv1 to lv4):

```json
"AbilityUnlockConditions": [
// level 1 is always unlocked
// level 2 is unconditionally unlocked
null,
// level 3 unlocked if player has a gold ore in inventory
"PLAYER_HAS_ITEM Current (O)384",
// level 4 is also unconditionally unlocked once 3 is unlocked
null,
// there is no level 5, so this value is meaningless
"FALSE",
],
```
23 changes: 0 additions & 23 deletions guide/6-Extras.md

This file was deleted.

23 changes: 23 additions & 0 deletions guide/6-Item Queries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# [Item Queries](https://stardewvalleywiki.com/Modding:Item_queries)

These are useful for populating shops and machine output rules.

## mushymato.TrinketTinker_CREATE_TRINKET

```
mushymato.TrinketTinker_CREATE_TRINKET <trinket id> [level] [variant]
```

Create a new trinket item. If the trinket has tinker data, set level and variant. Useful for producing a trinket at specified level/variant.

Setting level or variant to "R" will randomize the level or variant.

## mushymato.TrinketTinker_CREATE_TRINKET_ALL_VARIANTS

```
mushymato.TrinketTinker_CREATE_TRINKET_ALL_VARIANTS <trinket id> [level]
```

Create all variants of a trinket (with tinker data). Useful for making a shop sell all variants of a trinket instead of making the player roll for them.

Setting level to "R" will randomize the level once, and then set trinkets created by this query to that level.
9 changes: 9 additions & 0 deletions guide/7-Trinket Colorizer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Trinket Colorizer ![Trinket Colorizer](~/images/favicon.png)

The trinket colorizer is a big craftable [machine](https://stardewvalleywiki.com/Modding:Machines) that can be purchased from [the Blacksmith](https://stardewvalleywiki.com/Blacksmith) for 50 [Gold Bars](https://stardewvalleywiki.com/Gold_Bar) once the [Anvil](https://stardewvalleywiki.com/Anvil) recipe is obtained. Trinkets must have at least 2 [variants](2-Variant.md) and `CanBeReforged` set to true in order to use the colorizer.

Consumes 15 [Omni Geode](https://stardewvalleywiki.com/Omni_Geode) to reroll the variant on a TrinketTinker trinket, no effect on vanilla trinkets.

The colorizer will never roll the same variant twice in a row. Anvils have similar rule applied to them for TrinketTinker trinkets.

Implementation wise, the colorizer is a standard machine with qualified ID `(BC)mushymato.TrinketTinker_TrinketColorizer` and a single complex output machine rule. Mods are can add more ways to obtain this machine or prepend the colorizer with special upgrade rules for their trinkets.
6 changes: 4 additions & 2 deletions guide/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,7 @@
name: Ability
- href: 5-Temporary Animated Sprite.md
name: Temporary Animated Sprite
- href: 6-Extras.md
name: Extras
- href: 6-Item Queries.md
name: Item Queries
- href: 7-Trinket Colorizer.md
name: Trinket Colorizer

0 comments on commit 0b38197

Please sign in to comment.