Exemple #1
0
    def getImage(self, zoom=None, x=None, y=None, z=None, callback=None):
        try:
            # can't do anything if they don't send the full address
            if zoom == None or x == None or y == None or z == None:
                msg = "model-server.getImage: Need full parameters"
                raise khopeshpy.exceptions.JSONException(msg)

                # first check that there really isn't an image
            imageName = "img-world/zoom%d-%dx-%dy-%dz.png" % (int(zoom), int(x), int(y), int(z))
            if os.path.isfile(imageName):
                # file already exists, either it was created by another handler or somebody's mucking around
                # just return the image name
                return self.jsonpWrap(imageName, callback)

            conn = db.connect()

            # otherwise we have to pull it from the database
            if int(zoom) == 0:
                c = db.levelData.columns
                statment = db.select(
                    [c.baseImage], (c.cellIdX == int(x)) & (c.cellIdY == int(y)) & (c.levelIdZ == int(z))
                )

                result = conn.execute(statment)
                level = result.fetchone()
                result.close()

                if level == None:
                    ret = "img-src/void.png"
                else:
                    ret = level["baseImage"]
            elif int(zoom) == 1:
                c = db.cellData.columns
                statment = db.select([c.cellImage], (c.cellIdX == int(x)) & (c.cellIdY == int(y)))

                result = conn.execute(statment)
                cell = result.fetchone()
                result.close()

                if cell == None:
                    ret = "img-src/void.png"
                else:
                    ret = cell["cellImage"]
            else:
                # note: all zoomed images above level 1 should have been pregenerated
                ret = "img-src/void.png"

            conn.close()

            return self.jsonpWrap(ret, callback)
        except khopeshpy.exceptions.JSONException as e:
            return self.errorHandler(e.msg)
Exemple #2
0
    def commandNext(self):
        """
		find the next command and set it as the current one
		"""

        # get the next command
        c = db.avatarCmdQueue.columns
        statement = (
            db.select([db.avatarCmdQueue], (c.avatarId == self.avatarId) & (c.done == False))
            .order_by(c.sequence.asc())
            .limit(1)
        )
        result = self.conn.execute(statement)
        row = result.fetchone()
        result.close()

        if row == None:
            # add a default one if there is none
            self.addCommandDefault()
        else:
            if self.mapPreCommand(row["command"])(row["data"]) != False:

                # only set the command if the precommand succeeded
                self.commandSet(row["animalCmdId"], row["timeExpected"])
            else:
                # otherwise mark the command as failed and move onto the next one
                self.markCmdFinished(row["eventId"], False)
                self.commandNext()
Exemple #3
0
 def commandNext(self):
     '''
     find the next command and set it as the current one
     '''
     
     #get the next command
     c = db.animalCmdQueue.columns
     statement = db.select([db.animalCmdQueue], (c.animalId == self.animalId) 
         & (c.done == False)).order_by(c.sequence.asc()).limit(1)
     result = self.conn.execute(statement)
     row = result.fetchone()
     result.close()
     
     if row == None:
         #add a default one if there is none
         self.addCommandDefault()
     else:
         #quick point: preCommands can fail (an animal is already being attacked)
         #    how are we going to handle this?
         #two possibilities for failure, move on to the next command or invalidate
         #    all the commands
         
         
         ##expecting problems with the data field, we're using the same format for
         ## direct calls as for calls from the database
         #scratch that, removed the direct call and replaced it with a call to this
         # function
         if(self.mapPreCommand(row['command'])(row['data']) != False):
             #print 'precommand failed: ' + row['command']
             #only set the command if the precommand succeeded 
             self.commandSet(row['animalCmdId'], row['timeExpected'])
         else:
             #otherwise mark the command as failed and move onto the next one
             self.markCmdFinished(row['eventId'], False)
             self.commandNext()
