def __init__(self, logger=None):
     self.id = util.register(self)     
     print self.id
     if not hasattr(self,'size'): self.size = np.array([ 3 , 2 , 2 ])
     self.stowage = Stowage(10) #things floating around in the module
     self.exterior_stowage = Stowage(0) #things strapped to the outside of the module
     self.sprite = None 
     self.gravity = np.array([ 0 , 0 , 0 ])
     self.max_gravity = 0.01
     self.min_gravity = 0
     self.orientation = np.array([ math.pi/4 , 0 ])
     self.location = np.array([ 0 , 0 , 0 ])
     self.composition = {'Al' : 14500}      
     self.package_material = [] #if a list of filters, material put in this will not be removed
     self.station = None
     self.manifest=None
     self.logger = logging.getLogger(logger.name + '.' + self.name) if logger else util.generic_logger
     self.loggername = self.logger.name
     
     self.atmo = Atmosphere()
     self.atmo.volume= math.pi * 2*self.size[0] * pow (self.size[1], 2)   
     self.atmo.initialize('Air')  
     
     self.equipment=dict() #miscellaneous (or unremovable) non-rack equipment
     self.player_installable = True
     
     self.paths = nx.Graph() 
     
     self.nodes=dict()
     
     self.touched = False        
     
     self.refresh_image()
 def __init__(self):
     self.id = str(uuid.uuid4())        
     if not hasattr(self,'size'): self.size = np.array([ 3 , 2 , 2 ])
     self.stowage = Stowage(10) #things floating around in the module
     self.exterior_stowage = Stowage(0) #things strapped to the outside of the module
     self.sprite = None 
     self.gravity = np.array([ 0 , 0 , 0 ])
     self.max_gravity = 0.01
     self.min_gravity = 0
     self.orientation = np.array([ math.pi/4 , 0 ])
     self.location = np.array([ 0 , 0 , 0 ])
     self.composition = {'Al' : 14500}      
     self.package_material = [] #if a list of filters, material put in this will not be removed
     self.station = None
     
     self.atmo = Atmosphere()
     self.atmo.volume= math.pi * 2*self.size[0] * pow (self.size[1], 2)   
     self.atmo.initialize('Air')  
     
     self.equipment=dict() #miscellaneous (or unremovable) non-rack equipment
     self.paths = nx.Graph() 
     
     self.nodes=dict()
     
     
     self.refresh_image()
Exemple #3
0
 def __init__(self,name='Place Holder',station=None, logger=None):
     self.my_tasks = TaskTracker()
     self.id = util.register(self) 
     self.name = name
     if logger:
         self.logger = logging.getLogger(logger.name + '.' + self.name)
     elif station:
         self.logger = logging.getLogger(station.logger.name + '.' + self.name)
     else: 
         self.logger = logging.getLogger(util.generic_logger.name + '.' + self.name)
     self.loggername = self.logger.name    
         
     self.needs = dict()
     self.needs['Idle Curiosity']=Need('Idle Curiosity', self, 100, 0, 0, self.new_idle_task, None)
     self.task = None #currently active task
     self.action = None #placeholder for graphical animation or tweening or w/e
     self.task_abandon_value = 5 #if a task's importance outweighs the current task by this much, we drop and switch
     self.location = None
     self.station = station
     self.inventory = Stowage(0.5)
     self.path=None
     self.held=None
     self.sprite=None
     self.xyz = np.array([ 0, 0, 0 ])
     self.orientation = np.array([ 0, 0, 0 ])
     self.speed = 1.0 #meter per second travel time, "A leisurely float"
     
     if self.station is not None:
         self.station.actors[self.id] = self
         self.location = self.station.random_location()[1]
         self.xyz = self.station.loc_to_xyz(self.location)                         
     
     self.refresh_image()
 def __init__(self,name='Place Holder',station=None, logger=None):
     self.my_tasks = TaskTracker()
     self.id = str(uuid.uuid4())  
     self.name = name
     self.logger = logging.getLogger(logger.name + '.' + self.name) if logger else util.generic_logger
     self.needs = dict()
     self.needs['Idle Curiosity']=Need('Idle Curiosity', self, 100, 0, 0, self.new_idle_task, None)
     self.task = None #currently active task
     self.action = None #placeholder for graphical animation or tweening or w/e
     self.task_abandon_value = 5 #if a task's importance outweighs the current task by this much, we drop and switch
     self.location = None
     self.station = station
     self.inventory = Stowage(0.5)
     self.path=None
     self.held=None
     self.xyz = np.array([ 0, 0, 0 ])
     self.orientation = np.array([ 0, 0, 0 ])
     self.speed = 1.0 #meter per second travel time, "A leisurely float"
     
     if not hasattr(self,'imgfile'): self.imgfile = "images/placeholder_actor.tif"
     self.refresh_image()
class BasicModule():
    '''Basic Module: literally just a tin can'''
    def __init__(self, logger=None):
        self.id = util.register(self)     
        print self.id
        if not hasattr(self,'size'): self.size = np.array([ 3 , 2 , 2 ])
        self.stowage = Stowage(10) #things floating around in the module
        self.exterior_stowage = Stowage(0) #things strapped to the outside of the module
        self.sprite = None 
        self.gravity = np.array([ 0 , 0 , 0 ])
        self.max_gravity = 0.01
        self.min_gravity = 0
        self.orientation = np.array([ math.pi/4 , 0 ])
        self.location = np.array([ 0 , 0 , 0 ])
        self.composition = {'Al' : 14500}      
        self.package_material = [] #if a list of filters, material put in this will not be removed
        self.station = None
        self.manifest=None
        self.logger = logging.getLogger(logger.name + '.' + self.name) if logger else util.generic_logger
        self.loggername = self.logger.name
        
        self.atmo = Atmosphere()
        self.atmo.volume= math.pi * 2*self.size[0] * pow (self.size[1], 2)   
        self.atmo.initialize('Air')  
        
        self.equipment=dict() #miscellaneous (or unremovable) non-rack equipment
        self.player_installable = True
        
        self.paths = nx.Graph() 
        
        self.nodes=dict()
        
        self.touched = False        
        
        self.refresh_image()
     
    def __getstate__(self):
        d = dict(self.__dict__)
        del d['logger']
        del d['sprite']
        return d    
        
    def __setstate__(self, d):
        self.__dict__.update(d)   
        self.logger = logging.getLogger(self.loggername) if self.loggername else util.generic_logger    
        self.sprite=None
        self.refresh_image() 
     
    def refresh_image(self):
        if not gv.config['GRAPHICS']: return                            
                
        if gv.config['GRAPHICS'] == 'pyglet':           
            if self.sprite: self.sprite.delete()
            self.sprite = util.make_solid_sprite(int(2*self.size[0]*gv.config['ZOOM']),int(2*self.size[1]*gv.config['ZOOM']),(128,128,128,255),None,None,self.location[0],self.location[1], self.orientation[0],batch = util.station_batch)
            self.sprite.owner = self
        elif gv.config['GRAPHICS'] == 'cocos2d':
            self.sprite = util.make_solid_sprite(int(2*self.size[0]*gv.config['ZOOM']),int(2*self.size[1]*gv.config['ZOOM']),(128,128,128,255),None,None,self.location[0],self.location[1], self.orientation[0])
            if self.station: self.station.sprite.add(self.sprite)
            
    def new_manifest(self):
        self.manifest = manifest.Manifest(self)    
     
    def search(self, filter_, **kwargs):
        hits=[]
        if "Equipment" in filter_.comparison_type or 'All' in filter_.comparison_type:
            hits.extend([[self.equipment[e][3], self.node( e ), filter_.compare(self.equipment[e][3]) ]  for e in self.equipment.keys() if self.equipment[e][3]])
            
            s = self.stowage.search( filter_ )
            if hasattr(s,'local_coords'):
                snode = self.node( self.nearest_hall_node(s.local_coords) )
            else:
                snode = self.filterNode( self.node('Inside') )
            hits.append( [ s, snode, s != None ] )
            #hits.append( self.exterior_stowage.find_resource( filter_ ) )

        if "Equipment Slot" in filter_.comparison_type or 'All' in filter_.comparison_type:
            hits.extend([[self.equipment[e][2], self.node( e ), filter_.compare(self.equipment[e][2]) ]  for e in self.equipment.keys()  if not self.equipment[e][3] and self.player_installable])
 
        if "Clutter" in filter_.comparison_type:
            s = self.stowage.search( filter_ )
            if hasattr(s,'local_coords'):
                snode = self.node( self.nearest_hall_node(s.local_coords) )
            else:
                snode = self.filterNode( self.node('Inside') )
            hits.append( [ s, snode, s != None ] )
            
        random.shuffle(hits)    
        hits.sort(key=lambda tup: tup[2], reverse=True)
        
        return hits[0] if hits and hits[0][2] else [None, None, False]        
                     
    def get_living_space(self): return self.stowage.free_space       
    living_space = property(get_living_space, None, None, "Living space" ) 
    #exterior_space = self.exterior_stowage.free_space
        
    def compute_short_id(self): return string.upper(self.id[0:6])       
    short_id = property(compute_short_id, None, None, "Short ID" )     
        
    def get_mass(self): return sum([self.composition.values()])        
    mass = property(get_mass, None, None, "Total mass" )     
        
    def node(self, to_append):
        return ''.join( [ self.id, '|', to_append ] )
        
    def getXYZ(self,offset):
        return absolute_xyz(self.location, offset, self.orientation, self.size)       
        
    def filterNode(self,node):
        [ module, name ] = separate_node(node)
        if module != self.id: return None
        if name == "Inside": return random.choice(self.nodes.keys())    
        return node
        
    def mix_neighbor(self,neighbor,amt=1.0):
        self.atmo.mix( neighbor.atmo, 1.0 )     
        
    def update(self, dt):
        for e in self.equipment:            
            if self.equipment[e][3]: 
                self.equipment[e][3].update( dt )
        self.stowage.update(dt)
        self.exterior_stowage.update(dt)
        #if 'Equipment' not in self.package_material:
        #    for c in self.stowage.contents:
        #        if isinstance(c,Equipment) and not c.installed and not c.task:
        #            c.install_task(self.station)
        if self.manifest: 
            satisfaction = self.manifest.check_satisfied()
            #print satisfaction    
            
        if random.random() < 0.05:
            #atmo mix with neighbors
            for n in self.get_neighbors():
                self.mix_neighbor(n)
        
    def get_random_dock(self, side_port_allowed=True, unused = True, used = False):
        docks=[]
        if unused: docks.extend([f for f in self.equipment.keys() if self.equipment[f][2] in DOCK_EQUIPMENT and self.equipment[f][3] and not self.equipment[f][3].docked and ( side_port_allowed or not ( '2' in f or '3' in f ) ) and self.equipment[f][3].player_usable ])
        if used: docks.extend([f for f in self.equipment.keys() if self.equipment[f][2] in DOCK_EQUIPMENT and self.equipment[f][3] and self.equipment[f][3].docked and ( side_port_allowed or not ( '2' in f or '3' in f ) ) and self.equipment[f][3].player_usable ])
        if not docks: return None
        return random.choice(docks)    
            
    def get_neighbors(self, equipment=False):
        out=[]
        for e in [f for f in self.equipment.keys() if self.equipment[f][2] in DOCK_EQUIPMENT and self.equipment[f][3] and self.equipment[f][3].docked ]:
            if not equipment:
                out.append(self.equipment[e][3].partner.installed)
            else:
                out.append(self.equipment[e][3])
        return out
        
    def get_neighbor(self,station=None):
        for n in self.get_neighbors():
            if station and n.station == station: return n
        return None
        
    def percolate(self):
        if self.touched: return []
        out = [self]
        self.touched=True
        for n in self.get_neighbors():
            out.extend(n.percolate())
        return out    
            
    def percolate_location(self):
        if self.touched: return
        self.touched = True
        for e in self.get_neighbors(equipment=True):
             #update e's partner's module's location
             n = e.partner.installed
             if not n.touched:                
                n.adjust_location(e.partner.get_name(),self,e.get_name())        
                n.refresh_image()     
             #call n
             n.percolate_location()           
            
    def get_empty_slot(self,slot_type='LSS'):
        if not self.player_installable: return None
        slots = [s for s in self.equipment.keys() if ( self.equipment[s][2] == slot_type or slot_type=='ANY' ) and not self.equipment[s][3]]
        if not slots: return None
        return random.choice(slots)
            
    def get_node(self,equip):
        for f in self.equipment.keys():
            if self.equipment[f][3] == equip:
                return self.node(f)
        return None        
            
    def uninstall_equipment(self,equip):
        for f in self.equipment.keys():
            if self.equipment[f][3] == equip:
                self.equipment[f][3] = None
                self.stowage.add( equip )
                return True
        return False                            
        
    def adjust_location(self,my_node,neighbor,their_node):
        self.orientation = ( neighbor.orientation + neighbor.equipment[their_node][1] - self.equipment[my_node][1] ) + np.array([math.pi, 0])
        self.orientation %= 2*math.pi
        
        #calculate location
        self.location=np.array([ 0,0,0 ])
        loc_offset = self.getXYZ(self.equipment[my_node][0])
        self.location = neighbor.getXYZ(neighbor.equipment[their_node][0]) - loc_offset        
        
            
    def dock(self, my_node, neighbor, their_node):
        if not neighbor or not my_node or not their_node: return False, "Docking cancelled: pointers missing" 
        if not my_node in self.equipment or not their_node in neighbor.equipment: return False, "Docking cancelled: wrong module, I guess?"
        if not self.equipment[my_node][2] in DOCK_EQUIPMENT or not neighbor.equipment[their_node][2] in DOCK_EQUIPMENT: return False, "Docking cancelled: requested interface(s) are not docking equipment!"
        if self.equipment[my_node][2] != neighbor.equipment[their_node][2]: return False, "Docking cancelled: incompatible docking mechanisms"
        if self.equipment[my_node][3].docked or neighbor.equipment[their_node][3].docked: return False, "Docking cancelled: at least one module already docked elsewhere"
        
        self.adjust_location(my_node,neighbor,their_node)        
        
        #collision detection   
                        
        if neighbor.station:    
            if not self.station:     
                self.station = neighbor.station 
                self.station.paths.add_nodes_from(self.paths.nodes())
                self.station.paths.add_edges_from(self.paths.edges(data=True))
                self.refresh_station()                
        else:             
            neighbor.station = self.station                                    
            if self.station:
                self.station.paths.add_nodes_from(neighbor.paths.nodes())
                self.station.paths.add_edges_from(neighbor.paths.edges(data=True))
                neighbor.refresh_station()         
                     
        neighbor.refresh_image()    
        self.refresh_image()
            
        return True        
        
    def connect(self, my_node, neighbor, their_node, instant=False):    
        #dock, finally
        self.equipment[my_node][3].dock( neighbor, neighbor.equipment[their_node][3], instant)
        neighbor.equipment[their_node][3].dock( self, self.equipment[my_node][3], instant )
        
    
    def disconnect(self, my_node, their_node, instant=False):    
        #dock, finally
        a = self.equipment[my_node][3].undock( instant )
        b = their_node.undock( instant )
        return a and b
            
        
    def add_edge(self,one,two):
        delta = self.nodes[two] - self.nodes[one] #numpy vector subtraction, I hope
        delta *= self.size
        mag = abs( np.sqrt( np.vdot( delta , delta ) ) )
        self.paths.add_edge(one,two,weight=mag)
        
    def add_edge_list(self,edges):
        for e in range(1,len(edges)):            
            self.add_edge( self.node( edges[ e - 1 ] ), self.node( edges[ e ] ) )
        
    def nearest_hall_node(self,coords):
        all_nodes = [separate_node(n)[1] for n in self.nodes.keys()]
        hall_nodes = [n for n in all_nodes if not n in self.equipment.keys()]            
        hall_nodes.sort(key=lambda t: util.vec_dist( self.nodes[self.node( t )] , coords ), reverse=False)
        return hall_nodes[0]
        
    def add_equipment(self, eq_node, eq_obj, eq_coords, hall_node=None, eq_orientation=np.array([ 0 , 0]), eq_type='MISC' ):
        if not hall_node: hall_node = self.nearest_hall_node(eq_coords)
        node_coords = self.nodes[ self.node( hall_node ) ] + ( eq_coords - self.nodes[ self.node( hall_node ) ] ) 
        self.nodes[self.node(eq_node)] = node_coords
        self.add_edge( self.node(hall_node), self.node(eq_node) )
        self.equipment[ eq_node ] = [ eq_coords, eq_orientation, eq_type, eq_obj]

    def refresh_station(self, station=None):
        if station and station != self.station: self.station = station
        if gv.config['GRAPHICS'] == 'cocos2d': self.station.sprite.add(self.sprite)
        if self.manifest: self.manifest.refresh_station(self.station)
        for e in self.equipment:            
            if self.equipment[e][3]: 
                self.equipment[e][3].refresh_station()
                
    def draw(self,window):
        zoom=gv.config['ZOOM']
        #self.img.blit(zoom*self.location[0]+window.width // 2, zoom*self.location[1]+window.height // 2, 0)
        if hasattr(self.sprite, 'update_sprite'):
            l=self.location
            self.sprite.update_sprite(zoom*l[0], zoom*l[1],-180*(self.orientation[0])/math.pi)
        if self.sprite: self.sprite.draw()
        
        for e in self.equipment.keys():
            if self.equipment[e][3] and self.equipment[e][3].visible:
                l=self.getXYZ(self.equipment[e][0]) 
                #rotimg=self.equipment[e][3].img.get_transform
                self.equipment[e][3].sprite.update_sprite(zoom*l[0], zoom*l[1],-180*(self.equipment[e][1][0]+self.orientation[0])/math.pi)
                #self.equipment[e][3].sprite.set_position(zoom*l[0], zoom*l[1])
                #self.equipment[e][3].sprite.rotation = -180*(self.equipment[e][1][0]+self.orientation[0])/math.pi
                self.equipment[e][3].sprite.draw()#img.blit(zoom*l[0]+window.width // 2, zoom*l[1]+window.height // 2, 0)

        for c in self.stowage.contents:
            if hasattr(c,'sprite') and hasattr(c,'local_coords') and c.sprite:
                loc_xyz = self.getXYZ( 1.0*c.local_coords )
                c.sprite.set_position(zoom*loc_xyz[0],zoom*loc_xyz[1])
                #c.sprite.rotation = (-180/math.pi)*self.orientation[0]
                c.sprite.visible=True
                c.sprite.draw()         
