Пример #1
0
 def otherInfo(self, tree, entry):
     owner = dataModel.playerNameGet(self.game, entry['owner'])
     othr = tree.insert("",
                        'end',
                        image=self.photo,
                        text=entry['name'],
                        values=[owner, entry['type']])
Пример #2
0
    def starInfo(self, tree, entry):
        owner = dataModel.playerNameGet(self.game, entry['owner'])
        desc = "Star holding " + str(int(entry['BP']['cur'])) + " BP"
        if (entry['BP']['perturn'] > 0):
            desc += "(+" + str(int(entry['BP']['perturn'])) + " per turn)"

        star = tree.insert("",
                           'end',
                           image=self.photo,
                           text=entry['name'],
                           values=[owner, desc])
Пример #3
0
    def shipInfo(self, tree, entry):
        if (entry['WG']['max']):
            text = "Warp" + entry['type']
            if (not entry['WG']['cur']):
                text += "(Drive Currently Damaged)"
        else:
            text = "System" + entry['type']

        title = "techLevel " + str(entry['techLevel'])

        text1 = "Moves left: " + str(entry['moves']['cur'])
        text1 += ", "
        text1 += "PowerDrive: " + str(entry['PD']['cur']) + "/" + str(
            entry['PD']['max'])

        text2 = "Shields " + str(entry['S']['cur']) + "/" + str(
            entry['S']['max'])
        text2 += ", "
        text2 += "Beams: " + str(entry['B']['cur']) + "/" + str(
            entry['B']['max'])

        text3 = "Tubes: " + str(entry['T']['cur']) + "/" + str(
            entry['T']['max'])
        text3 += " - "
        text3 += "Missiles: " + str(entry['M']['cur']) + "/" + str(
            entry['M']['max'])

        text4 = "SystemRacks: " + str(entry['SR']['cur']) + "/" + str(
            entry['SR']['max'])
        text4 += ", "
        text4 += "Holds: " + str(entry['H']['cur']) + "/" + str(
            entry['H']['max'])
        text4 += "[" + str(entry['Hauled']) + "]"

        owner = dataModel.playerNameGet(self.game, entry['owner'])
        base = tree.insert("",
                           'end',
                           image=self.photo,
                           text=entry['name'],
                           values=[owner, text])
        line = tree.insert(base, 'end', text=title, values=["", text1])
        line = tree.insert(base, 'end', text="", values=["", text2])
        line = tree.insert(base, 'end', text="", values=["", text3])
        line = tree.insert(base, 'end', text="", values=["", text4])