Exemple #4
0
 def register(self, username = None, password = None):
     if username == None or password == None:
         msg = "User.Control.register needs both a username and a password"
         print msg
         return (-1,msg)
     
     #first we have to check if a user with that name already exists
     c = db.userData.columns
     statment = db.select([db.userData], (c.username == username))
     
     conn = db.connect()
     result = conn.execute(statment)
     row = result.fetchone()
     result.close()
     conn.close()
     
     if row != None:
         self.valid = False
         self.loggedIn = False
         msg = "Player with username: %s already exists" % (username)
         print msg
         return (-1, msg)
     else:
         conn = db.connect()
         ins = db.userData.insert().values(username = username, password = password)
         result = conn.execute(ins)            
         conn.close()
         
         #cheap way for now
         return self.login(username, password)
	def pollEventQueue(self):
		trans = self.conn.begin()
		try:
			c1 = db.animalEventQueue.columns
			c2 = db.animalCmdQueue.columns
			#find a event that has ended in the eventQueue
			statement = db.select([c1.eventId, c2.animalCmdId, c2.animalId, c2.timeExpected, c2.timeStarted, c2.command, c2.data],\
				(c1.eventEnd < time.time()) & (c1.eventId == c2.eventId)).limit(1)
			#print statement
			result = self.conn.execute(statement)
			row = result.fetchone()
			result.close()
			
			if row == None:
				trans.rollback()
				return False
			else:
				row = dict(row)
				
				c = db.animalEventQueue.columns
				#remove the event from the queue
				up = db.animalEventQueue.delete().where(c.eventId == (row['eventId']))
				result = self.conn.execute(up)
			
				#only if we've managed to grab an event
				self.processEvent(row)
					
				trans.commit()
				return True
		except Exception as e:
			print e
			print "rolling back"
			trans.rollback()
			raise
	def pollBroken(self):
		c = db.animalData.columns
		d = db.animalEventQueue.columns
		statement = db.select([db.animalData], db.not_(c.eventId.in_(db.select([d.eventId],None)))).limit(1)
		result = self.conn.execute(statement)
		row = result.fetchone()
		result.close()
		
		if row == None:
			return False
			
		else:
			row = dict(row)
			self.broken(row)
			
			return True
Exemple #7
0
    def commandNextDefault(self):
        """
		find the next command and set it as the current one
		(this version is only used by addCommandDefault
		"""

        # get the next command
        c = db.avatarCmdQueue.columns
        statement = (
            db.select([db.avatarCmdQueue], (c.avatarId == self.avatarId) & (c.done == False))
            .order_by(c.sequence.asc())
            .limit(1)
        )
        result = self.conn.execute(statement)
        row = result.fetchone()
        result.close()

        if row == None:
            raise Exception("addCommandDefault() did not add any commands")
        else:
            if self.mapPreCommand(row["command"])(row["data"]) != False:
                # only set the command if the precommand succeeded
                self.commandSet(row["animalCmdId"], row["timeExpected"])
            else:
                print "Command: " + row["command"] + " Data: " + row["data"]
                raise Exception("addCommandDefault() added a command that could not be executed")
	def pollBrokenAvatars(self):
		c = db.avatarData.columns
		d = db.avatarEventQueue.columns
		statement = db.select([db.avatarData], c.eventId != db.select([d.eventId],d.eventId == d.eventId)).limit(1)
		result = self.conn.execute(statement)
		row = result.fetchone()
		result.close()
		
		if row == None:
			return False
			
		else:
			row = dict(row)
			self.brokenAvatar(row)
			
			return True
Exemple #9
0
 def preCommandAttackCooldown(self, preyId):
     #check the lock
     c = db.animalData.columns
     statement = db.select([db.animalData], c.animalId == preyId)
     result = self.conn.execute(statement)
     row = result.fetchone()
     result.close()
     
     if row == None:
         #prey no longer exists
         return False
     elif row['attackerId'] == self.animalId:
         #we're already the attacker
         return True
     elif row['attackerId'] == None:
         #lock the prey as ours
         c = db.animalData.columns
         up = db.animalData.update().where((c.animalId == preyId)).\
             values(attackerId = self.data['animalId'])
         self.conn.execute(up)
         
         return True
     else:
         #the prey already has an attacker
         return False
Exemple #10
0
    def login(self, username = None, password = None):
        if username == None or password == None:
            msg = "user.Control.login needs both a username and a password"
            print msg
            return (-1, msg)
            
        c = db.userData.columns
        statment = db.select([db.userData], (c.username == username) & (c.password == password))
        
        conn = db.connect()
        result = conn.execute(statment)
        row = result.fetchone()
        result.close()
        conn.close()

        if row == None:
            self.loggedIn = False
            msg = "User failed to login with username: %s password: %s" % (username, password)
            print msg
            return (-1, msg)
        else:
            self.loggedIn = True
            self.userId = row['userId']
            self.pullData()
            return (self.userId, 'Ok')
	def pollEventQueue(self):
		trans = self.conn.begin()
		try:
			c1 = db.avatarEventQueue.columns
			c2 = db.avatarCmdQueue.columns
			#find a event that has ended in the eventQueue
			statement = db.select([c1.eventId, c2.avatarCmdId, c2.avatarId, c2.timeExpected, c2.timeStarted, c2.command, c2.data],\
				(c1.eventEnd < time.time()) & (c1.eventId == c2.eventId)).limit(1)
			
			result = self.conn.execute(statement)
			rows = result.fetchall()
			result.close()
			
			good = False
			for row in rows:
				
				c = db.avatarEventQueue.columns
				#remove the event from the queue
				up = db.avatarEventQueue.delete().where(c.eventId == (row['eventId']))
				result = self.conn.execute(up)
				
				#make sure we were able to delete the row
				if result.rowcount == 1:
					#only if we've managed to grab an event
					self.processEvent(row)
					good = True
					
			trans.commit()
			return good
		except Exception as e:
			print e
			print "rolling back"
			trans.rollback()
			raise
Exemple #12
0
 def preCommandScavenge(self, preyId):
     '''
     What to do right before a scavenge command is set
     '''
     
     #check that the prey.attackerId is free
     
     c = db.animalData.columns
     statement = db.select([db.animalData], c.animalId == preyId)
     result = self.conn.execute(statement)
     row = result.fetchone()
     result.close()
     
     
     #TODO: clean this up
     if row == None:
         #prey no longer exists
         #print "prey id: " + preyId + "no longer exists"
         #raise Exception("prey no longer exsists")
         return False
     elif row['attackerId'] == self.animalId:
         #we're already the attacker
         #print "success: we're the attacker"
         return True
     elif row['attackerId'] == None:
         #print "setting self as the atacker"
         #lock the prey as ours
         c = db.animalData.columns
         up = db.animalData.update().where((c.animalId == preyId)).\
             values(attackerId = self.data['animalId'])
         self.conn.execute(up)
     else:
         #print "prey's attacker is: " + repr(row['attackerId'])
         #the prey already has an attacker
         return False
Exemple #13
0
 def selectScavengePrey(self, lvl):
     '''
     Select the best animal to feed on
     we want to find the animal from which we'll find the most food in the time
     alotted    this can either be limited by the amount of biomass, or by the 
     animal's speed of eating
     '''
     maxBiomass = 0.0
     maxPrey = None
     
     #get all dead animals in the passed level
     c = db.animalData.columns
     statement = db.select([db.animalData], (c.animalX == lvl.cellIdX)\
         & (c.animalY == lvl.cellIdY) & (c.animalZ == lvl.levelIdZ)\
         & (c.state == base.States.DEAD) & ((c.attackerId == None) | (c.attackerId == self.animalId)))
     result = self.conn.execute(statement)
     rows = result.fetchall()
     result.close()
     
     #print "prey: " + repr(self.preySpecies)
     
     #select the best one to scavange
     # note: we could check here if we can break early
     
     for row in rows:
         #print repr(rows)
         #prey = base.Event(row = row, conn = self.conn)
         prey = top.eventAnimalFactory(self.conn, row = row)
         
         #print "species: " + repr(prey.species)
         
         if prey.species in self.preySpecies:
             #print "prey is a prey species"
             biomass = (prey.growth + prey.stored) * self.scavengeEfficiency
             
             if biomass > maxBiomass:
                 maxBiomass = biomass
                 maxPrey = prey
         #else:
             #print "prey is not a prey species"
                 
                 
                 
     #can't eat more than there is room for
     room = self.unprocessedMax - self.unprocessed #room in it's stomach
     amount = min(room, maxBiomass)
     time = amount / self.scavengeRate
     
     if maxBiomass > room:
         maxBiomass = room
     
     if maxBiomass < 0.01:
         return False
     else:
         return (maxPrey, maxBiomass, time)
Exemple #14
0
 def pullData(self):
     #NOTE: selecting old family id's may be a problem
     if self.familyId > 0:
         c = db.familyData.columns
         statment = db.select([db.familyData], c.familyId == self.familyId)
         
         conn = db.connect()
         result = conn.execute(statment)
         row = result.fetchone()
         result.close()
         conn.close()
         
         if row == None:
             msg = "No record found for a family with familyId: %d" % (self.familyId)
             raise Exception(msg)
         
         self.data.update(dict(row))
         self.valid = True
         self.userId = self.data['userId']
     elif self.userId > 0:
         c = db.familyData.columns
         statment = db.select([db.familyData], (c.userId == self.userId) & (c.state == States.ALIVE))
         
         conn = db.connect()
         result = conn.execute(statment)
         row = result.fetchone()
         result.close()
         conn.close()
         
         if row == None:
             msg = "No record found for a living family for userId: %d" % (self.userId)
             raise Exception(msg)
         
         self.data.update(dict(row))
         self.valid = True
         self.familyId = self.data['familyId']
     else:
         msg = "Family objects must be initialized with a valid a userId or a valid familyId"
         raise Exception(msg)        
Exemple #15
0
    def pullData(self):
        c = db.userData.columns
        statment = db.select([db.userData], c.userId == self.userId)
        
        result = self.conn.execute(statment)
        row = result.fetchone()
        result.close()

        if row == None:
            msg = "user.Model.pullData: Did not find userData record for id: %d, exiting." % (self.userId)
            raise exceptions.JSONException(msg)
        
        self.data.update(dict(row))
Exemple #16
0
def getStartingLocation(conn):
    c = db.cityData.columns
    statment = db.select([db.cityData], c.cityStarter == True)
    
    result = conn.execute(statment)
    row = result.fetchone()
    result.close()
    
    #just get the first one now, select one randomly later
    if row != None:
        return (row['cityStartX'],row['cityStartY'],row['cityStartZ'],)
    else:
        return (-1,-1,-1)
	def pollIdle(self):
		c = db.animalData.columns
		statement = db.select([db.animalData], c.eventId == None).limit(1)
		result = self.conn.execute(statement)
		row = result.fetchone()
		result.close()
		
		if row == None:
			return False
		else:
			row = dict(row)
			self.idle(row)
			
			return True
Exemple #18
0
def createNew(conn, userId, familyName, avatarName):    
    #first we have to check if a family with that name already exists
    c = db.familyData.columns
    statment = db.select([db.familyData], (c.name == familyName))
    
    result = conn.execute(statment)
    row = result.fetchone()
    result.close()
    
    if row != None:
        msg = "Family with name: %s already exists" % (familyName)
        print msg
        return (-1, msg)
    else:
        #Avatar names aren't unique so we don't have to check that.
        #This is a new family so we don't have to worry about the
        # second check if an avatar with that name already exits        
        
        ins = db.familyData.insert()\
            .values(
                userId = userId, 
                name = familyName, 
                state = States.ALIVE
            )
            
        result = conn.execute(ins)
        
        familyId = result.last_inserted_ids()[0]
        
        #now that we a family id create the avatar
        #how to pick the location?
        # thinking we'll set certain cities to be starter cities (their's 
        # currently a flag to do that....)
        #woo! cities are defined over a number of cells, just select a random one? 
        avatar.createNew(conn, userId,  familyId, avatarName, city.getStartingLocation(conn))
        return (familyId, "Ok")
    
    
        
        
        

        

        
        
        
        
        
Exemple #19
0
    def getPlayerList(self, callback=None):
        c = db.userData.columns
        statment = db.select([c.userId, c.username], 1)

        conn = db.connect()
        result = conn.execute(statment)
        rows = result.fetchall()
        result.close()
        conn.close()

        ret = {}
        for row in rows:
            ret[row.userId] = row.userName

        return self.jsonpWrap(ret, callback)
