feat(xanthous): Allow selecting hand for wielding
When wielding items, allow selecting which hand the item should be wielded in. Currently this has no actual effect on the mechanics of combat - that'll come next. Change-Id: Ic289ca2d8fa6f5fc0ad5bd0b012818a3acd8599e Reviewed-on: https://cl.tvl.fyi/c/depot/+/5470 Reviewed-by: grfn <grfn@gws.fyi> Autosubmit: grfn <grfn@gws.fyi> Tested-by: BuildkiteCI
This commit is contained in:
parent
8da2fce9ef
commit
632c4280b5
4 changed files with 119 additions and 30 deletions
|
@ -54,12 +54,12 @@ import Xanthous.Physics (throwDistance, bluntThrowDamage)
|
||||||
import Xanthous.Data.EntityMap.Graphics (lineOfSight)
|
import Xanthous.Data.EntityMap.Graphics (lineOfSight)
|
||||||
import Xanthous.Data.EntityMap (EntityID)
|
import Xanthous.Data.EntityMap (EntityID)
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
import Xanthous.Entities.Common
|
import Xanthous.Entities.Common
|
||||||
( InventoryPosition, describeInventoryPosition, backpack
|
( InventoryPosition, describeInventoryPosition, backpack
|
||||||
, wieldableItem, wieldedItems, wielded, itemsWithPosition
|
, wieldableItem, wieldedItems, wielded, itemsWithPosition
|
||||||
, removeItemFromPosition, asWieldedItem, inRightHand
|
, removeItemFromPosition, asWieldedItem
|
||||||
, wieldedItem, items
|
, wieldedItem, items, Hand (..), describeHand, wieldInHand
|
||||||
|
, WieldedItem
|
||||||
)
|
)
|
||||||
import qualified Xanthous.Entities.Character as Character
|
import qualified Xanthous.Entities.Character as Character
|
||||||
import Xanthous.Entities.Character hiding (pickUpItem)
|
import Xanthous.Entities.Character hiding (pickUpItem)
|
||||||
|
@ -296,14 +296,30 @@ handleCommand DescribeInventory = do
|
||||||
|
|
||||||
|
|
||||||
handleCommand Wield = do
|
handleCommand Wield = do
|
||||||
takeItemFromInventory_ ["wield", "menu"] Cancellable asWieldedItem
|
selectItem $ \(MenuResult (item :: WieldedItem)) -> do
|
||||||
(say_ ["wield", "nothing"])
|
selectHand $ \(MenuResult hand) -> do
|
||||||
$ \(MenuResult item) -> do
|
prevItems <- character . inventory . wielded %%= wieldInHand hand item
|
||||||
prevItems <- character . inventory . wielded <<.= inRightHand item
|
|
||||||
character . inventory . backpack
|
character . inventory . backpack
|
||||||
<>= fromList (prevItems ^.. wieldedItems . wieldedItem)
|
<>= fromList (map (view wieldedItem) prevItems)
|
||||||
say ["wield", "wielded"] item
|
say ["wield", "wielded"] $ object [ "item" A..= item
|
||||||
|
, "hand" A..= describeHand hand
|
||||||
|
]
|
||||||
continue
|
continue
|
||||||
|
where
|
||||||
|
selectItem =
|
||||||
|
takeItemFromInventory_ ["wield", "menu"] Cancellable asWieldedItem
|
||||||
|
(say_ ["wield", "nothing"])
|
||||||
|
selectHand
|
||||||
|
= menu_
|
||||||
|
["wield", "hand"]
|
||||||
|
Cancellable
|
||||||
|
handsMenu
|
||||||
|
handsMenu = mapFromList
|
||||||
|
. map (second $ MenuOption =<< describeHand)
|
||||||
|
$ [ ('l', LeftHand)
|
||||||
|
, ('r', RightHand)
|
||||||
|
, ('b', BothHands)
|
||||||
|
]
|
||||||
|
|
||||||
handleCommand Fire = do
|
handleCommand Fire = do
|
||||||
selectItemFromInventory_ ["fire", "menu"] Cancellable id
|
selectItemFromInventory_ ["fire", "menu"] Cancellable id
|
||||||
|
|
|
@ -20,12 +20,18 @@ module Xanthous.Entities.Common
|
||||||
|
|
||||||
-- ** Wielded items
|
-- ** Wielded items
|
||||||
, Wielded(..)
|
, Wielded(..)
|
||||||
|
, nothingWielded
|
||||||
, hands
|
, hands
|
||||||
, leftHand
|
, leftHand
|
||||||
, rightHand
|
, rightHand
|
||||||
, inLeftHand
|
, inLeftHand
|
||||||
, inRightHand
|
, inRightHand
|
||||||
, doubleHanded
|
, doubleHanded
|
||||||
|
, Hand(..)
|
||||||
|
, itemsInHand
|
||||||
|
, inHand
|
||||||
|
, wieldInHand
|
||||||
|
, describeHand
|
||||||
, wieldedItems
|
, wieldedItems
|
||||||
, WieldedItem(..)
|
, WieldedItem(..)
|
||||||
, wieldedItem
|
, wieldedItem
|
||||||
|
@ -95,6 +101,7 @@ data Wielded
|
||||||
via WithOptions '[ 'SumEnc 'ObjWithSingleField ]
|
via WithOptions '[ 'SumEnc 'ObjWithSingleField ]
|
||||||
Wielded
|
Wielded
|
||||||
|
|
||||||
|
|
||||||
nothingWielded :: Wielded
|
nothingWielded :: Wielded
|
||||||
nothingWielded = Hands Nothing Nothing
|
nothingWielded = Hands Nothing Nothing
|
||||||
|
|
||||||
|
@ -124,6 +131,43 @@ wieldedItems :: Traversal' Wielded WieldedItem
|
||||||
wieldedItems k (DoubleHanded wielded) = DoubleHanded <$> k wielded
|
wieldedItems k (DoubleHanded wielded) = DoubleHanded <$> k wielded
|
||||||
wieldedItems k (Hands l r) = Hands <$> _Just k l <*> _Just k r
|
wieldedItems k (Hands l r) = Hands <$> _Just k l <*> _Just k r
|
||||||
|
|
||||||
|
|
||||||
|
data Hand
|
||||||
|
= LeftHand
|
||||||
|
| RightHand
|
||||||
|
| BothHands
|
||||||
|
deriving stock (Eq, Show, Ord, Generic)
|
||||||
|
deriving anyclass (NFData, CoArbitrary, Function)
|
||||||
|
deriving Arbitrary via GenericArbitrary Hand
|
||||||
|
|
||||||
|
itemsInHand :: Hand -> Wielded -> [WieldedItem]
|
||||||
|
itemsInHand LeftHand (DoubleHanded wi) = [wi]
|
||||||
|
itemsInHand LeftHand (Hands lh _) = toList lh
|
||||||
|
itemsInHand RightHand (DoubleHanded wi) = [wi]
|
||||||
|
itemsInHand RightHand (Hands _ rh) = toList rh
|
||||||
|
itemsInHand BothHands (DoubleHanded wi) = [wi]
|
||||||
|
itemsInHand BothHands (Hands lh rh) = toList lh <> toList rh
|
||||||
|
|
||||||
|
inHand :: Hand -> WieldedItem -> Wielded
|
||||||
|
inHand LeftHand = inLeftHand
|
||||||
|
inHand RightHand = inRightHand
|
||||||
|
inHand BothHands = review doubleHanded
|
||||||
|
|
||||||
|
wieldInHand :: Hand -> WieldedItem -> Wielded -> ([WieldedItem], Wielded)
|
||||||
|
wieldInHand hand item w = (itemsInHand hand w, doWield)
|
||||||
|
where
|
||||||
|
doWield = case (hand, w) of
|
||||||
|
(LeftHand, Hands _ r) -> Hands (Just item) r
|
||||||
|
(LeftHand, DoubleHanded _) -> inLeftHand item
|
||||||
|
(RightHand, Hands l _) -> Hands l (Just item)
|
||||||
|
(RightHand, DoubleHanded _) -> inRightHand item
|
||||||
|
(BothHands, _) -> DoubleHanded item
|
||||||
|
|
||||||
|
describeHand :: Hand -> Text
|
||||||
|
describeHand LeftHand = "your left hand"
|
||||||
|
describeHand RightHand = "your right hand"
|
||||||
|
describeHand BothHands = "both hands"
|
||||||
|
|
||||||
data Inventory = Inventory
|
data Inventory = Inventory
|
||||||
{ _backpack :: Vector Item
|
{ _backpack :: Vector Item
|
||||||
, _wielded :: Wielded
|
, _wielded :: Wielded
|
||||||
|
@ -199,27 +243,23 @@ class HasInventory s a | s -> a where
|
||||||
-- | Representation for where in the inventory an item might be
|
-- | Representation for where in the inventory an item might be
|
||||||
data InventoryPosition
|
data InventoryPosition
|
||||||
= Backpack
|
= Backpack
|
||||||
| LeftHand
|
| InHand Hand
|
||||||
| RightHand
|
|
||||||
| BothHands
|
|
||||||
deriving stock (Eq, Show, Ord, Generic)
|
deriving stock (Eq, Show, Ord, Generic)
|
||||||
deriving anyclass (NFData, CoArbitrary, Function)
|
deriving anyclass (NFData, CoArbitrary, Function)
|
||||||
deriving Arbitrary via GenericArbitrary InventoryPosition
|
deriving Arbitrary via GenericArbitrary InventoryPosition
|
||||||
|
|
||||||
-- | Return a human-readable description of the given 'InventoryPosition'
|
-- | Return a human-readable description of the given 'InventoryPosition'
|
||||||
describeInventoryPosition :: InventoryPosition -> Text
|
describeInventoryPosition :: InventoryPosition -> Text
|
||||||
describeInventoryPosition Backpack = "In backpack"
|
describeInventoryPosition Backpack = "In backpack"
|
||||||
describeInventoryPosition LeftHand = "Wielded, in left hand"
|
describeInventoryPosition (InHand hand) = "Wielded, in " <> describeHand hand
|
||||||
describeInventoryPosition RightHand = "Wielded, in right hand"
|
|
||||||
describeInventoryPosition BothHands = "Wielded, in both hands"
|
|
||||||
|
|
||||||
-- | Given a position in the inventory, return a traversal on the inventory over
|
-- | Given a position in the inventory, return a traversal on the inventory over
|
||||||
-- all the items in that position
|
-- all the items in that position
|
||||||
inventoryPosition :: InventoryPosition -> Traversal' Inventory Item
|
inventoryPosition :: InventoryPosition -> Traversal' Inventory Item
|
||||||
inventoryPosition Backpack = backpack . traversed
|
inventoryPosition Backpack = backpack . traversed
|
||||||
inventoryPosition LeftHand = wielded . leftHand . _Just . wieldedItem
|
inventoryPosition (InHand LeftHand) = wielded . leftHand . _Just . wieldedItem
|
||||||
inventoryPosition RightHand = wielded . leftHand . _Just . wieldedItem
|
inventoryPosition (InHand RightHand) = wielded . leftHand . _Just . wieldedItem
|
||||||
inventoryPosition BothHands = wielded . doubleHanded . wieldedItem
|
inventoryPosition (InHand BothHands) = wielded . doubleHanded . wieldedItem
|
||||||
|
|
||||||
-- | A fold over all the items in the inventory accompanied by their position in
|
-- | A fold over all the items in the inventory accompanied by their position in
|
||||||
-- the inventory
|
-- the inventory
|
||||||
|
@ -230,20 +270,20 @@ itemsWithPosition = folding $ (<>) <$> backpackItems <*> handItems
|
||||||
where
|
where
|
||||||
backpackItems = toListOf $ backpack . folded . to (Backpack ,)
|
backpackItems = toListOf $ backpack . folded . to (Backpack ,)
|
||||||
handItems inv = case inv ^. wielded of
|
handItems inv = case inv ^. wielded of
|
||||||
DoubleHanded i -> pure (BothHands, i ^. wieldedItem)
|
DoubleHanded i -> pure (InHand BothHands, i ^. wieldedItem)
|
||||||
Hands l r -> (l ^.. folded . wieldedItem . to (LeftHand ,))
|
Hands l r -> (l ^.. folded . wieldedItem . to (InHand LeftHand ,))
|
||||||
<> (r ^.. folded . wieldedItem . to (RightHand ,))
|
<> (r ^.. folded . wieldedItem . to (InHand RightHand ,))
|
||||||
|
|
||||||
-- | Remove the first item equal to 'Item' from the given position in the
|
-- | Remove the first item equal to 'Item' from the given position in the
|
||||||
-- inventory
|
-- inventory
|
||||||
removeItemFromPosition :: InventoryPosition -> Item -> Inventory -> Inventory
|
removeItemFromPosition :: InventoryPosition -> Item -> Inventory -> Inventory
|
||||||
removeItemFromPosition Backpack item inv
|
removeItemFromPosition Backpack item inv
|
||||||
= inv & backpack %~ removeFirst (== item)
|
= inv & backpack %~ removeFirst (== item)
|
||||||
removeItemFromPosition LeftHand item inv
|
removeItemFromPosition (InHand LeftHand) item inv
|
||||||
= inv & wielded . leftHand %~ filter ((/= item) . view wieldedItem)
|
= inv & wielded . leftHand %~ filter ((/= item) . view wieldedItem)
|
||||||
removeItemFromPosition RightHand item inv
|
removeItemFromPosition (InHand RightHand) item inv
|
||||||
= inv & wielded . rightHand %~ filter ((/= item) . view wieldedItem)
|
= inv & wielded . rightHand %~ filter ((/= item) . view wieldedItem)
|
||||||
removeItemFromPosition BothHands item inv
|
removeItemFromPosition (InHand BothHands) item inv
|
||||||
| has (wielded . doubleHanded . wieldedItem . filtered (== item)) inv
|
| has (wielded . doubleHanded . wieldedItem . filtered (== item)) inv
|
||||||
= inv & wielded .~ nothingWielded
|
= inv & wielded .~ nothingWielded
|
||||||
| otherwise
|
| otherwise
|
||||||
|
|
|
@ -115,8 +115,8 @@ wield:
|
||||||
- You can't wield anything in your backpack
|
- You can't wield anything in your backpack
|
||||||
- You can't wield anything currently in your backpack
|
- You can't wield anything currently in your backpack
|
||||||
menu: What would you like to wield?
|
menu: What would you like to wield?
|
||||||
# TODO: use actual hands
|
hand: Wield in which hand?
|
||||||
wielded : You wield the {{wieldedItem.itemType.name}} in your right hand.
|
wielded: You wield the {{item.wieldedItem.itemType.name}} in {{hand}}
|
||||||
|
|
||||||
fire:
|
fire:
|
||||||
nothing:
|
nothing:
|
||||||
|
|
|
@ -10,6 +10,17 @@ import Xanthous.Entities.Common
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = defaultMain test
|
main = defaultMain test
|
||||||
|
|
||||||
|
newtype OneHand = OneHand Hand
|
||||||
|
deriving stock Show
|
||||||
|
|
||||||
|
instance Arbitrary OneHand where
|
||||||
|
arbitrary = OneHand <$> elements [LeftHand, RightHand]
|
||||||
|
|
||||||
|
otherHand :: Hand -> Hand
|
||||||
|
otherHand LeftHand = RightHand
|
||||||
|
otherHand RightHand = LeftHand
|
||||||
|
otherHand BothHands = error "OtherHand BothHands"
|
||||||
|
|
||||||
test :: TestTree
|
test :: TestTree
|
||||||
test = testGroup "Xanthous.Entities.CommonSpec"
|
test = testGroup "Xanthous.Entities.CommonSpec"
|
||||||
[ testGroup "Inventory"
|
[ testGroup "Inventory"
|
||||||
|
@ -20,13 +31,35 @@ test = testGroup "Xanthous.Entities.CommonSpec"
|
||||||
let (old, inv') = inv & wielded <<.~ w
|
let (old, inv') = inv & wielded <<.~ w
|
||||||
in inv' & backpack <>~ toVectorOf (wieldedItems . wieldedItem) old
|
in inv' & backpack <>~ toVectorOf (wieldedItems . wieldedItem) old
|
||||||
in [ (Backpack, \item -> backpack %~ (item ^. wieldedItem <|))
|
in [ (Backpack, \item -> backpack %~ (item ^. wieldedItem <|))
|
||||||
, (LeftHand, rewield . inLeftHand)
|
, (InHand LeftHand, rewield . inLeftHand)
|
||||||
, (RightHand, rewield . inRightHand)
|
, (InHand RightHand, rewield . inRightHand)
|
||||||
, (BothHands, rewield . review doubleHanded)
|
, (InHand BothHands, rewield . review doubleHanded)
|
||||||
] <&> \(pos, addItem) ->
|
] <&> \(pos, addItem) ->
|
||||||
testProperty (show pos) $ \inv item ->
|
testProperty (show pos) $ \inv item ->
|
||||||
let inv' = addItem item inv
|
let inv' = addItem item inv
|
||||||
inv'' = removeItemFromPosition pos (item ^. wieldedItem) inv'
|
inv'' = removeItemFromPosition pos (item ^. wieldedItem) inv'
|
||||||
in inv'' ^.. items === inv ^.. items
|
in inv'' ^.. items === inv ^.. items
|
||||||
]
|
]
|
||||||
|
, testGroup "Wielded items"
|
||||||
|
[ testGroup "wieldInHand"
|
||||||
|
[ testProperty "puts the item in the hand" $ \w hand item ->
|
||||||
|
let (_, w') = wieldInHand hand item w
|
||||||
|
in itemsInHand hand w' === [item]
|
||||||
|
, testProperty "returns items in both hands when wielding double-handed"
|
||||||
|
$ \lh rh newItem ->
|
||||||
|
let w = Hands (Just lh) (Just rh)
|
||||||
|
(prevItems, _) = wieldInHand BothHands newItem w
|
||||||
|
in prevItems === [lh, rh]
|
||||||
|
, testProperty "wielding in one hand leaves the item in the other hand"
|
||||||
|
$ \(OneHand h) existingItem newItem ->
|
||||||
|
let (_, w) = wieldInHand h existingItem nothingWielded
|
||||||
|
(prevItems, w') = wieldInHand (otherHand h) newItem w
|
||||||
|
in prevItems === []
|
||||||
|
.&&. sort (w' ^.. wieldedItems) === sort [existingItem, newItem]
|
||||||
|
, testProperty "always leaves the same items overall" $ \w hand item ->
|
||||||
|
let (prevItems, w') = wieldInHand hand item w
|
||||||
|
in sort (prevItems <> (w' ^.. wieldedItems))
|
||||||
|
=== sort (item : w ^.. wieldedItems)
|
||||||
|
]
|
||||||
|
]
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue