module CXJ module FREE_MOVEMENT ENABLE_DIAGONAL = true # Enables diagonal movement. DEFAULT_COLLISION = [8, 12, 16, 20] DEFAULT_INTERACTION = { 2 => [4, 0, 24, 24], 4 => [16, 10, 24, 24], 6 => [-8, 10, 24, 24], 8 => [4, 20, 24, 24], } BOAT_COLLISION = [4, 4, 24, 24] SHIP_COLLISION = [2, 2, 28, 28] AIRSHIP_COLLISION = [4, 4, 24, 24] PIXELS_PER_STEP = 4 FOLLOWERS_DISTANCE = 16 FOLLOWERS_DISTANCE_MARGIN = 4 JUMP_SPEED = 0.5 # Debug variables SHOW_COLLISION_BOXES = false end end #============================================================================== # ** Game_Map #------------------------------------------------------------------------------ # This class handles maps. It includes scrolling and passage determination # functions. The instance of this class is referenced by $game_map. #============================================================================== class Game_Map #-------------------------------------------------------------------------- # * New: Determine Valid Coordinates #-------------------------------------------------------------------------- def valid_rect?(x, y, rect) x2 = x + (rect.x / 32.0) y2 = y + (rect.y / 32.0) x3 = x2 + (rect.width / 32.0) y3 = y2 + (rect.height / 32.0) round_x(x2) >= 0 && round_x(x3) < width && round_y(y2) >= 0 && round_y(y3) < height end #-------------------------------------------------------------------------- # * Override: Check Passage # bit: Inhibit passage check bit #-------------------------------------------------------------------------- def check_passage(x, y, bit) x = round_x(x) y = round_y(y) all_tiles(x, y).each do |tile_id| flag = tileset.flags[tile_id] next if flag & 0x10 != 0 # [?]: No effect on passage return true if flag & bit == 0 # [?] : Passable return false if flag & bit == bit # [×] : Impassable end return false # Impassable end #-------------------------------------------------------------------------- # * New: Determine Passability of Normal Character # d: direction (2,4,6,8) # Determines whether the tile at the specified coordinates is passable # in the specified direction. #-------------------------------------------------------------------------- def passable_rect?(x, y, d, rect) x2 = x + (rect.x / 32.0) y2 = y + (rect.y / 32.0) x3 = x2 + (rect.width / 32.0) y3 = y2 + (rect.height / 32.0) return false unless check_passage(x2, y2, (1 << (d / 2 - 1)) & 0x0f) return false unless check_passage(x2, y3, (1 << (d / 2 - 1)) & 0x0f) return false unless check_passage(x3, y2, (1 << (d / 2 - 1)) & 0x0f) return check_passage(x3, y3, (1 << (d / 2 - 1)) & 0x0f) end #-------------------------------------------------------------------------- # * Determine if Passable by Boat #-------------------------------------------------------------------------- def boat_passable_rect?(x, y, rect) x2 = x + (rect.x / 32.0) y2 = y + (rect.y / 32.0) x3 = x2 + (rect.width / 32.0) y3 = y2 + (rect.height / 32.0) return false unless check_passage(x2, y2, 0x0200) return false unless check_passage(x2, y3, 0x0200) return false unless check_passage(x3, y2, 0x0200) return check_passage(x3, y3, 0x0200) end #-------------------------------------------------------------------------- # * Determine if Passable by Ship #-------------------------------------------------------------------------- def ship_passable_rect?(x, y, rect) x2 = x + (rect.x / 32.0) y2 = y + (rect.y / 32.0) x3 = x2 + (rect.width / 32.0) y3 = y2 + (rect.height / 32.0) return false unless check_passage(x2, y2, 0x0400) return false unless check_passage(x2, y3, 0x0400) return false unless check_passage(x3, y2, 0x0400) return check_passage(x3, y3, 0x0400) end #-------------------------------------------------------------------------- # * Determine if Airship can Land #-------------------------------------------------------------------------- def airship_land_ok_rect?(x, y, rect) x2 = x + (rect.x / 32.0) y2 = y + (rect.y / 32.0) x3 = x2 + (rect.width / 32.0) y3 = y2 + (rect.height / 32.0) return false unless check_passage(x2, y2, 0x0800) && check_passage(x2, y2, 0x0f) return false unless check_passage(x2, y3, 0x0800) && check_passage(x2, y3, 0x0f) return false unless check_passage(x3, y2, 0x0800) && check_passage(x3, y2, 0x0f) return check_passage(x3, y3, 0x0800) && check_passage(x3, y3, 0x0f) end #-------------------------------------------------------------------------- # * Get Array of Events at Designated Coordinates #-------------------------------------------------------------------------- def events_xy_rect(x, y, rect) @events.values.select {|event| event.pos_rect?(x, y, rect) } end #-------------------------------------------------------------------------- # * Get Array of Events at Designated Coordinates (Except Pass-Through) #-------------------------------------------------------------------------- def events_xy_rect_nt(x, y, rect) @events.values.select {|event| event.pos_rect_nt?(x, y, rect) } end #-------------------------------------------------------------------------- # * Get Array of Tile-Handling Events at Designated Coordinates # (Except Pass-Through) #-------------------------------------------------------------------------- def tile_events_xy_rect(x, y, rect) @tile_events.select {|event| event.pos_rect_nt?(x, y, rect) } end end #============================================================================== # ** Game_CharacterBase #------------------------------------------------------------------------------ # This base class handles characters. It retains basic information, such as # coordinates and graphics, shared by all characters. #============================================================================== class Game_CharacterBase attr_accessor :move_poll #-------------------------------------------------------------------------- # * Alias: Object Initialization #-------------------------------------------------------------------------- alias game_characterbase_initialize_cxj_fm initialize def initialize game_characterbase_initialize_cxj_fm @old_x = @real_x @old_y = @real_y @move_poll = [] end #-------------------------------------------------------------------------- # * Alias: Frame Update # # Added processing of movement being polled. #-------------------------------------------------------------------------- alias game_characterbase_update_cxj_fm update def update @old_x = @real_x @old_y = @real_y interpret_move unless moving? game_characterbase_update_cxj_fm end #-------------------------------------------------------------------------- # * New: Movement Interpreting # Interprets the polled movement. #-------------------------------------------------------------------------- def interpret_move(step_left = distance_per_frame) if @move_poll.size > 0 current_move = @move_poll.shift() d = current_move[0] horz = (d - 1) % 3 - 1 vert = 1 - ((d - 1) / 3) turn_ok = current_move[1] set_direction(d) check_event_trigger_touch_front processed = false if (d % 2 == 0 && passable?(@x, @y, d)) || (d % 2 != 0 && diagonal_passable?(@x, @y, horz, vert)) process_move(horz, vert) processed = true elsif d % 2 != 0 && !diagonal_passable?(@x, @y, horz, vert) if passable?(@x, @y, horz + 5) set_direction(horz + 5) process_move(horz, 0) processed = true end if passable?(@x, @y, 5 - vert * 3) set_direction(5 - vert * 3) process_move(0, vert) processed = true end end if(processed) pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0 if(step_left > pixelstep && !@move_poll.empty?) interpret_move(step_left - pixelstep) elsif(jumping? && !@move_poll.empty?) interpret_move(0) end else @move_poll.clear end current_move end end def process_move(horz, vert) pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0 @x = @x + horz * pixelstep @y = @y + vert * pixelstep if(!jumping?) @x = $game_map.round_x(@x) @y = $game_map.round_y(@y) @real_x = @x - horz * pixelstep @real_y = @y - vert * pixelstep increase_steps end end #-------------------------------------------------------------------------- # * Determine Triggering of Frontal Touch Event #-------------------------------------------------------------------------- def check_event_trigger_touch_front d = @direction horz = (d - 1) % 3 - 1 vert = 1 - ((d - 1) / 3) pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0 x2 = $game_map.round_x(x + horz * pixelstep) y2 = $game_map.round_y(y + vert * pixelstep) check_event_trigger_touch(x2, y2) end #-------------------------------------------------------------------------- # * New: Collision Rectangle # Gets the collision rectangle. #-------------------------------------------------------------------------- def collision_rect collision = CXJ::FREE_MOVEMENT::DEFAULT_COLLISION return Rect.new(collision[0], collision[1], collision[2] - 1, collision[3] - 1) end #-------------------------------------------------------------------------- # * Override: Determine if Passable # d : Direction (2,4,6,8) #-------------------------------------------------------------------------- def passable?(x, y, d) horz = (d - 1) % 3 - 1 vert = 1 - ((d - 1) / 3) pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0 x2 = $game_map.round_x(x + horz * pixelstep) y2 = $game_map.round_y(y + vert * pixelstep) return false unless $game_map.valid_rect?(x2, y2, collision_rect) return true if @through || debug_through? return false unless map_passable_rect?(x, y, d, collision_rect) return false unless map_passable_rect?(x2, y2, reverse_dir(d), collision_rect) return false if collide_with_characters?(x2, y2) return true end #-------------------------------------------------------------------------- # * Determine Diagonal Passability # horz : Horizontal (4 or 6) # vert : Vertical (2 or 8) #-------------------------------------------------------------------------- def diagonal_passable?(x, y, horz, vert) pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0 x2 = $game_map.round_x(x + horz * pixelstep) y2 = $game_map.round_y(y + vert * pixelstep) d = (horz == 4 ? -1 : 1) + (vert == 2 ? -3 : 3) + 5 passable?(x, y, vert) && passable?(x, y, horz) && passable?(x, y, d) && passable?(x2, y2, vert) && passable?(x2, y2, horz) && passable?(x2, y2, d) end #-------------------------------------------------------------------------- # * Determine if Map is Passable # d : Direction (2,4,6,8) #-------------------------------------------------------------------------- def map_passable_rect?(x, y, d, rect) $game_map.passable_rect?(x, y, d, rect) end #-------------------------------------------------------------------------- # * Override: Change Direction to Designated Direction # d : Direction (2,4,6,8) # # Fix for diagonal movement. #-------------------------------------------------------------------------- def set_direction(d) if !@direction_fix && d != 0 @direction = d if d % 2 != 0 @direction+= 1 @direction-= 2 if d > 5 @direction = 10 - direction if d > 2 && d < 8 end end @stop_count = 0 end #-------------------------------------------------------------------------- # * Override: Move Straight # d: Direction (2,4,6,8) # turn_ok : Allows change of direction on the spot # # Polls the movement instead of processing them immediately. #-------------------------------------------------------------------------- def move_straight(d, turn_ok = true) pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0 @move_poll+= [[d, turn_ok]] * (distance_per_frame / pixelstep).ceil end #-------------------------------------------------------------------------- # * Override: Move Diagonally # horz: Horizontal (4 or 6) # vert: Vertical (2 or 8) # # Polls the movement instead of processing them immediately. #-------------------------------------------------------------------------- def move_diagonal(horz, vert) pixelstep = CXJ::FREE_MOVEMENT::PIXELS_PER_STEP / 32.0 @move_poll+= [[vert + (horz > 5 ? 1 : -1), true]] * (distance_per_frame / pixelstep).ceil end #-------------------------------------------------------------------------- # * New: Determine Coordinate Match #-------------------------------------------------------------------------- def pos_rect?(x, y, rect) main_left = @x + collision_rect.x / 32.0 main_top = @y + collision_rect.y / 32.0 main_right = main_left + collision_rect.width / 32.0 main_bottom = main_top + collision_rect.height / 32.0 other_left = x + rect.x / 32.0 other_top = y + rect.y / 32.0 other_right = other_left + rect.width / 32.0 other_bottom = other_top + rect.height / 32.0 coltest = true coltest = false if main_right < other_left coltest = false if main_left > other_right coltest = false if main_bottom < other_top coltest = false if main_top > other_bottom if coltest == false && ($game_map.loop_horizontal? || $game_map.loop_vertical?) && x <= $game_map.width && y <= $game_map.height return true if $game_map.loop_horizontal? && pos_rect?(x + $game_map.width, y, rect) return true if $game_map.loop_vertical? && pos_rect?(x, y + $game_map.height, rect) end return coltest end #-------------------------------------------------------------------------- # * New: Determine if Coordinates Match and Pass-Through Is Off (nt = No Through) #-------------------------------------------------------------------------- def pos_rect_nt?(x, y, rect) pos_rect?(x, y, rect) && !@through end #-------------------------------------------------------------------------- # * Detect Collision with Event #-------------------------------------------------------------------------- def collide_with_events?(x, y) $game_map.events_xy_rect_nt(x, y, collision_rect).any? do |event| (event.normal_priority? || self.is_a?(Game_Event)) && event != self end end #-------------------------------------------------------------------------- # * Override: Detect Collision with Vehicle #-------------------------------------------------------------------------- def collide_with_vehicles?(x, y) $game_map.boat.pos_rect_nt?(x, y, collision_rect) || $game_map.ship.pos_rect_nt?(x, y, collision_rect) end #-------------------------------------------------------------------------- # * Override: Update While Jumping #-------------------------------------------------------------------------- def update_jump @jump_count -= 1 diff_x = @real_x @real_x = (@real_x * @jump_count + @x) / (@jump_count + 1.0) @real_y = (@real_y * @jump_count + @y) / (@jump_count + 1.0) update_bush_depth if @jump_count == 0 @real_x = @x = $game_map.round_x(@x) @real_y = @y = $game_map.round_y(@y) end end #-------------------------------------------------------------------------- # * Override: Calculate Jump Height #-------------------------------------------------------------------------- def jump_height (@jump_peak * @jump_peak - (@jump_count * CXJ::FREE_MOVEMENT::JUMP_SPEED - @jump_peak).abs ** 2) / 2 end end #============================================================================== # ** Game_Character #------------------------------------------------------------------------------ # A character class with mainly movement route and other such processing # added. It is used as a super class of Game_Player, Game_Follower, # GameVehicle, and Game_Event. #============================================================================== class Game_Character < Game_CharacterBase #-------------------------------------------------------------------------- # * Move at Random #-------------------------------------------------------------------------- def move_random @move_poll+= [[2 + rand(4) * 2, false]] * ((24.0 + (rand(160) / 10) ) / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil end #-------------------------------------------------------------------------- # * Move Toward Character #-------------------------------------------------------------------------- def move_toward_character(character) sx = distance_x_from(character.x) sy = distance_y_from(character.y) if sx.abs > sy.abs if passable?(@x, @y, (sx > 0 ? 4 : 6)) @move_poll+= [[sx > 0 ? 4 : 6, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil else @move_poll+= [[sy > 0 ? 8 : 2, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil end elsif sy != 0 if passable?(@x, @y, (sy > 0 ? 8 : 2)) @move_poll+= [[sy > 0 ? 8 : 2, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil else @move_poll+= [[sx > 0 ? 4 : 6, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil end end end #-------------------------------------------------------------------------- # * Move Away from Character #-------------------------------------------------------------------------- def move_away_from_character(character) sx = distance_x_from(character.x) sy = distance_y_from(character.y) if sx.abs > sy.abs if passable?(@x, @y, (sx > 0 ? 6 : 4)) @move_poll+= [[sx > 0 ? 6 : 4, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil else @move_poll+= [[sy > 0 ? 2 : 8, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil end elsif sy != 0 if passable?(@x, @y, (sy > 0 ? 2 : 8)) @move_poll+= [[sy > 0 ? 2 : 8, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil else @move_poll+= [[sx > 0 ? 6 : 4, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil end end end #-------------------------------------------------------------------------- # * Override: 1 Step Forward #-------------------------------------------------------------------------- def move_forward @move_poll+= [[@direction, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil end #-------------------------------------------------------------------------- # * Override: 1 Step Backward #-------------------------------------------------------------------------- def move_backward last_direction_fix = @direction_fix @direction_fix = true @move_poll+= [[reverse_dir(@direction), false]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil @direction_fix = last_direction_fix end #-------------------------------------------------------------------------- # * Override: Jump # x_plus : x-coordinate plus value # y_plus : y-coordinate plus value #-------------------------------------------------------------------------- def jump(x_plus, y_plus) if x_plus.abs > y_plus.abs set_direction(x_plus < 0 ? 4 : 6) if x_plus != 0 else set_direction(y_plus < 0 ? 8 : 2) if y_plus != 0 end distance = Math.sqrt(x_plus * x_plus + y_plus * y_plus).round pollcount = distance * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil @move_poll+= [[(x_plus < 0 ? -1 : x_plus > 0 ? 1 : 0) + (y_plus < 0 ? 8 : y_plus > 0 ? 2 : 5), false]] * pollcount @jump_peak = 10 + distance - @move_speed @jump_count = @jump_peak / CXJ::FREE_MOVEMENT::JUMP_SPEED * 2 @stop_count = 0 straighten end #-------------------------------------------------------------------------- # * Alias: Process Move Command #-------------------------------------------------------------------------- alias game_character_process_move_command_cxj_fm process_move_command def process_move_command(command) case command.code when ROUTE_MOVE_DOWN; @move_poll+= [[2, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil when ROUTE_MOVE_LEFT; @move_poll+= [[4, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil when ROUTE_MOVE_RIGHT; @move_poll+= [[6, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil when ROUTE_MOVE_UP; @move_poll+= [[8, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil when ROUTE_MOVE_LOWER_L; @move_poll+= [[1, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil when ROUTE_MOVE_LOWER_R; @move_poll+= [[3, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil when ROUTE_MOVE_UPPER_L; @move_poll+= [[7, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil when ROUTE_MOVE_UPPER_R; @move_poll+= [[9, true]] * (32.0 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP).ceil else; game_character_process_move_command_cxj_fm(command) end end end #============================================================================== # ** Game_Player #------------------------------------------------------------------------------ # This class handles the player. It includes event starting determinants and # map scrolling functions. The instance of this class is referenced by # $game_player. #============================================================================== class Game_Player < Game_Character #-------------------------------------------------------------------------- # * Object Initialization #-------------------------------------------------------------------------- alias game_player_initialize_cxj_fm initialize def initialize @last_poll = [] game_player_initialize_cxj_fm @custom_collision = [] @interaction = CXJ::FREE_MOVEMENT::DEFAULT_INTERACTION if @note =~ //i @custom_collision = Rect.new($1, $2, $3 - 1, $4) end if @note =~ //i && $1 > 0 && $1 < 10 && $1 % 2 == 0 @interaction[$1] = [$2, $3, $4, $5] end end #-------------------------------------------------------------------------- # * New: Movement Interpreting # Interprets the polled movement. #-------------------------------------------------------------------------- def interpret_move(step_left = distance_per_frame) current_move = super(step_left) @last_poll.push(current_move) if !current_move.nil? end #-------------------------------------------------------------------------- # * New: Collision Rectangle # Gets the collision rectangle. #-------------------------------------------------------------------------- def collision_rect return @custom_collision if @custom_collision.size > 0 return super end #-------------------------------------------------------------------------- # * New: Interaction Rectangle # Gets the interaction rectangle. #-------------------------------------------------------------------------- def interaction_rect collision = @interaction[@direction] return Rect.new(collision[0], collision[1], collision[2] - 1, collision[3] - 1) end #-------------------------------------------------------------------------- # * Override: Processing of Movement via Input from Directional Buttons # # Added diagonal movement. #-------------------------------------------------------------------------- def move_by_input return if !movable? || $game_map.interpreter.running? if CXJ::FREE_MOVEMENT::ENABLE_DIAGONAL && Input.dir8 > 0 && Input.dir8 % 2 != 0 d = Input.dir8 horz = (d == 1 || d == 7 ? 4 : 6) vert = (d == 1 || d == 3 ? 2 : 8) move_diagonal(horz, vert) elsif Input.dir4 > 0 move_straight(Input.dir4) end end #-------------------------------------------------------------------------- # * Detect Collision (Including Followers) #-------------------------------------------------------------------------- def collide_rect?(x, y, rect) !@through && (pos_rect?(x, y, rect) || followers.collide_rect?(x, y, rect)) end #-------------------------------------------------------------------------- # * Trigger Map Event # triggers : Trigger array # normal : Is priority set to [Same as Characters] ? #-------------------------------------------------------------------------- def start_map_event(x, y, triggers, normal, rect = collision_rect) return if $game_map.interpreter.running? $game_map.events_xy_rect(x, y, rect).each do |event| if event.trigger_in?(triggers) && event.normal_priority? == normal event.start unless event.is_touching?(self) event.add_touch(self) end end end #-------------------------------------------------------------------------- # * Determine if Front Event is Triggered #-------------------------------------------------------------------------- def check_event_trigger_there(triggers) x2 = $game_map.round_x_with_direction(@x, @direction) y2 = $game_map.round_y_with_direction(@y, @direction) start_map_event(x2, y2, triggers, true, interaction_rect) return if $game_map.any_event_starting? return unless $game_map.counter?(x2, y2) x3 = $game_map.round_x_with_direction(x2, @direction) y3 = $game_map.round_y_with_direction(y2, @direction) start_map_event(x3, y3, triggers, true, interaction_rect) end #-------------------------------------------------------------------------- # * Board Vehicle # Assumes that the player is not currently in a vehicle. #-------------------------------------------------------------------------- def get_on_vehicle front_x = $game_map.round_x_with_direction(@x, @direction) front_y = $game_map.round_y_with_direction(@y, @direction) @vehicle_type = :boat if $game_map.boat.pos_rect?(front_x, front_y, interaction_rect) @vehicle_type = :ship if $game_map.ship.pos_rect?(front_x, front_y, interaction_rect) @vehicle_type = :airship if $game_map.airship.pos_rect?(@x, @y, collision_rect) if vehicle @vehicle_getting_on = true horz = (@x > vehicle.x ? -1 : @x < vehicle.x ? 1 : 0) vert = (@y > vehicle.y ? -3 : @y < vehicle.y ? 3 : 0) d = 5 + horz - vert set_direction(d) @x = vehicle.x @y = vehicle.y @followers.gather end @vehicle_getting_on end #-------------------------------------------------------------------------- # * Get Off Vehicle # Assumes that the player is currently riding in a vehicle. #-------------------------------------------------------------------------- def get_off_vehicle if vehicle.land_ok?(@x, @y, @direction) set_direction(2) if in_airship? @followers.synchronize(@x, @y, @direction) vehicle.get_off unless in_airship? @x = $game_map.round_x_with_direction(@x, @direction) @y = $game_map.round_y_with_direction(@y, @direction) @transparent = false end @vehicle_getting_off = true @move_speed = 4 @through = false make_encounter_count @followers.gather end @vehicle_getting_off end #-------------------------------------------------------------------------- # * Determine if Map is Passable # d: Direction (2,4,6,8) #-------------------------------------------------------------------------- def map_passable_rect?(x, y, d, rect) case @vehicle_type when :boat $game_map.boat_passable_rect?(x, y, vehicle.collision_rect) when :ship $game_map.ship_passable_rect?(x, y, vehicle.collision_rect) when :airship true else super end end #-------------------------------------------------------------------------- # * Override: Move Diagonally #-------------------------------------------------------------------------- def move_diagonal(horz, vert) @followers.move if diagonal_passable?(@x, @y, horz, vert) || passable?(@x, @y, horz + 5) || passable?(@x, @y, 5 - vert * 3) super end #-------------------------------------------------------------------------- # * Alias: Create Encounter Count #-------------------------------------------------------------------------- alias game_player_make_encounter_count_cxj_fm make_encounter_count def make_encounter_count game_player_make_encounter_count_cxj_fm @encounter_count*= (32 / CXJ::FREE_MOVEMENT::PIXELS_PER_STEP) + (32 / 2 < CXJ::FREE_MOVEMENT::PIXELS_PER_STEP ? 1 : 0) end #-------------------------------------------------------------------------- # * Detect Collision with Vehicle #-------------------------------------------------------------------------- def collide_with_vehicles?(x, y) (@vehicle_type != :boat && $game_map.boat.pos_rect_nt?(x, y, collision_rect)) || (@vehicle_type != :ship && $game_map.ship.pos_rect_nt?(x, y, collision_rect)) end #-------------------------------------------------------------------------- # * Processing When Not Moving # last_moving : Was it moving previously? #-------------------------------------------------------------------------- alias game_player_update_nonmoving_cxj_fm update_nonmoving def update_nonmoving(last_moving) game_player_update_nonmoving_cxj_fm(last_moving || @old_x != @real_x || @old_y != @real_y) update_encounter if !last_moving && !@last_poll.empty? @last_poll.clear end end #============================================================================== # ** Game_Followers #------------------------------------------------------------------------------ # This is a wrapper for a follower array. This class is used internally for # the Game_Player class. #============================================================================== class Game_Followers #-------------------------------------------------------------------------- # * Detect Collision #-------------------------------------------------------------------------- def collide_rect?(x, y, rect) visible_folloers.any? {|follower| follower.pos_rect?(x, y, rect) } end #-------------------------------------------------------------------------- # * Movement #-------------------------------------------------------------------------- def move reverse_each {|follower| follower.board if gathering?; follower.chase_preceding_character } end end #============================================================================== # ** Game_Vehicle #------------------------------------------------------------------------------ # This class handles vehicles. It's used within the Game_Map class. If there # are no vehicles on the current map, the coordinates are set to (-1,-1). #============================================================================== class Game_Vehicle < Game_Character #-------------------------------------------------------------------------- # * New: Collision Rectangle # Gets the collision rectangle. #-------------------------------------------------------------------------- def collision_rect collision = CXJ::FREE_MOVEMENT::DEFAULT_COLLISION case @type when :boat collision = CXJ::FREE_MOVEMENT::BOAT_COLLISION when :ship collision = CXJ::FREE_MOVEMENT::SHIP_COLLISION when :airship collision = CXJ::FREE_MOVEMENT::AIRSHIP_COLLISION end return Rect.new(collision[0], collision[1], collision[2] - 1, collision[3] - 1) end #-------------------------------------------------------------------------- # * Determine if Docking/Landing Is Possible # d: Direction (2,4,6,8) #-------------------------------------------------------------------------- def land_ok?(x, y, d) if @type == :airship return false unless $game_map.airship_land_ok_rect?(x, y, collision_rect) return false unless $game_map.events_xy_rect(x, y, collision_rect).empty? else x2 = $game_map.round_x_with_direction(x, d) y2 = $game_map.round_y_with_direction(y, d) return false unless $game_map.valid_rect?(x2, y2, collision_rect) return false unless $game_map.passable_rect?(x2, y2, reverse_dir(d), collision_rect) return false if collide_with_characters?(x2, y2) end return true end end #============================================================================== # ** Game_Event #------------------------------------------------------------------------------ # This class handles events. Functions include event page switching via # condition determinants and running parallel process events. Used within the # Game_Map class. #============================================================================== class Game_Event < Game_Character #-------------------------------------------------------------------------- # * Initialize Public Member Variables #-------------------------------------------------------------------------- alias game_event_init_public_members_cxj_fm init_public_members def init_public_members game_event_init_public_members_cxj_fm @collisionbox = Rect.new(0, 0, 31, 31) @touch_chars = [] end #-------------------------------------------------------------------------- # * Frame Update #-------------------------------------------------------------------------- alias game_event_update_cxj_fm update def update temp_chars = [] @touch_chars.each do |character| temp_chars.push(character) if character.pos_rect?(@x, @y, collision_rect) end @touch_chars = temp_chars game_event_update_cxj_fm end #-------------------------------------------------------------------------- # * Initialize Public Member Variables #-------------------------------------------------------------------------- def set_collision_rect(x, y, width, height) @collisionbox = Rect.new(x, y, width - 1, height - 1) end #-------------------------------------------------------------------------- # * New: Collision Rectangle # Gets the collision rectangle. #-------------------------------------------------------------------------- def collision_rect return @collisionbox end #-------------------------------------------------------------------------- # * Detect Collision with Player (Including Followers) #-------------------------------------------------------------------------- def collide_with_player_characters?(x, y) normal_priority? && $game_player.collide_rect?(x, y, collision_rect) end #-------------------------------------------------------------------------- # * Determine if Touch Event is Triggered #-------------------------------------------------------------------------- def check_event_trigger_touch(x, y) return if $game_map.interpreter.running? if @trigger == 2 && $game_player.pos_rect?(x, y, $game_player.collision_rect) start if !jumping? && normal_priority? end end def add_touch(character) @touch_chars.push(character) unless is_touching?(character) end def is_touching?(character) @touch_chars.include?(character) end end #============================================================================== # ** Game_Follower #------------------------------------------------------------------------------ # This class handles followers. A follower is an allied character, other than # the front character, displayed in the party. It is referenced within the # Game_Followers class. #============================================================================== class Game_Follower < Game_Character #-------------------------------------------------------------------------- # * Alias: Object Initialization #-------------------------------------------------------------------------- alias game_follower_initialize_cxj_fm initialize def initialize(member_index, preceding_character) game_follower_initialize_cxj_fm(member_index, preceding_character) @force_chase = false @board = false end #-------------------------------------------------------------------------- # * Pursue Preceding Character #-------------------------------------------------------------------------- def chase_preceding_character unless moving? && !@force_chase dist = CXJ::FREE_MOVEMENT::FOLLOWERS_DISTANCE / 32.0 mrgn = CXJ::FREE_MOVEMENT::FOLLOWERS_DISTANCE_MARGIN / 32.0 sx = distance_x_from(@preceding_character.x) sy = distance_y_from(@preceding_character.y) sd = Math.hypot(sx, sy) if @board @x = @preceding_character.x @y = @preceding_character.y @board = false elsif(sd > dist && sx.abs > mrgn && sy.abs > mrgn) @move_poll+=[[(sx > 0 ? -1 : 1) + (sy > 0 ? 8 : 2), true]] elsif sx.abs > dist && sx.abs > sy.abs @move_poll+=[[sx > 0 ? 4 : 6, true]] elsif sy.abs > dist && sx.abs < sy.abs @move_poll+=[[sy > 0 ? 8 : 2, true]] end end end def distance_preceding_character sx = distance_x_from(@preceding_character.x) sy = distance_y_from(@preceding_character.y) return Math.hypot(sx, sy) end def process_move(horz, vert) super(horz, vert) dist = CXJ::FREE_MOVEMENT::FOLLOWERS_DISTANCE / 32.0 if distance_preceding_character > dist && @move_poll.size == 0 @force_chase = true chase_preceding_character @force_chase = false end end def board @board = true end end #============================================================================== # ** Game_Interpreter #------------------------------------------------------------------------------ # An interpreter for executing event commands. This class is used within the # Game_Map, Game_Troop, and Game_Event classes. #============================================================================== class Game_Interpreter #-------------------------------------------------------------------------- # * Initialize Public Member Variables #-------------------------------------------------------------------------- def set_collision_rect(x, y, width, height) $game_map.events[@event_id].set_collision_rect(x, y, width, height) end end if(CXJ::FREE_MOVEMENT::SHOW_COLLISION_BOXES) class Sprite_CollisionBox < Sprite def initialize(viewport, parent_sprite = nil) super(viewport) @color = Color.new(0, 255, 0, 128) @icolor = Color.new(255, 0, 0, 128) @parent_sprite = parent_sprite self.bitmap = Bitmap.new(96, 96) update end def update self.x = @parent_sprite.x self.y = @parent_sprite.y draw_box end def draw_box self.ox = 48 self.oy = 64 self.bitmap.clear return if @parent_sprite.character.through && @parent_sprite.character.transparent col_rect = @parent_sprite.character.collision_rect self.bitmap.fill_rect(col_rect.x + 32, col_rect.y + 32, col_rect.width, col_rect.height, @color) if(@parent_sprite.character == $game_player) int_rec = $game_player.interaction_rect d = $game_player.direction int_rect = Rect.new(int_rec.x + 32 + 32 * (d == 4 ? -1 : d == 6 ? 1 : 0), int_rec.y + 32 + 32 * (d == 8 ? -1 : d == 2 ? 1 : 0), int_rec.width, int_rec.height) self.bitmap.fill_rect(int_rect, @icolor) end end end class Spriteset_Map #-------------------------------------------------------------------------- # * Alias: Create Character Sprite #-------------------------------------------------------------------------- alias spriteset_map_create_characters_cxj_fm create_characters def create_characters spriteset_map_create_characters_cxj_fm @collision_sprites = [] @character_sprites.each do |char| @collision_sprites.push(Sprite_CollisionBox.new(@viewport, char)) end end #-------------------------------------------------------------------------- # * Alias: Update Character Sprite #-------------------------------------------------------------------------- alias spriteset_map_update_characters_cxj_fm update_characters def update_characters spriteset_map_update_characters_cxj_fm @collision_sprites.each {|sprite| sprite.update } end end end