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 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)
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 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")