Пример #4
0
    def parseCmd(self, jsonStr):
        try:
            root = json.loads(jsonStr)
        except Exception as error:
            print("GServer:", "JSON parse error for ", jsonStr, "\n")
            return False

        cmd = root['cmd']
        cmdStr = cmd['cmd']
        if (self.cmdStr != cmdStr):
            print("GServer: (%s) CMD: %s PHASE: %s" %
                  (cmd['plid'], cmdStr, self.game['state']['phase']))
        self.cmdStr = cmdStr

        if cmdStr == 'quit':
            # Quit the game and exit the server process
            # This cmd doesn't save anything. Call save if you want to save
            self.log(
                dataModel.playerNameGet(self.game, cmd['plid']) +
                " Ended the game")

            self.game['state']['phase'] = "quitting"
            self.gameContinues = False

        elif cmdStr == 'ping':
            # simple test to see if server responds. So do nothing and respond
            pass

        elif cmdStr == 'newplayer':
            # New player requests to join.
            # I guess we would look at the game state? Hmmm
            # What about a player joining a previously saved game?
            # Input? Player name and potentially player specific options
            # What player specific options? IP:port?
            newPlayer = cmd['name']
            startingBases = cmd['bases']
            color = cmd['color']

            if int(cmd['plid']) == 0:
                # If they didn't provide a playerid create one
                plid = max(
                    [0] +
                    [player['plid'] for player in self.game['playerList']]) + 1
            else:
                plid = cmd['plid']

            print("GServer:", "newPlayer", newPlayer, plid, startingBases)

            player = dataModel.playerTableGet(self.game, plid)

            if player is None:
                # Brand new player. If the game is "accepting players"
                # Add the new player
                if ((self.game['state']['phase'] is None)
                        or (self.game['state']['phase'] == "creating")):

                    self.game['playerList'].append({
                        'name': newPlayer,
                        'phase': "creating",
                        'color': color,
                        'plid': plid
                    })
                    player = dataModel.playerTableGet(self.game, plid)
                    player['color'] = color
                    self.log(newPlayer + " is " + color + " and starts with" +
                             str(startingBases))
                    for base in startingBases:
                        ownIt = dataModel.findBase(self.game, base)
                        if ownIt:
                            print(newPlayer, "owns", base)
                            ownIt['owner'] = plid
                            #give them everything at that base
                            baseItems = dataModel.findObjectsAt(
                                self.game, ownIt['location']['x'],
                                ownIt['location']['y'])
                            for baseItem in baseItems:
                                baseItem['owner'] = plid
                        else:
                            self.log(newPlayer + " Error: Missing base " +
                                     base)
                else:
                    print("GServer:", "may not join on going game!")
                    self.log(newPlayer + " rejected from game in phase " +
                             self.game['state']['phase'])

            else:
                # Normally the player shouldn't exist! But they do for the
                # sample game (or if reconnecting to a game)
                if (player['phase'] is None):
                    assert ((self.game['state']['phase'] is None)
                            or (self.game['state']['phase'] == "creating"))
                    player['phase'] = "creating"
                    print("GServer: I don't think this should happen anymore")
                else:
                    self.log(newPlayer + " is rejoining game")

        elif cmdStr == 'newgame':
            # What to do? Offer to save current game? NO! this is the server,
            # do as commanded
            # erase current game/dictionary
            # Start empty
            # Input? Would be list of options for game
            # Should we prevent this? Perhaps block it? Only permit it
            # if there is only one connected player?
            #
            # Need to be given the name of the game?
            # Warn/Error if current game hasn't been saved (is dirty)
            plid = cmd['plid']
            gamename = cmd['gamename']
            name = cmd['name']
            self.game = dataModel.defaultGame()
            self.game['state']['phase'] = "creating"
            self.log(name + " Created a new game")
            # TODO probably need things like game options???
            # TODO lots of options, right?

        elif cmdStr == 'start':
            # Basically just change state so players can begin building
            # and playing
            self.log("Starting game. Players should build now.")
            assert (self.game['state']['phase'] == "creating")
            self.game['state']['phase'] = "build"
            changeAllPlayerPhase(self.game, "creating", "build")

        elif cmdStr == 'buildship':
            # Now we get to fun stuff
            # Check for proper state to see if player permitted to build.
            # Validate a legal build. Does player have the money?
            # Input? ... this is a lot... The entire ship? We would have
            # to calculate the cost based on the options and validate it.
            # We would have to deduct the cost from the players total.
            # Of course need to see if it is a valid ship to begin with
            # TODO lots of parameters!
            ship = cmd['ship']
            baseName = cmd['base']
            assert (self.game['state']['phase'] == "build")

            #lets do this the lazy way first. just append the ship to the list!
            print("GServer:", "ship to append: The ", ship['name'])
            #print(ship)
            #How much will this ship cost?
            cost = 0
            cost += ship['PD']['max']
            cost += ship['B']['max']
            cost += ship['S']['max']
            cost += ship['E']['max']
            cost += ship['T']['max']
            cost += ship['M']['max'] / 3
            cost += ship['A']['max'] / 2
            cost += ship['C']['max']
            cost += ship['SH']['max'] / 6
            cost += ship['SR']['max']
            cost += ship['H']['max']
            cost += ship['R']['max'] * 5
            if ship['WG']['max'] == True:
                cost += 5

            print("GServer cost:", cost)

            #TODO: This next section is bad. we don't check to see if the player
            #who sent the command owns the base, or is in the right spot.
            #what we should really do is have this command only take the ship,
            #and have the base we work with just be any base on the ship's hex
            #owned by the right player

            #find the base in the game
            base = dataModel.findBase(self.game, baseName)
            if (base is not None):
                #does the base have enough to pay for the ship?
                if base['BP']['cur'] >= cost:
                    #subtract the cost...
                    #print (base)
                    base['BP']['cur'] -= cost
                    #print (base)
                    #and build the ship!
                    self.game['objects']['shipList'].append(ship)
                    self.log(
                        dataModel.playerNameGet(self.game, cmd['plid']) +
                        " Built the '" + ship['name'] + "' at " + baseName)
                else:
                    print(
                        "GServer cheater!:",
                        "base({}) can't afford ship({})".format(
                            base['BP']['cur'], cost))

        elif cmdStr == 'ready':
            # A generic cmd used to end several phases
            plid = cmd['plid']
            print("GServer:", "player", plid, "done with phase",
                  self.game['state']['phase'])

            # Based on current phase what do we do?
            if (self.game['state']['phase'] == "creating"):
                # Record ready for given player
                changePlayerPhase(self.game, plid, "creating", "waiting")

            elif (self.game['state']['phase'] == "build"):
                # Given player can no longer build and must wait
                # When all players ready AUTO move to move phase
                # Record ready for given player
                changePlayerPhase(self.game, plid, "build", "waiting")

                if areAllPlayersInPhase(self.game, "waiting"):
                    self.game['state']['phase'] = "move"
                    changeAllPlayerPhase(self.game, "waiting", "move")
                    # Reset all ships so that can move again
                    for ship in self.game['objects']['shipList']:
                        ship['moves']['cur'] = math.ceil(ship['PD']['cur'] / 2)

            elif (self.game['state']['phase'] == "move"):
                # Given player can no longer move and must wait
                changePlayerPhase(self.game, plid, "move", "waiting")

                # When all players ready AUTO move to combat phase
                if areAllPlayersInPhase(self.game, "waiting"):
                    self.game['state']['phase'] = "combat"
                    changeAllPlayerPhase(self.game, "waiting", "combat")

            elif (self.game['state']['phase'] == "combat"):
                # Given player finished submitting orders must wait
                changePlayerPhase(self.game, plid, "combat", "waiting")

                # When all players ready AUTO move to ... something
                # damage selection phase if there was combat
                # end turn if there wasn't
                if areAllPlayersInPhase(self.game, "waiting"):
                    if (self.game['orders']):
                        resolveCombat(self, self.game, self.game['orders'])
                        self.game['state']['phase'] = "damageselection"
                        changeAllPlayerPhase(self.game, "waiting",
                                             "damageselection")
                    else:
                        # Skip "SystemShipRearrangement"
                        # Start turn sequence over again
                        # Collect build points, Check victory conditions

                        harvest(self.game)

                        winner = checkForVictory(self.game)
                        if (winner):
                            self.game['state']['phase'] = "victory"
                            changeAllPlayerPhase(self.game, "waiting", "loser")
                            changePlayerPhase(self.game, winner, "loser",
                                              "winner")
                            self.log(
                                "Admiral " +
                                dataModel.playerNameGet(self.game, winner) +
                                " is victorious")
                        else:
                            self.game['state']['phase'] = "build"
                            changeAllPlayerPhase(self.game, "waiting", "build")

                # What if there is no combat? Probably go on to build
                # self.game['state']['phase'] = "build"

            elif (self.game['state']['phase'] == "damageselection"):

                # Given player finished allocating damage to ships
                # Are they being honest?
                isHonest = True
                for ship in self.game['objects']['shipList']:
                    print(" ship name ", ship['name'], " dam ", ship['damage'])
                    if (ship['owner'] == plid) and (ship['damage'] > 0):
                        isHonest = False
                        break
                if (isHonest):
                    changePlayerPhase(self.game, plid, "damageselection",
                                      "waiting")
                else:
                    self.log(
                        dataModel.playerNameGet(self.game, plid) +
                        " Still has damage to allocate")

                # When all players ready AUTO move to the next round of combat
                if areAllPlayersInPhase(self.game, "waiting"):
                    self.game['state']['phase'] = "combat"
                    changeAllPlayerPhase(self.game, "waiting", "combat")

                    # Erase any existing orders. They no longer have any use
                    self.game['orders'] = {}

            # UNUSED? FIXME
            elif (self.game['state']['phase'] == "battle"):
                # Given player can no longer give orders and must wait
                # When all players ready AUTO move to damageSelection phase
                # or resolve combat phase? Is there such a phase?
                self.game['state']['phase'] = "damageselection"
            else:
                print("GServer:", "Invalid phase for 'ready'")
                assert (False)

        elif cmdStr == 'moveship':
            # Input? ShipID, new location of ship? Movement vector?
            # Is it legal to move? (Proper turn sequence. Valid location on
            # map? Currently in combat? Does move cause combat? (meaning ship
            # halts immediately))
            # Deduct movement from ship
            name = cmd['name']
            x = cmd['x']
            y = cmd['y']

            assert (self.game['state']['phase'] == "move")

            ship = dataModel.findShip(self.game, name)
            if (ship is None):
                print("GServer:", "error: Ship not found", name)
                return False

            si, sj, sk = ijk.XYtoIJK(x, y)
            fi, fj, fk = ijk.XYtoIJK(ship['location']['x'],
                                     ship['location']['y'])
            delta = int((abs(si - fi) + abs(sj - fj) + abs(sk - fk)) / 2)

            #the above only works if no warplines are involved
            #if they go to one of these locations, it only costs one
            warpEnds = dataModel.getWarpLineEnd(self.game,
                                                ship['location']['x'],
                                                ship['location']['y'])
            if [x, y] in warpEnds:
                delta = 1

            print("GServer:", " delta", delta, ship['location']['x'],
                  ship['location']['y'], x, y)
            #can we actually move this far?
            if (delta <= ship['moves']['cur']):
                self.log(
                    dataModel.playerNameGet(self.game, cmd['plid']) +
                    " Moved the '" + name + "' from (" +
                    str(ship['location']['x']) + "," +
                    str(ship['location']['y']) + ")" + " to (" + str(x) + "," +
                    str(y) + ")")
                ship['location']['x'] = x
                ship['location']['y'] = y
                ship['moves']['cur'] = ship['moves']['cur'] - delta

            #are there any system ships stored on this ship?
            #TODO: make sure we don't move too many ships
            for carried_name in ship['carried_ships']:
                #all we have is the name. We need to find the actual ship object in the data model
                carried_ship = dataModel.findShip(self.game, carried_name)
                #update the position of the carried ship
                carried_ship['location']['x'] = x
                carried_ship['location']['y'] = y

            #now we start a battle, if we can.
            #Is there anything here that can trigger a battle?
            for otherShip in self.game['objects']['shipList']:
                if otherShip['name'] != name:
                    if otherShip['location']['x'] == x and otherShip[
                            'location']['y'] == y:
                        if otherShip['owner'] != ship['owner']:
                            ship['moves']['cur'] = 0
                            #if we want wierd simultaneous movement, both ships stop
                            otherShip['moves']['cur'] = 0
                            #set a flag, or have everyone else figure it out for themselves?

        elif cmdStr == 'loadship':
            #this is as simple as can be.
            #find both ships, add the name of 1 to the carried list of 2
            ship = dataModel.findShip(self.game, cmd['shipName'])
            mother = dataModel.findShip(self.game, cmd['motherName'])
            #are these guys in the same square
            if ship['location']['x'] == mother['location']['x'] and ship[
                    'location']['y'] == mother['location']['y']:
                mother['carried_ships'].append(ship['name'])
                self.log(
                    dataModel.playerNameGet(self.game, cmd['plid']) +
                    " loaded the '" + cmd['shipName'] + " onto the '" +
                    cmd['motherName'])

        elif cmdStr == 'unloadship':
            #this is as simple as can be.
            #find the mother, and remove the name of the first ship
            mother = dataModel.findShip(self.game, cmd['motherName'])
            #are these guys in the same square
            mother['carried_ships'].remove(cmd['shipName'])
            self.log(
                dataModel.playerNameGet(self.game, cmd['plid']) +
                " unloaded the '" + cmd['shipName'] + " from the '" +
                cmd['motherName'])

        elif cmdStr == 'loadcargo':
            #this is as simple as can be.
            #find both ships, add the name of 1 to the carried list of 2
            ship = dataModel.findShip(self.game, cmd['shipName'])
            star = dataModel.findObjectsInListAtLoc(
                self.game['objects']['starList'], ship['location']['x'],
                ship['location']['y'])
            base = dataModel.findObjectsInListAtLoc(
                self.game['objects']['starBaseList'], ship['location']['x'],
                ship['location']['y'])

            if base != None:
                target = base
            else:
                target = star
            shipment = int(cmd['shipment'])
            #are these guys in the same square
            if ship['location']['x'] == target['location']['x'] and ship[
                    'location']['y'] == target['location']['y']:
                target['BP']['cur'] -= shipment
                ship['Hauled'] += shipment
                if (shipment > 0):
                    action = "loading"
                else:
                    action = "unloading"
                self.log(
                    dataModel.playerNameGet(self.game, cmd['plid']) + ":" +
                    ship['name'] + " " + action + " at " + target['name'])

        elif cmdStr == 'combatorders':  # Per ship? All ships?
            # A combat instruction
            # Check for proper state. Are there existing orders?
            # Have all ships in combat been given orders?
            # Have all opponents ships in *this* combat been given orders?
            # Input? ShipID, combat command (fire, move, shields ...)
            # TODO many more parameters

            plid = cmd['plid']
            battleOrders = cmd['battleOrders']
            print("battleOrders:", battleOrders)

            assert (self.game['state']['phase'] == "combat")

            #Every player gives a list of orders, for all ships involved in a
            #Conflict. Once both players have sent orders, we start processing.

            self.game['orders'][plid] = battleOrders

            # Set a flag for every ship that is RETREATing.
            # This flag assumes the retreat was successful.
            # Prove it false. When another ship stops
            # you from succeeding the other ship will turn the
            # flag off.
            for myShip, shipOrders, in battleOrders.items():
                myTactic = shipOrders['tactic'][0]
                print("order for ", myShip, myTactic)
                if (myTactic == 'RETREAT'):
                    ship = dataModel.findShip(self.game, myShip)
                    ship['damage'] = -1

            # When all players ready (have submitted orders)
            # AUTO move to damageselection phase
            # When all damage has been selected ... by all players ...
            # move to battle .... or retreat ... or combat over ... or next
            # battle?

        elif cmdStr == 'acceptdamage':
            # Deduct combat damage
            # Input? ShipID, damage deducted from each component
            # Did they deduct enough damage?
            # Do they have more ships with damage to deduct?
            # TODO many more parameters
            # A ship that has been destroyed should be removed
            # (perhaps moved to a "dead" list)

            plid = cmd['plid']
            newShip = cmd['ship']
            print("ship update:", newShip['name'], newShip)
            assert (self.game['state']['phase'] == "damageselection")

            # maybe findShip could return the index too?
            # lookup = dataModel.findShip(self.game, newShip['name'])
            for i, ship in enumerate(self.game['objects']['shipList']):
                if ship['name'] == newShip['name']:
                    index = i
                    break

            assert (index is not None)
            if (newShip['damage'] > 0):
                # the damage must have been more than the ship
                # could take; therefore, destroy it.
                self.log("The '" + newShip['name'] + " Exploded!")
                del self.game['objects']['shipList'][index]
            else:
                # Replace existing ship
                self.game['objects']['shipList'][index] = newShip

        elif cmdStr == 'acceptretreat':
            self.acceptRetreat(cmd['plid'], cmd['ship'], cmd['x'], cmd['y'])

        elif cmdStr == 'savegame':
            # Write file ... who is responsible for game save?
            # I Don't want to load/restore game that is stored on the server
            # ... well, I would like to but that API would be a pain.
            # I'd have to do all the directory I/O work. Remember the game
            # server has no UI. So I would read files and directories
            # off of the server and then let the client navigate, select and
            # choose save/load
            #
            # Given a file name write that file to some save location
            # Mark the game as saved (not dirty)
            # It is possible that the name of the game (name of the file)
            # is already part of the game so you wouldn't need to provide
            # the name.
            #
            # Server does nothing with saveGame. The client must save the game
            print("GServer:", "saveGame")
            self.log("savegame isn't implemented")

        elif cmdStr == 'restoregame':
            # Because games are saved/restored on client ...
            # This would do nothing. Just like saveGame
            #
            # Given the name of a file/game.
            # restore that game overwriting the current game
            # Warn/Error if current game hasn't been saved (is dirty)
            print("GServer:", "restoreGame")
            self.log(
                dataModel.playerNameGet(self.game, cmd['plid']) +
                " Restored a saved game")
            self.game = cmd['game']

        elif cmdStr == 'listgames':
            # Because games are saved/restored on client ...
            # This would do nothing. Just like saveGame
            #
            # List all of the saved games
            print("GServer:", "listGames")
            self.log("listgames isn't implemented")

        elif cmdStr == 'loadgame':
            # Offer to save current game?
            # Bring up selection dialog
            # load game overwriting existing game
            #
            # Like, newGame check for permission.
            # Input? Would be an entire JSON game
            # We should probably do some kind of validation but
            # this would just be pulling in the JSON and
            # translating it to the dict.
            #
            # Warn/Error if current game hasn't been saved (is dirty)
            print("GServer:", "loadGame")
            self.log("loadgame isn't implemented")

        elif cmdStr == 'playerleave':
            # Player is quitting
            # We could check for permission but I don't think so.
            # This is informational
            # Input? Player name? Some unique player key code for security?
            print("GServer:", "playerLeaving")
            self.log("playerleave isn't implemented")

        else:
            print("GServer:", "Not a legal command '", cmdStr, "'")
            return False

        return True
