def _setup_camp(m): cfire=m.make('campfire',pos=(100,-50,settlement_height)) m.make('fire',pos=(0,0,0),parent=cfire.id) cfire=m.make('campfire',pos=(90,-50,settlement_height)) m.make('fire',pos=(0,0,0),parent=cfire.id) for i in range(10, 350, 5): direction=Vector3D(sin(radians(i)) * uniform(0,2), cos(radians(i)) * uniform(0,2), 10).unit_vector() orient=Quaternion(Vector3D(0, 1, 0), direction) m.make('stake', pos=(100 + 14 * sin(radians(i)), -50 + 16 * cos(radians(i)), -1), bbox=[-0.5,-0.5,0,0.5,0.5,5 + uniform(0,2)], orientation=orient.as_list()) camp_area_points=[] for i in range(10, 350, 17): camp_area_points.append([14 * sin(radians(i)), 16 * cos(radians(i))]) camp_area={'shape': {'points': camp_area_points, 'type': 'polygon'}, 'layer': 7 } m.make('path', name='camp_area', pos=camp_pos, area=camp_area, bbox=[-14, -16, 0, 14, 16, 1], spawn={'name': 'goblin village', 'character_types': ['goblin'], 'contains': ['shirt', 'pants', 'cloak', 'boots', 'hat']})
def shoot_poison_in_direction(direction, instance, res): Usage.set_cooldown_on_attached(instance.tool, instance.actor) direction.normalize() # Adjust the start position of the projectile, so it's outside of the actor, at mid height start_adjust = Vector3D(direction) start_adjust.y = 0 start_adjust.normalize() start_adjust.y = instance.actor.location.bbox.high_corner.y * 0.8 new_loc = instance.actor.location.copy() new_loc.pos += start_adjust new_loc.orientation = Quaternion(Vector3D(0, 0, 1), direction, Vector3D(1, 0, 0)) mode_data = {"mode": "projectile", "$eid": instance.actor.id} res.append( Operation("create", Entity(parent="poisonball", location=new_loc, velocity=direction * 60, mode="projectile", mode_data=mode_data, damage_poison=instance.tool.props.damage), to=instance.tool.id))
def shoot_in_direction(direction, instance, res): Usage.set_cooldown_on_attached(instance.tool, instance.actor) arrows = instance.actor.find_in_contains(arrow_filter) if len(arrows): direction.normalize() # Adjust the start position of the arrow, so it's outside of the actor, at mid height start_adjust = Vector3D(direction) start_adjust.y = 0 start_adjust.normalize() start_adjust.y = instance.actor.location.bbox.high_corner.y * 0.8 new_loc = instance.actor.location.copy() new_loc.pos += start_adjust new_loc.orientation = Quaternion(Vector3D(0, 0, 1), direction, Vector3D(1, 0, 0)) mode_data = {"mode": "projectile", "$eid": instance.actor.id, "extra": {"damage": 20}} # TODO: match with animation in client res.append(instance.actor.start_action("bow/releasing", 1)) res.append(Operation("move", Entity(arrows[0].id, location=new_loc, velocity=direction * 60, mode="projectile", mode_data=mode_data), to=arrows[0].id))
def knowledge_updated(self, entity): if entity.has_prop_map('_knowledge'): knowledge = entity.get_prop_map('_knowledge') for key, knowledge_element in knowledge.items(): (predicate, subject) = key.split(':') object_word = knowledge_element if predicate == 'location': # If it's just a string it's a reference to an entity id (with zero position). if isinstance(object_word, str): entity_id_string = object_word # A prefix of "$eid:" denotes an entity id; it should be stripped first. if entity_id_string.startswith("$eid:"): entity_id_string = entity_id_string[5:] where = self.map.get_add(entity_id_string) object_word = Location(where) else: if len(object_word) == 3: loc = self.entity.location.copy() loc.pos = Vector3D(object_word) object_word = loc elif len(object_word) == 4: entity_id_string = object_word[0] # A prefix of "$eid:" denotes an entity id; it should be stripped first. if entity_id_string.startswith("$eid:"): entity_id_string = entity_id_string[5:] where = self.map.get_add(entity_id_string) object_word = Location(where, Vector3D(object_word[:3])) self.add_knowledge(predicate, subject, object_word)
def sift_operation(self, op): newloc = self.location.copy() newloc.velocity = Vector3D() item = Gravestone.items[randint(0, 5)] newloc.pos = newloc.pos + Vector3D(uniform(-1, 1), uniform(-1, 1), uniform(-1, 1)) return Operation("create", Entity(name=item, parent=item, location=newloc.copy()), to=self) + \ Operation("imaginary", Entity(description="You dig up a bone from the grave."), to=op.id, from_=op.id)
def info_operation(self,op): print("Aframe info") aframe = server.world.get_object_ref(op[0].id) self.lcount = 0 raw_materials = [] for item in self.character.contains: if item.type[0] == str(self.materials): raw_materials.append(item) self.lcount = self.lcount + 1 if self.lcount == 3 : break else: print( "No materials in inventory for A frame") self.irrelevant() return chunk_loc = Location(aframe()) chunk_loc.coordinates =Point3D([0,0,0]) count = self.lcount res=Oplist() #loops through raw_materials and places 3 lumber #in inventory infront of user offset=Vector3D(0,0,0) while (count > 0) : tar = raw_materials.pop() #length of the lumber obtained lumberlength=tar.location.bbox.far_point[2]- \ tar.location.bbox.near_point[2] lumberheight=tar.location.bbox.far_point[1]- \ tar.location.bbox.near_point[1] #rough length to position lumber lumber_length=lumberlength/4 if count == 3 : #left component chunk_loc.orientation=Quaternion([.653,0.27,.27,.653]) if count == 2 : #right component chunk_loc.orientation=Quaternion([.653,-0.27,-.27,.653]) offset=Vector3D(lumber_length,0,0) chunk_loc.coordinates=chunk_loc.coordinates+offset if count == 1 : #bottom component chunk_loc.coordinates = Point3D([0,0,0]) #self.pos #.707 is sin(.5) which is needed for a 90 degree rotation chunk_loc.orientation=Quaternion([.707,0,.707,0]) offset=Vector3D(-(1.5*lumber_length),-(2.5*lumber_length),0) chunk_loc.coordinates=chunk_loc.coordinates+offset move=Operation("move", Entity(tar.id,location=chunk_loc, mode="fixed"), to=tar) res.append(move) count = count - 1 self.progress =1 self.irrelevant() return res
def drop_fruit(self, res, parent): height = self.location.bbox.high_corner.y newloc = self.location.copy() newloc.velocity = Vector3D() newloc.pos = newloc.pos + Vector3D(random.uniform(-height, height), 0, random.uniform(-height, height)) res.append(Operation("create", Entity(parent=parent, location=newloc), to=self))
def create_skeletonpart(self, op): retops = Oplist() newloc=self.location.copy() newloc.velocity=Vector3D() items = ['skull', 'ribcage', 'arm', 'pelvis', 'thigh', 'shin'] item = items[randint(0,5)] newloc.coordinates = newloc.coordinates + Vector3D(uniform(-1,1), uniform(-1,1), uniform(-1,1)) retops = retops + Operation("create", Entity(name=item,parents=[item],location=newloc.copy()), to=self) return retops
def do_peck(self, me): # world = # ground = world.id # op = Operation("eat", ground) target = Location(me.entity.location.parent, me.entity.location.pos) target.pos = Vector3D(target.pos.x + uniform(-1.5, 1.5), target.pos.y, target.pos.z + uniform(-1.5, 1.5)) target.velocity = Vector3D(1, 0, 0) # op += Operation("move", Entity(me.entity.id, location=target)) return Operation("move", Entity(me.entity.id, location=target))
def face(self, other): vector = distance_to(self.location, other.location) vector.y = 0 if vector.square_mag() < 0.1: return vector = vector.unit_vector() newloc = Location(self.location.parent) newloc.orientation = Quaternion(Vector3D(0, 0, 1), vector, Vector3D(0, 1, 0)) return Operation("move", Entity(self.id, location=newloc))
def touch_operation(self, op): retops = Oplist() if self.props.status<0: return newloc=self.location.copy() newloc.velocity=Vector3D() retops = retops + Operation("move", Entity(self.id, location=newloc.copy(), mode="collapsed"), to=self) for item in ['skull', 'ribcage', 'femur', 'pelvis', 'tibia']: newloc.coordinates = newloc.coordinates + Vector3D(uniform(-1,1), uniform(-1,1), uniform(-1,1)) retops = retops + Operation("create", Entity(name=item,parent=item,location=newloc.copy()), to=self) retops = retops + Operation("set", Entity(self.id, status=-1), to=self) return retops
def face(self, other): """turn to face other entity""" vector = self.steering.direction_to(other) if vector is None: return vector.y = 0 if vector.sqr_mag() < 0.1: return vector = vector.unit_vector() return Operation( "set", Entity(self.entity.id, _direction=Quaternion(Vector3D(0, 0, 1), vector, Vector3D(0, 1, 0)).as_list()))
def touch_operation(self, op): retops = Oplist() if self.props.status and self.props.status < 0: return newloc = extract_location(self) newloc.velocity = Vector3D() # retops += Operation("move", Entity(self.id, location=newloc.copy(), mode="collapsed"), to=self) for item in ['skull', 'ribcage', 'femur', 'pelvis', 'tibia']: newloc.pos = newloc.pos + Vector3D(uniform(-1, 1), uniform(-1, 1), uniform(-1, 1)) retops += Operation("create", newloc.add_to_entity( Entity(name=item, parent=item)), to=self) retops += Operation("set", Entity(self.id, status=-1), to=self) return server.OPERATION_BLOCKED, retops
def move_it_to_loc(self, me): if self.wait > 0: self.wait = self.wait - 1 return if type(self.location) == str: self.location = me.get_knowledge("location", self.location) elif not isLocation(self.location): self.location = Location(self.location, Point3D(0.0, 0.0, 0.0)) if type(self.what) == str: if (self.what in me.things) == 0: return what = me.things[self.what][0] if self.speed == 0 or what.location.parent.id != self.location.parent.id: return Operation("move", Entity(what.id, location=self.location)) iloc = what.location.copy() vel = what.location.pos.unit_vector_to(self.location.pos) iloc.velocity = vel * self.speed self.location.velocity = Vector3D(0.0, 0.0, 0.0) m_op1 = Operation("move", Entity(what.id, location=iloc)) m_op2 = Operation("move", Entity(what.id, location=self.location)) time = ((self.location.pos - what.location.pos).mag() / self.speed) self.wait = (time / const.basic_tick) + 1 m_op2.set_future_seconds(time) return Oplist(m_op1, m_op2)
def _add_obstacles(m): for i in range(0, num_obstacles): xpos = uniform(xmin, xmax) ypos = uniform(ymin, ymax) orient = Quaternion(Vector3D(0, 1, 0), uniform(0, pi * 2.0)) m.make('stone_palisade', pos=(xpos, ypos, defaultZ), orientation=orient.as_list())
def sow_operation(self, op): """ Op handler for sow op which activates this task """ if len(op) < 1: sys.stderr.write("Fish task has no target in sow op") # FIXME Use weak references, once we have them self.target = server.world.get_object_ref(op[0].id) self.tool = op.to self.pos = Point3D(op[0].pos) #self.character.contains is a list of entities inside the player's inventory bait = 0 for item in self.character.contains: if item.type[0] in self.baitlist: bait = item #self.character.contains.remove(item) break else: print("No bait in inventory") self.irrelevant() return if "ocean" not in self.target().type: print("Can fish only in the ocean") self.irrelevant() return self.bait = weakref.ref(bait) self.progress = 0.5 res = Oplist() float_loc = Location(self.character.location.parent) #This is <server.Entity object at 0xb161b90> float_loc.coordinates = self.pos bait_vector = Vector3D(0, -0.5, -0) bait_loc = float_loc.copy() bait_loc.coordinates = bait_loc.coordinates + bait_vector res = Operation("create", Entity(name="bobber", parent="bobber", location=float_loc), to=self.target()) res = res + Operation( "move", Entity(bait.id, location=bait_loc), to=bait) res = res + Operation("create", Entity(parent="fishing_hook", location=Location(bait, Point3D(0, 0, 0))), to=bait) return res
def tick_operation(self, op): """ Op handler for regular tick op """ res = Oplist() if self.target() is None: # print "Target is no more" self.irrelevant() return if not self.target().location.parent: self.irrelevant() return if square_distance(self.character.location, self.target().location) > self.target( ).location.bbox.square_bounding_radius(): return self.next_tick(1) target_location = Location(self.target().location.parent, self.target().location.position) target_location.velocity = Vector3D(0, -0.5, 0) target_entity_moving = Entity(self.target().id, location=target_location) target_location = Location( self.target().location.parent, Point3D(self.target().location.position.x, self.target().location.position.y - 0.1, self.target().location.position.z)) target_location.velocity = Vector3D(0, 0, 0) target_entity = Entity(self.target().id, location=target_location) if not hasattr(self.target(), 'mode') or self.target().props.mode != 'fixed': target_entity.mode = 'fixed' move = Operation("move", target_entity, to=self.target()) move.set_future_seconds(0.2) res.append(move) move = Operation("move", target_entity_moving, to=self.target()) res.append(move) res.append(self.next_tick(1)) return res
def tick_operation(self, op): """ Op handler for regular tick op """ res = Oplist() if self.target() is None: # print "Target is no more" self.irrelevant() return if not self.target().location.parent: self.irrelevant() return target_location = Location(self.target().location.parent, self.target().location.pos) target_location.velocity = Vector3D(0, -0.5, 0) new_loc = self.character.location.pos origin = self.points[0] # Get the diffrence in the location of user at current time to the time when he started the task diff = origin.x - new_loc.x target_entity_moving = Entity(self.target().id, location=target_location) # Replicate the diffrence in position to the corresponding change in height. target_location = Location( self.target().location.parent, Point3D(self.target().location.pos.x, self.target().location.pos.y + diff, self.target().location.pos.z)) target_location.velocity = Vector3D(0, 0, 0) target_entity = Entity(self.target().id, location=target_location) # Make the mode fixed to remove the height constraint on entity. if not hasattr(self.target(), 'mode') or self.target().props.mode != 'fixed': target_entity.mode = 'fixed' move = Operation("move", target_entity, to=self.target()) move.set_future_seconds(0.2) res.append(move) res.append(self.next_tick(1.5)) return res
def tick_operation(self, op): """ Op handler for regular tick op """ res = Oplist() target = server.world.get_object(self.target) if not target: # print "Target is no more" self.irrelevant() return if not target.location.parent: self.irrelevant() return if square_distance(self.character.location, target.location ) > target.location.bbox.square_bounding_radius(): return self.next_tick(1) target_location = Location(target.location.parent, target.location.coordinates) target_location.velocity = Vector3D(0, 0, -0.5) target_entity_moving = Entity(self.target, location=target_location) target_location = Location( target.location.parent, Point3D(target.location.coordinates.x, target.location.coordinates.y, target.location.coordinates.z - 0.1)) target_location.velocity = Vector3D(0, 0, 0) target_entity = Entity(self.target, location=target_location) if not hasattr(target, 'mode') or target.mode != 'fixed': target_entity.mode = 'fixed' move = Operation("move", target_entity, to=self.target) move.setFutureSeconds(0.2) res.append(move) move = Operation("move", target_entity_moving, to=self.target) res.append(move) res.append(self.next_tick(1)) return res
def event(self, me, original_op, op): # FIXME Trigger this on interlinguish instead # FIXME Use the verb rather than the hardcoded RE talk_entity=op[0] if hasattr(talk_entity, "say"): say=talk_entity.say if sowee_pattern.match(say): destination=Location() destination.velocity=Vector3D(0,0,0) return Operation("move", Entity(me.id, location=destination))
def think_operation(self, op): args = op.getArgs() for thought in args: #Check if there's a 'predicate' set; if so handle it as knowledge. #Else check if it's things that we know we own or ought to own. if hasattr(thought, "predicate") == False: if hasattr(thought, "things"): things = thought.things for (id, thinglist) in things.items(): #We can't iterate directly over the list, as it's of type atlas.Message; we must first "pythonize" it. #This should be reworked into a better way. thinglist = thinglist.pythonize() for thingId in thinglist: thingId = str(thingId) thing = self.map.get(thingId) if thing and thing.type[0]: self.add_thing(thing) else: self.pending_things.append(thingId) elif hasattr(thought, "pending_things"): for id in thought.pending_things: self.pending_things.append(str(id)) elif hasattr(thought, "goal"): goalElem = thought.goal id = str(goalElem["id"]) goal = self.find_goal(id) if goal: if "definition" in goalElem: self.update_goal(goal, str(goalElem["definition"])) else: self.remove_goal(goal) else: subject = thought.subject predicate = thought.predicate object = thought.object #handle goals in a special way if predicate == "goal": self.add_goal(subject, object) else: #Handle locations. if len(object) > 0 and object[0] == '(': #CHEAT!: remove eval locdata = eval(object) #If only coords are supplied, it's handled as a location within the same parent space as ourselves if (len(locdata) == 3): loc = self.location.copy() loc.coordinates = Vector3D(list(locdata)) elif (len(locdata) == 2): where = self.map.get_add(locdata[0]) coords = Point3D(list(locdata[1])) loc = Location(where, coords) self.add_knowledge(predicate, subject, loc) else: self.add_knowledge(predicate, subject, object)
def get_quality(self, location, target, moisture): y = location.y yval = math.exp(-y*y/2) if not hasattr(target, 'location'): self.irrelevant() return 0 normal = target.location.parent.terrain.get_normal(location.x, location.z) #print normal i = Vector3D(1, 0, 0) slope = normal.dot(i) / normal.mag() return yval + moisture + (1 - slope)
def do_amble(self, me): id = me.get_knowledge('focus', 'hook') if id is not None: thing = me.map.get(id) if thing is None: me.remove_knowledge('focus', self.what) else: if thing.parent.id != me.entity.parent.id: me.remove_knowledge('focus', self.what) else: if thing.parent.id == me.entity.id: return # world = # ground = world.id # op = Operation("eat", ground) # print "Fish ambling" target = Location(me.entity.parent, me.entity.location.pos) target.pos = Vector3D(target.pos.x + uniform(-1.5, 1.5), target.pos.y, target.pos.z + uniform(-1.5, 1.5)) target.velocity = Vector3D(1, 0, 0) return Operation("move", Entity(me.entity.id, location=target))
def tick_operation(self, op): """ Op handler for regular tick op """ # print "Reap.tick" if self.target() is None: # print "Target is no more" self.irrelevant() return if self.count == 0: self.count = int(self.target().mass) # print "setting target mass to ", self.count if not self.character.location.velocity.is_valid() or \ self.character.location.velocity.square_mag() < 1 or \ self.character.location.velocity.square_mag() > 10: self.rate = 0 self.progress = 0 # print "Not moving the right speed" return self.next_tick(1.75) old_rate = self.rate self.rate = 1.0 / 1.75 self.progress = 0.01 if old_rate < 0.1: # print "Wasn't moving right speed" return self.next_tick(1.75) surface = self.target().terrain.get_surface( self.character.location.coordinates) if surface is not 2: # print "Not grass" return self.next_tick(1.75) res = Oplist() chunk_loc = Location(self.character.location.parent) chunk_loc.velocity = Vector3D() chunk_loc.coordinates = self.character.location.coordinates create = Operation("create", Entity(name="grass", type="grass", location=chunk_loc), to=self.target()) res.append(create) res.append(self.next_tick(1.75)) return res
def face(self, other): """ Turn to face that another character, ensuring that we are facing the character we are hitting """ vector = distance_to(self.character.location, other.location) vector.z = 0 if vector.square_mag() < 0.1: return vector = vector.unit_vector() newloc = Location(self.character.location.parent) newloc.orientation = Quaternion(Vector3D(1, 0, 0), vector) return Operation("move", Entity(self.character.id, location=newloc))
def tick_operation(self, op): """ Op handler for regular tick op """ # print "Dig.tick" if self.target() is None: print("Target is no more") self.irrelevant() return world = self.target().location.parent material = self.target().name #print material if material not in Sift.materials: print("Not right material for earthworms") self.irrelevant() return old_rate = self.rate self.rate = 0.1 / 1.75 self.progress += 0.1 if old_rate < 0.01: self.progress = 0 # print "%s" % self.pos if self.progress < 1: # print "Not done yet" return self.next_tick(1.75) self.progress = 0 res=Oplist() self_loc = Location(self.character) self_loc.velocity = Vector3D() if hasattr(world, 'moisture'): moisture = 10 * world.moisture else: moisture = 1 self_loc.coordinates = self.pos quality = int(self.get_quality(self_loc.coordinates, self.target(), moisture)) print(quality) for i in range(int(quality/2), quality): res = res + Operation("create", Entity(name = "scrawny earthworm", parent="annelid", location = self_loc), to=self.character) for i in range(int((10-quality)/2), quality): res = res + Operation("create", Entity(name = "juicy earthworm", parent="annelid", location = self_loc), to=self.character) self.irrelevant() return res
def setup_operation(self, op): ret = Oplist() # West wall with door loc = Location(self, Point3D(0,0,-1)) loc.bbox = Vector3D(0.1,2,4) ret.append(Operation("create",Entity(parents=['wall'],location=loc),to=self)) loc = Location(self, Point3D(0,4,-1)) loc.bbox = Vector3D(0.1,2,4) ret.append(Operation("create",Entity(parents=['wall'],location=loc),to=self)) # South wall loc = Location(self, Point3D(0,0,-1)) loc.bbox = Vector3D(9,0.1,4) ret.append(Operation("create",Entity(parents=['wall'],location=loc),to=self)) # North wall loc = Location(self, Point3D(0,5.9,-1)) loc.bbox = Vector3D(9,0.1,4) ret.append(Operation("create",Entity(parents=['wall'],location=loc),to=self)) # East wall loc = Location(self, Point3D(8.9,0,-1)) loc.bbox = Vector3D(0.1,6,4) ret.append(Operation("create",Entity(parents=['wall'],location=loc),to=self)) return ret
def tick_operation(self, op): """ Op handler for regular tick op """ # print "Raise.tick" if self.target() is None: # print "Target is no more" self.irrelevant() return if not self.target().location.parent: # Not withstanding famous quotes to the contrary, in these # system we can not move the world no matter how large a lever # or firm a place to stand we have. self.irrelevant() return distance = distance_to(self.character.location, self.target().location) # Check we are not too far away from the object to interact with it # This calculation is imprecise as it sums the square radii, but # its usually close enough. d = distance.square_mag() r = self.character.location.bbox.square_bounding_radius() + \ self.target().location.bbox.square_bounding_radius() if d > r: return self.next_tick(1) if d < const.epsilon: # print "Going nowhere" return self.next_tick(1) # print "DISTANCE ", distance, distance.is_valid() axis = distance.cross(Vector3D(0, 0, 1)) # If distance is zero, axis becomes zero # print "DISTANCE ", distance, distance.is_valid(), axis, axis.is_valid() # If axis is zero, the quaternion contains NaNs. rotation = Quaternion(axis, -0.05) # print "ROT ", rotation, rotation.is_valid() if self.target().location.orientation.is_valid(): # print "VALID" rotation = self.target().location.orientation * rotation # print "NEW_ROT", rotation, rotation.is_valid() target_location = Location(self.target().location.parent, self.target().location.coordinates) target_location.orientation = rotation move = Operation("move", Entity(self.target().id, location=target_location), to=self.target()) res = Oplist() res.append(move) res.append(self.next_tick(0.5)) return res
def tick_operation(self, op): """ Op handler for regular tick op """ # print "Dig.tick" if self.target() is None: # print "Target is no more" self.irrelevant() return old_rate = self.rate self.rate = 0.1 / 1.75 self.progress += 0.1 if old_rate < 0.01: self.progress = 0 # print "%s" % self.pos if self.progress < 1: # print "Not done yet" return self.next_tick(1.75) self.progress = 0 surface = self.target().terrain.get_surface(self.pos) # print "SURFACE %d at %s" % (surface, self.pos) if surface not in Dig.materials: print "Not right" self.irrelevant() return res = Oplist() chunk_loc = Location(self.character.location.parent) chunk_loc.velocity = Vector3D() chunk_loc.coordinates = self.pos create = Operation("create", Entity(name=Dig.materials[surface], type="pile", material=Dig.materials[surface], location=chunk_loc), to=self.target()) create.setSerialno(0) res.append(create) res.append(self.next_tick(1.75)) return res
def _add_agents(m): for i in range(0, num_humans): xpos = uniform(xmin, xmax) ypos = uniform(ymin, ymax) orient = Quaternion(Vector3D(0, 0, 1), uniform(0, pi * 2.0)) h = m.make('human', pos=(xpos, ypos, defaultZ), orientation=orient.as_list()) m.know(h, [('w1', 'location', (uniform(xmin, xmax), uniform(ymin, ymax), defaultZ)) , ('w2', 'location', (uniform(xmin, xmax), uniform(ymin, ymax), defaultZ)) , ('w3', 'location', (uniform(xmin, xmax), uniform(ymin, ymax), defaultZ)) , ('w4', 'location', (uniform(xmin, xmax), uniform(ymin, ymax), defaultZ))]) m.learn(h, [(il.patrol, "patrol(['w1', 'w2', 'w3', 'w4'])")])