Exemple #20
0
def getControlAvatars(conn, familyId):
    
    c = db.avatarData.columns
    statment = db.select([db.avatarData], c.familyId == familyId)
    result = conn.execute(statment)
    rows = result.fetchall()
    result.close()
    
    ret = {}
    for row in rows:
        ret[row['avatarId']] =  controlAvatarFactory(conn, row = row)
        
    return ret
        
    
Exemple #21
0
    def getNextSequenceNumber(self):
        """
		find the sequence number to add this command to the end of the command queue
		"""

        c = db.avatarCmdQueue.columns
        statement = db.select([db.avatarCmdQueue], (c.avatarId == self.avatarId)).order_by(c.sequence.desc()).limit(1)
        result = self.conn.execute(statement)
        row = result.fetchone()
        result.close()

        if row == None:
            return 1
        if row["sequence"] == None:
            return 1
        else:
            return row["sequence"] + 1
Exemple #22
0
 def getNextSequenceNumber(self):
     '''
     find the sequence number to add this command to the end of the command queue
     '''
     
     c = db.animalCmdQueue.columns
     statement = db.select([db.animalCmdQueue], (c.animalId == self.animalId))\
         .order_by(c.sequence.desc()).limit(1)
     result = self.conn.execute(statement)
     row = result.fetchone()
     result.close()
     
     if row == None:
         return 1
     if row['sequence'] == None:
         return 1
     else:
         return (row['sequence'] + 1)
Exemple #23
0
	def preCommandHunt(self, preyId):
		'''
		What to do right before a hunt command is set
		'''
		
		#check that the prey.attackerId is free
		c = db.animalData.columns
		statement = db.select([db.animalData], c.animalId == preyId)
		result = self.conn.execute(statement)
		row = result.fetchone()
		result.close()
		
		if row == None or row['state'] == base.States.DEAD:
			#prey no longer exists, or is dead
			return False
		elif row['attackerId'] != None and row['attackerId'] != self.data['animalId']:
			#has has an attacker who isn't us
			return False
			
		#do the actual attack
		#from khopeshpy.animals import top
		#prey = top.event(animalId = preyId, conn = self.conn)
		#prey = base.Event(animalId = preyId, conn = self.conn)
		prey = top.eventAnimalFactory(self.conn, row = row)
		
		#first, attacker gets first strike so do that first
		self.stamina -= self.attackStaminaCost
		
		atkStr = self.attackStrength(self.health)
		prey.attacked(self.animalId, atkStr)
		
		dt = self.attackCooldown(self.stamina)
		self.addCommandAttackCooldown(dt, preyId)
		
		#two options
		if prey.health > 0.0:
			#print 'the prey lives'
			#any code to break off the attack would go here
			#do we need to be able to set this as un-interruptable?
			self.addCommandHunt(preyId, 0.0)
		else:
			#print 'the prey is dead'
			#set it to scavange the prey for a token amount of time
			self.addCommandScavenge(preyId, 1.0)
Exemple #24
0
    def pullData(self):
        if self.userId <= 0:
            msg = "pullData needs a userId greater than 0, id was: %d" % (self.userId)
            raise Exception(msg)
        
        c = db.userData.columns
        statment = db.select([db.userData], c.userId == self.userId)
        
        conn = db.connect()
        result = conn.execute(statment)
        row = result.fetchone()
        result.close()
        conn.close()

        if row == None:
            msg = "pullData did not find userData record for id: %d" % (self.userId)
            raise Exception(msg)
        
        self.data.update(dict(row))
        self.valid = True
Exemple #25
0
def eventAnimalFactory(conn, animalId = None, row = None):
    '''
    Return the correct event animal object if it exists in the 
        registered event animal list
    ''' 
    if animalId != None:
        c = db.animalData.columns
        statment = db.select([db.animalData], c.animalId == animalId)
        
        result = conn.execute(statment)
        row = result.fetchone()
        result.close()
        
        if row == None:
            msg = "No record found for an animal with animalId: %d" % (animalId)
            raise Exception(msg)
        #fall though now that row is populated
        
    if row['animalSpecies'] in eventAnimalList:
        return eventAnimalList[row['animalSpecies']](conn, row)
    else:
        msg = "Unknown species: " + repr(row['animalSpecies'])
        raise Exception(msg)