Пример #5
0
def resolveCombat(logger, game, orders):
    # For testing
    #for ship in game['objects']['shipList']:
    #    ship['damage'] = 5

    print("ALLorders:")
    print(orders)

    # What are the combat orders?
    # Find each combat order.
    # Find target of each order (an order can have multiple targets)
    # Find the orders for each target.
    # Match them up and resolve - so I need a simple function
    # for one v one orders to resolve against the chart

    # Table of orders is:
    # Array of players (dict)
    #    For each player there is an array of ships (dict)
    #       For each ship there is an order
    #           each order can have a unique target
    for player, playerOrders in orders.items():
        for myShip, shipOrders, in playerOrders.items():
            if (not shipOrders):
                print("ERROR:", myShip, "has no orders")
                print("Should assert ... but must fix client")
                continue
            if 'conquer' in shipOrders:
                # This is a change of ownership.
                for baseName in shipOrders['conquer']:
                    logger.log(
                        dataModel.playerNameGet(game, player) + ": conquers " +
                        baseName + " with " + myShip)
                    base = dataModel.findBase(game, baseName)
                    base['owner'] = player
                continue
            pretty = dataModel.prettyOrders(shipOrders)
            logger.log(
                dataModel.playerNameGet(game, player) + ": " + myShip + ": " +
                pretty)
            myPower = shipOrders['beams'][1]
            if (myPower > 0):
                myTactic = shipOrders['tactic'][0]
                myDrive = shipOrders['tactic'][1]
                myTarget = shipOrders['beams'][0]

                figureStuffOut(logger, game, orders, myShip, myPower, myTactic,
                               myDrive, myTarget)

            else:
                for missile in shipOrders['missiles']:
                    myPower = 2
                    myTactic = 'ATTACK'
                    myDrive = missile[1]
                    myTarget = missile[0]
                    if (myDrive > 0):
                        # Need ship to deduct missiles
                        ship = dataModel.findShip(game, myShip)
                        assert (ship)
                        assert (ship['M']['cur'] > 0)
                        ship['M']['cur'] -= 1
                        figureStuffOut(logger, game, orders, myShip, myPower,
                                       myTactic, myDrive, myTarget)