Ejemplo n.º 1
0
    def add_monster(self, name=None, level=None, tolerance=None, location=None, region=None, ai=None):
        #Handle Default Objects
        if not level:
            level = self.paneLevel
        if not tolerance:
            if level == 0:
                tolerance = 0
                level = 1
            else:
                tolerance = 1
        if not location:
            location = Location(self.location, (random.randrange(PANE_X), random.randrange(PANE_Y)))

        ignore_max = True if level > 9 else False

        level = min(level, 9) if name != "Devil" else level
        # print ignore_max
        person = TheoryCraft.getMonster(level=level, name=name, tolerance=tolerance, ignoreMaxLevel=ignore_max)
        person.location = location
        if not region:
            region = Region()
            region("ADD", "CIRCLE", person.location, PANE_Y/4)
        if ai:
            print "add_monster(ai) not implemented"

        person.ai.add("wander", person.movementSpeed, pid=id(person), region=region, move_chance=1.0 / (person.movementSpeed))
        self.person[id(person)] = person
Ejemplo n.º 2
0
    def load_monsters(self, monsters=None):
        '''
        Parameters:
            monsters:   A list of tuples with a monster dehydrated string and location object:
                [("dehydrated_string", Location()), ...]

        '''

        if monsters != None:
            for monster in monsters:
                person = TheoryCraft.rehydrateMonster(monster[0], save=True)
                person.location = monster[1]
                self.person[id(person)] = person
        else:   #TODO: Make this better. We're creating monsters from scratch here
            pass
            random.seed(self.seed + str(self.location) + "load_monsters")
            for i in range(0):
                self.add_monster()