Exemple #26
0
 def commandNextDefault(self):
     '''
     find the next command and set it as the current one
     (this version is only used by addCommandDefault
     '''
     
     #get the next command
     c = db.animalCmdQueue.columns
     statement = db.select([db.animalCmdQueue], (c.animalId == self.animalId) 
         & (c.done == False)).order_by(c.sequence.asc()).limit(1)
     result = self.conn.execute(statement)
     row = result.fetchone()
     result.close()
     
     if row == None:
         raise Exception("addCommandDefault() did not add any commands")
     else:
         if(self.mapPreCommand(row['command'])(row['data']) != False):
             #print 'precommand failed: ' + row['command']
             #only set the command if the precommand succeeded 
             self.commandSet(row['animalCmdId'], row['timeExpected'])
         else:
             print "Command: " + row['command'] + " Data: " + row['data']
             raise Exception("addCommandDefault() added a command that could not be executed")
Exemple #27
0
 def attacked(self, attackerId, atkStrength):
     '''
     Called by an attacker when it attacks us
     '''
     #being attacked is an interrupt
     
     #forage: cancel everything
     #attack cooldown.... add it to the list of attackers?
     #    defending container needs to handle multiple attackers?
     #        Not yet since we put in the lock, but we may want to account for it anyway
     #move: cancled
     #idle: cancled
     #sleep: cancled
     #dead: wtf
     
     #stack on the attacked command to then end, then delete all interruptable
     # commands
     
     #set the attacker
     self.data['attackerId'] = attackerId
     
     #update our health, can adjust later here for defense
     self.data['health'] -= atkStrength
     
     if self.data['health'] < 0.01:
         self.data['state'] = base.States.DEAD
         self.deathCleanup()
     else:
         #add the defend command to the end of the queue
         self.addCmdQueue('defend', 0.0, attackerId)
         
         #TODO: generate this automatically
         interruptibleCommands = ['forage', 'move', 'idle', 'sleep']
         
         
         #TODO: make sure this is producing the sql we want
         #remove all interruptible comands
         c = db.animalCmdQueue.columns
         up = db.animalCmdQueue.update()\
             .where((c.animalId == self.animalId) & (c.done == False) & c.command.in_(interruptibleCommands))\
             .values(active = False, done = True, successful = False, timeEnded = time.time()) 
         result = self.conn.execute(up)
         
         #pull up the current command, current is different because it has to be
         #    removed from the eventQueue:
         eventId = self.data['eventId']
         
         c = db.animalCmdQueue.columns
         statement = db.select([db.animalCmdQueue], c.eventId == eventId)
         result = self.conn.execute(statement)
         row = result.fetchone()
         result.close()
         
         if row == None:
             #...? something went wrong
             raise Exception('unknown state')
         
         if row['command'] in interruptibleCommands:
             c = db.animalEventQueue.columns
             up = db.animalEventQueue.delete().where(c.eventId == eventId)
             result = self.conn.execute(up)            
             
             #NOTE: need to adjust stats for unfinished command,
             # also we sould finish up anything we can on the interrupted command
             #self.updateStats(dt)
         
             #execute the next command only if we removed the current command
             self.commandNext()
         
     self.pushData()
