diff --git a/src/ConsoleUI.hs b/src/ConsoleUI.hs index 454116e..52c88c1 100755 --- a/src/ConsoleUI.hs +++ b/src/ConsoleUI.hs @@ -23,6 +23,7 @@ import System.Random import System.Random.Shuffle import Text.Printf import Waterdeep.Actions +import Waterdeep.Buildings import Waterdeep.Logic import Waterdeep.Quests import Waterdeep.Types @@ -47,41 +48,6 @@ f2 = Faction "Pilots" Green l2 = Lord "Princess Anastasia" "" (QuestBonus [Arcana, Warfare] 4) p2 = ("Ned", f2, l2) -b1 = Building { _buildingCost = 6 - , _buildingTitle = "Monastary" - , _buildingAction = takeResources 2 [Cleric] - , _buildingOwnerAction = takeResources 1 [Cleric] - , _buildingAccumType = NoAccumulation - } - -b2 = Building { _buildingCost = 4 - , _buildingTitle = "Training Hall" - , _buildingAction = takeResources 2 [Fighter] - , _buildingOwnerAction = takeResources 1 [Fighter] - , _buildingAccumType = NoAccumulation - } - -b3 = Building { _buildingCost = 4 - , _buildingTitle = "Prison Yard" - , _buildingAction = takeResources 2 [Rogue] - , _buildingOwnerAction = takeResources 1 [Rogue] - , _buildingAccumType = NoAccumulation - } - -b4 = Building { _buildingCost = 6 - , _buildingTitle = "Wizard School" - , _buildingAction = takeResources 2 [Wizard] - , _buildingOwnerAction = takeResources 1 [Wizard] - , _buildingAccumType = NoAccumulation - } - -b5 = Building { _buildingCost = 4 - , _buildingTitle = "Gold Mine" - , _buildingAction = takeResources 4 [Gold] - , _buildingOwnerAction = takeResources 2 [Gold] - , _buildingAccumType = NoAccumulation - } - i1 = IntrigueCard { _intrigueTitle = "Graduation Day" , _intrigueType = Utility , _intrigueAction = do @@ -197,8 +163,7 @@ printMenu cs = do main :: IO () main = do - w0 <- newGame [p1, p2] defaultQuestDeck (mrepeat 4 [i1, i2]) [b1, b2, b3, b4, b5] <$> getSplit + w0 <- newGame [p1, p2] defaultQuestDeck (mrepeat 4 [i1, i2]) defaultBuildingDeck <$> getSplit ref <- newIORef (DisplayState { _gameState = w0, _gameMessages = [] }) - Just (winners, w') <- runWaterdeepM (menuPrompt ref (drawState ref)) waterdeepGame w0 - let playerIDToName n = w0 ^. gamePlayerName n - putStrLn ("Winner(s): " ++ intercalate ", " (winners ^.. traverse . to playerIDToName)) + runWaterdeepM (menuPrompt ref (drawState ref)) waterdeepGame w0 + return () diff --git a/src/Waterdeep/Buildings.hs b/src/Waterdeep/Buildings.hs new file mode 100644 index 0000000..4a29171 --- /dev/null +++ b/src/Waterdeep/Buildings.hs @@ -0,0 +1,214 @@ +module Waterdeep.Buildings + ( basicBuildings + , defaultBuildingDeck + ) where + +import Control.Applicative +import Control.Monad +import Data.List +import Data.Monoid +import Data.Traversable (traverse) +import Lens.Family2 +import Lens.Family2.Stock +import Lens.Family2.State +import Lens.Family2.TH +import Waterdeep.Actions +import Waterdeep.Types +import Waterdeep.Util + +import qualified Data.IntMap as IM +import qualified Data.Map as M +import qualified Data.MultiSet as MS + +basicBuildings :: [Building] +basicBuildings = + [ basicBuilding "Aurora's Realms Shop" (takeResources 4 [Gold]) + , basicBuilding "Blackstaff Tower" (takeResources 1 [Wizard]) + , basicBuilding "Builder's Hall" buyBuilding + , basicBuilding "Castle Waterdeep" (becomeFirstPlayer >> drawIntrigue) + , basicBuilding "Field of Triumph" (takeResources 2 [Fighter]) + , basicBuilding "The Grinning Lion Tavern" (takeResources 2 [Rogue]) + , basicBuilding "The Plinth" (takeResources 1 [Cleric]) + , basicBuilding "Cliffwatch Inn (2 Gold)" (chooseQuest >> takeResources 2 [Gold]) + , basicBuilding "Cliffwatch Inn (Intrigue)" (chooseQuest >> drawIntrigue) + , basicBuilding "Cliffwatch Inn (Reset)" (replaceQuests >> chooseQuest) + ] + +basicBuilding :: String -> GameAction -> Building +basicBuilding title action = + Building + { _buildingCost = 0 + , _buildingTitle = title + , _buildingAction = action + , _buildingOwnerAction = noAction + , _buildingAccumType = NoAccumulation + } + +defaultBuildingDeck :: [Building] +defaultBuildingDeck = + [ Building { _buildingCost = 4 + , _buildingTitle = "The Palace of Waterdeep" + , _buildingAction = gainAmbassador + , _buildingOwnerAction = scorePoints 2 + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 4 + , _buildingTitle = "Heroes' Garden" + , _buildingAction = chooseAndCompleteQuest $ scorePoints 4 + , _buildingOwnerAction = scorePoints 2 + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 4 + , _buildingTitle = "The Golden Horn" + , _buildingAction = noAction + , _buildingOwnerAction = takeResources 2 [Gold] + , _buildingAccumType = AccumulateResource Gold 4 + } + , Building { _buildingCost = 4 + , _buildingTitle = "The Waymoot" + , _buildingAction = chooseQuest + , _buildingOwnerAction = scorePoints 2 + , _buildingAccumType = AccumulatePoints 3 + } + , Building { _buildingCost = 3 + , _buildingTitle = "House of Good Spirits" + , _buildingAction = do + takeResources 1 [Fighter] + takeResources 1 [Cleric, Fighter, Rogue, Wizard] + , _buildingOwnerAction = takeResources 1 [Fighter] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 3 + , _buildingTitle = "Helmstar Warehouse" + , _buildingAction = do + takeResources 2 [Rogue] + takeResources 2 [Gold] + , _buildingOwnerAction = takeResources 1 [Rogue] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 4 + , _buildingTitle = "Smuggler's Dock" + , _buildingAction = do + returnResources 2 [Gold] + takeResources 4 [Fighter, Rogue] + , _buildingOwnerAction = takeResources 2 [Gold] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 4 + , _buildingTitle = "House of Wonder" + , _buildingAction = do + returnResources 2 [Gold] + takeResources 2 [Cleric, Wizard] + , _buildingOwnerAction = takeResources 2 [Gold] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 4 + , _buildingTitle = "The Three Pearls" + , _buildingAction = do + returnResources 2 [Cleric, Fighter, Rogue, Wizard] + takeResources 3 [Cleric, Fighter, Rogue, Wizard] + , _buildingOwnerAction = takeResources 2 [Gold] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 8 + , _buildingTitle = "The Zoarstar" + , _buildingAction = do + useOpponentsSpace + , _buildingOwnerAction = scorePoints 2 + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 4 + , _buildingTitle = "The Stone House" + , _buildingAction = do + forEachBuilding $ takeResources 1 [Gold] + , _buildingOwnerAction = takeResources 2 [Gold] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 8 + , _buildingTitle = "Fetlock Court" + , _buildingAction = do + takeResources 2 [Fighter] + takeResources 1 [Wizard] + , _buildingOwnerAction = takeResources 1 [Fighter, Wizard] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 4 + , _buildingTitle = "The Yawning Portal" + , _buildingAction = do + takeResources 2 [Cleric, Fighter, Rogue, Wizard] + , _buildingOwnerAction = takeResources 1 [Cleric, Fighter, Rogue, Wizard] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 8 + , _buildingTitle = "House of Heroes" + , _buildingAction = do + takeResources 1 [Cleric] + takeResources 2 [Fighter] + , _buildingOwnerAction = takeResources 1 [Cleric, Fighter] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 8 + , _buildingTitle = "The Tower of Luck" + , _buildingAction = do + takeResources 1 [Cleric] + takeResources 2 [Rogue] + , _buildingOwnerAction = takeResources 1 [Cleric, Rogue] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 4 + , _buildingTitle = "Jester's Court" + , _buildingAction = noAction + , _buildingOwnerAction = takeResources 1 [Rogue] + , _buildingAccumType = AccumulateResource Rogue 2 + } + , Building { _buildingCost = 4 + , _buildingTitle = "Caravan Court" + , _buildingAction = noAction + , _buildingOwnerAction = takeResources 1 [Fighter] + , _buildingAccumType = AccumulateResource Fighter 2 + } + , Building { _buildingCost = 4 + , _buildingTitle = "Spires of the Morning" + , _buildingAction = noAction + , _buildingOwnerAction = scorePoints 2 + , _buildingAccumType = AccumulateResource Cleric 1 + } + , Building { _buildingCost = 8 + , _buildingTitle = "New Olamn" + , _buildingAction = do + takeResources 2 [Rogue] + takeResources 1 [Wizard] + , _buildingOwnerAction = takeResources 1 [Rogue, Wizard] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 4 + , _buildingTitle = "Tower of the Order" + , _buildingAction = noAction + , _buildingOwnerAction = drawIntrigue + , _buildingAccumType = AccumulateResource Wizard 1 + } + , Building { _buildingCost = 3 + , _buildingTitle = "Dragon Tower" + , _buildingAction = do + takeResources 1 [Wizard] + drawIntrigue + , _buildingOwnerAction = drawIntrigue + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 3 + , _buildingTitle = "House of the Moon" + , _buildingAction = do + takeResources 1 [Cleric] + chooseQuest + , _buildingOwnerAction = takeResources 2 [Gold] + , _buildingAccumType = NoAccumulation + } + , Building { _buildingCost = 3 + , _buildingTitle = "Northgate" + , _buildingAction = do + takeResources 1 [Cleric, Fighter, Rogue, Wizard] + takeResources 2 [Gold] + , _buildingOwnerAction = scorePoints 2 + , _buildingAccumType = NoAccumulation + } + ] diff --git a/src/Waterdeep/Logic.hs b/src/Waterdeep/Logic.hs index 6f68ff0..286d6f8 100644 --- a/src/Waterdeep/Logic.hs +++ b/src/Waterdeep/Logic.hs @@ -25,6 +25,7 @@ import Lens.Family2.Stock import System.Random.Shuffle import Text.Printf import Waterdeep.Actions +import Waterdeep.Buildings (basicBuildings) import Waterdeep.Types import Waterdeep.Util @@ -64,30 +65,6 @@ newGame players quests intrigues buildings rndgen = buildingStates = zipWith (\i b -> (i, newBuildingState np b)) [1..] basicBuildings np = noPlayerID -basicBuildings :: [Building] -basicBuildings = - [ basicBuilding "Aurora's Realms Shop" (takeResources 4 [Gold]) - , basicBuilding "Blackstaff Tower" (takeResources 1 [Wizard]) - , basicBuilding "Builder's Hall" buyBuilding - , basicBuilding "Castle Waterdeep" (becomeFirstPlayer >> drawIntrigue) - , basicBuilding "Field of Triumph" (takeResources 2 [Fighter]) - , basicBuilding "The Grinning Lion Tavern" (takeResources 2 [Rogue]) - , basicBuilding "The Plinth" (takeResources 1 [Cleric]) - , basicBuilding "Cliffwatch Inn (2 Gold)" (chooseQuest >> takeResources 2 [Gold]) - , basicBuilding "Cliffwatch Inn (Intrigue)" (chooseQuest >> drawIntrigue) - , basicBuilding "Cliffwatch Inn (Reset)" (replaceQuests >> chooseQuest) - ] - -basicBuilding :: String -> GameAction -> Building -basicBuilding title action = - Building - { _buildingCost = 0 - , _buildingTitle = title - , _buildingAction = action - , _buildingOwnerAction = noAction - , _buildingAccumType = NoAccumulation - } - waterdeepGame :: Waterdeep [PlayerID] waterdeepGame = do np <- use gameNumberOfPlayers @@ -182,11 +159,13 @@ scoreFinalPoints = do determineWinners :: Waterdeep [PlayerID] determineWinners = do playerStates <- toListOf traverse <$> use gamePlayerStates - let bestScore = maximum $ map (view playerScore) playerStates - let winners1 = filter ((== bestScore) . view playerScore) playerStates - let bestGold = maximum $ map playerGold winners1 - let winners2 = filter ((== bestGold) . playerGold) winners1 - broadcast $ "Winners: " ++ (intercalate ", " (winners2 ^.. traverse . playerName)) + let bestScore = maximum $ map (view playerScore) playerStates + let winners1 = filter ((== bestScore) . view playerScore) playerStates + let bestGold = maximum $ map playerGold winners1 + let winners2 = filter ((== bestGold) . playerGold) winners1 + if null (drop 1 winners2) + then broadcast $ "Winner: " ++ (head winners2 ^. playerName) + else broadcast $ "Winners: " ++ (intercalate ", " (winners2 ^.. traverse . playerName)) return (winners2 ^.. traverse . playerNumber) where playerGold = MS.occur Gold . view playerTavern