Ejemplo n.º 3
0
    def server_loop(self):
        '''
        Network.py fills SDF.queue with commands from the clients
        server_loop handles them in the general pattern of validating the command, updating the game
        state, and then broadcasting the command to everyone else who needs to act on it.
        '''
        while not self.SDF.queue.empty():
            port, command = self.SDF.queue.get()

            if command.type == "PERSON" and command.action == "REMOVE" and port \
                    and not hasattr(command, 'id'):
                command.id = self.player[port]
            if hasattr(command, 'id') and (command.id in self.person and self.person[command.id].cPane):
                self.CS.handle(port, command)
                continue
            if hasattr(command, 'id') and not (command.type == "PERSON" and command.action in \
                    ["CREATE", "LOAD"]) and command.id not in self.person:
                continue

            ###### CreatePerson ######
            if command.type == "PERSON" and (command.action == "CREATE" or command.action == "LOAD"):
                self.load_pane(command.location.pane)
                if command.action == "LOAD":
                    person = TheoryCraft.rehydratePlayer(command.details)
                elif command.action == "CREATE":
                    person = TheoryCraft.convertFromDetails(command.details)
                person.id = id(person)
                command.id = person.id
                person.ai.startup(self)

                if port:
                    self.player[port] = person.id
                self.person[person.id] = person
                self.pane[command.location.pane].person.append(person.id)
                if port:
                    self.broadcast(Command("UPDATE", "SEED", seed=self.world.seed), command.id)
                    self.broadcast(Command("UPDATE", "TURNTIME", turnTime=self.turnTime), command.id)

                # Send command to each player in the affected pane
                self.broadcast(command, -command.id)

                # Send list of players to the issuing client
                if port:
                    for i in self.pane[command.location.pane].person:
                        if i != command.id:
                            comm = Command("PERSON", "CREATE", id=i, \
                                    location=self.person[i].location, \
                                    details=self.person[i].dehydrate())
                            self.broadcast(comm, port=port)

                    self.send_world_items(command.location, port=port)

            ###### MovePerson ######
            if command.type == "PERSON" and command.action == "MOVE":
                self.load_pane(command.location.pane)

                portal=command.portal if hasattr(command, "portal") else None
                iLoc = command.iLocation if hasattr(command, "iLocation") else None
                if command.id in self.person:
                    if iLoc:
                        self.person[command.id].iLocation = iLoc
                    else:
                        iLoc = self.person[command.id].iLocation

                # If this is a legal move request
                if self.tile_is_open(command.location, pid=command.id, portal=portal, iLoc=iLoc):
                    if not portal:
                        #Check for entities that have a trigger() attribute
                        p = iLoc if iLoc in self.pane else command.location.pane if command.location.pane in self.pane else None
                        if command.location.pane in self.pane and not iLoc:
                            ent_list = self.pane[command.location.pane].get_trigger_entities(command.location)
                        elif iLoc in self.pane:
                            ent_list = self.pane[iLoc].get_trigger_entities(command.location)
                        for entity in ent_list:
                            portal_loc, new_loc = entity.trigger()
                            # print "PORTAL LOCATION: " + str(portal_loc)
                            # self.SDF.queue.put((None, Command("PERSON", "MOVE", id=command.id, portal=entity, iLocation=portal_loc, location=new_loc)))
                            #"SHOP" and command.action == "REQUESTSHOP"
                            if entity.portal_type == Portal.SHOP:
                                self.SDF.queue.put((None, Command("SHOP", "REQUESTSHOP", id=command.id)))

                    # If the origin and destination are in the same pane
                    if self.person[command.id].location.pane == command.location.pane:
                        # Update location and broadcast
                        self.person[command.id].location = command.location
                        self.broadcast(command, -command.id, exclude=True if port else False)
                    else:
                        # Remove person from players' person tables, and pane's person list
                        self.pane[self.person[command.id].location.pane].person.remove(command.id)
                        self.broadcast(Command("PERSON", "REMOVE", id=command.id), -command.id)

                        # Update location in server memory
                        self.person[command.id].location = command.location

                        # Add player to new pane lists and send to clients in the affected pane
                        self.pane[command.location.pane].person.append(command.id)
                        command.action = "CREATE"
                        command.details = self.person[command.id].dehydrate()
                        self.broadcast(command, pane=command.location.pane)

                        # Send list of players to the issuing client
                        if command.id in self.player.values():
                            for i in self.pane[command.location.pane].person:
                                if i != command.id:
                                    comm = Command("PERSON", "CREATE", id=i, \
                                            location=self.person[i].location, \
                                            details=self.person[i].dehydrate())
                                    self.broadcast(comm, command.id)

                            # HANDLE SENDING SPECIFIC PANE THINGS HERE
                            self.send_world_items(command.location, pid=command.id)

                        self.unload_panes()

                    # Check for combat range and initiate combat states
                    if command.id in self.player.values():
                        for person in self.pane[self.person[command.id].location.pane].person:
                            if self.person[command.id].location.in_melee_range( \
                                    self.person[person].location) and \
                                    self.person[person].team == "Monsters":
                                self.CS.startCombat(command.id, person)

                else:
                    if port:
                        command.location = self.person[command.id].location
                        command.details = True
                        self.broadcast(command, port=port)

            ###### RemovePerson ######
            if command.type == "PERSON" and command.action == "REMOVE":
                if command.id in self.person:
                    if port:
                        command.id = self.player[port]
                        del self.player[port]

                    self.pane[self.person[command.id].location.pane].person.remove(command.id)
                    self.broadcast(command, -command.id)
                    del self.person[command.id]
                    self.unload_panes()

            ###### Levelup Player ######
            if command.type == "PERSON" and command.action == "REPLACE":
                newPerson = TheoryCraft.rehydratePlayer(command.player)
                newPerson.location = self.person[command.id].location
                newPerson.id = command.id
                self.person[command.id] = newPerson
                self.broadcast(command, -command.id, exclude=True)

            #### Shop Creation ####
            if command.type == "SHOP" and command.action == "REQUESTSHOP":
                activePlayer = self.person[command.id]
                requestedPane = self.pane[activePlayer.location.pane]
                if self.world.is_town_pane(activePlayer.location):
                    currentShop = None
                    if requestedPane not in self.shops:
                        level = requestedPane.paneLevel
                        currentShop = shop.Shop(level=level)
                        self.shops[requestedPane] = currentShop
                    else:
                        currentShop = self.shops[requestedPane]
                    action = Command("SHOP", "OPEN", id=command.id,
                                     shopLevel=currentShop.level, shopSeed=currentShop.seed)
                    self.broadcast(action, pid=command.id)

            #### Respec ####
            if command.type == "RESPEC" and command.action == "REQUESTRESPEC":
                activePlayer = self.person[command.id]
                if self.world.is_town_pane(activePlayer.location):
                    if activePlayer.ironman:
                        text = "You are on Ironman mode, and are thus too cool to respec!"
                        action = Command("UPDATE", "TEXT", text=text, color='white')
                        self.broadcast(action, pid=activePlayer.id)
                    elif activePlayer.level > 1:
                        oldExp = activePlayer._experience
                        newHero = TheoryCraft.resetPlayerLevel(activePlayer)
                        newHero.location = self.person[command.id].location
                        newHero.id = command.id
                        newHero._experience = oldExp
                        self.person[command.id] = newHero
                        jerky = newHero.dehydrate()

                        # Send the newHero to the client.
                        action = Command("PERSON", "REPLACE", id=command.id, player=jerky)
                        self.broadcast(action, pid=-command.id)

            ###### Get Item / Open Chest ######
            if command.type == "PERSON" and command.action == "BASHCHEST":
                activePlayer = self.person[command.id]
                currentPane = self.pane[activePlayer.location.pane]
                chest, loc = currentPane.get_treasure_chest(activePlayer.location)
                if chest:
                    if chest.locked:
                        success = chest.bash(activePlayer)
                        if success:
                            chest.locked = False
                            text = activePlayer.name + " successfully bashed open a chest."
                            action = Command("UPDATE", "TEXT", text=text, color='lightskyblue')
                            self.broadcast(action, pid=-activePlayer.id)
                        else:
                            text = activePlayer.name + " failed to bash open a chest."
                            action = Command("UPDATE", "TEXT", text=text, color='red')
                            self.broadcast(action, pid=-activePlayer.id)
                    else:
                        text = "No need to bash -- chest is unlocked."
                        action = Command("UPDATE", "TEXT", text=text, color='white')
                        self.broadcast(action, pid=activePlayer.id)
            if command.type == "PERSON" and command.action == "OPEN":
                activePlayer = self.person[command.id]
                currentPane = self.pane[activePlayer.location.pane]
                chest, loc = currentPane.get_treasure_chest(activePlayer.location)
                if chest and chest.locked:
                    picklockSuccess = chest.pickLock(activePlayer)
                    if picklockSuccess:
                        chest.locked = False
                        text = activePlayer.name + " successfully unlocked a chest."
                        action = Command("UPDATE", "TEXT", text=text, color='lightskyblue')
                        self.broadcast(action, pid=-activePlayer.id)
                    else:
                        text = "The chest is locked"
                        if activePlayer.lockpicking > 0:
                            # This is a class that *could* unlock it with more Cunning.
                            text += " and you lack the Cunning to unlock it."
                        action = Command("UPDATE", "TEXT", text=text, color='red')
                        self.broadcast(action, pid=-activePlayer.id)
                    return
                if chest and not chest.locked:
                    inventories = chest.open(self.get_nearby_players(command.id))
                    currentPane.remove_chest(loc)

                    #Notify clients in the affected pane
                    for p, i in self.player.iteritems():    #Replace this with list of players on current pane
                        if self.person[i].location.pane == self.person[command.id].location.pane:
                            #Send animation request...
                            action_animate = Command(type="ENTITY", action="ANIMATE", location=loc)
                            self.broadcast(action_animate, port=p)
                            action_remove = Command(type="CHEST", action="REMOVE", location=loc)
                            self.broadcast(action_remove, port=p)

                            thisPlayer = self.person[self.player[p]]
                            itemList = inventories[thisPlayer]
                            if not itemList:
                                action = Command("UPDATE", "TEXT", text='Chest was empty', color='lightskyblue')
                                self.broadcast(action, port=p)
                            for item in itemList:
                                equipped = False
                                action = None
                                if isinstance(item, int):
                                    action = Command("ITEM", "CREATE", itemIdentifier=item, id=thisPlayer.id)
                                else:
                                    action = Command("ITEM", "CREATE", itemIdentifier=item.identifier, id=thisPlayer.id)
                                self.broadcast(action, port=p)
                                if thisPlayer.shouldAutoEquip(item):
                                    thisPlayer.equip(item)
                                    action = Command("ITEM", "EQUIP", itemIdentifier=item.identifier, id=thisPlayer.id)
                                    self.broadcast(action, port=p)
                                    equipped = True
                                text = ''
                                if isinstance(item, int):
                                    text = 'Found ' + `item` + ' pieces of gold.'
                                else:
                                    text = 'Found item: ' + item.displayName
                                if equipped:
                                    text ='Found and equipped item: ' + item.displayName
                                action = Command("UPDATE", "TEXT", text=text, color='lightskyblue')
                                self.broadcast(action, port=p)
                                thisPlayer.refreshAP()
                            action = Command("PERSON", "UPDATE", id=thisPlayer.id, AP=thisPlayer.AP, totalAP=thisPlayer.totalAP)
                            self.broadcast(action, port=p)