Exemple #28
0
    def addCommandDefault(self):
        """
		search for the best command for the animal and add it to the command queue
		"""

        # death check is done here
        if self.data["state"] == States.DEAD:
            cmdId, dt = self.actionMap["dead"]["add"](dt=1.0)
            # being dead has no preCommand
            self.commandSet(cmdId, dt)
            return

            # get the levels we have access to
        c = db.levelData.columns
        # unlike animals, avatars won't automatically move
        statement = db.select(
            [db.levelData],
            (c.cellIdX == self.position[0]) & (c.cellIdY == self.position[1]) & (c.levelIdZ == self.position[2]),
        )
        result = self.conn.execute(statement)
        rows = result.fetchall()
        result.close()

        levels = []
        for row in rows:
            levels.append(level.Event(conn=self.conn, row=row))

            # list of sequences of valid actions, parameters, and their need calculation
            # form of [(needCalc, [(command1, param1), (command2, param2)]]
        validActionList = []

        for lvl in levels:
            # only need to check if we can move to the level
            if lvl.walkable:
                for action in self.actionMap:
                    if "try" in self.actionMap[action]:
                        stateDiff = {"health": 0.0, "stamina": 0.0, "unprocessed": 0.0, "time": 0.0}

                        cmdQueue = self.actionMap[action]["try"](lvl, stateDiff)

                        # if the command is false then it failed for some reason, usually
                        # 	either ran out of health or stamina
                        if cmdQueue != False and len(cmdQueue) > 0:
                            validActionList.append((self.needCalc(stateDiff), cmdQueue))

                            # if there was no valid action then kill the animal
        if len(validActionList) == 0:
            self.data["state"] = States.DEAD
            self.deathCleanup()

            # sort and run the top action queue
        validActionList.sort(reverse=True)

        # break out the best action to preform
        # 	(don't actually need the needRating)
        needRating, bestActionSequence = validActionList[0]

        # iterate over the cmdQueue of the top (best) action, adding each command
        # in turn
        # NOTE: could we do this better with closures?
        for action in bestActionSequence:

            # the first arguement should be the function to add the command to the
            # 	queue, the second should be the arguments to pass to the add command
            # function
            cmdId, dt = self.mapAddCommand(action[0])(*action[1])
        self.commandNextDefault()
Exemple #29
0
    def addCommandDefault(self):
        '''
        search for the best command for the animal and add it to the command queue
        '''
        
        #death check is done here
        if self.data['state'] == States.DEAD:
            cmdId, dt = self.actionMap['dead']['add'](dt = 1.0)
            #being dead has no preCommand
            self.commandSet(cmdId, dt)
            return
            
        #get the levels we have access to
        c = db.levelData.columns
        statement = db.select([db.levelData],
                c.cellIdX.between(self.position[0]-1, self.position[0]+1) &
                c.cellIdY.between(self.position[1]-1, self.position[1]+1) &
                c.levelIdZ.between(self.position[2]-1, self.position[2]+1))
        #statement = db.select([db.levelData],
                #(c.cellIdX == self.position[0]) &
                #(c.cellIdY == self.position[1]) &
                #(c.levelIdZ == self.position[2]))
        result = self.conn.execute(statement)
        rows = result.fetchall()
        result.close()

        levels = []
        for row in rows:
            levels.append(level.Event(row = row, conn = self.conn))

        #list of sequences of valid actions, parameters, and their need calculation
        #form of [(needCalc, [(command1, param1), (command2, param2)]]
        validActionList = []
        
        for lvl in levels:
            #only need to check if we can move to the level
            if lvl.walkable:
                #for action in self.getActionList():
                for action in self.actionMap:
                    if 'try' in self.actionMap[action]:
                        stateDiff = {'health': 0.0, 'stamina': 0.0, \
                            'unprocessed': 0.0, 'time': 0.0}
                        
                        cmdQueue = self.actionMap[action]['try'](lvl, stateDiff)
                        
                        #if the command is false then it failed for some reason, usually
                        #    either ran out of health or stamina
                        if cmdQueue != False and len(cmdQueue) > 0:
                            validActionList.append((self.needCalc(stateDiff), cmdQueue))
            
        
        #NOTE: what happens if the validActionList is empty? pass out or suicide?
        # right now the only possiblity of this happening is if a level becomes
        #    unwalkable, and (there is either not a walkable level nearby or the\
        # animal doesn't have enough stamina to walk there)
        #if there was no action then kill the animal
        if len(validActionList) == 0:
            self.data['state'] = States.DEAD
            self.deathCleanup()
            
        #sort and run the top action queue
        validActionList.sort(reverse = True)
        
        
        #break out the best action to preform
        #    (don't actually need the needRating)
        #print repr(validActionList)
        #pprint.pprint(validActionList)
        needRating, bestActionSequence = validActionList[0]
        
        #iterate over the cmdQueue of the top (best) action, adding each command 
        # in turn
        #NOTE: could we do this better with closures?
        for action in bestActionSequence:
            
            #the first arguement should be the function to add the command to the
            #    queue, the second should be the arguments to pass to the add command
            # function
            #cmdId, dt = action[0](*action[1])
            cmdId, dt = self.mapAddCommand(action[0])(*action[1])
            
            #if first:
                ##if it's the first we want to set the command
                ##do the preCommand stuff
                #self.mapPreCommand(action[0])(*action[1])
                
                ## and set the command
                #self.commandSet(cmdId, dt)
                #first = False
            #NOTE: ran into problems while adding the pre command option
            #    Just calling command next after the commands are added 
            # means we don't duplicate code and don't have to have
            # two interfaces to pre-commands
            #But gives us one more command against the database
            #    we may want to move it back out again later.
            #
            #Finally, this introduces the possibility of an infinite loop because
            #    commandNext calls this function if it can't find any queued commands
        self.commandNextDefault()