class Actor(object):
    def __init__(self,name='Place Holder',station=None, logger=None):
        self.my_tasks = TaskTracker()
        self.id = str(uuid.uuid4())  
        self.name = name
        self.logger = logging.getLogger(logger.name + '.' + self.name) if logger else util.generic_logger
        self.needs = dict()
        self.needs['Idle Curiosity']=Need('Idle Curiosity', self, 100, 0, 0, self.new_idle_task, None)
        self.task = None #currently active task
        self.action = None #placeholder for graphical animation or tweening or w/e
        self.task_abandon_value = 5 #if a task's importance outweighs the current task by this much, we drop and switch
        self.location = None
        self.station = station
        self.inventory = Stowage(0.5)
        self.path=None
        self.held=None
        self.xyz = np.array([ 0, 0, 0 ])
        self.orientation = np.array([ 0, 0, 0 ])
        self.speed = 1.0 #meter per second travel time, "A leisurely float"
        
        if not hasattr(self,'imgfile'): self.imgfile = "images/placeholder_actor.tif"
        self.refresh_image()
     
    def refresh_image(self):
        self.img = util.load_image(self.imgfile)
    
    def draw(self,window):
        zoom=util.ZOOM
        l= self.path.current_coords if (self.path and not self.path.completed) else self.station.loc_to_xyz( self.location )
        self.img.blit(zoom*l[0], zoom*l[1], 0)        
        
    def drop(self):
        pass #TODO drop held item        
        
    def new_idle_task(self,timeout,severity):
        t=Task(''.join(['Satisfy Idle Curiosity']), owner = self, timeout = None, task_duration = 150, severity='IGNORABLE', fetch_location_method=self.station.random_location,logger=self.logger)
        return t     
        
    def update(self,dt):
        self.my_tasks.update(dt)
        for n in self.needs.values():
            n.update(dt)
            
        self.inventory.update(dt)
        
        if self.task and self.task.task_ended():            
            self.task=None
        
        #'grab new task'                
        _curr_value = -5 if not self.task else self.task.task_value()
        _new_task = self.my_tasks.fetch_open_task() if not self.station else max(self.my_tasks.fetch_open_task(), self.station.tasks.fetch_open_task())
        #print "TASK VALUES", self.my_tasks.fetch_open_task()
        if _new_task and _new_task.task_value() > _curr_value + self.task_abandon_value:            
            if self.task: self.task.drop()
            self.task = _new_task
            self.task.assign(self)
        
        #'work on task'
        if not self.task: return
        if not self.task.location: 
            self.task.target, self.task.location, d = self.task.fetch_location() #Grab location
            #print self.task.name, self.task.target, self.task.location
            if not self.task.location: 
                self.task.drop()
                self.task=None
                return
        if self.location == self.task.location: 
            #work on task
            #print "Check", self.task.name
            self.task.do_work(dt)
            #print [[c.name, c.volume] for c in self.inventory.contents]
        else:
            if self.task.location and not self.task.location == self.location: 
                #go to location 
                if self.path and not self.path.completed:
                    self.path.traverse_step(dt*self.speed)
                else:
                    #print self.task.name, self.task.target, self.task.location
                    new_path = PathingWidget(self,self.station.paths,self.location, self.task.location, self.xyz)
                    if not new_path.valid: assert False, "ERROR: some kind of pathing error!"
                    self.path = new_path
                    self.path.traverse_step(dt*self.speed)
                    
    def transfer_node(self, new_loc ):
        '''moving to new node, exchange air flow'''
        my_mod = self.station.get_module_from_loc( self.location )
        new_mod = self.station.get_module_from_loc( new_loc )
        my_mod.atmo.mix( new_mod.atmo, 1.0 )             
       
    def summarize_needs(self, ret_string=False):
        if ret_string:
            out = 'Needs'
            for n in self.needs.keys():
                #print n, self.needs[n].current_severity()
                out = ''.join([out,'; ',n,'-',self.needs[n].current_severity()])
            return out #what a huge PITA
        return [[n, self.needs[n].current_severity()] for n in self.needs.keys()]
        
    def log_status(self):
        #TODO log task
        #self.logger.info(self.summarize_needs(True))
        self.logger.info(self.task.name if self.task else "Task: idling")        
