class TestsViewer(): def __init__(self, stage, tests): self.layer = Layer() self.stage = stage self.tests = tests data = DictClass(load(file('data/common/tests_viewer.yaml'))) layers = [test.get_layer() for test in tests] self.paginator = Paginator(self.stage, layers, data.get("pagination", None)) for item in self.stage.create_items_from_yaml(data.other, self): self.layer.add(item) def handle_confirm(self, item, args): failed = 0 for test in self.tests: if not test.check(): failed += 1 if failed: fail_dialog = Fail(self.stage, failed) fail_dialog.start() else: self.stop() win = Win(self.stage) win.start() def handle_close(self, item, args): self.stop() def exit(self): self.paginator.exit() self.paginator = None self.stage = None self.layer.exit() self.layer = None for test in self.tests: test.exit() self.tests = None def stop(self): for layer in self.paginator.get_layers(): self.stage.remove_layer(layer) self.stage.close_dialog(self.layer) def start(self): self.stage.show_dialog(self.layer, None) for layer in self.paginator.get_layers(): self.stage.add_layer(layer)
class Intro: def __init__(self, stage, data, next_cb): self.next_cb = next_cb self.layer = Layer() self.stage = stage self.layer.add(stage.create_image(data.intro)[0]) self.layer.add(stage.create_button(data.next, self)[0]) def stop(self): self.stage.close_dialog(self.layer) def start(self): self.stage.show_dialog(self.layer, None) def handle_next(self, *args, **kwargs): self.stop() self.next_cb() self.next_cb = None self.layer.exit() self.stage = None
class Paginator(): def __init__(self, stage, items, optional_data=None): self.layer = Layer() self.items_layer = Layer() self.items = items self.stage = stage from yaml import load data = load(file('data/common/pagination.yaml')) if optional_data is not None: data.update(optional_data) self.current = 1 if len(self.items): self.current_layer = self.items[0] else: self.current_layer = Layer() self.min = 1 self.max = len(self.items) self.count = len(self.items) for item in items: item.set_visible(False) self.previous = stage.create_button(data["previous"], self)[0] self.next = stage.create_button(data["next"], self)[0] self.last = None if "last" in data: self.last = stage.create_button(data["last"], self)[0] if "page_count" in data and data["page_count"]: self.page_count_text = stage.create_text(data["page_count"])[0] self.page_count_base_text = data["page_count"]["text"] else: self.page_count_text = None self.update_page_count() self.update_items() self.update_buttons() self.layer.add(self.previous) self.layer.add(self.next) if self.page_count_text: self.layer.add(self.page_count_text) if self.last: self.layer.add(self.last) def exit(self): self.layer.exit() self.items_layer.exit() for item in self.items: item.exit() self.items = None self.stage = None self.previous.exit() self.previous = None self.next.exit() self.next = None if self.last: self.last.exit() self.last = None if self.page_count_text: self.page_count_text.exit() self.page_count_text = None def update_page_count(self): if self.page_count_text: self.page_count_text.set_text(self.page_count_base_text % { "page": self.current, "total": self.max }) def update_items(self): self.current_layer.set_visible(False) if len(self.items) > 0: self.current_layer = self.items[self.current - 1] self.current_layer.set_visible(True) def update_buttons(self): if self.current > self.min: self.previous.set_visible(True) else: self.previous.set_visible(False) if self.current < self.max: self.next.set_visible(True) else: self.next.set_visible(False) if self.last: if self.current == self.max: self.last.set_visible(False) else: self.last.set_visible(True) def handle_previous(self, item, args): if self.current > self.min: self.current -= 1 self.update_buttons() self.update_page_count() self.update_items() def handle_next(self, item, args): if self.current < self.max: self.current += 1 self.update_buttons() self.update_page_count() self.update_items() def get_current(self): return self.current def go_to(self, current): if current < self.max: self.current = current else: self.current = current self.update_buttons() self.update_page_count() self.update_items() def go_to_last(self): self.current = self.max self.update_buttons() self.update_page_count() self.update_items() def handle_go_to_last(self, item, args): self.go_to_last() def get_layers(self): return [self.layer] + self.items
class BackPack: ITEMS_PER_PAGE = 5 def __init__(self, stage, elements): self.stage = stage self.layer = Layer() self.elements_layer = Layer() from yaml import load data = load(file('data/common/backpack.yaml')) self.elements = elements self.close_button = stage.create_button(data["close"], self)[0] self.next_button = stage.create_button(data["next"], self)[0] self.previous_button = stage.create_button(data["previous"], self)[0] self.description_text = stage.create_text(data["description"])[0] self.element_count_text = stage.create_text_count( data["element_count"], len(elements))[0] self.previous_button.set_visible(False) self.current_page = 0 self.create_elements(data, elements) if len(elements) <= self.ITEMS_PER_PAGE: self.next_button.set_visible(False) self.set_elements() self.other = stage.create_items_from_yaml(data["other"]) for other in self.other: self.layer.add(other) self.layer.add(self.close_button) self.layer.add(self.next_button) self.layer.add(self.previous_button) self.layer.add(self.description_text) self.layer.add(self.element_count_text) self.current_items = [] def create_elements(self, data, elements): self.elements = [] start_top = data["elements_pos"]["top"] inter = data["elements_pos"]["interspace"] element_data = DictClass(load(file('data/common/books.yaml'))) current = 0 for page in xrange(0, len(elements) / self.ITEMS_PER_PAGE + 1): start_left = 0 for element in elements[page * self.ITEMS_PER_PAGE:(page + 1) * self.ITEMS_PER_PAGE]: element_data[element.type]['action'] = 'click' new = self.stage.create_button(element_data[element.type], manager=self)[0] new.set_top(start_top) new.set_left(start_left) new.add_event_handler(ItemEvent.MOUSE_ENTER, self.handle_element_enter) new.add_event_handler(ItemEvent.MOUSE_LEAVE, self.handle_element_leave) new.info = element start_left += new.get_width() + inter self.elements.append(new) current += 1 start_left -= inter new_left = (data["elements_pos"]["width"] - start_left) / 2 + data["elements_pos"]["left"] for element in self.elements[page * self.ITEMS_PER_PAGE:(page + 1) * self.ITEMS_PER_PAGE]: element.set_left(element.get_left() + new_left) def set_elements(self): self.elements_layer.empty() fromm = self.current_page * self.ITEMS_PER_PAGE for element in self.elements[fromm:fromm + self.ITEMS_PER_PAGE]: self.elements_layer.add(element) def start(self): self.stage.show_dialog(self.layer, None) self.stage.add_layer(self.elements_layer) def handle_close(self, item, args): self.stage.remove_layer(self.elements_layer) self.stage.close_dialog(self.layer) self.layer.exit() self.layer = None self.close_button.exit() self.next_button.exit() self.previous_button.exit() self.description_text.exit() self.element_count_text.exit() self.previous_button.exit() for element in self.elements: element.exit() self.elements = None self.elements_layer.exit() self.elements_layer = None def handle_next(self, item, args): self.current_page += 1 if len( self.elements ) - self.current_page * self.ITEMS_PER_PAGE <= self.ITEMS_PER_PAGE: self.next_button.set_visible(False) self.previous_button.set_visible(True) self.set_elements() def handle_previous(self, item, args): self.current_page -= 1 if not self.current_page: self.previous_button.set_visible(False) if len(self.elements) > self.ITEMS_PER_PAGE: self.next_button.set_visible(True) self.set_elements() def handle_element_enter(self, item, args): self.description_text.set_text(item.info.title) def handle_element_leave(self, item, args): self.description_text.set_text("") def handle_click(self, item, args): paginate = Content(self.stage, item.info.title, item.info.text) paginate.start()
class Map(GameStage): def __init__(self, game): GameStage.__init__(self, game) INTERVAL = 30 def initialize(self): GameStage.initialize(self) self.tests = None self.h_key = None self.v_key = None self.map_character = None self.named_layers = None self.collisions = None self.map_manager = None if self.game.datastore.datamodel.current_map_index: self.current_map_index = self.game.datastore.datamodel.current_map_index self.game.datastore.datamodel.current_map_index = None else: self.current_map_index = 4 # Load the sound self.street_ambience_sound = assets.load_sound( 'DGI_street_ambience.ogg') self.street_ambience_sound.play(-1) def set_up_background(self): return def load_quadrant(self): # remove the character before it gets destroyed if self.named_layers and hasattr(self.named_layers, "character"): self.named_layers.character.remove(self.map_character.item) if self.layers: self.remove_layer(self.gui) for layer in self.layers: layer.exit() self.empty_layers() data = DictClass( load(file('data/map/quadrant_%d.yaml' % self.current_map_index))) self.named_layers, layers = self.create_layers(data["layers"]) self.named_layers.character.add(self.map_character.item) if self.game.datastore.datamodel.map_character_left: self.map_character.item.set_left( self.game.datastore.datamodel.map_character_left) self.game.datastore.datamodel.map_character_left = None if self.game.datastore.datamodel.map_character_top: self.map_character.item.set_top( self.game.datastore.datamodel.map_character_top) self.game.datastore.datamodel.map_character_top = None class Collision(): def __init__(self, collision_map, trans_x=0, trans_y=0): self.collision_map = collision_map self.trans_x = trans_x self.trans_y = trans_y def get_at(self, pos): return self.collision_map.get_at( (pos[0] + self.trans_x, pos[1] + self.trans_y)) def bottom(self): return self.collision_map.get_height() - self.trans_y def left(self): return -self.trans_x def right(self): return self.collision_map.get_width() - self.trans_x def top(self): return -self.trans_y def exit(self): self.collision_map = None if "collision" in data: if self.collisions: for col in self.collisions: col.exit() self.collisions = [] base_data = data.collision.base self.collisions.append( Collision(assets.load_mask(base_data.src), base_data.get("trans_x", 0), base_data.get("trans_y", 0))) if self.game.datastore.datamodel.unlocked_level >= 3: self.collisions.append( Collision(assets.load_mask(data.collision.trash.src))) if self.game.datastore.datamodel.unlocked_level >= 4: self.collisions.append( Collision(assets.load_mask(data.collision.lights.src))) if self.game.datastore.datamodel.unlocked_level >= 5 and "vegetation" in data.collision: self.collisions.append( Collision(assets.load_mask(data.collision.vegetation.src))) else: self.collisions = [] if "entrance" in data: self.entrance = assets.load_mask(data.entrance.src) to = data.entrance.to index = to.rfind(".") if (index > 1): self.entrance_class = getattr( __import__(to[:index], globals(), locals(), to[index + 1:]), to[index + 1:]) else: self.entrance_class = globals()[to] else: self.entrance = None if self.map_manager: self.map_manager.exit() self.map_manager = MapManager(self, self.map_character.item, self.named_layers.character) for layer in layers: self.add_layer(layer) self.add_layer(self.gui) # Start processing events after everything is loaded self.start_timer(0, self.INTERVAL, self.manage_key) def prepare(self): data = DictClass(load(file('data/map/common.yaml'))) self.gui = Layer() for item in self.create_items_from_yaml(data.gui): self.gui.add(item) self.create_selected_map_character(data.character) self.load_quadrant() self.tests_counter = self.create_text(data.counters.tests)[0] self.backpack_counter = self.create_text(data.counters.backpack)[0] self.games_counter = self.create_text(data.counters.games)[0] self.gui.add(self.tests_counter) self.gui.add(self.backpack_counter) self.gui.add(self.games_counter) self.backpack_counter.set_text( str( len(self.game.datastore.datamodel.backpack[ self.game.datastore.datamodel.level - 1]))) self.tests_counter.set_text( str( len(self.game.datastore.levels[ self.game.datastore.datamodel.level].tests))) self.games_counter.set_text( str(self.game.datastore.datamodel.unlocked_level - 1)) def create_selected_map_character(self, data): if not self.map_character: character = self.game.datastore.datamodel.character params = data[character] params['base'] = data.base[character].small params["jumping"] = None self.map_character = Character(**params) return [self.map_character.item] def create_buildings(self, data): return self.create_items_from_yaml(data["items"]) def create_background(self, data): if self.game.datastore.datamodel.unlocked_level <= 1: return self.create_image(data["dirty"]) else: return self.create_image(data["clean"]) def create_text_tab(self, data): args, kwargs = self.text_arguments(data) return [ItemTextTab(*args, **kwargs)] def create_trash(self, data): if self.game.datastore.datamodel.unlocked_level <= 2: return self.create_items_from_yaml(data["before"]) else: return self.create_items_from_yaml(data["after"]) def create_lights(self, data): if self.game.datastore.datamodel.unlocked_level <= 3: return [] else: return self.create_items_from_yaml(data["items"]) def create_level_counter(self, data): data["src"] = data["src"][self.game.datastore.datamodel.level] return self.create_image(data) def create_vegetation(self, data): if self.game.datastore.datamodel.unlocked_level <= 4: return [] else: return self.create_items_from_yaml(data["items"]) def handle_backpack(self, items, args): backpack = BackPack(self, [ self.game.datastore.contents[content_id] for content_id in self.game.datastore.datamodel.backpack[ self.game.datastore.datamodel.level - 1] ]) backpack.start() def handle_exercises(self, item, args): if not self.tests: tests = [] for test in self.game.datastore.levels[ self.game.datastore.datamodel.level].tests: test = self.game.datastore.tests[test] if test.type == "multiple": tests.append( MultipleChoice(self, test.title, test.description, test.options, test.answer)) elif test.type == "true_false": tests.append( TrueFalse(self, test.title, test.description, test.options, test.answer)) elif test.type == "joining": tests.append( Joining(self, test.title, test.description, test.left_options, test.right_options, map(tuple, test.answer), test.get("visualization", None))) self.tests = TestsViewer(self, tests) self.tests.start() def handle_games(self, item, args): games = GamesViewer(self) games.start() def handle_activity(self, item, args): activity = Activity(self) activity.start() def handle_previous(self, item, args): if self.actual_screen == 0: from presentation import Presentation presentation = Presentation(self.game, 2) self.game.set_stage(presentation) else: self.show_previous_screen() def exit(self, other_self): GameStage.exit(self, other_self) self.gui.exit() self.gui = None if self.tests: self.tests.exit() self.tests = None self.map_character.exit() self.map_character = None if self.collisions: for col in self.collisions: col.exit() self.collisions = None self.named_layers = None self.entrance = None if self.map_manager: self.map_manager.exit() self.map_manager = None def handle_back(self, *args, **kwargs): dialog = ExitDialog(self, self.on_exit_no) self.stop_timer(0) dialog.start() def on_exit_no(self): self.start_timer(0, self.INTERVAL, self.manage_key) def handle_next(self, item, args): self.show_next_screen() def handle_event(self, e): if e.type == KEYDOWN: if (e.key == K_LEFT or e.key == K_RIGHT): self.h_key = e.key elif (e.key == K_UP or e.key == K_DOWN): self.v_key = e.key if e.type == KEYUP: if self.h_key == e.key: self.h_key = None elif self.v_key == e.key: self.v_key = None def manage_key(self, key, data): if self.map_character: if not self.h_key and self.v_key == K_UP: x = 0 y = -1 elif not self.h_key and self.v_key == K_DOWN: x = 0 y = 1 elif self.h_key == K_LEFT and not self.v_key: x = -1 y = 0 elif self.h_key == K_RIGHT and not self.v_key: x = 1 y = 0 elif self.h_key == K_LEFT and self.v_key == K_UP: x = -cos(1) y = -sin(1) elif self.h_key == K_LEFT and self.v_key == K_DOWN: x = -cos(1) y = sin(1) elif self.h_key == K_RIGHT and self.v_key == K_UP: x = cos(1) y = -sin(1) elif self.h_key == K_RIGHT and self.v_key == K_DOWN: x = cos(1) y = sin(1) else: x = 0 y = 0 r = 4 x *= r y *= r self.move_character(x, y) def move_character(self, delta_left, delta_top): current_map_index = self.current_map_index window_width, window_height = self.game.get_window_size() character = self.map_character.item height = character.get_height() width = character.get_width() left = character.get_left() top = character.get_top() new_left = left + delta_left new_top = top + delta_top if (self.check_entrance(new_left + width / 2, new_top + height)): self.game.datastore.datamodel.current_map_index = self.current_map_index self.game.datastore.datamodel.map_character_left = self.map_character.item.get_left( ) self.game.datastore.datamodel.map_character_top = self.map_character.item.get_top( ) self.game.set_stage(self.entrance_class(self.game)) return if delta_left or delta_top: new_left, new_top = self.check_collition(left + width / 2, top + height, new_left + width / 2, new_top + height) new_left -= width / 2 new_top -= height self.map_manager.update() if self.current_map_index == 1: if new_left < 0: new_left = 0 elif new_left > window_width - width / 2: new_left = -width / 2 self.current_map_index = 2 if new_top < 0: new_top = 0 elif new_top > window_height - height / 2: new_top = -height / 2 self.current_map_index = 4 elif self.current_map_index == 2: if new_left < -width / 2: new_left = window_width - width / 2 self.current_map_index = 1 elif new_left > window_width - width: new_left = window_width - width if new_top < 0: new_top = 0 elif new_top > window_height - height / 2: new_top = -height / 2 self.current_map_index = 3 elif self.current_map_index == 3: if new_left < -width / 2: new_left = window_width - width / 2 self.current_map_index = 4 elif new_left > window_width - width: new_left = window_width - width if new_top < -height / 2: new_top = window_height - height / 2 self.current_map_index = 2 elif new_top > window_height - height: new_top = window_height - height elif self.current_map_index == 4: if new_left < 0: new_left = 0 elif new_left > window_width - width / 2: new_left = -width / 2 self.current_map_index = 3 if new_top < -height / 2: new_top = window_height - height / 2 self.current_map_index = 1 elif new_top > window_height - height: new_top = window_height - height if (left != new_left or top != new_top): character.set_left(new_left) character.set_top(new_top) self.map_character.update(self.INTERVAL, delta_left, delta_top) if self.current_map_index != current_map_index: self.load_quadrant() def check_entrance(self, left, top): if self.game.datastore.levels[ self.game.datastore.datamodel. level].place_quadrant != self.current_map_index - 1: return False entrance = self.entrance if not entrance: return False c_width = entrance.get_width() c_height = entrance.get_height() return left >= 0 and top >= 0 and left < c_width and top < c_height \ and entrance.get_at((int(left), int(top))) == ENTRANCE_COLOR def handle_level_change(self): if self.game.datastore.datamodel.level < 4: from presentation import Presentation presentation = Presentation(self.game, 3) self.game.datastore.changed_data = True self.game.set_stage(presentation) else: self.game.set_stage(Map(self.game)) def check_collition_color(self, left, top): exists = False for collision in self.collisions: if left < collision.right() and left >= collision.left() and top < collision.bottom()\ and top >= collision.top(): if collision.get_at((left, top)) == COLLISION_COLOR: return True exists = True return not exists def check_collition(self, left, top, new_left, new_top): if self.check_collition_color(int(new_left), int(new_top)): Dx = float(new_left - left) Dy = float(new_top - top) left = float(left) top = float(top) dx = Dx / 4.0 dy = Dy / 4.0 n_dx = dy n_dy = -dx Dx = fabs(Dx) Dy = fabs(Dy) fdy = fabs(dy) fdx = fabs(dx) total = sqrt(Dx * Dx + Dy * Dy) while total > 0: left = left + dx top = top + dy found = True if self.check_collition_color(int(left), int(top)): slide_total = total slide_left = left + n_dx slide_top = top + n_dy found = False while slide_total > 0: if self.check_collition_color(int(slide_left), int(slide_top)): slide_left = slide_left + n_dx slide_top = slide_top + n_dy slide_total -= sqrt(n_dx**2 + n_dy**2) else: total = slide_total - sqrt(fdx**2 + fdy**2) left = slide_left top = slide_top found = True break if not found: slide_total = total slide_left = left - n_dx slide_top = top - n_dy while slide_total > 0: if self.check_collition_color( int(slide_left), int(slide_top)): slide_left = slide_left - n_dx slide_top = slide_top - n_dy slide_total -= sqrt(n_dx**2 + n_dy**2) else: total = slide_total - sqrt(fdx**2 + fdy**2) left = slide_left top = slide_top found = True break if not found: return left - dx, top - dy else: Dx -= fdx Dy -= fdy total -= sqrt(fdx**2 + fdy**2) return left, top return new_left, new_top