diff --git a/idk/asci.py b/idk/asci.py index 14cd5bc..6cd85fe 100644 --- a/idk/asci.py +++ b/idk/asci.py @@ -1,4 +1,4 @@ -# Asci (1.7.0) +# Asci (1.7.2) class Asci: def __init__(self, maps, events_mapping, keys_mapping, behaviors=None, screen_width=21, screen_height=6): @@ -11,14 +11,13 @@ class Asci: self._game_keys_mapping = {key: keys_mapping[key] for key in keys_mapping if not key in (1, 2, 3, 5)} # Custom entities behavior - self._behaviors = {"stand by": stand_by, "follow": follow, "walk": walk} + self._behaviors = {"permanent": permanent, "stand by": stand_by, "follow": follow, "walk": walk} if behaviors: for i in behaviors: self._behaviors[i] = behaviors[i] # Screen initialisation self.screen = Screen(screen_width, screen_height) self.current_map = None - self.visible_entities = [] def _looked_case(self, direction): if direction == 1: # Left @@ -38,18 +37,17 @@ class Asci: def _cell_test(self, direction): if direction == 1: if self.data[2] - 1 < 0: return -1 - else: cell = self.screen.get_cell(self.data[2: 4], self.data[2] - 1, self.data[3]) + else: cell = self.screen.get_cell(self.data[2] - 1, self.data[3]) if direction == 3: if self.data[2] + 1 >= self.map_width: return -1 - else: cell = self.screen.get_cell(self.data[2: 4], self.data[2] + 1, self.data[3]) + else: cell = self.screen.get_cell(self.data[2] + 1, self.data[3]) if direction == 5: if self.data[3] - 1 < 0: return -1 - else: cell = self.screen.get_cell(self.data[2: 4], self.data[2], self.data[3] - 1) + else: cell = self.screen.get_cell(self.data[2], self.data[3] - 1) if direction == 2: if self.data[3] + 1 >= self.map_height: return -1 - else: cell = self.screen.get_cell(self.data[2: 4], self.data[2], self.data[3] + 1) + else: cell = self.screen.get_cell(self.data[2], self.data[3] + 1) - print(f"'{cell}'") cell_patterns = self._legend for pattern_index in range(len(cell_patterns)): if cell in cell_patterns[pattern_index]: return pattern_index @@ -66,12 +64,12 @@ class Asci: if key == 1: self.data[2] -= 1 if key == 3: self.data[2] += 1 if key == 5: self.data[3] -= 1 - if key == 2: self.data[3] += 1 - + if key == 2: self.data[3] += 1 + # Change map elif interaction and cell_test == len(self._legend) - 2: new_map, self.data[2], self.data[3] = self._get_map(key) - self._change_map(new_map) + if self.data[1] != new_map: self._change_map(new_map) # Interaction elif interaction and cell_test >= 0: self._interaction(key, cell_test) @@ -93,10 +91,11 @@ class Asci: def _change_map(self, new_map): # Update entities if self.current_map: - for i in range(len(self.current_map.entities)): + for i in self.current_map.entities.copy(): entity = self.current_map.entities[i] if entity.behavior == "follow": - self.maps[new_map].entities.append(entity) + entity.pos_x = entity.pos_y = -1 + self.maps[new_map].entities[entity.entity_id] = entity self.maps[self.data[1]].entities.pop(i) # Update current map @@ -106,7 +105,6 @@ class Asci: # Update screen configuration self.screen.set_world(self.current_map.map_data) self.map_width, self.map_height = self.screen.get_map_size() - self._get_visible_entities() def _interaction(self, direction, cell_content): x, y = self._looked_case(direction) @@ -142,24 +140,10 @@ class Asci: self.data[0][quest] += answer_selected self._interaction(direction, cell_content) - # Entities gestion - def _get_visible_entities(self): - self.visible_entities = {} - for entity in self.current_map.entities: - if (0 <= entity.pos_x - self.data[2] + 10 < self.screen.screen_width) and (0 <= entity.pos_y - self.data[3] + 3 < self.screen.screen_height): - self.visible_entities[entity.entity_id] = entity - def _get_entity_id(self, x, y): - for entity_id in self.visible_entities: - entity = self.visible_entities[entity_id] + for entity in self.current_map.entities.values(): if entity.pos_x == x and entity.pos_y == y: - return entity_id - - def _run_entities_behaviors(self): - for entity in self.current_map.entities: - data_copy = get_data_copy(self.data) - self._behaviors[entity.behavior](entity, data_copy, self.stat, self.screen, self.walkable) - self._get_visible_entities() + return entity.entity_id # Mainloop def mainloop(self, end_game, stat=None, data=None, routine=None, player="@", door="^", walkable=" ", exit_key=9, multi_move="."): @@ -174,39 +158,46 @@ class Asci: else: self.data = [data[0], data[1], data[2], data[3], 0] # Configuration - self.walkable = walkable self._legend.append(door) self._legend.append(walkable) self._change_map(data[1]) + self.screen.load_data(self.data) key = 0 while key != exit_key and self.stat[0] > 0 and self.data[0]["main"] < end_game: # Update the map - self.screen.set_screen(self.data[2], self.data[3]) + self.screen.set_screen() # Compute the player's and entities' positions - self.screen.set_cell(self.data[2] - 10, self.data[3] - 3, self.data[2], self.data[3], player) - self._run_entities_behaviors() - for entity in self.visible_entities.values(): - self.screen.set_cell(self.data[2] - 10, self.data[3] - 3, entity.pos_x, entity.pos_y, entity.symbol) - - # Display map and get the key - key = convert(self.screen.display()) + data_copy = self.data[:] + for entity in self.current_map.entities.values(): + self._behaviors[entity.behavior](entity, data_copy, self.stat, self.screen, walkable) + if (0 <= entity.pos_x - self.data[2] + 10 < self.screen.screen_width) and (0 <= entity.pos_y - self.data[3] + 3 < self.screen.screen_height): + self.screen.set_cell(entity.pos_x, entity.pos_y, entity.symbol) + self.screen.set_cell(self.data[2], self.data[3], player) + + # Display map, get the key and update key buffer + key = convert(self.screen.display()) if not key: key = self.data[4] else: self.data[4] = key + # Multi-move and key gestion if type(key) == str and key[0] == multi_move: - for i in list(key[1:]): - self._keyboard(convert(i), False) - self.data[4] = convert(key[-1]) + key = key[1:] + for k, r in get_multi_move(key): + for _ in range(r): + self._keyboard(k, False) + self.screen.set_screen() + + self.data[4] = k else: self._keyboard(key) # Launching the game routine if routine: - data_copy = get_data_copy(self.data) + data_copy = self.data[:] routine(data_copy, self.stat) if self.stat[0] <= 0: self.stat[0] = 100 @@ -220,6 +211,10 @@ class Screen: self.screen_width = screen_width self.screen_height = screen_height self._on_screen = [[" " for _ in range(screen_width)] for _ in range(screen_height)] + self._asci_data = [] + + def load_data(self, data): + self._asci_data = data def get_map_size(self): return self.map_width, self.map_height @@ -229,8 +224,8 @@ class Screen: self.map_width = max([len(line) for line in self._world]) self.map_height = len(self._world) - def set_screen(self, x, y): - x -= 10 ; y -= 3 + def set_screen(self): + x = self._asci_data[2] - 10 ; y = self._asci_data[3] - 3 for x_map in range(x, x + self.screen_width): for y_map in range(y, y + self.screen_height): self._on_screen[y_map - y][x_map - x] = " " @@ -238,6 +233,7 @@ class Screen: try: self._on_screen[y_map - y][x_map - x] = self._world[y_map][x_map] except: pass + def display(self, return_input=True): for line in self._on_screen: print("".join(line)) @@ -256,13 +252,16 @@ class Screen: if index + 1 == nb_par: return input(">") else: input() - def set_cell(self, x_offset, y_offset, x, y, value): - self._on_screen[y - y_offset][x - x_offset] = value + def set_cell(self, x, y, value): + x = x - (self._asci_data[2] - 10) + y = y - (self._asci_data[3] - 3) + if 0 <= x < self.screen_width and 0 <= y < self.screen_height: + self._on_screen[y][x] = value - def get_cell(self, offsets, x, y): - x = x - (offsets[0] - 10) - y = y - (offsets[1] - 3) - if 0 <= x < self.screen_width and 0 <= y <= self.screen_height: + def get_cell(self, x, y): + x = x - (self._asci_data[2] - 10) + y = y - (self._asci_data[3] - 3) + if 0 <= x < self.screen_width and 0 <= y < self.screen_height: return self._on_screen[y][x] else: return " " @@ -277,8 +276,8 @@ class Event: class Map: def __init__(self, map_data, entities, *coords): self.map_data = map_data - if entities: self.entities = [Entity(*i) for i in entities] - else: self.entities = [] + if entities: self.entities = {i[0]: Entity(*i) for i in entities} + else: self.entities = {} self.coords = coords class Entity: @@ -291,7 +290,7 @@ class Entity: self.args = list(args) def change_behavior(self, new_behavior): - self.behavior = new_behavior + if self.behavior != "permanent": self.behavior = new_behavior # Functions used by Asci @@ -305,18 +304,24 @@ def convert(string, force_int=False): def text_formater(string, screen_width=21, screen_height=6): def line_formater(string, screen_width): - if len(string) <= screen_width: return string + string_result = "" + while len(string) > screen_width: + stop_index = screen_width + while stop_index > 0 and not string[stop_index].isspace(): stop_index -= 1 + if not stop_index: stop_index = screen_width - stop_index = screen_width - while stop_index > 0 and not string[stop_index].isspace(): stop_index -= 1 - if not stop_index: stop_index = screen_width - - return string[:stop_index].strip() + "\n" + line_formater(string[stop_index:].strip(), screen_width) + string_result += string[:stop_index].strip() + "\n" + string = string[stop_index:].strip() + + return string_result + string def paragraph_formater(lines, screen_height): - if len(lines) < screen_height: return "\n".join(lines) + paragraphs = "" + while len(lines) >= screen_height: + paragraphs += "\n".join(lines[:screen_height]) + "\n\n" + lines = lines[screen_height:] - return "\n".join(lines[:screen_height]) + "\n\n" + paragraph_formater(lines[screen_height:], screen_height) + return paragraphs + "\n".join(lines) lines = [] for line in string.split("\n"): @@ -340,8 +345,25 @@ def read_event(data, event, quest): return Event(*event) -def get_data_copy(data): - return [data[0], data[1], data[2], data[3], data[4]] +def get_multi_move(key): + if "," in key: + result = [] + for k in key.split(","): + if "*" in k: + k = k.split("*") + result.append((convert(k[0]), convert(k[1]))) + else: + result.append((convert(k), 1)) + + return result + + elif "*" in key: + key = key.split("*") + return [(convert(key[0]), convert(key[1]))] + + else: + return [(convert(k), 1) for k in key] + # Extra functions @@ -366,16 +388,24 @@ def print_text(text, min_value=0, max_value=0, default_value=0): def stand_by(entity, data, stat, screen, walkable): pass +def permanent(entity, data, stat, screen, walkable): + pass + + def follow(entity, data, stat, screen, walkable): - if data[4] == 1 and screen.get_cell(data[2: 4], data[2] + 1, data[3]) in walkable: entity.pos_x, entity.pos_y = data[2] + 1, data[3] - elif data[4] == 2 and screen.get_cell(data[2: 4], data[2], data[3] - 1) in walkable: entity.pos_x, entity.pos_y = data[2], data[3] - 1 - elif data[4] == 3 and screen.get_cell(data[2: 4], data[2] - 1, data[3]) in walkable: entity.pos_x, entity.pos_y = data[2] - 1, data[3] - elif data[4] == 5 and screen.get_cell(data[2: 4], data[2], data[3] + 1) in walkable: entity.pos_x, entity.pos_y = data[2], data[3] + 1 + if entity.pos_x == entity.pos_y == -1: + entity.pos_x, entity.pos_y = data[2], data[3] + + elif data[4] in (1, 2, 3, 5): + if entity.args: walkable += entity.args[0] + cases = ((data[2] + 1, data[3]), (data[2], data[3] - 1), (data[2] - 1, data[3]), 0, (data[2], data[3] + 1))[data[4] - 1] + if not (0 <= cases[0] < screen.map_width and 0 <= cases[1] < screen.map_height): entity.pos_x, entity.pos_y = data[2], data[3] + elif screen.get_cell(cases[0], cases[1]) in walkable: entity.pos_x, entity.pos_y = cases + def walk(entity, data, stat, screen, walkable): frame = (entity.args[0] + 1) % len(entity.args[1]) new_x, new_y = entity.args[1][frame] - print(new_x, new_y) - if screen.get_cell(data[2: 4], new_x, new_y) in walkable: + if screen.get_cell(new_x, new_y) in walkable: entity.pos_x, entity.pos_y = new_x, new_y entity.args[0] = frame diff --git a/idk/idk.py b/idk/idk.py index caee35d..9bca62b 100644 --- a/idk/idk.py +++ b/idk/idk.py @@ -79,10 +79,7 @@ def idk(save_code=None): name = stat[5] data = [{"main": 0}, 3, 44, 66] - print_text("Au alentour du Ve siecle, quelque part en Scandinavie. La bataille prenait place dans un champ saccage, et la nuit etait tombee depuis quelques heures lorsque l'assaut debuta.") - print_text("Hache levee, a la seule lueur de la pleine lune, {0} et sa division se jeterent sur le camp adverse, mais, pris a revers, le combat tourna vite a la defaveur des assaillants qui furent reduit sans autres difficultes.".format(name)) - print_text("Blesse a plusieurs endroit, {0} se trainait sur le sol, tentant de se refugier dans la nuit lorsqu'une forme humaine portant un espadon dans le dos et une lourde armure d'argent s'arreta devant lui. La Valkyrie degaina son espadon et acheva {0} avant de l'emporter dans ses bras.".format(name)) - print_text("Mais Odin avait d'autres plan pour {0} qu'une retraite parmi les meilleurs guerriers, et il le renvoya dans le vaste monde avec cet ultimatum : si il trouve la voie jusqu'a Asgard et le Valaskjalf, Odin conscent a le garder a son service, sinon il sera condamne a errer dans le monde sans jamais trouver le repos.".format(name)) + print_text("Au alentour du Ve siecle, quelque part en Scandinavie. La bataille prenait place dans un champ saccage, et la nuit etait tombee depuis quelques heures lorsque l'assaut debuta. Hache levee, a la seule lueur de la pleine lune, {0} et sa division se jeterent sur le camp adverse, mais, pris a revers, le combat tourna vite a la defaveur des assaillants qui furent reduit sans autres difficultes.\nBlesse a plusieurs endroit, {0} se trainait sur le sol, tentant de se refugier dans la nuit lorsqu'une forme humaine portant un espadon dans le dos et une lourde armure d'argent s'arreta silencieusement devant lui. La Valkyrie degaina son espadon et acheva {0} avant de l'emporter dans ses bras.\nMais Odin, septique des exploits au combat de {0}, lui refusa une retraite parmi les meilleurs guerriers, et il le renvoya dans le vaste monde avec cet ultimatum : s'il trouve la voie jusqu'a Asgard et le Valaskjalf, Odin conscent a revoir son jugement, sinon il sera condamne a errer dans le monde sans jamais trouver le repos.".format(name)) else: stat, data = decode_save(save_code) diff --git a/idk/midgard.py b/idk/midgard.py index dae1bdd..94d5c18 100644 --- a/idk/midgard.py +++ b/idk/midgard.py @@ -112,6 +112,7 @@ midgard = (r""" (3, '*', 66, 56, 'stand by'), (4, '*', 51, 60, 'stand by'), (5, '*', 68, 71, 'stand by'), + (6, '*', 94, 85, 'stand by') ],