Skip to content

Commit

Permalink
🚸 Address multi-band inventory
Browse files Browse the repository at this point in the history
Yeah, I know it's funny to address this before we even support multiple bands, but it'll make it easier in the future™️
  • Loading branch information
sleepyfran committed Jul 8, 2024
1 parent 4898aa8 commit 5a18af1
Show file tree
Hide file tree
Showing 14 changed files with 48 additions and 36 deletions.
2 changes: 1 addition & 1 deletion src/Duets.Cli/Components/Effect.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/Duets.Entities/Types/Effect.Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module EffectTypes =
| ItemAddedToCharacterInventory of Item
| ItemChangedInCharacterInventory of Diff<Item>
| ItemRemovedFromCharacterInventory of Item
| ItemAddedToBandInventory of Item * int<quantity>
| ItemAddedToBandInventory of Band * Item * int<quantity>
| ItemAddedToWorld of RoomCoordinates * Item
| ItemChangedInWorld of RoomCoordinates * Diff<Item>
| ItemRemovedFromWorld of RoomCoordinates * Item
Expand Down
5 changes: 2 additions & 3 deletions src/Duets.Entities/Types/Item.Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Item, int<quantity>> (* TODO: Make it compatible with multiple bands. *)
type BandInventory = Map<Item, int<quantity>>

/// 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<BandId, BandInventory> }

/// Contains all the items that a specific location has.
type WorldItems = Map<RoomCoordinates, Item list>
3 changes: 2 additions & 1 deletion src/Duets.Simulation/Merchandise/PickUp.Merchandise.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand All @@ -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) ]
| _ -> [])
2 changes: 1 addition & 1 deletion src/Duets.Simulation/Merchandise/Sell.Merchandise.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 9 additions & 3 deletions src/Duets.Simulation/Queries/Inventory.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ namespace Duets.Simulation.Queries

open Aether
open Aether.Operators
open Duets.Common
open Duets.Entities

module Inventory =
/// Returns the content of the character's 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
16 changes: 10 additions & 6 deletions src/Duets.Simulation/State/Inventory.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,31 @@ 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 ])

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)
8 changes: 4 additions & 4 deletions src/Duets.Simulation/State/State.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<quantity>
| _ -> false)
|> should haveLength 1
Expand Down
12 changes: 6 additions & 6 deletions tests/Simulation.Tests/Merchandise/Sell.Merchandise.Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ let stateWithMerch =
dummyState
|> State.Merch.setPrice dummyBand.Id dummyVinylMerch 15m<dd>
|> State.Merch.setPrice dummyBand.Id dummyTShirtMerch 15m<dd>
|> State.Inventory.addToBand dummyTShirtMerch 200<quantity>
|> State.Inventory.addToBand dummyVinylMerch 150<quantity>
|> State.Inventory.addToBand dummyBand.Id dummyTShirtMerch 200<quantity>
|> State.Inventory.addToBand dummyBand.Id dummyVinylMerch 150<quantity>

[<Test>]
let ``Sell.afterConcert does nothing if band has no merch`` () =
Expand Down Expand Up @@ -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<dd>
|> State.Inventory.addToBand dummyVinylMerch 100<quantity>
|> State.Inventory.addToBand dummyBand.Id dummyVinylMerch 100<quantity>

checkExpectedSales state headlinerConcert 99<quality> 100

Expand All @@ -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<dd>
|> State.Inventory.addToBand dummyTShirtMerch 200<quantity>
|> State.Inventory.addToBand dummyBand.Id dummyTShirtMerch 200<quantity>

checkExpectedSales stateWithOverpricedMerch headlinerConcert 99<quality> 100

Expand All @@ -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<dd>
|> State.Inventory.addToBand dummyTShirtMerch 200<quantity>
|> State.Inventory.addToBand dummyBand.Id dummyTShirtMerch 200<quantity>

checkExpectedSales stateWithOverpricedMerch headlinerConcert 99<quality> 20

Expand All @@ -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<dd>
|> State.Inventory.addToBand dummyTShirtMerch 200<quantity>
|> State.Inventory.addToBand dummyBand.Id dummyTShirtMerch 200<quantity>

checkExpectedSales stateWithOverpricedMerch headlinerConcert 99<quality> 0

Expand Down
10 changes: 5 additions & 5 deletions tests/Simulation.Tests/State/State.Inventory.Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ let private dummyMerch =
[<Test>]
let ``ItemAddedToBandInventory adds the item to the inventory`` () =
let state =
ItemAddedToBandInventory(dummyMerch, 200<quantity>)
ItemAddedToBandInventory(dummyBand, dummyMerch, 200<quantity>)
|> State.Root.applyEffect dummyState

Queries.Inventory.band state
Queries.Inventory.band dummyBand.Id state
|> Map.find dummyMerch
|> should equal 200<quantity>

Expand All @@ -27,13 +27,13 @@ let ``ItemAddedToInventory sums the new quantity to the previous if the item was
()
=
let state =
ItemAddedToBandInventory(dummyMerch, 200<quantity>)
ItemAddedToBandInventory(dummyBand, dummyMerch, 200<quantity>)
|> State.Root.applyEffect dummyState

let state =
ItemAddedToBandInventory(dummyMerch, 100<quantity>)
ItemAddedToBandInventory(dummyBand, dummyMerch, 100<quantity>)
|> State.Root.applyEffect state

Queries.Inventory.band state
Queries.Inventory.band dummyBand.Id state
|> Map.find dummyMerch
|> should equal 300<quantity>
4 changes: 2 additions & 2 deletions tests/Simulation.Tests/State/State.Merch.Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ let private dummyMerch =
[<Test>]
let ``MerchSold updates the band inventory removing the sold items`` () =
let state =
ItemAddedToBandInventory(dummyMerch, 200<quantity>)
ItemAddedToBandInventory(dummyBand, dummyMerch, 200<quantity>)
|> State.Root.applyEffect dummyState

let state =
MerchSold(dummyBand, [ dummyMerch, 91<quantity> ], 200m<dd>)
|> State.Root.applyEffect state

Queries.Inventory.band state
Queries.Inventory.band dummyBand.Id state
|> Map.find dummyMerch
|> should equal 109<quantity>

0 comments on commit 5a18af1

Please sign in to comment.