diff --git a/Data/Scripts/001_Technical/002_RubyUtilities.rb b/Data/Scripts/001_Technical/002_RubyUtilities.rb index 339b4cab5..1b796b039 100644 --- a/Data/Scripts/001_Technical/002_RubyUtilities.rb +++ b/Data/Scripts/001_Technical/002_RubyUtilities.rb @@ -389,14 +389,3 @@ end def nil_or_empty?(string) return string.nil? || !string.is_a?(String) || string.size == 0 end - -# Linear interpolation between two values, given the duration of the change and -# either: -# - the time passed since the start of the change (delta), or -# - the start time of the change (delta) and the current time (now) -def lerp(start_val, end_val, duration, delta, now = nil) - delta = now - delta if now - return start_val if delta <= 0 - return end_val if delta >= duration - return start_val + (end_val - start_val) * delta / duration -end diff --git a/Data/Scripts/005_Sprites/012_Interpolators.rb b/Data/Scripts/001_Technical/007_Interpolators.rb similarity index 85% rename from Data/Scripts/005_Sprites/012_Interpolators.rb rename to Data/Scripts/001_Technical/007_Interpolators.rb index 4399b1be5..7688871b0 100644 --- a/Data/Scripts/005_Sprites/012_Interpolators.rb +++ b/Data/Scripts/001_Technical/007_Interpolators.rb @@ -1,88 +1,52 @@ +#=============================================================================== +# Linear interpolation between two values, given the duration of the change and +# either: +# - the time passed since the start of the change (delta), or +# - the start time of the change (delta) and the current time (now) +#=============================================================================== +def lerp(start_val, end_val, duration, delta, now = nil) + delta = now - delta if now + return start_val if delta <= 0 + return end_val if delta >= duration + return start_val + (end_val - start_val) * delta / duration +end + #=============================================================================== # #=============================================================================== -class Interpolator - ZOOM_X = 1 - ZOOM_Y = 2 - X = 3 - Y = 4 - OPACITY = 5 - COLOR = 6 - WAIT = 7 +class PointInterpolator + attr_reader :x + attr_reader :y - def initialize - @tweening = false - @tweensteps = [] - @sprite = nil - @frames = 0 - @step = 0 + def initialize(oldx, oldy, newx, newy, frames) + restart(oldx, oldy, newx, newy, frames) end - def tweening? - return @tweening + def restart(oldx, oldy, newx, newy, frames) + @oldx = oldx + @oldy = oldy + @newx = newx + @newy = newy + @frames = frames + @curframe = 0 + @x = oldx + @y = oldy end - def tween(sprite, items, frames) - @tweensteps = [] - if sprite && !sprite.disposed? && frames > 0 - @frames = frames - @step = 0 - @sprite = sprite - items.each do |item| - case item[0] - when ZOOM_X - @tweensteps[item[0]] = [sprite.zoom_x, item[1] - sprite.zoom_x] - when ZOOM_Y - @tweensteps[item[0]] = [sprite.zoom_y, item[1] - sprite.zoom_y] - when X - @tweensteps[item[0]] = [sprite.x, item[1] - sprite.x] - when Y - @tweensteps[item[0]] = [sprite.y, item[1] - sprite.y] - when OPACITY - @tweensteps[item[0]] = [sprite.opacity, item[1] - sprite.opacity] - when COLOR - @tweensteps[item[0]] = [sprite.color.clone, - Color.new(item[1].red - sprite.color.red, - item[1].green - sprite.color.green, - item[1].blue - sprite.color.blue, - item[1].alpha - sprite.color.alpha)] - end - end - @tweening = true - end + def done? + @curframe > @frames end def update - if @tweening - t = @step.to_f / @frames - @tweensteps.length.times do |i| - item = @tweensteps[i] - next if !item - case i - when ZOOM_X - @sprite.zoom_x = item[0] + (item[1] * t) - when ZOOM_Y - @sprite.zoom_y = item[0] + (item[1] * t) - when X - @sprite.x = item[0] + (item[1] * t) - when Y - @sprite.y = item[0] + (item[1] * t) - when OPACITY - @sprite.opacity = item[0] + (item[1] * t) - when COLOR - @sprite.color = Color.new(item[0].red + (item[1].red * t), - item[0].green + (item[1].green * t), - item[0].blue + (item[1].blue * t), - item[0].alpha + (item[1].alpha * t)) - end - end - @step += 1 - if @step == @frames - @step = 0 - @frames = 0 - @tweening = false - end - end + return if done? + t = @curframe.to_f / @frames + rx1 = @oldx + rx2 = @newx + @x = rx1 + (t * (rx2 - rx1)) + ry1 = @oldy + ry2 = @newy + @y = ry1 + (t * (ry2 - ry1)) + @curframe += 1 end end @@ -137,38 +101,86 @@ end #=============================================================================== # #=============================================================================== -class PointInterpolator - attr_reader :x - attr_reader :y +class SpriteInterpolator + X = 1 + Y = 2 + ZOOM_X = 3 + ZOOM_Y = 4 + COLOR = 5 + OPACITY = 6 - def initialize(oldx, oldy, newx, newy, frames) - restart(oldx, oldy, newx, newy, frames) + def initialize + @tweening = false + @tweensteps = [] + @sprite = nil + @frames = 0 + @step = 0 end - def restart(oldx, oldy, newx, newy, frames) - @oldx = oldx - @oldy = oldy - @newx = newx - @newy = newy - @frames = frames - @curframe = 0 - @x = oldx - @y = oldy + def tweening? + return @tweening end - def done? - @curframe > @frames + def tween(sprite, items, frames) + @tweensteps = [] + if sprite && !sprite.disposed? && frames > 0 + @frames = frames + @step = 0 + @sprite = sprite + items.each do |item| + case item[0] + when X + @tweensteps[item[0]] = [sprite.x, item[1] - sprite.x] + when Y + @tweensteps[item[0]] = [sprite.y, item[1] - sprite.y] + when ZOOM_X + @tweensteps[item[0]] = [sprite.zoom_x, item[1] - sprite.zoom_x] + when ZOOM_Y + @tweensteps[item[0]] = [sprite.zoom_y, item[1] - sprite.zoom_y] + when COLOR + @tweensteps[item[0]] = [sprite.color.clone, + Color.new(item[1].red - sprite.color.red, + item[1].green - sprite.color.green, + item[1].blue - sprite.color.blue, + item[1].alpha - sprite.color.alpha)] + when OPACITY + @tweensteps[item[0]] = [sprite.opacity, item[1] - sprite.opacity] + end + end + @tweening = true + end end def update - return if done? - t = @curframe.to_f / @frames - rx1 = @oldx - rx2 = @newx - @x = rx1 + (t * (rx2 - rx1)) - ry1 = @oldy - ry2 = @newy - @y = ry1 + (t * (ry2 - ry1)) - @curframe += 1 + if @tweening + t = @step.to_f / @frames + @tweensteps.length.times do |i| + item = @tweensteps[i] + next if !item + case i + when X + @sprite.x = item[0] + (item[1] * t) + when Y + @sprite.y = item[0] + (item[1] * t) + when ZOOM_X + @sprite.zoom_x = item[0] + (item[1] * t) + when ZOOM_Y + @sprite.zoom_y = item[0] + (item[1] * t) + when COLOR + @sprite.color = Color.new(item[0].red + (item[1].red * t), + item[0].green + (item[1].green * t), + item[0].blue + (item[1].blue * t), + item[0].alpha + (item[1].alpha * t)) + when OPACITY + @sprite.opacity = item[0] + (item[1] * t) + end + end + @step += 1 + if @step == @frames + @step = 0 + @frames = 0 + @tweening = false + end + end end end diff --git a/Data/Scripts/003_Game processing/004_Interpreter_Commands.rb b/Data/Scripts/003_Game processing/004_Interpreter_Commands.rb index 1c828f347..f0e9476b6 100644 --- a/Data/Scripts/003_Game processing/004_Interpreter_Commands.rb +++ b/Data/Scripts/003_Game processing/004_Interpreter_Commands.rb @@ -416,8 +416,8 @@ class Interpreter result = ($game_self_switches[key] == (@parameters[2] == 0)) end when 3 # timer - if $game_system.timer_working - sec = $game_system.timer / Graphics.frame_rate + if $game_system.timer_start + sec = $game_system.timer result = (@parameters[2] == 0) ? (sec >= @parameters[1]) : (sec <= @parameters[1]) end # when 4, 5 # actor, enemy @@ -588,13 +588,13 @@ class Interpreter end when 7 # other case @parameters[4] - when 0 then value = $game_map.map_id # map ID - when 1 then value = $player.pokemon_party.length # party members - when 2 then value = $player.money # gold -# when 3 # steps - when 4 then value = Graphics.frame_count / Graphics.frame_rate # play time - when 5 then value = $game_system.timer / Graphics.frame_rate # timer - when 6 then value = $game_system.save_count # save count + when 0 then value = $game_map.map_id # map ID + when 1 then value = $player.pokemon_party.length # party members + when 2 then value = $player.money # gold + when 3 then value = $stats.distance_moved # steps + when 4 then value = $stats.play_time # play time + when 5 then value = $game_system.timer # timer + when 6 then value = $game_system.save_count # save count end end # Apply value and operation to all specified game variables @@ -645,8 +645,8 @@ class Interpreter # * Control Timer #----------------------------------------------------------------------------- def command_124 - $game_system.timer_working = (@parameters[0] == 0) - $game_system.timer = @parameters[1] * Graphics.frame_rate if @parameters[0] == 0 + $game_system.timer_start = (@parameters[0] == 0) ? $stats.play_time : nil + $game_system.timer_duration = @parameters[1] if @parameters[0] == 0 return true end @@ -815,7 +815,7 @@ class Interpreter # * Change Fog Color Tone #----------------------------------------------------------------------------- def command_205 - $game_map.start_fog_tone_change(@parameters[0], @parameters[1] * Graphics.frame_rate / 20) + $game_map.start_fog_tone_change(@parameters[0], @parameters[1]) return true end @@ -823,7 +823,7 @@ class Interpreter # * Change Fog Opacity #----------------------------------------------------------------------------- def command_206 - $game_map.start_fog_opacity_change(@parameters[0], @parameters[1] * Graphics.frame_rate / 20) + $game_map.start_fog_opacity_change(@parameters[0], @parameters[1]) return true end @@ -897,7 +897,7 @@ class Interpreter # * Change Screen Color Tone #----------------------------------------------------------------------------- def command_223 - $game_screen.start_tone_change(@parameters[0], @parameters[1] * Graphics.frame_rate / 20) + $game_screen.start_tone_change(@parameters[0], @parameters[1]) return true end @@ -905,7 +905,7 @@ class Interpreter # * Screen Flash #----------------------------------------------------------------------------- def command_224 - $game_screen.start_flash(@parameters[0], @parameters[1] * Graphics.frame_rate / 20) + $game_screen.start_flash(@parameters[0], @parameters[1]) return true end @@ -946,8 +946,9 @@ class Interpreter x = $game_variables[@parameters[4]] y = $game_variables[@parameters[5]] end - $game_screen.pictures[number].move(@parameters[1] * Graphics.frame_rate / 20, - @parameters[2], x, y, @parameters[6], @parameters[7], @parameters[8], @parameters[9]) + $game_screen.pictures[number].move(@parameters[1], @parameters[2], x, y, + @parameters[6], @parameters[7], + @parameters[8], @parameters[9]) return true end @@ -965,8 +966,7 @@ class Interpreter #----------------------------------------------------------------------------- def command_234 number = @parameters[0] + ($game_temp.in_battle ? 50 : 0) - $game_screen.pictures[number].start_tone_change(@parameters[1], - @parameters[2] * Graphics.frame_rate / 20) + $game_screen.pictures[number].start_tone_change(@parameters[1], @parameters[2]) return true end diff --git a/Data/Scripts/004_Game classes/001_Game_Screen.rb b/Data/Scripts/004_Game classes/001_Game_Screen.rb index 20fb1e485..88600b9f5 100644 --- a/Data/Scripts/004_Game classes/001_Game_Screen.rb +++ b/Data/Scripts/004_Game classes/001_Game_Screen.rb @@ -15,37 +15,46 @@ class Game_Screen attr_accessor :weather_duration # ticks in which the weather should fade in def initialize - @brightness = 255 - @fadeout_duration = 0 - @fadein_duration = 0 - @tone = Tone.new(0, 0, 0, 0) - @tone_target = Tone.new(0, 0, 0, 0) - @tone_duration = 0 - @flash_color = Color.new(0, 0, 0, 0) - @flash_duration = 0 - @shake_power = 0 - @shake_speed = 0 - @shake_duration = 0 - @shake_direction = 1 - @shake = 0 - @pictures = [nil] - (1..100).each do |i| - @pictures.push(Game_Picture.new(i)) - end - @weather_type = :None - @weather_max = 0.0 - @weather_duration = 0 + @brightness = 255 + @fadeout_duration = 0 + @fadein_duration = 0 + @tone = Tone.new(0, 0, 0, 0) + @tone_target = Tone.new(0, 0, 0, 0) + @tone_duration = 0 + @tone_timer_start = nil + @flash_color = Color.new(0, 0, 0, 0) + @flash_duration = 0 + @flash_timer_start = nil + @shake_power = 0 + @shake_speed = 0 + @shake_duration = 0 + @shake_direction = 1 + @shake = 0 + @pictures = [nil] + (1..100).each { |i| @pictures.push(Game_Picture.new(i)) } + @weather_type = :None + @weather_max = 0.0 + @weather_duration = 0 end + # duration is time in 1/20ths of a second. def start_tone_change(tone, duration) - @tone_target = tone.clone - @tone_duration = duration - @tone = @tone_target.clone if @tone_duration == 0 + if duration == 0 + @tone = tone.clone + return + end + @tone_initial = @tone.clone + @tone_target = tone.clone + @tone_duration = duration / 20.0 + @tone_timer_start = $stats.play_time end + # duration is time in 1/20ths of a second. def start_flash(color, duration) - @flash_color = color.clone - @flash_duration = duration + @flash_color = color.clone + @flash_initial_alpha = @flash_color.alpha + @flash_duration = duration / 20.0 + @flash_timer_start = $stats.play_time end def start_shake(power, speed, duration) @@ -71,18 +80,23 @@ class Game_Screen @brightness = ((@brightness * (d - 1)) + 255) / d @fadein_duration -= 1 end - if @tone_duration >= 1 - d = @tone_duration - @tone.red = ((@tone.red * (d - 1)) + @tone_target.red) / d - @tone.green = ((@tone.green * (d - 1)) + @tone_target.green) / d - @tone.blue = ((@tone.blue * (d - 1)) + @tone_target.blue) / d - @tone.gray = ((@tone.gray * (d - 1)) + @tone_target.gray) / d - @tone_duration -= 1 + now = $stats.play_time + if @tone_timer_start + @tone.red = lerp(@tone_initial.red, @tone_target.red, @tone_duration, @tone_timer_start, now) + @tone.green = lerp(@tone_initial.green, @tone_target.green, @tone_duration, @tone_timer_start, now) + @tone.blue = lerp(@tone_initial.blue, @tone_target.blue, @tone_duration, @tone_timer_start, now) + @tone.gray = lerp(@tone_initial.gray, @tone_target.gray, @tone_duration, @tone_timer_start, now) + if now - @tone_timer_start >= @tone_duration + @tone_initial = nil + @tone_timer_start = nil + end end - if @flash_duration >= 1 - d = @flash_duration - @flash_color.alpha = @flash_color.alpha * (d - 1) / d - @flash_duration -= 1 + if @flash_timer_start + @flash_color.alpha = lerp(@flash_initial_alpha, 0, @flash_duration, @flash_timer_start, now) + if now - @flash_timer_start >= @flash_duration + @flash_initial_alpha = nil + @flash_timer_start = nil + end end if @shake_duration >= 1 || @shake != 0 delta = (@shake_power * @shake_speed * @shake_direction) / 10.0 @@ -96,13 +110,9 @@ class Game_Screen @shake_duration -= 1 if @shake_duration >= 1 end if $game_temp.in_battle - (51..100).each do |i| - @pictures[i].update - end + (51..100).each { |i| @pictures[i].update } else - (1..50).each do |i| - @pictures[i].update - end + (1..50).each { |i| @pictures[i].update } end end end @@ -111,16 +121,14 @@ end # #=============================================================================== def pbToneChangeAll(tone, duration) - $game_screen.start_tone_change(tone, duration * Graphics.frame_rate / 20) - $game_screen.pictures.each do |picture| - picture&.start_tone_change(tone, duration * Graphics.frame_rate / 20) - end + $game_screen.start_tone_change(tone, duration) + $game_screen.pictures.each { |picture| picture&.start_tone_change(tone, duration) } +end + +def pbFlash(color, frames) + $game_screen.start_flash(color, frames) end def pbShake(power, speed, frames) $game_screen.start_shake(power, speed, frames * Graphics.frame_rate / 20) end - -def pbFlash(color, frames) - $game_screen.start_flash(color, frames * Graphics.frame_rate / 20) -end diff --git a/Data/Scripts/004_Game classes/002_Game_System.rb b/Data/Scripts/004_Game classes/002_Game_System.rb index a821bd679..95c749329 100644 --- a/Data/Scripts/004_Game classes/002_Game_System.rb +++ b/Data/Scripts/004_Game classes/002_Game_System.rb @@ -8,8 +8,8 @@ class Game_System attr_reader :map_interpreter # map event interpreter attr_reader :battle_interpreter # battle event interpreter - attr_accessor :timer # timer - attr_accessor :timer_working # timer working flag + attr_accessor :timer_start # $stats.play_time when timer was started, or nil + attr_accessor :timer_duration # Time (in seconds) the timer is initially set to attr_accessor :save_disabled # save forbidden attr_accessor :menu_disabled # menu forbidden attr_accessor :encounter_disabled # encounter forbidden @@ -24,8 +24,8 @@ class Game_System def initialize @map_interpreter = Interpreter.new(0, true) @battle_interpreter = Interpreter.new(0, false) - @timer = 0 - @timer_working = false + @timer_start = nil + @timer_duration = 0 @save_disabled = false @menu_disabled = false @encounter_disabled = false @@ -265,17 +265,18 @@ class Game_System #----------------------------------------------------------------------------- def windowskin_name - if @windowskin_name.nil? - return $data_system.windowskin_name - else - return @windowskin_name - end + return $data_system.windowskin_name if @windowskin_name.nil? + return @windowskin_name end attr_writer :windowskin_name + def timer + return 0 if !@timer_start || !$stats + return @timer_duration - $stats.play_time + @timer_start + end + def update - @timer -= 1 if @timer_working && @timer > 0 if Input.trigger?(Input::SPECIAL) && pbCurrentEventCommentInput(1, "Cut Scene") event = @map_interpreter.get_self @map_interpreter.pbSetSelfSwitch(event.id, "A", true) diff --git a/Data/Scripts/004_Game classes/003_Game_Picture.rb b/Data/Scripts/004_Game classes/003_Game_Picture.rb index 721cac8f1..78b9cc1dc 100644 --- a/Data/Scripts/004_Game classes/003_Game_Picture.rb +++ b/Data/Scripts/004_Game classes/003_Game_Picture.rb @@ -28,6 +28,7 @@ class Game_Picture @opacity = 255.0 @blend_type = 1 @duration = 0 + @move_timer_start = nil @target_x = @x @target_y = @y @target_zoom_x = @zoom_x @@ -36,6 +37,7 @@ class Game_Picture @tone = Tone.new(0, 0, 0, 0) @tone_target = Tone.new(0, 0, 0, 0) @tone_duration = 0 + @tone_timer_start = nil @angle = 0 @rotate_speed = 0 end @@ -67,12 +69,13 @@ class Game_Picture @tone = Tone.new(0, 0, 0, 0) @tone_target = Tone.new(0, 0, 0, 0) @tone_duration = 0 + @tone_timer_start = nil @angle = 0 @rotate_speed = 0 end # Move Picture - # duration : time + # duration : time in 1/20ths of a second # origin : starting point # x : x-coordinate # y : y-coordinate @@ -81,57 +84,79 @@ class Game_Picture # opacity : opacity level # blend_type : blend method def move(duration, origin, x, y, zoom_x, zoom_y, opacity, blend_type) - @duration = duration - @origin = origin - @target_x = x.to_f - @target_y = y.to_f - @target_zoom_x = zoom_x.to_f - @target_zoom_y = zoom_y.to_f - @target_opacity = opacity.to_f - @blend_type = blend_type || 0 + @duration = duration / 20.0 + @origin = origin + @initial_x = @x + @initial_y = @y + @target_x = x.to_f + @target_y = y.to_f + @initial_zoom_x = @zoom_x + @initial_zoom_y = @zoom_y + @target_zoom_x = zoom_x.to_f + @target_zoom_y = zoom_y.to_f + @initial_opacity = @opacity + @target_opacity = opacity.to_f + @blend_type = blend_type || 0 + @move_timer_start = $stats.play_time end # Change Rotation Speed - # speed : rotation speed + # speed : rotation speed (degrees to change per 1/20th of a second) def rotate(speed) + @rotate_timer = (speed == 0) ? nil : System.uptime # Time since last frame @rotate_speed = speed end # Start Change of Color Tone # tone : color tone - # duration : time + # duration : time in 1/20ths of a second def start_tone_change(tone, duration) + if duration == 0 + @tone = tone.clone + return + end + @tone_initial = @tone.clone @tone_target = tone.clone - @tone_duration = duration - @tone = @tone_target.clone if @tone_duration == 0 + @tone_duration = duration / 20.0 + @tone_timer_start = $stats.play_time end - # Erase Picture def erase @name = "" end - # Frame Update def update - if @duration >= 1 - d = @duration - @x = ((@x * (d - 1)) + @target_x) / d - @y = ((@y * (d - 1)) + @target_y) / d - @zoom_x = ((@zoom_x * (d - 1)) + @target_zoom_x) / d - @zoom_y = ((@zoom_y * (d - 1)) + @target_zoom_y) / d - @opacity = ((@opacity * (d - 1)) + @target_opacity) / d - @duration -= 1 + return if @name == "" + now = $stats.play_time + if @move_timer_start + @x = lerp(@initial_x, @target_x, @duration, @move_timer_start, now) + @y = lerp(@initial_y, @target_y, @duration, @move_timer_start, now) + @zoom_x = lerp(@initial_zoom_x, @target_zoom_x, @duration, @move_timer_start, now) + @zoom_y = lerp(@initial_zoom_y, @target_zoom_y, @duration, @move_timer_start, now) + @opacity = lerp(@initial_opacity, @target_opacity, @duration, @move_timer_start, now) + if now - @move_timer_start >= @duration + @initial_x = nil + @initial_y = nil + @initial_zoom_x = nil + @initial_zoom_y = nil + @initial_opacity = nil + @move_timer_start = nil + end end - if @tone_duration >= 1 - d = @tone_duration - @tone.red = ((@tone.red * (d - 1)) + @tone_target.red) / d - @tone.green = ((@tone.green * (d - 1)) + @tone_target.green) / d - @tone.blue = ((@tone.blue * (d - 1)) + @tone_target.blue) / d - @tone.gray = ((@tone.gray * (d - 1)) + @tone_target.gray) / d - @tone_duration -= 1 + if @tone_timer_start + @tone.red = lerp(@tone_initial.red, @tone_target.red, @tone_duration, @tone_timer_start, now) + @tone.green = lerp(@tone_initial.green, @tone_target.green, @tone_duration, @tone_timer_start, now) + @tone.blue = lerp(@tone_initial.blue, @tone_target.blue, @tone_duration, @tone_timer_start, now) + @tone.gray = lerp(@tone_initial.gray, @tone_target.gray, @tone_duration, @tone_timer_start, now) + if now - @tone_timer_start >= @tone_duration + @tone_initial = nil + @tone_timer_start = nil + end end if @rotate_speed != 0 - @angle += @rotate_speed / 2.0 + @rotate_timer = System.uptime if !@rotate_timer + @angle += @rotate_speed * (System.uptime - @rotate_timer) * 20.0 + @rotate_timer = System.uptime while @angle < 0 @angle += 360 end diff --git a/Data/Scripts/004_Game classes/004_Game_Map.rb b/Data/Scripts/004_Game classes/004_Game_Map.rb index 64e78d685..455733941 100644 --- a/Data/Scripts/004_Game classes/004_Game_Map.rb +++ b/Data/Scripts/004_Game classes/004_Game_Map.rb @@ -47,28 +47,30 @@ class Game_Map @map = load_data(sprintf("Data/Map%03d.rxdata", map_id)) tileset = $data_tilesets[@map.tileset_id] updateTileset - @fog_ox = 0 - @fog_oy = 0 - @fog_tone = Tone.new(0, 0, 0, 0) - @fog_tone_target = Tone.new(0, 0, 0, 0) - @fog_tone_duration = 0 - @fog_opacity_duration = 0 - @fog_opacity_target = 0 - self.display_x = 0 - self.display_y = 0 - @need_refresh = false + @fog_ox = 0 + @fog_oy = 0 + @fog_tone = Tone.new(0, 0, 0, 0) + @fog_tone_target = Tone.new(0, 0, 0, 0) + @fog_tone_duration = 0 + @fog_tone_timer_start = nil + @fog_opacity_duration = 0 + @fog_opacity_target = 0 + @fog_opacity_timer_start = nil + self.display_x = 0 + self.display_y = 0 + @need_refresh = false EventHandlers.trigger(:on_game_map_setup, map_id, @map, tileset) - @events = {} + @events = {} @map.events.each_key do |i| - @events[i] = Game_Event.new(@map_id, @map.events[i], self) + @events[i] = Game_Event.new(@map_id, @map.events[i], self) end - @common_events = {} + @common_events = {} (1...$data_common_events.size).each do |i| - @common_events[i] = Game_CommonEvent.new(i) + @common_events[i] = Game_CommonEvent.new(i) end - @scroll_direction = 2 - @scroll_rest = 0 - @scroll_speed = 4 + @scroll_direction = 2 + @scroll_rest = 0 + @scroll_speed = 4 end def updateTileset @@ -368,16 +370,28 @@ class Game_Map return @scroll_rest > 0 end + # duration is time in 1/20ths of a second. def start_fog_tone_change(tone, duration) + if duration == 0 + @fog_tone = tone.clone + return + end + @fog_tone_initial = @fog_tone.clone @fog_tone_target = tone.clone - @fog_tone_duration = duration - @fog_tone = @fog_tone_target.clone if @fog_tone_duration == 0 + @fog_tone_duration = duration / 20.0 + @fog_tone_timer_start = $stats.play_time end + # duration is time in 1/20ths of a second. def start_fog_opacity_change(opacity, duration) + if duration == 0 + @fog_opacity = opacity.to_f + return + end + @fog_opacity_initial = @fog_opacity @fog_opacity_target = opacity.to_f - @fog_opacity_duration = duration - @fog_opacity = @fog_opacity_target if @fog_opacity_duration == 0 + @fog_opacity_duration = duration / 20.0 + @fog_opacity_timer_start = $stats.play_time end def set_tile(x, y, layer, id = 0) @@ -399,11 +413,9 @@ class Game_Map end def update - # refresh maps if necessary + # Refresh maps if necessary if $map_factory - $map_factory.maps.each do |i| - i.refresh if i.need_refresh - end + $map_factory.maps.each { |i| i.refresh if i.need_refresh } $map_factory.setCurrentMap end # If scrolling @@ -419,29 +431,31 @@ class Game_Map @scroll_rest -= distance end # Only update events that are on-screen - @events.each_value do |event| - event.update + if !$game_temp.in_menu + @events.each_value { |event| event.update } end # Update common events - @common_events.each_value do |common_event| - common_event.update - end + @common_events.each_value { |common_event| common_event.update } # Update fog + now = $stats.play_time @fog_ox -= @fog_sx / 8.0 @fog_oy -= @fog_sy / 8.0 - if @fog_tone_duration >= 1 - d = @fog_tone_duration - target = @fog_tone_target - @fog_tone.red = ((@fog_tone.red * (d - 1)) + target.red) / d - @fog_tone.green = ((@fog_tone.green * (d - 1)) + target.green) / d - @fog_tone.blue = ((@fog_tone.blue * (d - 1)) + target.blue) / d - @fog_tone.gray = ((@fog_tone.gray * (d - 1)) + target.gray) / d - @fog_tone_duration -= 1 + if @fog_tone_timer_start + @fog_tone.red = lerp(@fog_tone_initial.red, @fog_tone_target.red, @fog_tone_duration, @fog_tone_timer_start, now) + @fog_tone.green = lerp(@fog_tone_initial.green, @fog_tone_target.green, @fog_tone_duration, @fog_tone_timer_start, now) + @fog_tone.blue = lerp(@fog_tone_initial.blue, @fog_tone_target.blue, @fog_tone_duration, @fog_tone_timer_start, now) + @fog_tone.gray = lerp(@fog_tone_initial.gray, @fog_tone_target.gray, @fog_tone_duration, @fog_tone_timer_start, now) + if now - @fog_tone_timer_start >= @fog_tone_duration + @fog_tone_initial = nil + @fog_tone_timer_start = nil + end end - if @fog_opacity_duration >= 1 - d = @fog_opacity_duration - @fog_opacity = ((@fog_opacity * (d - 1)) + @fog_opacity_target) / d - @fog_opacity_duration -= 1 + if @fog_opacity_timer_start + @fog_opacity = lerp(@fog_opacity_initial, @fog_opacity_target, @fog_opacity_duration, @fog_opacity_timer_start, now) + if now - @fog_opacity_timer_start >= @fog_opacity_duration + @fog_opacity_initial = nil + @fog_opacity_timer_start = nil + end end end end diff --git a/Data/Scripts/004_Game classes/007_Game_Character.rb b/Data/Scripts/004_Game classes/007_Game_Character.rb index 7479b4310..7a70e2b14 100644 --- a/Data/Scripts/004_Game classes/007_Game_Character.rb +++ b/Data/Scripts/004_Game classes/007_Game_Character.rb @@ -25,6 +25,7 @@ class Game_Character attr_accessor :animation_id attr_accessor :transparent attr_reader :move_speed + attr_accessor :jump_speed attr_accessor :walk_anime attr_writer :bob_height @@ -60,6 +61,7 @@ class Game_Character @move_type = 0 self.move_speed = 3 self.move_frequency = 6 + self.jump_speed = 3 @move_route = nil @move_route_index = 0 @original_move_route = nil @@ -68,12 +70,12 @@ class Game_Character @step_anime = false # Whether character should animate while still @direction_fix = false @always_on_top = false - @anime_count = 0 - @stop_count = 0 + @anime_count = 0 # Time since pattern was last changed + @stop_count = 0 # Time since character last finished moving @jump_peak = 0 # Max height while jumping @jump_distance = 0 # Total distance of jump - @jump_distance_left = 0 # Distance left to travel - @jump_count = 0 # Frames left in a stationary jump + @jump_fraction = 0 # How far through a jump we currently are (0-1) + @jumping_on_spot = false @bob_height = 0 @wait_count = 0 @wait_start = nil @@ -105,62 +107,45 @@ class Game_Character end def move_speed=(val) - return if val == @move_speed @move_speed = val - # @move_speed_real is the number of quarter-pixels to move each frame. There - # are 128 quarter-pixels per tile. By default, it is calculated from - # @move_speed and has these values (assuming 40 fps): - # 1 => 3.2 # 40 frames per tile - # 2 => 6.4 # 20 frames per tile - # 3 => 12.8 # 10 frames per tile - walking speed - # 4 => 25.6 # 5 frames per tile - running speed (2x walking speed) - # 5 => 32 # 4 frames per tile - cycling speed (1.25x running speed) - # 6 => 64 # 2 frames per tile - self.move_speed_real = (val == 6) ? 64 : (val == 5) ? 32 : (2**(val + 1)) * 0.8 + # Time taken to traverse one tile (in seconds) for each speed: + # 1 => 1.0 + # 2 => 0.5 + # 3 => 0.25 # Walking speed + # 4 => 0.125 # Running speed (2x walking speed) + # 5 => 0.1 # Cycling speed (1.25x running speed) + # 6 => 0.05 + @move_time = (val == 6) ? 0.05 : (val == 5) ? 0.1 : 2.0 / (2**val) end - def move_speed_real - self.move_speed = @move_speed if !@move_speed_real - return @move_speed_real + # Takes the same values as move_speed above. + def jump_speed=(val) + @jump_speed = val + @jump_time = (val == 6) ? 0.05 : (val == 5) ? 0.1 : 2.0 / (2**val) end - def move_speed_real=(val) - @move_speed_real = val * 40.0 / Graphics.frame_rate - end - - def jump_speed_real - self.jump_speed_real = (2**(3 + 1)) * 0.8 if !@jump_speed_real # 3 is walking speed - return @jump_speed_real - end - - def jump_speed_real=(val) - @jump_speed_real = val * 40.0 / Graphics.frame_rate + # Returns time in seconds for one full cycle (4 frames) of an animating + # charset to show. Two frames are shown per movement across one tile. + def pattern_update_speed + return @jump_time * 2 if jumping? + ret = @move_time * 2 + ret *= 2 if @move_speed >= 5 # Cycling speed or faster; slower animation + return ret end def move_frequency=(val) return if val == @move_frequency @move_frequency = val - # @move_frequency_real is the number of frames to wait between each action - # in a move route (not forced). Specifically, this is the number of frames - # to wait after the character stops moving because of the previous action. - # By default, it is calculated from @move_frequency and has these values - # (assuming 40 fps): - # 1 => 190 # 4.75 seconds - # 2 => 144 # 3.6 seconds - # 3 => 102 # 2.55 seconds - # 4 => 64 # 1.6 seconds - # 5 => 30 # 0.75 seconds - # 6 => 0 # 0 seconds, i.e. continuous movement - self.move_frequency_real = (40 - (val * 2)) * (6 - val) - end - - def move_frequency_real - self.move_frequency = @move_frequency if !@move_frequency_real - return @move_frequency_real - end - - def move_frequency_real=(val) - @move_frequency_real = val * Graphics.frame_rate / 40.0 + # Time in seconds to wait between each action in a move route (not forced). + # Specifically, this is the time to wait after the character stops moving + # because of the previous action. + # 1 => 4.75 seconds + # 2 => 3.6 seconds + # 3 => 2.55 seconds + # 4 => 1.6 seconds + # 5 => 0.75 seconds + # 6 => 0 seconds, i.e. continuous movement + @command_delay = (40 - (val * 2)) * (6 - val) / 40.0 end def bob_height @@ -327,12 +312,8 @@ class Game_Character def screen_y ret = screen_y_ground if jumping? - if @jump_count > 0 - jump_fraction = ((@jump_count * jump_speed_real / Game_Map::REAL_RES_X) - 0.5).abs # 0.5 to 0 to 0.5 - else - jump_fraction = ((@jump_distance_left / @jump_distance) - 0.5).abs # 0.5 to 0 to 0.5 - end - ret += @jump_peak * ((4 * (jump_fraction**2)) - 1) + jump_progress = (@jump_fraction - 0.5).abs # 0.5 to 0 to 0.5 + ret += @jump_peak * ((4 * (jump_progress**2)) - 1) end ret += self.y_offset return ret @@ -361,7 +342,7 @@ class Game_Character end def jumping? - return (@jump_distance_left || 0) > 0 || @jump_count > 0 + return !@jump_timer.nil? end def straighten @@ -437,11 +418,17 @@ class Game_Character def move_type_custom return if jumping? || moving? + return if @move_route.list.size <= 1 # Empty move route + start_index = @move_route_index + done_one_command = false while @move_route_index < @move_route.list.size + return if @move_route_index == start_index && done_one_command + done_one_command = true command = @move_route.list[@move_route_index] if command.code == 0 if @move_route.repeat @move_route_index = 0 + command = @move_route.list[@move_route_index] else if @move_route_forcing @move_route_forcing = false @@ -450,9 +437,11 @@ class Game_Character @original_move_route = nil end @stop_count = 0 + return end - return end + # The below move route commands wait for a frame (i.e. return) after + # executing them if command.code <= 14 case command.code when 1 then move_down @@ -473,14 +462,13 @@ class Game_Character @move_route_index += 1 if @move_route.skippable || moving? || jumping? return end - if command.code == 15 # Wait - @wait_count = command.parameters[0] / 20.0 - @wait_start = System.uptime - @move_route_index += 1 - return - end - if command.code >= 16 && command.code <= 26 + # The below move route commands wait for a frame (i.e. return) after + # executing them + if command.code >= 15 && command.code <= 26 case command.code + when 15 # Wait + @wait_count = command.parameters[0] / 20.0 + @wait_start = System.uptime when 16 then turn_down when 17 then turn_left when 18 then turn_right @@ -496,6 +484,8 @@ class Game_Character @move_route_index += 1 return end + # The below move route commands don't wait for a frame (i.e. return) after + # executing them if command.code >= 27 case command.code when 27 @@ -551,8 +541,11 @@ class Game_Character turn_generic(dir) if turn_enabled if can_move_in_direction?(dir) turn_generic(dir) + @move_initial_x = @x + @move_initial_y = @y @x += (dir == 4) ? -1 : (dir == 6) ? 1 : 0 @y += (dir == 8) ? -1 : (dir == 2) ? 1 : 0 + @move_timer = 0.0 increase_steps else check_event_trigger_touch(dir) @@ -580,8 +573,11 @@ class Game_Character @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction) end if can_move_in_direction?(7) + @move_initial_x = @x + @move_initial_y = @y @x -= 1 @y -= 1 + @move_timer = 0.0 increase_steps end end @@ -591,8 +587,11 @@ class Game_Character @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction) end if can_move_in_direction?(9) + @move_initial_x = @x + @move_initial_y = @y @x += 1 @y -= 1 + @move_timer = 0.0 increase_steps end end @@ -602,8 +601,11 @@ class Game_Character @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction) end if can_move_in_direction?(1) + @move_initial_x = @x + @move_initial_y = @y @x -= 1 @y += 1 + @move_timer = 0.0 increase_steps end end @@ -613,8 +615,11 @@ class Game_Character @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction) end if can_move_in_direction?(3) + @move_initial_x = @x + @move_initial_y = @y @x += 1 @y += 1 + @move_timer = 0.0 increase_steps end end @@ -753,19 +758,16 @@ class Game_Character end each_occupied_tile { |i, j| return if !passable?(i + x_plus, j + y_plus, 0) } end + @jump_initial_x = @x + @jump_initial_y = @y @x = @x + x_plus @y = @y + y_plus - real_distance = Math.sqrt((x_plus * x_plus) + (y_plus * y_plus)) + @jump_timer = 0.0 + real_distance = Math.sqrt(x_plus**2 + y_plus**2) distance = [1, real_distance].max @jump_peak = distance * Game_Map::TILE_HEIGHT * 3 / 8 # 3/4 of tile for ledge jumping @jump_distance = [x_plus.abs * Game_Map::REAL_RES_X, y_plus.abs * Game_Map::REAL_RES_Y].max - @jump_distance_left = 1 # Just needs to be non-zero - if real_distance > 0 # Jumping to somewhere else - @jump_count = 0 - else # Jumping on the spot - @jump_speed_real = nil # Reset jump speed - @jump_count = Game_Map::REAL_RES_X / jump_speed_real # Number of frames to jump one tile - end + @jumping_on_spot = (real_distance == 0) increase_steps end @@ -874,16 +876,20 @@ class Game_Character # Updating #============================================================================= def update + return if $game_temp.in_menu + time_now = System.uptime + @last_update_time = time_now if !@last_update_time || @last_update_time > time_now + @delta_t = time_now - @last_update_time + @last_update_time = time_now + return if @delta_t > 0.25 # Was in a menu; delay movement @moved_last_frame = @moved_this_frame @stopped_last_frame = @stopped_this_frame @moved_this_frame = false @stopped_this_frame = false - if !$game_temp.in_menu - # Update command - update_command - # Update movement - (moving? || jumping?) ? update_move : update_stop - end + # Update command + update_command + # Update movement + (moving? || jumping?) ? update_move : update_stop # Update animation update_pattern end @@ -902,15 +908,7 @@ class Game_Character end def update_command_new - # @stop_count is the number of frames since the last movement finished. - # @move_frequency has these values: - # 1 => @stop_count > 190 # 4.75 seconds - # 2 => @stop_count > 144 # 3.6 seconds - # 3 => @stop_count > 102 # 2.55 seconds - # 4 => @stop_count > 64 # 1.6 seconds - # 5 => @stop_count > 30 # 0.75 seconds - # 6 => @stop_count > 0 # 0 seconds - if @stop_count >= self.move_frequency_real + if @stop_count >= @command_delay case @move_type when 1 then move_type_random when 2 then move_type_toward_player @@ -920,29 +918,48 @@ class Game_Character end def update_move - # Move the character (the 0.1 catches rounding errors) - distance = (jumping?) ? jump_speed_real : move_speed_real - dest_x = @x * Game_Map::REAL_RES_X - dest_y = @y * Game_Map::REAL_RES_Y - if @real_x < dest_x - @real_x += distance - @real_x = dest_x if @real_x > dest_x - 0.1 - else - @real_x -= distance - @real_x = dest_x if @real_x < dest_x + 0.1 + if @move_timer + @move_timer += @delta_t + # Move horizontally + if @x != @move_initial_x + dist = (@move_initial_x - @x).abs + @real_x = lerp(@move_initial_x, @x, @move_time * dist, @move_timer) * Game_Map::REAL_RES_X + end + # Move vertically + if @y != @move_initial_y + dist = (@move_initial_y - @y).abs + @real_y = lerp(@move_initial_y, @y, @move_time * dist, @move_timer) * Game_Map::REAL_RES_Y + end + elsif @jump_timer + self.jump_speed = 3 if !@jump_time + @jump_timer += @delta_t + dist = [(@x - @jump_initial_x).abs, (@y - @jump_initial_y).abs].max + dist = 1 if dist == 0 # Jumping on spot + # Move horizontally + if @x != @jump_initial_x + @real_x = lerp(@jump_initial_x, @x, @jump_time * dist, @jump_timer) * Game_Map::REAL_RES_X + end + # Move vertically + if @y != @jump_initial_y + @real_y = lerp(@jump_initial_y, @y, @jump_time * dist, @jump_timer) * Game_Map::REAL_RES_Y + end + # Calculate how far through the jump we are (from 0 to 1) + @jump_fraction = @jump_timer / (@jump_time * dist) end - if @real_y < dest_y - @real_y += distance - @real_y = dest_y if @real_y > dest_y - 0.1 - else - @real_y -= distance - @real_y = dest_y if @real_y < dest_y + 0.1 + # Snap to end position if close enough + @real_x = @x * Game_Map::REAL_RES_X if (@real_x - (@x * Game_Map::REAL_RES_X)).abs < Game_Map::X_SUBPIXELS / 2 + @real_y = @y * Game_Map::REAL_RES_Y if (@real_y - (@y * Game_Map::REAL_RES_Y)).abs < Game_Map::Y_SUBPIXELS / 2 + # End of move + if !moving? + @move_timer = nil end - # Refresh how far is left to travel in a jump - was_jumping = jumping? - if was_jumping - @jump_count -= 1 if @jump_count > 0 # For stationary jumps only - @jump_distance_left = [(dest_x - @real_x).abs, (dest_y - @real_y).abs].max + # End of jump + if jumping? && @jump_fraction >= 1 + @jump_timer = nil + @jump_peak = 0 + @jump_distance = 0 + @jump_fraction = 0 + @jumping_on_spot = false end # End of a step, so perform events that happen at this time if !jumping? && !moving? @@ -953,18 +970,18 @@ class Game_Character calculate_bush_depth end # Increment animation counter - @anime_count += 1 if @walk_anime || @step_anime + @anime_count += @delta_t if @walk_anime || @step_anime @moved_this_frame = true end def update_stop - @anime_count += 1 if @step_anime - @stop_count += 1 if !@starting && !lock? + @anime_count += @delta_t if @step_anime + @stop_count += @delta_t if !@starting && !lock? end def update_pattern return if @lock_pattern -# return if @jump_count > 0 # Don't animate if jumping on the spot +# return if @jumping_on_spot # Don't animate if jumping on the spot # Character has stopped moving, return to original pattern if @moved_last_frame && !@moved_this_frame && !@step_anime @pattern = @original_pattern @@ -980,12 +997,10 @@ class Game_Character # Calculate how many frames each pattern should display for, i.e. the time # it takes to move half a tile (or a whole tile if cycling). We assume the # game uses square tiles. - real_speed = (jumping?) ? jump_speed_real : move_speed_real - frames_per_pattern = Game_Map::REAL_RES_X / (real_speed * 2.0) - frames_per_pattern *= 2 if move_speed >= 5 # Cycling speed or faster - return if @anime_count < frames_per_pattern + pattern_time = pattern_update_speed / 4 # 4 frames per cycle in a charset + return if @anime_count < pattern_time # Advance to the next animation frame @pattern = (@pattern + 1) % 4 - @anime_count -= frames_per_pattern + @anime_count -= pattern_time end end diff --git a/Data/Scripts/004_Game classes/009_Game_Player.rb b/Data/Scripts/004_Game classes/009_Game_Player.rb index c97bc8d1f..634682732 100644 --- a/Data/Scripts/004_Game classes/009_Game_Player.rb +++ b/Data/Scripts/004_Game classes/009_Game_Player.rb @@ -48,6 +48,8 @@ class Game_Player < Game_Character return $PokemonGlobal.followers.length == 0 end + #----------------------------------------------------------------------------- + def can_run? return @move_speed > 3 if @move_route_forcing return false if $game_temp.in_menu || $game_temp.in_battle || @@ -110,6 +112,8 @@ class Game_Player < Game_Character @character_name = new_charset if new_charset end + #----------------------------------------------------------------------------- + def bump_into_object return if @bump_se && @bump_se > 0 pbSEPlay("Player bump") if !@move_route_forcing @@ -146,8 +150,11 @@ class Game_Player < Game_Character # General movement turn_generic(dir, true) if !$game_temp.encounter_triggered + @move_initial_x = @x + @move_initial_y = @y @x += x_offset @y += y_offset + @move_timer = 0.0 add_move_distance_to_stats(x_offset.abs + y_offset.abs) increase_steps end @@ -174,49 +181,7 @@ class Game_Player < Game_Character add_move_distance_to_stats(x_plus.abs + y_plus.abs) if @x != old_x || @y != old_y end - def pbTriggeredTrainerEvents(triggers, checkIfRunning = true, trainer_only = false) - result = [] - # If event is running - return result if checkIfRunning && $game_system.map_interpreter.running? - # All event loops - $game_map.events.each_value do |event| - next if !triggers.include?(event.trigger) - next if !event.name[/trainer\((\d+)\)/i] && (trainer_only || !event.name[/sight\((\d+)\)/i]) - distance = $~[1].to_i - next if !pbEventCanReachPlayer?(event, self, distance) - next if event.jumping? || event.over_trigger? - result.push(event) - end - return result - end - - def pbTriggeredCounterEvents(triggers, checkIfRunning = true) - result = [] - # If event is running - return result if checkIfRunning && $game_system.map_interpreter.running? - # All event loops - $game_map.events.each_value do |event| - next if !triggers.include?(event.trigger) - next if !event.name[/counter\((\d+)\)/i] - distance = $~[1].to_i - next if !pbEventFacesPlayer?(event, self, distance) - next if event.jumping? || event.over_trigger? - result.push(event) - end - return result - end - - def pbCheckEventTriggerAfterTurning; end - - def pbCheckEventTriggerFromDistance(triggers) - ret = pbTriggeredTrainerEvents(triggers) - ret.concat(pbTriggeredCounterEvents(triggers)) - return false if ret.length == 0 - ret.each do |event| - event.start - end - return true - end + #----------------------------------------------------------------------------- def pbTerrainTag(countBridge = false) return $map_factory.getTerrainTagFromCoords(self.map.map_id, @x, @y, countBridge) if $map_factory @@ -303,6 +268,52 @@ class Game_Player < Game_Character @blend_type = 0 end + #----------------------------------------------------------------------------- + + def pbTriggeredTrainerEvents(triggers, checkIfRunning = true, trainer_only = false) + result = [] + # If event is running + return result if checkIfRunning && $game_system.map_interpreter.running? + # All event loops + $game_map.events.each_value do |event| + next if !triggers.include?(event.trigger) + next if !event.name[/trainer\((\d+)\)/i] && (trainer_only || !event.name[/sight\((\d+)\)/i]) + distance = $~[1].to_i + next if !pbEventCanReachPlayer?(event, self, distance) + next if event.jumping? || event.over_trigger? + result.push(event) + end + return result + end + + def pbTriggeredCounterEvents(triggers, checkIfRunning = true) + result = [] + # If event is running + return result if checkIfRunning && $game_system.map_interpreter.running? + # All event loops + $game_map.events.each_value do |event| + next if !triggers.include?(event.trigger) + next if !event.name[/counter\((\d+)\)/i] + distance = $~[1].to_i + next if !pbEventFacesPlayer?(event, self, distance) + next if event.jumping? || event.over_trigger? + result.push(event) + end + return result + end + + def pbCheckEventTriggerAfterTurning; end + + def pbCheckEventTriggerFromDistance(triggers) + ret = pbTriggeredTrainerEvents(triggers) + ret.concat(pbTriggeredCounterEvents(triggers)) + return false if ret.length == 0 + ret.each do |event| + event.start + end + return true + end + # Trigger event(s) at the same coordinates as self with the appropriate # trigger(s) that can be triggered def check_event_trigger_here(triggers) @@ -387,6 +398,8 @@ class Game_Player < Game_Character return result end + #----------------------------------------------------------------------------- + def update last_real_x = @real_x last_real_y = @real_y diff --git a/Data/Scripts/004_Game classes/011_Game_Follower.rb b/Data/Scripts/004_Game classes/011_Game_Follower.rb index 5573c55df..16113fac6 100644 --- a/Data/Scripts/004_Game classes/011_Game_Follower.rb +++ b/Data/Scripts/004_Game classes/011_Game_Follower.rb @@ -68,11 +68,12 @@ class Game_Follower < Game_Event # Can't walk over the middle tile, but can walk over the end tile; jump over if location_passable?(self.x, self.y, direction) if leader.jumping? - @jump_speed_real = leader.jump_speed_real + self.jump_speed = leader.jump_speed || 3 else - # This is doubled because self has to jump 2 tiles in the time it - # takes the leader to move one tile. - @jump_speed_real = leader.move_speed_real * 2 + self.jump_speed = leader.move_speed || 3 + # This is halved because self has to jump 2 tiles in the time it takes + # the leader to move one tile + @jump_time /= 2 end jump(delta_x, delta_y) else @@ -105,6 +106,21 @@ class Game_Follower < Game_Event end end + # Ceases all movement immediately. Used when the leader wants to move another + # tile but self hasn't quite finished its previous movement yet. + def end_movement + @x = x % self.map.width + @y = y % self.map.height + @real_x = @x * Game_Map::REAL_RES_X + @real_y = @y * Game_Map::REAL_RES_Y + @move_timer = nil + @jump_timer = nil + @jump_peak = 0 + @jump_distance = 0 + @jump_fraction = 0 + @jumping_on_spot = false + end + #----------------------------------------------------------------------------- def turn_towards_leader(leader) @@ -113,6 +129,7 @@ class Game_Follower < Game_Event def follow_leader(leader, instant = false, leaderIsTrueLeader = true) return if @move_route_forcing + end_movement maps_connected = $map_factory.areConnected?(leader.map.map_id, self.map.map_id) target = nil # Get the target tile that self wants to move to diff --git a/Data/Scripts/004_Game classes/012_Game_FollowerFactory.rb b/Data/Scripts/004_Game classes/012_Game_FollowerFactory.rb index 031a27101..aa26bd01a 100644 --- a/Data/Scripts/004_Game classes/012_Game_FollowerFactory.rb +++ b/Data/Scripts/004_Game classes/012_Game_FollowerFactory.rb @@ -240,6 +240,7 @@ class Game_FollowerFactory #----------------------------------------------------------------------------- def update + return if $game_temp.in_menu followers = $PokemonGlobal.followers return if followers.length == 0 # Update all followers diff --git a/Data/Scripts/005_Sprites/002_Sprite_Timer.rb b/Data/Scripts/005_Sprites/002_Sprite_Timer.rb index 74e01d297..f379d2364 100644 --- a/Data/Scripts/005_Sprites/002_Sprite_Timer.rb +++ b/Data/Scripts/005_Sprites/002_Sprite_Timer.rb @@ -18,7 +18,7 @@ class Sprite_Timer def update return if disposed? - if $game_system.timer_working + if $game_system.timer_start @timer.visible = true if @timer if !@timer @timer = Window_AdvancedTextPokemon.newWithSize("", Graphics.width - 120, 0, 120, 64) @@ -27,7 +27,7 @@ class Sprite_Timer @timer.viewport = @viewport @timer.z = 99998 end - curtime = $game_system.timer / Graphics.frame_rate + curtime = $game_system.timer curtime = 0 if curtime < 0 if curtime != @total_sec # Calculate total number of seconds diff --git a/Data/Scripts/005_Sprites/013_ScreenPosHelper.rb b/Data/Scripts/005_Sprites/012_ScreenPosHelper.rb similarity index 100% rename from Data/Scripts/005_Sprites/013_ScreenPosHelper.rb rename to Data/Scripts/005_Sprites/012_ScreenPosHelper.rb diff --git a/Data/Scripts/009_Scenes/001_Transitions.rb b/Data/Scripts/009_Scenes/001_Transitions.rb index 4333af331..b333aef33 100644 --- a/Data/Scripts/009_Scenes/001_Transitions.rb +++ b/Data/Scripts/009_Scenes/001_Transitions.rb @@ -22,7 +22,7 @@ module Graphics duration = 0 filename = "" end - duration *= Graphics.frame_rate / 20 # For default fade-in animation + duration *= Graphics.frame_rate / 20 # For default fade-in animation, must be in frames begin transition_KGC_SpecialTransition(duration, filename, vague) rescue Exception diff --git a/Data/Scripts/011_Battle/004_Scene/001_Battle_Scene.rb b/Data/Scripts/011_Battle/004_Scene/001_Battle_Scene.rb index 7299310f2..b3b1e5914 100644 --- a/Data/Scripts/011_Battle/004_Scene/001_Battle_Scene.rb +++ b/Data/Scripts/011_Battle/004_Scene/001_Battle_Scene.rb @@ -98,8 +98,6 @@ class Battle::Scene # Update other graphics @sprites["battle_bg"].update if @sprites["battle_bg"].respond_to?("update") Graphics.update - @frameCounter += 1 - @frameCounter = @frameCounter % (Graphics.frame_rate * 12 / 20) end def pbInputUpdate @@ -114,9 +112,9 @@ class Battle::Scene cw&.update @battle.battlers.each_with_index do |b, i| next if !b - @sprites["dataBox_#{i}"]&.update(@frameCounter) - @sprites["pokemon_#{i}"]&.update(@frameCounter) - @sprites["shadow_#{i}"]&.update(@frameCounter) + @sprites["dataBox_#{i}"]&.update + @sprites["pokemon_#{i}"]&.update + @sprites["shadow_#{i}"]&.update end end diff --git a/Data/Scripts/011_Battle/004_Scene/002_Scene_Initialize.rb b/Data/Scripts/011_Battle/004_Scene/002_Scene_Initialize.rb index 3861bd6d9..1384def4d 100644 --- a/Data/Scripts/011_Battle/004_Scene/002_Scene_Initialize.rb +++ b/Data/Scripts/011_Battle/004_Scene/002_Scene_Initialize.rb @@ -3,12 +3,11 @@ class Battle::Scene # Create the battle scene and its elements #============================================================================= def initialize - @battle = nil - @abortable = false - @aborted = false - @battleEnd = false - @animations = [] - @frameCounter = 0 + @battle = nil + @abortable = false + @aborted = false + @battleEnd = false + @animations = [] end # Called whenever the battle begins. diff --git a/Data/Scripts/011_Battle/004_Scene/004_Scene_PlayAnimations.rb b/Data/Scripts/011_Battle/004_Scene/004_Scene_PlayAnimations.rb index f65f1e116..5df4c2c08 100644 --- a/Data/Scripts/011_Battle/004_Scene/004_Scene_PlayAnimations.rb +++ b/Data/Scripts/011_Battle/004_Scene/004_Scene_PlayAnimations.rb @@ -225,8 +225,8 @@ class Battle::Scene elsif battler.hp < oldHP pbCommonAnimation("HealthDown", battler) if showAnim && @battle.showAnims end - @sprites["dataBox_#{battler.index}"].animateHP(oldHP, battler.hp, battler.totalhp) - while @sprites["dataBox_#{battler.index}"].animatingHP + @sprites["dataBox_#{battler.index}"].animate_hp(oldHP, battler.hp) + while @sprites["dataBox_#{battler.index}"].animating_hp? pbUpdate end end @@ -253,7 +253,7 @@ class Battle::Scene targets.each do |t| anim = Animation::BattlerDamage.new(@sprites, @viewport, t[0].index, t[2]) damageAnims.push(anim) - @sprites["dataBox_#{t[0].index}"].animateHP(t[1], t[0].hp, t[0].totalhp) + @sprites["dataBox_#{t[0].index}"].animate_hp(t[1], t[0].hp) end # Update loop loop do @@ -261,7 +261,7 @@ class Battle::Scene pbUpdate allDone = true targets.each do |t| - next if !@sprites["dataBox_#{t[0].index}"].animatingHP + next if !@sprites["dataBox_#{t[0].index}"].animating_hp? allDone = false break end @@ -286,8 +286,8 @@ class Battle::Scene endExpLevel = tempExp2 - startExp expRange = endExp - startExp dataBox = @sprites["dataBox_#{battler.index}"] - dataBox.animateExp(startExpLevel, endExpLevel, expRange) - while dataBox.animatingExp + dataBox.animate_exp(startExpLevel, endExpLevel, expRange) + while dataBox.animating_exp? pbUpdate end end diff --git a/Data/Scripts/011_Battle/004_Scene/006_Battle_Scene_Objects.rb b/Data/Scripts/011_Battle/004_Scene/006_Battle_Scene_Objects.rb index 0bbee48bb..f80bd5d51 100644 --- a/Data/Scripts/011_Battle/004_Scene/006_Battle_Scene_Objects.rb +++ b/Data/Scripts/011_Battle/004_Scene/006_Battle_Scene_Objects.rb @@ -4,14 +4,20 @@ class Battle::Scene::PokemonDataBox < Sprite attr_reader :battler attr_accessor :selected - attr_reader :animatingHP - attr_reader :animatingExp # Time in seconds to fully fill the Exp bar (from empty). EXP_BAR_FILL_TIME = 1.75 + # Time in seconds for this data box to flash when the Exp fully fills. + EXP_FULL_FLASH_DURATION = 0.2 # Maximum time in seconds to make a change to the HP bar. HP_BAR_CHANGE_TIME = 1.0 + # Time (in seconds) for one complete sprite bob cycle (up and down) while + # choosing a command for this battler or when this battler is being chosen as + # a target. Set to nil to prevent bobbing. + BOBBING_DURATION = 0.6 + # Height in pixels of a status icon STATUS_ICON_HEIGHT = 16 + # Text colors NAME_BASE_COLOR = Color.new(72, 72, 72) NAME_SHADOW_COLOR = Color.new(184, 184, 184) MALE_BASE_COLOR = Color.new(48, 96, 216) @@ -21,18 +27,14 @@ class Battle::Scene::PokemonDataBox < Sprite def initialize(battler, sideSize, viewport = nil) super(viewport) - @battler = battler - @sprites = {} - @spriteX = 0 - @spriteY = 0 - @spriteBaseX = 0 - @selected = 0 - @frame = 0 - @showHP = false # Specifically, show the HP numbers - @animatingHP = false - @showExp = false # Specifically, show the Exp bar - @animatingExp = false - @expFlash = 0 + @battler = battler + @sprites = {} + @spriteX = 0 + @spriteY = 0 + @spriteBaseX = 0 + @selected = 0 + @show_hp_numbers = false + @show_exp_bar = false initializeDataBoxGraphic(sideSize) initializeOtherGraphics(viewport) refresh @@ -45,8 +47,8 @@ class Battle::Scene::PokemonDataBox < Sprite bgFilename = ["Graphics/UI/Battle/databox_normal", "Graphics/UI/Battle/databox_normal_foe"][@battler.index % 2] if onPlayerSide - @showHP = true - @showExp = true + @show_hp_numbers = true + @show_exp_bar = true end else # Multiple Pokémon on side, use the thin dara box BG bgFilename = ["Graphics/UI/Battle/databox_thin", @@ -143,7 +145,7 @@ class Battle::Scene::PokemonDataBox < Sprite @sprites.each do |i| i[1].visible = value if !i[1].disposed? end - @expBar.visible = (value && @showExp) + @expBar.visible = (value && @show_exp_bar) end def color=(value) @@ -159,38 +161,46 @@ class Battle::Scene::PokemonDataBox < Sprite end def hp - return (@animatingHP) ? @currentHP : @battler.hp + return (animating_hp?) ? @anim_hp_current : @battler.hp end def exp_fraction - return 0.0 if @rangeExp == 0 - return (@animatingExp) ? @currentExp.to_f / @rangeExp : @battler.pokemon.exp_fraction + if animating_exp? + return 0.0 if @anim_exp_range == 0 + return @anim_exp_current.to_f / @anim_exp_range + end + return @battler.pokemon.exp_fraction end - def animateHP(oldHP, newHP, rangeHP) - @currentHP = oldHP - @endHP = newHP - @rangeHP = rangeHP - # NOTE: A change in HP takes the same amount of time to animate, no matter - # how big a change it is. - @hpIncPerFrame = (newHP - oldHP).abs / (HP_BAR_CHANGE_TIME * Graphics.frame_rate) - # minInc is the smallest amount that HP is allowed to change per frame. - # This avoids a tiny change in HP still taking HP_BAR_CHANGE_TIME seconds. - minInc = (rangeHP * 4) / (@hpBarBitmap.width * HP_BAR_CHANGE_TIME * Graphics.frame_rate) - @hpIncPerFrame = minInc if @hpIncPerFrame < minInc - @animatingHP = true + # NOTE: A change in HP takes the same amount of time to animate, no matter how + # big a change it is. + def animate_hp(old_val, new_val) + return if old_val == new_val + @anim_hp_start = old_val + @anim_hp_end = new_val + @anim_hp_current = old_val + @anim_hp_timer_start = System.uptime end - def animateExp(oldExp, newExp, rangeExp) - return if rangeExp == 0 - @currentExp = oldExp - @endExp = newExp - @rangeExp = rangeExp - # NOTE: Filling the Exp bar from empty to full takes EXP_BAR_FILL_TIME - # seconds no matter what. Filling half of it takes half as long, etc. - @expIncPerFrame = rangeExp / (EXP_BAR_FILL_TIME * Graphics.frame_rate) - @animatingExp = true - pbSEPlay("Pkmn exp gain") if @showExp + def animating_hp? + return @anim_hp_timer_start != nil + end + + # NOTE: Filling the Exp bar from empty to full takes EXP_BAR_FILL_TIME seconds + # no matter what. Filling half of it takes half as long, etc. + def animate_exp(old_val, new_val, range) + return if old_val == new_val || range == 0 || !@show_exp_bar + @anim_exp_start = old_val + @anim_exp_end = new_val + @anim_exp_range = range + @anim_exp_duration_mult = (new_val - old_val).abs / range.to_f + @anim_exp_current = old_val + @anim_exp_timer_start = System.uptime + pbSEPlay("Pkmn exp gain") if @show_exp_bar + end + + def animating_exp? + return @anim_exp_timer_start != nil end def pbDrawNumber(number, btmp, startX, startY, align = 0) @@ -284,15 +294,15 @@ class Battle::Scene::PokemonDataBox < Sprite draw_shiny_icon draw_special_form_icon draw_owned_icon - refreshHP - refreshExp + refresh_hp + refresh_exp end - def refreshHP + def refresh_hp @hpNumbers.bitmap.clear return if !@battler.pokemon # Show HP numbers - if @showHP + if @show_hp_numbers pbDrawNumber(self.hp, @hpNumbers.bitmap, 54, 2, 1) pbDrawNumber(-1, @hpNumbers.bitmap, 54, 2) # / char pbDrawNumber(@battler.totalhp, @hpNumbers.bitmap, 70, 2) @@ -307,14 +317,14 @@ class Battle::Scene::PokemonDataBox < Sprite w = ((w / 2.0).round) * 2 end @hpBar.src_rect.width = w - hpColor = 0 # Green bar + hpColor = 0 # Green bar hpColor = 1 if self.hp <= @battler.totalhp / 2 # Yellow bar hpColor = 2 if self.hp <= @battler.totalhp / 4 # Red bar @hpBar.src_rect.y = hpColor * @hpBarBitmap.height / 3 end - def refreshExp - return if !@showExp + def refresh_exp + return if !@show_exp_bar w = exp_fraction * @expBarBitmap.width # NOTE: The line below snaps the bar's width to the nearest 2 pixels, to # fit in with the rest of the graphics which are doubled in size. @@ -322,80 +332,82 @@ class Battle::Scene::PokemonDataBox < Sprite @expBar.src_rect.width = w end - def updateHPAnimation - return if !@animatingHP - if @currentHP < @endHP # Gaining HP - @currentHP += @hpIncPerFrame - @currentHP = @endHP if @currentHP >= @endHP - elsif @currentHP > @endHP # Losing HP - @currentHP -= @hpIncPerFrame - @currentHP = @endHP if @currentHP <= @endHP - end + def update_hp_animation + return if !animating_hp? + @anim_hp_current = lerp(@anim_hp_start, @anim_hp_end, HP_BAR_CHANGE_TIME, + @anim_hp_timer_start, System.uptime) # Refresh the HP bar/numbers - refreshHP - @animatingHP = false if @currentHP == @endHP + refresh_hp + # End the HP bar filling animation + if @anim_hp_current == @anim_hp_end + @anim_hp_start = nil + @anim_hp_end = nil + @anim_hp_timer_start = nil + @anim_hp_current = nil + end end - def updateExpAnimation - return if !@animatingExp - if !@showExp # Not showing the Exp bar, no need to waste time animating it - @currentExp = @endExp - @animatingExp = false + def update_exp_animation + return if !animating_exp? + if !@show_exp_bar # Not showing the Exp bar, no need to waste time animating it + @anim_exp_timer_start = nil return end - if @currentExp < @endExp # Gaining Exp - @currentExp += @expIncPerFrame - @currentExp = @endExp if @currentExp >= @endExp - elsif @currentExp > @endExp # Losing Exp - @currentExp -= @expIncPerFrame - @currentExp = @endExp if @currentExp <= @endExp - end + duration = EXP_BAR_FILL_TIME * @anim_exp_duration_mult + @anim_exp_current = lerp(@anim_exp_start, @anim_exp_end, duration, + @anim_exp_timer_start, System.uptime) # Refresh the Exp bar - refreshExp - return if @currentExp != @endExp # Exp bar still has more to animate - # Exp bar is completely filled, level up with a flash and sound effect - if @currentExp >= @rangeExp - if @expFlash == 0 - pbSEStop - @expFlash = Graphics.frame_rate / 5 - pbSEPlay("Pkmn exp full") - self.flash(Color.new(64, 200, 248, 192), @expFlash) - @sprites.each do |i| - i[1].flash(Color.new(64, 200, 248, 192), @expFlash) if !i[1].disposed? - end + refresh_exp + return if @anim_exp_current != @anim_exp_end # Exp bar still has more to animate + # End the Exp bar filling animation + if @anim_exp_current >= @anim_exp_range + if @anim_exp_flash_timer_start + # Waiting for Exp full flash to finish + return if System.uptime - @anim_exp_flash_timer_start < EXP_FULL_FLASH_DURATION else - @expFlash -= 1 - @animatingExp = false if @expFlash == 0 + # Show the Exp full flash + @anim_exp_flash_timer_start = System.uptime + pbSEStop + pbSEPlay("Pkmn exp full") + flash_duration = EXP_FULL_FLASH_DURATION * Graphics.frame_rate # Must be in frames, not seconds + self.flash(Color.new(64, 200, 248, 192), flash_duration) + @sprites.each do |i| + i[1].flash(Color.new(64, 200, 248, 192), flash_duration) if !i[1].disposed? + end + return end - else - pbSEStop - # Exp bar has finished filling, end animation - @animatingExp = false end + pbSEStop if !@anim_exp_flash_timer_start + @anim_exp_start = nil + @anim_exp_end = nil + @anim_exp_duration_mult = nil + @anim_exp_current = nil + @anim_exp_timer_start = nil + @anim_exp_flash_timer_start = nil end - QUARTER_ANIM_PERIOD = Graphics.frame_rate * 3 / 20 - - def updatePositions(frameCounter) + def update_positions self.x = @spriteX self.y = @spriteY # Data box bobbing while Pokémon is selected - if @selected == 1 || @selected == 2 # Choosing commands/targeted or damaged - case (frameCounter / QUARTER_ANIM_PERIOD).floor + if (@selected == 1 || @selected == 2) && BOBBING_DURATION # Choosing commands/targeted + bob_delta = System.uptime % BOBBING_DURATION # 0-BOBBING_DURATION + bob_frame = (4 * bob_delta / BOBBING_DURATION).floor + case bob_frame when 1 then self.y = @spriteY - 2 when 3 then self.y = @spriteY + 2 end end end - def update(frameCounter = 0) - super() + def update + super # Animate HP bar - updateHPAnimation + update_hp_animation # Animate Exp bar - updateExpAnimation + update_exp_animation # Update coordinates of the data box - updatePositions(frameCounter) + update_positions pbUpdateSpriteHash(@sprites) end end @@ -502,6 +514,13 @@ class Battle::Scene::BattlerSprite < RPG::Sprite attr_accessor :selected attr_reader :sideSize + # Time (in seconds) for one complete sprite bob cycle (up and down) while + # choosing a command for this battler. Set to nil to prevent bobbing. + COMMAND_BOBBING_DURATION = 0.6 + # Time (in seconds) for one complete blinking cycle while this battler is + # being chosen as a target. Set to nil to prevent blinking. + TARGET_BLINKING_DURATION = 0.3 + def initialize(viewport, sideSize, index, battleAnimations) super(viewport) @pkmn = nil @@ -511,7 +530,6 @@ class Battle::Scene::BattlerSprite < RPG::Sprite # @selected: 0 = not selected, 1 = choosing action bobbing for this Pokémon, # 2 = flashing when targeted @selected = 0 - @frame = 0 @updating = false @spriteX = 0 # Actual x coordinate @spriteY = 0 # Actual y coordinate @@ -588,10 +606,7 @@ class Battle::Scene::BattlerSprite < RPG::Sprite @pkmn&.play_cry end - QUARTER_ANIM_PERIOD = Graphics.frame_rate * 3 / 20 - SIXTH_ANIM_PERIOD = Graphics.frame_rate * 2 / 20 - - def update(frameCounter = 0) + def update return if !@_iconBitmap @updating = true # Update bitmap @@ -599,8 +614,10 @@ class Battle::Scene::BattlerSprite < RPG::Sprite self.bitmap = @_iconBitmap.bitmap # Pokémon sprite bobbing while Pokémon is selected @spriteYExtra = 0 - if @selected == 1 # When choosing commands for this Pokémon - case (frameCounter / QUARTER_ANIM_PERIOD).floor + if @selected == 1 && COMMAND_BOBBING_DURATION # When choosing commands for this Pokémon + bob_delta = System.uptime % COMMAND_BOBBING_DURATION # 0-COMMAND_BOBBING_DURATION + bob_frame = (4 * bob_delta / COMMAND_BOBBING_DURATION).floor + case bob_frame when 1 then @spriteYExtra = 2 when 3 then @spriteYExtra = -2 end @@ -609,11 +626,10 @@ class Battle::Scene::BattlerSprite < RPG::Sprite self.y = self.y self.visible = @spriteVisible # Pokémon sprite blinking when targeted - if @selected == 2 && @spriteVisible - case (frameCounter / SIXTH_ANIM_PERIOD).floor - when 2, 5 then self.visible = false - else self.visible = true - end + if @selected == 2 && @spriteVisible && TARGET_BLINKING_DURATION + blink_delta = System.uptime % TARGET_BLINKING_DURATION # 0-TARGET_BLINKING_DURATION + blink_frame = (3 * blink_delta / TARGET_BLINKING_DURATION).floor + self.visible = (blink_frame != 0) end @updating = false end @@ -673,7 +689,7 @@ class Battle::Scene::BattlerShadowSprite < RPG::Sprite pbSetPosition end - def update(frameCounter = 0) + def update return if !@_iconBitmap # Update bitmap @_iconBitmap.update diff --git a/Data/Scripts/011_Battle/008_Other battle types/001_SafariBattle.rb b/Data/Scripts/011_Battle/008_Other battle types/001_SafariBattle.rb index 0a767eb68..afa6936d5 100644 --- a/Data/Scripts/011_Battle/008_Other battle types/001_SafariBattle.rb +++ b/Data/Scripts/011_Battle/008_Other battle types/001_SafariBattle.rb @@ -85,10 +85,6 @@ class Battle::Scene::SafariDataBox < Sprite textpos.push([_INTL("Left: {1}", @battle.ballCount), 30, 44, :left, base, shadow]) pbDrawTextPositions(self.bitmap, textpos) end - - def update(frameCounter = 0) - super() - end end #=============================================================================== diff --git a/Data/Scripts/012_Overworld/001_Overworld.rb b/Data/Scripts/012_Overworld/001_Overworld.rb index 5f1cf4151..73189a318 100644 --- a/Data/Scripts/012_Overworld/001_Overworld.rb +++ b/Data/Scripts/012_Overworld/001_Overworld.rb @@ -49,7 +49,6 @@ EventHandlers.add(:on_frame_update, :low_battery_warning, next if $game_temp.warned_low_battery || !pbBatteryLow? next if $game_temp.in_menu || $game_temp.in_battle || $game_player.move_route_forcing || $game_temp.message_window_showing || pbMapInterpreterRunning? - next if Time.now.sec != 0 $game_temp.warned_low_battery = true pbMessage(_INTL("The game has detected that the battery is low. You should save soon to avoid losing your progress.")) } diff --git a/Data/Scripts/013_Items/007_Item_Sprites.rb b/Data/Scripts/013_Items/007_Item_Sprites.rb index cc93a64ff..e95aa6c68 100644 --- a/Data/Scripts/013_Items/007_Item_Sprites.rb +++ b/Data/Scripts/013_Items/007_Item_Sprites.rb @@ -4,15 +4,17 @@ class ItemIconSprite < Sprite attr_reader :item - ANIM_ICON_SIZE = 48 - FRAMES_PER_CYCLE = Graphics.frame_rate + # Height in pixels the item's icon graphic must be for it to be animated by + # being a horizontal set of frames. + ANIM_ICON_SIZE = 48 + # Time in seconds for one animation cycle of this item icon. + ANIMATION_DURATION = 1.0 def initialize(x, y, item, viewport = nil) super(viewport) @animbitmap = nil - @animframe = 0 - @numframes = 1 - @frame = 0 + @frames_count = 1 + @current_frame = 0 self.x = x self.y = y @blankzero = false @@ -28,7 +30,7 @@ class ItemIconSprite < Sprite def width return 0 if !self.bitmap || self.bitmap.disposed? - return (@numframes == 1) ? self.bitmap.width : ANIM_ICON_SIZE + return (@frames_count == 1) ? self.bitmap.width : ANIM_ICON_SIZE end def height @@ -76,34 +78,32 @@ class ItemIconSprite < Sprite @animbitmap = AnimatedBitmap.new(GameData::Item.icon_filename(@item)) self.bitmap = @animbitmap.bitmap if self.bitmap.height == ANIM_ICON_SIZE - @numframes = [(self.bitmap.width / ANIM_ICON_SIZE).floor, 1].max + @frames_count = [(self.bitmap.width / ANIM_ICON_SIZE).floor, 1].max self.src_rect = Rect.new(0, 0, ANIM_ICON_SIZE, ANIM_ICON_SIZE) else - @numframes = 1 + @frames_count = 1 self.src_rect = Rect.new(0, 0, self.bitmap.width, self.bitmap.height) end - @animframe = 0 - @frame = 0 + @current_frame = 0 else self.bitmap = nil end changeOrigin end + def update_frame + @current_frame = (@frames_count * (System.uptime % ANIMATION_DURATION) / ANIMATION_DURATION).floor + end + def update @updating = true super if @animbitmap @animbitmap.update self.bitmap = @animbitmap.bitmap - if @numframes > 1 - frameskip = (FRAMES_PER_CYCLE / @numframes).floor - @frame = (@frame + 1) % FRAMES_PER_CYCLE - if @frame >= frameskip - @animframe = (@animframe + 1) % @numframes - self.src_rect.x = @animframe * ANIM_ICON_SIZE - @frame = 0 - end + if @frames_count > 1 + update_frame + self.src_rect.x = @current_frame * ANIM_ICON_SIZE end end @updating = false diff --git a/Data/Scripts/014_Pokemon/001_Pokemon-related/003_Pokemon_Sprites.rb b/Data/Scripts/014_Pokemon/001_Pokemon-related/003_Pokemon_Sprites.rb index 92ef5a813..12da4a054 100644 --- a/Data/Scripts/014_Pokemon/001_Pokemon-related/003_Pokemon_Sprites.rb +++ b/Data/Scripts/014_Pokemon/001_Pokemon-related/003_Pokemon_Sprites.rb @@ -1,5 +1,5 @@ #=============================================================================== -# Pokémon sprite (used out of battle) +# Pokémon sprite (used out of battle). #=============================================================================== class PokemonSprite < Sprite def initialize(viewport = nil) @@ -78,25 +78,29 @@ class PokemonSprite < Sprite end #=============================================================================== -# Pokémon icon (for defined Pokémon) +# Pokémon icon (for defined Pokémon). #=============================================================================== class PokemonIconSprite < Sprite attr_accessor :selected attr_accessor :active attr_reader :pokemon + # Time in seconds for one animation cycle of this Pokémon icon. It is doubled + # if the Pokémon is at 50% HP or lower, and doubled again if it is at 25% HP + # or lower. The icon doesn't animate at all if the Pokémon is fainted. + ANIMATION_DURATION = 0.25 + def initialize(pokemon, viewport = nil) super(viewport) - @selected = false - @active = false - @numFrames = 0 - @currentFrame = 0 - @counter = 0 - self.pokemon = pokemon - @logical_x = 0 # Actual x coordinate - @logical_y = 0 # Actual y coordinate - @adjusted_x = 0 # Offset due to "jumping" animation in party screen - @adjusted_y = 0 # Offset due to "jumping" animation in party screen + @selected = false + @active = false + @frames_count = 0 + @current_frame = 0 + self.pokemon = pokemon + @logical_x = 0 # Actual x coordinate + @logical_y = 0 # Actual y coordinate + @adjusted_x = 0 # Offset due to "jumping" animation in party screen + @adjusted_y = 0 # Offset due to "jumping" animation in party screen end def dispose @@ -123,16 +127,15 @@ class PokemonIconSprite < Sprite @animBitmap = nil if !@pokemon self.bitmap = nil - @currentFrame = 0 - @counter = 0 + @current_frame = 0 return end @animBitmap = AnimatedBitmap.new(GameData::Species.icon_filename_from_pokemon(value)) self.bitmap = @animBitmap.bitmap self.src_rect.width = @animBitmap.height self.src_rect.height = @animBitmap.height - @numFrames = @animBitmap.width / @animBitmap.height - @currentFrame = 0 if @currentFrame >= @numFrames + @frames_count = @animBitmap.width / @animBitmap.height + @current_frame = 0 if @current_frame >= @frames_count changeOrigin end @@ -164,20 +167,18 @@ class PokemonIconSprite < Sprite end end - # How long to show each frame of the icon for - def counterLimit - return 0 if @pokemon.fainted? # Fainted - no animation - # ret is initially the time a whole animation cycle lasts. It is divided by - # the number of frames in that cycle at the end. - ret = Graphics.frame_rate / 4 # Green HP - 0.25 seconds - if @pokemon.hp <= @pokemon.totalhp / 4 # Red HP - 1 second - ret *= 4 - elsif @pokemon.hp <= @pokemon.totalhp / 2 # Yellow HP - 0.5 seconds - ret *= 2 + def update_frame + if @pokemon.fainted? + @current_frame = 0 + return end - ret /= @numFrames - ret = 1 if ret < 1 - return ret + duration = ANIMATION_DURATION + if @pokemon.hp <= @pokemon.totalhp / 4 # Red HP - 1 second + duration *= 4 + elsif @pokemon.hp <= @pokemon.totalhp / 2 # Yellow HP - 0.5 seconds + duration *= 2 + end + @current_frame = (@frames_count * (System.uptime % duration) / duration).floor end def update @@ -186,21 +187,12 @@ class PokemonIconSprite < Sprite @animBitmap.update self.bitmap = @animBitmap.bitmap # Update animation - cl = self.counterLimit - if cl == 0 - @currentFrame = 0 - else - @counter += 1 - if @counter >= cl - @currentFrame = (@currentFrame + 1) % @numFrames - @counter = 0 - end - end - self.src_rect.x = self.src_rect.width * @currentFrame + update_frame + self.src_rect.x = self.src_rect.width * @current_frame # Update "jumping" animation (used in party screen) if @selected @adjusted_x = 4 - @adjusted_y = (@currentFrame >= @numFrames / 2) ? -2 : 6 + @adjusted_y = (@current_frame >= @frames_count / 2) ? -2 : 6 else @adjusted_x = 0 @adjusted_y = 0 @@ -211,7 +203,7 @@ class PokemonIconSprite < Sprite end #=============================================================================== -# Pokémon icon (for species) +# Pokémon icon (for species). #=============================================================================== class PokemonSpeciesIconSprite < Sprite attr_reader :species @@ -219,15 +211,17 @@ class PokemonSpeciesIconSprite < Sprite attr_reader :form attr_reader :shiny + # Time in seconds for one animation cycle of this Pokémon icon. + ANIMATION_DURATION = 0.25 + def initialize(species, viewport = nil) super(viewport) - @species = species - @gender = 0 - @form = 0 - @shiny = 0 - @numFrames = 0 - @currentFrame = 0 - @counter = 0 + @species = species + @gender = 0 + @form = 0 + @shiny = 0 + @frames_count = 0 + @current_frame = 0 refresh end @@ -292,16 +286,6 @@ class PokemonSpeciesIconSprite < Sprite end end - # How long to show each frame of the icon for - def counterLimit - # ret is initially the time a whole animation cycle lasts. It is divided by - # the number of frames in that cycle at the end. - ret = Graphics.frame_rate / 4 # 0.25 seconds - ret /= @numFrames - ret = 1 if ret < 1 - return ret - end - def refresh @animBitmap&.dispose @animBitmap = nil @@ -311,22 +295,22 @@ class PokemonSpeciesIconSprite < Sprite self.bitmap = @animBitmap.bitmap self.src_rect.width = @animBitmap.height self.src_rect.height = @animBitmap.height - @numFrames = @animBitmap.width / @animBitmap.height - @currentFrame = 0 if @currentFrame >= @numFrames + @frames_count = @animBitmap.width / @animBitmap.height + @current_frame = 0 if @current_frame >= @frames_count changeOrigin end + def update_frame + @current_frame = (@frames_count * (System.uptime % ANIMATION_DURATION) / ANIMATION_DURATION).floor + end + def update return if !@animBitmap super @animBitmap.update self.bitmap = @animBitmap.bitmap # Update animation - @counter += 1 - if @counter >= self.counterLimit - @currentFrame = (@currentFrame + 1) % @numFrames - @counter = 0 - end - self.src_rect.x = self.src_rect.width * @currentFrame + update_frame + self.src_rect.x = self.src_rect.width * @current_frame end end diff --git a/Data/Scripts/015_Trainers and player/003_Trainer_Sprites.rb b/Data/Scripts/015_Trainers and player/003_Trainer_Sprites.rb index 79c81bfb1..a02b04512 100644 --- a/Data/Scripts/015_Trainers and player/003_Trainer_Sprites.rb +++ b/Data/Scripts/015_Trainers and player/003_Trainer_Sprites.rb @@ -2,13 +2,23 @@ # Walking charset, for use in text entry screens and load game screen #=============================================================================== class TrainerWalkingCharSprite < Sprite + attr_accessor :anim_duration + + # Default time in seconds for one animation cycle of a charset. The icon for a + # storage box is 0.4 instead (set manually). + ANIMATION_DURATION = 0.5 + def initialize(charset, viewport = nil) super(viewport) @animbitmap = nil self.charset = charset - @animframe = 0 # Current pattern - @frame = 0 # Frame counter - self.animspeed = 5 # Animation speed (frames per pattern) + @current_frame = 0 # Current pattern + @anim_duration = ANIMATION_DURATION + end + + def dispose + @animbitmap&.dispose + super end def charset=(value) @@ -38,13 +48,8 @@ class TrainerWalkingCharSprite < Sprite end end - def animspeed=(value) - @frameskip = value * Graphics.frame_rate / 40 - end - - def dispose - @animbitmap&.dispose - super + def update_frame + @current_frame = (4 * (System.uptime % @anim_duration) / @anim_duration).floor end def update @@ -54,12 +59,9 @@ class TrainerWalkingCharSprite < Sprite @animbitmap.update self.bitmap = @animbitmap.bitmap end - @frame += 1 - if @frame >= @frameskip - @animframe = (@animframe + 1) % 4 - self.src_rect.x = @animframe * @animbitmap.bitmap.width / 4 - @frame -= @frameskip - end + # Update animation + update_frame + self.src_rect.x = self.src_rect.width * @current_frame @updating = false end end diff --git a/Data/Scripts/016_UI/001_Non-interactive UI/004_UI_Evolution.rb b/Data/Scripts/016_UI/001_Non-interactive UI/004_UI_Evolution.rb index bf0940432..7d1ed60ff 100644 --- a/Data/Scripts/016_UI/001_Non-interactive UI/004_UI_Evolution.rb +++ b/Data/Scripts/016_UI/001_Non-interactive UI/004_UI_Evolution.rb @@ -23,14 +23,6 @@ class SpriteMetafile FLASHDURATION = 18 BITMAP = 19 - def length - return @metafile.length - end - - def [](i) - return @metafile[i] - end - def initialize(viewport = nil) @metafile = [] @values = [ @@ -44,11 +36,19 @@ class SpriteMetafile ] end + def dispose; end + def disposed? return false end - def dispose; end + def [](i) + return @metafile[i] + end + + def length + return @metafile.length + end def flash(color, duration) if duration > 0 @@ -252,35 +252,34 @@ class SpriteMetafilePlayer end def update - if @playing - (@index...@metafile.length).each do |j| - @index = j + 1 - break if @metafile[j][0] < 0 - code = @metafile[j][0] - value = @metafile[j][1] - @sprites.each do |sprite| - case code - when SpriteMetafile::X then sprite.x = value - when SpriteMetafile::Y then sprite.y = value - when SpriteMetafile::OX then sprite.ox = value - when SpriteMetafile::OY then sprite.oy = value - when SpriteMetafile::ZOOM_X then sprite.zoom_x = value - when SpriteMetafile::ZOOM_Y then sprite.zoom_y = value - when SpriteMetafile::SRC_RECT then sprite.src_rect = value - when SpriteMetafile::VISIBLE then sprite.visible = value - when SpriteMetafile::Z then sprite.z = value # prevent crashes - when SpriteMetafile::ANGLE then sprite.angle = (value == 180) ? 179.9 : value - when SpriteMetafile::MIRROR then sprite.mirror = value - when SpriteMetafile::BUSH_DEPTH then sprite.bush_depth = value - when SpriteMetafile::OPACITY then sprite.opacity = value - when SpriteMetafile::BLEND_TYPE then sprite.blend_type = value - when SpriteMetafile::COLOR then sprite.color = value - when SpriteMetafile::TONE then sprite.tone = value - end + return if !@playing + (@index...@metafile.length).each do |j| + @index = j + 1 + break if @metafile[j][0] < 0 + code = @metafile[j][0] + value = @metafile[j][1] + @sprites.each do |sprite| + case code + when SpriteMetafile::X then sprite.x = value + when SpriteMetafile::Y then sprite.y = value + when SpriteMetafile::OX then sprite.ox = value + when SpriteMetafile::OY then sprite.oy = value + when SpriteMetafile::ZOOM_X then sprite.zoom_x = value + when SpriteMetafile::ZOOM_Y then sprite.zoom_y = value + when SpriteMetafile::SRC_RECT then sprite.src_rect = value + when SpriteMetafile::VISIBLE then sprite.visible = value + when SpriteMetafile::Z then sprite.z = value # prevent crashes + when SpriteMetafile::ANGLE then sprite.angle = (value == 180) ? 179.9 : value + when SpriteMetafile::MIRROR then sprite.mirror = value + when SpriteMetafile::BUSH_DEPTH then sprite.bush_depth = value + when SpriteMetafile::OPACITY then sprite.opacity = value + when SpriteMetafile::BLEND_TYPE then sprite.blend_type = value + when SpriteMetafile::COLOR then sprite.color = value + when SpriteMetafile::TONE then sprite.tone = value end end - @playing = false if @index == @metafile.length end + @playing = false if @index == @metafile.length end end @@ -420,36 +419,29 @@ class PokemonEvolutionScene end end - def pbUpdateNarrowScreen - halfResizeDiff = 8 * 20 / Graphics.frame_rate - if @bgviewport.rect.y < 80 - @bgviewport.rect.height -= halfResizeDiff * 2 - if @bgviewport.rect.height < Graphics.height - 64 - @bgviewport.rect.y += halfResizeDiff - @sprites["background"].oy = @bgviewport.rect.y - end - end + def pbUpdateNarrowScreen(timer_start) + return if @bgviewport.rect.y >= 80 + buffer = 80 + @bgviewport.rect.height = Graphics.height - lerp(0, 64 + (buffer * 2), 0.7, timer_start, System.uptime).to_i + @bgviewport.rect.y = lerp(0, buffer, 0.5, timer_start + 0.2, System.uptime).to_i + @sprites["background"].oy = @bgviewport.rect.y end - def pbUpdateExpandScreen - halfResizeDiff = 8 * 20 / Graphics.frame_rate - if @bgviewport.rect.y > 0 - @bgviewport.rect.y -= halfResizeDiff - @sprites["background"].oy = @bgviewport.rect.y - end - if @bgviewport.rect.height < Graphics.height - @bgviewport.rect.height += halfResizeDiff * 2 - end + def pbUpdateExpandScreen(timer_start) + return if @bgviewport.rect.height >= Graphics.height + buffer = 80 + @bgviewport.rect.height = Graphics.height - lerp(64 + (buffer * 2), 0, 0.7, timer_start, System.uptime).to_i + @bgviewport.rect.y = lerp(buffer, 0, 0.5, timer_start, System.uptime).to_i + @sprites["background"].oy = @bgviewport.rect.y end def pbFlashInOut(canceled, oldstate, oldstate2) - tone = 0 - toneDiff = 20 * 20 / Graphics.frame_rate + timer_start = System.uptime loop do Graphics.update pbUpdate(true) - pbUpdateExpandScreen - tone += toneDiff + pbUpdateExpandScreen(timer_start) + tone = lerp(0, 255, 0.7, timer_start, System.uptime) @viewport.tone.set(tone, tone, tone, 0) break if tone >= 255 end @@ -471,16 +463,18 @@ class PokemonEvolutionScene @sprites["rsprite2"].zoom_y = 1.0 @sprites["rsprite2"].color.alpha = 0 end - (Graphics.frame_rate / 4).times do + timer_start = System.uptime + loop do Graphics.update pbUpdate(true) + break if System.uptime - timer_start >= 0.25 end - tone = 255 - toneDiff = 40 * 20 / Graphics.frame_rate + timer_start = System.uptime loop do Graphics.update pbUpdate - tone -= toneDiff + pbUpdateExpandScreen(timer_start) + tone = lerp(255, 0, 0.4, timer_start, System.uptime) @viewport.tone.set(tone, tone, tone, 0) break if tone <= 0 end @@ -551,8 +545,9 @@ class PokemonEvolutionScene pbMEPlay("Evolution start") pbBGMPlay("Evolution") canceled = false + timer_start = System.uptime loop do - pbUpdateNarrowScreen + pbUpdateNarrowScreen(timer_start) metaplayer1.update metaplayer2.update Graphics.update @@ -579,11 +574,13 @@ class PokemonEvolutionScene def pbEvolutionSuccess $stats.evolution_count += 1 # Play cry of evolved species - frames = (GameData::Species.cry_length(@newspecies, @pokemon.form) * Graphics.frame_rate).ceil + cry_time = GameData::Species.cry_length(@newspecies, @pokemon.form) Pokemon.play_cry(@newspecies, @pokemon.form) - (frames + 4).times do + timer_start = System.uptime + loop do Graphics.update pbUpdate + break if System.uptime - timer_start >= cry_time end pbBGMStop # Success jingle/message diff --git a/Data/Scripts/016_UI/013_UI_Load.rb b/Data/Scripts/016_UI/013_UI_Load.rb index 929b01c35..7ec3ebae8 100644 --- a/Data/Scripts/016_UI/013_UI_Load.rb +++ b/Data/Scripts/016_UI/013_UI_Load.rb @@ -17,7 +17,7 @@ class PokemonLoadPanel < Sprite @title = title @isContinue = isContinue @trainer = trainer - @totalsec = stats.play_time.to_i + @totalsec = stats&.play_time.to_i || 0 @mapid = mapid @selected = (index == 0) @bgbitmap = AnimatedBitmap.new("Graphics/UI/Load/panels") diff --git a/Data/Scripts/016_UI/017_UI_PokemonStorage.rb b/Data/Scripts/016_UI/017_UI_PokemonStorage.rb index 1dabe2a5d..d3ef4b291 100644 --- a/Data/Scripts/016_UI/017_UI_PokemonStorage.rb +++ b/Data/Scripts/016_UI/017_UI_PokemonStorage.rb @@ -5,7 +5,7 @@ class PokemonBoxIcon < IconSprite def initialize(pokemon, viewport = nil) super(0, 0, viewport) @pokemon = pokemon - @release = Interpolator.new + @release = SpriteInterpolator.new @startRelease = false refresh end @@ -20,9 +20,9 @@ class PokemonBoxIcon < IconSprite self.x += self.src_rect.width / 2 # 32 self.y += self.src_rect.height / 2 # 32 @release.tween(self, - [[Interpolator::ZOOM_X, 0], - [Interpolator::ZOOM_Y, 0], - [Interpolator::OPACITY, 0]], + [[SpriteInterpolator::ZOOM_X, 0], + [SpriteInterpolator::ZOOM_Y, 0], + [SpriteInterpolator::OPACITY, 0]], 100) @startRelease = true end @@ -969,34 +969,32 @@ class PokemonStorageScene end def pbChangeBackground(wp) + duration = 0.2 # Time in seconds to fade out or fade in @sprites["box"].refreshSprites = false - alpha = 0 Graphics.update self.update - timeTaken = Graphics.frame_rate * 4 / 10 - alphaDiff = (255.0 / timeTaken).ceil - timeTaken.times do - alpha += alphaDiff - Graphics.update - Input.update + # Fade old background to white + timer_start = System.uptime + loop do + alpha = lerp(0, 255, duration, timer_start, System.uptime) @sprites["box"].color = Color.new(248, 248, 248, alpha) + Graphics.update self.update + break if alpha >= 255 end + # Fade in new background from white @sprites["box"].refreshBox = true @storage[@storage.currentBox].background = wp - (Graphics.frame_rate / 10).times do - Graphics.update - Input.update - self.update - end - timeTaken.times do - alpha -= alphaDiff - Graphics.update - Input.update + timer_start = System.uptime + loop do + alpha = lerp(255, 0, duration, timer_start, System.uptime) @sprites["box"].color = Color.new(248, 248, 248, alpha) + Graphics.update self.update + break if alpha <= 0 end @sprites["box"].refreshSprites = true + Input.update end def pbSwitchBoxToRight(newbox) diff --git a/Data/Scripts/016_UI/025_UI_TextEntry.rb b/Data/Scripts/016_UI/025_UI_TextEntry.rb index 908da2b5e..d0b05d741 100644 --- a/Data/Scripts/016_UI/025_UI_TextEntry.rb +++ b/Data/Scripts/016_UI/025_UI_TextEntry.rb @@ -168,7 +168,7 @@ class PokemonEntryScene when 4 # Storage box @sprites["subject"] = TrainerWalkingCharSprite.new(nil, @viewport) @sprites["subject"].altcharset = "Graphics/UI/Naming/icon_storage" - @sprites["subject"].animspeed = 4 + @sprites["subject"].anim_duration = 0.4 charwidth = @sprites["subject"].bitmap.width charheight = @sprites["subject"].bitmap.height @sprites["subject"].x = 88 - (charwidth / 8) @@ -449,7 +449,7 @@ class PokemonEntryScene2 when 4 # Storage box @sprites["subject"] = TrainerWalkingCharSprite.new(nil, @viewport) @sprites["subject"].altcharset = "Graphics/UI/Naming/icon_storage" - @sprites["subject"].animspeed = 4 + @sprites["subject"].anim_duration = 0.4 charwidth = @sprites["subject"].bitmap.width charheight = @sprites["subject"].bitmap.height @sprites["subject"].x = 88 - (charwidth / 8) diff --git a/Data/Scripts/017_Minigames/003_Minigame_SlotMachine.rb b/Data/Scripts/017_Minigames/003_Minigame_SlotMachine.rb index 0f04c2e6e..888e6ffc6 100644 --- a/Data/Scripts/017_Minigames/003_Minigame_SlotMachine.rb +++ b/Data/Scripts/017_Minigames/003_Minigame_SlotMachine.rb @@ -169,7 +169,6 @@ class SlotMachineScene end end @sprites["payout"].score = payout - frame = 0 if payout > 0 || @replay if bonus > 0 pbMEPlay("Slots big win") @@ -177,30 +176,31 @@ class SlotMachineScene pbMEPlay("Slots win") end # Show winning animation - timePerFrame = Graphics.frame_rate / 8 - until frame == Graphics.frame_rate * 3 - Graphics.update - Input.update - update + timer_start = System.uptime + loop do + frame = ((System.uptime - timer_start) / 0.125).to_i @sprites["window2"].bitmap&.clear @sprites["window1"].setBitmap("Graphics/UI/Slot Machine/win") - @sprites["window1"].src_rect.set(152 * ((frame / timePerFrame) % 4), 0, 152, 208) + @sprites["window1"].src_rect.set(152 * (frame % 4), 0, 152, 208) if bonus > 0 @sprites["window2"].setBitmap("Graphics/UI/Slot Machine/bonus") @sprites["window2"].src_rect.set(152 * (bonus - 1), 0, 152, 208) end @sprites["light1"].visible = true - @sprites["light1"].src_rect.set(0, 26 * ((frame / timePerFrame) % 4), 96, 26) + @sprites["light1"].src_rect.set(0, 26 * (frame % 4), 96, 26) @sprites["light2"].visible = true - @sprites["light2"].src_rect.set(0, 26 * ((frame / timePerFrame) % 4), 96, 26) + @sprites["light2"].src_rect.set(0, 26 * (frame % 4), 96, 26) (1..5).each do |i| if wonRow[i - 1] - @sprites["row#{i}"].visible = (frame / timePerFrame).even? + @sprites["row#{i}"].visible = frame.even? else @sprites["row#{i}"].visible = false end end - frame += 1 + Graphics.update + Input.update + update + break if System.uptime - timer_start >= 3.0 end @sprites["light1"].visible = false @sprites["light2"].visible = false @@ -218,22 +218,25 @@ class SlotMachineScene @sprites["payout"].score = 0 end end - (Graphics.frame_rate / 2).times do + timer_start = System.uptime + loop do Graphics.update Input.update update + break if System.uptime - timer_start >= 0.5 end else # Show losing animation - timePerFrame = Graphics.frame_rate / 4 - until frame == Graphics.frame_rate * 2 + timer_start = System.uptime + loop do + frame = ((System.uptime - timer_start) / 0.25).to_i + @sprites["window2"].bitmap&.clear + @sprites["window1"].setBitmap("Graphics/UI/Slot Machine/lose") + @sprites["window1"].src_rect.set(152 * (frame % 2), 0, 152, 208) Graphics.update Input.update update - @sprites["window2"].bitmap&.clear - @sprites["window1"].setBitmap("Graphics/UI/Slot Machine/lose") - @sprites["window1"].src_rect.set(152 * ((frame / timePerFrame) % 2), 0, 152, 208) - frame += 1 + break if System.uptime - timer_start >= 2.0 end end @wager = 0 @@ -278,9 +281,6 @@ class SlotMachineScene end def pbMain - frame = 0 - spinFrameTime = Graphics.frame_rate / 4 - insertFrameTime = Graphics.frame_rate * 4 / 10 loop do Graphics.update Input.update @@ -295,23 +295,31 @@ class SlotMachineScene break elsif @gameRunning # Reels are spinning @sprites["window1"].setBitmap("Graphics/UI/Slot Machine/stop") - @sprites["window1"].src_rect.set(152 * ((frame / spinFrameTime) % 4), 0, 152, 208) - if Input.trigger?(Input::USE) - pbSEPlay("Slots stop") - if @sprites["reel1"].spinning - @sprites["reel1"].stopSpinning(@replay) - @sprites["button1"].visible = true - elsif @sprites["reel2"].spinning - @sprites["reel2"].stopSpinning(@replay) - @sprites["button2"].visible = true - elsif @sprites["reel3"].spinning - @sprites["reel3"].stopSpinning(@replay) - @sprites["button3"].visible = true + timer_start = System.uptime + loop do + frame = ((System.uptime - timer_start) / 0.25).to_i + @sprites["window1"].src_rect.set(152 * (frame % 4), 0, 152, 208) + Graphics.update + Input.update + update + if Input.trigger?(Input::USE) + pbSEPlay("Slots stop") + if @sprites["reel1"].spinning + @sprites["reel1"].stopSpinning(@replay) + @sprites["button1"].visible = true + elsif @sprites["reel2"].spinning + @sprites["reel2"].stopSpinning(@replay) + @sprites["button2"].visible = true + elsif @sprites["reel3"].spinning + @sprites["reel3"].stopSpinning(@replay) + @sprites["button3"].visible = true + end end - end - if !@sprites["reel3"].spinning - @gameEnd = true - @gameRunning = false + if !@sprites["reel3"].spinning + @gameEnd = true + @gameRunning = false + end + break if !@gameRunning end elsif @gameEnd # Reels have been stopped pbPayout @@ -325,42 +333,47 @@ class SlotMachineScene @gameEnd = false else # Awaiting coins for the next spin @sprites["window1"].setBitmap("Graphics/UI/Slot Machine/insert") - @sprites["window1"].src_rect.set(152 * ((frame / insertFrameTime) % 2), 0, 152, 208) - if @wager > 0 - @sprites["window2"].setBitmap("Graphics/UI/Slot Machine/press") - @sprites["window2"].src_rect.set(152 * ((frame / insertFrameTime) % 2), 0, 152, 208) - end - if Input.trigger?(Input::DOWN) && @wager < 3 && @sprites["credit"].score > 0 - pbSEPlay("Slots coin") - @wager += 1 - @sprites["credit"].score -= 1 - if @wager >= 3 - @sprites["row5"].visible = true - @sprites["row4"].visible = true - elsif @wager >= 2 - @sprites["row3"].visible = true - @sprites["row2"].visible = true - elsif @wager >= 1 - @sprites["row1"].visible = true + timer_start = System.uptime + loop do + frame = ((System.uptime - timer_start) / 0.4).to_i + @sprites["window1"].src_rect.set(152 * (frame % 2), 0, 152, 208) + if @wager > 0 + @sprites["window2"].setBitmap("Graphics/UI/Slot Machine/press") + @sprites["window2"].src_rect.set(152 * (frame % 2), 0, 152, 208) end - elsif @wager >= 3 || (@wager > 0 && @sprites["credit"].score == 0) || - (Input.trigger?(Input::USE) && @wager > 0) || @replay - if @replay - @wager = 3 - (1..5).each do |i| - @sprites["row#{i}"].visible = true + Graphics.update + Input.update + update + if Input.trigger?(Input::DOWN) && @wager < 3 && @sprites["credit"].score > 0 + pbSEPlay("Slots coin") + @wager += 1 + @sprites["credit"].score -= 1 + if @wager >= 3 + @sprites["row5"].visible = true + @sprites["row4"].visible = true + elsif @wager >= 2 + @sprites["row3"].visible = true + @sprites["row2"].visible = true + elsif @wager >= 1 + @sprites["row1"].visible = true end + elsif @wager >= 3 || (@wager > 0 && @sprites["credit"].score == 0) || + (Input.trigger?(Input::USE) && @wager > 0) || @replay + if @replay + @wager = 3 + (1..5).each { |i| @sprites["row#{i}"].visible = true } + end + @sprites["reel1"].startSpinning + @sprites["reel2"].startSpinning + @sprites["reel3"].startSpinning + @gameRunning = true + elsif Input.trigger?(Input::BACK) && @wager == 0 + break end - @sprites["reel1"].startSpinning - @sprites["reel2"].startSpinning - @sprites["reel3"].startSpinning - frame = 0 - @gameRunning = true - elsif Input.trigger?(Input::BACK) && @wager == 0 - break + break if @gameRunning end + break if !@gameRunning end - frame = (frame + 1) % (Graphics.frame_rate * 4) end old_coins = $player.coins $player.coins = @sprites["credit"].score diff --git a/Data/Scripts/017_Minigames/004_Minigame_VoltorbFlip.rb b/Data/Scripts/017_Minigames/004_Minigame_VoltorbFlip.rb index 242b4e5a3..97909d8d6 100644 --- a/Data/Scripts/017_Minigames/004_Minigame_VoltorbFlip.rb +++ b/Data/Scripts/017_Minigames/004_Minigame_VoltorbFlip.rb @@ -94,10 +94,11 @@ class VoltorbFlip pbUpdateCoins # Draw curtain effect if @firstRound - angleDiff = 10 * 20 / Graphics.frame_rate + curtain_duration = 0.5 + timer_start = System.uptime loop do - @sprites["curtainL"].angle -= angleDiff - @sprites["curtainR"].angle += angleDiff + @sprites["curtainL"].angle = lerp(-90, -180, curtain_duration, timer_start, System.uptime) + @sprites["curtainR"].angle = lerp(0, 90, curtain_duration, timer_start, System.uptime) Graphics.update Input.update update @@ -535,9 +536,9 @@ class VoltorbFlip @sprites["cursor"].bitmap.clear end -# def pbWaitText(msg,frames) -# msgwindow=pbCreateMessageWindow -# pbMessageDisplay(msgwindow,msg) +# def pbWaitText(msg, frames) +# msgwindow = pbCreateMessageWindow +# pbMessageDisplay(msgwindow, msg) # pbWait(frames / 20.0) # pbDisposeMessageWindow(msgwindow) # end @@ -548,12 +549,11 @@ class VoltorbFlip # Draw curtain effect @sprites["curtainL"].visible = true @sprites["curtainR"].visible = true - angleDiff = 18 * 20 / Graphics.frame_rate + curtain_duration = 0.25 + timer_start = System.uptime loop do - @sprites["curtainL"].angle += angleDiff - @sprites["curtainR"].angle -= angleDiff - # Fixes a minor graphical bug - @sprites["curtainL"].y -= 2 if @sprites["curtainL"].angle >= -90 + @sprites["curtainL"].angle = lerp(-180, -90, curtain_duration, timer_start, System.uptime) + @sprites["curtainR"].angle = lerp(90, 0, curtain_duration, timer_start, System.uptime) Graphics.update Input.update update diff --git a/Data/Scripts/017_Minigames/006_Minigame_Mining.rb b/Data/Scripts/017_Minigames/006_Minigame_Mining.rb index 8355a9261..073dce933 100644 --- a/Data/Scripts/017_Minigames/006_Minigame_Mining.rb +++ b/Data/Scripts/017_Minigames/006_Minigame_Mining.rb @@ -489,23 +489,26 @@ class MiningGameScene def pbFlashItems(revealed) return if revealed.length <= 0 revealeditems = BitmapSprite.new(Graphics.width, Graphics.height, @viewport) - halfFlashTime = Graphics.frame_rate / 8 - alphaDiff = (255.0 / halfFlashTime).ceil - (1..halfFlashTime * 2).each do |i| - revealed.each do |index| - burieditem = @items[index] - revealeditems.bitmap.blt(32 * burieditem[1], 64 + (32 * burieditem[2]), - @itembitmap.bitmap, - Rect.new(32 * ITEMS[burieditem[0]][2], 32 * ITEMS[burieditem[0]][3], - 32 * ITEMS[burieditem[0]][4], 32 * ITEMS[burieditem[0]][5])) - if i > halfFlashTime - revealeditems.color = Color.new(255, 255, 255, ((halfFlashTime * 2) - i) * alphaDiff) - else - revealeditems.color = Color.new(255, 255, 255, i * alphaDiff) + revealeditems.color = Color.new(255, 255, 255, 0) + flash_duration = 0.25 + 2.times do |i| + alpha_start = (i == 0) ? 0 : 255 + alpha_end = (i == 0) ? 255 : 0 + timer_start = System.uptime + loop do + revealed.each do |index| + burieditem = @items[index] + revealeditems.bitmap.blt(32 * burieditem[1], 64 + (32 * burieditem[2]), + @itembitmap.bitmap, + Rect.new(32 * ITEMS[burieditem[0]][2], 32 * ITEMS[burieditem[0]][3], + 32 * ITEMS[burieditem[0]][4], 32 * ITEMS[burieditem[0]][5])) end + flash_alpha = lerp(alpha_start, alpha_end, flash_duration / 2, timer_start, System.uptime) + revealeditems.color.alpha = flash_alpha + update + Graphics.update + break if flash_alpha == alpha_end end - update - Graphics.update end revealeditems.dispose revealed.each do |index|