def process_action(self, action): """Process this Action by executing its phase sequence within a list of prefixes. The necessary arguments for each phase are pulled from the provided keyword arguments. The return value accumulates the method return values into a list like so: ["believe", "can", "do"] x ["touch", "get", "drop"] = ["believe_touch", "can_touch", "do_touch", "believe_get", "can_get", "do_get", "believe_drop", "can_drop", "do_drop"] If any function returns False, processing will stop, meaning that the return value has variable length.""" debug.log("ACT: %s" % action.__class__.get_name()) ctx = action.context # ctx.set_active(action.__class__) # This is a generator, so we can check the Context object for a # different list of phases between go-arounds. for phase in action.get_phases(): phase.context = ctx result = self.process_phase(phase) ctx.append_result(action.__class__, result) outcome, cause = ctx.parse_result(result) if outcome is False: break return ctx.parse_results(action.__class__)
def react(self): key = kernel.input.pop() if key: command = Command(key, self.keybindings.get(key, False)) if command: debug.log("{} received command: {}".format(self, command)) self.push(command) return command
def input(self, command): """Recurse through children trying their keyin functions until you've done your own.""" debug.log("{} received command: {}.".format(self, command)) for child in reversed(self.children): if child.input(command) is False or child.blocking is True: return False return self.process(command)
def react(self): """Get key codes from the display. If there is one, push it to the keyin service.""" event = self.display.input() if event is not -1: # TODO: Handle mice. key_name = self.key_name(event) debug.log("Input event: `{}` => `{}`".format(event, key_name)) if key_name == "Ctrl+c": assert False, "Keyboard interrupt!" self.push(key_name)
def _act(self): if not self.turn(): debug.die("%s tried to act when not the acting actor in queue %s." % (self, Queue)) if self.controlled: debug.die("Player-controlled actor %s tried to hit AI code." % self.appearance()) # If we don't have a target, try to find a new one. if not self.pathing.target and not self.pathing.retarget(): # wander aimlessly return self.do(random.choice(dirs)) # Repath if our current target isn't correct if self.pathing.target: if self.pathing.target.coords != self.pathing.destination: self.pathing.destination = self.pathing.target.coords if isinstance(self.pathing.destination, tuple): debug.die([self, self.pathing.destination, self.pathing.target]) self.pathing.repath() # Calculate the distance to the target. self.pathing.distance = self.distance(self.pathing.target) else: if isinstance(self.pathing.destination, tuple): debug.die([self, self.pathing.destination, self.pathing.target]) self.pathing.repath() # TODO: If within attack range, do so. # if self.preferred_reach(self.distance) is True: # return self.do(sub(self.target.coords, self.coords)) # If we've successfully pathed, follow it. if self.pathing.path: debug.log("%s had a path." % self.appearance()) next_step = self.pathing.path.pop() next_dir = next_step - self.coords # # HACK, fixes stuff like teleporting # if dir not in dirs: # self.path.append(pos) # dir = CC if self.map.cell(next_step).can_block(self, next_dir): # TODO: Randomize choice here for alt_dir in arc(next_dir)[1:]: # We already checked the first one alt_next = self.coords + alt_dir # Prefer unoccupied cells, but accept sharing. if not self.map.cell(alt_pos).occupied(): next_dir = alt_dir break elif self.map.cell(alt_pos).blocked(alt_dir) is False: next_dir = alt_dir self.do(next_dir)
def launch(self, package_choice): """Spawn the selected module's main.Game as a child Component and then launch it.""" # TODO: Handle multiple game folders # TODO: Permit class names other than 'main' package_name, package_info = package_choice # e.g., hellmouth, Hellmouth, <description>, <version> game_module = __import__('src.games.%s.main' % package_name, globals(), locals(), ['main']) game_class = game_module.main debug.log("In launch") # Spawn the game as a child Component, and then launch it. self.game = self.spawn(game_class()) self.game.launch() debug.log("Launched the game!")
def react(self): """Loop drawing, keyin, and event processing through this Component and into its children. If still alive, perform a Game loop.""" # Input tree. command = kernel.command.pop() if command: self.input(command) # The RootComponent dies if it has no children. if not self.children: self.alive = False if self.alive and self.game: debug.log("Acting game: {}".format(self.game)) self.game.loop()
def process_phase(self, phase): """Process a Phase object. Returns an outcome and a cause, based on the Context's parsing. """ ctx = phase.context ctx.set_active(phase) debug.log("PHASE: %s" % phase.name) # TODO: 7DRL ctx.require_arguments(phase.required_arguments) # arguments = {} # for argument in phase.required_arguments: # arguments[phase.aliases.get(argument, argument)] = ctx.get_argument(argument) arguments = {} for argument in phase.required_arguments: send = ctx.get_argument(argument) send_as = phase.aliases.get(argument, argument) arguments[send_as] = send is_method = getattr(ctx.agent, "is" + "_" + phase.name, None) if is_method: is_result = is_method(**arguments) outcome, cause = ctx.parse_result(is_result) if outcome: debug.log("***PHASE SATISFIED***: %s (%s)" % ("is" + "_" + phase.name, outcome)) return True, "done" # TODO: Rewrite this entire section, augh could_result = getattr(ctx.agent, "could" + "_" + phase.name)() outcome, cause = ctx.parse_result(could_result) debug.log("METHOD: %s (%s)" % ("could" + "_" + phase.name, outcome)) if not outcome: return False, "could" + "_" + phase.name can_result = getattr(ctx.agent, "can" + "_" + phase.name)(**arguments) outcome, cause = ctx.parse_result(can_result) debug.log("METHOD: %s (%s)" % ("can" + "_" + phase.name, outcome)) if not outcome: return False, "can" + "_" + phase.name result = getattr(ctx.agent, "do" + "_" + phase.name)(**arguments) outcome, cause = ctx.parse_result(result) debug.log("METHOD: %s (%s)" % ("do" + "_" + phase.name, outcome)) ctx.append_result(phase.__class__, result) return outcome, cause
def process_command(self, command): """Process a Command object by attempting to process each of its Actions in sequence. Returns an outcome and a cause, based on the Context's parsing. """ ctx = command.context # ctx.set_active(command.__class__) debug.log("CMD: %s." % command.__class__.get_name()) # This is a generator, so we can check the Context object for a # different list of actions between go-arounds. for action_class in command.get_actions(ctx): action = action_class(command) result = self.process_action(action) ctx.append_result(command.__class__, result) outcome, cause = ctx.parse_result(result) if outcome is False: break return ctx.parse_results(command.__class__)
def process_event(self, event, context): """Find the first Command matching an event, instantiate it, and process it.""" if not self.turn(): debug.die("Event %s by %s; should be acting: %s; queue: %s" % (event, self.appearance(), Queue.get_acting().appearance(), [a.appearance() for a in Queue.queue])) if event not in ["Up", "Down"]: debug.log("EVENT: %s" % event) for command_class, command_arguments in context.get_commands(): for command_event in command_class.get_events(): if event != command_event: continue command = command_class(context) context.update_arguments(**command_arguments) result = self.process_command(command) outcome, cause = context.parse_result(result) if outcome is True: debug.log("(+): %s" % cause) Log.add("(+): %s" % cause) else: debug.log("(-): %s" % cause) Log.add("(-): %s" % cause) # TODO: Something else to decide this self.end_turn() # TODO: Instead return whether the event was consumed. return outcome, cause if event not in ["Up", "Down"]: debug.log("( ): %s" % event) Log.add("( ): %s" % event) # TODO: Instead return whether the event was consumed. return False
def retarget(self): target = self.owner.call("Faction", "get_target").get_result() if target: self.target = target self.destination = self.target.coords debug.log("%s retargeted to %s." % (self.owner.appearance(), self.target.appearance())) return True destination = self.owner.call("Faction", "get_destination").get_result() if destination: self.destination = destination debug.log("%s found no target but instead a destination." % self.owner.appearance()) return True # Move somewhere random. debug.log("%s failed to retarget." % self.owner.appearance()) self.destination = random.choice([h for h in Hexagon.area(self.owner.coords, 10)]) return True
from src.lib.util import debug from src.lib.util.define import * from src.lib.util import system debug.log("Completed all imports.") # Import and initialize the Unicursal kernel. from src.lib.core.kernel import kernel debug.log("Kernel initialization complete.") # Set a bitmask for game-wide display modes. displayflags = { "silent" : 0b1, "curses" : 0b10, "unicode" : 0b100, "256" : 0b1000, } # Set up a dictionary of game settings. # TODO: Have the kernel parse this. arguments = {} # Add a folder with default configurations. arguments["configuration"] = 'src/lib/data/configuration' # Default to displaying with curses arguments["displaymode"] = displayflags["curses"] # Default to launching Meat Arena # TODO: If not provided, always get a game launcher
def run(self): """Run an instance of the main application loop.""" # Allow services to react to the loop. for service in kernel.loop: debug.log("Acting service: {}".format(service)) service.react()
def act(self): debug.log("%s started turn." % self.appearance()) self._act() debug.log("%s ended turn." % self.appearance()) self.end_turn()
def repath(self): debug.log("%s repathed." % self.owner.appearance()) self.astar = AStar(self.owner, self.owner.map) self.path = self.astar.path(self.owner.coords, self.destination)
def draw(self, display): for text, color in self.get_controller().values("Status", "get_view_data", self): debug.log("text: %s, color: %s" % (text, color)) display.line(self, text, color) return True
def pop(self): if self.queue: command = self.queue.pop() debug.log("{} popped: {}".format(self, command)) return command
def __exit__(self, exception_type, exception_val, trace): """Tell the display to stop using curses.""" debug.log("{}: {}".format(exception_type, exception_val)) self.display.reset_mode() del self.display
def push(self, value): debug.log("{} pushed: {}".format(self, value)) self.queue.append(value)