def calc_cover_tiles(self, sprite): sx = pal_x(self.viewport) + pal_x(sprite.pos) sy = pal_y(self.viewport) + pal_y(sprite.pos) sh = bool(sx % 32) width, height = sprite.frame.size dx = dy = dh = 0 for y in range((sy - height - 15) // 16, sy // 16 + 1): for x in range((sx - width // 2) // 32, (sx + width // 2) // 32 + 1): for i in range(0 if x == (sx - width // 2) // 32 else 3, 5): if i == 0: dx, dy, dh = x, y, sh elif i == 1: dx = x - 1 elif i == 2: dx = x if sh else x - 1 dy = y + 1 if sh else y dh = 1 - sh elif i == 3: dx, dy, dh = x + 1, y, sh elif i == 4: dx = x + 1 if sh else x dy = y + 1 if sh else y dh = 1 - sh for l in range(2): tile = self.maps.get_tile_bitmap(dx, dy, dh, l) tile_hight = self.maps.get_tile_height(dx, dy, dh, l) if tile is not None and tile_hight > 0 and ( (dy + tile_hight) * 16 + dh * 8 >= sy): self.add_sprite_to_draw( tile, (dx * 32 + dh * 16 - 16 - pal_x(self.viewport), dy * 16 + dh * 8 + 7 + l + (tile_hight * 8) - pal_y(self.viewport)), tile_hight * 8 + l)
def scene_draw_sprites(self): self.sprite_to_draw.empty() for i in range(self.max_party_member_index + self.follower_num + 1): if i > MAX_PLAYERS_IN_PARTY: break sprite = self.player_sprites[i] if sprite is None: continue sprite_frame = sprite[self.party[i].frame] if sprite_frame is None: continue self.add_sprite_to_draw(sprite_frame, (self.party[i].x - sprite_frame.width // 2, self.party[i].y + self.layer + 10), self.layer + 6) self.calc_cover_tiles(self.sprite_to_draw.sprites()[-1]) for i in range( self.scenes[self.num_scene - 1].event_object_index, self.scenes[self.num_scene].event_object_index, ): evt_obj = self.event_objects[i] if evt_obj.state == ObjectState.Hidden: continue elif evt_obj.vanish_time > 0: continue elif evt_obj.state < 0: continue sprite = self.get_event_object_sprite((i & 0xFFFF) + 1) if sprite is None: continue frame = evt_obj.current_frame_num if evt_obj.sprite_frames_num == 3: if frame == 2: frame = 0 elif frame == 3: frame = 2 sprite_frame = sprite[evt_obj.direction * evt_obj.sprite_frames_num + frame] if sprite_frame is None: continue x = evt_obj.x - pal_x(self.viewport) x -= sprite_frame.width // 2 if x >= 320 or x < -sprite_frame.width: continue y = evt_obj.y - pal_y(self.viewport) y += evt_obj.layer * 8 + 9 vy = y - sprite_frame.height - evt_obj.layer * 8 + 2 if vy >= 200 or vy < -sprite_frame.height: continue self.add_sprite_to_draw(sprite_frame, (x, y), evt_obj.layer * 8 + 2) self.calc_cover_tiles(self.sprite_to_draw.sprites()[-1]) self.sprite_to_draw._spritelist.sort( key=lambda sprite: pal_y(sprite.pos)) for p in self.sprite_to_draw: x = pal_x(p.pos) y = pal_y(p.pos) - p.frame.height - p.layer p.frame.blit_to(self.screen, (x, y))
def start_dialog_with_offset(self, dialog_location, font_color, num_char_face, playing_rng, x_off, y_off): if self.in_battle and self.updated_in_battle: self.update_screen() self.updated_in_battle = True self.icon = 0 self.pos_icon = 0 self.current_dialog_line_num = 0 self.pos_dialog_title = 12, 8 self.user_skip = False if font_color != 0: self.current_font_color = font_color if playing_rng and num_char_face: self.screen_bak.blit(self.screen, (0, 0)) self.playing_rng = True if dialog_location == DialogPos.Upper: if num_char_face > 0: w, h = self.rgm[num_char_face].size pos = (max(48 - w // 2 + x_off, 0), max(55 - h // 2 + y_off, 0)) self.rgm[num_char_face].blit_to(self.screen, pos) rect = pg.Rect(pos, (w, h)) self.update_screen(rect) self.pos_dialog_title = 80, 8 self.pos_dialog_text = 96, 26 else: self.pos_dialog_title = 12, 8 self.pos_dialog_text = 44, 26 elif dialog_location == DialogPos.Center: self.pos_dialog_text = 80, 40 elif dialog_location == DialogPos.Lower: if num_char_face > 0: pos = ( 270 - self.rgm[num_char_face].width // 2 + x_off, 144 - self.rgm[num_char_face].height // 2 + y_off, ) self.rgm[num_char_face].blit_to(self.screen, pos) self.update_screen() self.pos_dialog_title = 4, 108 self.pos_dialog_text = 20, 126 else: self.pos_dialog_title = 12, 108 self.pos_dialog_text = 44, 126 elif dialog_location == DialogPos.CenterWindow: self.pos_dialog_text = 160, 40 self.pos_dialog_title = (pal_x(self.pos_dialog_title) + x_off, pal_y(self.pos_dialog_title) + y_off) self.pos_dialog_text = (pal_x(self.pos_dialog_text) + x_off, pal_y(self.pos_dialog_text) + y_off) self.dialog_position = dialog_location
def search(self): x = pal_x(self.viewport) + pal_x(self.partyoffset) y = pal_y(self.viewport) + pal_y(self.partyoffset) x_offset = 16 if self.party_direction in { Direction.North, Direction.East } else -16 y_offset = 8 if self.party_direction in { Direction.South, Direction.East } else -8 pos = [(x, y)] for i in range(4): pos.extend([ (x + x_offset, y + y_offset), (x, y + y_offset * 2), (x + x_offset, y), ]) x += x_offset y += y_offset for i in range(13): dh = bool(pal_x(pos[i]) % 32) dx = pal_x(pos[i]) // 32 dy = pal_y(pos[i]) // 16 for k in range(self.scenes[self.num_scene - 1].event_object_index, self.scenes[self.num_scene].event_object_index): p = self.event_objects[k] ex = p.x // 32 ey = p.y // 16 eh = bool(p.x % 32) if p.state <= 0: continue elif p.trigger_mode >= TriggerMode.TouchNear: continue elif p.trigger_mode * 6 - 4 < i: continue elif not (dx == ex and dy == ey and dh == eh): continue if p.sprite_frames_num * 4 > p.current_frame_num: p.current_frame_num = 0 p.direction = (self.party_direction + 2) % 4 for l in range(self.max_party_member_index + 1): self.party[l].frame = self.party_direction * 3 self.make_scene() self.update_screen() p.trigger_script = self.run_trigger_script( p.trigger_script, k + 1) self.delay(50) self.clear_key_state() return
def check_obstacle(self, pos, check_event_objects, self_object): x, y = pos if not pg.Rect(0, 0, 2047, 2047).collidepoint(x, y): return True x, xr = divmod(x, 32) y, yr = divmod(y, 16) h = 0 if xr + yr * 2 >= 16: if xr + yr * 2 >= 48: x += 1 y += 1 elif 32 - xr + yr * 2 < 16: x += 1 elif 32 - xr + yr * 2 < 48: h = 1 else: y += 1 if self.maps.tile_blocked(x, y, h): return True if check_event_objects: for i in range( self.scenes[self.num_scene - 1].event_object_index, self.scenes[self.num_scene].event_object_index, ): p = self.event_objects[i] if i == self_object - 1: continue if p.state >= ObjectState.Blocker: if abs(p.x - pal_x(pos)) + abs(p.y - pal_y(pos)) * 2 < 16: return True return False
def show_dialog_text(self, text): self.clear_key_state() self.icon = 0 if self.in_battle and not self.updated_in_battle: self.update_screen() self.updated_in_battle = False if self.current_dialog_line_num > 3: self.dialog_wait_for_key() self.current_dialog_line_num = 0 self.blit(self.screen_bak, (0, 0)) self.update_screen() x = pal_x(self.pos_dialog_text) y = pal_y(self.pos_dialog_text) + self.current_dialog_line_num * 18 if self.dialog_position == DialogPos.CenterWindow: length = wcwidth.wcswidth(text) pos = (pal_x(self.pos_dialog_text) - length * 4, pal_y(self.pos_dialog_text)) box = self.one_line_box_with_shadow(pos, (length + 1) // 2, False, self.dialog_shadow) rect = pg.Rect(pos, (320 - pal_x(pos) * 2 + 32, 64)) self.update_screen(rect) self.display_text(text, pal_x(pos) + 8 + ((length & 1) << 2), pal_y(pos) + 10, True) self.update_screen(rect) self.dialog_wait_for_key_with_maximum_seconds(1.4) self.delete_box(box) self.update_screen(rect) self.end_dialog() else: if (self.current_dialog_line_num == 0 and self.dialog_position != DialogPos.Center and text[-1] in {u'\uff1a', u'\u2236', u':'}): self.draw_text(text, self.pos_dialog_title, FONT_COLOR_CYAN_ALT, True, True) else: if not self.playing_rng and self.current_dialog_line_num == 0: self.screen_bak.blit(self.screen, (0, 0)) x = self.display_text(text, x, y, False) if self.user_skip: self.update_screen() self.pos_icon = x, y self.current_dialog_line_num += 1
def update_party(self): if self.input_state.curdir != Direction.Unknown: x_offset = -16 if self.input_state.curdir in { Direction.West, Direction.South } else 16 y_offset = -8 if self.input_state.curdir in { Direction.West, Direction.North } else 8 x_source = pal_x(self.viewport) + pal_x(self.partyoffset) y_source = pal_y(self.viewport) + pal_y(self.partyoffset) x_target = x_source + x_offset y_target = y_source + y_offset self.party_direction = self.input_state.curdir if not self.check_obstacle((x_target, y_target), True, 0): for i in range(4, 0, -1): self.trail[i] = self.trail[i - 1] self.trail[0].direction = self.input_state.curdir self.trail[0].x = x_source self.trail[0].y = y_source self.viewport = (pal_x(self.viewport) + x_offset, pal_y(self.viewport) + y_offset) self.update_party_gestures(True) return self.update_party_gestures(False)
def blit_mono_color(self, dst_surface, pos, color_shift, color=None): pxarray = pg.PixelArray(dst_surface) max_w, max_h = dst_surface.get_size() ui_width, ui_height = self.size offset = 4 i = 0 if color is not None: color &= 0xF0 while i < ui_width * ui_height: num = self.data[offset] offset += 1 if (num & 0x80) and num <= 0x80 + ui_width: i += num - 0x80 else: j = -1 while j < num - 1: j += 1 y = (i + j) // ui_width + pal_y(pos) x = (i + j) % ui_width + pal_x(pos) if x < 0: j += -x - 1 continue elif x >= max_w: j += x - max_w continue if y < 0: j += -y * ui_width - 1 continue elif y >= max_h: return b = self.data[offset + j] & 0x0F if b + color_shift > 0x0F: b = 0x0F elif b + color_shift < 0: b = 0 else: b += color_shift if color is None: pxarray[x, y] = b | (self.data[offset + j] & 0xF0) else: pxarray[x, y] = b | color offset += num i += num
def update(self, trigger): if trigger: if self.entering_scene: self.entering_scene = False i = self.num_scene - 1 self.scenes[i].script_on_enter = self.run_trigger_script( self.scenes[i].script_on_enter, 0xFFFF) if self.entering_scene or self.to_start: return self.clear_key_state() self.make_scene() for event_object_id in range(len(self.event_objects)): p = self.event_objects[event_object_id] if p.vanish_time != 0: p.vanish_time += 1 if p.vanish_time < 0 else -1 for event_object_id in range( self.scenes[self.num_scene - 1].event_object_index + 1, self.scenes[self.num_scene].event_object_index + 1, ): p = self.event_objects[event_object_id - 1] if p.vanish_time != 0: continue if p.state < 0: if (p.x < pal_x(self.viewport) or p.x > pal_x(self.viewport) + 320 or p.y < pal_y(self.viewport) or p.y > pal_y(self.viewport) + 320): p.state = abs(p.state) p.current_frame_num = 0 elif p.state > 0 and p.trigger_mode >= TriggerMode.TouchNear: if (abs( pal_x(self.viewport) + pal_x(self.partyoffset) - p.x) + abs( pal_y(self.viewport) + pal_y(self.partyoffset) - p.y) * 2 < (p.trigger_mode - TriggerMode.TouchNear) * 32 + 16): if p.sprite_frames_num: p.current_frame_num = 0 x_offset = pal_x(self.viewport) + \ pal_x(self.partyoffset) - p.x y_offset = pal_y(self.viewport) + \ pal_y(self.partyoffset) - p.y if x_offset > 0: p.direction = Direction.East if y_offset > 0 else Direction.North else: p.direction = Direction.South if y_offset > 0 else Direction.West self.update_party_gestures(False) self.make_scene() self.update_screen() p.trigger_script = self.run_trigger_script( p.trigger_script, event_object_id) self.clear_key_state() if self.entering_scene or self.to_start: return for event_object_id in range( self.scenes[self.num_scene - 1].event_object_index + 1, self.scenes[self.num_scene].event_object_index + 1, ): p = self.event_objects[event_object_id - 1] if p.state > 0 and p.vanish_time == 0: script_entry = p.auto_script if script_entry != 0: p.auto_script = self.run_auto_script( script_entry, event_object_id) if self.entering_scene or self.to_start: return if (trigger and p.state >= ObjectState.Blocker and p.sprite_num != 0 and abs(p.x - pal_x(self.viewport) - pal_x(self.partyoffset)) + abs(p.y - pal_y(self.viewport) - pal_y(self.partyoffset)) * 2 <= 12): direction = (p.direction + 1) % 4 for i in range(4): x = pal_x(self.viewport) + pal_x(self.partyoffset) y = pal_y(self.viewport) + pal_y(self.partyoffset) x += -16 if direction in {Direction.West, Direction.South } else 16 y += -8 if direction in {Direction.West, Direction.North } else 8 pos = x, y if not self.check_obstacle(pos, True, 0): self.viewport = (x - pal_x(self.partyoffset), y - pal_y(self.partyoffset)) break direction = (direction + 1) % 4 self.frame_num += 1
def update_party_gestures(self, walking): save = self.update_party_gestures.__dict__ step_frame_follower = step_frame_leader = 0 if walking: save['this_step_frame'] = (save['this_step_frame'] + 1) % 4 if save['this_step_frame'] & 1: step_frame_leader = (save['this_step_frame'] + 1) // 2 step_frame_follower = 3 - step_frame_leader else: step_frame_leader = step_frame_follower = 0 self.party[0].x = pal_x(self.partyoffset) self.party[0].y = pal_y(self.partyoffset) if self.player_roles.walk_frames[self.party[0].player_role] == 4: self.party[0].frame = self.party_direction * 4 + save[ 'this_step_frame'] else: self.party[ 0].frame = self.party_direction * 3 + step_frame_leader for i in range(1, self.max_party_member_index + 1): self.party[i].x = self.trail[1].x - pal_x(self.viewport) self.party[i].y = self.trail[1].y - pal_y(self.viewport) if i == 2: self.party[i].x += -16 if self.trail[1].direction in { Direction.East, Direction.West } else 16 self.party[i].y += 8 else: self.party[i].x += 16 if self.trail[1].direction in { Direction.West, Direction.South } else -16 self.party[i].y += 8 if self.trail[1].direction in { Direction.West, Direction.North } else -8 if self.check_obstacle( (self.party[i].x + pal_x(self.viewport), self.party[i].y + pal_y(self.viewport)), True, 0): self.party[i].x = self.trail[1].x - pal_x(self.viewport) self.party[i].y = self.trail[1].y - pal_y(self.viewport) if self.player_roles.walk_frames[ self.party[i].player_role] == 4: self.party[i].frame = self.trail[2].direction * \ 4 + save['this_step_frame'] else: self.party[i].frame = self.trail[2].direction * \ 3 + step_frame_leader if self.follower_num > 0: self.party[self.max_party_member_index + 1].x = self.trail[3].x - pal_x(self.viewport) self.party[self.max_party_member_index + 1].y = self.trail[3].y - pal_y(self.viewport) self.party[self.max_party_member_index + 1].frame = (self.trail[3].direction * 3 + step_frame_follower) else: i = self.player_roles.walk_frames[self.party[0].player_role] or 3 self.party[0].frame = self.party_direction * i for i in range(self.max_party_member_index): f = self.player_roles.walk_frames[self.party[ i + 1].player_role] or 3 self.party[i + 1].frame = self.trail[2].direction * f if self.follower_num > 0: self.party[self.max_party_member_index + 1].frame = self.trail[3].direction * 3 save['this_step_frame'] &= 2 save['this_step_frame'] ^= 2