Exemple #30
0
	def selectHuntPrey(self, lvl, stateDiff):
		'''
		Select the best animal to attack
		We want to find the animal which will give the best cost/oppertunity
		We have to consider how much mass we expect to get if we kill the animal vs.
		How much mass we'll lose to damage, energy, etc?
		'''
		
		#print "stateDiff before: " + repr(stateDiff)
		
		maxBiomass = 0.0
		maxPrey = None
		
		#ugh, have to pop these up to this level
		maxGainedBiomass = None
		maxNetStamina = None
		maxNetHealth = None
		maxNetTime = None
		
		#get all live animals, in the passed level, who don't have an attacker
		# current model can't handle multiple attackers
		c = db.animalData.columns
		statement = db.select([db.animalData], (c.animalX == lvl.cellIdX) &\
				(c.animalY == lvl.cellIdY) & (c.animalZ == lvl.levelIdZ) &\
				(c.state != base.States.DEAD) & (c.attackerId == None) & (c.animalId != self.animalId))
		result = self.conn.execute(statement)
		rows = result.fetchall()
		result.close()
		
		#select the best one to hunt
		
		#create a dictionary of cost/advantage?
		for row in rows:
			#prey = base.Event(self.conn, animalId = row['animalId'])
			prey = top.eventAnimalFactory(self.conn, row = row)
			
			#only consider if it is a prey species
			if prey.species in self.preySpecies:
				#total biomass that will be available having killed the animal
				gainedBiomass = (prey.growth + prey.stored) * self.scavengeEfficiency
				
				#now the hard part
				#we want to simulate the fight and try to guess how much health we'll lose
				
				#the oppertunity cost should be absolute (ratio makes no sense)
				result = self.simulateFight(self, prey)
				
				
				if result != False: #if we didn't lose the fight
					lostStamina, lostHealth, lostTime = result
					
					netBiomass = gainedBiomass - (lostStamina + lostHealth)
					
					if netBiomass > maxBiomass:
						maxBiomass = netBiomass
						maxPrey = prey
						maxGainedBiomass = gainedBiomass
						maxNetStamina = lostStamina
						maxNetHealth = lostHealth
						maxNetTime = lostTime
					
					
		if maxPrey == None:
			#didn't find anything woth attacking
			return False
			
			
		#found something we want to attack, adjust the stateDiff
		stateDiff['stamina'] += maxNetStamina
		stateDiff['health'] += maxNetHealth
		stateDiff['time'] += maxNetTime
		
		if self.stamina + stateDiff['stamina'] <= 0.0:
			#ran out of stamina
			return False
		elif self.health + stateDiff['health'] <= 0.0:
			#ran out of health
			return False
			
			
		#now to calculate how much we gain by scavanging
	
		#only test for unprocessedMax because the hunter will be able to sit down and eat until their full

		#can't eat more than there is room for
		room = self.unprocessedMax - self.unprocessed #room in it's stomach
		amount = min(room, maxGainedBiomass)
		eatingTime = amount / self.scavengeRate
			
		#simulate eating until full
		stateDiff['unprocessed'] += amount
		stateDiff['time'] += eatingTime
		
		#print "stateDiff after: " + repr(stateDiff)
		
		totalTime = maxNetTime + eatingTime
		stateDiff['stamina'] -= self.staminaDrain * totalTime
		stateDiff['stamina'] -= self.scavengeStaminaCost * eatingTime
		return maxPrey.data['animalId'], totalTime