gameServer/HWProtoInRoomState.hs
branchwebgl
changeset 8444 75db7bb8dce8
parent 8330 aaefa587e277
parent 8429 f814a7c2a318
child 8833 c13ebed437cb
equal deleted inserted replaced
8340:46a9fde631f4 8444:75db7bb8dce8
     1 {-# LANGUAGE OverloadedStrings #-}
     1 {-# LANGUAGE OverloadedStrings #-}
     2 module HWProtoInRoomState where
     2 module HWProtoInRoomState where
     3 
     3 
     4 import qualified Data.Map as Map
     4 import qualified Data.Map as Map
     5 import Data.Sequence((|>))
       
     6 import Data.List as L
     5 import Data.List as L
     7 import Data.Maybe
     6 import Data.Maybe
     8 import qualified Data.ByteString.Char8 as B
     7 import qualified Data.ByteString.Char8 as B
     9 import Control.Monad
     8 import Control.Monad
    10 import Control.Monad.Reader
     9 import Control.Monad.Reader
    11 import Control.DeepSeq
       
    12 --------------------------------------
    10 --------------------------------------
    13 import CoreTypes
    11 import CoreTypes
    14 import Actions
    12 import Actions
    15 import Utils
    13 import Utils
    16 import HandlerUtils
    14 import HandlerUtils
    27 handleCmd_inRoom ["PART"] = return [MoveToLobby "part"]
    25 handleCmd_inRoom ["PART"] = return [MoveToLobby "part"]
    28 handleCmd_inRoom ["PART", msg] = return [MoveToLobby $ "part: " `B.append` msg]
    26 handleCmd_inRoom ["PART", msg] = return [MoveToLobby $ "part: " `B.append` msg]
    29 
    27 
    30 
    28 
    31 handleCmd_inRoom ("CFG" : paramName : paramStrs)
    29 handleCmd_inRoom ("CFG" : paramName : paramStrs)
    32     | null paramStrs = return [ProtocolError "Empty config entry"]
    30     | null paramStrs = return [ProtocolError $ loc "Empty config entry"]
    33     | otherwise = do
    31     | otherwise = do
    34         chans <- roomOthersChans
    32         chans <- roomOthersChans
    35         cl <- thisClient
    33         cl <- thisClient
    36         if isMaster cl then
    34         if isMaster cl then
    37            return [
    35            return [
    38                 ModifyRoom f,
    36                 ModifyRoom f,
    39                 AnswerClients chans ("CFG" : paramName : paramStrs)]
    37                 AnswerClients chans ("CFG" : paramName : paramStrs)]
    40             else
    38             else
    41             return [ProtocolError "Not room master"]
    39             return [ProtocolError $ loc "Not room master"]
    42     where
    40     where
    43         f r = if paramName `Map.member` (mapParams r) then
    41         f r = if paramName `Map.member` (mapParams r) then
    44                 r{mapParams = Map.insert paramName (head paramStrs) (mapParams r)}
    42                 r{mapParams = Map.insert paramName (head paramStrs) (mapParams r)}
    45                 else
    43                 else
    46                 r{params = Map.insert paramName paramStrs (params r)}
    44                 r{params = Map.insert paramName paramStrs (params r)}
    47 
    45 
    48 handleCmd_inRoom ("ADD_TEAM" : tName : color : grave : fort : voicepack : flag : difStr : hhsInfo)
    46 handleCmd_inRoom ("ADD_TEAM" : tName : color : grave : fort : voicepack : flag : difStr : hhsInfo)
    49     | length hhsInfo /= 16 = return [ProtocolError "Corrupted hedgehogs info"]
    47     | length hhsInfo /= 16 = return [ProtocolError $ loc "Corrupted hedgehogs info"]
    50     | otherwise = do
    48     | otherwise = do
    51         (ci, _) <- ask
    49         (ci, _) <- ask
    52         rm <- thisRoom
    50         rm <- thisRoom
    53         clNick <- clientNick
    51         clNick <- clientNick
    54         clChan <- thisClientChans
    52         clChan <- thisClientChans
    58         teamColor <-
    56         teamColor <-
    59             if clientProto cl < 42 then
    57             if clientProto cl < 42 then
    60                 return color
    58                 return color
    61                 else
    59                 else
    62                 liftM (head . (L.\\) (map B.singleton ['0'..]) . map teamcolor . teams) thisRoom
    60                 liftM (head . (L.\\) (map B.singleton ['0'..]) . map teamcolor . teams) thisRoom
    63         let newTeam = clNick `seq` TeamInfo ci clNick tName teamColor grave fort voicepack flag dif (newTeamHHNum rm) (hhsList hhsInfo)
    61         let roomTeams = teams rm
       
    62         let hhNum = let p = if not $ null roomTeams then hhnum $ head roomTeams else 4 in newTeamHHNum roomTeams p
       
    63         let newTeam = clNick `seq` TeamInfo ci clNick tName teamColor grave fort voicepack flag dif hhNum (hhsList hhsInfo)
    64         return $
    64         return $
    65             if not . null . drop (maxTeams rm - 1) $ teams rm then
    65             if not . null . drop (maxTeams rm - 1) $ roomTeams then
    66                 [Warning "too many teams"]
    66                 [Warning $ loc "too many teams"]
    67             else if canAddNumber rm <= 0 then
    67             else if canAddNumber roomTeams <= 0 then
    68                 [Warning "too many hedgehogs"]
    68                 [Warning $ loc "too many hedgehogs"]
    69             else if isJust $ findTeam rm then
    69             else if isJust $ findTeam rm then
    70                 [Warning "There's already a team with same name in the list"]
    70                 [Warning $ loc "There's already a team with same name in the list"]
    71             else if isJust $ gameInfo rm then
    71             else if isJust $ gameInfo rm then
    72                 [Warning "round in progress"]
    72                 [Warning $ loc "round in progress"]
    73             else if isRestrictedTeams rm then
    73             else if isRestrictedTeams rm then
    74                 [Warning "restricted"]
    74                 [Warning $ loc "restricted"]
    75             else
    75             else
    76                 [ModifyRoom (\r -> r{teams = teams r ++ [newTeam]}),
    76                 [ModifyRoom (\r -> r{teams = teams r ++ [newTeam]}),
    77                 SendUpdateOnThisRoom,
    77                 SendUpdateOnThisRoom,
    78                 ModifyClient (\c -> c{teamsInGame = teamsInGame c + 1, clientClan = Just teamColor}),
    78                 ModifyClient (\c -> c{teamsInGame = teamsInGame c + 1, clientClan = Just teamColor}),
    79                 AnswerClients clChan ["TEAM_ACCEPTED", tName],
    79                 AnswerClients clChan ["TEAM_ACCEPTED", tName],
       
    80                 AnswerClients clChan ["HH_NUM", tName, showB $ hhnum newTeam],
    80                 AnswerClients othChans $ teamToNet $ newTeam,
    81                 AnswerClients othChans $ teamToNet $ newTeam,
    81                 AnswerClients roomChans ["TEAM_COLOR", tName, teamColor]
    82                 AnswerClients roomChans ["TEAM_COLOR", tName, teamColor]
    82                 ]
    83                 ]
    83         where
    84         where
    84         canAddNumber r = 48 - (sum . map hhnum $ teams r)
    85         canAddNumber rt = (48::Int) - (sum $ map hhnum rt)
    85         findTeam = find (\t -> tName == teamname t) . teams
    86         findTeam = find (\t -> tName == teamname t) . teams
    86         dif = readInt_ difStr
    87         dif = readInt_ difStr
    87         hhsList [] = []
    88         hhsList [] = []
    88         hhsList [_] = error "Hedgehogs list with odd elements number"
    89         hhsList [_] = error "Hedgehogs list with odd elements number"
    89         hhsList (n:h:hhs) = HedgehogInfo n h : hhsList hhs
    90         hhsList (n:h:hhs) = HedgehogInfo n h : hhsList hhs
    90         newTeamHHNum r = min 4 (canAddNumber r)
    91         newTeamHHNum rt p = min p (canAddNumber rt)
    91         maxTeams r
    92         maxTeams r
    92             | roomProto r < 38 = 6
    93             | roomProto r < 38 = 6
    93             | otherwise = 8
    94             | otherwise = 8
    94 
    95 
    95 
    96 
   100 
   101 
   101         let maybeTeam = findTeam r
   102         let maybeTeam = findTeam r
   102         let team = fromJust maybeTeam
   103         let team = fromJust maybeTeam
   103 
   104 
   104         return $
   105         return $
   105             if isNothing $ findTeam r then
   106             if isNothing $ maybeTeam then
   106                 [Warning "REMOVE_TEAM: no such team"]
   107                 [Warning $ loc "REMOVE_TEAM: no such team"]
   107             else if clNick /= teamowner team then
   108             else if clNick /= teamowner team then
   108                 [ProtocolError "Not team owner!"]
   109                 [ProtocolError $ loc "Not team owner!"]
   109             else
   110             else
   110                 [RemoveTeam tName,
   111                 [RemoveTeam tName,
   111                 ModifyClient
   112                 ModifyClient
   112                     (\c -> c{
   113                     (\c -> c{
   113                         teamsInGame = teamsInGame c - 1,
   114                         teamsInGame = teamsInGame c - 1,
   119         findTeam = find (\t -> tName == teamname t) . teams
   120         findTeam = find (\t -> tName == teamname t) . teams
   120 
   121 
   121 
   122 
   122 handleCmd_inRoom ["HH_NUM", teamName, numberStr] = do
   123 handleCmd_inRoom ["HH_NUM", teamName, numberStr] = do
   123     cl <- thisClient
   124     cl <- thisClient
   124     others <- roomOthersChans
       
   125     r <- thisRoom
   125     r <- thisRoom
       
   126     clChan <- thisClientChans
       
   127     roomChans <- roomClientsChans
   126 
   128 
   127     let maybeTeam = findTeam r
   129     let maybeTeam = findTeam r
   128     let team = fromJust maybeTeam
   130     let team = fromJust maybeTeam
   129 
   131 
   130     return $
   132     return $
   131         if not $ isMaster cl then
   133         if not $ isMaster cl then
   132             [ProtocolError "Not room master"]
   134             [ProtocolError $ loc "Not room master"]
   133         else if hhNumber < 1 || hhNumber > 8 || isNothing maybeTeam || hhNumber > canAddNumber r + hhnum team then
   135         else if isNothing maybeTeam then
   134             []
   136             []
       
   137         else if hhNumber < 1 || hhNumber > 8 || hhNumber > canAddNumber r + hhnum team then
       
   138             [AnswerClients clChan ["HH_NUM", teamName, showB $ hhnum team]]
   135         else
   139         else
   136             [ModifyRoom $ modifyTeam team{hhnum = hhNumber},
   140             [ModifyRoom $ modifyTeam team{hhnum = hhNumber},
   137             AnswerClients others ["HH_NUM", teamName, showB hhNumber]]
   141             AnswerClients roomChans ["HH_NUM", teamName, showB hhNumber]]
   138     where
   142     where
   139         hhNumber = readInt_ numberStr
   143         hhNumber = readInt_ numberStr
   140         findTeam = find (\t -> teamName == teamname t) . teams
   144         findTeam = find (\t -> teamName == teamname t) . teams
   141         canAddNumber = (-) 48 . sum . map hhnum . teams
   145         canAddNumber = (-) 48 . sum . map hhnum . teams
   142 
   146 
   150     let maybeTeam = findTeam r
   154     let maybeTeam = findTeam r
   151     let team = fromJust maybeTeam
   155     let team = fromJust maybeTeam
   152 
   156 
   153     return $
   157     return $
   154         if not $ isMaster cl then
   158         if not $ isMaster cl then
   155             [ProtocolError "Not room master"]
   159             [ProtocolError $ loc "Not room master"]
   156         else if isNothing maybeTeam then
   160         else if isNothing maybeTeam then
   157             []
   161             []
   158         else
   162         else
   159             [ModifyRoom $ modifyTeam team{teamcolor = newColor},
   163             [ModifyRoom $ modifyTeam team{teamcolor = newColor},
   160             AnswerClients others ["TEAM_COLOR", teamName, newColor],
   164             AnswerClients others ["TEAM_COLOR", teamName, newColor],
   185     chans <- roomClientsChans
   189     chans <- roomClientsChans
   186 
   190 
   187     let nicks = map (nick . client rnc) . roomClients rnc $ clientRoom rnc ci
   191     let nicks = map (nick . client rnc) . roomClients rnc $ clientRoom rnc ci
   188     let allPlayersRegistered = all ((<) 0 . B.length . webPassword . client rnc . teamownerId) $ teams rm
   192     let allPlayersRegistered = all ((<) 0 . B.length . webPassword . client rnc . teamownerId) $ teams rm
   189 
   193 
   190     if isMaster cl && playersIn rm == readyPlayers rm && not (isJust $ gameInfo rm) then
   194     if isMaster cl && (playersIn rm == readyPlayers rm || clientProto cl > 43) && not (isJust $ gameInfo rm) then
   191         if enoughClans rm then
   195         if enoughClans rm then
   192             return [
   196             return [
   193                 ModifyRoom
   197                 ModifyRoom
   194                     (\r -> r{
   198                     (\r -> r{
   195                         gameInfo = Just $ newGameInfo (teams rm) (length $ teams rm) allPlayersRegistered (mapParams rm) (params rm)
   199                         gameInfo = Just $ newGameInfo (teams rm) (length $ teams rm) allPlayersRegistered (mapParams rm) (params rm)
   199                 , SendUpdateOnThisRoom
   203                 , SendUpdateOnThisRoom
   200                 , AnswerClients chans $ "CLIENT_FLAGS" : "+g" : nicks
   204                 , AnswerClients chans $ "CLIENT_FLAGS" : "+g" : nicks
   201                 , ModifyRoomClients (\c -> c{isInGame = True})
   205                 , ModifyRoomClients (\c -> c{isInGame = True})
   202                 ]
   206                 ]
   203             else
   207             else
   204             return [Warning "Less than two clans!"]
   208             return [Warning $ loc "Less than two clans!"]
   205         else
   209         else
   206         return []
   210         return []
   207     where
   211     where
   208         enoughClans = not . null . drop 1 . group . map teamcolor . teams
   212         enoughClans = not . null . drop 1 . group . map teamcolor . teams
   209 
   213 
   212     cl <- thisClient
   216     cl <- thisClient
   213     rm <- thisRoom
   217     rm <- thisRoom
   214     chans <- roomOthersChans
   218     chans <- roomOthersChans
   215 
   219 
   216     if teamsInGame cl > 0 && (isJust $ gameInfo rm) && isLegal then
   220     if teamsInGame cl > 0 && (isJust $ gameInfo rm) && isLegal then
   217         return $ AnswerClients chans ["EM", msg] : [ModifyRoom (\r -> r{gameInfo = liftM (\g -> g{roundMsgs = roundMsgs g |> msg}) $ gameInfo r}) | not isKeepAlive]
   221         return $ AnswerClients chans ["EM", msg]
       
   222             : [ModifyRoom (\r -> r{gameInfo = liftM (\g -> g{roundMsgs = msg : roundMsgs g}) $ gameInfo r}) | not isKeepAlive]
   218         else
   223         else
   219         return []
   224         return []
   220     where
   225     where
   221         (isLegal, isKeepAlive) = checkNetCmd msg
   226         (isLegal, isKeepAlive) = checkNetCmd msg
   222 
   227 
   229     let clTeams = map teamname . filter (\t -> teamowner t == nick cl) . teams $ rm
   234     let clTeams = map teamname . filter (\t -> teamowner t == nick cl) . teams $ rm
   230     let unsetInGameState = [AnswerClients chans ["CLIENT_FLAGS", "-g", nick cl], ModifyClient (\c -> c{isInGame = False})]
   235     let unsetInGameState = [AnswerClients chans ["CLIENT_FLAGS", "-g", nick cl], ModifyClient (\c -> c{isInGame = False})]
   231 
   236 
   232     if isInGame cl then
   237     if isInGame cl then
   233         if isJust $ gameInfo rm then
   238         if isJust $ gameInfo rm then
   234             if (isMaster cl && isCorrect) then
   239             return $ unsetInGameState ++ map SendTeamRemovalMessage clTeams
   235                 return $ FinishGame : unsetInGameState
       
   236                 else
       
   237                 return $ unsetInGameState ++ map SendTeamRemovalMessage clTeams
       
   238             else
   240             else
   239             return unsetInGameState
   241             return unsetInGameState
   240         else
   242         else
   241         return [] -- don't accept this message twice
   243         return [] -- don't accept this message twice
   242     where
   244     where
   248 
   250 
   249 handleCmd_inRoom ["TOGGLE_RESTRICT_JOINS"] = do
   251 handleCmd_inRoom ["TOGGLE_RESTRICT_JOINS"] = do
   250     cl <- thisClient
   252     cl <- thisClient
   251     return $
   253     return $
   252         if not $ isMaster cl then
   254         if not $ isMaster cl then
   253             [ProtocolError "Not room master"]
   255             [ProtocolError $ loc "Not room master"]
   254         else
   256         else
   255             [ModifyRoom (\r -> r{isRestrictedJoins = not $ isRestrictedJoins r})]
   257             [ModifyRoom (\r -> r{isRestrictedJoins = not $ isRestrictedJoins r})]
   256 
   258 
   257 
   259 
   258 handleCmd_inRoom ["TOGGLE_RESTRICT_TEAMS"] = do
   260 handleCmd_inRoom ["TOGGLE_RESTRICT_TEAMS"] = do
   259     cl <- thisClient
   261     cl <- thisClient
   260     return $
   262     return $
   261         if not $ isMaster cl then
   263         if not $ isMaster cl then
   262             [ProtocolError "Not room master"]
   264             [ProtocolError $ loc "Not room master"]
   263         else
   265         else
   264             [ModifyRoom (\r -> r{isRestrictedTeams = not $ isRestrictedTeams r})]
   266             [ModifyRoom (\r -> r{isRestrictedTeams = not $ isRestrictedTeams r})]
   265 
   267 
   266 
   268 
   267 handleCmd_inRoom ["TOGGLE_REGISTERED_ONLY"] = do
   269 handleCmd_inRoom ["TOGGLE_REGISTERED_ONLY"] = do
   268     cl <- thisClient
   270     cl <- thisClient
   269     return $
   271     return $
   270         if not $ isMaster cl then
   272         if not $ isMaster cl then
   271             [ProtocolError "Not room master"]
   273             [ProtocolError $ loc "Not room master"]
   272         else
   274         else
   273             [ModifyRoom (\r -> r{isRegisteredOnly = not $ isRegisteredOnly r})]
   275             [ModifyRoom (\r -> r{isRegisteredOnly = not $ isRegisteredOnly r})]
   274 
   276 
   275 handleCmd_inRoom ["ROOM_NAME", newName] = do
   277 handleCmd_inRoom ["ROOM_NAME", newName] = do
   276     cl <- thisClient
   278     cl <- thisClient
   278     rm <- thisRoom
   280     rm <- thisRoom
   279     chans <- sameProtoChans
   281     chans <- sameProtoChans
   280 
   282 
   281     return $
   283     return $
   282         if not $ isMaster cl then
   284         if not $ isMaster cl then
   283             [ProtocolError "Not room master"]
   285             [ProtocolError $ loc "Not room master"]
   284         else
   286         else
   285         if isJust $ find (\r -> newName == name r) rs then
   287         if isJust $ find (\r -> newName == name r) rs then
   286             [Warning "Room with such name already exists"]
   288             [Warning $ loc "Room with such name already exists"]
   287         else
   289         else
   288             [ModifyRoom roomUpdate,
   290             [ModifyRoom roomUpdate,
   289             AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo (nick cl) (roomUpdate rm))]
   291             AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo (nick cl) (roomUpdate rm))]
   290     where
   292     where
   291         roomUpdate r = r{name = newName}
   293         roomUpdate r = r{name = newName}
   303 
   305 
   304 handleCmd_inRoom ["DELEGATE", newAdmin] = do
   306 handleCmd_inRoom ["DELEGATE", newAdmin] = do
   305     (thisClientId, rnc) <- ask
   307     (thisClientId, rnc) <- ask
   306     maybeClientId <- clientByNick newAdmin
   308     maybeClientId <- clientByNick newAdmin
   307     master <- liftM isMaster thisClient
   309     master <- liftM isMaster thisClient
       
   310     serverAdmin <- liftM isAdministrator thisClient
   308     let newAdminId = fromJust maybeClientId
   311     let newAdminId = fromJust maybeClientId
   309     let sameRoom = clientRoom rnc thisClientId == clientRoom rnc newAdminId
   312     let sameRoom = clientRoom rnc thisClientId == clientRoom rnc newAdminId
   310     return
   313     return
   311         [ChangeMaster (Just newAdminId) | master && isJust maybeClientId && (newAdminId /= thisClientId) && sameRoom]
   314         [ChangeMaster (Just newAdminId) |
       
   315             (master || serverAdmin)
       
   316                 && isJust maybeClientId
       
   317                 && ((newAdminId /= thisClientId) || (serverAdmin && not master))
       
   318                 && sameRoom]
   312 
   319 
   313 
   320 
   314 handleCmd_inRoom ["TEAMCHAT", msg] = do
   321 handleCmd_inRoom ["TEAMCHAT", msg] = do
   315     cl <- thisClient
   322     cl <- thisClient
   316     chans <- roomSameClanChans
   323     chans <- roomSameClanChans