From 5a18af183b9f58f09732473676a7d51c2630ae62 Mon Sep 17 00:00:00 2001 From: sleepyfran Date: Tue, 9 Jul 2024 00:05:38 +0200 Subject: [PATCH] :children_crossing: Address multi-band inventory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yeah, I know it's funny to address this before we even support multiple bands, but it'll make it easier in the future™️ --- src/Duets.Cli/Components/Effect.fs | 2 +- src/Duets.Entities/Types/Effect.Types.fs | 2 +- src/Duets.Entities/Types/Item.Types.fs | 5 ++--- .../Merchandise/PickUp.Merchandise.fs | 3 ++- .../Merchandise/Sell.Merchandise.fs | 2 +- .../Interactions/Interactions.ConcertSpace.fs | 2 +- .../Interactions/Interactions.RehearsalSpace.fs | 4 +++- src/Duets.Simulation/Queries/Inventory.fs | 12 +++++++++--- src/Duets.Simulation/State/Inventory.fs | 16 ++++++++++------ src/Duets.Simulation/State/State.fs | 8 ++++---- .../Merchandise/PickUp.Merchandise.Tests.fs | 2 +- .../Merchandise/Sell.Merchandise.Tests.fs | 12 ++++++------ .../State/State.Inventory.Tests.fs | 10 +++++----- .../Simulation.Tests/State/State.Merch.Tests.fs | 4 ++-- 14 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/Duets.Cli/Components/Effect.fs b/src/Duets.Cli/Components/Effect.fs index aeae36c9..d65d5de7 100644 --- a/src/Duets.Cli/Components/Effect.fs +++ b/src/Duets.Cli/Components/Effect.fs @@ -134,7 +134,7 @@ let private displayEffect effect = |> showMessage | ItemAddedToCharacterInventory item -> Items.itemAddedCharacterToInventory item |> showMessage - | ItemAddedToBandInventory(item, quantity) -> + | ItemAddedToBandInventory(_, item, quantity) -> Items.itemAddedToBandInventory item quantity |> showMessage | ItemRemovedFromCharacterInventory item -> Items.itemRemovedFromCharacterInventory item |> showMessage diff --git a/src/Duets.Entities/Types/Effect.Types.fs b/src/Duets.Entities/Types/Effect.Types.fs index f1c17c88..af63f675 100644 --- a/src/Duets.Entities/Types/Effect.Types.fs +++ b/src/Duets.Entities/Types/Effect.Types.fs @@ -39,7 +39,7 @@ module EffectTypes = | ItemAddedToCharacterInventory of Item | ItemChangedInCharacterInventory of Diff | ItemRemovedFromCharacterInventory of Item - | ItemAddedToBandInventory of Item * int + | ItemAddedToBandInventory of Band * Item * int | ItemAddedToWorld of RoomCoordinates * Item | ItemChangedInWorld of RoomCoordinates * Diff | ItemRemovedFromWorld of RoomCoordinates * Item diff --git a/src/Duets.Entities/Types/Item.Types.fs b/src/Duets.Entities/Types/Item.Types.fs index aec379c7..982e1f9f 100644 --- a/src/Duets.Entities/Types/Item.Types.fs +++ b/src/Duets.Entities/Types/Item.Types.fs @@ -138,15 +138,14 @@ module rec ItemTypes = /// of that item. This is done mostly to avoid saving thousands of items /// in the savegame, since things like merchandise are not really used /// individually but only sold as a whole. - type BandInventory = - Map> (* TODO: Make it compatible with multiple bands. *) + type BandInventory = Map> /// Defines the character's and band's inventory, where only the character /// one is interactive and the band's only holds items that are needed /// for a certain situation, i.e. merch, etc. type Inventories = { Character: CharacterInventory - Band: BandInventory } + Band: Map } /// Contains all the items that a specific location has. type WorldItems = Map diff --git a/src/Duets.Simulation/Merchandise/PickUp.Merchandise.fs b/src/Duets.Simulation/Merchandise/PickUp.Merchandise.fs index ff30cf33..ad0f3b09 100644 --- a/src/Duets.Simulation/Merchandise/PickUp.Merchandise.fs +++ b/src/Duets.Simulation/Merchandise/PickUp.Merchandise.fs @@ -8,6 +8,7 @@ open Duets.Simulation /// and kept in the world. let pickUpOrder state items = let coords = Queries.World.currentCoordinates state + let currentBand = Queries.Bands.currentBand state items |> List.collect (fun deliveryItem -> @@ -19,6 +20,6 @@ let pickUpOrder state items = match order with | Some(DeliverableItem.Description(merchItem, quantity)) -> - [ ItemAddedToBandInventory(merchItem, quantity) + [ ItemAddedToBandInventory(currentBand, merchItem, quantity) ItemRemovedFromWorld(coords, deliveryItem) ] | _ -> []) diff --git a/src/Duets.Simulation/Merchandise/Sell.Merchandise.fs b/src/Duets.Simulation/Merchandise/Sell.Merchandise.fs index 3b94ebb3..8c6a0454 100644 --- a/src/Duets.Simulation/Merchandise/Sell.Merchandise.fs +++ b/src/Duets.Simulation/Merchandise/Sell.Merchandise.fs @@ -12,7 +12,7 @@ open Duets.Simulation.Bank.Operations /// sale of the merch, or an empty list if no merch was sold or available. let afterConcert (band: Band) performedConcert state = let concert = Concert.fromPast performedConcert - let merch = Queries.Inventory.band state + let merch = Queries.Inventory.band band.Id state let totalPossibleMerchSales = attendantsBuyingMerch performedConcert if Map.isEmpty merch then diff --git a/src/Duets.Simulation/Queries/Interactions/Interactions.ConcertSpace.fs b/src/Duets.Simulation/Queries/Interactions/Interactions.ConcertSpace.fs index 1116ad92..acaf4749 100644 --- a/src/Duets.Simulation/Queries/Interactions/Interactions.ConcertSpace.fs +++ b/src/Duets.Simulation/Queries/Interactions/Interactions.ConcertSpace.fs @@ -16,7 +16,7 @@ module ConcertSpace = let private setupMerchStandInteraction state checklist = let band = Queries.Bands.currentBand state - let merch = Queries.Inventory.band state + let merch = Queries.Inventory.band band.Id state let itemsWithoutPrice = merch diff --git a/src/Duets.Simulation/Queries/Interactions/Interactions.RehearsalSpace.fs b/src/Duets.Simulation/Queries/Interactions/Interactions.RehearsalSpace.fs index 96ac6eea..368e312d 100644 --- a/src/Duets.Simulation/Queries/Interactions/Interactions.RehearsalSpace.fs +++ b/src/Duets.Simulation/Queries/Interactions/Interactions.RehearsalSpace.fs @@ -33,7 +33,9 @@ module RehearsalSpace = let genresWithPopularity = Queries.Genres.allWithPopularity state - let bandInventory = Queries.Inventory.band state |> List.ofMap + let bandInventory = + Queries.Inventory.band currentBand.Id state |> List.ofMap + let hasItemsInInventory = bandInventory |> (not << List.isEmpty) [ yield Interaction.Rehearsal RehearsalInteraction.ComposeNewSong diff --git a/src/Duets.Simulation/Queries/Inventory.fs b/src/Duets.Simulation/Queries/Inventory.fs index 83837350..b5e2cd1c 100644 --- a/src/Duets.Simulation/Queries/Inventory.fs +++ b/src/Duets.Simulation/Queries/Inventory.fs @@ -2,6 +2,7 @@ namespace Duets.Simulation.Queries open Aether open Aether.Operators +open Duets.Common open Duets.Entities module Inventory = @@ -9,6 +10,11 @@ module Inventory = let character = Optic.get (Lenses.State.inventories_ >-> Lenses.Inventories.character_) - /// Returns the content of the band's inventory. - let band = - Optic.get (Lenses.State.inventories_ >-> Lenses.Inventories.band_) + /// Returns the content of a specific band's inventory. + let band id state = + Optic.get + (Lenses.State.inventories_ + >-> Lenses.Inventories.band_ + >-> Map.keyWithDefault_ id Map.empty) + state + |> Option.defaultValue Map.empty diff --git a/src/Duets.Simulation/State/Inventory.fs b/src/Duets.Simulation/State/Inventory.fs index ed9c9543..f0fac37b 100644 --- a/src/Duets.Simulation/State/Inventory.fs +++ b/src/Duets.Simulation/State/Inventory.fs @@ -8,7 +8,10 @@ open Duets.Entities let private charactersLenses = Lenses.State.inventories_ >-> Lenses.Inventories.character_ -let private bandsLenses = Lenses.State.inventories_ >-> Lenses.Inventories.band_ +let private bandsLenses id = + Lenses.State.inventories_ + >-> Lenses.Inventories.band_ + >-> Map.keyWithDefault_ id Map.empty let addToCharacter item = Optic.map charactersLenses (List.append [ item ]) @@ -16,19 +19,20 @@ let addToCharacter item = let removeFromCharacter item = Optic.map charactersLenses (List.removeFirstOccurrenceOf item) -let addToBand item quantity = +let addToBand bandId item quantity = Optic.map - bandsLenses + (bandsLenses bandId) (Map.change item (fun q -> match q with | Some q -> Some(q + quantity) | None -> Some quantity)) -let reduceForBand item quantity = +let reduceForBand bandId item quantity = Optic.map - bandsLenses + (bandsLenses bandId) (Map.change item (function | Some q -> Some(q - quantity) | None -> None)) -let removeFromBand item = Optic.map bandsLenses (Map.remove item) +let removeFromBand bandId item = + Optic.map (bandsLenses bandId) (Map.remove item) diff --git a/src/Duets.Simulation/State/State.fs b/src/Duets.Simulation/State/State.fs index fdb18024..6436e51f 100644 --- a/src/Duets.Simulation/State/State.fs +++ b/src/Duets.Simulation/State/State.fs @@ -73,19 +73,19 @@ let applyEffect state effect = |> Inventory.addToCharacter currItem | ItemRemovedFromCharacterInventory item -> Inventory.removeFromCharacter item state - | ItemAddedToBandInventory(item, quantity) -> - Inventory.addToBand item quantity state + | ItemAddedToBandInventory(band, item, quantity) -> + Inventory.addToBand band.Id item quantity state | ItemAddedToWorld(coords, item) -> World.add coords item state | ItemChangedInWorld(coords, Diff(prevItem, currItem)) -> World.remove coords prevItem state |> World.add coords currItem | ItemRemovedFromWorld(coords, item) -> World.remove coords item state | MerchPriceSet(band, merch, price) -> Merch.setPrice band.Id merch price state - | MerchSold(_, items, _) -> + | MerchSold(band, items, _) -> items |> List.fold (fun state (item, quantity) -> - Inventory.reduceForBand item quantity state) + Inventory.reduceForBand band.Id item quantity state) state | MemberHired(band, character, currentMember, skills) -> let stateWithMember = diff --git a/tests/Simulation.Tests/Merchandise/PickUp.Merchandise.Tests.fs b/tests/Simulation.Tests/Merchandise/PickUp.Merchandise.Tests.fs index 19d038ea..a186f678 100644 --- a/tests/Simulation.Tests/Merchandise/PickUp.Merchandise.Tests.fs +++ b/tests/Simulation.Tests/Merchandise/PickUp.Merchandise.Tests.fs @@ -33,7 +33,7 @@ let ``pick-up ignores non-deliverable items`` () = let ``pick-up adds the merch to the band inventory`` () = pickUpOrder dummyState [ deliverable ] |> List.filter (function - | ItemAddedToBandInventory(item, quantity) -> + | ItemAddedToBandInventory(_, item, quantity) -> item = dummyMerch && quantity = 100 | _ -> false) |> should haveLength 1 diff --git a/tests/Simulation.Tests/Merchandise/Sell.Merchandise.Tests.fs b/tests/Simulation.Tests/Merchandise/Sell.Merchandise.Tests.fs index 81aa371f..de68da79 100644 --- a/tests/Simulation.Tests/Merchandise/Sell.Merchandise.Tests.fs +++ b/tests/Simulation.Tests/Merchandise/Sell.Merchandise.Tests.fs @@ -28,8 +28,8 @@ let stateWithMerch = dummyState |> State.Merch.setPrice dummyBand.Id dummyVinylMerch 15m
|> State.Merch.setPrice dummyBand.Id dummyTShirtMerch 15m
- |> State.Inventory.addToBand dummyTShirtMerch 200 - |> State.Inventory.addToBand dummyVinylMerch 150 + |> State.Inventory.addToBand dummyBand.Id dummyTShirtMerch 200 + |> State.Inventory.addToBand dummyBand.Id dummyVinylMerch 150 [] let ``Sell.afterConcert does nothing if band has no merch`` () = @@ -102,7 +102,7 @@ let ``Sell.afterConcert limits the sales to the stock of merch the band has`` let state = dummyState |> State.Merch.setPrice dummyBand.Id dummyVinylMerch 15m
- |> State.Inventory.addToBand dummyVinylMerch 100 + |> State.Inventory.addToBand dummyBand.Id dummyVinylMerch 100 checkExpectedSales state headlinerConcert 99 100 @@ -117,7 +117,7 @@ let ``Sell.afterConcert reduces the sales to 50% if price is more than recommend let stateWithOverpricedMerch = dummyState |> State.Merch.setPrice dummyBand.Id dummyTShirtMerch 16m
- |> State.Inventory.addToBand dummyTShirtMerch 200 + |> State.Inventory.addToBand dummyBand.Id dummyTShirtMerch 200 checkExpectedSales stateWithOverpricedMerch headlinerConcert 99 100 @@ -128,7 +128,7 @@ let ``Sell.afterConcert reduces the sales to 10% if price is more than 10% of th let stateWithOverpricedMerch = dummyState |> State.Merch.setPrice dummyBand.Id dummyTShirtMerch 21m
- |> State.Inventory.addToBand dummyTShirtMerch 200 + |> State.Inventory.addToBand dummyBand.Id dummyTShirtMerch 200 checkExpectedSales stateWithOverpricedMerch headlinerConcert 99 20 @@ -139,7 +139,7 @@ let ``Sell.afterConcert sells nothing if price is more than than 50% of the reco let stateWithOverpricedMerch = dummyState |> State.Merch.setPrice dummyBand.Id dummyTShirtMerch 25m
- |> State.Inventory.addToBand dummyTShirtMerch 200 + |> State.Inventory.addToBand dummyBand.Id dummyTShirtMerch 200 checkExpectedSales stateWithOverpricedMerch headlinerConcert 99 0 diff --git a/tests/Simulation.Tests/State/State.Inventory.Tests.fs b/tests/Simulation.Tests/State/State.Inventory.Tests.fs index 193b4c10..4bb2fc61 100644 --- a/tests/Simulation.Tests/State/State.Inventory.Tests.fs +++ b/tests/Simulation.Tests/State/State.Inventory.Tests.fs @@ -15,10 +15,10 @@ let private dummyMerch = [] let ``ItemAddedToBandInventory adds the item to the inventory`` () = let state = - ItemAddedToBandInventory(dummyMerch, 200) + ItemAddedToBandInventory(dummyBand, dummyMerch, 200) |> State.Root.applyEffect dummyState - Queries.Inventory.band state + Queries.Inventory.band dummyBand.Id state |> Map.find dummyMerch |> should equal 200 @@ -27,13 +27,13 @@ let ``ItemAddedToInventory sums the new quantity to the previous if the item was () = let state = - ItemAddedToBandInventory(dummyMerch, 200) + ItemAddedToBandInventory(dummyBand, dummyMerch, 200) |> State.Root.applyEffect dummyState let state = - ItemAddedToBandInventory(dummyMerch, 100) + ItemAddedToBandInventory(dummyBand, dummyMerch, 100) |> State.Root.applyEffect state - Queries.Inventory.band state + Queries.Inventory.band dummyBand.Id state |> Map.find dummyMerch |> should equal 300 diff --git a/tests/Simulation.Tests/State/State.Merch.Tests.fs b/tests/Simulation.Tests/State/State.Merch.Tests.fs index 22131862..c44b93dd 100644 --- a/tests/Simulation.Tests/State/State.Merch.Tests.fs +++ b/tests/Simulation.Tests/State/State.Merch.Tests.fs @@ -15,13 +15,13 @@ let private dummyMerch = [] let ``MerchSold updates the band inventory removing the sold items`` () = let state = - ItemAddedToBandInventory(dummyMerch, 200) + ItemAddedToBandInventory(dummyBand, dummyMerch, 200) |> State.Root.applyEffect dummyState let state = MerchSold(dummyBand, [ dummyMerch, 91 ], 200m
) |> State.Root.applyEffect state - Queries.Inventory.band state + Queries.Inventory.band dummyBand.Id state |> Map.find dummyMerch |> should equal 109