class BasicModule():
    '''Basic Module: literally just a tin can'''
    def __init__(self):
        self.id = str(uuid.uuid4())        
        if not hasattr(self,'size'): self.size = np.array([ 3 , 2 , 2 ])
        self.stowage = Stowage(10) #things floating around in the module
        self.exterior_stowage = Stowage(0) #things strapped to the outside of the module
        self.sprite = None 
        self.gravity = np.array([ 0 , 0 , 0 ])
        self.max_gravity = 0.01
        self.min_gravity = 0
        self.orientation = np.array([ math.pi/4 , 0 ])
        self.location = np.array([ 0 , 0 , 0 ])
        self.composition = {'Al' : 14500}      
        self.package_material = [] #if a list of filters, material put in this will not be removed
        self.station = None
        
        self.atmo = Atmosphere()
        self.atmo.volume= math.pi * 2*self.size[0] * pow (self.size[1], 2)   
        self.atmo.initialize('Air')  
        
        self.equipment=dict() #miscellaneous (or unremovable) non-rack equipment
        self.paths = nx.Graph() 
        
        self.nodes=dict()
        
        
        self.refresh_image()
     
    def refresh_image(self):
        if not util.GRAPHICS: return                            
                
        if True:#not hasattr(self,'imgfile'):
            if util.GRAPHICS:
                self.img = util.make_solid_image(int(2*self.size[0]*util.ZOOM),int(2*self.size[1]*util.ZOOM),(128,128,128,255))
            else: 
                self.imgfile = "images/module_placeholder.jpg"            

        #if hasattr(self,'imgfile'):
        #    self.img = util.load_image(self.imgfile)
        
        '''if math.sin(self.orientation[0]) < 0:
            self.img = self.img.get_transform(flip_y=True)
            #TODO replace with different image altogether
        if math.cos(self.orientation[0]) < 0:
            self.img = self.img.get_transform(flip_x=True)
           ''' 
        self.sprite = util.image_to_sprite(self.img,self.location[0],self.location[1], self.orientation[0])
            
        
     
    def search(self, filter_):
        hits=[]
        if "Equipment" in filter_.comparison_type or 'All' in filter_.comparison_type:
            hits.extend([[self.equipment[e][3], self.node( e ), filter_.compare(self.equipment[e][3]) ]  for e in self.equipment.keys() if self.equipment[e][3]])
            
            hits.append( [ self.stowage.search( filter_ ), self.filterNode( self.node('Inside') ), self.stowage.search( filter_ ) != None ] )
            #hits.append( self.exterior_stowage.find_resource( filter_ ) )

        if "Equipment Slot" in filter_.comparison_type or 'All' in filter_.comparison_type:
            hits.extend([[self.equipment[e][2], self.node( e ), filter_.compare(self.equipment[e][2]) ]  for e in self.equipment.keys()  if not self.equipment[e][3]])
 
        if "Clutter" in filter_.comparison_type:
            hits.append( [ self.stowage.search( filter_ ), self.filterNode( self.node('Inside') ), self.stowage.search( filter_ ) != None ] )
            
        random.shuffle(hits)    
        hits.sort(key=lambda tup: tup[2], reverse=True)
        #print hits        
        return hits[0] if hits and hits[0][2] else [None, None, False]        
                     
    def get_living_space(self): return self.stowage.free_space       
    living_space = property(get_living_space, None, None, "Living space" ) 
    #exterior_space = self.exterior_stowage.free_space
        
    def compute_short_id(self): return string.upper(self.id[0:6])       
    short_id = property(compute_short_id, None, None, "Short ID" )     
        
    def get_mass(self): return sum([self.composition.values()])        
    mass = property(get_mass, None, None, "Total mass" )     
        
    def node(self, to_append):
        return ''.join( [ self.id, '|', to_append ] )
        
    def getXYZ(self,offset):
        return absolute_xyz(self.location, offset, self.orientation, self.size)       
        
    def filterNode(self,node):
        [ module, name ] = separate_node(node)
        if module != self.id: return None
        if name == "Inside": return random.choice(self.nodes.keys())    
        return node
        
    def update(self, dt):
        for e in self.equipment:            
            if self.equipment[e][3]: 
                self.equipment[e][3].update( dt )
        self.stowage.update(dt)
        self.exterior_stowage.update(dt)
        if 'Equipment' not in self.package_material:
            for c in self.stowage.contents:
                if isinstance(c,Equipment) and not c.installed and not c.task:
                    c.install_task(self.station)
                
        
    def get_random_dock(self, side_port_allowed=True):
        docks=[f for f in self.equipment.keys() if self.equipment[f][2] in DOCK_EQUIPMENT and self.equipment[f][3] and not self.equipment[f][3].docked and ( side_port_allowed or not ( '2' in f or '3' in f ) ) ]
        if not docks: return None
        return random.choice(docks)    
            
    def get_empty_slot(self,slot_type='LSS'):
        slots = [s for s in self.equipment.keys() if ( self.equipment[s][2] == slot_type or slot_type=='ANY' ) and not self.equipment[s][3]]
        if not slots: return None
        return random.choice(slots)
            
    def uninstall_equipment(self,equip):
        for f in self.equipment.keys():
            if self.equipment[f][3] == equip:
                self.equipment[f][3] = None
                self.stowage.add( equip )
                return True
        return False                            
        
    
            
    def berth(self, my_node, neighbor, their_node, instant=False):
        if not neighbor or not my_node or not their_node: return False, "Docking cancelled: pointers missing" 
        if not my_node in self.equipment or not their_node in neighbor.equipment: return False, "Docking cancelled: wrong module, I guess?"
        if not self.equipment[my_node][2] in DOCK_EQUIPMENT or not neighbor.equipment[their_node][2] in DOCK_EQUIPMENT: return False, "Docking cancelled: requested interface(s) are not docking equipment!"
        if self.equipment[my_node][2] != neighbor.equipment[their_node][2]: return False, "Docking cancelled: incompatible docking mechanisms"
        if self.equipment[my_node][3].docked or neighbor.equipment[their_node][3].docked: return False, "Docking cancelled: at least one module already docked elsewhere"
        
        #calculate orientation
        self.orientation = ( neighbor.orientation + neighbor.equipment[their_node][1] - self.equipment[my_node][1] ) + np.array([math.pi, 0])
        
        #calculate location
        self.location=np.array([ 0,0,0 ])
        loc_offset = self.getXYZ(self.equipment[my_node][0])
        self.location = neighbor.getXYZ(neighbor.equipment[their_node][0]) - loc_offset
        self.orientation %= 2*math.pi
        
        #collision detection

        #dock, finally
        self.equipment[my_node][3].dock( neighbor, neighbor.equipment[their_node][3], instant)
        neighbor.equipment[their_node][3].dock( self, self.equipment[my_node][3], instant )
        
        # map graphs together
        
        if neighbor.station:    
            if self.station:
                print self.station, neighbor.station
                assert False, "Station merging not in yet" #TODO replace with station merge
            else:         
                self.station = neighbor.station 
                self.station.paths.add_nodes_from(self.paths.nodes())
                self.station.paths.add_edges_from(self.paths.edges(data=True))
                self.station.paths.add_edge(self.node(my_node),neighbor.node(their_node),weight=1)
                self.refresh_equipment()
                
        else:             
            neighbor.station = self.station
                                    
            if self.station:
                self.station.paths.add_nodes_from(neighbor.paths.nodes())
                self.station.paths.add_edges_from(neighbor.paths.edges(data=True))
                self.station.paths.add_edge(self.node(my_node),neighbor.node(their_node),weight=1)
                neighbor.refresh_equipment()
            
        neighbor.refresh_image()    
        self.refresh_image()
            
        return True        
        
    def add_edge(self,one,two):
        delta = self.nodes[two] - self.nodes[one] #numpy vector subtraction, I hope
        delta *= self.size
        mag = abs( np.sqrt( np.vdot( delta , delta ) ) )
        self.paths.add_edge(one,two,weight=mag)
        
    def add_edge_list(self,edges):
        for e in range(1,len(edges)):            
            self.add_edge( self.node( edges[ e - 1 ] ), self.node( edges[ e ] ) )
        
    def add_equipment(self, eq_node, eq_obj, eq_coords, hall_node=None, eq_orientation=np.array([ 0 , 0]), eq_type='MISC' ):
        if not hall_node:
            all_nodes = [separate_node(n)[1] for n in self.nodes.keys()]
            hall_nodes = [n for n in all_nodes if not n in self.equipment.keys()]            
            hall_nodes.sort(key=lambda t: util.vec_dist( self.nodes[self.node( t )] , eq_coords ), reverse=False)
            #print [util.vec_dist( self.nodes[self.node( t )] , eq_coords ) for t in hall_nodes]
            hall_node = hall_nodes[0]
        node_coords = self.nodes[ self.node( hall_node ) ] + ( eq_coords - self.nodes[ self.node( hall_node ) ] ) 
        self.nodes[self.node(eq_node)] = node_coords
        self.add_edge( self.node(hall_node), self.node(eq_node) )
        self.equipment[ eq_node ] = [ eq_coords, eq_orientation, eq_type, eq_obj]

    def refresh_equipment(self):
        for e in self.equipment:            
            if self.equipment[e][3]: 
                self.equipment[e][3].refresh_station()
                
    def draw(self,window):
        zoom=util.ZOOM
        #self.img.blit(zoom*self.location[0]+window.width // 2, zoom*self.location[1]+window.height // 2, 0)
        self.sprite.draw()
        for c in self.stowage.contents:
            if hasattr(c,'sprite') and hasattr(c,'local_coords') and c.sprite:
                loc_xyz = self.getXYZ( 0.8*c.local_coords )
                c.sprite.set_position(zoom*loc_xyz[0],zoom*loc_xyz[1])
                c.sprite.rotation = (-180/math.pi)*self.orientation[0]
                c.sprite.draw()
        for e in self.equipment.keys():
            if self.equipment[e][3] and self.equipment[e][3].visible:
                l=self.getXYZ(self.equipment[e][0]) 
                #rotimg=self.equipment[e][3].img.get_transform
                self.equipment[e][3].sprite.update_sprite(zoom*l[0], zoom*l[1],-180*(self.equipment[e][1][0]+self.orientation[0])/math.pi)
