def event(self, me, op, say): object = say[1].word thing = me.map.get(object) who = me.map.get(op.to) if thing is None: if object != self.what: return Operation("talk", Entity(say=who.name + ", I am not interested in buying your " + str(object) + ".")) me.goals.insert(0, BuyFrom(self.what, self.cost, op.to)) return Operation("talk", Entity(say=who.name + " which " + object + " would you like to sell?")) if self.what not in thing.type: return if thing in me.find_thing(self.what): return # price=me.get_knowledge("price", thing.type[0]) price = self.cost * int(thing.mass) res = Oplist() coins = me.find_thing("coin") if len(coins) < int(price): print("Coins: " + str(len(coins)) + " Cost: " + str(self.cost)) return Operation("talk", Entity(say="I can't afford any " + self.what + "s at the moment.")) for i in range(0, int(price)): coin = coins[0] me.remove_thing(coin) res.append(Operation("move", Entity(coin.id, location=Location(who, Point3D(0, 0, 0))))) res.append(Operation("talk", Entity(say="Thankyou " + who.name + ", come again."))) me.add_thing(thing) return res
def consume_operation(self, op): if len(op) > 0: arg = op[0] if arg.consume_type == "fire": # Determine the burn speed, i.e. how much to remove of the status for each burn burn_speed = 0.1 burn_speed_prop = self.props._burn_speed if burn_speed_prop: burn_speed = burn_speed_prop nourish_ent = Entity() nourish_ent.consume_type = arg.consume_type nourish_op = Operation("nourish", nourish_ent, to=op.from_) status_prop = self.props.status if status_prop: return server.OPERATION_BLOCKED, nourish_op, Operation( "set", Entity(self.id, status=status_prop - burn_speed), to=self) else: return server.OPERATION_BLOCKED, nourish_op return server.OPERATION_IGNORED
def do(self, me): if (self.tool in me.things) == 0: # print "No tool" return tool = me.find_thing(self.tool)[0] if not hasattr(me, 'right_hand_wield') or me.right_hand_wield != tool.id: # FIXME We need to sort out how to tell seed one is wielding return Operation("wield", Entity(tool.id)) id = me.get_knowledge('focus', self.seed) if id is None: return seed = me.map.get(id) if seed is None: me.remove_knowledge('focus', self.seed) return if not seed.visible: me.remove_knowledge('focus', self.seed) return # Check that the seed isn't too close to other sources (to prevent us from planting too closely) sources_all = me.map.find_by_filter(self.source_filter) spacing_sqr = self.spacing * self.spacing for thing in sources_all: sqr_dist = square_distance(seed.location, thing.location) if sqr_dist and sqr_dist < spacing_sqr: # We've found a source which is too close to the seed, so we'll not plant this one me.remove_knowledge('focus', self.seed) return return Operation("use", Entity(seed.id, objtype="obj"))
def transact(self, me): employer = me.get_knowledge('employer', me) if employer: print('Already employed by ' + employer) return Operation( "talk", Entity(say="Sorry, I am currently working for someone else.")) who = me.map.get(self.who) if not who: print("Who am I talking to") return if self.payed < self.cost: return Operation( "talk", Entity(say=who.name + " you owe me " + str(self.cost - self.payed) + " coins.")) res = Oplist() me.add_knowledge('employer', me.entity.id, who.id) # FIXME add the new goal goal = Accompany(who.id) me.goals.insert(0, goal) res.append( Operation("talk", Entity(say="I will help you out until sundown today."))) self.irrelevant = 1 return res
def completed(self): res = Oplist() # Find one charcoal and one ore amongst the children and delete them, and create one iron ingot. charcoals = self.usage.tool.find_in_contains(charcoal_filter) if len(charcoals): # We have charcoal, lets see if we also have something to smelt. We'll go through the map of ores to find a match. for key, value in ores.items(): inputs = self.usage.tool.find_in_contains(value) if len(inputs) > 0: res.append( Operation("delete", Entity(inputs[0].id), to=inputs[0])) res.append( Operation("delete", Entity(charcoals[0].id), to=charcoals[0])) new_entity = Entity(parent=key, loc=self.usage.tool.id) res.append( Operation("create", new_entity, to=self.usage.tool.id)) res.append( Operation( "imaginary", Entity( description="You successfully refine the ore." ), to=self.usage.actor.id, from_=self.usage.actor.id)) return res
def consume(instance): """ When drinking the potion the __effects should be applied to the drinker, and the potion destroyed. In addition, if a script handler is registered in the __handler property it will be called as well. """ op_list = Oplist() op_list += Operation("delete", Entity(instance.tool.id), to=instance.tool) handler_props = instance.tool.props["__handler"] if handler_props is not None: mod_name, func_name = handler_props["name"].rsplit('.', 1) mod = importlib.import_module(mod_name) func = getattr(mod, func_name) result = func(instance) if result: op_list.append(result) effects_prop = instance.tool.props["__effects"] if effects_prop is not None: # Copy over all props in "__effects" to a "set" op. for prop_name, effect in effects_prop.items(): ent = Entity(instance.actor.id) ent[str(prop_name)] = effect op_list += Operation("set", ent, to=instance.actor.id) msg_prop = instance.tool.props["__message"] if msg_prop is not None: op_list += Operation("imaginary", Entity(description=str(msg_prop)), to=instance.actor.id, from_=instance.actor.id) op_list.append(instance.actor.start_action("drinking", 1)) return server.OPERATION_BLOCKED, op_list
def consume(instance): """ When drinking the potion the __effects should be applied to the drinker, and the potion destroyed """ op_list = Oplist() op_list += Operation("delete", Entity(instance.tool.id), to=instance.tool) effects_prop = instance.tool.props["__effects"] if effects_prop is not None: for prop_name, effect in effects_prop.items(): actual_value = effect effect_prop = instance.actor.props[prop_name] if effect_prop is not None: actual_value = effect_prop + effect ent = Entity(instance.actor.id) ent[str(prop_name)] = actual_value op_list += Operation("set", ent, to=instance.actor.id) msg_prop = instance.tool.props["__message"] if msg_prop is not None: op_list += Operation("imaginary", Entity(description=str(msg_prop)), to=instance.actor.id, from_=instance.actor.id) return server.OPERATION_BLOCKED, op_list
def equip_melee_weapon(self, me): # First check if we're holding a weapon attached_current = me.get_attached_entity("hand_primary") has_attached = False if attached_current: has_attached = True # Check that the attached entity can be used to strike usages = attached_current.get_prop_map("usages") if usages: for usage, _ in usages.items(): if usage in weapon_usages: self.weapon_usage = usage return None # Current tool isn't a weapon, or we have nothing attached, try to find one, # and if not unequip so we can fight with our fists for child in me.entity.contains: usages = child.get_prop_map("usages") if usages: for usage, _ in usages.items(): if usage in weapon_usages: self.weapon_usage = usage return Operation("wield", Entity(child.id, attachment="hand_primary")) # Couldn't find any weapon to wield, check if we should unwield the current tool so we can fight with our fists if has_attached: return Operation("wield", Entity(attachment="hand_primary")) return None
def tick_operation(self, op): res = Oplist() if verify_tick(self, op, res, self.tick_interval): # Default to 1.0 for max scale, unless something is set. max_scale = 1.0 if self.props.maxscale: max_scale = self.props.maxscale if self.props.mass and self.props.density and self.props.bbox and self.props._nutrients and self.props._nutrients > 0: # Use half of the nutrients to grow new_mass = self.props.mass + (self.props._nutrients * 0.5) bbox_unscaled = self.props.bbox volume_vector = bbox_unscaled.high_corner - bbox_unscaled.low_corner volume_unscaled = volume_vector.x * volume_vector.y * volume_vector.z volume_new = new_mass / self.props.density new_scale = min(pow(volume_new / volume_unscaled, 0.33333), max_scale) if not self.props.scale or new_scale != self.props.scale: set_ent = Entity(scale=[new_scale]) # check how much nutrient really was used final_new_mass = new_scale * volume_new * self.props.density set_ent._nutrients = self.props._nutrients - ( final_new_mass - self.props.mass) res += Operation("set", set_ent, to=self) return server.OPERATION_BLOCKED, res return server.OPERATION_IGNORED
def stop_usage(self, args): # Check that the usage still is valid (valid, _) = self.usage.is_valid() self.irrelevant() res = Oplist() if valid and self.fish_on_hook: worms = self.usage.actor.find_in_contains( entity_filter.Filter("entity instance_of types.annelid")) if len(worms): fish_type = self.fishes[randint(0, len(self.fishes) - 1)] res.append( Operation("create", Entity(parent=fish_type, loc=self.usage.actor.id, mind=None), to=self.usage.tool)) # Delete the worm res.append( Operation("delete", Entity(id=worms[0].id), to=worms[0].id)) res.append( Operation( "imaginary", Entity( description="You caught a {}.".format(fish_type)), to=self.usage.actor.id, from_=self.usage.actor.id)) return server.OPERATION_HANDLED, res
def tick_operation(self, op): if len(op) > 0: arg = op[0] if arg.name == self.__class__.__name__: res = Oplist() # Handle the world being recreated by checking for 0 if op.refno == self.tick_refno or self.tick_refno == 0: minds_prop = self.get_prop_list("_minds") if hasattr(arg, "type") and arg.type == "remove": # Check that the entity hasn't gotten a new mind in the meantime if minds_prop is None or len(minds_prop) == 0: # Move entity to limbo limbo_entity = server.get_alias_entity("limbo") if limbo_entity and self.location.parent != limbo_entity: # Store the current position in "__respawn" so we can spawn back there. res += Operation( "set", Entity(self.id, __respawn={ "loc": self.location.parent.id, "pos": self.location.pos }), to=self.id) res += Operation("move", Entity(self.id, loc=limbo_entity.id), to=self.id) else: # Only respawn if there's a mind if minds_prop is not None and len(minds_prop) > 0: res += self.respawn() return server.OPERATION_BLOCKED, res
def delete_operation(self, op): res = Oplist() # Restore status if it's zero. if self.has_prop_float("status"): res += Operation("set", Entity(self.id, status=1.0), to=self.id) # Respawn in a spawn area respawn_alias = self.get_prop_string("_respawning") if respawn_alias: respawn_entity = server.get_alias_entity(respawn_alias) if respawn_entity: pos = Spawner.get_spawn_pos(respawn_entity) if pos: location = Location() location.pos = pos # Randomize orientation rotation = random.random() * math.pi * 2 location.orientation = physics.Quaternion(physics.Vector3D(0, 1, 0), rotation) location.parent = respawn_entity.location.parent # Emit a sight of this entity being defeated res += Operation("sight", Operation("defeated", Entity(self.id))) res += Operation("move", Entity(self.id, location=location), to=self.id) res += Operation("imaginary", Entity(description="You were killed and will be respawned."), to=self.id, from_=self.id) return server.OPERATION_BLOCKED, res
def respawn(self): limbo_entity = server.get_alias_entity("limbo") # If we're in limbo we should respawn if limbo_entity and self.location.parent == limbo_entity: respawn_prop = self.props["__respawn"] if respawn_prop: set_op = Operation("set", Entity(self.id, __respawn=None), to=self.id) if hasattr(respawn_prop, "pos") and hasattr( respawn_prop, "loc"): return Operation("move", Entity(self.id, pos=respawn_prop.pos, loc=respawn_prop.loc), to=self.id), set_op elif hasattr(respawn_prop, "spawn") and respawn_prop.spawn: # Respawn in a spawn area respawn_entity = server.get_alias_entity( respawn_prop.spawn) if respawn_entity: location = respawn_entity.location return Operation("move", Entity(self.id, location=location), to=self.id), set_op else: print( "Could not get any entity with alias '{}'.".format( respawn_prop.spawn))
def dig_operation(self, op): arg = op[0] if not arg: return server.OPERATION_IGNORED if not arg.pos: print('No pos supplied') return server.OPERATION_IGNORED terrain_prop = self.props.terrain if not terrain_prop: print('No terrain prop on diggable terrain entity') return server.OPERATION_IGNORED surface = self.props.terrain.get_surface_name(arg.pos[0], arg.pos[2]) if surface not in DiggableTerrain.materials: print("The surface couldn't be digged here. Material {}.".format( surface)) return server.OPERATION_IGNORED material = DiggableTerrain.materials[surface] chunk_loc = Location(self, arg.pos) print("Creating pile of {} at {}".format(material, chunk_loc)) new_entity = Entity(name="Pile of {}".format(material), parent="pile", material=material, location=chunk_loc) if material == 'earth': new_entity._worms = random.randint(0, 3) create_op = Operation("create", new_entity, to=self.id) return server.OPERATION_BLOCKED, create_op
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 hit_operation(self, op): res = Oplist() arg = op[0] if arg: # Place the explosion at the point of collision. new_location = rules.Location(self.location.parent, arg.pos) entity = Entity(parent="explosion", location=new_location, mode="fixed") mode_data = self.props.mode_data actor_id = self.id # Check if there's an entity ref contained in the mode_data prop, # and if so attach that to the "entity_ref" prop of the explosion. # This way the explosion can properly attribute any Hit op it sends to the actor which fired the item. if mode_data: entity_ref = mode_data['$eid'] if entity_ref is not None: actor_id = entity_ref entity["entity_ref"] = {"$eid": actor_id} damage_explosion = self.props.damage_explosion if damage_explosion is not None: entity["damage"] = damage_explosion res.append(Operation("create", entity, to=self.id)) res.append(Operation("delete", Entity(self.id), to=self.id)) return server.OPERATION_HANDLED, res
def think_look_operation(self, op): """Sends back information about goals. This is mainly to be used for debugging minds. If no arguments are specified all goals will be reported, else a match will be done using 'index'. The information will be sent back as a Think operation wrapping an Info operation. This method is automatically invoked by the C++ BaseMind code, due to its *_*_operation name. """ think_op = Operation("think") goal_info_op = Operation("info") goal_infos = [] if not op.get_args(): # get all goals for (index, goal) in enumerate(self.goals): goal_infos.append(Entity(index=index, report=goal.report())) else: for arg in op.get_args(): goal = self.goals[arg.index] if goal and goal is not None: goal_infos.append( Entity(index=arg.index, report=goal.report())) goal_info_op.set_args(goal_infos) think_op.set_refno(op.get_serialno()) think_op.set_args([goal_info_op]) res = Oplist() res = res + think_op return res
def completed(self): res = Oplist() if self.is_valid(): for input_def in self.temporaries["inputs"]: input_entities = self.usage.actor.find_in_contains( input_def["criteria"]) needed_amount = input_def["amount"] for entity in input_entities: entity_amount = entity.get_prop_int("amount", 1) amount_to_delete = min(needed_amount, entity_amount) res.append( Operation("delete", Entity(entity.id, amount=amount_to_delete), to=entity)) needed_amount = needed_amount - amount_to_delete if needed_amount <= 0: break for output_def in self.temporaries["outputs"]: res.append( Operation("create", output_def, to=self.usage.tool.id)) craft_name = self.usage.tool.get_prop_string("craft_name", "tool") res.append( Operation( "imaginary", Entity(description="You successfully create '{}'.".format( craft_name)), to=self.usage.actor.id, from_=self.usage.actor.id)) return res
def do_peck(self, me): if not self.last_time or time.time() - self.last_time > self.interval: self.last_time = time.time() # stop moving me.steering.set_destination() return Operation("use", Operation("consume", Entity(me.entity.id, targets=[Entity(me.entity.parent.id, pos=me.entity.location.pos)])))
def attack_ranged(self, me): enemy = self.get_enemy(me) # check that we can reach the target, and if so attack it distance = me.steering.distance_to(enemy, ai.EDGE, ai.EDGE) if distance is None: print("Could not calculate distance.") return attached_current = me.get_attached_entity("hand_primary") tasks_prop = me.entity.get_prop_map('tasks') if distance < 50: move_to_face = me.face(enemy) if attached_current: # Check if we're already drawing if tasks_prop and "draw" in tasks_prop: # Check if we can release draw_task = tasks_prop["draw"] # print("draw task {}".format(str(draw_task))) usages = draw_task["usages"] for usage in usages: if usage.name == "release": direction = (enemy.location.pos + enemy.location.bbox.center) - (me.entity.location.pos + me.entity.location.bbox.center) direction.normalize() return move_to_face + Operation("use", Root(args=[Entity("release", direction=[direction])], id="draw", objtype="task")) return True direction = enemy.location.pos - me.entity.location.pos direction.normalize() return move_to_face + Operation("use", Operation("draw", Entity(attached_current.id, direction=[direction])))
def do(self, me): if (self.tool in me.things) == 0: # print "No tool" return tool = me.find_thing(self.tool)[0] if not hasattr(me, 'right_hand_wield') or me.right_hand_wield != tool.id: # FIXME We need to sort out how to tell seed one is wielding return Operation("wield", Entity(tool.id)) id = me.get_knowledge('focus', self.seed) if id is None: return seed = me.map.get(id) if seed is None: me.remove_knowledge('focus', self.seed) return if not seed.visible: me.remove_knowledge('focus', self.seed) return # Check that the seed isn't too close to other sources (to prevent us from planting too closely) sources_all = me.map.find_by_filter(self.source_filter) for thing in sources_all: #TODO: add "distance_between"; this won't work dist = me.steering.distance_to(thing, ai.EDGE, ai.EDGE) if dist is not None and dist < self.spacing: # We've found a source which is too close to the seed, so we'll not plant this one me.remove_knowledge('focus', self.seed) return return Operation("use", Entity(seed.id, objtype="obj"))
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 strike(instance): """Strike another entity with your fists.""" # If there's a cooldown we need to mark the actor cooldown = getattr(instance.tool.props, "cooldown_" + instance.op.parent) if cooldown and cooldown > 0.0: instance.tool.send_world(Operation('set', Entity(instance.tool.id, ready_at=server.world.get_time() + cooldown), to=instance.tool.id)) # Send sight even if we miss instance.actor.send_world(Operation("sight", instance.op)) # Unarmed strike only handles one target target = instance.get_arg("targets", 0) # Ignore pos if target: if instance.actor.can_reach(target): damage = 0 damage_attr = getattr(instance.actor.props, "damage_" + instance.op.parent) if damage_attr: damage = damage_attr hit_op = Operation('hit', Entity(damage=damage, hit_type=instance.op.parent), to=target.entity, id=instance.actor.id) return server.OPERATION_BLOCKED, hit_op, Operation('sight', hit_op) else: return server.OPERATION_BLOCKED, instance.actor.client_error(instance.op, "Too far away") else: return server.OPERATION_BLOCKED
def harvest_operation(self, op): res = Oplist() if self.props.fruits and self.props.fruits > 0 and self.props.fruit_name: res.append( Operation("create", Entity(parent=self.props.fruit_name, loc=op.id), to=self)) res.append( Operation("set", Entity(self.id, {"fruits!subtract": 1}), to=self)) res.append( Operation( "imaginary", Entity(description="You harvest an {} from the {}.".format( self.props.fruit_name, self.type)), to=op.id, from_=op.id)) else: res.append( Operation( "imaginary", Entity( description="There aren't any {}s in this {}.".format( self.props.fruit_name, self.type)), to=op.id, from_=op.id)) return server.OPERATION_BLOCKED, res
def tick_operation(self, op): res = Oplist() if Ticks.verify_tick(self, op, res, self.tick_interval): # Make ourselves go away after ten ticks by decreasing our status. res.append( Operation("set", Entity(self.id, {"status!subtract": 0.1}), to=self.id)) damage_prop = self.props.damage if self.parent and damage_prop is not None: # If there's an "entity_ref" prop it's the reference to the actor which caused the poisoning. actor_id = self.id entity_ref_prop = self.props.entity_ref if entity_ref_prop is not None: actor_id = entity_ref_prop["$eid"] res.append( Operation('hit', Entity(hit_type="poison", id=actor_id, damage=damage_prop), to=self.parent.id)) return server.OPERATION_HANDLED, res return server.OPERATION_IGNORED
def xp_property_update(self): xp = self.get_prop_float("xp") if xp is not None: level_from_xp = int(math.floor(xp / 100)) level = self.get_prop_int("level") if level is None or level != level_from_xp: return Operation("set", Entity(self.id, level=level_from_xp), to=self.id), \ Operation("imaginary", Entity(description="You are now at level {}!".format(level_from_xp)), to=self.id, from_=self.id)
def do(self, me): if (self.what in me.things) == 0: return if (self.tool in me.things) == 0: return if not hasattr(self, 'wield') or not self.wield: tool = me.find_thing(self.tool)[0] self.wield = True return Operation("wield", Entity(tool.id)) what = me.find_thing(self.what)[0] return Operation("use", Entity(what.id))
def process(self, me): if (self.wbuy in me.things) == 0: return if (self.tool in me.things) == 0: return tool = me.find_thing(self.tool)[0] if not self.wield: self.wield = True return Operation("wield", Entity(tool.id)) thing = me.find_thing(self.wbuy)[0] return Operation("use", Entity(thing.id, objtype="obj"))
def delete_operation(self, op): aggressor = self.get_prop_string("__aggressor") xp_provided = self.get_prop_float("xp_provided") if aggressor and xp_provided: return server.OPERATION_IGNORED, \ Operation("set", Entity(aggressor, {"xp!append": xp_provided}), to=aggressor, from_=aggressor), \ Operation("imaginary", Entity(description="You gain {} xp.".format(xp_provided)), to=aggressor, from_=aggressor) return server.OPERATION_IGNORED
def check(self, me): seller = me.map.get(self.who) if not seller: return for transfer in me.transfers: if transfer[0] != self.who: continue item = me.map.get(transfer[1]) if not item: continue if item.type[0] != self.what: continue # FIXME Removing messes up the for loop me.transfers.remove(transfer) if item.mass: price = int(item.mass * self.cost) coins = me.find_thing("coin") if len(coins) < price: me.remove_thing(item) return Operation("talk", Entity( say="I can't afford to buy that " + self.what + " at the moment.")) + Operation("move", Entity(item.id, location=Location( seller.id, Point3D( 0, 0, 0)))) res = Oplist() for i in range(0, price): coin = coins[0] me.remove_thing(coin) res.append(Operation("move", Entity(coin.id, location=Location(seller, Point3D(0, 0, 0))))) res.append(Operation("talk", Entity( say="Thankyou " + seller.name + ", here are " + str(price) + " coins for the pig."))) self.irrelevant = 1 return res if not hasattr(seller, "right_hand_wield") or not seller.right_hand_wield: return if self.last_valued and seller.right_hand_wield == self.last_valued: return wield = me.map.get(seller.right_hand_wield) if not wield: return if self.what != wield.type[0]: return if not wield.mass: return price = int(wield.mass * self.cost) coins = me.find_thing("coin") self.last_valued = wield.id if len(coins) < price: return Operation("talk", Entity(say="I can't afford to buy that " + self.what + " at the moment.")) else: return Operation("talk", Entity(say=seller.name + " that " + self.what + " is worth " + str(price) + " coins."))