Ejemplo n.º 4
0
    def __init__(self, pane, pane_focus, monster, num_players):
        '''
        A subpane of the current pane.  It will contain 10x6 of the original
        tiles which turn into 3x3 grids on the CombatPane.
        Dimensions are 30x18 (there will be a border around the pane)
        Member Variables:
            pane_focus:     a Location object with the current pane and the
                            tile of the monster of focus.  This is the location
                            from which we entered combat.  If this location is
                            far enough away from a border, sub pane will be centered
                            from here.

        '''
        super(CombatPane, self).__init__(pane.seed, (0,0), False)
        self.objects = dict()           #Fixed combat/overworld passability bug
        self.paneCharacterLevel = 1

        self.open_region = Region("SQUARE", Location(self.location, (0, 0)), Location(self.location, (PANE_X-1, PANE_Y-1)))

        loc_x = pane_focus.tile[0]
        loc_y = pane_focus.tile[1]

        dx_min = min(loc_x - 5, 0)     #yields 0 if far enough away from edge,
        dy_min = min(loc_y - 3, 0)     #and negative if too close
        # print "dx_min, dy_min: " + str(dx_min) + ", " + str(dy_min)
        dx_max = max(loc_x - 26, 0)    #yields 0 if far enough away from edge,
        dy_max = max(loc_y - 14, 0)    #and positive if too close
        # print "dx_max, dy_max: " + str(dx_max) + ", " + str(dy_max)
        dx = dx_min + dx_max - 1
        dy = dy_min + dy_max - 1
        loc_x -= dx
        loc_y -= dy

        self.focus_location = Location(PANE_X/2 + dx*3, PANE_Y/2 + dy*3)
        fx = max(0, min(PANE_X - 1, self.focus_location.tile[0]))
        fy = max(0, min(PANE_Y - 1, self.focus_location.tile[1]))
        self.focus_location = Location(fx, fy)

        i = 2
        for x in range(loc_x-4, loc_x+6):
            j = 2
            for y in range(loc_y-2, loc_y+4):
                # print "(" + str(x) + ", " + str(y) + ")"
                if (x,y) in pane.objects:
                    self.add_zoomed_obstacle((i, j), pane.objects[(x,y)])
                    #Remove areas where there are obstacles
                    self.open_region("SUB", "SQUARE", Location(self.location, (i-1, j-1)), Location(self.location, (i+1, j+1)))
                j+=3
            i+=3

        self.load_background_images()
        if monster:
            monsters = TheoryCraft.generateMonsterGroup(monster, numberOfPlayers=num_players)
            self.place_monsters(monsters, self.focus_location)
            # for id, monster in self.person.iteritems():
                # loc = monster.location
                # self.traps_region("SUB", "SQUARE", loc, loc)
            #Remove areas where players can enter
            for (x, y) in CombatPane.CombatEntrances:
                self.open_region("SUB", "SQUARE", Location(self.location, (x-1, y-1)), Location(self.location, (x+1, y+1)))

            self.place_traps(num_players)