--- Hostname, Port, Playername, Callback
-runPartty :: String -> Int -> String -> DayCallback d -> NightCallback d -> IO ()
-runPartty = undefined
+-- Hostname, Port, Playername, Password, Callback
+runPartty :: String -> Int -> String -> String -> DayCallback d -> NightCallback d -> d -> IO ()
+runPartty host port username password dcb ncb initialData = do
+ h <- connectTo host (PortNumber (fromIntegral port))
+ InternalMessage Welcome <- parseIncomingMessage `liftM` hGetLine h
+ hPutStrLn h $ unwords ["login", username, password]
+ InternalMessage (PlayerJoined myName) <- parseIncomingMessage `liftM` hGetLine h
+ when (myName /= username) $ error "Server returned a different name for me"
+
+ -- login has been successful, wait for the server start event
+ fix $ \loop -> do
+ msg <- parseIncomingMessage `liftM` hGetLine h
+ case msg of
+ (InternalMessage GameStarting) -> return ()
+ otherwise -> do
+ putStrLn "Waiting for game start..."
+ loop
+
+ -- We expect two more fixed events. If the server changes, this breaks!
+
+ InternalMessage (MyIdIs myId) <- parseIncomingMessage `liftM` hGetLine h
+ InternalMessage (PlayerEnter player startPlace) <- parseIncomingMessage `liftM` hGetLine h
+ when (player /= myId) $ error "Server did not tell us where we start"
+
+ let initialState = ParttyState
+ { psMyName = myId
+ , psDay = 0
+ , psPlayerInfo = empty
+ , psPartyHistory= []
+ , psPlace = startPlace
+ , psPlayers = []
+ }
+
+ -- The rest of the events are handled in the regular loop. Run the initial event
+ -- and call the runner
+
+ d' <- callNightCallback ncb initialState initialData Initialize
+
+ runner h dcb ncb initialState d'