Exemple #8
0
class Actor(object):
    def __init__(self,name='Place Holder',station=None, logger=None):
        self.my_tasks = TaskTracker()
        self.id = util.register(self) 
        self.name = name
        if logger:
            self.logger = logging.getLogger(logger.name + '.' + self.name)
        elif station:
            self.logger = logging.getLogger(station.logger.name + '.' + self.name)
        else: 
            self.logger = logging.getLogger(util.generic_logger.name + '.' + self.name)
        self.loggername = self.logger.name    
            
        self.needs = dict()
        self.needs['Idle Curiosity']=Need('Idle Curiosity', self, 100, 0, 0, self.new_idle_task, None)
        self.task = None #currently active task
        self.action = None #placeholder for graphical animation or tweening or w/e
        self.task_abandon_value = 5 #if a task's importance outweighs the current task by this much, we drop and switch
        self.location = None
        self.station = station
        self.inventory = Stowage(0.5)
        self.path=None
        self.held=None
        self.sprite=None
        self.xyz = np.array([ 0, 0, 0 ])
        self.orientation = np.array([ 0, 0, 0 ])
        self.speed = 1.0 #meter per second travel time, "A leisurely float"
        
        if self.station is not None:
            self.station.actors[self.id] = self
            self.location = self.station.random_location()[1]
            self.xyz = self.station.loc_to_xyz(self.location)                         
        
        self.refresh_image()
     
    def __getstate__(self):
        d = dict(self.__dict__)
        del d['logger']
        del d['sprite']        
        #d.pop('station') #TODO delete
        #d.pop('needs')#TODO delete
        return d    
        
    def __setstate__(self, d):
        self.__dict__.update(d)   
        util.register(self,self.id) 
        self.logger = logging.getLogger(self.loggername) if self.loggername else util.generic_logger    
        self.sprite=None
        self.refresh_image()           
     
    def refresh_image(self):
        if gv.config['GRAPHICS'] == 'pyglet': 
            import graphics_pyglet           
            if self.sprite: self.sprite.delete()
            
            self.sprite = graphics_pyglet.LayeredSprite(name=self.name,batch=util.actor_batch )     
            self.sprite.add_layer('ActorBase',util.load_image("images/npc_crafty_bot__x1_idle0_png_1354839494_crop.png"))
            self.sprite.owner = self
        
    def update_location(self):
        zoom = gv.config['ZOOM']
        l= self.path.current_coords if (self.path and not self.path.completed) else self.station.loc_to_xyz( self.location )
        self.xyz=l
        self.sprite.update_sprite(zoom*l[0], zoom*l[1],0)
       
        
    def drop_held(self):
        if self.held is None: return
        module = self.station.get_module_from_loc( self.location )
        module.stowage.add(self.held)
        self.held = None
        
    def new_idle_task(self,timeout,severity):
        t=Task(''.join(['Satisfy Idle Curiosity']), owner = self, timeout = None, task_duration = 150, severity='IGNORABLE', fetch_location_method=self.station.random_location,logger=self.logger)
        return t     
        
    def refresh_station(self):
        self.task=None    
        self.path=None
        #self.xyz = self.station.loc_to_xyz( self.location )
        if self.station: self.logger = logging.getLogger(self.station.logger.name + '.' + self.name)
        
    def update(self,dt):
        self.my_tasks.update(dt)
        for n in self.needs.values():
            n.update(dt)
            
        self.inventory.update(dt)        
        
        if self.task and self.task.task_ended():            
            self.task=None
            return
        #'grab new task'                
        _curr_value = -5 if not self.task else self.task.task_value()
        _new_task = self.my_tasks.fetch_open_task() if not self.station else max(self.my_tasks.fetch_open_task(), self.station.tasks.fetch_open_task())
        #print "TASK VALUES", self.my_tasks.fetch_open_task()
        if _new_task and _new_task.task_value() > _curr_value + self.task_abandon_value:            
            if self.task: self.task.drop()
            self.task = _new_task
            self.task.assign(self)
            self.logger.info("New task:"+self.task.name)
        #'work on task'
        if not self.task: return
        if not self.task.location:
            self.task.target, self.task.location, d = self.task.fetch_location() #Grab location
            if not self.task.location: 
                self.task.drop()
                self.task=None
                return
                
               
        if self.location == self.task.location: 
            #work on task
            self.task.do_work(dt)
            
        else:
            if self.task.location and not self.task.location == self.location: 
                #go to location 
                if self.path and not self.path.completed:
                    if not self.path.traverse_step(dt*self.speed):
                        self.logger.warning("Pathing error: Path suddenly invalid "+self.task.name+"!")
                        self.task.drop()
                        self.task=None
                        return                    
                else:
                    #print self.task.name, self.task.target, self.task.location
                    new_path = PathingWidget(self,self.station.paths,self.location, self.task.location, self.xyz)
                    if not new_path.valid: 
                        self.logger.warning("Pathing error: "+self.task.name+": !")
                        self.task.drop()
                        self.task=None
                        return
                    self.path = new_path
                    self.path.traverse_step(dt*self.speed)
                    
    def transfer_node(self, new_loc ):
        '''moving to new node, exchange air flow'''
        my_mod = self.station.get_module_from_loc( self.location )
        new_mod = self.station.get_module_from_loc( new_loc )
        my_mod.mix_neighbor(new_mod, 1.0 )             
       
    def summarize_needs(self, ret_string=False):
        if ret_string:
            out = 'Needs'
            for n in self.needs.keys():
                #print n, self.needs[n].current_severity()
                out = ''.join([out,'; ',n,'-',self.needs[n].current_severity()])
            return out #what a huge PITA
        return [[n, self.needs[n].current_severity()] for n in self.needs.keys()]
        
    def log_status(self):
        #TODO log task
        #self.logger.info(self.summarize_needs(True))
        self.logger.info(self.task.name if self.task else "Task: idling")