def test_get_part_of_speech(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) pos = dictionary.get_part_of_speech("torch") self.assertEqual(pos, "noun")
def test_lexer(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) parser = Parser(dictionary) src = "take the torch from the table" tokens = parser.lexer(src) self.assertEqual(len(tokens), 6)
def test_words(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) words = dictionary.words self.assertTrue(len(words), 16)
def test_parser_with_adjectives_wrong(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) parser = Parser(dictionary) src = "take the key rusty from the table" tree = parser.parse(src) self.assertFalse(tree)
def test_verb(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) parser = Parser(dictionary) src = "move" tree = parser.parse(src) self.assertTrue(tree) self.assertEqual(tree.verb.verb.word, "move")
def test_parser_with_adjectives(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) parser = Parser(dictionary) src = "take the rusty key from the table" tree = parser.parse(src) self.assertTrue(tree) self.assertTrue(tree.noun_phrase) self.assertEqual(tree.noun_phrase.modifier.adjective.word, "rusty")
def test_parser_phrasal_verb(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) parser = Parser(dictionary) src = "pick up the torch" tree = parser.parse(src) self.assertTrue(tree) self.assertEqual(tree.verb.verb.word, "pick up") self.assertEqual(tree.noun_phrase.noun.word, "torch")
def test_parser_complex(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) parser = Parser(dictionary) src = "take the torch from the table" tree = parser.parse(src) self.assertTrue(tree) self.assertTrue(tree.prep_phrase) self.assertEqual(tree.prep_phrase.prep.prep.word, "from") self.assertEqual(tree.prep_phrase.noun_phrase.noun.word, "table")
def test_visitor_simple(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) parser = Parser(dictionary) src = "move" tree = parser.parse(src) visitor = Visitor() command = tree.accept(visitor) self.assertTrue(command) self.assertEqual(command["verb"], "move")
def test_parser_with_adverb(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) parser = Parser(dictionary) src = "move north" tree = parser.parse(src) self.assertTrue(tree) self.assertTrue(isinstance(tree, VerbPhrase)) self.assertTrue(isinstance(tree.verb.verb.word, str)) self.assertTrue(tree.verb.verb.word, "move") self.assertTrue(tree.adverb_phrase.adverb.word, "north")
def test_parser_simple(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) parser = Parser(dictionary) src = "take the torch" tree = parser.parse(src) self.assertTrue(tree) self.assertTrue(isinstance(tree, VerbPhrase)) self.assertTrue(isinstance(tree.verb.verb.word, str)) self.assertTrue(tree.verb.verb.word, "take") self.assertTrue(tree.noun_phrase.noun.word, "torch")
def test_parser_phrasal_verb_complex(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") dictionary.load_words(filename) parser = Parser(dictionary) src = "pick up the rusty key from the table" tree = parser.parse(src) self.assertTrue(tree) self.assertEqual(tree.verb.verb.word, "pick up") self.assertEqual(tree.noun_phrase.modifier.adjective.word, "rusty") self.assertEqual(tree.noun_phrase.noun_phrase.noun.word, "key") self.assertEqual(tree.prep_phrase.prep.prep.word, "from") self.assertEqual(tree.prep_phrase.noun_phrase.noun.word, "table")
def test_load_words(self): dictionary = Dictionary() filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "tests/dictionary.json") try: dictionary.load_words(filename) except Exception as e: self.assertTrue(False) self.assertTrue(len(dictionary.verbs), 3) self.assertTrue(len(dictionary.nouns), 3) self.assertTrue(len(dictionary.adverbs), 4) self.assertTrue(len(dictionary.prepositions), 3) self.assertTrue(len(dictionary.adjectives), 1) self.assertTrue(len(dictionary.articles), 3)
class Engine: def __init__(self): self._id = 0 self.playing = False self.moved = True self.enemy = None self.npc = None self.combatants = None self.explore_actions = { "move": self.move, "take": self.take, "look": self.look, "search": self.search, "unlock": self.unlock, "throw": self.throw, "drop": self.drop, "examine": self.examine, "trade": self.trade, "sleep": self.sleep, "speak": self.speak, "use": self.use, "consume": self.use, "equip": self.equip, "unequip": self.unequip, "mine": self.use } def init_crafting_systems(self): filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "resources/crafting.json") systems = [] with open(filename) as f: data = json.load(f) for system in data: systems.append(CraftingSystem(self.event_queue, **system)) self.crafting_systems = systems def init_systems(self): self.dictionary = Dictionary() self.input_handler = InputHandler(self.dictionary) self.mob_factory = MobFactory() self.renderer = Renderer() self.event_queue = EventQueue() self.event_queue.register_system(self) self.message_log = MessageLog(self.event_queue) self.combat_system = CombatSystem(self.event_queue) self.init_crafting_systems() def init_game_data(self): self.world_map = WorldMap() # load rooms filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "resources/rooms.json") self.world_map.load_rooms(filename) # load cutscenes filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "resources/cutscenes.json") self.world_map.load_cutscenes(filename) # load items filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "resources/items.json") self.world_map.load_items(filename) #load mobs filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "resources/enemies.json") self.world_map.load_mobs(filename) # load npcs filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "resources/npcs.json") self.world_map.load_npcs(filename) # load quests filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "resources/quests.json") self.world_map.load_quests(filename) # load dictionary filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "resources/dictionary.json") self.dictionary.load_words(filename) def create_player(self): filedir = os.path.dirname(os.path.realpath('__file__')) filename = os.path.join(filedir, "resources/player.json") with open(filename) as f: data = json.load(f) self.player = Player(**data) def get_crafting_system(self, name): """Retreive the specified crafting system.""" for system in self.crafting_systems: if system.name == name: return system def list_items(self, container): """Builds a string containing all items in a container.""" str = "{}{}{}" for i, _id in enumerate(container): item = self.world_map.items[_id] if i == 0: str = str.format(c.yellow, item.name, c.end) continue if i == len(container) - 1: str = "{} and {}{}{}".format(str, c.yellow, item.name, c.end) break str = "{}, {}{}{}".format(str, c.yellow, item.name, c.end) if str != "": if len(container) > 1: str = "You see the following items: {}".format(str) else: if str[0] == "a": str = "You see an {}{}{}.".format(c.yellow, str, c.end) else: str = "You see a {}{}{}.".format(c.yellow, str, c.end) self.event_queue.add_event({"message": str}) def check_object(self, object, container, flag=0): """Checks if the specified object is in the passed container. flag = 0 represents an inanimate container (room or item), whereas flag = 1 represents an animate container (NPC). """ if flag == 0: for _id in container: item = self.world_map.items[_id] if item.name.lower() == object: return item elif flag == 1: names = [ self.world_map.npcs[npc].name.lower() for npc in container ] if object in ["man", "woman"]: object = names[0] if object in names: for _id in container: npc = self.world_map.npcs[_id] if npc.name.lower() == object: return npc else: return False def transition(self, from_id, to_id): """Represents the transition between moving from room A to room B.""" from_room = self.world_map.get_room_at(from_id) to_room = self.world_map.get_room_at(to_id) self.moved = True self.world_map._id = to_id if not to_room.safe: if randrange(1, 100) < to_room.fight_chance: self.state = State.PRE_BATTLE mob_index = choice(to_room.mobs) mob_data = self.world_map.mobs[mob_index] mob = self.mob_factory.spawn(**mob_data) self.enemy = mob self.combatants = sorted([self.player, self.enemy], key=lambda entity: entity.speed)[::-1] return if to_room.tryattr("cutscene"): if to_room.cutscene == self.world_map.cutscene_id: for line in self.world_map.cutscenes[to_room.cutscene]["text"]: self.event_queue.add_event({"message": line}) self.world_map.cutscene_id += 1 self.state = State.CUTSCENE return def move_player(self, action): """Moves the player in the direction specified if an exit exists.""" exits = self.world_map.get_current_exits() index = self.world_map.directions.index(action["adverb"]) if exits[index] != -1: self.transition(self.world_map._id, exits[index]) else: msg = "There's no way out that way." self.event_queue.add_event({"message": msg}) def move_item(self, action): """Passes to the 'use' method to call the 'move' script on an item.""" self.use(action) def move(self, action): """Handles the two 'move' commands.""" if (action["adverb"] in self.world_map.directions and not action["noun_phrase"]): self.move_player(action) else: self.move_item(action) def take(self, action): """Moves the specified item into the player's inventory.""" items = [self.world_map.get_items_in_room()] object = action["noun_phrase"] prep = None indir_obj = None if action["prep_phrase"]: prep = action["prep_phrase"]["prep"] indir_obj = action["prep_phrase"]["noun_phrase"] if not object: self.event_queue.add_event({"message": "I don't understand that!"}) return if indir_obj: switched = False item = self.check_object(indir_obj, items[0], flag=0) if item: if not item.locked: items[0] = item.container switched = True if item.locked: self.event_queue.add_event({"message": "That's locked!"}) return if not switched: msg = "{}{}{} isn't here.".format(c.yellow, indir_obj, c.end) self.event_queue.add_event({"message": msg}) else: for _id in items[0]: if self.world_map.items[_id].tryattr("container"): if (self.world_map.items[_id].container and self.world_map.items[_id].searched): items.append(self.world_map.items[_id].container) taken = False attempted = False for container in items: item = self.check_object(object, container, flag=0) if item: if item.takeable: if indir_obj: msg = ("You take the {}{}{} from the {}{}{}.".format( c.yellow, item.name, c.end, c.yellow, indir_obj, c.end)) self.event_queue.add_event({"message": msg}) else: msg = ("You take the {}{}{}.".format( c.yellow, item.name, c.end)) self.event_queue.add_event({"message": msg}) self.player.container.append(item._id) container.remove(item._id) taken = True elif not item.takeable: attempted = True msg = "You're quite strong, but even you can't lift that..." self.event_queue.add_event({"message": msg}) if not taken and not attempted: msg = "{}{}{} isn't here.".format(c.yellow, object, c.end) self.event_queue.add_event({"message": msg}) if taken: self.event_queue.add_event({"taken": item}) def look_direction(self, action): """Reveals the description of the room in the specified direction.""" exits = self.world_map.get_current_exits() index = self.world_map.directions.index(action["adverb"]) if exits[index] == -1: msg = "You can't see anything of interest in that direction." self.event_queue.add_event({"message": msg}) else: look_room = self.world_map.rooms[exits[index]] direction = action["adverb"] msg = ("You look {}{}{} and see the {}{}{}.".format( c.blue, direction, c.end, c.blue, look_room.name.title(), c.end)) self.event_queue.add_event({"message": msg}) def look_room(self, action): """Reveals items in, and extra info about, the current room.""" ids = self.world_map.get_items_in_room() room = self.world_map.get_current_room() self.event_queue.add_event({"message": room.long_desc}) if not ids: msg = "There's nothing of interest here..." self.event_queue.add_event({"message": msg}) else: self.list_items(ids) def look(self, action): """Handles the two 'look' commands.""" if action["adverb"] is not None: self.look_direction(action) else: self.look_room(action) def search(self, action): """Reveals any items stored within another object.""" ids = self.world_map.get_items_in_room() object = action["noun_phrase"] item = self.check_object(object, ids, flag=0) if not item: msg = "You can't search something that's not here..." self.event_queue.add_event({"message": msg}) return if item.tryattr("in_sight"): if item.in_sight: if item.container: self.list_items(item.container) item.searched = True else: msg = "There's nothing here..." self.event_queue.add_event({"message": msg}) else: if item.tryattr("locked"): if item.locked: msg = "You can't see inside that." self.event_queue.add_event({"message": msg}) else: if item.container: self.list_items(item.container) item.searched = True else: msg = "There's nothing here..." self.event_queue.add_event({"message": msg}) def unlock(self, action): """Unlocks a locked object if the player has the right key.""" object = action["noun_phrase"] unlocked = False items = self.world_map.get_items_in_room() item = self.check_object(object, items, flag=0) if item.tryattr("locked"): for _item in self.player.container: if item.locked_id == _item: item.locked = False self.player.container.remove(_item) msg = "You unlocked the {}.".format(item.name) self.event_queue.add_event({"message": msg}) unlocked = True if not unlocked: msg = "You don't have the right key for that..." self.event_queue.add_event({"message": msg}) def collide(self, item_1, item_2, flag=0): """Represents the collision between two objects. flag = 0 means the target object is inanimate, flag = 1 means the player has thrown something at an NPC. """ hit = randrange(1, 100) < 70 if not hit: self.event_queue.add_event({ "message": "You throw the {}{}{} but it misses!".format( c.yellow, item_1.name, c.end) }) else: if flag == 0: msg = ("You throw the {}{}{} at the {}{}{}.".format( c.yellow, item_1.name, c.end, c.yellow, item_2.name, c.end)) self.event_queue.add_event({"message": msg}) if item_2.breakable: msg = ( "The {}{}{} strikes the {}{}{} and breaks it!".format( c.yellow, item_1.name, c.end, c.yellow, item_2.name, c.end)) self.event_queue.add_event({"message": msg}) if item_2.tryattr("container"): room = self.world_map.get_current_room() room.container += item_2.container msg = ("The {}{}{} spills its contents onto the floor." .format(c.yellow, item_2.name, c.end)) self.event_queue.add_event({"message": msg}) room.container.remove(item_2._id) elif flag == 1: msg = "Ow! Why'd you throw the {} at me???".format(item_1.name) self.event_queue.add_event({"message": msg}) self.state = State.DIALOG self.npc = item_2 self.player.container.remove(item_1._id) self.world_map.get_current_room().container.append(item_1._id) def throw(self, action): """Throw the specified item at another object.""" object = action["noun_phrase"] prep = None indir_obj = None items = self.world_map.get_items_in_room() npcs = self.world_map.get_npcs_in_room() if action["prep_phrase"]: prep = action["prep_phrase"]["prep"] indir_obj = action["prep_phrase"]["noun_phrase"] if not object: msg = "I don't understand that..." self.event_queue.add_event({"message": msg}) return if prep not in ["at"]: msg = "You have to throw something AT something else." self.event_queue.add_event({"message": msg}) return if not indir_obj: msg = "You have to throw an object at something." self.event_queue.add_event({"message": msg}) return item_2 = self.check_object(indir_obj, items) item_1 = self.check_object(object, self.player.container) if not item_1: msg = "You don't have one of those to throw." self.event_queue.add_event({"message": msg}) return if not item_2: item_2 = self.check_object(indir_obj, npcs, flag=1) if not item_2: msg = "You can't throw an object at something that isn't here!" self.event_queue.add_event({"message": msg}) return if item_2.tryattr("takeable"): self.collide(item_1, item_2) else: self.collide(item_1, item_2, flag=1) def drop(self, action): """Drop the specified item.""" items = self.world_map.get_items_in_room() object = action["noun_phrase"] prep = None indir_obj = None item = self.check_object(object, self.player.container) if not item: if object in self.dictionary.words: msg = "You don't have one of those..." self.event_queue.add_event({"message": msg}) return else: msg = "I don't understand that..." self.event_queue.add_event({"message": msg}) return put = False if action["prep_phrase"]: prep = action["prep_phrase"]["prep"] indir_obj = action["prep_phrase"]["noun_phrase"] if prep: if prep in ["in", "on"]: indir_obj = self.check_object(indir_obj, items) indir_obj.container.append(item._id) self.player.container.remove(item._id) msg = ("You put the {}{}{} {} the {}{}{}".format( c.yellow, item.name, c.end, prep, c.yellow, indir_obj.name, c.end)) self.event_queue.add_event({"message": msg}) else: msg = "That doesn't make sense..." self.event_queue.add_event({"message": msg}) else: room = self.world_map.get_current_room() room.container.append(item._id) self.player.container.remove(item._id) msg = ("You drop the {}{}{}.".format(c.yellow, item.name, c.end)) self.event_queue.add_event({"message": msg}) def examine(self, action): """Retreive the specified item's long description.""" ids = self.world_map.get_items_in_room() object = action["noun_phrase"] item = None # make sure there is an object to examine if not object: msg = "You need to examine SOMETHING." self.event_queue.add_event({"message": msg}) return # get item from room if ids: item = self.check_object(object, ids, flag=0) # get item from the player if not item: item = self.check_object(object, self.player.container, flag=0) # check player's equipped items if not item: all_slots = list(self.player.slots.values()) equipped_items = [i for i in all_slots if i is not None] if equipped_items is not None: for id in equipped_items: item = self.world_map.items[id] if item.name == object: break # get item from containers in the room if not item: room = self.world_map.get_current_room() for _id in ids: container = self.world_map.items[_id].container if container: item = self.check_object(object, container, flag=0) if item: break if item: self.event_queue.add_event({"message": item.long_desc}) else: msg = "You can't examine the {} if it's not here...".format(object) self.event_queue.add_event({"message": msg}) def trade(self, action): pass def rest(self, on_floor=True): """Simulates resting and heals the player based on the type of bed.""" for i in range(2): self.event_queue.add_event({"message": "ZZZzzzz"}) if on_floor: self.player.hp += int(self.player.max_hp / 10) self.player.hp = min(self.player.hp, self.player.max_hp) self.event_queue.add_event( {"message": "You wake up feeling sore."}) elif not on_floor: self.player.hp = self.player.max_hp self.event_queue.add_event({"message": "You feel well rested."}) self.state = State.SLEEP def sleep(self, action): """Allows the player to 'sleep', providing there is a suitable bed.""" prep_phrase = action.get("prep_phrase") prep = None object = None room = self.world_map.get_current_room() if prep_phrase: prep = action.get("prep_phrase")["prep"] object = action.get("prep_phrase")["noun_phrase"] if prep != "on": msg = "I don't understand that..." self.event_queue.add_event({"message": msg}) return item = self.check_object(object, room.container) if item: if item.tryattr("sleep"): # can sleep on it self.rest(on_floor=False) else: msg = "You can't sleep on that." self.event_queue.add_event({"message": msg}) return else: if object == "floor": self.rest(on_floor=True) else: msg = "You need to sleep ON something..." self.event_queue.add_event({"message": msg}) def handle_quest(self, npc): """Starts or ends a quest with an NPC.""" quest = self.world_map.quests[npc.quest_id] if quest.check_requirements(self.player): if npc.quest_id in self.player.quests: if quest.check_objective(self.player, self.event_queue): for line in quest.outro: self.event_queue.add_event({"message": line}) quest.on_completion(self.player, self.event_queue) self.state = State.REWARD else: for line in quest.intro: self.event_queue.add_event({"message": line}) self.event_queue.add_event({"message": "y/n?"}) def identify_npc(self, indir_obj, npcs): """Attempts to determine the NPC name when referred to indirectly.""" if indir_obj in ["man", "gentleman"]: if self.world_map.npcs[npcs[0]].sex == 0: return self.world_map.npcs[npcs[0]].name.lower() else: msg = "There isn't a man here..." self.event_queue.add_event({"message": msg}) return elif indir_obj in ["woman", "lady"]: if self.world_map.npcs[npcs[0]].sex == 1: return self.world_map.npcs[npcs[0]].name.lower() else: msg = "There isn't a woman here..." self.event_queue.add_event({"message": msg}) return def introduce_npc(self, npc): """Introduces an NPC for the first time.""" npc.known = True msg = ("My name's {}. Nice to meet you, friend.".format( npc.name.capitalize())) self.event_queue.add_event({"message": msg}) self.event_queue.add_event({"meeting": npc}) def speak(self, action): """Begins dialog with an NPC, leading potentially to quest giving.""" npcs = self.world_map.get_npcs_in_room() prep = None indir_obj = None if action["prep_phrase"]: prep = action["prep_phrase"]["prep"] indir_obj = action["prep_phrase"]["noun_phrase"] if prep not in ["to", "with"]: self.event_queue.add_event( {"message": "That doesn't make sense..."}) msg = ("Do you mean \"{} to\" or \"{} with\"?".format( action["verb"], action["verb"])) self.event_queue.add_event({"message": msg}) return indir_obj = self.identify_npc(indir_obj, npcs) npc = self.check_object(indir_obj, npcs, flag=1) if not npc: names = [self.world_map.npcs[npc].name.lower() for npc in npcs] if indir_obj in names: msg = ("I'm sorry, but {}{}{} isn't here...".format( c.green, indir_obj.capitalize(), c.end)) self.event_queue.add_event({"message": msg}) return else: if indir_obj[0] == "a": msg = ("If you try talking to an {}{}{}, \ people will think you're mad.".format( c.yellow, indir_obj, c.end)) self.event_queue.add_event({"message": msg}) return else: msg = ("If you try talking to a {}{}{}, \ people will think you're mad.".format( c.yellow, indir_obj, c.end)) self.event_queue.add_event({"message": msg}) return self.npc = npc self.state = State.DIALOG if not npc.known: self.introduce_npc(npc) else: self.event_queue.add_event({"message": choice(s.GREETINGS)}) if npc.quest_id >= 0: self.handle_quest(npc) def use(self, action): """Activates an item's attached script.""" object = action.get("noun_phrase") item = self.check_object(object, self.player.container) room = self.world_map.get_current_room() if not item: item = self.check_object(object, room.container) if not item: msg = "That doesn't make sense..." self.event_queue.add_event({"message": msg}) return if item.takeable: item = None if item: if item.tryattr("script"): method_to_call = getattr(src.systems.scripts, item.script) kwargs = { "world_map": self.world_map, "event_queue": self.event_queue, "player": self.player, "item": item } method_to_call(**kwargs) else: self.event_queue.add_event({"message": "You can't do that..."}) else: self.event_queue.add_event({"message": "You can't do that..."}) def equip(self, action): """Equips the specified item into the relevant slot. If there is already an item in the relevant slot, this will be unequipped and placed into the player's inventory and the specified item will be equipped. """ object = action.get("noun_phrase") item = self.check_object(object, self.player.container) if item: if item.tryattr("slot"): if not self.player.slots[item.slot]: self.player.slots[item.slot] = item._id elif self.player.slots[item.slot]: self.player.container.append(self.player.slot[item.slot]) self.player.slots[item.slot] = item._id msg = "You equip {}{}{}.".format(c.yellow, item.name, c.end) self.event_queue.add_event({"message": msg}) self.player.container.remove(item._id) else: msg = "You can't equip that..." self.event_queue.add_event({"message": msg}) else: msg = "That doesn't make sense..." self.event_queue.add_event({"message": msg}) def unequip(self, action): """Unequips the specified item from the relevant slot.""" object = action.get("noun_phrase") items = [i for i in list(self.player.slots.values()) if i] item = self.check_object(object, items) if item: if item.tryattr("slot"): self.player.slots[item.slot] = None self.player.container.append(item._id) msg = ("You unequip the {}{}{}".format(c.yellow, item.name, c.end)) self.event_queue.add_event({"message": msg}) else: msg = "You haven't got that equipped." self.event_queue.add_event({"message": msg}) def add_quest(self): """Adds a quest to the player's quest log.""" quest = self.world_map.quests[self.npc.quest_id] self.player.quests.append(quest.id) msg = ("You accepted {}{}{} quest.".format(c.green, quest.name.title(), c.end)) self.event_queue.add_event({"message": msg}) def choose(self, action): """Presents the player the choice to accept or deny a quest.""" choice = action.get("choice") if choice: if choice == "yes": self.add_quest() self.progress_quests() self.npc = None self.state = State.EXPLORE return elif choice == "no": self.state = State.EXPLORE return quest = self.world_map.quests[self.npc.quest_id] if not quest.check_requirements(self.player): self.npc = None self.state = State.EXPLORE def loot(self): """Moves from the loot state back to the explore state after a fight.""" self.moved = True self.state = State.EXPLORE def pre_fight(self): """Moves from the pre-fight state to the battle state.""" self.state = State.BATTLE def game_over(self): """The player has died.""" self.playing = False def save_data(self): """Saves the player, world and game state data.""" try: with open("savegame.txt", "wb") as save_game: data = (self.player, self.world_map, self.state) pickle.dump(data, save_game) self.event_queue.add_event({"message": "GAME SAVED."}) except Exception as e: raise e def load_data(self): """Loads the player, world and game state data.""" try: with open("savegame.txt", "rb") as save_game: data = pickle.load(save_game) self.player = data[0] self.world_map = data[1] self.state = data[2] except Exception as e: raise e def explore(self): """Reverts back to the explore state.""" self.state = State.EXPLORE def do_action(self, action): """Executes the player's command when in the explore state.""" command = list(action.keys())[0] if command == "verb": verb = action.get("verb") if verb: self.explore_actions[verb](action) elif command == "quit": self.playing = False elif command in ["stats", "stat"]: self.state = State.CHAR_SCREEN elif command in ["j", "log", "journal"]: self.state = State.JOURNAL elif command in ["inventory"]: self.state = State.INVENTORY elif command in ["save"]: self.save_data() def validate_move(self, move, known_moves): """Checks whether the specified move is in known_moves. 'move' is single character. """ if len(move) > 1: return False if ord(move) - 97 in known_moves: return True else: return False def fight(self, action): """Execute combatant moves for this round of combat.""" if action.get("command"): move = action.get("command") if self.validate_move(move, self.player.learnt_moves): enemy_move = self.enemy.choose_move() self.combatants = sorted([self.player, self.enemy], key=lambda entity: entity.speed)[::-1] # loop through combatants and conduct moves. for combatant in self.combatants: if isinstance(combatant, Player): move_index = self.player.moves[ord(move) - 97] event_params = (self.player, self.enemy, move_index) self.event_queue.add_event({"attack": event_params}) continue if isinstance(combatant, Mob): event_params = (self.enemy, self.player, enemy_move) self.event_queue.add_event({"attack": event_params}) continue def level_up(self): """Level up the player.""" lvl = self.player.level while self.player.xp >= self.player.next_xp: self.player.xp -= self.player.next_xp self.player.level += 1 self.player.next_xp = 110 * lvl + 50 * (lvl - 1) msg = ("Congratulations! You advanced to {}level {}{}".format( c.yellow, self.player.level, c.end)) self.event_queue.add_event({"message": msg}) def check_level_up(self): """Check whether the player has reached the next level.""" if self.player.xp >= self.player.next_xp: return True def xp_gain(self, event): """Gives xp to the player.""" xp = event.get("xp") self.player.xp += xp msg = "You gained {}{}{} xp.".format(c.yellow, xp, c.end) self.event_queue.add_event({"message": msg}) if self.check_level_up(): return self.level_up() def money_gain(self, event): """Gives money to the player.""" money = event.get("money") self.player.wallet += money msg = ("You received {}{}{} coins as a reward.".format( c.yellow, money, c.end)) self.event_queue.add_event({"message": msg}) def on_enemy_death(self): """Handles enemy death. Gives xp and money, and drops items.""" room = self.world_map.get_current_room() room.container += self.enemy.container self.event_queue.inject({"xp": self.enemy.xp}) money = randrange(self.enemy.money[0], self.enemy.money[1]) self.player.wallet += money if money == -1: msg = ( "I'm not sure the {}{}{} is going to have any money on it...". format(c.red, self.enemy.name, c.end)) self.event_queue.add_event({"message": msg}) elif money == 0: msg = ("You loot the {}{}{} and find nothing!".format( c.red, self.enemy.name, c.end)) self.event_queue.add_event({"message": msg}) elif money == 1: msg = ("You loot the {}{}{} and find {}{}{} coin.".format( c.red, self.enemy.name, c.end, c.yellow, money, c.end)) self.event_queue.add_event({"message": msg}) elif money > 1: msg = ("You loot the {}{}{} and find {}{}{} coins.".format( c.red, self.enemy.name, c.end, c.yellow, money, c.end)) self.event_queue.add_event({"message": msg}) def update_quests(self, message): """Moves a completed quest from current to completed list.""" id = message.get("quest") self.player.quests.remove(id) self.player.completed_quests.append(id) def progress_quests(self, message): """Tracks the progress of active quests.""" entity = message.get("dead") npc = message.get("meeting") item = message.get("taken") for id in self.player.quests: quest = self.world_map.quests[id] for objective in quest.objectives: if objective["quest_type"] == "KILL" and entity: if objective["target"] == entity._id: objective["progress"] += 1 if objective["quest_type"] == "FIND" and npc: if npc._id == objective["target"]: objective["progress"] += 1 if objective["quest_type"] == "COLLECT" and item: if item._id == objective["target"]: objective["progress"] += 1 def reveal_exit(self, message): """Reveals hidden exits.""" exit_update = message.get("exit") room = self.world_map.rooms[exit_update[0]] room.exits[exit_update[1]] = exit_update[2] msg = ("A new exit has been revealed in the {}{}{}.".format( c.blue, room.name, c.end)) self.event_queue.add_event({"message": msg}) def learn_skill(self, message): """Learns a new skill.""" skill_info = message.get("skill") player_skill = getattr(self.player, skill_info[0]) player_skill.append(skill_info[1]) system = self.get_crafting_system(skill_info[0]) skill_learnt = system.recipe_names[skill_info[1]] msg = ("You have learnt how to make {}{}{}.".format( c.yellow, skill_learnt, c.end)) self.event_queue.add_event({"message": msg}) def change_state(self, new_state): """Changes state as requested by an external object.""" self.state = new_state.get("state") def start_game(self, action): """Starts up the game and determines whether to start anew or load.""" if action.get("command") == "new_game": self.playing = True elif action.get("command") == "load_game": self.playing = True self.load_data() else: pass def smelt(self, action): """Begins the smelting crafting system.""" if action.get("command"): if ord(action.get("command")) - 97 in self.player.smelting: event_params = (action.get("command"), self.player) self.event_queue.inject({"smelt": event_params}) else: msg = "You haven't learnt that yet..." self.event_queue.add_event({"message": msg}) else: self.state = State.EXPLORE def smith(self, action): """Begins the blacksmithing crafting system.""" if action.get("command"): if ord(action.get("command")) - 97 in self.player.blacksmithing: event_params = (action.get("command"), self.player) self.event_queue.inject({"smith": event_params}) else: self.state = State.EXPLORE def brew(self, action): """Begins the brewing crafting system.""" if action.get("command"): if ord(action.get("command")) - 97 in self.player.brewing: event_params = (action.get("command"), self.player) self.event_queue.inject({"brew": event_params}) else: self.state = State.EXPLORE def handle_input(self): """Handles input across all states.""" action = self.input_handler.prompt(self.state) if isinstance(action, Exception): self.event_queue.add_event({"message": str(action)}) return if self.state == State.EXPLORE: self.do_action(action) elif self.state == State.BATTLE: self.fight(action) elif self.state == State.LOOT: self.loot() elif self.state == State.PRE_BATTLE: self.pre_fight() elif self.state == State.GAME_OVER: self.game_over() elif self.state == State.CHAR_SCREEN: self.explore() elif self.state == State.DIALOG: self.choose(action) elif self.state == State.REWARD: self.explore() elif self.state == State.JOURNAL: self.explore() elif self.state == State.INVENTORY: self.explore() elif self.state == State.SLEEP: self.explore() elif self.state == State.START: self.start_game(action) elif self.state == State.CUTSCENE: self.explore() elif self.state == State.FURNACE: self.smelt(action) elif self.state == State.ANVIL: self.smith(action) def update(self): """Updates the game engine and other systems each turn.""" self.combat_system.update(self.combatants) self.world_map.update() self.event_queue.processs_queue() def draw(self): """Passes all relevant information to the renderer to be 'drawn'.""" self.renderer.draw(self.state, player=self.player, world=self.world_map, messages=self.message_log.messages, moved=self.moved, enemy=self.enemy, combat_system=self.combat_system, npc=self.npc, crafting_systems=self.crafting_systems) self.message_log.clear() def receive(self, message): """Handles the actioning of received events.""" if message.get("xp"): self.xp_gain(message) elif message.get("dead"): if not isinstance(message.get("dead"), Player): self.on_enemy_death() self.progress_quests(message) self.enemy = None self.state = State.LOOT elif message.get("meeting"): self.progress_quests(message) elif message.get("taken"): self.progress_quests(message) elif message.get("game over"): self.state = State.GAME_OVER elif message.get("money"): self.money_gain(message) elif list(message.keys())[0] == "quest": self.update_quests(message) elif message.get("exit"): self.reveal_exit(message) elif message.get("skill"): self.learn_skill(message) elif message.get("state"): self.change_state(message) def begin(self): """Begins the game and initalises/loads all systems and data.""" self.state = State.START self.init_systems() self.init_game_data() self.create_player() self.renderer.clear() self.draw() while (not self.playing): self.handle_input() if self.playing: break self.draw() # check whether a save file has been loaded if self.state == State.START: self.transition(0, 0) # move into the game world. def run(self): """The main game loop.""" self.begin() self.update() self.draw() while (self.playing): self.moved = False self.handle_input() self.update() self.draw()