diff --git a/Data/Scripts/001_Settings.rb b/Data/Scripts/001_Settings.rb index fe813737a..ddb373467 100644 --- a/Data/Scripts/001_Settings.rb +++ b/Data/Scripts/001_Settings.rb @@ -1,6 +1,6 @@ #==============================================================================# # Pokémon Essentials # -# Version 18 # +# Version 18.1 # #==============================================================================# #=============================================================================== diff --git a/Data/Scripts/001_Technical/005_Win32API.rb b/Data/Scripts/001_Technical/005_Win32API.rb index 706ec6e54..21fc9318f 100644 --- a/Data/Scripts/001_Technical/005_Win32API.rb +++ b/Data/Scripts/001_Technical/005_Win32API.rb @@ -100,5 +100,5 @@ end # Well done for finding this place. # DO NOT EDIT THESE -ESSENTIALS_VERSION = "18" +ESSENTIALS_VERSION = "18.1.dev" ERROR_TEXT = "" diff --git a/Data/Scripts/001_Technical/007_DebugConsole.rb b/Data/Scripts/001_Technical/007_DebugConsole.rb index 0c20df963..6a608ea38 100644 --- a/Data/Scripts/001_Technical/007_DebugConsole.rb +++ b/Data/Scripts/001_Technical/007_DebugConsole.rb @@ -48,6 +48,7 @@ module Console @apiSetConsoleTitle = Win32API.new("kernel32","SetConsoleTitle","p","s") access = (GENERIC_READ | GENERIC_WRITE) sharemode = (FILE_SHARE_READ | FILE_SHARE_WRITE) + AllocConsole() @bufferHandle = CreateConsoleScreenBuffer(access,sharemode,CONSOLE_TEXTMODE_BUFFER) f = File.open("Game.ini") lines = f.readlines() diff --git a/Data/Scripts/003_Game classes/005_Game_Character.rb b/Data/Scripts/003_Game classes/005_Game_Character.rb index 8b895a858..6221b5b61 100644 --- a/Data/Scripts/003_Game classes/005_Game_Character.rb +++ b/Data/Scripts/003_Game classes/005_Game_Character.rb @@ -33,7 +33,7 @@ class Game_Character @y = 0 @real_x = 0 @real_y = 0 - @sprite_size = [Game_Map::TILE_WIDTH,Game_Map::TILE_HEIGHT] + @sprite_size = [Game_Map::TILE_WIDTH, Game_Map::TILE_HEIGHT] @tile_id = 0 @character_name = "" @character_hue = 0 @@ -50,7 +50,7 @@ class Game_Character @original_direction = 2 @original_pattern = 0 @move_type = 0 - self.move_speed = 4 + self.move_speed = 3 self.move_frequency = 6 @move_route = nil @move_route_index = 0 @@ -62,8 +62,10 @@ class Game_Character @always_on_top = false @anime_count = 0 @stop_count = 0 - @jump_count = 0 - @jump_peak = 0 + @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 @bob_height = 0 @wait_count = 0 @moved_this_frame = false @@ -77,13 +79,13 @@ class Game_Character # @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 => 1.6 # 80 frames per tile - # 2 => 3.2 # 40 frames per tile - # 3 => 6.4 # 20 frames per tile - # 4 => 12.8 # 10 frames per tile - walking speed - # 5 => 25.6 # 5 frames per tile - running speed (2x walking speed) - # 6 => 32 # 4 frames per tile - cycling speed (1.25x running speed) - self.move_speed_real = (val == 6) ? 32 : (1 << val) * 0.8 + # 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 end def move_speed_real @@ -95,6 +97,10 @@ class Game_Character @move_speed_real = val * 40.0 / Graphics.frame_rate end + def jump_speed_real + return (2 ** (3 + 1)) * 0.8 * 40.0 / Graphics.frame_rate # Walking speed + end + def move_frequency=(val) return if val==@move_frequency @move_frequency = val @@ -160,7 +166,7 @@ class Game_Character end def bush_depth - return 0 if @tile_id > 0 or @always_on_top or @jump_count > 0 + return 0 if @tile_id > 0 || @always_on_top or jumping? xbehind = @x + (@direction==4 ? 1 : @direction==6 ? -1 : 0) ybehind = @y + (@direction==8 ? 1 : @direction==2 ? -1 : 0) return Game_Map::TILE_HEIGHT if self.map.deepBush?(@x, @y) and self.map.deepBush?(xbehind, ybehind) @@ -219,8 +225,12 @@ class Game_Character def screen_y ret = screen_y_ground if jumping? - n = ((2 * @jump_count * 20 / Graphics.frame_rate) - @jump_peak).abs - return ret - (@jump_peak * @jump_peak - n * n) / 2 + 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) end return ret end @@ -248,7 +258,7 @@ class Game_Character end def jumping? - return @jump_count > 0 + return (@jump_distance_left || 0) > 0 || @jump_count > 0 end def straighten @@ -422,48 +432,34 @@ class Game_Character end end - def move_up(turn_enabled = true) - turn_up if turn_enabled - if passable?(@x, @y, 8) - turn_up - @y -= 1 + def move_generic(dir, turn_enabled = true) + turn_generic(dir) if turn_enabled + x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0 + y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0 + if passable?(@x, @y, dir) + turn_generic(dir) + @x += x_offset + @y += y_offset increase_steps else - check_event_trigger_touch(@x, @y-1) + check_event_trigger_touch(@x + x_offset, @y + y_offset) end end def move_down(turn_enabled = true) - turn_down if turn_enabled - if passable?(@x, @y, 2) - turn_down - @y += 1 - increase_steps - else - check_event_trigger_touch(@x, @y+1) - end + move_generic(2, turn_enabled) end def move_left(turn_enabled = true) - turn_left if turn_enabled - if passable?(@x, @y, 4) - turn_left - @x -= 1 - increase_steps - else - check_event_trigger_touch(@x-1, @y) - end + move_generic(4, turn_enabled) end def move_right(turn_enabled = true) - turn_right if turn_enabled - if passable?(@x, @y, 6) - turn_right - @x += 1 - increase_steps - else - check_event_trigger_touch(@x+1, @y) - end + move_generic(6, turn_enabled) + end + + def move_up(turn_enabled = true) + move_generic(8, turn_enabled) end def move_upper_left @@ -648,12 +644,18 @@ class Game_Character new_x = @x + x_plus new_y = @y + y_plus if (x_plus == 0 and y_plus == 0) || passable?(new_x, new_y, 0) - straighten @x = new_x @y = new_y - distance = [4, x_plus * x_plus + y_plus * y_plus].max - @jump_peak = (6 + distance - move_speed).floor - @jump_count = @jump_peak * Graphics.frame_rate / 20 + real_distance = Math::sqrt(x_plus * x_plus + y_plus * y_plus) + 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_count = Game_Map::REAL_RES_X / jump_speed_real # Number of frames to jump one tile + end @stop_count = 0 if self.is_a?(Game_Player) $PokemonTemp.dependentEvents.pbMoveDependentEvents @@ -680,7 +682,7 @@ class Game_Character end end - def turnGeneric(dir) + def turn_generic(dir) return if @direction_fix oldDirection = @direction @direction = dir @@ -688,10 +690,10 @@ class Game_Character pbCheckEventTriggerAfterTurning if dir != oldDirection end - def turn_up; turnGeneric(8); end - def turn_down; turnGeneric(2); end - def turn_left; turnGeneric(4); end - def turn_right; turnGeneric(6); end + def turn_down; turn_generic(2); end + def turn_left; turn_generic(4); end + def turn_right; turn_generic(6); end + def turn_up; turn_generic(8); end def turn_right_90 case @direction @@ -764,10 +766,7 @@ class Game_Character # Update command update_command # Update movement - if jumping?; update_jump - elsif moving?; update_move - else; update_stop - end + (moving? || jumping?) ? update_move : update_stop end # Update animation update_pattern @@ -801,18 +800,9 @@ class Game_Character end end - def update_jump - @jump_count -= 1 - @real_x = (@real_x * @jump_count + @x * Game_Map::REAL_RES_X) / (@jump_count + 1) - @real_y = (@real_y * @jump_count + @y * Game_Map::REAL_RES_Y) / (@jump_count + 1) - @moved_this_frame = true - # End of a jump, so perform events that happen at this time - Events.onStepTakenFieldMovement.trigger(self,self) if !jumping? && !moving? - end - def update_move # Move the character (the 0.1 catches rounding errors) - distance = move_speed_real + 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 @@ -829,8 +819,13 @@ class Game_Character @real_y -= distance @real_y = dest_y if @real_y < dest_y + 0.1 end + # Refresh how far is left to travel in a jump + if 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 # End of a step, so perform events that happen at this time - Events.onStepTakenFieldMovement.trigger(self,self) if !jumping? && !moving? + Events.onStepTakenFieldMovement.trigger(self, self) if !jumping? && !moving? # Increment animation counter @anime_count += 1 if @walk_anime || @step_anime @moved_this_frame = true @@ -844,6 +839,7 @@ class Game_Character def update_pattern return if @lock_pattern +# return if @jump_count > 0 # 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 @@ -851,7 +847,7 @@ class Game_Character return end # Character has started to move, change pattern immediately - if !@moved_last_frame && @moved_this_frame && !jumping? && !@step_anime + if !@moved_last_frame && @moved_this_frame && !@step_anime @pattern = (@pattern + 1) % 4 if @walk_anime @anime_count = 0 return @@ -859,7 +855,8 @@ 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. - frames_per_pattern = Game_Map::REAL_RES_X / (move_speed_real * 2.0) + 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 == 6 # Cycling/fastest speed return if @anime_count < frames_per_pattern # Advance to the next animation frame diff --git a/Data/Scripts/003_Game classes/007_Game_Player.rb b/Data/Scripts/003_Game classes/007_Game_Player.rb index c1e50de57..fc211ff48 100644 --- a/Data/Scripts/003_Game classes/007_Game_Player.rb +++ b/Data/Scripts/003_Game classes/007_Game_Player.rb @@ -23,7 +23,7 @@ class Game_Player < Game_Character end def bush_depth - return 0 if @tile_id > 0 or @always_on_top + return 0 if @tile_id > 0 || @always_on_top xbehind = (@direction==4) ? @x+1 : (@direction==6) ? @x-1 : @x ybehind = (@direction==8) ? @y+1 : (@direction==2) ? @y-1 : @y # Both current tile and previous tile are on the same map; just return super @@ -47,7 +47,7 @@ class Game_Player < Game_Character behindmap = newbehind[0]; behindx = newbehind[1]; behindy = newbehind[2] end # Return bush depth - if @jump_count <= 0 + if !jumping? return 32 if heremap.deepBush?(herex, herey) && behindmap.deepBush?(behindx, behindy) return 12 if heremap.bush?(herex, herey) && !moving? end @@ -64,67 +64,36 @@ class Game_Player < Game_Character @bump_se = Graphics.frame_rate/4 end - def move_down(turn_enabled = true) - turn_down if turn_enabled - if passable?(@x, @y, 2) - return if pbLedge(0,1) - return if pbEndSurf(0,1) - turn_down - @y += 1 - $PokemonTemp.dependentEvents.pbMoveDependentEvents - increase_steps - else - if !check_event_trigger_touch(@x, @y+1) - bump_into_object + def move_generic(dir, turn_enabled = true) + turn_generic(dir, true) if turn_enabled + if !$PokemonTemp.encounterTriggered + x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0 + y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0 + if passable?(@x, @y, dir) + return if pbLedge(x_offset, y_offset) + return if pbEndSurf(x_offset, y_offset) + turn_generic(dir, true) + if !$PokemonTemp.encounterTriggered + @x += x_offset + @y += y_offset + $PokemonTemp.dependentEvents.pbMoveDependentEvents + increase_steps + end + else + if !check_event_trigger_touch(@x + x_offset, @y + y_offset) + bump_into_object + end end end + $PokemonTemp.encounterTriggered = false end - def move_left(turn_enabled = true) - turn_left if turn_enabled - if passable?(@x, @y, 4) - return if pbLedge(-1,0) - return if pbEndSurf(-1,0) - turn_left - @x -= 1 - $PokemonTemp.dependentEvents.pbMoveDependentEvents - increase_steps - else - if !check_event_trigger_touch(@x-1, @y) - bump_into_object - end - end - end - - def move_right(turn_enabled = true) - turn_right if turn_enabled - if passable?(@x, @y, 6) - return if pbLedge(1,0) - return if pbEndSurf(1,0) - turn_right - @x += 1 - $PokemonTemp.dependentEvents.pbMoveDependentEvents - increase_steps - else - if !check_event_trigger_touch(@x+1, @y) - bump_into_object - end - end - end - - def move_up(turn_enabled = true) - turn_up if turn_enabled - if passable?(@x, @y, 8) - return if pbLedge(0,-1) - return if pbEndSurf(0,-1) - turn_up - @y -= 1 - $PokemonTemp.dependentEvents.pbMoveDependentEvents - increase_steps - else - if !check_event_trigger_touch(@x, @y-1) - bump_into_object - end + def turn_generic(dir, keep_enc_indicator = false) + old_direction = @direction + super(dir) + if @direction != old_direction && !@move_route_forcing && !pbMapInterpreterRunning? + Events.onChangeDirection.trigger(self, self) + $PokemonTemp.encounterTriggered = false if !keep_enc_indicator end end @@ -162,8 +131,7 @@ class Game_Player < Game_Character return result end - def pbCheckEventTriggerAfterTurning - end + def pbCheckEventTriggerAfterTurning; end def pbCheckEventTriggerFromDistance(triggers) ret = pbTriggeredTrainerEvents(triggers) @@ -377,17 +345,18 @@ class Game_Player < Game_Character def update_command_new dir = Input.dir4 - unless pbMapInterpreterRunning? or $game_temp.message_window_showing or - $PokemonTemp.miniupdate or $game_temp.in_menu + unless pbMapInterpreterRunning? || $game_temp.message_window_showing || + $PokemonTemp.miniupdate || $game_temp.in_menu # Move player in the direction the directional button is being pressed - if dir==@lastdir && Graphics.frame_count-@lastdirframe>Graphics.frame_rate/20 + if @moved_last_frame || + (dir > 0 && dir == @lastdir && Graphics.frame_count - @lastdirframe > Graphics.frame_rate / 20) case dir when 2; move_down when 4; move_left when 6; move_right when 8; move_up end - elsif dir!=@lastdir + elsif dir != @lastdir case dir when 2; turn_down when 4; turn_left @@ -397,7 +366,7 @@ class Game_Player < Game_Character end end # Record last direction input - @lastdirframe = Graphics.frame_count if dir!=@lastdir + @lastdirframe = Graphics.frame_count if dir != @lastdir @lastdir = dir end diff --git a/Data/Scripts/003_Game classes/008_Game_Player_Visuals.rb b/Data/Scripts/003_Game classes/008_Game_Player_Visuals.rb index ec4f69ec1..5509e7d53 100644 --- a/Data/Scripts/003_Game classes/008_Game_Player_Visuals.rb +++ b/Data/Scripts/003_Game classes/008_Game_Player_Visuals.rb @@ -25,7 +25,7 @@ class Game_Player < Game_Character pbMapInterpreterRunning? terrain = pbGetTerrainTag input = ($PokemonSystem.runstyle==1) ? $PokemonGlobal.runtoggle : Input.press?(Input::A) - return input && $PokemonGlobal.runningShoes && + return input && $PokemonGlobal.runningShoes && !jumping? && !$PokemonGlobal.diving && !$PokemonGlobal.surfing && !$PokemonGlobal.bicycle && !PBTerrain.onlyWalk?(terrain) end @@ -54,14 +54,14 @@ class Game_Player < Game_Character def update_command if PBTerrain.isIce?(pbGetTerrainTag) - self.move_speed = 5 # Sliding on ice + self.move_speed = 4 # Sliding on ice elsif !moving? && !@move_route_forcing && $PokemonGlobal if $PokemonGlobal.bicycle - self.move_speed = 6 # Cycling - elsif pbCanRun? || $PokemonGlobal.surfing || $PokemonGlobal.diving - self.move_speed = 5 # Running, surfing or diving + self.move_speed = 5 # Cycling + elsif pbCanRun? || $PokemonGlobal.surfing + self.move_speed = 4 # Running, surfing else - self.move_speed = 4 # Walking + self.move_speed = 3 # Walking, diving end end super diff --git a/Data/Scripts/003_Game classes/009_Game_Map.rb b/Data/Scripts/003_Game classes/009_Game_Map.rb index 7cc43cf8f..3d66db54a 100644 --- a/Data/Scripts/003_Game classes/009_Game_Map.rb +++ b/Data/Scripts/003_Game classes/009_Game_Map.rb @@ -103,7 +103,7 @@ class Game_Map end #----------------------------------------------------------------------------- # * Autoplays background music - # Plays music called "[normal BGM]n" if it's night time and it exists + # Plays music called "[normal BGM]_n" if it's night time and it exists #----------------------------------------------------------------------------- def autoplayAsCue if @map.autoplay_bgm @@ -119,12 +119,12 @@ class Game_Map end #----------------------------------------------------------------------------- # * Plays background music - # Plays music called "[normal BGM]n" if it's night time and it exists + # Plays music called "[normal BGM]_n" if it's night time and it exists #----------------------------------------------------------------------------- def autoplay if @map.autoplay_bgm - if PBDayNight.isNight? && FileTest.audio_exist?("Audio/BGM/"+ @map.bgm.name+ "n") - pbBGMPlay(@map.bgm.name+"n",@map.bgm.volume,@map.bgm.pitch) + if PBDayNight.isNight? && FileTest.audio_exist?("Audio/BGM/"+ @map.bgm.name+ "_n") + pbBGMPlay(@map.bgm.name+"_n",@map.bgm.volume,@map.bgm.pitch) else pbBGMPlay(@map.bgm) end diff --git a/Data/Scripts/006_Game processing/003_Event_Handlers.rb b/Data/Scripts/006_Game processing/003_Event_Handlers.rb index 3822b9451..0c098655b 100644 --- a/Data/Scripts/006_Game processing/003_Event_Handlers.rb +++ b/Data/Scripts/006_Game processing/003_Event_Handlers.rb @@ -39,8 +39,8 @@ class Event # The first argument is the sender of the event, the second argument contains # the event's parameters. If three or more arguments are given, this method # supports the following callbacks: - # proc{ |sender,params| } where params is an array of the other parameters, and - # proc{ |sender,arg0,arg1,...| } + # proc { |sender,params| } where params is an array of the other parameters, and + # proc { |sender,arg0,arg1,...| } def trigger(*arg) arglist = arg[1,arg.length] for callback in @callbacks diff --git a/Data/Scripts/008_Audio/003_Audio_Utilities.rb b/Data/Scripts/008_Audio/003_Audio_Utilities.rb index ee36afbe9..3a04edf6b 100644 --- a/Data/Scripts/008_Audio/003_Audio_Utilities.rb +++ b/Data/Scripts/008_Audio/003_Audio_Utilities.rb @@ -108,7 +108,7 @@ def pbPlaySoundData(samples,volume,async=false,sampleFreq=11025) ret = name break end - return ret + next ret } playThenDelete = proc { |path,volume,length,_async| next if !path || !safeExists?(path) diff --git a/Data/Scripts/009_Objects and windows/003_SpriteWindow.rb b/Data/Scripts/009_Objects and windows/002_MessageConfig.rb similarity index 100% rename from Data/Scripts/009_Objects and windows/003_SpriteWindow.rb rename to Data/Scripts/009_Objects and windows/002_MessageConfig.rb diff --git a/Data/Scripts/009_Objects and windows/002_Window.rb b/Data/Scripts/009_Objects and windows/003_Window.rb similarity index 100% rename from Data/Scripts/009_Objects and windows/002_Window.rb rename to Data/Scripts/009_Objects and windows/003_Window.rb diff --git a/Data/Scripts/009_Objects and windows/004_SpriteWindow.rb b/Data/Scripts/009_Objects and windows/004_SpriteWindow.rb new file mode 100644 index 000000000..e4b2bae4a --- /dev/null +++ b/Data/Scripts/009_Objects and windows/004_SpriteWindow.rb @@ -0,0 +1,992 @@ +#=============================================================================== +# +#=============================================================================== +class SpriteWindowCursorRect < Rect + def initialize(window) + @window=window + @x=0 + @y=0 + @width=0 + @height=0 + end + + attr_reader :x,:y,:width,:height + + def empty + needupdate=@x!=0 || @y!=0 || @width!=0 || @height!=0 + if needupdate + @x=0 + @y=0 + @width=0 + @height=0 + @window.width=@window.width + end + end + + def isEmpty? + return @x==0 && @y==0 && @width==0 && @height==0 + end + + def set(x,y,width,height) + needupdate=@x!=x || @y!=y || @width!=width || @height!=height + if needupdate + @x=x + @y=y + @width=width + @height=height + @window.width=@window.width + end + end + + def height=(value) + @height=value; @window.width=@window.width + end + + def width=(value) + @width=value; @window.width=@window.width + end + + def x=(value) + @x=value; @window.width=@window.width + end + + def y=(value) + @y=value; @window.width=@window.width + end +end + + + +#=============================================================================== +# SpriteWindow is a class based on Window which emulates Window's functionality. +# This class is necessary in order to change the viewport of windows (with +# viewport=) and to make windows fade in and out (with tone=). +#=============================================================================== +class SpriteWindow < Window + attr_reader :tone + attr_reader :color + attr_reader :viewport + attr_reader :contents + attr_reader :ox + attr_reader :oy + attr_reader :x + attr_reader :y + attr_reader :z + attr_reader :zoom_x + attr_reader :zoom_y + attr_reader :offset_x + attr_reader :offset_y + attr_reader :width + attr_reader :active + attr_reader :pause + attr_reader :height + attr_reader :opacity + attr_reader :back_opacity + attr_reader :contents_opacity + attr_reader :visible + attr_reader :cursor_rect + attr_reader :contents_blend_type + attr_reader :blend_type + attr_reader :openness + + def windowskin + @_windowskin + end + + # Flags used to preserve compatibility + # with RGSS/RGSS2's version of Window + module CompatBits + CorrectZ = 1 + ExpandBack = 2 + ShowScrollArrows = 4 + StretchSides = 8 + ShowPause = 16 + ShowCursor = 32 + end + + attr_reader :compat + + def compat=(value) + @compat=value + privRefresh(true) + end + + def initialize(viewport=nil) + @sprites={} + @spritekeys=[ + "back", + "corner0","side0","scroll0", + "corner1","side1","scroll1", + "corner2","side2","scroll2", + "corner3","side3","scroll3", + "cursor","contents","pause" + ] + @viewport=viewport + @sidebitmaps=[nil,nil,nil,nil] + @cursorbitmap=nil + @bgbitmap=nil + for i in @spritekeys + @sprites[i]=Sprite.new(@viewport) + end + @disposed=false + @tone=Tone.new(0,0,0) + @color=Color.new(0,0,0,0) + @blankcontents=Bitmap.new(1,1) # RGSS2 requires this + @contents=@blankcontents + @_windowskin=nil + @rpgvx=false + @compat=CompatBits::ExpandBack|CompatBits::StretchSides + @x=0 + @y=0 + @width=0 + @height=0 + @offset_x=0 + @offset_y=0 + @zoom_x=1.0 + @zoom_y=1.0 + @ox=0 + @oy=0 + @z=0 + @stretch=true + @visible=true + @active=true + @openness=255 + @opacity=255 + @back_opacity=255 + @blend_type=0 + @contents_blend_type=0 + @contents_opacity=255 + @cursor_rect=SpriteWindowCursorRect.new(self) + @cursorblink=0 + @cursoropacity=255 + @pause=false + @pauseframe=0 + @flash=0 + @pauseopacity=0 + @skinformat=0 + @skinrect=Rect.new(0,0,0,0) + @trim=[16,16,16,16] + privRefresh(true) + end + + def dispose + if !self.disposed? + for i in @sprites + i[1].dispose if i[1] + @sprites[i[0]]=nil + end + for i in 0...@sidebitmaps.length + @sidebitmaps[i].dispose if @sidebitmaps[i] + @sidebitmaps[i]=nil + end + @blankcontents.dispose + @cursorbitmap.dispose if @cursorbitmap + @backbitmap.dispose if @backbitmap + @sprites.clear + @sidebitmaps.clear + @_windowskin=nil + @disposed=true + end + end + + def stretch=(value) + @stretch=value + privRefresh(true) + end + + def visible=(value) + @visible=value + privRefresh + end + + def viewport=(value) + @viewport=value + for i in @spritekeys + @sprites[i].dispose if @sprites[i] + end + for i in @spritekeys + if @sprites[i].is_a?(Sprite) + @sprites[i]=Sprite.new(@viewport) + else + @sprites[i]=nil + end + end + privRefresh(true) + end + + def z=(value) + @z=value + privRefresh + end + + def disposed? + return @disposed + end + + def contents=(value) + if @contents!=value + @contents=value + privRefresh if @visible + end + end + + def ox=(value) + if @ox!=value + @ox=value + privRefresh if @visible + end + end + + def oy=(value) + if @oy!=value + @oy=value + privRefresh if @visible + end + end + + def active=(value) + @active=value + privRefresh(true) + end + + def cursor_rect=(value) + if !value + @cursor_rect.empty + else + @cursor_rect.set(value.x,value.y,value.width,value.height) + end + end + + def openness=(value) + @openness=value + @openness=0 if @openness<0 + @openness=255 if @openness>255 + privRefresh + end + + def width=(value) + @width=value + privRefresh(true) + end + + def height=(value) + @height=value + privRefresh(true) + end + + def pause=(value) + @pause=value + @pauseopacity=0 if !value + privRefresh if @visible + end + + def x=(value) + @x=value + privRefresh if @visible + end + + def y=(value) + @y=value + privRefresh if @visible + end + + def zoom_x=(value) + @zoom_x=value + privRefresh if @visible + end + + def zoom_y=(value) + @zoom_y=value + privRefresh if @visible + end + + def offset_x=(value) + @x=value + privRefresh if @visible + end + + def offset_y=(value) + @y=value + privRefresh if @visible + end + + def opacity=(value) + @opacity=value + @opacity=0 if @opacity<0 + @opacity=255 if @opacity>255 + privRefresh if @visible + end + + def back_opacity=(value) + @back_opacity=value + @back_opacity=0 if @back_opacity<0 + @back_opacity=255 if @back_opacity>255 + privRefresh if @visible + end + + def contents_opacity=(value) + @contents_opacity=value + @contents_opacity=0 if @contents_opacity<0 + @contents_opacity=255 if @contents_opacity>255 + privRefresh if @visible + end + + def tone=(value) + @tone=value + privRefresh if @visible + end + + def color=(value) + @color=value + privRefresh if @visible + end + + def blend_type=(value) + @blend_type=value + privRefresh if @visible + end + + def flash(color,duration) + return if disposed? + @flash=duration+1 + for i in @sprites + i[1].flash(color,duration) + end + end + + def update + return if disposed? + mustchange=false + if @active + if @cursorblink==0 + @cursoropacity-=8 + @cursorblink=1 if @cursoropacity<=128 + else + @cursoropacity+=8 + @cursorblink=0 if @cursoropacity>=255 + end + privRefreshCursor + else + @cursoropacity=128 + privRefreshCursor + end + if @pause + oldpauseframe=@pauseframe + oldpauseopacity=@pauseopacity + @pauseframe=(Graphics.frame_count / 8) % 4 + @pauseopacity=[@pauseopacity+64,255].min + mustchange=@pauseframe!=oldpauseframe || @pauseopacity!=oldpauseopacity + end + privRefresh if mustchange + if @flash>0 + for i in @sprites.values + i.update + end + @flash-=1 + end + end + + ############# + attr_reader :skinformat + attr_reader :skinrect + + def loadSkinFile(_file) + if (self.windowskin.width==80 || self.windowskin.width==96) && + self.windowskin.height==48 + # Body = X, Y, width, height of body rectangle within windowskin + @skinrect.set(32,16,16,16) + # Trim = X, Y, width, height of trim rectangle within windowskin + @trim=[32,16,16,16] + elsif self.windowskin.width==80 && self.windowskin.height==80 + @skinrect.set(32,32,16,16) + @trim=[32,16,16,48] + end + end + + def windowskin=(value) + oldSkinWidth=(@_windowskin && !@_windowskin.disposed?) ? @_windowskin.width : -1 + oldSkinHeight=(@_windowskin && !@_windowskin.disposed?) ? @_windowskin.height : -1 + @_windowskin=value + if @skinformat==1 + @rpgvx=false + if @_windowskin && !@_windowskin.disposed? + if @_windowskin.width!=oldSkinWidth || @_windowskin.height!=oldSkinHeight + # Update skinrect and trim if windowskin's dimensions have changed + @skinrect.set((@_windowskin.width-16)/2,(@_windowskin.height-16)/2,16,16) + @trim=[@skinrect.x,@skinrect.y,@skinrect.x,@skinrect.y] + end + else + @skinrect.set(16,16,16,16) + @trim=[16,16,16,16] + end + else + if value && value.is_a?(Bitmap) && !value.disposed? && value.width==128 + @rpgvx=true + else + @rpgvx=false + end + @trim=[16,16,16,16] + end + privRefresh(true) + end + + def skinrect=(value) + @skinrect=value + privRefresh + end + + def skinformat=(value) + if @skinformat!=value + @skinformat=value + privRefresh(true) + end + end + + def borderX + return 32 if !@trim || skinformat==0 + if @_windowskin && !@_windowskin.disposed? + return @trim[0]+(@_windowskin.width-@trim[2]-@trim[0]) + end + return 32 + end + + def borderY + return 32 if !@trim || skinformat==0 + if @_windowskin && !@_windowskin.disposed? + return @trim[1]+(@_windowskin.height-@trim[3]-@trim[1]) + end + return 32 + end + + def leftEdge; self.startX; end + def topEdge; self.startY; end + def rightEdge; self.borderX-self.leftEdge; end + def bottomEdge; self.borderY-self.topEdge; end + + def startX + return !@trim || skinformat==0 ? 16 : @trim[0] + end + + def startY + return !@trim || skinformat==0 ? 16 : @trim[1] + end + + def endX + return !@trim || skinformat==0 ? 16 : @trim[2] + end + + def endY + return !@trim || skinformat==0 ? 16 : @trim[3] + end + + def startX=(value) + @trim[0]=value + privRefresh + end + + def startY=(value) + @trim[1]=value + privRefresh + end + + def endX=(value) + @trim[2]=value + privRefresh + end + + def endY=(value) + @trim[3]=value + privRefresh + end + + ############# + private + + def ensureBitmap(bitmap,dwidth,dheight) + if !bitmap||bitmap.disposed?||bitmap.width0 && @skinformat==0 && !@rpgvx + # Compatibility Mode: Cursor, pause, and contents have higher Z + @sprites["cursor"].z=@z+1 + @sprites["contents"].z=@z+2 + @sprites["pause"].z=@z+2 + end + if @skinformat==0 + startX=16 + startY=16 + endX=16 + endY=16 + trimStartX=16 + trimStartY=16 + trimWidth=32 + trimHeight=32 + if @rpgvx + trimX=64 + trimY=0 + backRect=Rect.new(0,0,64,64) + blindsRect=Rect.new(0,64,64,64) + else + trimX=128 + trimY=0 + backRect=Rect.new(0,0,128,128) + blindsRect=nil + end + if @_windowskin && !@_windowskin.disposed? + @sprites["corner0"].src_rect.set(trimX,trimY+0,16,16); + @sprites["corner1"].src_rect.set(trimX+48,trimY+0,16,16); + @sprites["corner2"].src_rect.set(trimX,trimY+48,16,16); + @sprites["corner3"].src_rect.set(trimX+48,trimY+48,16,16); + @sprites["scroll0"].src_rect.set(trimX+24, trimY+16, 16, 8) # up + @sprites["scroll3"].src_rect.set(trimX+24, trimY+40, 16, 8) # down + @sprites["scroll1"].src_rect.set(trimX+16, trimY+24, 8, 16) # left + @sprites["scroll2"].src_rect.set(trimX+40, trimY+24, 8, 16) # right + cursorX=trimX + cursorY=trimY+64 + sideRects=[ + Rect.new(trimX+16,trimY+0,32,16), + Rect.new(trimX,trimY+16,16,32), + Rect.new(trimX+48,trimY+16,16,32), + Rect.new(trimX+16,trimY+48,32,16) + ] + pauseRects=[ + trimX+32,trimY+64, + trimX+48,trimY+64, + trimX+32,trimY+80, + trimX+48,trimY+80, + ] + pauseWidth=16 + pauseHeight=16 + @sprites["pause"].src_rect.set( + pauseRects[@pauseframe*2], + pauseRects[@pauseframe*2+1], + pauseWidth,pauseHeight + ) + end + else + trimStartX=@trim[0] + trimStartY=@trim[1] + trimWidth=@trim[0]+(@skinrect.width-@trim[2]+@trim[0]) + trimHeight=@trim[1]+(@skinrect.height-@trim[3]+@trim[1]) + if @_windowskin && !@_windowskin.disposed? + # width of left end of window + startX=@skinrect.x + # width of top end of window + startY=@skinrect.y + cx=@skinrect.x+@skinrect.width # right side of BODY rect + cy=@skinrect.y+@skinrect.height # bottom side of BODY rect + # width of right end of window + endX=(!@_windowskin || @_windowskin.disposed?) ? @skinrect.x : @_windowskin.width-cx + # height of bottom end of window + endY=(!@_windowskin || @_windowskin.disposed?) ? @skinrect.y : @_windowskin.height-cy + @sprites["corner0"].src_rect.set(0,0,startX,startY); + @sprites["corner1"].src_rect.set(cx,0,endX,startY); + @sprites["corner2"].src_rect.set(0,cy,startX,endY); + @sprites["corner3"].src_rect.set(cx,cy,endX,endY); + backRect=Rect.new(@skinrect.x,@skinrect.y, + @skinrect.width,@skinrect.height); + blindsRect=nil + sideRects=[ + Rect.new(startX,0,@skinrect.width,startY), # side0 (top) + Rect.new(0,startY,startX,@skinrect.height), # side1 (left) + Rect.new(cx,startY,endX,@skinrect.height), # side2 (right) + Rect.new(startX,cy,@skinrect.width,endY) # side3 (bottom) + ] + end + end + if @width>trimWidth && @height>trimHeight + @sprites["contents"].src_rect.set(@ox,@oy,@width-trimWidth,@height-trimHeight) + else + @sprites["contents"].src_rect.set(0,0,0,0) + end + @sprites["contents"].x=@x+trimStartX + @sprites["contents"].y=@y+trimStartY + if (@compat & CompatBits::ShowScrollArrows)>0 && @skinformat==0 + # Compatibility mode: Make scroll arrows visible + if @skinformat==0 && @_windowskin && !@_windowskin.disposed? && + @contents && !@contents.disposed? + @sprites["scroll0"].visible = @visible && hascontents && @oy > 0 + @sprites["scroll1"].visible = @visible && hascontents && @ox > 0 + @sprites["scroll2"].visible = @visible && (@contents.width - @ox) > @width-trimWidth + @sprites["scroll3"].visible = @visible && (@contents.height - @oy) > @height-trimHeight + end + end + if @_windowskin && !@_windowskin.disposed? + borderX=startX+endX + borderY=startY+endY + @sprites["corner0"].x=@x + @sprites["corner0"].y=@y + @sprites["corner1"].x=@x+@width-endX + @sprites["corner1"].y=@y + @sprites["corner2"].x=@x + @sprites["corner2"].y=@y+@height-endY + @sprites["corner3"].x=@x+@width-endX + @sprites["corner3"].y=@y+@height-endY + @sprites["side0"].x=@x+startX + @sprites["side0"].y=@y + @sprites["side1"].x=@x + @sprites["side1"].y=@y+startY + @sprites["side2"].x=@x+@width-endX + @sprites["side2"].y=@y+startY + @sprites["side3"].x=@x+startX + @sprites["side3"].y=@y+@height-endY + @sprites["scroll0"].x = @x+@width / 2 - 8 + @sprites["scroll0"].y = @y+8 + @sprites["scroll1"].x = @x+8 + @sprites["scroll1"].y = @y+@height / 2 - 8 + @sprites["scroll2"].x = @x+@width - 16 + @sprites["scroll2"].y = @y+@height / 2 - 8 + @sprites["scroll3"].x = @x+@width / 2 - 8 + @sprites["scroll3"].y = @y+@height - 16 + @sprites["cursor"].x=@x+startX+@cursor_rect.x + @sprites["cursor"].y=@y+startY+@cursor_rect.y + if (@compat & CompatBits::ExpandBack)>0 && @skinformat==0 + # Compatibility mode: Expand background + @sprites["back"].x=@x+2 + @sprites["back"].y=@y+2 + else + @sprites["back"].x=@x+startX + @sprites["back"].y=@y+startY + end + end + if changeBitmap && @_windowskin && !@_windowskin.disposed? + if @skinformat==0 + @sprites["cursor"].x=@x+startX+@cursor_rect.x + @sprites["cursor"].y=@y+startY+@cursor_rect.y + width=@cursor_rect.width + height=@cursor_rect.height + if width > 0 && height > 0 + cursorrects=[ + # sides + Rect.new(cursorX+2, cursorY+0, 28, 2), + Rect.new(cursorX+0, cursorY+2, 2, 28), + Rect.new(cursorX+30, cursorY+2, 2, 28), + Rect.new(cursorX+2, cursorY+30, 28, 2), + # corners + Rect.new(cursorX+0, cursorY+0, 2, 2), + Rect.new(cursorX+30, cursorY+0, 2, 2), + Rect.new(cursorX+0, cursorY+30, 2, 2), + Rect.new(cursorX+30, cursorY+30, 2, 2), + # back + Rect.new(cursorX+2, cursorY+2, 28, 28) + ] + margin=2 + fullmargin=4 + @cursorbitmap = ensureBitmap(@cursorbitmap, width, height) + @cursorbitmap.clear + @sprites["cursor"].bitmap=@cursorbitmap + @sprites["cursor"].src_rect.set(0,0,width,height) + rect = Rect.new(margin,margin,width - fullmargin, height - fullmargin) + @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[8]) + @cursorbitmap.blt(0, 0, @_windowskin, cursorrects[4])# top left + @cursorbitmap.blt(width-margin, 0, @_windowskin, cursorrects[5]) # top right + @cursorbitmap.blt(0, height-margin, @_windowskin, cursorrects[6]) # bottom right + @cursorbitmap.blt(width-margin, height-margin, @_windowskin, cursorrects[7]) # bottom left + rect = Rect.new(margin, 0,width - fullmargin, margin) + @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[0]) + rect = Rect.new(0, margin,margin, height - fullmargin) + @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[1]) + rect = Rect.new(width - margin, margin, margin, height - fullmargin) + @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[2]) + rect = Rect.new(margin, height-margin, width - fullmargin, margin) + @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[3]) + else + @sprites["cursor"].visible=false + @sprites["cursor"].src_rect.set(0,0,0,0) + end + end + for i in 0..3 + case i + when 0 + dwidth = @width-startX-endX + dheight = startY + when 1 + dwidth = startX + dheight = @height-startY-endY + when 2 + dwidth = endX + dheight = @height-startY-endY + when 3 + dwidth = @width-startX-endX + dheight = endY + end + @sidebitmaps[i]=ensureBitmap(@sidebitmaps[i],dwidth,dheight) + @sprites["side#{i}"].bitmap=@sidebitmaps[i] + @sprites["side#{i}"].src_rect.set(0,0,dwidth,dheight) + @sidebitmaps[i].clear + if sideRects[i].width>0 && sideRects[i].height>0 + if (@compat & CompatBits::StretchSides)>0 && @skinformat==0 + # Compatibility mode: Stretch sides + @sidebitmaps[i].stretch_blt(@sprites["side#{i}"].src_rect, + @_windowskin,sideRects[i]) + else + tileBitmap(@sidebitmaps[i],@sprites["side#{i}"].src_rect, + @_windowskin,sideRects[i]) + end + end + end + if (@compat & CompatBits::ExpandBack)>0 && @skinformat==0 + # Compatibility mode: Expand background + backwidth=@width-4 + backheight=@height-4 + else + backwidth=@width-borderX + backheight=@height-borderY + end + if backwidth>0 && backheight>0 + @backbitmap=ensureBitmap(@backbitmap,backwidth,backheight) + @sprites["back"].bitmap=@backbitmap + @sprites["back"].src_rect.set(0,0,backwidth,backheight) + @backbitmap.clear + if @stretch + @backbitmap.stretch_blt(@sprites["back"].src_rect,@_windowskin,backRect) + else + tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,backRect) + end + if blindsRect + tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,blindsRect) + end + else + @sprites["back"].visible=false + @sprites["back"].src_rect.set(0,0,0,0) + end + end + if @openness!=255 + opn=@openness/255.0 + for k in @spritekeys + sprite=@sprites[k] + ratio=(@height<=0) ? 0 : (sprite.y-@y)*1.0/@height + sprite.zoom_y=opn + sprite.zoom_x=1.0 + sprite.oy=0 + sprite.y=(@y+(@height/2.0)+(@height*ratio*opn)-(@height/2*opn)).floor + end + else + for k in @spritekeys + sprite=@sprites[k] + sprite.zoom_x=1.0 + sprite.zoom_y=1.0 + end + end + i=0 + # Ensure Z order + for k in @spritekeys + sprite=@sprites[k] + y=sprite.y + sprite.y=i + sprite.oy=(sprite.zoom_y<=0) ? 0 : (i-y)/sprite.zoom_y + sprite.zoom_x*=@zoom_x + sprite.zoom_y*=@zoom_y + sprite.x*=@zoom_x + sprite.y*=@zoom_y + sprite.x+=(@offset_x/sprite.zoom_x) + sprite.y+=(@offset_y/sprite.zoom_y) + end + end +end + + + +#=============================================================================== +# +#=============================================================================== +class SpriteWindow_Base < SpriteWindow + TEXTPADDING=4 # In pixels + + def initialize(x, y, width, height) + super() + self.x = x + self.y = y + self.width = width + self.height = height + self.z = 100 + @curframe=MessageConfig.pbGetSystemFrame() + @curfont=MessageConfig.pbGetSystemFontName() + @sysframe=AnimatedBitmap.new(@curframe) + @customskin=nil + __setWindowskin(@sysframe.bitmap) + __resolveSystemFrame() + pbSetSystemFont(self.contents) if self.contents + end + + def __setWindowskin(skin) + if skin && (skin.width==192 && skin.height==128) || # RPGXP Windowskin + (skin.width==128 && skin.height==128) # RPGVX Windowskin + self.skinformat=0 + else + self.skinformat=1 + end + self.windowskin=skin + end + + def __resolveSystemFrame + if self.skinformat==1 + if !@resolvedFrame + @resolvedFrame=MessageConfig.pbGetSystemFrame() + @resolvedFrame.sub!(/\.[^\.\/\\]+$/,"") + end + self.loadSkinFile("#{@resolvedFrame}.txt") if @resolvedFrame!="" + end + end + + def setSkin(skin) # Filename of windowskin to apply. Supports XP, VX, and animated skins. + @customskin.dispose if @customskin + @customskin=nil + resolvedName=pbResolveBitmap(skin) + return if !resolvedName || resolvedName=="" + @customskin=AnimatedBitmap.new(resolvedName) + __setWindowskin(@customskin.bitmap) + if self.skinformat==1 + skinbase=resolvedName.sub(/\.[^\.\/\\]+$/,"") + self.loadSkinFile("#{skinbase}.txt") + end + end + + def setSystemFrame + @customskin.dispose if @customskin + @customskin=nil + __setWindowskin(@sysframe.bitmap) + __resolveSystemFrame() + end + + def update + super + if self.windowskin + if @customskin + if @customskin.totalFrames>1 + @customskin.update + __setWindowskin(@customskin.bitmap) + end + elsif @sysframe + if @sysframe.totalFrames>1 + @sysframe.update + __setWindowskin(@sysframe.bitmap) + end + end + end + if @curframe!=MessageConfig.pbGetSystemFrame() + @curframe=MessageConfig.pbGetSystemFrame() + if @sysframe && !@customskin + @sysframe.dispose if @sysframe + @sysframe=AnimatedBitmap.new(@curframe) + @resolvedFrame=nil + __setWindowskin(@sysframe.bitmap) + __resolveSystemFrame() + end + begin + refresh + rescue NoMethodError + end + end + if @curfont!=MessageConfig.pbGetSystemFontName() + @curfont=MessageConfig.pbGetSystemFontName() + if self.contents && !self.contents.disposed? + pbSetSystemFont(self.contents) + end + begin + refresh + rescue NoMethodError + end + end + end + + def dispose + self.contents.dispose if self.contents + @sysframe.dispose + @customskin.dispose if @customskin + super + end +end diff --git a/Data/Scripts/009_Objects and windows/005_SpriteWindow_sprites.rb b/Data/Scripts/009_Objects and windows/005_SpriteWindow_sprites.rb deleted file mode 100644 index 2a93d17b4..000000000 --- a/Data/Scripts/009_Objects and windows/005_SpriteWindow_sprites.rb +++ /dev/null @@ -1,1083 +0,0 @@ -module GifLibrary - @@loadlib = Win32API.new("Kernel32.dll","LoadLibrary",'p','') - if safeExists?("gif.dll") - PngDll = @@loadlib.call("gif.dll") - GifToPngFiles = Win32API.new("gif.dll","GifToPngFiles",'pp','l') - GifToPngFilesInMemory = Win32API.new("gif.dll","GifToPngFilesInMemory",'plp','l') - CopyDataString = Win32API.new("gif.dll","CopyDataString",'lpl','l') - FreeDataString = Win32API.new("gif.dll","FreeDataString",'l','') - else - PngDll=nil - end - - def self.getDataFromResult(result) - datasize=CopyDataString.call(result,"",0) - ret=nil - if datasize!=0 - data="0"*datasize - CopyDataString.call(result,data,datasize) - ret=data.unpack("V*") - end - FreeDataString.call(result) - return ret - end -end - - - -class AnimatedBitmap - def initialize(file,hue=0) - if file==nil - raise "Filename is nil (missing graphic)\r\n\r\n"+ - "If you see this error in the Continue/New Game screen, you may be loading another game's save file. "+ - "Check your project's title (\"Game > Change Title...\" in RMXP).\r\n" - end - if file.split(/[\\\/]/)[-1][/^\[\d+(?:,\d+)?]/] # Starts with 1 or more digits in square brackets - @bitmap = PngAnimatedBitmap.new(file,hue) - else - @bitmap = GifBitmap.new(file,hue) - end - end - - def [](index); @bitmap[index]; end - def width; @bitmap.bitmap.width; end - def height; @bitmap.bitmap.height; end - def length; @bitmap.length; end - def each; @bitmap.each { |item| yield item }; end - def bitmap; @bitmap.bitmap; end - def currentIndex; @bitmap.currentIndex; end - def frameDelay; @bitmap.frameDelay; end - def totalFrames; @bitmap.totalFrames; end - def disposed?; @bitmap.disposed?; end - def update; @bitmap.update; end - def dispose; @bitmap.dispose; end - def deanimate; @bitmap.deanimate; end - def copy; @bitmap.copy; end -end - - - -class PngAnimatedBitmap - # Creates an animated bitmap from a PNG file. - def initialize(file,hue=0) - @frames=[] - @currentFrame=0 - @framecount=0 - panorama=BitmapCache.load_bitmap(file,hue) - if file.split(/[\\\/]/)[-1][/^\[(\d+)(?:,(\d+))?]/] # Starts with 1 or more digits in brackets - # File has a frame count - numFrames = $1.to_i - delay = $2.to_i || 10 - raise "Invalid frame count in #{file}" if numFrames<=0 - raise "Invalid frame delay in #{file}" if delay<=0 - if panorama.width % numFrames != 0 - raise "Bitmap's width (#{panorama.width}) is not divisible by frame count: #{file}" - end - @frameDelay = delay - subWidth=panorama.width/numFrames - for i in 0...numFrames - subBitmap=BitmapWrapper.new(subWidth,panorama.height) - subBitmap.blt(0,0,panorama,Rect.new(subWidth*i,0,subWidth,panorama.height)) - @frames.push(subBitmap) - end - panorama.dispose - else - @frames=[panorama] - end - end - - def [](index) - return @frames[index] - end - - def width; self.bitmap.width; end - - def height; self.bitmap.height; end - - def deanimate - for i in 1...@frames.length - @frames[i].dispose - end - @frames=[@frames[0]] - @currentFrame=0 - return @frames[0] - end - - def bitmap - @frames[@currentFrame] - end - - def currentIndex - @currentFrame - end - - def frameDelay(_index) - return @frameDelay - end - - def length - @frames.length - end - - def each - @frames.each { |item| yield item} - end - - def totalFrames - @frameDelay*@frames.length - end - - def disposed? - @disposed - end - - def update - return if disposed? - if @frames.length>1 - @framecount+=1 - if @framecount>=@frameDelay - @framecount=0 - @currentFrame+=1 - @currentFrame%=@frames.length - end - end - end - - def dispose - if !@disposed - for i in @frames - i.dispose - end - end - @disposed=true - end - - attr_accessor :frames # internal - - def copy - x=self.clone - x.frames=x.frames.clone - for i in 0...x.frames.length - x.frames[i]=x.frames[i].copy - end - return x - end -end - - - -#internal class -class GifBitmap - # Creates a bitmap from a GIF file with the specified - # optional viewport. Can also load non-animated bitmaps. - def initialize(file,hue=0) - @gifbitmaps=[] - @gifdelays=[] - @totalframes=0 - @framecount=0 - @currentIndex=0 - @disposed=false - bitmap=nil - filestring=nil - filestrName=nil - file="" if !file - file=canonicalize(file) - begin - bitmap=BitmapCache.load_bitmap(file,hue) - rescue - bitmap=nil - end - if !bitmap || (bitmap.width==32 && bitmap.height==32) - if !file || file.length<1 || file[file.length-1]!=0x2F - if (filestring=pbGetFileChar(file)) - filestrName=file - elsif (filestring=pbGetFileChar(file+".gif")) - filestrName=file+".gif" - elsif (filestring=pbGetFileChar(file+".png")) - filestrName=file+".png" - elsif (filestring=pbGetFileChar(file+".jpg")) - filestrName=file+".jpg" - elsif (filestring=pbGetFileChar(file+".bmp")) - filestrName=file+".bmp" - end - end - end - if bitmap && filestring && filestring[0]==0x47 && - bitmap.width==32 && bitmap.height==32 - #File.open("debug.txt","ab") { |f| f.puts("rejecting bitmap") } - bitmap.dispose - bitmap=nil - end - if bitmap - #File.open("debug.txt","ab") { |f| f.puts("reusing bitmap") } - # Have a regular non-animated bitmap - @totalframes=1 - @framecount=0 - @gifbitmaps=[bitmap] - @gifdelays=[1] - else - tmpBase=File.basename(file)+"_tmp_" - filestring=pbGetFileString(filestrName) if filestring - Dir.chdir(ENV["TEMP"]) { # navigate to temp folder since game might be on a CD-ROM - if filestring && filestring[0]==0x47 && GifLibrary::PngDll - result=GifLibrary::GifToPngFilesInMemory.call(filestring, - filestring.length,tmpBase) - else - result=0 - end - if result>0 - @gifdelays=GifLibrary.getDataFromResult(result) - @totalframes=@gifdelays.pop - for i in 0...@gifdelays.length - @gifdelays[i]=[@gifdelays[i],1].max - bmfile=sprintf("%s%d.png",tmpBase,i) - if safeExists?(bmfile) - gifbitmap=BitmapWrapper.new(bmfile) - @gifbitmaps.push(gifbitmap) - bmfile.hue_change(hue) if hue!=0 - if hue==0 && @gifdelays.length==1 - BitmapCache.setKey(file,gifbitmap) - end - File.delete(bmfile) - else - @gifbitmaps.push(BitmapWrapper.new(32,32)) - end - end - end - } - if @gifbitmaps.length==0 - @gifbitmaps=[BitmapWrapper.new(32,32)] - @gifdelays=[1] - end - if @gifbitmaps.length==1 - BitmapCache.setKey(file,@gifbitmaps[0]) - end - end - end - - def [](index) - return @gifbitmaps[index] - end - - def deanimate - for i in 1...@gifbitmaps.length - @gifbitmaps[i].dispose - end - @gifbitmaps=[@gifbitmaps[0]] - @currentIndex=0 - return @gifbitmaps[0] - end - - def bitmap - @gifbitmaps[@currentIndex] - end - - def currentIndex - @currentIndex - end - - def frameDelay(index) - return @gifdelay[index]/2 # Due to frame count being incremented by 2 - end - - def length - @gifbitmaps.length - end - - def each - @gifbitmaps.each { |item| yield item } - end - - def totalFrames - @totalframes/2 # Due to frame count being incremented by 2 - end - - def disposed? - @disposed - end - - def width - @gifbitmaps.length==0 ? 0 : @gifbitmaps[0].width - end - - def height - @gifbitmaps.length==0 ? 0 : @gifbitmaps[0].height - end - - # This function must be called in order to animate the GIF image. - def update - return if disposed? - if @gifbitmaps.length>0 - @framecount+=2 - @framecount=@totalframes<=0 ? 0 : @framecount%@totalframes - frametoshow=0 - for i in 0...@gifdelays.length - frametoshow=i if @gifdelays[i]<=@framecount - end - @currentIndex=frametoshow - end - end - - def dispose - if !@disposed - for i in @gifbitmaps - i.dispose - end - end - @disposed=true - end - - attr_accessor :gifbitmaps # internal - attr_accessor :gifdelays # internal - - def copy - x=self.clone - x.gifbitmaps=x.gifbitmaps.clone - x.gifdelays=x.gifdelays.clone - for i in 0...x.gifbitmaps.length - x.gifbitmaps[i]=x.gifbitmaps[i].copy - end - return x - end -end - - - -def pbGetTileBitmap(filename, tile_id, hue) - return BitmapCache.tileEx(filename, tile_id, hue) { |f| - AnimatedBitmap.new("Graphics/Tilesets/"+filename).deanimate - } -end - -def pbGetTileset(name,hue=0) - return AnimatedBitmap.new("Graphics/Tilesets/"+name,hue).deanimate -end - -def pbGetAutotile(name,hue=0) - return AnimatedBitmap.new("Graphics/Autotiles/"+name,hue).deanimate -end - -def pbGetAnimation(name,hue=0) - return AnimatedBitmap.new("Graphics/Animations/"+name,hue).deanimate -end - - - -#=============================================================================== -# SpriteWrapper is a class based on Sprite which wraps Sprite's properties. -#=============================================================================== -class SpriteWrapper < Sprite - def initialize(viewport=nil) - @sprite = Sprite.new(viewport) - end - - def dispose; @sprite.dispose; end - def disposed?; return @sprite.disposed?; end - def viewport; return @sprite.viewport; end - def flash(color,duration); return @sprite.flash(color,duration); end - def update; return @sprite.update; end - def x; @sprite.x; end - def x=(value); @sprite.x = value; end - def y; @sprite.y; end - def y=(value); @sprite.y = value; end - def bitmap; @sprite.bitmap; end - def bitmap=(value); @sprite.bitmap = value; end - def src_rect; @sprite.src_rect; end - def src_rect=(value); @sprite.src_rect = value; end - def visible; @sprite.visible; end - def visible=(value); @sprite.visible = value; end - def z; @sprite.z; end - def z=(value); @sprite.z = value; end - def ox; @sprite.ox; end - def ox=(value); @sprite.ox = value; end - def oy; @sprite.oy; end - def oy=(value); @sprite.oy = value; end - def zoom_x; @sprite.zoom_x; end - def zoom_x=(value); @sprite.zoom_x = value; end - def zoom_y; @sprite.zoom_y; end - def zoom_y=(value); @sprite.zoom_y = value; end - def angle; @sprite.angle; end - def angle=(value); @sprite.angle = value; end - def mirror; @sprite.mirror; end - def mirror=(value); @sprite.mirror = value; end - def bush_depth; @sprite.bush_depth; end - def bush_depth=(value); @sprite.bush_depth = value; end - def opacity; @sprite.opacity; end - def opacity=(value); @sprite.opacity = value; end - def blend_type; @sprite.blend_type; end - def blend_type=(value); @sprite.blend_type = value; end - def color; @sprite.color; end - def color=(value); @sprite.color = value; end - def tone; @sprite.tone; end - def tone=(value); @sprite.tone = value; end - - def viewport=(value) - return if self.viewport==value - bitmap = @sprite.bitmap - src_rect = @sprite.src_rect - visible = @sprite.visible - x = @sprite.x - y = @sprite.y - z = @sprite.z - ox = @sprite.ox - oy = @sprite.oy - zoom_x = @sprite.zoom_x - zoom_y = @sprite.zoom_y - angle = @sprite.angle - mirror = @sprite.mirror - bush_depth = @sprite.bush_depth - opacity = @sprite.opacity - blend_type = @sprite.blend_type - color = @sprite.color - tone = @sprite.tone - @sprite.dispose - @sprite = Sprite.new(value) - @sprite.bitmap = bitmap - @sprite.src_rect = src_rect - @sprite.visible = visible - @sprite.x = x - @sprite.y = y - @sprite.z = z - @sprite.ox = ox - @sprite.oy = oy - @sprite.zoom_x = zoom_x - @sprite.zoom_y = zoom_y - @sprite.angle = angle - @sprite.mirror = mirror - @sprite.bush_depth = bush_depth - @sprite.opacity = opacity - @sprite.blend_type = blend_type - @sprite.color = color - @sprite.tone = tone - end -end - - - -#=============================================================================== -# Sprite class that maintains a bitmap of its own. -# This bitmap can't be changed to a different one. -#=============================================================================== -class BitmapSprite < SpriteWrapper - def initialize(width,height,viewport=nil) - super(viewport) - self.bitmap=Bitmap.new(width,height) - @initialized=true - end - - def bitmap=(value) - super(value) if !@initialized - end - - def dispose - self.bitmap.dispose if !self.disposed? - super - end -end - - - -#=============================================================================== -# -#=============================================================================== -class AnimatedSprite < SpriteWrapper - attr_reader :frame - attr_reader :framewidth - attr_reader :frameheight - attr_reader :framecount - attr_reader :animname - - def initializeLong(animname,framecount,framewidth,frameheight,frameskip) - @animname=pbBitmapName(animname) - @realframes=0 - @frameskip=[1,frameskip].max - @frameskip *= Graphics.frame_rate/20 - raise _INTL("Frame width is 0") if framewidth==0 - raise _INTL("Frame height is 0") if frameheight==0 - begin - @animbitmap=AnimatedBitmap.new(animname).deanimate - rescue - @animbitmap=Bitmap.new(framewidth,frameheight) - end - if @animbitmap.width%framewidth!=0 - raise _INTL("Bitmap's width ({1}) is not a multiple of frame width ({2}) [Bitmap={3}]", - @animbitmap.width,framewidth,animname) - end - if @animbitmap.height%frameheight!=0 - raise _INTL("Bitmap's height ({1}) is not a multiple of frame height ({2}) [Bitmap={3}]", - @animbitmap.height,frameheight,animname) - end - @framecount=framecount - @framewidth=framewidth - @frameheight=frameheight - @framesperrow=@animbitmap.width/@framewidth - @playing=false - self.bitmap=@animbitmap - self.src_rect.width=@framewidth - self.src_rect.height=@frameheight - self.frame=0 - end - - # Shorter version of AnimationSprite. All frames are placed on a single row - # of the bitmap, so that the width and height need not be defined beforehand - def initializeShort(animname,framecount,frameskip) - @animname=pbBitmapName(animname) - @realframes=0 - @frameskip=[1,frameskip].max - @frameskip *= Graphics.frame_rate/20 - begin - @animbitmap=AnimatedBitmap.new(animname).deanimate - rescue - @animbitmap=Bitmap.new(framecount*4,32) - end - if @animbitmap.width%framecount!=0 - raise _INTL("Bitmap's width ({1}) is not a multiple of frame count ({2}) [Bitmap={3}]", - @animbitmap.width,framewidth,animname) - end - @framecount=framecount - @framewidth=@animbitmap.width/@framecount - @frameheight=@animbitmap.height - @framesperrow=framecount - @playing=false - self.bitmap=@animbitmap - self.src_rect.width=@framewidth - self.src_rect.height=@frameheight - self.frame=0 - end - - def initialize(*args) - if args.length==1 - super(args[0][3]) - initializeShort(args[0][0],args[0][1],args[0][2]) - else - super(args[5]) - initializeLong(args[0],args[1],args[2],args[3],args[4]) - end - end - - def self.create(animname,framecount,frameskip,viewport=nil) - return self.new([animname,framecount,frameskip,viewport]) - end - - def dispose - return if disposed? - @animbitmap.dispose - @animbitmap=nil - super - end - - def playing? - return @playing - end - - def frame=(value) - @frame=value - @realframes=0 - self.src_rect.x=@frame%@framesperrow*@framewidth - self.src_rect.y=@frame/@framesperrow*@frameheight - end - - def start - @playing=true - @realframes=0 - end - - alias play start - - def stop - @playing=false - end - - def update - super - if @playing - @realframes+=1 - if @realframes==@frameskip - @realframes=0 - self.frame+=1 - self.frame%=self.framecount - end - end - end -end - - - -#=============================================================================== -# Displays an icon bitmap in a sprite. Supports animated images. -#=============================================================================== -class IconSprite < SpriteWrapper - attr_reader :name - - def initialize(*args) - if args.length==0 - super(nil) - self.bitmap=nil - elsif args.length==1 - super(args[0]) - self.bitmap=nil - elsif args.length==2 - super(nil) - self.x=args[0] - self.y=args[1] - else - super(args[2]) - self.x=args[0] - self.y=args[1] - end - @name="" - @_iconbitmap=nil - end - - def dispose - clearBitmaps() - super - end - - # Sets the icon's filename. Alias for setBitmap. - def name=(value) - setBitmap(value) - end - - # Sets the icon's filename. - def setBitmap(file,hue=0) - oldrc=self.src_rect - clearBitmaps() - @name=file - return if file==nil - if file!="" - @_iconbitmap=AnimatedBitmap.new(file,hue) - # for compatibility - self.bitmap=@_iconbitmap ? @_iconbitmap.bitmap : nil - self.src_rect=oldrc - else - @_iconbitmap=nil - end - end - - def clearBitmaps - @_iconbitmap.dispose if @_iconbitmap - @_iconbitmap=nil - self.bitmap=nil if !self.disposed? - end - - def update - super - return if !@_iconbitmap - @_iconbitmap.update - if self.bitmap!=@_iconbitmap.bitmap - oldrc=self.src_rect - self.bitmap=@_iconbitmap.bitmap - self.src_rect=oldrc - end - end -end - - - -#=============================================================================== -# Old GifSprite class, retained for compatibility -#=============================================================================== -class GifSprite < IconSprite - def initialize(path) - super(0,0) - setBitmap(path) - end -end - - - -#=============================================================================== -# SpriteWrapper that stores multiple bitmaps, and displays only one at once. -#=============================================================================== -class ChangelingSprite < SpriteWrapper - def initialize(x=0,y=0,viewport=nil) - super(viewport) - self.x = x - self.y = y - @bitmaps = {} - @currentBitmap = nil - end - - def addBitmap(key,path) - @bitmaps[key].dispose if @bitmaps[key] - @bitmaps[key] = AnimatedBitmap.new(path) - end - - def changeBitmap(key) - @currentBitmap = @bitmaps[key] - self.bitmap = (@currentBitmap) ? @currentBitmap.bitmap : nil - end - - def dispose - return if disposed? - for bm in @bitmaps.values; bm.dispose; end - @bitmaps.clear - super - end - - def update - return if disposed? - for bm in @bitmaps.values; bm.update; end - self.bitmap = (@currentBitmap) ? @currentBitmap.bitmap : nil - end -end - - - -#=============================================================================== -# Displays an icon bitmap in a window. Supports animated images. -#=============================================================================== -class IconWindow < SpriteWindow_Base - attr_reader :name - - def initialize(x,y,width,height,viewport=nil) - super(x,y,width,height) - self.viewport=viewport - self.contents=nil - @name="" - @_iconbitmap=nil - end - - def dispose - clearBitmaps() - super - end - - def update - super - if @_iconbitmap - @_iconbitmap.update - self.contents=@_iconbitmap.bitmap - end - end - - def clearBitmaps - @_iconbitmap.dispose if @_iconbitmap - @_iconbitmap=nil - self.contents=nil if !self.disposed? - end - - # Sets the icon's filename. Alias for setBitmap. - def name=(value) - setBitmap(value) - end - - # Sets the icon's filename. - def setBitmap(file,hue=0) - clearBitmaps() - @name=file - return if file==nil - if file!="" - @_iconbitmap=AnimatedBitmap.new(file,hue) - # for compatibility - self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil - else - @_iconbitmap=nil - end - end -end - - - -#=============================================================================== -# Displays an icon bitmap in a window. Supports animated images. -# Accepts bitmaps and paths to bitmap files in its constructor. -#=============================================================================== -class PictureWindow < SpriteWindow_Base - def initialize(pathOrBitmap) - super(0,0,32,32) - self.viewport=viewport - self.contents=nil - @_iconbitmap=nil - setBitmap(pathOrBitmap) - end - - def dispose - clearBitmaps() - super - end - - def update - super - if @_iconbitmap - if @_iconbitmap.is_a?(Bitmap) - self.contents=@_iconbitmap - else - @_iconbitmap.update - self.contents=@_iconbitmap.bitmap - end - end - end - - def clearBitmaps - @_iconbitmap.dispose if @_iconbitmap - @_iconbitmap=nil - self.contents=nil if !self.disposed? - end - - # Sets the icon's bitmap or filename. (hue parameter - # is ignored unless pathOrBitmap is a filename) - def setBitmap(pathOrBitmap,hue=0) - clearBitmaps() - if pathOrBitmap!=nil && pathOrBitmap!="" - if pathOrBitmap.is_a?(Bitmap) - @_iconbitmap=pathOrBitmap - self.contents=@_iconbitmap - self.width=@_iconbitmap.width+self.borderX - self.height=@_iconbitmap.height+self.borderY - elsif pathOrBitmap.is_a?(AnimatedBitmap) - @_iconbitmap=pathOrBitmap - self.contents=@_iconbitmap.bitmap - self.width=@_iconbitmap.bitmap.width+self.borderX - self.height=@_iconbitmap.bitmap.height+self.borderY - else - @_iconbitmap=AnimatedBitmap.new(pathOrBitmap,hue) - self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil - self.width=@_iconbitmap ? @_iconbitmap.bitmap.width+self.borderX : - 32+self.borderX - self.height=@_iconbitmap ? @_iconbitmap.bitmap.height+self.borderY : - 32+self.borderY - end - else - @_iconbitmap=nil - self.width=32+self.borderX - self.height=32+self.borderY - end - end -end - - - -#=============================================================================== -# -#=============================================================================== -class Plane - def update; end - def refresh; end -end - - - -#=============================================================================== -# This class works around a limitation that planes are always -# 640 by 480 pixels in size regardless of the window's size. -#=============================================================================== -class LargePlane < Plane - attr_accessor :borderX - attr_accessor :borderY - - def initialize(viewport=nil) - @__sprite=Sprite.new(viewport) - @__disposed=false - @__ox=0 - @__oy=0 - @__bitmap=nil - @__visible=true - @__sprite.visible=false - @borderX=0 - @borderY=0 - end - - def disposed? - return @__disposed - end - - def dispose - if !@__disposed - @__sprite.bitmap.dispose if @__sprite.bitmap - @__sprite.dispose - @__sprite=nil - @__bitmap=nil - @__disposed=true - end - super - end - - def ox; @__ox; end - def oy; @__oy; end - - def ox=(value); - return if @__ox==value - @__ox = value - refresh - end - - def oy=(value); - return if @__oy==value - @__oy = value - refresh - end - - def bitmap - return @__bitmap - end - - def bitmap=(value) - if value==nil - if @__bitmap!=nil - @__bitmap=nil - @__sprite.visible=(@__visible && !@__bitmap.nil?) - end - elsif @__bitmap!=value && !value.disposed? - @__bitmap=value - refresh - elsif value.disposed? - if @__bitmap!=nil - @__bitmap=nil - @__sprite.visible=(@__visible && !@__bitmap.nil?) - end - end - end - - def viewport; @__sprite.viewport; end - def zoom_x; @__sprite.zoom_x; end - def zoom_y; @__sprite.zoom_y; end - def opacity; @__sprite.opacity; end - def blend_type; @__sprite.blend_type; end - def visible; @__visible; end - def z; @__sprite.z; end - def color; @__sprite.color; end - def tone; @__sprite.tone; end - - def zoom_x=(v); - return if @__sprite.zoom_x==v - @__sprite.zoom_x = v - refresh - end - - def zoom_y=(v); - return if @__sprite.zoom_y==v - @__sprite.zoom_y = v - refresh - end - - def opacity=(v); @__sprite.opacity=(v); end - def blend_type=(v); @__sprite.blend_type=(v); end - def visible=(v); @__visible=v; @__sprite.visible=(@__visible && !@__bitmap.nil?); end - def z=(v); @__sprite.z=(v); end - def color=(v); @__sprite.color=(v); end - def tone=(v); @__sprite.tone=(v); end - def update; ;end - - def refresh - @__sprite.visible = (@__visible && !@__bitmap.nil?) - if @__bitmap - if !@__bitmap.disposed? - @__ox += @__bitmap.width*@__sprite.zoom_x if @__ox<0 - @__oy += @__bitmap.height*@__sprite.zoom_y if @__oy<0 - @__ox -= @__bitmap.width*@__sprite.zoom_x if @__ox>@__bitmap.width - @__oy -= @__bitmap.height*@__sprite.zoom_y if @__oy>@__bitmap.height - dwidth = (Graphics.width/@__sprite.zoom_x+@borderX).to_i # +2 - dheight = (Graphics.height/@__sprite.zoom_y+@borderY).to_i # +2 - @__sprite.bitmap = ensureBitmap(@__sprite.bitmap,dwidth,dheight) - @__sprite.bitmap.clear - tileBitmap(@__sprite.bitmap,@__bitmap,@__bitmap.rect) - else - @__sprite.visible = false - end - end - end - - private - - def ensureBitmap(bitmap,dwidth,dheight) - if !bitmap || bitmap.disposed? || bitmap.width0; left -= srcbitmap.width; end - while top>0; top -= srcbitmap.height; end - y = top - while y255 - privRefresh - end - - def width=(value) - @width=value - privRefresh(true) - end - - def height=(value) - @height=value - privRefresh(true) - end - - def pause=(value) - @pause=value - @pauseopacity=0 if !value - privRefresh if @visible - end - - def x=(value) - @x=value - privRefresh if @visible - end - - def y=(value) - @y=value - privRefresh if @visible - end - - def zoom_x=(value) - @zoom_x=value - privRefresh if @visible - end - - def zoom_y=(value) - @zoom_y=value - privRefresh if @visible - end - - def offset_x=(value) - @x=value - privRefresh if @visible - end - - def offset_y=(value) - @y=value - privRefresh if @visible - end - - def opacity=(value) - @opacity=value - @opacity=0 if @opacity<0 - @opacity=255 if @opacity>255 - privRefresh if @visible - end - - def back_opacity=(value) - @back_opacity=value - @back_opacity=0 if @back_opacity<0 - @back_opacity=255 if @back_opacity>255 - privRefresh if @visible - end - - def contents_opacity=(value) - @contents_opacity=value - @contents_opacity=0 if @contents_opacity<0 - @contents_opacity=255 if @contents_opacity>255 - privRefresh if @visible - end - - def tone=(value) - @tone=value - privRefresh if @visible - end - - def color=(value) - @color=value - privRefresh if @visible - end - - def blend_type=(value) - @blend_type=value - privRefresh if @visible - end - - def flash(color,duration) - return if disposed? - @flash=duration+1 - for i in @sprites - i[1].flash(color,duration) - end - end - - def update - return if disposed? - mustchange=false - if @active - if @cursorblink==0 - @cursoropacity-=8 - @cursorblink=1 if @cursoropacity<=128 - else - @cursoropacity+=8 - @cursorblink=0 if @cursoropacity>=255 - end - privRefreshCursor - else - @cursoropacity=128 - privRefreshCursor - end - if @pause - oldpauseframe=@pauseframe - oldpauseopacity=@pauseopacity - @pauseframe=(Graphics.frame_count / 8) % 4 - @pauseopacity=[@pauseopacity+64,255].min - mustchange=@pauseframe!=oldpauseframe || @pauseopacity!=oldpauseopacity - end - privRefresh if mustchange - if @flash>0 - for i in @sprites.values - i.update - end - @flash-=1 - end - end - - ############# - attr_reader :skinformat - attr_reader :skinrect - - def loadSkinFile(_file) - if (self.windowskin.width==80 || self.windowskin.width==96) && - self.windowskin.height==48 - # Body = X, Y, width, height of body rectangle within windowskin - @skinrect.set(32,16,16,16) - # Trim = X, Y, width, height of trim rectangle within windowskin - @trim=[32,16,16,16] - elsif self.windowskin.width==80 && self.windowskin.height==80 - @skinrect.set(32,32,16,16) - @trim=[32,16,16,48] - end - end - - def windowskin=(value) - oldSkinWidth=(@_windowskin && !@_windowskin.disposed?) ? @_windowskin.width : -1 - oldSkinHeight=(@_windowskin && !@_windowskin.disposed?) ? @_windowskin.height : -1 - @_windowskin=value - if @skinformat==1 - @rpgvx=false - if @_windowskin && !@_windowskin.disposed? - if @_windowskin.width!=oldSkinWidth || @_windowskin.height!=oldSkinHeight - # Update skinrect and trim if windowskin's dimensions have changed - @skinrect.set((@_windowskin.width-16)/2,(@_windowskin.height-16)/2,16,16) - @trim=[@skinrect.x,@skinrect.y,@skinrect.x,@skinrect.y] - end - else - @skinrect.set(16,16,16,16) - @trim=[16,16,16,16] - end - else - if value && value.is_a?(Bitmap) && !value.disposed? && value.width==128 - @rpgvx=true - else - @rpgvx=false - end - @trim=[16,16,16,16] - end - privRefresh(true) - end - - def skinrect=(value) - @skinrect=value - privRefresh - end - - def skinformat=(value) - if @skinformat!=value - @skinformat=value - privRefresh(true) - end - end - - def borderX - return 32 if !@trim || skinformat==0 - if @_windowskin && !@_windowskin.disposed? - return @trim[0]+(@_windowskin.width-@trim[2]-@trim[0]) - end - return 32 - end - - def borderY - return 32 if !@trim || skinformat==0 - if @_windowskin && !@_windowskin.disposed? - return @trim[1]+(@_windowskin.height-@trim[3]-@trim[1]) - end - return 32 - end - - def leftEdge; self.startX; end - def topEdge; self.startY; end - def rightEdge; self.borderX-self.leftEdge; end - def bottomEdge; self.borderY-self.topEdge; end - - def startX - return !@trim || skinformat==0 ? 16 : @trim[0] - end - - def startY - return !@trim || skinformat==0 ? 16 : @trim[1] - end - - def endX - return !@trim || skinformat==0 ? 16 : @trim[2] - end - - def endY - return !@trim || skinformat==0 ? 16 : @trim[3] - end - - def startX=(value) - @trim[0]=value - privRefresh - end - - def startY=(value) - @trim[1]=value - privRefresh - end - - def endX=(value) - @trim[2]=value - privRefresh - end - - def endY=(value) - @trim[3]=value - privRefresh - end - - ############# - private - - def ensureBitmap(bitmap,dwidth,dheight) - if !bitmap||bitmap.disposed?||bitmap.width0 && @skinformat==0 && !@rpgvx - # Compatibility Mode: Cursor, pause, and contents have higher Z - @sprites["cursor"].z=@z+1 - @sprites["contents"].z=@z+2 - @sprites["pause"].z=@z+2 - end - if @skinformat==0 - startX=16 - startY=16 - endX=16 - endY=16 - trimStartX=16 - trimStartY=16 - trimWidth=32 - trimHeight=32 - if @rpgvx - trimX=64 - trimY=0 - backRect=Rect.new(0,0,64,64) - blindsRect=Rect.new(0,64,64,64) - else - trimX=128 - trimY=0 - backRect=Rect.new(0,0,128,128) - blindsRect=nil - end - if @_windowskin && !@_windowskin.disposed? - @sprites["corner0"].src_rect.set(trimX,trimY+0,16,16); - @sprites["corner1"].src_rect.set(trimX+48,trimY+0,16,16); - @sprites["corner2"].src_rect.set(trimX,trimY+48,16,16); - @sprites["corner3"].src_rect.set(trimX+48,trimY+48,16,16); - @sprites["scroll0"].src_rect.set(trimX+24, trimY+16, 16, 8) # up - @sprites["scroll3"].src_rect.set(trimX+24, trimY+40, 16, 8) # down - @sprites["scroll1"].src_rect.set(trimX+16, trimY+24, 8, 16) # left - @sprites["scroll2"].src_rect.set(trimX+40, trimY+24, 8, 16) # right - cursorX=trimX - cursorY=trimY+64 - sideRects=[ - Rect.new(trimX+16,trimY+0,32,16), - Rect.new(trimX,trimY+16,16,32), - Rect.new(trimX+48,trimY+16,16,32), - Rect.new(trimX+16,trimY+48,32,16) - ] - pauseRects=[ - trimX+32,trimY+64, - trimX+48,trimY+64, - trimX+32,trimY+80, - trimX+48,trimY+80, - ] - pauseWidth=16 - pauseHeight=16 - @sprites["pause"].src_rect.set( - pauseRects[@pauseframe*2], - pauseRects[@pauseframe*2+1], - pauseWidth,pauseHeight - ) - end - else - trimStartX=@trim[0] - trimStartY=@trim[1] - trimWidth=@trim[0]+(@skinrect.width-@trim[2]+@trim[0]) - trimHeight=@trim[1]+(@skinrect.height-@trim[3]+@trim[1]) - if @_windowskin && !@_windowskin.disposed? - # width of left end of window - startX=@skinrect.x - # width of top end of window - startY=@skinrect.y - cx=@skinrect.x+@skinrect.width # right side of BODY rect - cy=@skinrect.y+@skinrect.height # bottom side of BODY rect - # width of right end of window - endX=(!@_windowskin || @_windowskin.disposed?) ? @skinrect.x : @_windowskin.width-cx - # height of bottom end of window - endY=(!@_windowskin || @_windowskin.disposed?) ? @skinrect.y : @_windowskin.height-cy - @sprites["corner0"].src_rect.set(0,0,startX,startY); - @sprites["corner1"].src_rect.set(cx,0,endX,startY); - @sprites["corner2"].src_rect.set(0,cy,startX,endY); - @sprites["corner3"].src_rect.set(cx,cy,endX,endY); - backRect=Rect.new(@skinrect.x,@skinrect.y, - @skinrect.width,@skinrect.height); - blindsRect=nil - sideRects=[ - Rect.new(startX,0,@skinrect.width,startY), # side0 (top) - Rect.new(0,startY,startX,@skinrect.height), # side1 (left) - Rect.new(cx,startY,endX,@skinrect.height), # side2 (right) - Rect.new(startX,cy,@skinrect.width,endY) # side3 (bottom) - ] - end - end - if @width>trimWidth && @height>trimHeight - @sprites["contents"].src_rect.set(@ox,@oy,@width-trimWidth,@height-trimHeight) - else - @sprites["contents"].src_rect.set(0,0,0,0) - end - @sprites["contents"].x=@x+trimStartX - @sprites["contents"].y=@y+trimStartY - if (@compat & CompatBits::ShowScrollArrows)>0 && @skinformat==0 - # Compatibility mode: Make scroll arrows visible - if @skinformat==0 && @_windowskin && !@_windowskin.disposed? && - @contents && !@contents.disposed? - @sprites["scroll0"].visible = @visible && hascontents && @oy > 0 - @sprites["scroll1"].visible = @visible && hascontents && @ox > 0 - @sprites["scroll2"].visible = @visible && (@contents.width - @ox) > @width-trimWidth - @sprites["scroll3"].visible = @visible && (@contents.height - @oy) > @height-trimHeight - end - end - if @_windowskin && !@_windowskin.disposed? - borderX=startX+endX - borderY=startY+endY - @sprites["corner0"].x=@x - @sprites["corner0"].y=@y - @sprites["corner1"].x=@x+@width-endX - @sprites["corner1"].y=@y - @sprites["corner2"].x=@x - @sprites["corner2"].y=@y+@height-endY - @sprites["corner3"].x=@x+@width-endX - @sprites["corner3"].y=@y+@height-endY - @sprites["side0"].x=@x+startX - @sprites["side0"].y=@y - @sprites["side1"].x=@x - @sprites["side1"].y=@y+startY - @sprites["side2"].x=@x+@width-endX - @sprites["side2"].y=@y+startY - @sprites["side3"].x=@x+startX - @sprites["side3"].y=@y+@height-endY - @sprites["scroll0"].x = @x+@width / 2 - 8 - @sprites["scroll0"].y = @y+8 - @sprites["scroll1"].x = @x+8 - @sprites["scroll1"].y = @y+@height / 2 - 8 - @sprites["scroll2"].x = @x+@width - 16 - @sprites["scroll2"].y = @y+@height / 2 - 8 - @sprites["scroll3"].x = @x+@width / 2 - 8 - @sprites["scroll3"].y = @y+@height - 16 - @sprites["cursor"].x=@x+startX+@cursor_rect.x - @sprites["cursor"].y=@y+startY+@cursor_rect.y - if (@compat & CompatBits::ExpandBack)>0 && @skinformat==0 - # Compatibility mode: Expand background - @sprites["back"].x=@x+2 - @sprites["back"].y=@y+2 - else - @sprites["back"].x=@x+startX - @sprites["back"].y=@y+startY - end - end - if changeBitmap && @_windowskin && !@_windowskin.disposed? - if @skinformat==0 - @sprites["cursor"].x=@x+startX+@cursor_rect.x - @sprites["cursor"].y=@y+startY+@cursor_rect.y - width=@cursor_rect.width - height=@cursor_rect.height - if width > 0 && height > 0 - cursorrects=[ - # sides - Rect.new(cursorX+2, cursorY+0, 28, 2), - Rect.new(cursorX+0, cursorY+2, 2, 28), - Rect.new(cursorX+30, cursorY+2, 2, 28), - Rect.new(cursorX+2, cursorY+30, 28, 2), - # corners - Rect.new(cursorX+0, cursorY+0, 2, 2), - Rect.new(cursorX+30, cursorY+0, 2, 2), - Rect.new(cursorX+0, cursorY+30, 2, 2), - Rect.new(cursorX+30, cursorY+30, 2, 2), - # back - Rect.new(cursorX+2, cursorY+2, 28, 28) - ] - margin=2 - fullmargin=4 - @cursorbitmap = ensureBitmap(@cursorbitmap, width, height) - @cursorbitmap.clear - @sprites["cursor"].bitmap=@cursorbitmap - @sprites["cursor"].src_rect.set(0,0,width,height) - rect = Rect.new(margin,margin,width - fullmargin, height - fullmargin) - @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[8]) - @cursorbitmap.blt(0, 0, @_windowskin, cursorrects[4])# top left - @cursorbitmap.blt(width-margin, 0, @_windowskin, cursorrects[5]) # top right - @cursorbitmap.blt(0, height-margin, @_windowskin, cursorrects[6]) # bottom right - @cursorbitmap.blt(width-margin, height-margin, @_windowskin, cursorrects[7]) # bottom left - rect = Rect.new(margin, 0,width - fullmargin, margin) - @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[0]) - rect = Rect.new(0, margin,margin, height - fullmargin) - @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[1]) - rect = Rect.new(width - margin, margin, margin, height - fullmargin) - @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[2]) - rect = Rect.new(margin, height-margin, width - fullmargin, margin) - @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[3]) - else - @sprites["cursor"].visible=false - @sprites["cursor"].src_rect.set(0,0,0,0) - end - end - for i in 0..3 - case i - when 0 - dwidth = @width-startX-endX - dheight = startY - when 1 - dwidth = startX - dheight = @height-startY-endY - when 2 - dwidth = endX - dheight = @height-startY-endY - when 3 - dwidth = @width-startX-endX - dheight = endY - end - @sidebitmaps[i]=ensureBitmap(@sidebitmaps[i],dwidth,dheight) - @sprites["side#{i}"].bitmap=@sidebitmaps[i] - @sprites["side#{i}"].src_rect.set(0,0,dwidth,dheight) - @sidebitmaps[i].clear - if sideRects[i].width>0 && sideRects[i].height>0 - if (@compat & CompatBits::StretchSides)>0 && @skinformat==0 - # Compatibility mode: Stretch sides - @sidebitmaps[i].stretch_blt(@sprites["side#{i}"].src_rect, - @_windowskin,sideRects[i]) - else - tileBitmap(@sidebitmaps[i],@sprites["side#{i}"].src_rect, - @_windowskin,sideRects[i]) - end - end - end - if (@compat & CompatBits::ExpandBack)>0 && @skinformat==0 - # Compatibility mode: Expand background - backwidth=@width-4 - backheight=@height-4 - else - backwidth=@width-borderX - backheight=@height-borderY - end - if backwidth>0 && backheight>0 - @backbitmap=ensureBitmap(@backbitmap,backwidth,backheight) - @sprites["back"].bitmap=@backbitmap - @sprites["back"].src_rect.set(0,0,backwidth,backheight) - @backbitmap.clear - if @stretch - @backbitmap.stretch_blt(@sprites["back"].src_rect,@_windowskin,backRect) - else - tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,backRect) - end - if blindsRect - tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,blindsRect) - end - else - @sprites["back"].visible=false - @sprites["back"].src_rect.set(0,0,0,0) - end - end - if @openness!=255 - opn=@openness/255.0 - for k in @spritekeys - sprite=@sprites[k] - ratio=(@height<=0) ? 0 : (sprite.y-@y)*1.0/@height - sprite.zoom_y=opn - sprite.zoom_x=1.0 - sprite.oy=0 - sprite.y=(@y+(@height/2.0)+(@height*ratio*opn)-(@height/2*opn)).floor - end - else - for k in @spritekeys - sprite=@sprites[k] - sprite.zoom_x=1.0 - sprite.zoom_y=1.0 - end - end - i=0 - # Ensure Z order - for k in @spritekeys - sprite=@sprites[k] - y=sprite.y - sprite.y=i - sprite.oy=(sprite.zoom_y<=0) ? 0 : (i-y)/sprite.zoom_y - sprite.zoom_x*=@zoom_x - sprite.zoom_y*=@zoom_y - sprite.x*=@zoom_x - sprite.y*=@zoom_y - sprite.x+=(@offset_x/sprite.zoom_x) - sprite.y+=(@offset_y/sprite.zoom_y) - end - end -end - - - -#=============================================================================== -# -#=============================================================================== -class SpriteWindow_Base < SpriteWindow - TEXTPADDING=4 # In pixels - - def initialize(x, y, width, height) - super() - self.x = x - self.y = y - self.width = width - self.height = height - self.z = 100 - @curframe=MessageConfig.pbGetSystemFrame() - @curfont=MessageConfig.pbGetSystemFontName() - @sysframe=AnimatedBitmap.new(@curframe) - @customskin=nil - __setWindowskin(@sysframe.bitmap) - __resolveSystemFrame() - pbSetSystemFont(self.contents) if self.contents - end - - def __setWindowskin(skin) - if skin && (skin.width==192 && skin.height==128) || # RPGXP Windowskin - (skin.width==128 && skin.height==128) # RPGVX Windowskin - self.skinformat=0 - else - self.skinformat=1 - end - self.windowskin=skin - end - - def __resolveSystemFrame - if self.skinformat==1 - if !@resolvedFrame - @resolvedFrame=MessageConfig.pbGetSystemFrame() - @resolvedFrame.sub!(/\.[^\.\/\\]+$/,"") - end - self.loadSkinFile("#{@resolvedFrame}.txt") if @resolvedFrame!="" - end - end - - def setSkin(skin) # Filename of windowskin to apply. Supports XP, VX, and animated skins. - @customskin.dispose if @customskin - @customskin=nil - resolvedName=pbResolveBitmap(skin) - return if !resolvedName || resolvedName=="" - @customskin=AnimatedBitmap.new(resolvedName) - __setWindowskin(@customskin.bitmap) - if self.skinformat==1 - skinbase=resolvedName.sub(/\.[^\.\/\\]+$/,"") - self.loadSkinFile("#{skinbase}.txt") - end - end - - def setSystemFrame - @customskin.dispose if @customskin - @customskin=nil - __setWindowskin(@sysframe.bitmap) - __resolveSystemFrame() - end - - def update - super - if self.windowskin - if @customskin - if @customskin.totalFrames>1 - @customskin.update - __setWindowskin(@customskin.bitmap) - end - elsif @sysframe - if @sysframe.totalFrames>1 - @sysframe.update - __setWindowskin(@sysframe.bitmap) - end - end - end - if @curframe!=MessageConfig.pbGetSystemFrame() - @curframe=MessageConfig.pbGetSystemFrame() - if @sysframe && !@customskin - @sysframe.dispose if @sysframe - @sysframe=AnimatedBitmap.new(@curframe) - @resolvedFrame=nil - __setWindowskin(@sysframe.bitmap) - __resolveSystemFrame() - end - begin - refresh - rescue NoMethodError - end - end - if @curfont!=MessageConfig.pbGetSystemFontName() - @curfont=MessageConfig.pbGetSystemFontName() - if self.contents && !self.contents.disposed? - pbSetSystemFont(self.contents) - end - begin - refresh - rescue NoMethodError - end - end - end - - def dispose - self.contents.dispose if self.contents - @sysframe.dispose - @customskin.dispose if @customskin - super - end -end - - - #=============================================================================== # #=============================================================================== diff --git a/Data/Scripts/009_Objects and windows/006_SpriteWindow_pictures.rb b/Data/Scripts/009_Objects and windows/006_SpriteWindow_pictures.rb new file mode 100644 index 000000000..33a367d0e --- /dev/null +++ b/Data/Scripts/009_Objects and windows/006_SpriteWindow_pictures.rb @@ -0,0 +1,121 @@ +#=============================================================================== +# Displays an icon bitmap in a window. Supports animated images. +#=============================================================================== +class IconWindow < SpriteWindow_Base + attr_reader :name + + def initialize(x,y,width,height,viewport=nil) + super(x,y,width,height) + self.viewport=viewport + self.contents=nil + @name="" + @_iconbitmap=nil + end + + def dispose + clearBitmaps() + super + end + + def update + super + if @_iconbitmap + @_iconbitmap.update + self.contents=@_iconbitmap.bitmap + end + end + + def clearBitmaps + @_iconbitmap.dispose if @_iconbitmap + @_iconbitmap=nil + self.contents=nil if !self.disposed? + end + + # Sets the icon's filename. Alias for setBitmap. + def name=(value) + setBitmap(value) + end + + # Sets the icon's filename. + def setBitmap(file,hue=0) + clearBitmaps() + @name=file + return if file==nil + if file!="" + @_iconbitmap=AnimatedBitmap.new(file,hue) + # for compatibility + self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil + else + @_iconbitmap=nil + end + end +end + + + +#=============================================================================== +# Displays an icon bitmap in a window. Supports animated images. +# Accepts bitmaps and paths to bitmap files in its constructor. +#=============================================================================== +class PictureWindow < SpriteWindow_Base + def initialize(pathOrBitmap) + super(0,0,32,32) + self.viewport=viewport + self.contents=nil + @_iconbitmap=nil + setBitmap(pathOrBitmap) + end + + def dispose + clearBitmaps() + super + end + + def update + super + if @_iconbitmap + if @_iconbitmap.is_a?(Bitmap) + self.contents=@_iconbitmap + else + @_iconbitmap.update + self.contents=@_iconbitmap.bitmap + end + end + end + + def clearBitmaps + @_iconbitmap.dispose if @_iconbitmap + @_iconbitmap=nil + self.contents=nil if !self.disposed? + end + + # Sets the icon's bitmap or filename. (hue parameter + # is ignored unless pathOrBitmap is a filename) + def setBitmap(pathOrBitmap,hue=0) + clearBitmaps() + if pathOrBitmap!=nil && pathOrBitmap!="" + if pathOrBitmap.is_a?(Bitmap) + @_iconbitmap=pathOrBitmap + self.contents=@_iconbitmap + self.width=@_iconbitmap.width+self.borderX + self.height=@_iconbitmap.height+self.borderY + elsif pathOrBitmap.is_a?(AnimatedBitmap) + @_iconbitmap=pathOrBitmap + self.contents=@_iconbitmap.bitmap + self.width=@_iconbitmap.bitmap.width+self.borderX + self.height=@_iconbitmap.bitmap.height+self.borderY + else + @_iconbitmap=AnimatedBitmap.new(pathOrBitmap,hue) + self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil + self.width=@_iconbitmap ? @_iconbitmap.bitmap.width+self.borderX : + 32+self.borderX + self.height=@_iconbitmap ? @_iconbitmap.bitmap.height+self.borderY : + 32+self.borderY + end + else + @_iconbitmap=nil + self.width=32+self.borderX + self.height=32+self.borderY + end + end +end diff --git a/Data/Scripts/009_Objects and windows/007_SpriteWrapper.rb b/Data/Scripts/009_Objects and windows/007_SpriteWrapper.rb new file mode 100644 index 000000000..84ab380e2 --- /dev/null +++ b/Data/Scripts/009_Objects and windows/007_SpriteWrapper.rb @@ -0,0 +1,359 @@ +#=============================================================================== +# SpriteWrapper is a class based on Sprite which wraps Sprite's properties. +#=============================================================================== +class SpriteWrapper < Sprite + def initialize(viewport=nil) + @sprite = Sprite.new(viewport) + end + + def dispose; @sprite.dispose; end + def disposed?; return @sprite.disposed?; end + def viewport; return @sprite.viewport; end + def flash(color,duration); return @sprite.flash(color,duration); end + def update; return @sprite.update; end + def x; @sprite.x; end + def x=(value); @sprite.x = value; end + def y; @sprite.y; end + def y=(value); @sprite.y = value; end + def bitmap; @sprite.bitmap; end + def bitmap=(value); @sprite.bitmap = value; end + def src_rect; @sprite.src_rect; end + def src_rect=(value); @sprite.src_rect = value; end + def visible; @sprite.visible; end + def visible=(value); @sprite.visible = value; end + def z; @sprite.z; end + def z=(value); @sprite.z = value; end + def ox; @sprite.ox; end + def ox=(value); @sprite.ox = value; end + def oy; @sprite.oy; end + def oy=(value); @sprite.oy = value; end + def zoom_x; @sprite.zoom_x; end + def zoom_x=(value); @sprite.zoom_x = value; end + def zoom_y; @sprite.zoom_y; end + def zoom_y=(value); @sprite.zoom_y = value; end + def angle; @sprite.angle; end + def angle=(value); @sprite.angle = value; end + def mirror; @sprite.mirror; end + def mirror=(value); @sprite.mirror = value; end + def bush_depth; @sprite.bush_depth; end + def bush_depth=(value); @sprite.bush_depth = value; end + def opacity; @sprite.opacity; end + def opacity=(value); @sprite.opacity = value; end + def blend_type; @sprite.blend_type; end + def blend_type=(value); @sprite.blend_type = value; end + def color; @sprite.color; end + def color=(value); @sprite.color = value; end + def tone; @sprite.tone; end + def tone=(value); @sprite.tone = value; end + + def viewport=(value) + return if self.viewport==value + bitmap = @sprite.bitmap + src_rect = @sprite.src_rect + visible = @sprite.visible + x = @sprite.x + y = @sprite.y + z = @sprite.z + ox = @sprite.ox + oy = @sprite.oy + zoom_x = @sprite.zoom_x + zoom_y = @sprite.zoom_y + angle = @sprite.angle + mirror = @sprite.mirror + bush_depth = @sprite.bush_depth + opacity = @sprite.opacity + blend_type = @sprite.blend_type + color = @sprite.color + tone = @sprite.tone + @sprite.dispose + @sprite = Sprite.new(value) + @sprite.bitmap = bitmap + @sprite.src_rect = src_rect + @sprite.visible = visible + @sprite.x = x + @sprite.y = y + @sprite.z = z + @sprite.ox = ox + @sprite.oy = oy + @sprite.zoom_x = zoom_x + @sprite.zoom_y = zoom_y + @sprite.angle = angle + @sprite.mirror = mirror + @sprite.bush_depth = bush_depth + @sprite.opacity = opacity + @sprite.blend_type = blend_type + @sprite.color = color + @sprite.tone = tone + end +end + + + +#=============================================================================== +# Sprite class that maintains a bitmap of its own. +# This bitmap can't be changed to a different one. +#=============================================================================== +class BitmapSprite < SpriteWrapper + def initialize(width,height,viewport=nil) + super(viewport) + self.bitmap=Bitmap.new(width,height) + @initialized=true + end + + def bitmap=(value) + super(value) if !@initialized + end + + def dispose + self.bitmap.dispose if !self.disposed? + super + end +end + + + +#=============================================================================== +# +#=============================================================================== +class AnimatedSprite < SpriteWrapper + attr_reader :frame + attr_reader :framewidth + attr_reader :frameheight + attr_reader :framecount + attr_reader :animname + + def initializeLong(animname,framecount,framewidth,frameheight,frameskip) + @animname=pbBitmapName(animname) + @realframes=0 + @frameskip=[1,frameskip].max + @frameskip *= Graphics.frame_rate/20 + raise _INTL("Frame width is 0") if framewidth==0 + raise _INTL("Frame height is 0") if frameheight==0 + begin + @animbitmap=AnimatedBitmap.new(animname).deanimate + rescue + @animbitmap=Bitmap.new(framewidth,frameheight) + end + if @animbitmap.width%framewidth!=0 + raise _INTL("Bitmap's width ({1}) is not a multiple of frame width ({2}) [Bitmap={3}]", + @animbitmap.width,framewidth,animname) + end + if @animbitmap.height%frameheight!=0 + raise _INTL("Bitmap's height ({1}) is not a multiple of frame height ({2}) [Bitmap={3}]", + @animbitmap.height,frameheight,animname) + end + @framecount=framecount + @framewidth=framewidth + @frameheight=frameheight + @framesperrow=@animbitmap.width/@framewidth + @playing=false + self.bitmap=@animbitmap + self.src_rect.width=@framewidth + self.src_rect.height=@frameheight + self.frame=0 + end + + # Shorter version of AnimationSprite. All frames are placed on a single row + # of the bitmap, so that the width and height need not be defined beforehand + def initializeShort(animname,framecount,frameskip) + @animname=pbBitmapName(animname) + @realframes=0 + @frameskip=[1,frameskip].max + @frameskip *= Graphics.frame_rate/20 + begin + @animbitmap=AnimatedBitmap.new(animname).deanimate + rescue + @animbitmap=Bitmap.new(framecount*4,32) + end + if @animbitmap.width%framecount!=0 + raise _INTL("Bitmap's width ({1}) is not a multiple of frame count ({2}) [Bitmap={3}]", + @animbitmap.width,framewidth,animname) + end + @framecount=framecount + @framewidth=@animbitmap.width/@framecount + @frameheight=@animbitmap.height + @framesperrow=framecount + @playing=false + self.bitmap=@animbitmap + self.src_rect.width=@framewidth + self.src_rect.height=@frameheight + self.frame=0 + end + + def initialize(*args) + if args.length==1 + super(args[0][3]) + initializeShort(args[0][0],args[0][1],args[0][2]) + else + super(args[5]) + initializeLong(args[0],args[1],args[2],args[3],args[4]) + end + end + + def self.create(animname,framecount,frameskip,viewport=nil) + return self.new([animname,framecount,frameskip,viewport]) + end + + def dispose + return if disposed? + @animbitmap.dispose + @animbitmap=nil + super + end + + def playing? + return @playing + end + + def frame=(value) + @frame=value + @realframes=0 + self.src_rect.x=@frame%@framesperrow*@framewidth + self.src_rect.y=@frame/@framesperrow*@frameheight + end + + def start + @playing=true + @realframes=0 + end + + alias play start + + def stop + @playing=false + end + + def update + super + if @playing + @realframes+=1 + if @realframes==@frameskip + @realframes=0 + self.frame+=1 + self.frame%=self.framecount + end + end + end +end + + + +#=============================================================================== +# Displays an icon bitmap in a sprite. Supports animated images. +#=============================================================================== +class IconSprite < SpriteWrapper + attr_reader :name + + def initialize(*args) + if args.length==0 + super(nil) + self.bitmap=nil + elsif args.length==1 + super(args[0]) + self.bitmap=nil + elsif args.length==2 + super(nil) + self.x=args[0] + self.y=args[1] + else + super(args[2]) + self.x=args[0] + self.y=args[1] + end + @name="" + @_iconbitmap=nil + end + + def dispose + clearBitmaps() + super + end + + # Sets the icon's filename. Alias for setBitmap. + def name=(value) + setBitmap(value) + end + + # Sets the icon's filename. + def setBitmap(file,hue=0) + oldrc=self.src_rect + clearBitmaps() + @name=file + return if file==nil + if file!="" + @_iconbitmap=AnimatedBitmap.new(file,hue) + # for compatibility + self.bitmap=@_iconbitmap ? @_iconbitmap.bitmap : nil + self.src_rect=oldrc + else + @_iconbitmap=nil + end + end + + def clearBitmaps + @_iconbitmap.dispose if @_iconbitmap + @_iconbitmap=nil + self.bitmap=nil if !self.disposed? + end + + def update + super + return if !@_iconbitmap + @_iconbitmap.update + if self.bitmap!=@_iconbitmap.bitmap + oldrc=self.src_rect + self.bitmap=@_iconbitmap.bitmap + self.src_rect=oldrc + end + end +end + + + +#=============================================================================== +# Old GifSprite class, retained for compatibility +#=============================================================================== +class GifSprite < IconSprite + def initialize(path) + super(0,0) + setBitmap(path) + end +end + + + +#=============================================================================== +# SpriteWrapper that stores multiple bitmaps, and displays only one at once. +#=============================================================================== +class ChangelingSprite < SpriteWrapper + def initialize(x=0,y=0,viewport=nil) + super(viewport) + self.x = x + self.y = y + @bitmaps = {} + @currentBitmap = nil + end + + def addBitmap(key,path) + @bitmaps[key].dispose if @bitmaps[key] + @bitmaps[key] = AnimatedBitmap.new(path) + end + + def changeBitmap(key) + @currentBitmap = @bitmaps[key] + self.bitmap = (@currentBitmap) ? @currentBitmap.bitmap : nil + end + + def dispose + return if disposed? + for bm in @bitmaps.values; bm.dispose; end + @bitmaps.clear + super + end + + def update + return if disposed? + for bm in @bitmaps.values; bm.update; end + self.bitmap = (@currentBitmap) ? @currentBitmap.bitmap : nil + end +end diff --git a/Data/Scripts/009_Objects and windows/008_AnimatedBitmap.rb b/Data/Scripts/009_Objects and windows/008_AnimatedBitmap.rb new file mode 100644 index 000000000..3791a738f --- /dev/null +++ b/Data/Scripts/009_Objects and windows/008_AnimatedBitmap.rb @@ -0,0 +1,363 @@ +module GifLibrary + @@loadlib = Win32API.new("Kernel32.dll","LoadLibrary",'p','') + if safeExists?("gif.dll") + PngDll = @@loadlib.call("gif.dll") + GifToPngFiles = Win32API.new("gif.dll","GifToPngFiles",'pp','l') + GifToPngFilesInMemory = Win32API.new("gif.dll","GifToPngFilesInMemory",'plp','l') + CopyDataString = Win32API.new("gif.dll","CopyDataString",'lpl','l') + FreeDataString = Win32API.new("gif.dll","FreeDataString",'l','') + else + PngDll=nil + end + + def self.getDataFromResult(result) + datasize=CopyDataString.call(result,"",0) + ret=nil + if datasize!=0 + data="0"*datasize + CopyDataString.call(result,data,datasize) + ret=data.unpack("V*") + end + FreeDataString.call(result) + return ret + end +end + + + +class AnimatedBitmap + def initialize(file,hue=0) + if file==nil + raise "Filename is nil (missing graphic)\r\n\r\n"+ + "If you see this error in the Continue/New Game screen, you may be loading another game's save file. "+ + "Check your project's title (\"Game > Change Title...\" in RMXP).\r\n" + end + if file.split(/[\\\/]/)[-1][/^\[\d+(?:,\d+)?]/] # Starts with 1 or more digits in square brackets + @bitmap = PngAnimatedBitmap.new(file,hue) + else + @bitmap = GifBitmap.new(file,hue) + end + end + + def [](index); @bitmap[index]; end + def width; @bitmap.bitmap.width; end + def height; @bitmap.bitmap.height; end + def length; @bitmap.length; end + def each; @bitmap.each { |item| yield item }; end + def bitmap; @bitmap.bitmap; end + def currentIndex; @bitmap.currentIndex; end + def frameDelay; @bitmap.frameDelay; end + def totalFrames; @bitmap.totalFrames; end + def disposed?; @bitmap.disposed?; end + def update; @bitmap.update; end + def dispose; @bitmap.dispose; end + def deanimate; @bitmap.deanimate; end + def copy; @bitmap.copy; end +end + + + +class PngAnimatedBitmap + # Creates an animated bitmap from a PNG file. + def initialize(file,hue=0) + @frames=[] + @currentFrame=0 + @framecount=0 + panorama=BitmapCache.load_bitmap(file,hue) + if file.split(/[\\\/]/)[-1][/^\[(\d+)(?:,(\d+))?]/] # Starts with 1 or more digits in brackets + # File has a frame count + numFrames = $1.to_i + delay = $2.to_i + delay = 10 if delay == 0 + raise "Invalid frame count in #{file}" if numFrames<=0 + raise "Invalid frame delay in #{file}" if delay<=0 + if panorama.width % numFrames != 0 + raise "Bitmap's width (#{panorama.width}) is not divisible by frame count: #{file}" + end + @frameDelay = delay + subWidth=panorama.width/numFrames + for i in 0...numFrames + subBitmap=BitmapWrapper.new(subWidth,panorama.height) + subBitmap.blt(0,0,panorama,Rect.new(subWidth*i,0,subWidth,panorama.height)) + @frames.push(subBitmap) + end + panorama.dispose + else + @frames=[panorama] + end + end + + def [](index) + return @frames[index] + end + + def width; self.bitmap.width; end + + def height; self.bitmap.height; end + + def deanimate + for i in 1...@frames.length + @frames[i].dispose + end + @frames=[@frames[0]] + @currentFrame=0 + return @frames[0] + end + + def bitmap + @frames[@currentFrame] + end + + def currentIndex + @currentFrame + end + + def frameDelay(_index) + return @frameDelay + end + + def length + @frames.length + end + + def each + @frames.each { |item| yield item} + end + + def totalFrames + @frameDelay*@frames.length + end + + def disposed? + @disposed + end + + def update + return if disposed? + if @frames.length>1 + @framecount+=1 + if @framecount>=@frameDelay + @framecount=0 + @currentFrame+=1 + @currentFrame%=@frames.length + end + end + end + + def dispose + if !@disposed + for i in @frames + i.dispose + end + end + @disposed=true + end + + attr_accessor :frames # internal + + def copy + x=self.clone + x.frames=x.frames.clone + for i in 0...x.frames.length + x.frames[i]=x.frames[i].copy + end + return x + end +end + + + +#internal class +class GifBitmap + # Creates a bitmap from a GIF file with the specified + # optional viewport. Can also load non-animated bitmaps. + def initialize(file,hue=0) + @gifbitmaps=[] + @gifdelays=[] + @totalframes=0 + @framecount=0 + @currentIndex=0 + @disposed=false + bitmap=nil + filestring=nil + filestrName=nil + file="" if !file + file=canonicalize(file) + begin + bitmap=BitmapCache.load_bitmap(file,hue) + rescue + bitmap=nil + end + if !bitmap || (bitmap.width==32 && bitmap.height==32) + if !file || file.length<1 || file[file.length-1]!=0x2F + if (filestring=pbGetFileChar(file)) + filestrName=file + elsif (filestring=pbGetFileChar(file+".gif")) + filestrName=file+".gif" + elsif (filestring=pbGetFileChar(file+".png")) + filestrName=file+".png" + elsif (filestring=pbGetFileChar(file+".jpg")) + filestrName=file+".jpg" + elsif (filestring=pbGetFileChar(file+".bmp")) + filestrName=file+".bmp" + end + end + end + if bitmap && filestring && filestring[0]==0x47 && + bitmap.width==32 && bitmap.height==32 + #File.open("debug.txt","ab") { |f| f.puts("rejecting bitmap") } + bitmap.dispose + bitmap=nil + end + if bitmap + #File.open("debug.txt","ab") { |f| f.puts("reusing bitmap") } + # Have a regular non-animated bitmap + @totalframes=1 + @framecount=0 + @gifbitmaps=[bitmap] + @gifdelays=[1] + else + tmpBase=File.basename(file)+"_tmp_" + filestring=pbGetFileString(filestrName) if filestring + Dir.chdir(ENV["TEMP"]) { # navigate to temp folder since game might be on a CD-ROM + if filestring && filestring[0]==0x47 && GifLibrary::PngDll + result=GifLibrary::GifToPngFilesInMemory.call(filestring, + filestring.length,tmpBase) + else + result=0 + end + if result>0 + @gifdelays=GifLibrary.getDataFromResult(result) + @totalframes=@gifdelays.pop + for i in 0...@gifdelays.length + @gifdelays[i]=[@gifdelays[i],1].max + bmfile=sprintf("%s%d.png",tmpBase,i) + if safeExists?(bmfile) + gifbitmap=BitmapWrapper.new(bmfile) + @gifbitmaps.push(gifbitmap) + bmfile.hue_change(hue) if hue!=0 + if hue==0 && @gifdelays.length==1 + BitmapCache.setKey(file,gifbitmap) + end + File.delete(bmfile) + else + @gifbitmaps.push(BitmapWrapper.new(32,32)) + end + end + end + } + if @gifbitmaps.length==0 + @gifbitmaps=[BitmapWrapper.new(32,32)] + @gifdelays=[1] + end + if @gifbitmaps.length==1 + BitmapCache.setKey(file,@gifbitmaps[0]) + end + end + end + + def [](index) + return @gifbitmaps[index] + end + + def deanimate + for i in 1...@gifbitmaps.length + @gifbitmaps[i].dispose + end + @gifbitmaps=[@gifbitmaps[0]] + @currentIndex=0 + return @gifbitmaps[0] + end + + def bitmap + @gifbitmaps[@currentIndex] + end + + def currentIndex + @currentIndex + end + + def frameDelay(index) + return @gifdelay[index]/2 # Due to frame count being incremented by 2 + end + + def length + @gifbitmaps.length + end + + def each + @gifbitmaps.each { |item| yield item } + end + + def totalFrames + @totalframes/2 # Due to frame count being incremented by 2 + end + + def disposed? + @disposed + end + + def width + @gifbitmaps.length==0 ? 0 : @gifbitmaps[0].width + end + + def height + @gifbitmaps.length==0 ? 0 : @gifbitmaps[0].height + end + + # This function must be called in order to animate the GIF image. + def update + return if disposed? + if @gifbitmaps.length>0 + @framecount+=2 + @framecount=@totalframes<=0 ? 0 : @framecount%@totalframes + frametoshow=0 + for i in 0...@gifdelays.length + frametoshow=i if @gifdelays[i]<=@framecount + end + @currentIndex=frametoshow + end + end + + def dispose + if !@disposed + for i in @gifbitmaps + i.dispose + end + end + @disposed=true + end + + attr_accessor :gifbitmaps # internal + attr_accessor :gifdelays # internal + + def copy + x=self.clone + x.gifbitmaps=x.gifbitmaps.clone + x.gifdelays=x.gifdelays.clone + for i in 0...x.gifbitmaps.length + x.gifbitmaps[i]=x.gifbitmaps[i].copy + end + return x + end +end + + + +def pbGetTileBitmap(filename, tile_id, hue) + return BitmapCache.tileEx(filename, tile_id, hue) { |f| + AnimatedBitmap.new("Graphics/Tilesets/"+filename).deanimate + } +end + +def pbGetTileset(name,hue=0) + return AnimatedBitmap.new("Graphics/Tilesets/"+name,hue).deanimate +end + +def pbGetAutotile(name,hue=0) + return AnimatedBitmap.new("Graphics/Autotiles/"+name,hue).deanimate +end + +def pbGetAnimation(name,hue=0) + return AnimatedBitmap.new("Graphics/Animations/"+name,hue).deanimate +end diff --git a/Data/Scripts/009_Objects and windows/009_Planes.rb b/Data/Scripts/009_Objects and windows/009_Planes.rb new file mode 100644 index 000000000..4a15d3f89 --- /dev/null +++ b/Data/Scripts/009_Objects and windows/009_Planes.rb @@ -0,0 +1,232 @@ +#=============================================================================== +# +#=============================================================================== +class Plane + def update; end + def refresh; end +end + + + +#=============================================================================== +# This class works around a limitation that planes are always +# 640 by 480 pixels in size regardless of the window's size. +#=============================================================================== +class LargePlane < Plane + attr_accessor :borderX + attr_accessor :borderY + + def initialize(viewport=nil) + @__sprite=Sprite.new(viewport) + @__disposed=false + @__ox=0 + @__oy=0 + @__bitmap=nil + @__visible=true + @__sprite.visible=false + @borderX=0 + @borderY=0 + end + + def disposed? + return @__disposed + end + + def dispose + if !@__disposed + @__sprite.bitmap.dispose if @__sprite.bitmap + @__sprite.dispose + @__sprite=nil + @__bitmap=nil + @__disposed=true + end + super + end + + def ox; @__ox; end + def oy; @__oy; end + + def ox=(value); + return if @__ox==value + @__ox = value + refresh + end + + def oy=(value); + return if @__oy==value + @__oy = value + refresh + end + + def bitmap + return @__bitmap + end + + def bitmap=(value) + if value==nil + if @__bitmap!=nil + @__bitmap=nil + @__sprite.visible=(@__visible && !@__bitmap.nil?) + end + elsif @__bitmap!=value && !value.disposed? + @__bitmap=value + refresh + elsif value.disposed? + if @__bitmap!=nil + @__bitmap=nil + @__sprite.visible=(@__visible && !@__bitmap.nil?) + end + end + end + + def viewport; @__sprite.viewport; end + def zoom_x; @__sprite.zoom_x; end + def zoom_y; @__sprite.zoom_y; end + def opacity; @__sprite.opacity; end + def blend_type; @__sprite.blend_type; end + def visible; @__visible; end + def z; @__sprite.z; end + def color; @__sprite.color; end + def tone; @__sprite.tone; end + + def zoom_x=(v); + return if @__sprite.zoom_x==v + @__sprite.zoom_x = v + refresh + end + + def zoom_y=(v); + return if @__sprite.zoom_y==v + @__sprite.zoom_y = v + refresh + end + + def opacity=(v); @__sprite.opacity=(v); end + def blend_type=(v); @__sprite.blend_type=(v); end + def visible=(v); @__visible=v; @__sprite.visible=(@__visible && !@__bitmap.nil?); end + def z=(v); @__sprite.z=(v); end + def color=(v); @__sprite.color=(v); end + def tone=(v); @__sprite.tone=(v); end + def update; ;end + + def refresh + @__sprite.visible = (@__visible && !@__bitmap.nil?) + if @__bitmap + if !@__bitmap.disposed? + @__ox += @__bitmap.width*@__sprite.zoom_x if @__ox<0 + @__oy += @__bitmap.height*@__sprite.zoom_y if @__oy<0 + @__ox -= @__bitmap.width*@__sprite.zoom_x if @__ox>@__bitmap.width + @__oy -= @__bitmap.height*@__sprite.zoom_y if @__oy>@__bitmap.height + dwidth = (Graphics.width/@__sprite.zoom_x+@borderX).to_i # +2 + dheight = (Graphics.height/@__sprite.zoom_y+@borderY).to_i # +2 + @__sprite.bitmap = ensureBitmap(@__sprite.bitmap,dwidth,dheight) + @__sprite.bitmap.clear + tileBitmap(@__sprite.bitmap,@__bitmap,@__bitmap.rect) + else + @__sprite.visible = false + end + end + end + + private + + def ensureBitmap(bitmap,dwidth,dheight) + if !bitmap || bitmap.disposed? || bitmap.width0; left -= srcbitmap.width; end + while top>0; top -= srcbitmap.height; end + y = top + while y") text.gsub!(/\\r/i,"") + text.gsub!(/\\[Ww]\[([^\]]*)\]/) { + w = $1.to_s + if w=="" + msgwindow.windowskin = nil + else + msgwindow.setSkin("Graphics/Windowskins/#{w}",false) + end + next "" + } isDarkSkin = isDarkWindowskin(msgwindow.windowskin) text.gsub!(/\\[Cc]\[([0-9]+)\]/) { m = $1.to_i @@ -951,7 +960,7 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil) ### Controls textchunks=[] controls=[] - while text[/(?:\\(w|f|ff|ts|cl|me|se|wt|wtnp|ch)\[([^\]]*)\]|\\(g|cn|wd|wm|op|cl|wu|\.|\||\!|\^))/i] + while text[/(?:\\(f|ff|ts|cl|me|se|wt|wtnp|ch)\[([^\]]*)\]|\\(g|cn|wd|wm|op|cl|wu|\.|\||\!|\^))/i] textchunks.push($~.pre_match) if $~[1] controls.push([$~[1].downcase,$~[2],-1]) @@ -1086,12 +1095,6 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil) msgback.y = msgwindow.y if msgback pbPositionNearMsgWindow(facewindow,msgwindow,:left) msgwindow.y = Graphics.height-msgwindow.height*(signWaitTime-signWaitCount)/signWaitTime - when "w" # Change windowskin - if param=="" - msgwindow.windowskin = nil - else - msgwindow.setSkin("Graphics/Windowskins/#{param}",false) - end when "ts" # Change text speed msgwindow.textspeed = (param=="") ? -999 : param.to_i when "." # Wait 0.25 seconds diff --git a/Data/Scripts/009_Objects and windows/008_TextEntry.rb b/Data/Scripts/009_Objects and windows/012_TextEntry.rb similarity index 100% rename from Data/Scripts/009_Objects and windows/008_TextEntry.rb rename to Data/Scripts/009_Objects and windows/012_TextEntry.rb diff --git a/Data/Scripts/009_Objects and windows/009_PictureEx.rb b/Data/Scripts/009_Objects and windows/013_PictureEx.rb similarity index 99% rename from Data/Scripts/009_Objects and windows/009_PictureEx.rb rename to Data/Scripts/009_Objects and windows/013_PictureEx.rb index 99dad9e56..404924d91 100644 --- a/Data/Scripts/009_Objects and windows/009_PictureEx.rb +++ b/Data/Scripts/009_Objects and windows/013_PictureEx.rb @@ -117,7 +117,7 @@ class PictureEx end def callback(cb) - if cb.is_a?(Proc); proc.call(self) + if cb.is_a?(Proc); cb.call(self) elsif cb.is_a?(Array); cb[0].method(cb[1]).call(self) elsif cb.is_a?(Method); cb.call(self) end diff --git a/Data/Scripts/009_Objects and windows/010_Interpolators.rb b/Data/Scripts/009_Objects and windows/014_Interpolators.rb similarity index 100% rename from Data/Scripts/009_Objects and windows/010_Interpolators.rb rename to Data/Scripts/009_Objects and windows/014_Interpolators.rb diff --git a/Data/Scripts/011_Data/005_PBTypes_Extra.rb b/Data/Scripts/011_Data/004_PBTypes_Extra.rb similarity index 100% rename from Data/Scripts/011_Data/005_PBTypes_Extra.rb rename to Data/Scripts/011_Data/004_PBTypes_Extra.rb diff --git a/Data/Scripts/011_Data/008_PBExperience.rb b/Data/Scripts/011_Data/005_PBExperience.rb similarity index 100% rename from Data/Scripts/011_Data/008_PBExperience.rb rename to Data/Scripts/011_Data/005_PBExperience.rb diff --git a/Data/Scripts/011_Data/009_PBStats.rb b/Data/Scripts/011_Data/006_PBStats.rb similarity index 99% rename from Data/Scripts/011_Data/009_PBStats.rb rename to Data/Scripts/011_Data/006_PBStats.rb index b81692d2e..2704dc948 100644 --- a/Data/Scripts/011_Data/009_PBStats.rb +++ b/Data/Scripts/011_Data/006_PBStats.rb @@ -28,6 +28,7 @@ begin names[EVASION] = _INTL("evasiveness") return names[id] end + def self.getNameBrief(id) id = getID(PBStats,id) names = [] @@ -41,6 +42,7 @@ begin names[EVASION] = _INTL("eva") return names[id] end + def self.eachStat [HP,ATTACK,DEFENSE,SPATK,SPDEF,SPEED].each { |s| yield s } end diff --git a/Data/Scripts/011_Data/004_PBStatuses.rb b/Data/Scripts/011_Data/007_PBStatuses.rb similarity index 100% rename from Data/Scripts/011_Data/004_PBStatuses.rb rename to Data/Scripts/011_Data/007_PBStatuses.rb diff --git a/Data/Scripts/011_Data/006_PBNatures.rb b/Data/Scripts/011_Data/008_PBNatures.rb similarity index 100% rename from Data/Scripts/011_Data/006_PBNatures.rb rename to Data/Scripts/011_Data/008_PBNatures.rb diff --git a/Data/Scripts/011_Data/007_PBGenderRates.rb b/Data/Scripts/011_Data/009_PBGenderRates.rb similarity index 100% rename from Data/Scripts/011_Data/007_PBGenderRates.rb rename to Data/Scripts/011_Data/009_PBGenderRates.rb diff --git a/Data/Scripts/012_Battle/001_Battler/001_PokeBattle_Battler.rb b/Data/Scripts/012_Battle/001_Battler/001_PokeBattle_Battler.rb index 33f333d63..00bbbda2b 100644 --- a/Data/Scripts/012_Battle/001_Battler/001_PokeBattle_Battler.rb +++ b/Data/Scripts/012_Battle/001_Battler/001_PokeBattle_Battler.rb @@ -220,7 +220,7 @@ class PokeBattle_Battler stageDiv = [8,7,6,5,4,3, 2, 2,2,2,2,2,2] stage = @stages[PBStats::SPEED] + 6 speed = @speed*stageMul[stage]/stageDiv[stage] - speedMult = 0x1000 + speedMult = 1.0 # Ability effects that alter calculated Speed if abilityActive? speedMult = BattleHandlers.triggerSpeedCalcAbility(@ability,self,speedMult) @@ -242,7 +242,7 @@ class PokeBattle_Battler speedMult *= 1.1 end # Calculation - return [(speed.to_f*speedMult/0x1000).round,1].max + return [(speed*speedMult).round,1].max end def pbWeight diff --git a/Data/Scripts/012_Battle/001_Battler/002_Battler_Initialize.rb b/Data/Scripts/012_Battle/001_Battler/002_Battler_Initialize.rb index 663fde76e..c99913020 100644 --- a/Data/Scripts/012_Battle/001_Battler/002_Battler_Initialize.rb +++ b/Data/Scripts/012_Battle/001_Battler/002_Battler_Initialize.rb @@ -65,6 +65,7 @@ class PokeBattle_Battler def pbInitialize(pkmn,idxParty,batonPass=false) pbInitPokemon(pkmn,idxParty) pbInitEffects(batonPass) + @damageState.reset end def pbInitPokemon(pkmn,idxParty) @@ -138,7 +139,6 @@ class PokeBattle_Battler @effects[PBEffects::Substitute] = 0 @effects[PBEffects::Telekinesis] = 0 end - @damageState.reset @fainted = (@hp==0) @initialHP = 0 @lastAttacker = [] @@ -302,7 +302,7 @@ class PokeBattle_Battler end end - # Used only to erase the battler of a Shadow Pokémon that has been snagged. + # Used to erase the battler of a Pokémon that has been caught. def pbReset @pokemon = nil @pokemonIndex = -1 diff --git a/Data/Scripts/012_Battle/001_Battler/004_Battler_Statuses.rb b/Data/Scripts/012_Battle/001_Battler/004_Battler_Statuses.rb index a74037885..c87f5f18d 100644 --- a/Data/Scripts/012_Battle/001_Battler/004_Battler_Statuses.rb +++ b/Data/Scripts/012_Battle/001_Battler/004_Battler_Statuses.rb @@ -171,7 +171,7 @@ class PokeBattle_Battler return true end - def pbCanSynchronizeStatus?(status,target) + def pbCanSynchronizeStatus?(newStatus,target) return false if fainted? # Trying to replace a status problem with another one return false if self.status!=PBStatuses::NONE @@ -179,7 +179,7 @@ class PokeBattle_Battler return false if @battle.field.terrain==PBBattleTerrains::Misty && affectedByTerrain? # Type immunities hasImmuneType = false - case self.status + case newStatus when PBStatuses::POISON # NOTE: target will have Synchronize, so it can't have Corrosion. if !(target && target.hasActiveAbility?(:CORROSION)) @@ -193,15 +193,15 @@ class PokeBattle_Battler end return false if hasImmuneType # Ability immunity - if BattleHandlers.triggerStatusImmunityAbilityNonIgnorable(@ability,self,status) + if BattleHandlers.triggerStatusImmunityAbilityNonIgnorable(@ability,self,newStatus) return false end - if abilityActive? && BattleHandlers.triggerStatusImmunityAbility(@ability,self,status) + if abilityActive? && BattleHandlers.triggerStatusImmunityAbility(@ability,self,newStatus) return false end eachAlly do |b| next if !b.abilityActive? - next if !BattleHandlers.triggerStatusImmunityAllyAbility(b.ability,self,status) + next if !BattleHandlers.triggerStatusImmunityAllyAbility(b.ability,self,newStatus) return false end # Safeguard immunity diff --git a/Data/Scripts/012_Battle/001_Battler/007_Battler_UseMove.rb b/Data/Scripts/012_Battle/001_Battler/007_Battler_UseMove.rb index a7211b8e4..46f4fa424 100644 --- a/Data/Scripts/012_Battle/001_Battler/007_Battler_UseMove.rb +++ b/Data/Scripts/012_Battle/001_Battler/007_Battler_UseMove.rb @@ -8,7 +8,8 @@ class PokeBattle_Battler if tryFlee && @battle.wildBattle? && opposes? && @battle.rules["alwaysflee"] && @battle.pbCanRun?(@index) pbBeginTurn(choice) - @battle.pbDisplay(_INTL("{1} fled from battle!",pbThis)) { pbSEPlay("Battle flee") } + pbSEPlay("Battle flee") + @battle.pbDisplay(_INTL("{1} fled from battle!",pbThis)) @battle.decision = 3 pbEndTurn(choice) return true @@ -323,7 +324,7 @@ class PokeBattle_Battler @battle.pbDisplay(_INTL("When the flame touched the powder on the Pokémon, it exploded!")) user.lastMoveFailed = true w = @battle.pbWeather - if w!=PBWeather.RAINDANCE && w!=PBWeather.HEAVYRAIN && user.takesIndirectDamage? + if w!=PBWeather::Rain && w!=PBWeather::HeavyRain && user.takesIndirectDamage? oldHP = user.hp user.pbReduceHP((user.totalhp/4.0).round,false) user.pbFaint if user.fainted? diff --git a/Data/Scripts/012_Battle/002_Move/003_Move_Usage_Calculations.rb b/Data/Scripts/012_Battle/002_Move/003_Move_Usage_Calculations.rb index 41bb7f38d..ba817641a 100644 --- a/Data/Scripts/012_Battle/002_Move/003_Move_Usage_Calculations.rb +++ b/Data/Scripts/012_Battle/002_Move/003_Move_Usage_Calculations.rb @@ -95,8 +95,8 @@ class PokeBattle_Move modifiers[BASE_ACC] = baseAcc modifiers[ACC_STAGE] = user.stages[PBStats::ACCURACY] modifiers[EVA_STAGE] = target.stages[PBStats::EVASION] - modifiers[ACC_MULT] = 0x1000 - modifiers[EVA_MULT] = 0x1000 + modifiers[ACC_MULT] = 1.0 + modifiers[EVA_MULT] = 1.0 pbCalcAccuracyModifiers(user,target,modifiers) # Check if move can't miss return true if modifiers[BASE_ACC]==0 @@ -107,8 +107,8 @@ class PokeBattle_Move stageDiv = [9,8,7,6,5,4, 3, 3,3,3,3,3,3] accuracy = 100.0 * stageMul[accStage] / stageDiv[accStage] evasion = 100.0 * stageMul[evaStage] / stageDiv[evaStage] - accuracy = (accuracy * modifiers[ACC_MULT] / 0x1000).round - evasion = (evasion * modifiers[EVA_MULT] / 0x1000).round + accuracy = (accuracy * modifiers[ACC_MULT]).round + evasion = (evasion * modifiers[EVA_MULT]).round evasion = 1 if evasion<1 # Calculation return @battle.pbRandom(100) < modifiers[BASE_ACC] * accuracy / evasion @@ -140,11 +140,11 @@ class PokeBattle_Move end # Other effects, inc. ones that set ACC_MULT or EVA_STAGE to specific values if @battle.field.effects[PBEffects::Gravity]>0 - modifiers[ACC_MULT] = (modifiers[ACC_MULT]*5/3).round + modifiers[ACC_MULT] *= 5/3.0 end if user.effects[PBEffects::MicleBerry] user.effects[PBEffects::MicleBerry] = false - modifiers[ACC_MULT] = (modifiers[ACC_MULT]*1.2).round + modifiers[ACC_MULT] *= 1.2 end modifiers[EVA_STAGE] = 0 if target.effects[PBEffects::Foresight] && modifiers[EVA_STAGE]>0 modifiers[EVA_STAGE] = 0 if target.effects[PBEffects::MiracleEye] && modifiers[EVA_STAGE]>0 @@ -244,14 +244,14 @@ class PokeBattle_Move defense = (defense.to_f*stageMul[defStage]/stageDiv[defStage]).floor end # Calculate all multiplier effects - multipliers = [0x1000,0x1000,0x1000,0x1000] + multipliers = [1.0, 1.0, 1.0, 1.0] pbCalcDamageMultipliers(user,target,numTargets,type,baseDmg,multipliers) # Main damage calculation - baseDmg = [(baseDmg * multipliers[BASE_DMG_MULT] / 0x1000).round,1].max - atk = [(atk * multipliers[ATK_MULT] / 0x1000).round,1].max - defense = [(defense * multipliers[DEF_MULT] / 0x1000).round,1].max - damage = (((2.0*user.level/5+2).floor*baseDmg*atk/defense).floor/50).floor+2 - damage = [(damage * multipliers[FINAL_DMG_MULT] / 0x1000).round,1].max + baseDmg = [(baseDmg * multipliers[BASE_DMG_MULT]).round, 1].max + atk = [(atk * multipliers[ATK_MULT]).round, 1].max + defense = [(defense * multipliers[DEF_MULT]).round, 1].max + damage = (((2.0 * user.level / 5 + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2 + damage = [(damage * multipliers[FINAL_DMG_MULT]).round, 1].max target.damageState.calcDamage = damage end @@ -306,10 +306,10 @@ class PokeBattle_Move end # Other if user.effects[PBEffects::MeFirst] - multipliers[BASE_DMG_MULT] = (multipliers[BASE_DMG_MULT]*1.5).round + multipliers[BASE_DMG_MULT] *= 1.5 end if user.effects[PBEffects::HelpingHand] && !self.is_a?(PokeBattle_Confusion) - multipliers[BASE_DMG_MULT] = (multipliers[BASE_DMG_MULT]*1.5).round + multipliers[BASE_DMG_MULT] *= 1.5 end if user.effects[PBEffects::Charge]>0 && isConst?(type,PBTypes,:ELECTRIC) multipliers[BASE_DMG_MULT] *= 2 @@ -341,15 +341,15 @@ class PokeBattle_Move case @battle.field.terrain when PBBattleTerrains::Electric if isConst?(type,PBTypes,:ELECTRIC) - multipliers[BASE_DMG_MULT] = (multipliers[BASE_DMG_MULT]*1.5).round + multipliers[BASE_DMG_MULT] *= 1.5 end when PBBattleTerrains::Grassy if isConst?(type,PBTypes,:GRASS) - multipliers[BASE_DMG_MULT] = (multipliers[BASE_DMG_MULT]*1.5).round + multipliers[BASE_DMG_MULT] *= 1.5 end when PBBattleTerrains::Psychic if isConst?(type,PBTypes,:PSYCHIC) - multipliers[BASE_DMG_MULT] = (multipliers[BASE_DMG_MULT]*1.5).round + multipliers[BASE_DMG_MULT] *= 1.5 end end end @@ -361,28 +361,28 @@ class PokeBattle_Move if @battle.internalBattle if user.pbOwnedByPlayer? if physicalMove? && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_ATTACK - multipliers[ATK_MULT] = (multipliers[ATK_MULT]*1.1).round + multipliers[ATK_MULT] *= 1.1 elsif specialMove? && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_SPATK - multipliers[ATK_MULT] = (multipliers[ATK_MULT]*1.1).round + multipliers[ATK_MULT] *= 1.1 end end if target.pbOwnedByPlayer? if physicalMove? && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_DEFENSE - multipliers[DEF_MULT] = (multipliers[DEF_MULT]*1.1).round + multipliers[DEF_MULT] *= 1.1 elsif specialMove? && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_SPDEF - multipliers[DEF_MULT] = (multipliers[DEF_MULT]*1.1).round + multipliers[DEF_MULT] *= 1.1 end end end # Multi-targeting attacks if numTargets>1 - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*0.75).round + multipliers[FINAL_DMG_MULT] *= 0.75 end # Weather case @battle.pbWeather when PBWeather::Sun, PBWeather::HarshSun if isConst?(type,PBTypes,:FIRE) - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*1.5).round + multipliers[FINAL_DMG_MULT] *= 1.5 elsif isConst?(type,PBTypes,:WATER) multipliers[FINAL_DMG_MULT] /= 2 end @@ -390,17 +390,17 @@ class PokeBattle_Move if isConst?(type,PBTypes,:FIRE) multipliers[FINAL_DMG_MULT] /= 2 elsif isConst?(type,PBTypes,:WATER) - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*1.5).round + multipliers[FINAL_DMG_MULT] *= 1.5 end when PBWeather::Sandstorm if target.pbHasType?(:ROCK) && specialMove? && @function!="122" # Psyshock - multipliers[DEF_MULT] = (multipliers[DEF_MULT]*1.5).round + multipliers[DEF_MULT] *= 1.5 end end # Critical hits if target.damageState.critical if NEWEST_BATTLE_MECHANICS - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*1.5).round + multipliers[FINAL_DMG_MULT] *= 1.5 else multipliers[FINAL_DMG_MULT] *= 2 end @@ -415,12 +415,11 @@ class PokeBattle_Move if user.hasActiveAbility?(:ADAPTABILITY) multipliers[FINAL_DMG_MULT] *= 2 else - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*1.5).round + multipliers[FINAL_DMG_MULT] *= 1.5 end end # Type effectiveness multipliers[FINAL_DMG_MULT] *= target.damageState.typeMod.to_f/PBTypeEffectiveness::NORMAL_EFFECTIVE - multipliers[FINAL_DMG_MULT] = multipliers[FINAL_DMG_MULT].round # Burn if user.status==PBStatuses::BURN && physicalMove? && damageReducedByBurn? && !user.hasActiveAbility?(:GUTS) @@ -431,19 +430,19 @@ class PokeBattle_Move !user.hasActiveAbility?(:INFILTRATOR) if target.pbOwnSide.effects[PBEffects::AuroraVeil]>0 if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*2/3).round + multipliers[FINAL_DMG_MULT] *= 2/3.0 else multipliers[FINAL_DMG_MULT] /= 2 end elsif target.pbOwnSide.effects[PBEffects::Reflect]>0 && physicalMove? if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*2/3).round + multipliers[FINAL_DMG_MULT] *= 2/3.0 else multipliers[FINAL_DMG_MULT] /= 2 end elsif target.pbOwnSide.effects[PBEffects::LightScreen]>0 && specialMove? if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*2/3).round + multipliers[FINAL_DMG_MULT] *= 2/3.0 else multipliers[FINAL_DMG_MULT] /= 2 end diff --git a/Data/Scripts/012_Battle/002_Move/005_Move_Effects_000-07F.rb b/Data/Scripts/012_Battle/002_Move/005_Move_Effects_000-07F.rb index 2e474c441..629551f20 100644 --- a/Data/Scripts/012_Battle/002_Move/005_Move_Effects_000-07F.rb +++ b/Data/Scripts/012_Battle/002_Move/005_Move_Effects_000-07F.rb @@ -1947,7 +1947,7 @@ class PokeBattle_Move_061 < PokeBattle_Move def pbEffectAgainstTarget(user,target) newType = getConst(PBTypes,:WATER) - user.pbChangeTypes(newType) + target.pbChangeTypes(newType) typeName = PBTypes.getName(newType) @battle.pbDisplay(_INTL("{1} transformed into the {2} type!",target.pbThis,typeName)) end @@ -2465,7 +2465,7 @@ end class PokeBattle_Move_073 < PokeBattle_FixedDamageMove def pbAddTarget(targets,user) return if user.lastFoeAttacker.length==0 - lastAttacker = user.lastFoeAttacker[user.lastFoeAttacker.last] + lastAttacker = user.lastFoeAttacker.last return if lastAttacker<0 || !user.opposes?(lastAttacker) user.pbAddTarget(targets,user,@battle.battlers[lastAttacker],self,false) end @@ -2546,7 +2546,7 @@ class PokeBattle_Move_076 < PokeBattle_Move def pbModifyDamage(damageMult,user,target) damageMult *= 2 if target.inTwoTurnAttack?("0CA") # Dig - damageMult = (damageMult/2.0).round if @battle.field.terrain==PBBattleTerrains::Grassy + damageMult /= 2 if @battle.field.terrain==PBBattleTerrains::Grassy return damageMult end end diff --git a/Data/Scripts/012_Battle/002_Move/006_Move_Effects_080-0FF.rb b/Data/Scripts/012_Battle/002_Move/006_Move_Effects_080-0FF.rb index 9cfc2a071..cfc9cd864 100644 --- a/Data/Scripts/012_Battle/002_Move/006_Move_Effects_080-0FF.rb +++ b/Data/Scripts/012_Battle/002_Move/006_Move_Effects_080-0FF.rb @@ -422,7 +422,7 @@ class PokeBattle_Move_095 < PokeBattle_Move def pbModifyDamage(damageMult,user,target) damageMult *= 2 if target.inTwoTurnAttack?("0CA") # Dig - damageMult = (damageMult/2.0).round if @battle.field.terrain==PBBattleTerrains::Grassy + damageMult /= 2 if @battle.field.terrain==PBBattleTerrains::Grassy return damageMult end end @@ -752,7 +752,7 @@ class PokeBattle_Move_09F < PokeBattle_Move elsif isConst?(@id,PBMoves,:MULTIATTACK) @itemTypes = { :FIGHTINGMEMORY => :FIGHTING, - :SLYINGMEMORY => :FLYING, + :FLYINGMEMORY => :FLYING, :POISONMEMORY => :POISON, :GROUNDMEMORY => :GROUND, :ROCKMEMORY => :ROCK, @@ -777,7 +777,7 @@ class PokeBattle_Move_09F < PokeBattle_Move if user.itemActive? @itemTypes.each do |item, itemType| next if !isConst?(user.item,PBItems,item) - t = hasConst?(PBTypes,itemType) + t = getConst(PBTypes,itemType) ret = t || ret break end @@ -1132,7 +1132,7 @@ class PokeBattle_Move_0AE < PokeBattle_Move return false end - def pbEffectGeneral(user) + def pbEffectAgainstTarget(user,target) user.pbUseMoveSimple(target.lastRegularMoveUsed,target.index) end @@ -2070,9 +2070,7 @@ class PokeBattle_Move_0C4 < PokeBattle_TwoTurnMove def pbBaseDamageMultiplier(damageMult,user,target) w = @battle.pbWeather - if w>0 && w!=PBWeather::Sun && w!=PBWeather::HarshSun - damageMult = (damageMult/2.0).round - end + damageMult /= 2 if w>0 && w!=PBWeather::Sun && w!=PBWeather::HarshSun return damageMult end end @@ -2405,18 +2403,19 @@ end #=============================================================================== class PokeBattle_Move_0D3 < PokeBattle_Move def pbBaseDamage(baseDmg,user,target) - shift = (4-user.effects[PBEffects::Rollout]) # 0-4, where 0 is most powerful + shift = (5 - user.effects[PBEffects::Rollout]) # 0-4, where 0 is most powerful + shift = 0 if user.effects[PBEffects::Rollout] == 0 # For first turn shift += 1 if user.effects[PBEffects::DefenseCurl] - baseDmg = baseDmg << shift + baseDmg *= 2**shift return baseDmg end def pbEffectAfterAllHits(user,target) - if !target.damageState.unaffected && user.effects[PBEffects::Rollout]==0 + if !target.damageState.unaffected && user.effects[PBEffects::Rollout] == 0 user.effects[PBEffects::Rollout] = 5 user.currentMove = @id end - user.effects[PBEffects::Rollout] -= 1 if user.effects[PBEffects::Rollout]>0 + user.effects[PBEffects::Rollout] -= 1 if user.effects[PBEffects::Rollout] > 0 end end @@ -3084,7 +3083,7 @@ class PokeBattle_Move_0EC < PokeBattle_Move switchedBattlers.push(b.index) roarSwitched.push(b.index) end - if roarSwitched>0 + if roarSwitched.length>0 @battle.moldBreaker = false if roarSwitched.include?(user.index) @battle.pbPriority(true).each do |b| b.pbEffectsOnSwitchIn(true) if roarSwitched.include?(b.index) diff --git a/Data/Scripts/012_Battle/003_Battle/002_PokeBattle_Battle.rb b/Data/Scripts/012_Battle/003_Battle/002_PokeBattle_Battle.rb index 8beb8a7e4..73d952058 100644 --- a/Data/Scripts/012_Battle/003_Battle/002_PokeBattle_Battle.rb +++ b/Data/Scripts/012_Battle/003_Battle/002_PokeBattle_Battle.rb @@ -692,9 +692,11 @@ class PokeBattle_Battle pbDisplay("The mysterious air current has dissipated!") end end - # Check for form changes caused by the weather changing if @field.weather!=oldWeather + # Check for form changes caused by the weather changing eachBattler { |b| b.pbCheckFormOnWeatherChange } + # Start up the default weather + pbStartWeather(nil,@field.defaultWeather) if @field.defaultWeather!=PBWeather::None end end diff --git a/Data/Scripts/012_Battle/003_Battle/006_Battle_Action_Switching.rb b/Data/Scripts/012_Battle/003_Battle/006_Battle_Action_Switching.rb index a21a53ecc..f1879eec3 100644 --- a/Data/Scripts/012_Battle/003_Battle/006_Battle_Action_Switching.rb +++ b/Data/Scripts/012_Battle/003_Battle/006_Battle_Action_Switching.rb @@ -169,7 +169,7 @@ class PokeBattle_Battle idxPartyForName = idxPartyNew enemyParty = pbParty(idxBattler) if isConst?(enemyParty[idxPartyNew].ability,PBAbilities,:ILLUSION) - idxPartyForName = pbGetLastPokeInTeam(idxBattler) + idxPartyForName = pbLastInTeam(idxBattler) end if pbDisplayConfirm(_INTL("{1} is about to send in {2}. Will you switch your Pokémon?", opponent.fullname,enemyParty[idxPartyForName].name)) @@ -245,7 +245,7 @@ class PokeBattle_Battle pbDisplayBrief(_INTL("{1}, switch out! Come back!",battler.name)) end else - owner = pbGetOwnerName(b.index) + owner = pbGetOwnerName(battler.index) pbDisplayBrief(_INTL("{1} withdrew {2}!",owner,battler.name)) end end diff --git a/Data/Scripts/012_Battle/003_Battle/007_Battle_Action_UseItem.rb b/Data/Scripts/012_Battle/003_Battle/007_Battle_Action_UseItem.rb index bf51ddfb7..d79509bc7 100644 --- a/Data/Scripts/012_Battle/003_Battle/007_Battle_Action_UseItem.rb +++ b/Data/Scripts/012_Battle/003_Battle/007_Battle_Action_UseItem.rb @@ -83,7 +83,7 @@ class PokeBattle_Battle end end - # Uses an item on a Pokémon in the player's party. + # Uses an item on a Pokémon in the trainer's party. def pbUseItemOnPokemon(item,idxParty,userBattler) trainerName = pbGetOwnerName(userBattler.index) pbUseItemMessage(item,trainerName) @@ -100,14 +100,14 @@ class PokeBattle_Battle pbReturnUnusedItemToBag(item,userBattler.index) end - # Uses an item on a Pokémon in battle that belongs to the player. - def pbUseItemOnBattler(item,idxParty,userBattler) + # Uses an item on a Pokémon in battle that belongs to the trainer. + def pbUseItemOnBattler(item,idxBattler,userBattler) trainerName = pbGetOwnerName(userBattler.index) pbUseItemMessage(item,trainerName) - pkmn = pbParty(userBattler.index)[idxParty] - battler = pbFindBattler(idxParty,userBattler.index) + idxBattler = userBattler.index if idxBattler<0 + battler = @battlers[idxBattler] ch = @choices[userBattler.index] - if ItemHandlers.triggerCanUseInBattle(item,pkmn,battler,ch[3],true,self,@scene,false) + if ItemHandlers.triggerCanUseInBattle(item,battler.pokemon,battler,ch[3],true,self,@scene,false) ItemHandlers.triggerBattleUseOnBattler(item,battler,@scene) ch[1] = 0 # Delete item from choice return diff --git a/Data/Scripts/012_Battle/003_Battle/008_Battle_Action_Running.rb b/Data/Scripts/012_Battle/003_Battle/008_Battle_Action_Running.rb index 0b9267a90..14ecd896d 100644 --- a/Data/Scripts/012_Battle/003_Battle/008_Battle_Action_Running.rb +++ b/Data/Scripts/012_Battle/003_Battle/008_Battle_Action_Running.rb @@ -52,7 +52,8 @@ class PokeBattle_Battle elsif @internalBattle pbDisplayPaused(_INTL("No! There's no running from a Trainer battle!")) elsif pbDisplayConfirm(_INTL("Would you like to forfeit the match and quit now?")) - pbDisplay(_INTL("{1} forfeited the match!",self.pbPlayer.name)) { pbSEPlay("Battle flee") } + pbSEPlay("Battle flee") + pbDisplay(_INTL("{1} forfeited the match!",self.pbPlayer.name)) @decision = 3 return 1 end @@ -60,7 +61,8 @@ class PokeBattle_Battle end # Fleeing from wild battles if $DEBUG && Input.press?(Input::CTRL) - pbDisplayPaused(_INTL("You got away safely!")) { pbSEPlay("Battle flee") } + pbSEPlay("Battle flee") + pbDisplayPaused(_INTL("You got away safely!")) @decision = 3 return 1 end @@ -70,7 +72,8 @@ class PokeBattle_Battle end if !duringBattle if battler.pbHasType?(:GHOST) && NEWEST_BATTLE_MECHANICS - pbDisplayPaused(_INTL("You got away safely!")) { pbSEPlay("Battle flee") } + pbSEPlay("Battle flee") + pbDisplayPaused(_INTL("You got away safely!")) @decision = 3 return 1 end @@ -79,7 +82,8 @@ class PokeBattle_Battle if BattleHandlers.triggerRunFromBattleAbility(battler.ability,battler) pbShowAbilitySplash(battler,true) pbHideAbilitySplash(battler) - pbDisplayPaused(_INTL("You got away safely!")) { pbSEPlay("Battle flee") } + pbSEPlay("Battle flee") + pbDisplayPaused(_INTL("You got away safely!")) @decision = 3 return 1 end @@ -87,8 +91,9 @@ class PokeBattle_Battle # Held items that guarantee escape if battler.itemActive? if BattleHandlers.triggerRunFromBattleItem(battler.item,battler) + pbSEPlay("Battle flee") pbDisplayPaused(_INTL("{1} fled using its {2}!", - battler.pbThis,battler.itemName)) { pbSEPlay("Battle flee") } + battler.pbThis,battler.itemName)) @decision = 3 return 1 end @@ -135,7 +140,8 @@ class PokeBattle_Battle rate += @runCommand*30 end if rate>=256 || @battleAI.pbAIRandom(256)=0 - @battle.pbRegisterMove(idxBattler,c[0],false) - @battle.pbRegisterTarget(idxBattler,c[2]) if c[2]>=0 - break + PBDebug.log("[AI] #{user.pbThis} (#{user.index}) doesn't want to use any moves; picking one at random") + user.eachMoveWithIndex do |_m,i| + next if !@battle.pbCanChooseMove?(idxBattler,i,false) + choices.push([i,100,-1]) # Move index, score, target end + if choices.length==0 # No moves are physically possible to use + user.eachMoveWithIndex do |_m,i| + choices.push([i,100,-1]) # Move index, score, target + end + end + end + # Randomly choose a move from the choices and register it + randNum = pbAIRandom(totalScore) + choices.each do |c| + randNum -= c[1] + next if randNum>=0 + @battle.pbRegisterMove(idxBattler,c[0],false) + @battle.pbRegisterTarget(idxBattler,c[2]) if c[2]>=0 + break end # Log the result if @battle.choices[idxBattler][2] diff --git a/Data/Scripts/012_Battle/004_AI/005_AI_Move_EffectScores.rb b/Data/Scripts/012_Battle/004_AI/005_AI_Move_EffectScores.rb index 648cd65be..f9afd1b77 100644 --- a/Data/Scripts/012_Battle/004_AI/005_AI_Move_EffectScores.rb +++ b/Data/Scripts/012_Battle/004_AI/005_AI_Move_EffectScores.rb @@ -1364,7 +1364,7 @@ class PokeBattle_AI :ROCK, # Cave :GROUND # Sand ] - type = envtypes[@environment] + type = envtypes[@battle.environment] score -= 90 if user.pbHasType?(type) end #--------------------------------------------------------------------------- @@ -2806,7 +2806,7 @@ class PokeBattle_AI when "152" #--------------------------------------------------------------------------- when "153" - score -= 95 if target.pbOwnSide.effects[PBEffects::StickyWeb] + score -= 95 if user.pbOpposingSide.effects[PBEffects::StickyWeb] #--------------------------------------------------------------------------- when "154" #--------------------------------------------------------------------------- diff --git a/Data/Scripts/012_Battle/004_AI/006_AI_Move_Utilities.rb b/Data/Scripts/012_Battle/004_AI/006_AI_Move_Utilities.rb index da0ddc614..2bb76a15f 100644 --- a/Data/Scripts/012_Battle/004_AI/006_AI_Move_Utilities.rb +++ b/Data/Scripts/012_Battle/004_AI/006_AI_Move_Utilities.rb @@ -275,7 +275,7 @@ class PokeBattle_AI defense = pbRoughStat(target,PBStats::SPDEF,skill) end ##### Calculate all multiplier effects ##### - multipliers = [0x1000,0x1000,0x1000,0x1000] + multipliers = [1.0, 1.0, 1.0, 1.0] # Ability effects that alter damage moldBreaker = false if skill>=PBTrainerAI.highSkill && target.hasMoldBreaker? @@ -364,7 +364,7 @@ class PokeBattle_AI end # Parental Bond if skill>=PBTrainerAI.mediumSkill && user.hasActiveAbility?(:PARENTALBOND) - multipliers[BASE_DMG_MULT] = (multipliers[BASE_DMG_MULT]*1.25).floor + multipliers[BASE_DMG_MULT] *= 1.25 end # Me First # TODO @@ -403,15 +403,15 @@ class PokeBattle_AI case @battle.field.terrain when PBBattleTerrains::Electric if isConst?(type,PBTypes,:ELECTRIC) - multipliers[BASE_DMG_MULT] = (multipliers[BASE_DMG_MULT]*1.5).round + multipliers[BASE_DMG_MULT] *= 1.5 end when PBBattleTerrains::Grassy if isConst?(type,PBTypes,:GRASS) - multipliers[BASE_DMG_MULT] = (multipliers[BASE_DMG_MULT]*1.5).round + multipliers[BASE_DMG_MULT] *= 1.5 end when PBBattleTerrains::Psychic if isConst?(type,PBTypes,:PSYCHIC) - multipliers[BASE_DMG_MULT] = (multipliers[BASE_DMG_MULT]*1.5).round + multipliers[BASE_DMG_MULT] *= 1.5 end end end @@ -427,9 +427,9 @@ class PokeBattle_AI # won't control the player's Pokémon. if target.pbOwnedByPlayer? if move.physicalMove?(type) && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_DEFENSE - multipliers[DEF_MULT] = (multipliers[DEF_MULT]*1.1).round + multipliers[DEF_MULT] *= 1.1 elsif move.specialMove?(type) && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_SPDEF - multipliers[DEF_MULT] = (multipliers[DEF_MULT]*1.1).round + multipliers[DEF_MULT] *= 1.1 end end end @@ -437,7 +437,7 @@ class PokeBattle_AI # Multi-targeting attacks if skill>=PBTrainerAI.highSkill if pbTargetsMultiple?(move,user) - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*0.75).round + multipliers[FINAL_DMG_MULT] *= 0.75 end end # Weather @@ -445,7 +445,7 @@ class PokeBattle_AI case @battle.pbWeather when PBWeather::Sun, PBWeather::HarshSun if isConst?(type,PBTypes,:FIRE) - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*1.5).round + multipliers[FINAL_DMG_MULT] *= 1.5 elsif isConst?(type,PBTypes,:WATER) multipliers[FINAL_DMG_MULT] /= 2 end @@ -453,11 +453,11 @@ class PokeBattle_AI if isConst?(type,PBTypes,:FIRE) multipliers[FINAL_DMG_MULT] /= 2 elsif isConst?(type,PBTypes,:WATER) - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*1.5).round + multipliers[FINAL_DMG_MULT] *= 1.5 end when PBWeather::Sandstorm if target.pbHasType?(:ROCK) && move.specialMove?(type) && move.function!="122" # Psyshock - multipliers[DEF_MULT] = (multipliers[DEF_MULT]*1.5).round + multipliers[DEF_MULT] *= 1.5 end end end @@ -469,7 +469,7 @@ class PokeBattle_AI if user.hasActiveAbility?(:ADAPTABILITY) multipliers[FINAL_DMG_MULT] *= 2 else - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*1.5).round + multipliers[FINAL_DMG_MULT] *= 1.5 end end end @@ -477,7 +477,6 @@ class PokeBattle_AI if skill>=PBTrainerAI.mediumSkill typemod = pbCalcTypeMod(type,user,target) multipliers[FINAL_DMG_MULT] *= typemod.to_f/PBTypeEffectiveness::NORMAL_EFFECTIVE - multipliers[FINAL_DMG_MULT] = multipliers[FINAL_DMG_MULT].round end # Burn if skill>=PBTrainerAI.highSkill @@ -492,19 +491,19 @@ class PokeBattle_AI if !move.ignoresReflect? && !user.hasActiveAbility?(:INFILTRATOR) if target.pbOwnSide.effects[PBEffects::AuroraVeil]>0 if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*2/3).round + multipliers[FINAL_DMG_MULT] *= 2/3.0 else multipliers[FINAL_DMG_MULT] /= 2 end elsif target.pbOwnSide.effects[PBEffects::Reflect]>0 && move.physicalMove?(type) if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*2/3).round + multipliers[FINAL_DMG_MULT] *= 2/3.0 else multipliers[FINAL_DMG_MULT] /= 2 end elsif target.pbOwnSide.effects[PBEffects::LightScreen]>0 && move.specialMove?(type) if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] = (multipliers[FINAL_DMG_MULT]*2/3).round + multipliers[FINAL_DMG_MULT] *= 2/3.0 else multipliers[FINAL_DMG_MULT] /= 2 end @@ -522,11 +521,11 @@ class PokeBattle_AI # Move-specific final damage modifiers # TODO ##### Main damage calculation ##### - baseDmg = [(baseDmg * multipliers[BASE_DMG_MULT] / 0x1000).round,1].max - atk = [(atk * multipliers[ATK_MULT] / 0x1000).round,1].max - defense = [(defense * multipliers[DEF_MULT] / 0x1000).round,1].max - damage = (((2.0*user.level/5+2).floor*baseDmg*atk/defense).floor/50).floor+2 - damage = [(damage * multipliers[FINAL_DMG_MULT] / 0x1000).round,1].max + baseDmg = [(baseDmg * multipliers[BASE_DMG_MULT]).round, 1].max + atk = [(atk * multipliers[ATK_MULT]).round, 1].max + defense = [(defense * multipliers[DEF_MULT]).round, 1].max + damage = (((2.0 * user.level / 5 + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2 + damage = [(damage * multipliers[FINAL_DMG_MULT]).round, 1].max # "AI-specific calculations below" # Increased critical hit rates if skill>=PBTrainerAI.mediumSkill @@ -585,8 +584,8 @@ class PokeBattle_AI modifiers[BASE_ACC] = baseAcc modifiers[ACC_STAGE] = user.stages[PBStats::ACCURACY] modifiers[EVA_STAGE] = target.stages[PBStats::EVASION] - modifiers[ACC_MULT] = 0x1000 - modifiers[EVA_MULT] = 0x1000 + modifiers[ACC_MULT] = 1.0 + modifiers[EVA_MULT] = 1.0 pbCalcAccuracyModifiers(user,target,modifiers,move,type,skill) # Check if move can't miss return 125 if modifiers[BASE_ACC]==0 @@ -597,8 +596,8 @@ class PokeBattle_AI stageDiv = [9,8,7,6,5,4, 3, 3,3,3,3,3,3] accuracy = 100.0 * stageMul[accStage] / stageDiv[accStage] evasion = 100.0 * stageMul[evaStage] / stageDiv[evaStage] - accuracy = (accuracy * modifiers[ACC_MULT] / 0x1000).round - evasion = (evasion * modifiers[EVA_MULT] / 0x1000).round + accuracy = (accuracy * modifiers[ACC_MULT]).round + evasion = (evasion * modifiers[EVA_MULT]).round evasion = 1 if evasion<1 return modifiers[BASE_ACC] * accuracy / evasion end @@ -642,10 +641,10 @@ class PokeBattle_AI # Other effects, inc. ones that set ACC_MULT or EVA_STAGE to specific values if skill>=PBTrainerAI.mediumSkill if @battle.field.effects[PBEffects::Gravity]>0 - modifiers[ACC_MULT] = (modifiers[ACC_MULT]*5/3).round + modifiers[ACC_MULT] *= 5/3.0 end if user.effects[PBEffects::MicleBerry] - modifiers[ACC_MULT] = (modifiers[ACC_MULT]*1.2).round + modifiers[ACC_MULT] *= 1.2 end modifiers[EVA_STAGE] = 0 if target.effects[PBEffects::Foresight] && modifiers[EVA_STAGE]>0 modifiers[EVA_STAGE] = 0 if target.effects[PBEffects::MiracleEye] && modifiers[EVA_STAGE]>0 diff --git a/Data/Scripts/012_Battle/004_PBTargets.rb b/Data/Scripts/012_Battle/004_PBTargets.rb index 233ad648a..0be66e948 100644 --- a/Data/Scripts/012_Battle/004_PBTargets.rb +++ b/Data/Scripts/012_Battle/004_PBTargets.rb @@ -5,19 +5,19 @@ module PBTargets User = 10 NearAlly = 100 # Aromatic Mist, Helping Hand, Hold Hands UserOrNearAlly = 200 # Acupressure + UserAndAllies = 5 # Aromatherapy, Gear Up, Heal Bell, Life Dew, Magnetic Flux, Howl (in Gen 8+) NearFoe = 400 # Me First - AllNearFoes = 4 RandomNearFoe = 2 # Petal Dance, Outrage, Struggle, Thrash, Uproar + AllNearFoes = 4 Foe = 9 # For throwing a Poké Ball + AllFoes = 6 # Unused (for completeness) NearOther = 0 AllNearOthers = 8 Other = 3 # Most Flying-type moves, pulse moves (hits non-near targets) + AllBattlers = 7 # Flower Shield, Perish Song, Rototiller, Teatime UserSide = 40 FoeSide = 80 # Entry hazards BothSides = 20 - UserAndAllies = 5 # Aromatherapy, Gear Up, Heal Bell, Life Dew, Magnetic Flux, Howl (in Gen 8+) - AllFoes = 6 # Unused (for completeness) - AllBattlers = 7 # Flower Shield, Perish Song, Rototiller, Teatime def self.noTargets?(target) return target==None || diff --git a/Data/Scripts/012_Battle/005_Battle scene/004_PokeBattle_SceneElements.rb b/Data/Scripts/012_Battle/005_Battle scene/004_PokeBattle_SceneElements.rb index 04e0bf2ca..304ddc7ff 100644 --- a/Data/Scripts/012_Battle/005_Battle scene/004_PokeBattle_SceneElements.rb +++ b/Data/Scripts/012_Battle/005_Battle scene/004_PokeBattle_SceneElements.rb @@ -326,7 +326,7 @@ class PokemonDataBox < SpriteWrapper if @expFlash==0 pbSEStop @expFlash = Graphics.frame_rate/5 - pbSEPlay("Exp full") + pbSEPlay("Pkmn exp full") self.flash(Color.new(64,200,248,192),@expFlash) for i in @sprites i[1].flash(Color.new(64,200,248,192),@expFlash) if !i[1].disposed? diff --git a/Data/Scripts/012_Battle/006_BattleHandlers.rb b/Data/Scripts/012_Battle/006_BattleHandlers.rb index e159defcd..b0080dba5 100644 --- a/Data/Scripts/012_Battle/006_BattleHandlers.rb +++ b/Data/Scripts/012_Battle/006_BattleHandlers.rb @@ -578,16 +578,16 @@ def pbBattleGem(user,type,move,mults,moveType) return if !isConst?(moveType,PBTypes,type) user.effects[PBEffects::GemConsumed] = user.item if NEWEST_BATTLE_MECHANICS - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.3).round + mults[BASE_DMG_MULT] *= 1.3 else - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.5).round + mults[BASE_DMG_MULT] *= 1.5 end end def pbBattleTypeWeakingBerry(type,moveType,target,mults) return if !isConst?(moveType,PBTypes,type) return if PBTypes.resistant?(target.damageState.typeMod) && !isConst?(moveType,PBTypes,:NORMAL) - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]/2).round + mults[FINAL_DMG_MULT] /= 2 target.damageState.berryWeakened = true target.battle.pbCommonAnimation("EatBerry",target) end diff --git a/Data/Scripts/012_Battle/006_Other battle types/002_PokeBattle_SafariZone.rb b/Data/Scripts/012_Battle/006_Other battle types/002_PokeBattle_SafariZone.rb index dfb942701..47696e46c 100644 --- a/Data/Scripts/012_Battle/006_Other battle types/002_PokeBattle_SafariZone.rb +++ b/Data/Scripts/012_Battle/006_Other battle types/002_PokeBattle_SafariZone.rb @@ -25,6 +25,10 @@ class PokeBattle_FakeBattler def shiny?; return @pokemon.shiny?; end alias isShiny? shiny? + def isSpecies?(check_species) + return @pokemon && @pokemon.isSpecies?(check_species) + end + def fainted?; return false; end alias isFainted? fainted? def shadowPokemon?; return false; end @@ -458,7 +462,8 @@ class PokeBattle_SafariZone catchFactor *= 2 # Easier to catch escapeFactor *= 2 if pbRandom(100)<90 # More likely to escape when 3 # Run - pbDisplayPaused(_INTL("You got away safely!")) { pbSEPlay("Battle flee") } + pbSEPlay("Battle flee") + pbDisplayPaused(_INTL("You got away safely!")) @decision = 3 end catchFactor = [[catchFactor,3].max,20].min @@ -469,7 +474,8 @@ class PokeBattle_SafariZone pbDisplay(_INTL("PA: You have no Safari Balls left! Game over!")) @decision = 2 elsif pbRandom(100)<5*escapeFactor - pbDisplay(_INTL("{1} fled!",wildpoke.name)) { pbSEPlay("Battle flee") } + pbSEPlay("Battle flee") + pbDisplay(_INTL("{1} fled!",wildpoke.name)) @decision = 3 elsif cmd==1 # Bait pbDisplay(_INTL("{1} is eating!",wildpoke.name)) diff --git a/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb b/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb index 031aab5f7..b28019536 100644 --- a/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb +++ b/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb @@ -11,7 +11,7 @@ BattleHandlers::SpeedCalcAbility.add(:CHLOROPHYLL, BattleHandlers::SpeedCalcAbility.add(:QUICKFEET, proc { |ability,battler,mult| - next (mult*1.5).round if battler.pbHasAnyStatus? + next mult*1.5 if battler.pbHasAnyStatus? } ) @@ -24,7 +24,7 @@ BattleHandlers::SpeedCalcAbility.add(:SANDRUSH, BattleHandlers::SpeedCalcAbility.add(:SLOWSTART, proc { |ability,battler,mult| - next mult/2 if battler.turnCount<=5 + next mult/2 if battler.effects[PBEffects::SlowStart]>0 } ) @@ -83,7 +83,8 @@ BattleHandlers::AbilityOnHPDroppedBelowHalf.add(:EMERGENCYEXIT, next false if !battle.pbCanRun?(battler.index) battle.pbShowAbilitySplash(battler,true) battle.pbHideAbilitySplash(battler) - battle.pbDisplay(_INTL("{1} fled from battle!",battler.pbThis)) { pbSEPlay("Battle flee") } + pbSEPlay("Battle flee") + battle.pbDisplay(_INTL("{1} fled from battle!",battler.pbThis)) battle.decision = 3 # Escaped next true end @@ -767,13 +768,13 @@ BattleHandlers::MoveBaseTypeModifierAbility.add(:REFRIGERATE, BattleHandlers::AccuracyCalcUserAbility.add(:COMPOUNDEYES, proc { |ability,mods,user,target,move,type| - mods[ACC_MULT] = (mods[ACC_MULT]*1.3).round + mods[ACC_MULT] *= 1.3 } ) BattleHandlers::AccuracyCalcUserAbility.add(:HUSTLE, proc { |ability,mods,user,target,move,type| - mods[ACC_MULT] = (mods[ACC_MULT]*0.8).round if move.physicalMove? + mods[ACC_MULT] *= 0.8 if move.physicalMove? } ) @@ -797,7 +798,7 @@ BattleHandlers::AccuracyCalcUserAbility.add(:UNAWARE, BattleHandlers::AccuracyCalcUserAbility.add(:VICTORYSTAR, proc { |ability,mods,user,target,move,type| - mods[ACC_MULT] = (mods[ACC_MULT]*1.1).round + mods[ACC_MULT] *= 1.1 } ) @@ -807,7 +808,7 @@ BattleHandlers::AccuracyCalcUserAbility.add(:VICTORYSTAR, BattleHandlers::AccuracyCalcUserAllyAbility.add(:VICTORYSTAR, proc { |ability,mods,user,target,move,type| - mods[ACC_MULT] = (mods[ACC_MULT]*1.1).round + mods[ACC_MULT] *= 1.1 } ) @@ -830,7 +831,7 @@ BattleHandlers::AccuracyCalcTargetAbility.add(:NOGUARD, BattleHandlers::AccuracyCalcTargetAbility.add(:SANDVEIL, proc { |ability,mods,user,target,move,type| if target.battle.pbWeather==PBWeather::Sandstorm - mods[EVA_MULT] = (mods[EVA_MULT]*1.25).round + mods[EVA_MULT] *= 1.25 end } ) @@ -838,7 +839,7 @@ BattleHandlers::AccuracyCalcTargetAbility.add(:SANDVEIL, BattleHandlers::AccuracyCalcTargetAbility.add(:SNOWCLOAK, proc { |ability,mods,user,target,move,type| if target.battle.pbWeather==PBWeather::Hail - mods[EVA_MULT] = (mods[EVA_MULT]*1.25).round + mods[EVA_MULT] *= 1.25 end } ) @@ -875,7 +876,7 @@ BattleHandlers::AccuracyCalcTargetAbility.add(:WONDERSKIN, BattleHandlers::DamageCalcUserAbility.add(:AERILATE, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if move.powerBoost + mults[BASE_DMG_MULT] *= 1.2 if move.powerBoost } ) @@ -886,7 +887,7 @@ BattleHandlers::DamageCalcUserAbility.add(:ANALYTIC, if (target.battle.choices[target.index][0]!=:UseMove && target.battle.choices[target.index][0]!=:Shift) || target.movedThisRound? - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.3).round + mults[BASE_DMG_MULT] *= 1.3 end } ) @@ -894,21 +895,21 @@ BattleHandlers::DamageCalcUserAbility.add(:ANALYTIC, BattleHandlers::DamageCalcUserAbility.add(:BLAZE, proc { |ability,user,target,move,mults,baseDmg,type| if user.hp<=user.totalhp/3 && isConst?(type,PBTypes,:FIRE) - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:DEFEATIST, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] = (mults[ATK_MULT]*0.5).round if user.hp<=user.totalhp/2 + mults[ATK_MULT] /= 2 if user.hp<=user.totalhp/2 } ) BattleHandlers::DamageCalcUserAbility.add(:FLAREBOOST, proc { |ability,user,target,move,mults,baseDmg,type| if user.burned? && move.specialMove? - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.5).round + mults[BASE_DMG_MULT] *= 1.5 end } ) @@ -916,7 +917,7 @@ BattleHandlers::DamageCalcUserAbility.add(:FLAREBOOST, BattleHandlers::DamageCalcUserAbility.add(:FLASHFIRE, proc { |ability,user,target,move,mults,baseDmg,type| if user.effects[PBEffects::FlashFire] && isConst?(type,PBTypes,:FIRE) - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 end } ) @@ -925,7 +926,7 @@ BattleHandlers::DamageCalcUserAbility.add(:FLOWERGIFT, proc { |ability,user,target,move,mults,baseDmg,type| w = user.battle.pbWeather if move.physicalMove? && (w==PBWeather::Sun || w==PBWeather::HarshSun) - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 end } ) @@ -933,7 +934,7 @@ BattleHandlers::DamageCalcUserAbility.add(:FLOWERGIFT, BattleHandlers::DamageCalcUserAbility.add(:GUTS, proc { |ability,user,target,move,mults,baseDmg,type| if user.pbHasAnyStatus? && move.physicalMove? - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 end } ) @@ -948,19 +949,19 @@ BattleHandlers::DamageCalcUserAbility.copy(:HUGEPOWER,:PUREPOWER) BattleHandlers::DamageCalcUserAbility.add(:HUSTLE, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round if move.physicalMove? + mults[ATK_MULT] *= 1.5 if move.physicalMove? } ) BattleHandlers::DamageCalcUserAbility.add(:IRONFIST, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if move.punchingMove? + mults[BASE_DMG_MULT] *= 1.2 if move.punchingMove? } ) BattleHandlers::DamageCalcUserAbility.add(:MEGALAUNCHER, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.5).round if move.pulseMove? + mults[BASE_DMG_MULT] *= 1.5 if move.pulseMove? } ) @@ -969,7 +970,7 @@ BattleHandlers::DamageCalcUserAbility.add(:MINUS, next if !move.specialMove? user.eachAlly do |b| next if !b.hasActiveAbility?([:MINUS,:PLUS]) - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 break end } @@ -980,7 +981,7 @@ BattleHandlers::DamageCalcUserAbility.copy(:MINUS,:PLUS) BattleHandlers::DamageCalcUserAbility.add(:NEUROFORCE, proc { |ability,user,target,move,mults,baseDmg,type| if PBTypes.superEffective?(target.damageState.typeMod) - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*1.25).round + mults[FINAL_DMG_MULT] *= 1.25 end } ) @@ -988,14 +989,14 @@ BattleHandlers::DamageCalcUserAbility.add(:NEUROFORCE, BattleHandlers::DamageCalcUserAbility.add(:OVERGROW, proc { |ability,user,target,move,mults,baseDmg,type| if user.hp<=user.totalhp/3 && isConst?(type,PBTypes,:GRASS) - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:RECKLESS, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if move.recoilMove? + mults[BASE_DMG_MULT] *= 1.2 if move.recoilMove? } ) @@ -1003,9 +1004,9 @@ BattleHandlers::DamageCalcUserAbility.add(:RIVALRY, proc { |ability,user,target,move,mults,baseDmg,type| if user.gender!=2 && target.gender!=2 if user.gender==target.gender - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.25).round + mults[BASE_DMG_MULT] *= 1.25 else - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*0.75).round + mults[BASE_DMG_MULT] *= 0.75 end end } @@ -1017,22 +1018,20 @@ BattleHandlers::DamageCalcUserAbility.add(:SANDFORCE, (isConst?(type,PBTypes,:ROCK) || isConst?(type,PBTypes,:GROUND) || isConst?(type,PBTypes,:STEEL)) - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.3).round + mults[BASE_DMG_MULT] *= 1.3 end } ) BattleHandlers::DamageCalcUserAbility.add(:SHEERFORCE, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.3).round if move.addlEffect>0 + mults[BASE_DMG_MULT] *= 1.3 if move.addlEffect>0 } ) BattleHandlers::DamageCalcUserAbility.add(:SLOWSTART, proc { |ability,user,target,move,mults,baseDmg,type| - if user.turnCount<=5 && move.physicalMove? - mults[ATK_MULT] = (mults[ATK_MULT]*0.5).round - end + mults[ATK_MULT] /= 2 if user.effects[PBEffects::SlowStart]>0 && move.physicalMove? } ) @@ -1040,7 +1039,7 @@ BattleHandlers::DamageCalcUserAbility.add(:SOLARPOWER, proc { |ability,user,target,move,mults,baseDmg,type| w = user.battle.pbWeather if move.specialMove? && (w==PBWeather::Sun || w==PBWeather::HarshSun) - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 end } ) @@ -1048,7 +1047,7 @@ BattleHandlers::DamageCalcUserAbility.add(:SOLARPOWER, BattleHandlers::DamageCalcUserAbility.add(:SNIPER, proc { |ability,user,target,move,mults,baseDmg,type| if target.damageState.critical - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*1.5).round + mults[FINAL_DMG_MULT] *= 1.5 end } ) @@ -1061,28 +1060,28 @@ BattleHandlers::DamageCalcUserAbility.add(:STAKEOUT, BattleHandlers::DamageCalcUserAbility.add(:STEELWORKER, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round if isConst?(type,PBTypes,:STEEL) + mults[ATK_MULT] *= 1.5 if isConst?(type,PBTypes,:STEEL) } ) BattleHandlers::DamageCalcUserAbility.add(:STRONGJAW, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.5).round if move.bitingMove? + mults[BASE_DMG_MULT] *= 1.5 if move.bitingMove? } ) BattleHandlers::DamageCalcUserAbility.add(:SWARM, proc { |ability,user,target,move,mults,baseDmg,type| if user.hp<=user.totalhp/3 && isConst?(type,PBTypes,:BUG) - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:TECHNICIAN, proc { |ability,user,target,move,mults,baseDmg,type| - if user.index!=target.index && move.id>0 && baseDmg*mults[BASE_DMG_MULT]/0x1000<=60 - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.5).round + if user.index!=target.index && move.id>0 && baseDmg*mults[BASE_DMG_MULT]<=60 + mults[BASE_DMG_MULT] *= 1.5 end } ) @@ -1096,21 +1095,21 @@ BattleHandlers::DamageCalcUserAbility.add(:TINTEDLENS, BattleHandlers::DamageCalcUserAbility.add(:TORRENT, proc { |ability,user,target,move,mults,baseDmg,type| if user.hp<=user.totalhp/3 && isConst?(type,PBTypes,:WATER) - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:TOUGHCLAWS, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*4/3.0).round if move.contactMove? + mults[BASE_DMG_MULT] *= 4/3.0 if move.contactMove? } ) BattleHandlers::DamageCalcUserAbility.add(:TOXICBOOST, proc { |ability,user,target,move,mults,baseDmg,type| if user.poisoned? && move.physicalMove? - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.5).round + mults[BASE_DMG_MULT] *= 1.5 end } ) @@ -1128,7 +1127,7 @@ BattleHandlers::DamageCalcUserAbility.add(:WATERBUBBLE, BattleHandlers::DamageCalcUserAllyAbility.add(:BATTERY, proc { |ability,user,target,move,mults,baseDmg,type| next if !move.specialMove? - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*1.3).round + mults[FINAL_DMG_MULT] *= 1.3 } ) @@ -1136,7 +1135,7 @@ BattleHandlers::DamageCalcUserAllyAbility.add(:FLOWERGIFT, proc { |ability,user,target,move,mults,baseDmg,type| w = user.battle.pbWeather if move.physicalMove? && (w==PBWeather::Sun || w==PBWeather::HarshSun) - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 end } ) @@ -1148,7 +1147,7 @@ BattleHandlers::DamageCalcUserAllyAbility.add(:FLOWERGIFT, BattleHandlers::DamageCalcTargetAbility.add(:DRYSKIN, proc { |ability,user,target,move,mults,baseDmg,type| if isConst?(type,PBTypes,:FIRE) - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.25).round + mults[BASE_DMG_MULT] *= 1.25 end } ) @@ -1156,7 +1155,7 @@ BattleHandlers::DamageCalcTargetAbility.add(:DRYSKIN, BattleHandlers::DamageCalcTargetAbility.add(:FILTER, proc { |ability,user,target,move,mults,baseDmg,type| if PBTypes.superEffective?(target.damageState.typeMod) - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*0.75).round + mults[FINAL_DMG_MULT] *= 0.75 end } ) @@ -1167,7 +1166,7 @@ BattleHandlers::DamageCalcTargetAbility.add(:FLOWERGIFT, proc { |ability,user,target,move,mults,baseDmg,type| w = user.battle.pbWeather if move.specialMove? && (w==PBWeather::Sun || w==PBWeather::HarshSun) - mults[DEF_MULT] = (mults[DEF_MULT]*1.5).round + mults[DEF_MULT] *= 1.5 end } ) @@ -1175,7 +1174,7 @@ BattleHandlers::DamageCalcTargetAbility.add(:FLOWERGIFT, BattleHandlers::DamageCalcTargetAbility.add(:FLUFFY, proc { |ability,user,target,move,mults,baseDmg,type| mults[FINAL_DMG_MULT] *= 2 if isConst?(move.calcType,PBTypes,:FIRE) - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*0.5).round if move.contactMove? + mults[FINAL_DMG_MULT] /= 2 if move.contactMove? } ) @@ -1188,21 +1187,21 @@ BattleHandlers::DamageCalcTargetAbility.add(:FURCOAT, BattleHandlers::DamageCalcTargetAbility.add(:GRASSPELT, proc { |ability,user,target,move,mults,baseDmg,type| if user.battle.field.terrain==PBBattleTerrains::Grassy - mults[DEF_MULT] = (mults[DEF_MULT]*1.5).round + mults[DEF_MULT] *= 1.5 end } ) BattleHandlers::DamageCalcTargetAbility.add(:HEATPROOF, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*0.5).round if isConst?(type,PBTypes,:FIRE) + mults[BASE_DMG_MULT] /= 2 if isConst?(type,PBTypes,:FIRE) } ) BattleHandlers::DamageCalcTargetAbility.add(:MARVELSCALE, proc { |ability,user,target,move,mults,baseDmg,type| if target.pbHasAnyStatus? && move.physicalMove? - mults[DEF_MULT] = (mults[DEF_MULT]*1.5).round + mults[DEF_MULT] *= 1.5 end } ) @@ -1210,7 +1209,7 @@ BattleHandlers::DamageCalcTargetAbility.add(:MARVELSCALE, BattleHandlers::DamageCalcTargetAbility.add(:MULTISCALE, proc { |ability,user,target,move,mults,baseDmg,type| if target.hp==target.totalhp - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*0.5).round + mults[FINAL_DMG_MULT] /= 2 end } ) @@ -1218,7 +1217,7 @@ BattleHandlers::DamageCalcTargetAbility.add(:MULTISCALE, BattleHandlers::DamageCalcTargetAbility.add(:THICKFAT, proc { |ability,user,target,move,mults,baseDmg,type| if isConst?(type,PBTypes,:FIRE) || isConst?(type,PBTypes,:ICE) - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*0.5).round + mults[BASE_DMG_MULT] /= 2 end } ) @@ -1226,7 +1225,7 @@ BattleHandlers::DamageCalcTargetAbility.add(:THICKFAT, BattleHandlers::DamageCalcTargetAbility.add(:WATERBUBBLE, proc { |ability,user,target,move,mults,baseDmg,type| if isConst?(type,PBTypes,:FIRE) - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*0.5).round + mults[FINAL_DMG_MULT] /= 2 end } ) @@ -1238,7 +1237,7 @@ BattleHandlers::DamageCalcTargetAbility.add(:WATERBUBBLE, BattleHandlers::DamageCalcTargetAbilityNonIgnorable.add(:PRISMARMOR, proc { |ability,user,target,move,mults,baseDmg,type| if PBTypes.superEffective?(target.damageState.typeMod) - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*0.75).round + mults[FINAL_DMG_MULT] *= 0.75 end } ) @@ -1246,7 +1245,7 @@ BattleHandlers::DamageCalcTargetAbilityNonIgnorable.add(:PRISMARMOR, BattleHandlers::DamageCalcTargetAbilityNonIgnorable.add(:SHADOWSHIELD, proc { |ability,user,target,move,mults,baseDmg,type| if target.hp==target.totalhp - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*0.5).round + mults[FINAL_DMG_MULT] /= 2 end } ) @@ -1259,14 +1258,14 @@ BattleHandlers::DamageCalcTargetAllyAbility.add(:FLOWERGIFT, proc { |ability,user,target,move,mults,baseDmg,type| w = user.battle.pbWeather if move.specialMove? && (w==PBWeather::Sun || w==PBWeather::HarshSun) - mults[DEF_MULT] = (mults[DEF_MULT]*1.5).round + mults[DEF_MULT] *= 1.5 end } ) BattleHandlers::DamageCalcTargetAllyAbility.add(:FRIENDGUARD, proc { |ability,user,target,move,mults,baseDmg,type| - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*0.75).round + mults[FINAL_DMG_MULT] *= 0.75 } ) @@ -2407,7 +2406,7 @@ BattleHandlers::AbilityOnSwitchOut.add(:NATURALCURE, BattleHandlers::AbilityOnSwitchOut.add(:REGENERATOR, proc { |ability,battler,endOfBattle| - next if !endOfBattle + next if endOfBattle PBDebug.log("[Ability triggered] #{battler.pbThis}'s #{battler.abilityName}") battler.pbRecoverHP(battler.totalhp/3,false,false) } diff --git a/Data/Scripts/012_Battle/008_BattleHandlers_Items.rb b/Data/Scripts/012_Battle/008_BattleHandlers_Items.rb index 65eba3f33..541d16c79 100644 --- a/Data/Scripts/012_Battle/008_BattleHandlers_Items.rb +++ b/Data/Scripts/012_Battle/008_BattleHandlers_Items.rb @@ -4,7 +4,7 @@ BattleHandlers::SpeedCalcItem.add(:CHOICESCARF, proc { |item,battler,mult| - next (mult*1.5).round + next mult*1.5 } ) @@ -414,7 +414,7 @@ BattleHandlers::PriorityBracketUseItem.add(:QUICKCLAW, BattleHandlers::AccuracyCalcUserItem.add(:WIDELENS, proc { |item,mods,user,target,move,type| - mods[ACC_MULT] = (mods[ACC_MULT]*1.1).round + mods[ACC_MULT] *= 1.1 } ) @@ -423,7 +423,7 @@ BattleHandlers::AccuracyCalcUserItem.add(:ZOOMLENS, if (target.battle.choices[target.index][0]!=:UseMove && target.battle.choices[target.index][0]!=:Shift) || target.movedThisRound? - mods[ACC_MULT] = (mods[ACC_MULT]*1.2).round + mods[ACC_MULT] *= 1.2 end } ) @@ -434,7 +434,7 @@ BattleHandlers::AccuracyCalcUserItem.add(:ZOOMLENS, BattleHandlers::AccuracyCalcTargetItem.add(:BRIGHTPOWDER, proc { |item,mods,user,target,move,type| - mods[ACC_MULT] = (mods[ACC_MULT]*0.9).round + mods[ACC_MULT] *= 0.9 } ) @@ -448,14 +448,14 @@ BattleHandlers::DamageCalcUserItem.add(:ADAMANTORB, proc { |item,user,target,move,mults,baseDmg,type| if user.isSpecies?(:DIALGA) && (isConst?(type,PBTypes,:DRAGON) || isConst?(type,PBTypes,:STEEL)) - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round + mults[BASE_DMG_MULT] *= 1.2 end } ) BattleHandlers::DamageCalcUserItem.add(:BLACKBELT, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:FIGHTING) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:FIGHTING) } ) @@ -463,7 +463,7 @@ BattleHandlers::DamageCalcUserItem.copy(:BLACKBELT,:FISTPLATE) BattleHandlers::DamageCalcUserItem.add(:BLACKGLASSES, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:DARK) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:DARK) } ) @@ -477,7 +477,7 @@ BattleHandlers::DamageCalcUserItem.add(:BUGGEM, BattleHandlers::DamageCalcUserItem.add(:CHARCOAL, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:FIRE) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:FIRE) } ) @@ -485,13 +485,13 @@ BattleHandlers::DamageCalcUserItem.copy(:CHARCOAL,:FLAMEPLATE) BattleHandlers::DamageCalcUserItem.add(:CHOICEBAND, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.5).round if move.physicalMove? + mults[BASE_DMG_MULT] *= 1.5 if move.physicalMove? } ) BattleHandlers::DamageCalcUserItem.add(:CHOICESPECS, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.5).round if move.specialMove? + mults[BASE_DMG_MULT] *= 1.5 if move.specialMove? } ) @@ -511,7 +511,7 @@ BattleHandlers::DamageCalcUserItem.add(:DEEPSEATOOTH, BattleHandlers::DamageCalcUserItem.add(:DRAGONFANG, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:DRAGON) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:DRAGON) } ) @@ -532,7 +532,7 @@ BattleHandlers::DamageCalcUserItem.add(:ELECTRICGEM, BattleHandlers::DamageCalcUserItem.add(:EXPERTBELT, proc { |item,user,target,move,mults,baseDmg,type| if PBTypes.superEffective?(target.damageState.typeMod) - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*1.2).round + mults[FINAL_DMG_MULT] *= 1.2 end } ) @@ -577,7 +577,7 @@ BattleHandlers::DamageCalcUserItem.add(:GRISEOUSORB, proc { |item,user,target,move,mults,baseDmg,type| if user.isSpecies?(:GIRATINA) && (isConst?(type,PBTypes,:DRAGON) || isConst?(type,PBTypes,:GHOST)) - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round + mults[BASE_DMG_MULT] *= 1.2 end } ) @@ -590,7 +590,7 @@ BattleHandlers::DamageCalcUserItem.add(:GROUNDGEM, BattleHandlers::DamageCalcUserItem.add(:HARDSTONE, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:ROCK) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:ROCK) } ) @@ -605,7 +605,7 @@ BattleHandlers::DamageCalcUserItem.add(:ICEGEM, BattleHandlers::DamageCalcUserItem.add(:LIFEORB, proc { |item,user,target,move,mults,baseDmg,type| if !move.is_a?(PokeBattle_Confusion) - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*1.3).round + mults[FINAL_DMG_MULT] *= 1.3 end } ) @@ -622,14 +622,14 @@ BattleHandlers::DamageCalcUserItem.add(:LUSTROUSORB, proc { |item,user,target,move,mults,baseDmg,type| if user.isSpecies?(:PALKIA) && (isConst?(type,PBTypes,:DRAGON) || isConst?(type,PBTypes,:WATER)) - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round + mults[BASE_DMG_MULT] *= 1.2 end } ) BattleHandlers::DamageCalcUserItem.add(:MAGNET, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:ELECTRIC) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:ELECTRIC) } ) @@ -637,7 +637,7 @@ BattleHandlers::DamageCalcUserItem.copy(:MAGNET,:ZAPPLATE) BattleHandlers::DamageCalcUserItem.add(:METALCOAT, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:STEEL) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:STEEL) } ) @@ -646,13 +646,13 @@ BattleHandlers::DamageCalcUserItem.copy(:METALCOAT,:IRONPLATE) BattleHandlers::DamageCalcUserItem.add(:METRONOME, proc { |item,user,target,move,mults,baseDmg,type| met = 1+0.2*[user.effects[PBEffects::Metronome],5].min - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*met).round + mults[FINAL_DMG_MULT] *= met } ) BattleHandlers::DamageCalcUserItem.add(:MIRACLESEED, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:GRASS) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:GRASS) } ) @@ -660,13 +660,13 @@ BattleHandlers::DamageCalcUserItem.copy(:MIRACLESEED,:MEADOWPLATE,:ROSEINCENSE) BattleHandlers::DamageCalcUserItem.add(:MUSCLEBAND, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.1).round if move.physicalMove? + mults[BASE_DMG_MULT] *= 1.1 if move.physicalMove? } ) BattleHandlers::DamageCalcUserItem.add(:MYSTICWATER, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:WATER) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:WATER) } ) @@ -674,7 +674,7 @@ BattleHandlers::DamageCalcUserItem.copy(:MYSTICWATER,:SPLASHPLATE,:SEAINCENSE,:W BattleHandlers::DamageCalcUserItem.add(:NEVERMELTICE, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:ICE) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:ICE) } ) @@ -688,13 +688,13 @@ BattleHandlers::DamageCalcUserItem.add(:NORMALGEM, BattleHandlers::DamageCalcUserItem.add(:PIXIEPLATE, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:FAIRY) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:FAIRY) } ) BattleHandlers::DamageCalcUserItem.add(:POISONBARB, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:POISON) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:POISON) } ) @@ -720,7 +720,7 @@ BattleHandlers::DamageCalcUserItem.add(:ROCKGEM, BattleHandlers::DamageCalcUserItem.add(:SHARPBEAK, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:FLYING) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:FLYING) } ) @@ -728,13 +728,13 @@ BattleHandlers::DamageCalcUserItem.copy(:SHARPBEAK,:SKYPLATE) BattleHandlers::DamageCalcUserItem.add(:SILKSCARF, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:NORMAL) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:NORMAL) } ) BattleHandlers::DamageCalcUserItem.add(:SILVERPOWDER, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:BUG) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:BUG) } ) @@ -742,7 +742,7 @@ BattleHandlers::DamageCalcUserItem.copy(:SILVERPOWDER,:INSECTPLATE) BattleHandlers::DamageCalcUserItem.add(:SOFTSAND, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:GROUND) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:GROUND) } ) @@ -753,11 +753,11 @@ BattleHandlers::DamageCalcUserItem.add(:SOULDEW, next if !user.isSpecies?(:LATIAS) && !user.isSpecies?(:LATIOS) if NEWEST_BATTLE_MECHANICS if isConst?(type,PBTypes,:PSYCHIC) || isConst?(type,PBTypes,:DRAGON) - mults[FINAL_DMG_MULT] = (mults[FINAL_DMG_MULT]*1.2).round + mults[FINAL_DMG_MULT] *= 1.2 end else if move.specialMove? && !user.battle.rules["souldewclause"] - mults[ATK_MULT] = (mults[ATK_MULT]*1.5).round + mults[ATK_MULT] *= 1.5 end end } @@ -765,7 +765,7 @@ BattleHandlers::DamageCalcUserItem.add(:SOULDEW, BattleHandlers::DamageCalcUserItem.add(:SPELLTAG, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:GHOST) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:GHOST) } ) @@ -787,7 +787,7 @@ BattleHandlers::DamageCalcUserItem.add(:THICKCLUB, BattleHandlers::DamageCalcUserItem.add(:TWISTEDSPOON, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.2).round if isConst?(type,PBTypes,:PSYCHIC) + mults[BASE_DMG_MULT] *= 1.2 if isConst?(type,PBTypes,:PSYCHIC) } ) @@ -801,7 +801,7 @@ BattleHandlers::DamageCalcUserItem.add(:WATERGEM, BattleHandlers::DamageCalcUserItem.add(:WISEGLASSES, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] = (mults[BASE_DMG_MULT]*1.1).round if move.specialMove? + mults[BASE_DMG_MULT] *= 1.1 if move.specialMove? } ) @@ -814,7 +814,7 @@ BattleHandlers::DamageCalcUserItem.add(:WISEGLASSES, BattleHandlers::DamageCalcTargetItem.add(:ASSAULTVEST, proc { |item,user,target,move,mults,baseDmg,type| - mults[DEF_MULT] = (mults[DEF_MULT]*1.5).round if move.specialMove? + mults[DEF_MULT] *= 1.5 if move.specialMove? } ) @@ -869,7 +869,7 @@ BattleHandlers::DamageCalcTargetItem.add(:EVIOLITE, # evolve even if the species generally can, and such forms are not # affected by Eviolite. evos = pbGetEvolvedFormData(target.pokemon.fSpecies,true) - mults[DEF_MULT] = (mults[DEF_MULT]*1.5).round if evos && evos.length>0 + mults[DEF_MULT] *= 1.5 if evos && evos.length>0 } ) @@ -894,7 +894,7 @@ BattleHandlers::DamageCalcTargetItem.add(:KEBIABERRY, BattleHandlers::DamageCalcTargetItem.add(:METALPOWDER, proc { |item,user,target,move,mults,baseDmg,type| if target.isSpecies?(:DITTO) && !target.effects[PBEffects::Transform] - mults[DEF_MULT] = (mults[DEF_MULT]*1.5).round + mults[DEF_MULT] *= 1.5 end } ) @@ -940,7 +940,7 @@ BattleHandlers::DamageCalcTargetItem.add(:SOULDEW, next if NEWEST_BATTLE_MECHANICS next if !target.isSpecies?(:LATIAS) && !target.isSpecies?(:LATIOS) if move.specialMove? && !user.battle.rules["souldewclause"] - mults[DEF_MULT] = (mults[DEF_MULT]*1.5).round + mults[DEF_MULT] *= 1.5 end } ) @@ -1003,7 +1003,7 @@ BattleHandlers::TargetItemOnHit.add(:ABSORBBULB, next if !target.pbCanRaiseStatStage?(PBStats::SPATK,target) battle.pbCommonAnimation("UseItem",target) target.pbRaiseStatStageByCause(PBStats::SPATK,1,target,target.itemName) - target.pbConsumeItem + target.pbHeldItemTriggered(item) } ) @@ -1011,6 +1011,7 @@ BattleHandlers::TargetItemOnHit.add(:AIRBALLOON, proc { |item,user,target,move,battle| battle.pbDisplay(_INTL("{1}'s {2} popped!",target.pbThis,target.itemName)) target.pbConsumeItem(false,true) + target.pbSymbiosis } ) @@ -1020,7 +1021,7 @@ BattleHandlers::TargetItemOnHit.add(:CELLBATTERY, next if !target.pbCanRaiseStatStage?(PBStats::ATTACK,target) battle.pbCommonAnimation("UseItem",target) target.pbRaiseStatStageByCause(PBStats::ATTACK,1,target,target.itemName) - target.pbConsumeItem + target.pbHeldItemTriggered(item) } ) @@ -1028,7 +1029,9 @@ BattleHandlers::TargetItemOnHit.add(:ENIGMABERRY, proc { |item,user,target,move,battle| next if target.damageState.substitute || target.damageState.disguise next if !PBTypes.superEffective?(target.damageState.typeMod) - BattleHandlers.triggerTargetItemOnHitPositiveBerry(item,target,battle,false) + if BattleHandlers.triggerTargetItemOnHitPositiveBerry(item,target,battle,false) + target.pbHeldItemTriggered(item) + end } ) @@ -1042,7 +1045,7 @@ BattleHandlers::TargetItemOnHit.add(:JABOCABERRY, user.pbReduceHP(user.totalhp/8,false) battle.pbDisplay(_INTL("{1} consumed its {2} and hurt {3}!",target.pbThis, target.itemName,user.pbThis(true))) - target.pbConsumeItem + target.pbHeldItemTriggered(item) } ) @@ -1054,7 +1057,9 @@ BattleHandlers::TargetItemOnHit.add(:JABOCABERRY, BattleHandlers::TargetItemOnHit.add(:KEEBERRY, proc { |item,user,target,move,battle| next if !move.physicalMove? - BattleHandlers.triggerTargetItemOnHitPositiveBerry(item,target,battle,false) + if BattleHandlers.triggerTargetItemOnHitPositiveBerry(item,target,battle,false) + target.pbHeldItemTriggered(item) + end } ) @@ -1064,7 +1069,7 @@ BattleHandlers::TargetItemOnHit.add(:LUMINOUSMOSS, next if !target.pbCanRaiseStatStage?(PBStats::SPDEF,target) battle.pbCommonAnimation("UseItem",target) target.pbRaiseStatStageByCause(PBStats::SPDEF,1,target,target.itemName) - target.pbConsumeItem + target.pbHeldItemTriggered(item) } ) @@ -1076,7 +1081,9 @@ BattleHandlers::TargetItemOnHit.add(:LUMINOUSMOSS, BattleHandlers::TargetItemOnHit.add(:MARANGABERRY, proc { |item,user,target,move,battle| next if !move.specialMove? - BattleHandlers.triggerTargetItemOnHitPositiveBerry(item,target,battle,false) + if BattleHandlers.triggerTargetItemOnHitPositiveBerry(item,target,battle,false) + target.pbHeldItemTriggered(item) + end } ) @@ -1100,7 +1107,7 @@ BattleHandlers::TargetItemOnHit.add(:ROWAPBERRY, user.pbReduceHP(user.totalhp/8,false) battle.pbDisplay(_INTL("{1} consumed its {2} and hurt {3}!",target.pbThis, target.itemName,user.pbThis(true))) - target.pbConsumeItem + target.pbHeldItemTriggered(item) } ) @@ -1110,7 +1117,7 @@ BattleHandlers::TargetItemOnHit.add(:SNOWBALL, next if !target.pbCanRaiseStatStage?(PBStats::ATTACK,target) battle.pbCommonAnimation("UseItem",target) target.pbRaiseStatStageByCause(PBStats::ATTACK,1,target,target.itemName) - target.pbConsumeItem + target.pbHeldItemTriggered(item) } ) @@ -1147,7 +1154,7 @@ BattleHandlers::TargetItemOnHit.add(:WEAKNESSPOLICY, if target.pbCanRaiseStatStage?(PBStats::SPATK,target) target.pbRaiseStatStageByCause(PBStats::SPATK,2,target,target.itemName,showAnim) end - target.pbConsumeItem + target.pbHeldItemTriggered(item) } ) @@ -1509,7 +1516,7 @@ BattleHandlers::EORHealingItem.add(:LEFTOVERS, BattleHandlers::EOREffectItem.add(:FLAMEORB, proc { |item,battler,battle| - next if !battler.pbCanBurn?(battler,false) + next if !battler.pbCanBurn?(nil,false) battler.pbBurn(nil,_INTL("{1} was burned by the {2}!",battler.pbThis,battler.itemName)) } ) @@ -1529,7 +1536,7 @@ BattleHandlers::EOREffectItem.add(:STICKYBARB, BattleHandlers::EOREffectItem.add(:TOXICORB, proc { |item,battler,battle| - next if !battler.pbCanPoison?(battler,false) + next if !battler.pbCanPoison?(nil,false) battler.pbPoison(nil,_INTL("{1} was badly poisoned by the {2}!", battler.pbThis,battler.itemName),true) } diff --git a/Data/Scripts/013_Overworld/002_PField_Field.rb b/Data/Scripts/013_Overworld/002_PField_Field.rb index 394e1de26..04d15f8e1 100644 --- a/Data/Scripts/013_Overworld/002_PField_Field.rb +++ b/Data/Scripts/013_Overworld/002_PField_Field.rb @@ -54,6 +54,7 @@ module Events @@OnWildBattleOverride = Event.new @@OnWildBattleEnd = Event.new @@OnTrainerPartyLoad = Event.new + @@OnChangeDirection = Event.new # Fires whenever a map is created. Event handler receives two parameters: the # map (RPG::Map) and the tileset (RPG::Tileset) @@ -159,6 +160,10 @@ module Events # e[2] - Party def self.onTrainerPartyLoad; @@OnTrainerPartyLoad; end def self.onTrainerPartyLoad=(v); @@OnTrainerPartyLoad = v; end + + # Fires whenever the player changes direction. + def self.onChangeDirection; @@OnChangeDirection; end + def self.onChangeDirection=(v); @@OnChangeDirection = v; end end @@ -254,7 +259,7 @@ Events.onMapUpdate += proc { |_sender,_e| # Checks per step #=============================================================================== # Party Pokémon gain happiness from walking -Events.onStepTaken += proc{ +Events.onStepTaken += proc { $PokemonGlobal.happinessSteps = 0 if !$PokemonGlobal.happinessSteps $PokemonGlobal.happinessSteps += 1 if $PokemonGlobal.happinessSteps>=128 @@ -363,26 +368,34 @@ def pbOnStepTaken(eventTriggered) Events.onStepTakenTransferPossible.trigger(nil,handled) return if handled[0] pbBattleOnStepTaken(repel) if !eventTriggered && !$game_temp.in_menu + $PokemonTemp.encounterTriggered = false # This info isn't needed end -def pbBattleOnStepTaken(repel=false) - return if $Trainer.ablePokemonCount==0 +# Start wild encounters while turning on the spot +Events.onChangeDirection += proc { + repel = ($PokemonGlobal.repel > 0) + pbBattleOnStepTaken(repel) if !$game_temp.in_menu +} + +def pbBattleOnStepTaken(repel = false) + return if $Trainer.ablePokemonCount == 0 encounterType = $PokemonEncounters.pbEncounterType - return if encounterType<0 + return if encounterType < 0 return if !$PokemonEncounters.isEncounterPossibleHere? $PokemonTemp.encounterType = encounterType encounter = $PokemonEncounters.pbGenerateEncounter(encounterType) encounter = EncounterModifier.trigger(encounter) - if $PokemonEncounters.pbCanEncounter?(encounter,repel) + if $PokemonEncounters.pbCanEncounter?(encounter, repel) if !$PokemonTemp.forceSingleBattle && !pbInSafari? && ($PokemonGlobal.partner || - ($Trainer.ablePokemonCount>1 && PBTerrain.isDoubleWildBattle?(pbGetTerrainTag) && rand(100)<30)) + ($Trainer.ablePokemonCount > 1 && PBTerrain.isDoubleWildBattle?(pbGetTerrainTag) && rand(100) < 30)) encounter2 = $PokemonEncounters.pbEncounteredPokemon(encounterType) encounter2 = EncounterModifier.trigger(encounter2) - pbDoubleWildBattle(encounter[0],encounter[1],encounter2[0],encounter2[1]) + pbDoubleWildBattle(encounter[0], encounter[1], encounter2[0], encounter2[1]) else - pbWildBattle(encounter[0],encounter[1]) + pbWildBattle(encounter[0], encounter[1]) end $PokemonTemp.encounterType = -1 + $PokemonTemp.encounterTriggered = true end $PokemonTemp.forceSingleBattle = false EncounterModifier.triggerEncounterEnd @@ -489,6 +502,421 @@ Events.onMapSceneChange += proc { |_sender,e| +#=============================================================================== +# Event locations, terrain tags +#=============================================================================== +def pbEventFacesPlayer?(event,player,distance) + return false if distance<=0 + # Event can't reach player if no coordinates coincide + return false if event.x!=player.x && event.y!=player.y + deltaX = (event.direction==6) ? 1 : (event.direction==4) ? -1 : 0 + deltaY = (event.direction==2) ? 1 : (event.direction==8) ? -1 : 0 + # Check for existence of player + curx = event.x + cury = event.y + found = false + distance.times do + curx += deltaX + cury += deltaY + if player.x==curx && player.y==cury + found = true + break + end + end + return found +end + +def pbEventCanReachPlayer?(event,player,distance) + return false if distance<=0 + # Event can't reach player if no coordinates coincide + return false if event.x!=player.x && event.y!=player.y + deltaX = (event.direction==6) ? 1 : (event.direction==4) ? -1 : 0 + deltaY = (event.direction==2) ? 1 : (event.direction==8) ? -1 : 0 + # Check for existence of player + curx = event.x + cury = event.y + found = false + realdist = 0 + distance.times do + curx += deltaX + cury += deltaY + if player.x==curx && player.y==cury + found = true + break + end + realdist += 1 + end + return false if !found + # Check passibility + curx = event.x + cury = event.y + realdist.times do + return false if !event.passable?(curx,cury,event.direction) + curx += deltaX + cury += deltaY + end + return true +end + +def pbFacingTileRegular(direction=nil,event=nil) + event = $game_player if !event + return [0,0,0] if !event + x = event.x + y = event.y + direction = event.direction if !direction + case direction + when 1; y += 1; x -= 1 + when 2; y += 1 + when 3; y += 1; x += 1 + when 4; x -= 1 + when 6; x += 1 + when 7; y -= 1; x -= 1 + when 8; y -= 1 + when 9; y -= 1; x += 1 + end + return [$game_map.map_id,x,y] +end + +def pbFacingTile(direction=nil,event=nil) + return $MapFactory.getFacingTile(direction,event) if $MapFactory + return pbFacingTileRegular(direction,event) +end + +def pbFacingEachOther(event1,event2) + return false if !event1 || !event2 + if $MapFactory + tile1 = $MapFactory.getFacingTile(nil,event1) + tile2 = $MapFactory.getFacingTile(nil,event2) + return false if !tile1 || !tile2 + return tile1[0]==event2.map.map_id && + tile1[1]==event2.x && tile1[2]==event2.y && + tile2[0]==event1.map.map_id && + tile2[1]==event1.x && tile2[2]==event1.y + else + tile1 = pbFacingTile(nil,event1) + tile2 = pbFacingTile(nil,event2) + return false if !tile1 || !tile2 + return tile1[1]==event2.x && tile1[2]==event2.y && + tile2[1]==event1.x && tile2[2]==event1.y + end +end + +def pbGetTerrainTag(event=nil,countBridge=false) + event = $game_player if !event + return 0 if !event + if $MapFactory + return $MapFactory.getTerrainTag(event.map.map_id,event.x,event.y,countBridge) + end + $game_map.terrain_tag(event.x,event.y,countBridge) +end + +def pbFacingTerrainTag(event=nil,dir=nil) + if $MapFactory + return $MapFactory.getFacingTerrainTag(dir,event) + end + event = $game_player if !event + return 0 if !event + facing = pbFacingTile(dir,event) + return $game_map.terrain_tag(facing[1],facing[2]) +end + + + +#=============================================================================== +# Events +#=============================================================================== +class Game_Event + def cooledDown?(seconds) + return true if expired?(seconds) && tsOff?("A") + self.need_refresh = true + return false + end + + def cooledDownDays?(days) + return true if expiredDays?(days) && tsOff?("A") + self.need_refresh = true + return false + end +end + + + +module InterpreterFieldMixin + # Used in boulder events. Allows an event to be pushed. To be used in + # a script event command. + def pbPushThisEvent + event = get_character(0) + oldx = event.x + oldy = event.y + # Apply strict version of passable, which makes impassable + # tiles that are passable only from certain directions + return if !event.passableStrict?(event.x,event.y,$game_player.direction) + case $game_player.direction + when 2; event.move_down # down + when 4; event.move_left # left + when 6; event.move_right # right + when 8; event.move_up # up + end + $PokemonMap.addMovedEvent(@event_id) if $PokemonMap + if oldx!=event.x || oldy!=event.y + $game_player.lock + loop do + Graphics.update + Input.update + pbUpdateSceneMap + break if !event.moving? + end + $game_player.unlock + end + end + + def pbPushThisBoulder + pbPushThisEvent if $PokemonMap.strengthUsed + return true + end + + def pbSmashThisEvent + event = get_character(0) + pbSmashEvent(event) if event + @index += 1 + return true + end + + def pbTrainerIntro(symbol) + return if $DEBUG && !pbTrainerTypeCheck(symbol) + trtype = PBTrainers.const_get(symbol) + pbGlobalLock + pbPlayTrainerIntroME(trtype) + return true + end + + def pbTrainerEnd + pbGlobalUnlock + e = get_character(0) + e.erase_route if e + end + + def pbParams + (@parameters) ? @parameters : @params + end + + def pbGetPokemon(id) + return $Trainer.party[pbGet(id)] + end + + def pbSetEventTime(*arg) + $PokemonGlobal.eventvars = {} if !$PokemonGlobal.eventvars + time = pbGetTimeNow + time = time.to_i + pbSetSelfSwitch(@event_id,"A",true) + $PokemonGlobal.eventvars[[@map_id,@event_id]]=time + for otherevt in arg + pbSetSelfSwitch(otherevt,"A",true) + $PokemonGlobal.eventvars[[@map_id,otherevt]]=time + end + end + + def getVariable(*arg) + if arg.length==0 + return nil if !$PokemonGlobal.eventvars + return $PokemonGlobal.eventvars[[@map_id,@event_id]] + else + return $game_variables[arg[0]] + end + end + + def setVariable(*arg) + if arg.length==1 + $PokemonGlobal.eventvars = {} if !$PokemonGlobal.eventvars + $PokemonGlobal.eventvars[[@map_id,@event_id]]=arg[0] + else + $game_variables[arg[0]] = arg[1] + $game_map.need_refresh = true + end + end + + def tsOff?(c) + get_character(0).tsOff?(c) + end + + def tsOn?(c) + get_character(0).tsOn?(c) + end + + alias isTempSwitchOn? tsOn? + alias isTempSwitchOff? tsOff? + + def setTempSwitchOn(c) + get_character(0).setTempSwitchOn(c) + end + + def setTempSwitchOff(c) + get_character(0).setTempSwitchOff(c) + end + + # Must use this approach to share the methods because the methods already + # defined in a class override those defined in an included module + CustomEventCommands=<<_END_ + + def command_352 + scene = PokemonSave_Scene.new + screen = PokemonSaveScreen.new(scene) + screen.pbSaveScreen + return true + end + + def command_125 + value = operate_value(pbParams[0], pbParams[1], pbParams[2]) + $Trainer.money += value + return true + end + + def command_132 + ($PokemonGlobal.nextBattleBGM = pbParams[0]) ? pbParams[0].clone : nil + return true + end + + def command_133 + ($PokemonGlobal.nextBattleME = pbParams[0]) ? pbParams[0].clone : nil + return true + end + + def command_353 + pbBGMFade(1.0) + pbBGSFade(1.0) + pbFadeOutIn { pbStartOver(true) } + end + + def command_314 + pbHealAll if pbParams[0]==0 + return true + end + +_END_ +end + + + +class Interpreter + include InterpreterFieldMixin + eval(InterpreterFieldMixin::CustomEventCommands) +end + + + +class Game_Interpreter + include InterpreterFieldMixin + eval(InterpreterFieldMixin::CustomEventCommands) +end + + + +#=============================================================================== +# Audio playing +#=============================================================================== +def pbCueBGM(bgm,seconds,volume=nil,pitch=nil) + return if !bgm + bgm = pbResolveAudioFile(bgm,volume,pitch) + playingBGM = $game_system.playing_bgm + if !playingBGM || playingBGM.name!=bgm.name || playingBGM.pitch!=bgm.pitch + pbBGMFade(seconds) + if !$PokemonTemp.cueFrames + $PokemonTemp.cueFrames = (seconds*Graphics.frame_rate)*3/5 + end + $PokemonTemp.cueBGM=bgm + elsif playingBGM + pbBGMPlay(bgm) + end +end + +def pbAutoplayOnTransition + surfbgm = pbGetMetadata(0,MetadataSurfBGM) + if $PokemonGlobal.surfing && surfbgm + pbBGMPlay(surfbgm) + else + $game_map.autoplayAsCue + end +end + +def pbAutoplayOnSave + surfbgm = pbGetMetadata(0,MetadataSurfBGM) + if $PokemonGlobal.surfing && surfbgm + pbBGMPlay(surfbgm) + else + $game_map.autoplay + end +end + + + +#=============================================================================== +# Voice recorder +#=============================================================================== +def pbRecord(text,maxtime=30.0) + text = "" if !text + textwindow = Window_UnformattedTextPokemon.newWithSize(text,0,0,Graphics.width,Graphics.height-96) + textwindow.z=99999 + if text=="" + textwindow.visible = false + end + wave = nil + msgwindow = pbCreateMessageWindow + oldvolume = Audio_bgm_get_volume() + Audio_bgm_set_volume(0) + delay = 2 + delay.times do |i| + pbMessageDisplay(msgwindow,_INTL("Recording in {1} second(s)...\nPress ESC to cancel.",delay-i),false) + Graphics.frame_rate.times do + Graphics.update + Input.update + textwindow.update + msgwindow.update + if Input.trigger?(Input::B) + Audio_bgm_set_volume(oldvolume) + pbDisposeMessageWindow(msgwindow) + textwindow.dispose + return nil + end + end + end + pbMessageDisplay(msgwindow,_INTL("NOW RECORDING\nPress ESC to stop recording."),false) + if beginRecordUI + frames = (maxtime*Graphics.frame_rate).to_i + frames.times do + Graphics.update + Input.update + textwindow.update + msgwindow.update + if Input.trigger?(Input::B) + break + end + end + tmpFile = ENV["TEMP"]+"\\record.wav" + endRecord(tmpFile) + wave = getWaveDataUI(tmpFile,true) + if wave + pbMessageDisplay(msgwindow,_INTL("PLAYING BACK..."),false) + textwindow.update + msgwindow.update + Graphics.update + Input.update + wave.play + (Graphics.frame_rate*wave.time).to_i.times do + Graphics.update + Input.update + textwindow.update + msgwindow.update + end + end + end + Audio_bgm_set_volume(oldvolume) + pbDisposeMessageWindow(msgwindow) + textwindow.dispose + return wave +end + + + #=============================================================================== # Event movement #=============================================================================== @@ -895,414 +1323,6 @@ end -#=============================================================================== -# Event locations, terrain tags -#=============================================================================== -def pbEventFacesPlayer?(event,player,distance) - return false if distance<=0 - # Event can't reach player if no coordinates coincide - return false if event.x!=player.x && event.y!=player.y - deltaX = (event.direction==6) ? 1 : (event.direction==4) ? -1 : 0 - deltaY = (event.direction==2) ? 1 : (event.direction==8) ? -1 : 0 - # Check for existence of player - curx = event.x - cury = event.y - found = false - distance.times do - curx += deltaX - cury += deltaY - if player.x==curx && player.y==cury - found = true - break - end - end - return found -end - -def pbEventCanReachPlayer?(event,player,distance) - return false if distance<=0 - # Event can't reach player if no coordinates coincide - return false if event.x!=player.x && event.y!=player.y - deltaX = (event.direction==6) ? 1 : (event.direction==4) ? -1 : 0 - deltaY = (event.direction==2) ? 1 : (event.direction==8) ? -1 : 0 - # Check for existence of player - curx = event.x - cury = event.y - found = false - realdist = 0 - distance.times do - curx += deltaX - cury += deltaY - if player.x==curx && player.y==cury - found = true - break - end - realdist += 1 - end - return false if !found - # Check passibility - curx = event.x - cury = event.y - realdist.times do - return false if !event.passable?(curx,cury,event.direction) - curx += deltaX - cury += deltaY - end - return true -end - -def pbFacingTileRegular(direction=nil,event=nil) - event = $game_player if !event - return [0,0,0] if !event - x = event.x - y = event.y - direction = event.direction if !direction - case direction - when 1; y += 1; x -= 1 - when 2; y += 1 - when 3; y += 1; x += 1 - when 4; x -= 1 - when 6; x += 1 - when 7; y -= 1; x -= 1 - when 8; y -= 1 - when 9; y -= 1; x += 1 - end - return [$game_map.map_id,x,y] -end - -def pbFacingTile(direction=nil,event=nil) - return $MapFactory.getFacingTile(direction,event) if $MapFactory - return pbFacingTileRegular(direction,event) -end - -def pbFacingEachOther(event1,event2) - return false if !event1 || !event2 - if $MapFactory - tile1 = $MapFactory.getFacingTile(nil,event1) - tile2 = $MapFactory.getFacingTile(nil,event2) - return false if !tile1 || !tile2 - return tile1[0]==event2.map.map_id && - tile1[1]==event2.x && tile1[2]==event2.y && - tile2[0]==event1.map.map_id && - tile2[1]==event1.x && tile2[2]==event1.y - else - tile1 = pbFacingTile(nil,event1) - tile2 = pbFacingTile(nil,event2) - return false if !tile1 || !tile2 - return tile1[1]==event2.x && tile1[2]==event2.y && - tile2[1]==event1.x && tile2[2]==event1.y - end -end - -def pbGetTerrainTag(event=nil,countBridge=false) - event = $game_player if !event - return 0 if !event - if $MapFactory - return $MapFactory.getTerrainTag(event.map.map_id,event.x,event.y,countBridge) - end - $game_map.terrain_tag(event.x,event.y,countBridge) -end - -def pbFacingTerrainTag(event=nil,dir=nil) - if $MapFactory - return $MapFactory.getFacingTerrainTag(dir,event) - end - event = $game_player if !event - return 0 if !event - facing = pbFacingTile(dir,event) - return $game_map.terrain_tag(facing[1],facing[2]) -end - - - -#=============================================================================== -# Events -#=============================================================================== -class Game_Event - def cooledDown?(seconds) - return true if expired?(seconds) && tsOff?("A") - self.need_refresh = true - return false - end - - def cooledDownDays?(days) - return true if expiredDays?(days) && tsOff?("A") - self.need_refresh = true - return false - end -end - - - -module InterpreterFieldMixin - # Used in boulder events. Allows an event to be pushed. To be used in - # a script event command. - def pbPushThisEvent - event = get_character(0) - oldx = event.x - oldy = event.y - # Apply strict version of passable, which makes impassable - # tiles that are passable only from certain directions - return if !event.passableStrict?(event.x,event.y,$game_player.direction) - case $game_player.direction - when 2; event.move_down # down - when 4; event.move_left # left - when 6; event.move_right # right - when 8; event.move_up # up - end - $PokemonMap.addMovedEvent(@event_id) if $PokemonMap - if oldx!=event.x || oldy!=event.y - $game_player.lock - loop do - Graphics.update - Input.update - pbUpdateSceneMap - break if !event.moving? - end - $game_player.unlock - end - end - - def pbPushThisBoulder - pbPushThisEvent if $PokemonMap.strengthUsed - return true - end - - def pbSmashThisEvent - event = get_character(0) - pbSmashEvent(event) if event - @index += 1 - return true - end - - def pbTrainerIntro(symbol) - return if $DEBUG && !pbTrainerTypeCheck(symbol) - trtype = PBTrainers.const_get(symbol) - pbGlobalLock - pbPlayTrainerIntroME(trtype) - return true - end - - def pbTrainerEnd - pbGlobalUnlock - e = get_character(0) - e.erase_route if e - end - - def pbParams - (@parameters) ? @parameters : @params - end - - def pbGetPokemon(id) - return $Trainer.party[pbGet(id)] - end - - def pbSetEventTime(*arg) - $PokemonGlobal.eventvars = {} if !$PokemonGlobal.eventvars - time = pbGetTimeNow - time = time.to_i - pbSetSelfSwitch(@event_id,"A",true) - $PokemonGlobal.eventvars[[@map_id,@event_id]]=time - for otherevt in arg - pbSetSelfSwitch(otherevt,"A",true) - $PokemonGlobal.eventvars[[@map_id,otherevt]]=time - end - end - - def getVariable(*arg) - if arg.length==0 - return nil if !$PokemonGlobal.eventvars - return $PokemonGlobal.eventvars[[@map_id,@event_id]] - else - return $game_variables[arg[0]] - end - end - - def setVariable(*arg) - if arg.length==1 - $PokemonGlobal.eventvars = {} if !$PokemonGlobal.eventvars - $PokemonGlobal.eventvars[[@map_id,@event_id]]=arg[0] - else - $game_variables[arg[0]] = arg[1] - $game_map.need_refresh = true - end - end - - def tsOff?(c) - get_character(0).tsOff?(c) - end - - def tsOn?(c) - get_character(0).tsOn?(c) - end - - alias isTempSwitchOn? tsOn? - alias isTempSwitchOff? tsOff? - - def setTempSwitchOn(c) - get_character(0).setTempSwitchOn(c) - end - - def setTempSwitchOff(c) - get_character(0).setTempSwitchOff(c) - end - - # Must use this approach to share the methods because the methods already - # defined in a class override those defined in an included module - CustomEventCommands=<<_END_ - - def command_352 - scene = PokemonSave_Scene.new - screen = PokemonSaveScreen.new(scene) - screen.pbSaveScreen - return true - end - - def command_125 - value = operate_value(pbParams[0], pbParams[1], pbParams[2]) - $Trainer.money += value - return true - end - - def command_132 - ($PokemonGlobal.nextBattleBGM = pbParams[0]) ? pbParams[0].clone : nil - return true - end - - def command_133 - ($PokemonGlobal.nextBattleME = pbParams[0]) ? pbParams[0].clone : nil - return true - end - - def command_353 - pbBGMFade(1.0) - pbBGSFade(1.0) - pbFadeOutIn { pbStartOver(true) } - end - - def command_314 - pbHealAll if pbParams[0]==0 - return true - end - -_END_ -end - - - -class Interpreter - include InterpreterFieldMixin - eval(InterpreterFieldMixin::CustomEventCommands) -end - - - -#=============================================================================== -# Audio playing -#=============================================================================== -def pbCueBGM(bgm,seconds,volume=nil,pitch=nil) - return if !bgm - bgm = pbResolveAudioFile(bgm,volume,pitch) - playingBGM = $game_system.playing_bgm - if !playingBGM || playingBGM.name!=bgm.name || playingBGM.pitch!=bgm.pitch - pbBGMFade(seconds) - if !$PokemonTemp.cueFrames - $PokemonTemp.cueFrames = (seconds*Graphics.frame_rate)*3/5 - end - $PokemonTemp.cueBGM=bgm - elsif playingBGM - pbBGMPlay(bgm) - end -end - -def pbAutoplayOnTransition - surfbgm = pbGetMetadata(0,MetadataSurfBGM) - if $PokemonGlobal.surfing && surfbgm - pbBGMPlay(surfbgm) - else - $game_map.autoplayAsCue - end -end - -def pbAutoplayOnSave - surfbgm = pbGetMetadata(0,MetadataSurfBGM) - if $PokemonGlobal.surfing && surfbgm - pbBGMPlay(surfbgm) - else - $game_map.autoplay - end -end - - - -#=============================================================================== -# Voice recorder -#=============================================================================== -def pbRecord(text,maxtime=30.0) - text = "" if !text - textwindow = Window_UnformattedTextPokemon.newWithSize(text,0,0,Graphics.width,Graphics.height-96) - textwindow.z=99999 - if text=="" - textwindow.visible = false - end - wave = nil - msgwindow = pbCreateMessageWindow - oldvolume = Audio_bgm_get_volume() - Audio_bgm_set_volume(0) - delay = 2 - delay.times do |i| - pbMessageDisplay(msgwindow,_INTL("Recording in {1} second(s)...\nPress ESC to cancel.",delay-i),false) - Graphics.frame_rate.times do - Graphics.update - Input.update - textwindow.update - msgwindow.update - if Input.trigger?(Input::B) - Audio_bgm_set_volume(oldvolume) - pbDisposeMessageWindow(msgwindow) - textwindow.dispose - return nil - end - end - end - pbMessageDisplay(msgwindow,_INTL("NOW RECORDING\nPress ESC to stop recording."),false) - if beginRecordUI - frames = (maxtime*Graphics.frame_rate).to_i - frames.times do - Graphics.update - Input.update - textwindow.update - msgwindow.update - if Input.trigger?(Input::B) - break - end - end - tmpFile = ENV["TEMP"]+"\\record.wav" - endRecord(tmpFile) - wave = getWaveDataUI(tmpFile,true) - if wave - pbMessageDisplay(msgwindow,_INTL("PLAYING BACK..."),false) - textwindow.update - msgwindow.update - Graphics.update - Input.update - wave.play - (Graphics.frame_rate*wave.time).to_i.times do - Graphics.update - Input.update - textwindow.update - msgwindow.update - end - end - end - Audio_bgm_set_volume(oldvolume) - pbDisposeMessageWindow(msgwindow) - textwindow.dispose - return wave -end - - - #=============================================================================== # Picking up an item found on the ground #=============================================================================== diff --git a/Data/Scripts/013_Overworld/003_PField_Visuals.rb b/Data/Scripts/013_Overworld/003_PField_Visuals.rb index 54aa7d0e1..925ed9b0b 100644 --- a/Data/Scripts/013_Overworld/003_PField_Visuals.rb +++ b/Data/Scripts/013_Overworld/003_PField_Visuals.rb @@ -1,228 +1,3 @@ -#=============================================================================== -# Location signpost -#=============================================================================== -class LocationWindow - def initialize(name) - @window = Window_AdvancedTextPokemon.new(name) - @window.resizeToFit(name,Graphics.width) - @window.x = 0 - @window.y = -@window.height - @window.height = 64 - @window.viewport = Viewport.new(0,0,Graphics.width,Graphics.height) - @window.viewport.z = 99999 - @currentmap = $game_map.map_id - @frames = 0 - end - - def disposed? - @window.disposed? - end - - def dispose - @window.dispose - end - - def update - return if @window.disposed? - @window.update - if $game_temp.message_window_showing || @currentmap!=$game_map.map_id - @window.dispose - return - end - if @frames>80 - @window.y -= 4 - @window.dispose if @window.y+@window.height<0 - else - @window.y += 4 if @window.y<0 - @frames += 1 - end - end -end - - - -#=============================================================================== -# Visibility circle in dark maps -#=============================================================================== -class DarknessSprite < SpriteWrapper - attr_reader :radius - - def initialize(viewport=nil) - super(viewport) - @darkness = BitmapWrapper.new(Graphics.width,Graphics.height) - @radius = radiusMin - self.bitmap = @darkness - self.z = 99998 - refresh - end - - def dispose - @darkness.dispose - super - end - - def radiusMin; return 64; end # Before using Flash - def radiusMax; return 176; end # After using Flash - - def radius=(value) - @radius = value - refresh - end - - def refresh - @darkness.fill_rect(0,0,Graphics.width,Graphics.height,Color.new(0,0,0,255)) - cx = Graphics.width/2 - cy = Graphics.height/2 - cradius = @radius - numfades = 5 - for i in 1..numfades - for j in cx-cradius..cx+cradius - diff2 = (cradius * cradius) - ((j - cx) * (j - cx)) - diff = Math.sqrt(diff2) - @darkness.fill_rect(j,cy-diff,1,diff*2,Color.new(0,0,0,255.0*(numfades-i)/numfades)) - end - cradius = (cradius*0.9).floor - end - end -end - - - -#=============================================================================== -# Lights -#=============================================================================== -class LightEffect - def initialize(event,viewport=nil,map=nil,filename=nil) - @light = IconSprite.new(0,0,viewport) - if filename!=nil && filename!="" && pbResolveBitmap("Graphics/Pictures/"+filename) - @light.setBitmap("Graphics/Pictures/"+filename) - else - @light.setBitmap("Graphics/Pictures/LE") - end - @light.z = 1000 - @event = event - @map = (map) ? map : $game_map - @disposed = false - end - - def disposed? - return @disposed - end - - def dispose - @light.dispose - @map = nil - @event = nil - @disposed = true - end - - def update - @light.update - end -end - - - -class LightEffect_Lamp < LightEffect - def initialize(event,viewport=nil,map=nil) - lamp = AnimatedBitmap.new("Graphics/Pictures/LE") - @light = Sprite.new(viewport) - @light.bitmap = Bitmap.new(128,64) - src_rect = Rect.new(0, 0, 64, 64) - @light.bitmap.blt(0, 0, lamp.bitmap, src_rect) - @light.bitmap.blt(20, 0, lamp.bitmap, src_rect) - @light.visible = true - @light.z = 1000 - lamp.dispose - @map = (map) ? map : $game_map - @event = event - end -end - - - -class LightEffect_Basic < LightEffect - def update - return if !@light || !@event - super - @light.opacity = 100 - @light.ox = 32 - @light.oy = 48 - if (Object.const_defined?(:ScreenPosHelper) rescue false) - @light.x = ScreenPosHelper.pbScreenX(@event) - @light.y = ScreenPosHelper.pbScreenY(@event) - @light.zoom_x = ScreenPosHelper.pbScreenZoomX(@event) - else - @light.x = @event.screen_x - @light.y = @event.screen_y - @light.zoom_x = 1.0 - end - @light.zoom_y = @light.zoom_x - @light.tone = $game_screen.tone - end -end - - - -class LightEffect_DayNight < LightEffect - def update - return if !@light || !@event - super - shade = PBDayNight.getShade - if shade>=144 # If light enough, call it fully day - shade = 255 - elsif shade<=64 # If dark enough, call it fully night - shade = 0 - else - shade = 255-(255*(144-shade)/(144-64)) - end - @light.opacity = 255-shade - if @light.opacity>0 - @light.ox = 32 - @light.oy = 48 - if (Object.const_defined?(:ScreenPosHelper) rescue false) - @light.x = ScreenPosHelper.pbScreenX(@event) - @light.y = ScreenPosHelper.pbScreenY(@event) - @light.zoom_x = ScreenPosHelper.pbScreenZoomX(@event) - @light.zoom_y = ScreenPosHelper.pbScreenZoomY(@event) - else - @light.x = @event.screen_x - @light.y = @event.screen_y - @light.zoom_x = 1.0 - @light.zoom_y = 1.0 - end - @light.tone.set($game_screen.tone.red, - $game_screen.tone.green, - $game_screen.tone.blue, - $game_screen.tone.gray) - end - end -end - - - -Events.onSpritesetCreate += proc { |_sender,e| - spriteset = e[0] # Spriteset being created - viewport = e[1] # Viewport used for tilemap and characters - map = spriteset.map # Map associated with the spriteset (not necessarily the current map) - for i in map.events.keys - if map.events[i].name[/^outdoorlight\((\w+)\)$/i] - filename = $~[1].to_s - spriteset.addUserSprite(LightEffect_DayNight.new(map.events[i],viewport,map,filename)) - elsif map.events[i].name.downcase=="outdoorlight" - spriteset.addUserSprite(LightEffect_DayNight.new(map.events[i],viewport,map)) - elsif map.events[i].name[/^light\((\w+)\)$/i] - filename = $~[1].to_s - spriteset.addUserSprite(LightEffect_Basic.new(map.events[i],viewport,map,filename)) - elsif map.events[i].name.downcase=="light" - spriteset.addUserSprite(LightEffect_Basic.new(map.events[i],viewport,map)) - end - end - spriteset.addUserSprite(Particle_Engine.new(viewport,map)) -} - - - #=============================================================================== # Battle start animation #=============================================================================== @@ -541,6 +316,231 @@ def pbBattleAnimationOverride(viewport,battletype=0,foe=nil) end + +#=============================================================================== +# Location signpost +#=============================================================================== +class LocationWindow + def initialize(name) + @window = Window_AdvancedTextPokemon.new(name) + @window.resizeToFit(name,Graphics.width) + @window.x = 0 + @window.y = -@window.height + @window.viewport = Viewport.new(0,0,Graphics.width,Graphics.height) + @window.viewport.z = 99999 + @currentmap = $game_map.map_id + @frames = 0 + end + + def disposed? + @window.disposed? + end + + def dispose + @window.dispose + end + + def update + return if @window.disposed? + @window.update + if $game_temp.message_window_showing || @currentmap!=$game_map.map_id + @window.dispose + return + end + if @frames>80 + @window.y -= 4 + @window.dispose if @window.y+@window.height<0 + else + @window.y += 4 if @window.y<0 + @frames += 1 + end + end +end + + + +#=============================================================================== +# Visibility circle in dark maps +#=============================================================================== +class DarknessSprite < SpriteWrapper + attr_reader :radius + + def initialize(viewport=nil) + super(viewport) + @darkness = BitmapWrapper.new(Graphics.width,Graphics.height) + @radius = radiusMin + self.bitmap = @darkness + self.z = 99998 + refresh + end + + def dispose + @darkness.dispose + super + end + + def radiusMin; return 64; end # Before using Flash + def radiusMax; return 176; end # After using Flash + + def radius=(value) + @radius = value + refresh + end + + def refresh + @darkness.fill_rect(0,0,Graphics.width,Graphics.height,Color.new(0,0,0,255)) + cx = Graphics.width/2 + cy = Graphics.height/2 + cradius = @radius + numfades = 5 + for i in 1..numfades + for j in cx-cradius..cx+cradius + diff2 = (cradius * cradius) - ((j - cx) * (j - cx)) + diff = Math.sqrt(diff2) + @darkness.fill_rect(j,cy-diff,1,diff*2,Color.new(0,0,0,255.0*(numfades-i)/numfades)) + end + cradius = (cradius*0.9).floor + end + end +end + + + +#=============================================================================== +# Lights +#=============================================================================== +class LightEffect + def initialize(event,viewport=nil,map=nil,filename=nil) + @light = IconSprite.new(0,0,viewport) + if filename!=nil && filename!="" && pbResolveBitmap("Graphics/Pictures/"+filename) + @light.setBitmap("Graphics/Pictures/"+filename) + else + @light.setBitmap("Graphics/Pictures/LE") + end + @light.z = 1000 + @event = event + @map = (map) ? map : $game_map + @disposed = false + end + + def disposed? + return @disposed + end + + def dispose + @light.dispose + @map = nil + @event = nil + @disposed = true + end + + def update + @light.update + end +end + + + +class LightEffect_Lamp < LightEffect + def initialize(event,viewport=nil,map=nil) + lamp = AnimatedBitmap.new("Graphics/Pictures/LE") + @light = Sprite.new(viewport) + @light.bitmap = Bitmap.new(128,64) + src_rect = Rect.new(0, 0, 64, 64) + @light.bitmap.blt(0, 0, lamp.bitmap, src_rect) + @light.bitmap.blt(20, 0, lamp.bitmap, src_rect) + @light.visible = true + @light.z = 1000 + lamp.dispose + @map = (map) ? map : $game_map + @event = event + end +end + + + +class LightEffect_Basic < LightEffect + def update + return if !@light || !@event + super + @light.opacity = 100 + @light.ox = 32 + @light.oy = 48 + if (Object.const_defined?(:ScreenPosHelper) rescue false) + @light.x = ScreenPosHelper.pbScreenX(@event) + @light.y = ScreenPosHelper.pbScreenY(@event) + @light.zoom_x = ScreenPosHelper.pbScreenZoomX(@event) + else + @light.x = @event.screen_x + @light.y = @event.screen_y + @light.zoom_x = 1.0 + end + @light.zoom_y = @light.zoom_x + @light.tone = $game_screen.tone + end +end + + + +class LightEffect_DayNight < LightEffect + def update + return if !@light || !@event + super + shade = PBDayNight.getShade + if shade>=144 # If light enough, call it fully day + shade = 255 + elsif shade<=64 # If dark enough, call it fully night + shade = 0 + else + shade = 255-(255*(144-shade)/(144-64)) + end + @light.opacity = 255-shade + if @light.opacity>0 + @light.ox = 32 + @light.oy = 48 + if (Object.const_defined?(:ScreenPosHelper) rescue false) + @light.x = ScreenPosHelper.pbScreenX(@event) + @light.y = ScreenPosHelper.pbScreenY(@event) + @light.zoom_x = ScreenPosHelper.pbScreenZoomX(@event) + @light.zoom_y = ScreenPosHelper.pbScreenZoomY(@event) + else + @light.x = @event.screen_x + @light.y = @event.screen_y + @light.zoom_x = 1.0 + @light.zoom_y = 1.0 + end + @light.tone.set($game_screen.tone.red, + $game_screen.tone.green, + $game_screen.tone.blue, + $game_screen.tone.gray) + end + end +end + + + +Events.onSpritesetCreate += proc { |_sender,e| + spriteset = e[0] # Spriteset being created + viewport = e[1] # Viewport used for tilemap and characters + map = spriteset.map # Map associated with the spriteset (not necessarily the current map) + for i in map.events.keys + if map.events[i].name[/^outdoorlight\((\w+)\)$/i] + filename = $~[1].to_s + spriteset.addUserSprite(LightEffect_DayNight.new(map.events[i],viewport,map,filename)) + elsif map.events[i].name.downcase=="outdoorlight" + spriteset.addUserSprite(LightEffect_DayNight.new(map.events[i],viewport,map)) + elsif map.events[i].name[/^light\((\w+)\)$/i] + filename = $~[1].to_s + spriteset.addUserSprite(LightEffect_Basic.new(map.events[i],viewport,map,filename)) + elsif map.events[i].name.downcase=="light" + spriteset.addUserSprite(LightEffect_Basic.new(map.events[i],viewport,map)) + end + end + spriteset.addUserSprite(Particle_Engine.new(viewport,map)) +} + + + #=============================================================================== # Entering/exiting cave animations #=============================================================================== diff --git a/Data/Scripts/013_Overworld/006_PField_Battles.rb b/Data/Scripts/013_Overworld/006_PField_Battles.rb index 87b40282c..40492caf2 100644 --- a/Data/Scripts/013_Overworld/006_PField_Battles.rb +++ b/Data/Scripts/013_Overworld/006_PField_Battles.rb @@ -11,6 +11,7 @@ end class PokemonTemp + attr_accessor :encounterTriggered attr_accessor :encounterType attr_accessor :evolutionLevels @@ -34,8 +35,8 @@ class PokemonTemp when "canrun"; rules["canRun"] = true when "cannotrun"; rules["canRun"] = false when "roamerflees"; rules["roamerFlees"] = true - when "noExp"; rules["expGain"] = false - when "noMoney"; rules["moneyGain"] = false + when "noexp"; rules["expGain"] = false + when "nomoney"; rules["moneyGain"] = false when "switchstyle"; rules["switchStyle"] = true when "setstyle"; rules["switchStyle"] = false when "anims"; rules["battleAnims"] = true @@ -45,7 +46,7 @@ class PokemonTemp when "environment", "environ"; rules["environment"] = getID(PBEnvironment,var) when "backdrop", "battleback"; rules["backdrop"] = var when "base"; rules["base"] = var - when "outcomevar", "outcome"; rules["outcomeVar"] = var + when "outcome", "outcomevar"; rules["outcomeVar"] = var when "nopartner"; rules["noPartner"] = true else raise _INTL("Battle rule \"{1}\" does not exist.",rule) @@ -64,7 +65,7 @@ def setBattleRule(*args) else case arg.downcase when "terrain", "weather", "environment", "environ", "backdrop", - "battleback", "base", "outcomevar", "outcome" + "battleback", "base", "outcome", "outcomevar" r = arg next end @@ -251,7 +252,12 @@ def pbWildBattleCore(*args) playerTrainers = [$Trainer] playerParty = $Trainer.party playerPartyStarts = [0] - if $PokemonGlobal.partner && !$PokemonTemp.battleRules["noPartner"] && foeParty.length>1 + room_for_partner = (foeParty.length > 1) + if !room_for_partner && $PokemonTemp.battleRules["size"] && + !["single", "1v1", "1v2", "1v3"].include?($PokemonTemp.battleRules["size"]) + room_for_partner = true + end + if $PokemonGlobal.partner && !$PokemonTemp.battleRules["noPartner"] && room_for_partner ally = PokeBattle_Trainer.new($PokemonGlobal.partner[1],$PokemonGlobal.partner[0]) ally.id = $PokemonGlobal.partner[2] ally.party = $PokemonGlobal.partner[3] @@ -391,7 +397,12 @@ def pbTrainerBattleCore(*args) playerTrainers = [$Trainer] playerParty = $Trainer.party playerPartyStarts = [0] - if $PokemonGlobal.partner && !$PokemonTemp.battleRules["noPartner"] && foeParty.length>1 + room_for_partner = (foeParty.length > 1) + if !room_for_partner && $PokemonTemp.battleRules["size"] && + !["single", "1v1", "1v2", "1v3"].include?($PokemonTemp.battleRules["size"]) + room_for_partner = true + end + if $PokemonGlobal.partner && !$PokemonTemp.battleRules["noPartner"] && room_for_partner ally = PokeBattle_Trainer.new($PokemonGlobal.partner[1],$PokemonGlobal.partner[0]) ally.id = $PokemonGlobal.partner[2] ally.party = $PokemonGlobal.partner[3] @@ -553,6 +564,7 @@ def pbAfterBattle(decision,canLose) end end Events.onEndBattle.trigger(nil,decision,canLose) + $game_player.straighten end Events.onEndBattle += proc { |_sender,e| diff --git a/Data/Scripts/013_Overworld/009_PField_RoamingPokemon.rb b/Data/Scripts/013_Overworld/009_PField_RoamingPokemon.rb index 9a2b86126..05aadd9b9 100644 --- a/Data/Scripts/013_Overworld/009_PField_RoamingPokemon.rb +++ b/Data/Scripts/013_Overworld/009_PField_RoamingPokemon.rb @@ -241,6 +241,6 @@ def pbRoamingPokemonBattle(species, level) return (decision!=2 && decision!=5) end -EncounterModifier.registerEncounterEnd(proc{ +EncounterModifier.registerEncounterEnd(proc { $PokemonTemp.roamerIndex = nil }) diff --git a/Data/Scripts/013_Overworld/011_PField_FieldMoves.rb b/Data/Scripts/013_Overworld/011_PField_FieldMoves.rb index c7fd4150b..6695c6a1e 100644 --- a/Data/Scripts/013_Overworld/011_PField_FieldMoves.rb +++ b/Data/Scripts/013_Overworld/011_PField_FieldMoves.rb @@ -393,7 +393,7 @@ Events.onAction += proc { |_sender,_e| divemap = i; break end end - if PBTerrain.isDeepWater?($MapFactory.getTerrainTag(divemap,$game_player.x,$game_player.y)) + if divemap && PBTerrain.isDeepWater?($MapFactory.getTerrainTag(divemap,$game_player.x,$game_player.y)) pbSurfacing end end diff --git a/Data/Scripts/013_Overworld/014_PField_DependentEvents.rb b/Data/Scripts/013_Overworld/014_PField_DependentEvents.rb index 44ee53b1b..3081ef66c 100644 --- a/Data/Scripts/013_Overworld/014_PField_DependentEvents.rb +++ b/Data/Scripts/013_Overworld/014_PField_DependentEvents.rb @@ -2,7 +2,7 @@ class PokemonTemp attr_writer :dependentEvents def dependentEvents - @dependentEvents=DependentEvents.new if !@dependentEvents + @dependentEvents = DependentEvents.new if !@dependentEvents return @dependentEvents end end @@ -41,7 +41,8 @@ class PokemonGlobalMetadata attr_writer :dependentEvents def dependentEvents - return @dependentEvents || [] + @dependentEvents = [] if !@dependentEvents + return @dependentEvents end end diff --git a/Data/Scripts/015_Items/002_PItem_ItemEffects.rb b/Data/Scripts/015_Items/002_PItem_ItemEffects.rb index b40202189..8ac98f5cb 100644 --- a/Data/Scripts/015_Items/002_PItem_ItemEffects.rb +++ b/Data/Scripts/015_Items/002_PItem_ItemEffects.rb @@ -112,9 +112,9 @@ ItemHandlers::UseInField.add(:MAXREPEL,proc { |item| next pbRepel(item,250) }) -Events.onStepTaken += proc{ - if !PBTerrain.isIce?($game_player.terrain_tag) # Shouldn't count down if on ice - if $PokemonGlobal.repel>0 +Events.onStepTaken += proc { + if $PokemonGlobal.repel>0 + if !PBTerrain.isIce?($game_player.terrain_tag) # Shouldn't count down if on ice $PokemonGlobal.repel -= 1 if $PokemonGlobal.repel<=0 if $PokemonBag.pbHasItem?(:REPEL) || @@ -955,6 +955,7 @@ ItemHandlers::UseOnPokemon.add(:DNASPLICERS,proc { |item,pkmn,scene| end if pkmn.fainted? scene.pbDisplay(_INTL("This can't be used on the fainted Pokémon.")) + next false end # Fusing if pkmn.fused==nil @@ -963,13 +964,17 @@ ItemHandlers::UseOnPokemon.add(:DNASPLICERS,proc { |item,pkmn,scene| poke2 = $Trainer.party[chosen] if pkmn==poke2 scene.pbDisplay(_INTL("It cannot be fused with itself.")) + next false elsif poke2.egg? scene.pbDisplay(_INTL("It cannot be fused with an Egg.")) + next false elsif poke2.fainted? scene.pbDisplay(_INTL("It cannot be fused with that fainted Pokémon.")) + next false elsif !poke2.isSpecies?(:RESHIRAM) && !poke2.isSpecies?(:ZEKROM) scene.pbDisplay(_INTL("It cannot be fused with that Pokémon.")) + next false end newForm = 0 newForm = 1 if poke2.isSpecies?(:RESHIRAM) @@ -997,12 +1002,13 @@ ItemHandlers::UseOnPokemon.add(:DNASPLICERS,proc { |item,pkmn,scene| }) ItemHandlers::UseOnPokemon.add(:NSOLARIZER,proc { |item,pkmn,scene| - if !pkmn.isSpecies?(:NECROZMA) || pkmn.form==0 + if !pkmn.isSpecies?(:NECROZMA) || pkmn.form == 2 scene.pbDisplay(_INTL("It had no effect.")) next false end if pkmn.fainted? scene.pbDisplay(_INTL("This can't be used on the fainted Pokémon.")) + next false end # Fusing if pkmn.fused==nil @@ -1011,12 +1017,16 @@ ItemHandlers::UseOnPokemon.add(:NSOLARIZER,proc { |item,pkmn,scene| poke2 = $Trainer.party[chosen] if pkmn==poke2 scene.pbDisplay(_INTL("It cannot be fused with itself.")) + next false elsif poke2.egg? scene.pbDisplay(_INTL("It cannot be fused with an Egg.")) + next false elsif poke2.fainted? scene.pbDisplay(_INTL("It cannot be fused with that fainted Pokémon.")) + next false elsif !poke2.isSpecies?(:SOLGALEO) scene.pbDisplay(_INTL("It cannot be fused with that Pokémon.")) + next false end pkmn.setForm(1) { pkmn.fused = poke2 @@ -1041,12 +1051,13 @@ ItemHandlers::UseOnPokemon.add(:NSOLARIZER,proc { |item,pkmn,scene| }) ItemHandlers::UseOnPokemon.add(:NLUNARIZER,proc { |item,pkmn,scene| - if !pkmn.isSpecies?(:NECROZMA) || pkmn.form==1 + if !pkmn.isSpecies?(:NECROZMA) || pkmn.form == 1 scene.pbDisplay(_INTL("It had no effect.")) next false end if pkmn.fainted? scene.pbDisplay(_INTL("This can't be used on the fainted Pokémon.")) + next false end # Fusing if pkmn.fused==nil @@ -1055,12 +1066,16 @@ ItemHandlers::UseOnPokemon.add(:NLUNARIZER,proc { |item,pkmn,scene| poke2 = $Trainer.party[chosen] if pkmn==poke2 scene.pbDisplay(_INTL("It cannot be fused with itself.")) + next false elsif poke2.egg? scene.pbDisplay(_INTL("It cannot be fused with an Egg.")) + next false elsif poke2.fainted? scene.pbDisplay(_INTL("It cannot be fused with that fainted Pokémon.")) + next false elsif !poke2.isSpecies?(:LUNALA) scene.pbDisplay(_INTL("It cannot be fused with that Pokémon.")) + next false end pkmn.setForm(2) { pkmn.fused = poke2 diff --git a/Data/Scripts/016_Pokemon/002_Pokemon_Forms.rb b/Data/Scripts/016_Pokemon/002_Pokemon_Forms.rb index ecada1c63..cef9e2f25 100644 --- a/Data/Scripts/016_Pokemon/002_Pokemon_Forms.rb +++ b/Data/Scripts/016_Pokemon/002_Pokemon_Forms.rb @@ -37,15 +37,6 @@ class PokeBattle_Pokemon return pbGetFSpeciesFromForm(@species,formSimple) end - alias __mf_compatibleWithMove? compatibleWithMove? # Deprecated - def compatibleWithMove?(move) - v = MultipleForms.call("getMoveCompatibility",self) - if v!=nil - return v.any? { |j| j==move } - end - return __mf_compatibleWithMove?(move) - end - alias __mf_initialize initialize def initialize(*args) @form = (pbGetSpeciesFromFSpecies(args[0])[1] rescue 0) diff --git a/Data/Scripts/017_UI/009_PScreen_RegionMap.rb b/Data/Scripts/017_UI/009_PScreen_RegionMap.rb index 621947e03..b535c6970 100644 --- a/Data/Scripts/017_UI/009_PScreen_RegionMap.rb +++ b/Data/Scripts/017_UI/009_PScreen_RegionMap.rb @@ -165,9 +165,15 @@ class PokemonRegionMap_Scene def pbSaveMapData File.open("PBS/townmap.txt","wb") { |f| + f.write(0xEF.chr) + f.write(0xBB.chr) + f.write(0xBF.chr) + f.write("\# "+_INTL("See the documentation on the wiki to learn how to edit this file.")) + f.write("\r\n") for i in 0...@mapdata.length map = @mapdata[i] - return if !map + next if !map + f.write("\#-------------------------------\r\n") f.write(sprintf("[%d]\r\n",i)) f.write(sprintf("Name=%s\r\nFilename=%s\r\n",csvQuote(map[0]),csvQuote(map[1]))) for loc in map[2] diff --git a/Data/Scripts/020_System and utilities/004_PSystem_PokemonUtilities.rb b/Data/Scripts/020_System and utilities/004_PSystem_PokemonUtilities.rb index 725f808e0..e6eee895d 100644 --- a/Data/Scripts/020_System and utilities/004_PSystem_PokemonUtilities.rb +++ b/Data/Scripts/020_System and utilities/004_PSystem_PokemonUtilities.rb @@ -77,7 +77,7 @@ def pbAddPokemon(pokemon,level=nil,seeform=true) pokemon = pbNewPkmn(pokemon,level) end speciesname = PBSpecies.getName(pokemon.species) - pbMessage(_INTL("\\me[Pkmn get]{1} obtained {2}!\1",$Trainer.name,speciesname)) + pbMessage(_INTL("{1} obtained {2}!\\me[Pkmn get]\\wtnp[80]\1",$Trainer.name,speciesname)) pbNicknameAndStore(pokemon) pbSeenForm(pokemon) if seeform return true @@ -113,7 +113,7 @@ def pbAddToParty(pokemon,level=nil,seeform=true) pokemon = pbNewPkmn(pokemon,level) end speciesname = PBSpecies.getName(pokemon.species) - pbMessage(_INTL("\\me[Pkmn get]{1} obtained {2}!\1",$Trainer.name,speciesname)) + pbMessage(_INTL("{1} obtained {2}!\\me[Pkmn get]\\wtnp[80]\1",$Trainer.name,speciesname)) pbNicknameAndStore(pokemon) pbSeenForm(pokemon) if seeform return true diff --git a/Data/Scripts/020_System and utilities/005_PSystem_Utilities.rb b/Data/Scripts/020_System and utilities/005_PSystem_Utilities.rb index 73598486b..7e68c1af5 100644 --- a/Data/Scripts/020_System and utilities/005_PSystem_Utilities.rb +++ b/Data/Scripts/020_System and utilities/005_PSystem_Utilities.rb @@ -286,7 +286,7 @@ end #=============================================================================== -# JavaScript-related utilities +# Json-related utilities #=============================================================================== # Returns true if the given string represents a valid object in JavaScript # Object Notation, and false otherwise. @@ -1172,10 +1172,10 @@ def pbLoadRpgxpScene(scene) end Graphics.transition(20) Graphics.freeze - oldscene.createSpritesets + $scene = oldscene + $scene.createSpritesets pbShowObjects(visibleObjects) Graphics.transition(20) - $scene = oldscene end diff --git a/Data/Scripts/021_Debug/001_Debug_Menu.rb b/Data/Scripts/021_Debug/001_Debug_Menu.rb index ba7f3b3a4..0010519cf 100644 --- a/Data/Scripts/021_Debug/001_Debug_Menu.rb +++ b/Data/Scripts/021_Debug/001_Debug_Menu.rb @@ -208,6 +208,8 @@ def pbDebugMenuCommands(showall=true) _INTL("Fully compile all data.")) commands.add("othermenu","debugconsole",_INTL("Debug Console"), _INTL("Open the Debug Console.")) + commands.add("othermenu","invalidtiles",_INTL("Fix Invalid Tiles"), + _INTL("Scans all maps and erases non-existent tiles.")) return commands end @@ -348,7 +350,7 @@ def pbDebugMenuActions(cmd="",sprites=nil,viewport=nil) params.setCancelValue(0) level = pbMessageChooseNumber(_INTL("Set the wild {1}'s level.",PBSpecies.getName(species)),params) if level>0 - pkmn.push(pbNewPkmn(species,level)) + pkmn.push(pbGenerateWildPokemon(species,level)) end end else # Edit a Pokémon @@ -366,7 +368,7 @@ def pbDebugMenuActions(cmd="",sprites=nil,viewport=nil) battle = pbListScreen(_INTL("SINGLE TRAINER"),TrainerBattleLister.new(0,false)) if battle trainerdata = battle[1] - pbTrainerBattle(trainerdata[0],trainerdata[1],"...",false,trainerdata[4],true) + pbTrainerBattle(trainerdata[0],trainerdata[1],nil,false,trainerdata[4],true) end when "testtrainerbattleadvanced" trainers = [] @@ -795,6 +797,8 @@ def pbDebugMenuActions(cmd="",sprites=nil,viewport=nil) pbDisposeMessageWindow(msgwindow) when "debugconsole" Console::setup_console + when "invalidtiles" + pbDebugFixInvalidTiles end return false end diff --git a/Data/Scripts/021_Debug/002_Debug_Actions.rb b/Data/Scripts/021_Debug/002_Debug_Actions.rb index cb7a41659..b0d68fc30 100644 --- a/Data/Scripts/021_Debug/002_Debug_Actions.rb +++ b/Data/Scripts/021_Debug/002_Debug_Actions.rb @@ -82,9 +82,16 @@ class SpriteWindow_DebugVariables < Window_DrawableCommand name = $data_system.switches[index+1] codeswitch = (name[/^s\:/]) val = (codeswitch) ? (eval($~.post_match) rescue nil) : $game_switches[index+1] - if val==nil; status = "[-]"; colors = 0; codeswitch = true - elsif val; status = "[ON]"; colors = 2 - else; status = "[OFF]"; colors = 1 + if val==nil + status = "[-]" + colors = 0 + codeswitch = true + elsif val + status = "[ON]" + colors = 2 + else + status = "[OFF]" + colors = 1 end else name = $data_system.variables[index+1] @@ -791,6 +798,76 @@ def pbImportAllAnimations end end +#=============================================================================== +# Properly erases all non-existent tiles in maps (including event graphics) +#=============================================================================== +def pbDebugFixInvalidTiles + num_errors = 0 + num_error_maps = 0 + @tilesets = pbLoadRxData("Data/Tilesets") + mapData = MapData.new + t = Time.now.to_i + Graphics.update + for id in mapData.mapinfos.keys.sort + if Time.now.to_i - t >= 5 + Graphics.update + t = Time.now.to_i + end + changed = false + map = mapData.getMap(id) + next if !map || !mapData.mapinfos[id] + Win32API.SetWindowText(_INTL("Processing map {1} ({2})", id, mapData.mapinfos[id].name)) + passages = mapData.getTilesetPassages(map, id) + # Check all tiles in map for non-existent tiles + for x in 0...map.data.xsize + for y in 0...map.data.ysize + for i in 0...map.data.zsize + tile_id = map.data[x, y, i] + next if pbCheckTileValidity(tile_id, map, @tilesets, passages) + map.data[x, y, i] = 0 + changed = true + num_errors += 1 + end + end + end + # Check all events in map for page graphics using a non-existent tile + for key in map.events.keys + event = map.events[key] + for page in event.pages + next if page.graphic.tile_id <= 0 + next if pbCheckTileValidity(page.graphic.tile_id, map, @tilesets, passages) + page.graphic.tile_id = 0 + changed = true + num_errors += 1 + end + end + next if !changed + # Map was changed; save it + num_error_maps += 1 + mapData.saveMap(id) + end + if num_error_maps == 0 + pbMessage(_INTL("No invalid tiles were found.")) + else + pbMessage(_INTL("{1} error(s) were found across {2} map(s) and fixed.", num_errors, num_error_maps)) + pbMessage(_INTL("Close RPG Maker XP to ensure the changes are applied properly.")) + end +end + +def pbCheckTileValidity(tile_id, map, tilesets, passages) + return false if !tile_id + if tile_id > 0 && tile_id < 384 + # Check for defined autotile + autotile_id = tile_id / 48 - 1 + autotile_name = tilesets[map.tileset_id].autotile_names[autotile_id] + return true if autotile_name && autotile_name != "" + else + # Check for tileset data + return true if passages[tile_id] + end + return false +end + #=============================================================================== diff --git a/Data/Scripts/021_Debug/004_Editor_Screens.rb b/Data/Scripts/021_Debug/004_Editor_Screens.rb index 5568fdf27..8f0410600 100644 --- a/Data/Scripts/021_Debug/004_Editor_Screens.rb +++ b/Data/Scripts/021_Debug/004_Editor_Screens.rb @@ -669,13 +669,6 @@ def pbItemEditorNew(defaultname) itemdata = pbLoadItemsData # Get the first blank ID for the new item to use. maxid = PBItems.maxValue+1 - for i in 1..PBItems.maxValue - name = itemdata[i][1] - if !name || name=="" || itemdata[i][ITEM_POCKET]==0 - maxid = i - break - end - end index = maxid itemname = pbMessageFreeText(_INTL("Please enter the item's name."), (defaultname) ? defaultname.gsub(/_+/," ") : "",false,30) diff --git a/Data/Scripts/021_Debug/005_Editor_SaveData.rb b/Data/Scripts/021_Debug/005_Editor_SaveData.rb index 65a882a56..d162b4944 100644 --- a/Data/Scripts/021_Debug/005_Editor_SaveData.rb +++ b/Data/Scripts/021_Debug/005_Editor_SaveData.rb @@ -550,7 +550,7 @@ def pbSaveTownMap f.write("\r\n") for i in 0...mapdata.length map = mapdata[i] - return if !map + next if !map f.write("\#-------------------------------\r\n") f.write(sprintf("[%d]\r\n",i)) rname = pbGetMessage(MessageTypes::RegionNames,i) @@ -839,11 +839,14 @@ def pbSavePokemonData pokedata.write(",") if count>0 pokedata.write(sprintf("%s,%s,",cnew_species,evoname)) param_type = PBEvolution.getFunction(method, "parameterType") - if param_type - cparameter = getConstantName(param_type,parameter) rescue "" - pokedata.write("#{cparameter}") - else - pokedata.write("#{parameter}") + has_param = !PBEvolution.hasFunction?(method, "parameterType") || param_type != nil + if has_param + if param_type + cparameter = (getConstantName(param_type, parameter) rescue parameter) + pokedata.write("#{cparameter}") + else + pokedata.write("#{parameter}") + end end count += 1 end @@ -1299,11 +1302,14 @@ def pbSavePokemonFormsData next if !cnew_species || cnew_species=="" pokedata.write(sprintf("%s,%s,",cnew_species,evoname)) param_type = PBEvolution.getFunction(method, "parameterType") - if param_type - cparameter = getConstantName(param_type,parameter) rescue "" - pokedata.write("#{cparameter}") - else - pokedata.write("#{parameter}") + has_param = !PBEvolution.hasFunction?(method, "parameterType") || param_type != nil + if has_param + if param_type + cparameter = (getConstantName(param_type, parameter) rescue parameter) + pokedata.write("#{cparameter}") + else + pokedata.write("#{parameter}") + end end pokedata.write(",") if k=0 for reqtype in requiredtypes.keys if !foundtypes.include?(reqtype) - raise _INTL("Required value '{1}' not given in section '{2}'\r\n{3}",reqtype,currentmap,FileLineData.linereport) + raise _INTL("Required value '{1}' not given in section [{2}].\r\n{3}",reqtype,currentmap,FileLineData.linereport) end end foundtypes.clear @@ -363,10 +365,10 @@ def pbCompileTypes types[currentmap] = [currentmap,nil,nil,false,false,[],[],[]] else if currentmap<0 - raise _INTL("Expected a section at the beginning of the file\r\n{1}",FileLineData.linereport) + raise _INTL("Expected a section at the beginning of the file.\r\n{1}",FileLineData.linereport) end if !line[/^\s*(\w+)\s*=\s*(.*)$/] - raise _INTL("Bad line syntax (expected syntax like XXX=YYY)\r\n{1}",FileLineData.linereport) + raise _INTL("Bad line syntax (expected syntax like XXX=YYY).\r\n{1}",FileLineData.linereport) end matchData = $~ schema = nil @@ -401,17 +403,17 @@ def pbCompileTypes n = type[1] for w in type[5] if !typeinames.include?(w) - raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Weaknesses)",w,n) + raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Weaknesses).",w,n) end end for w in type[6] if !typeinames.include?(w) - raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Resistances)",w,n) + raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Resistances).",w,n) end end for w in type[7] if !typeinames.include?(w) - raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Immunities)",w,n) + raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Immunities).",w,n) end end end @@ -463,6 +465,9 @@ def pbCompileAbilities maxValue = 0 pbCompilerEachPreppedLine("PBS/abilities.txt") { |line,lineno| record = pbGetCsvRecord(line,lineno,[0,"vnss"]) + if movenames[record[0]] + raise _INTL("Ability ID number '{1}' is used twice.\r\n{2}",record[0],FileLineData.linereport) + end movenames[record[0]] = record[2] movedescs[record[0]] = record[3] maxValue = [maxValue,record[0]].max @@ -545,6 +550,9 @@ def pbCompileItems pbCompilerEachCommentedLine("PBS/items.txt") { |line,lineno| linerecord = pbGetCsvRecord(line,lineno,[0,"vnssuusuuUN"]) id = linerecord[0] + if records[id] + raise _INTL("Item ID number '{1}' is used twice.\r\n{2}",id,FileLineData.linereport) + end record = [] record[ITEM_ID] = id constant = linerecord[1] @@ -603,11 +611,14 @@ def pbCompileMoves nil,nil,nil,nil,nil,PBTypes,["Physical","Special","Status"], nil,nil,nil,PBTargets,nil,nil,nil ]) + if records[lineRecord[0]] + raise _INTL("Move ID number '{1}' is used twice.\r\n{2}",lineRecord[0],FileLineData.linereport) + end if lineRecord[6]==2 && lineRecord[4]!=0 - raise _INTL("Status moves must have a base damage of 0, use either Physical or Special\r\n{1}",FileLineData.linereport) + raise _INTL("Status moves must have a base damage of 0, use either Physical or Special.\r\n{1}",FileLineData.linereport) end if lineRecord[6]!=2 && lineRecord[4]==0 - print _INTL("Warning: Physical and special moves can't have a base damage of 0, changing to a Status move\r\n{1}",FileLineData.linereport) + print _INTL("Warning: Physical and special moves can't have a base damage of 0, changing to a Status move.\r\n{1}",FileLineData.linereport) lineRecord[6] = 2 end record[MOVE_ID] = lineRecord[0] @@ -717,6 +728,14 @@ def pbCompilePokemonData # contents is a hash containing all the XXX=YYY lines in that section, where # the keys are the XXX and the values are the YYY (as unprocessed strings). pbEachFileSection(f) { |contents,speciesID| + # Raise an error if the species ID is 0. + if speciesID==0 + raise _INTL("A Pokémon species can't be numbered 0 (PBS/pokemon.txt)") + end + # Raise an error if the species ID has already been defined. + if speciesData[speciesID] + raise _INTL("Species ID number '{1}' is used twice.\r\n{2}",speciesID,FileLineData.linereport) + end # Create array to store compiled data in. speciesData[speciesID] = [] # Copy Type1 into Type2 if Type2 is undefined. (All species must have two @@ -733,10 +752,6 @@ def pbCompilePokemonData FileLineData.setSection(speciesID,key,contents[key]) # For error reporting maxValue = [maxValue,speciesID].max # Set highest species ID next if hash[key][0]<0 # Property is not to be compiled; skip it - # Raise an error if the species ID is 0. - if speciesID==0 - raise _INTL("A Pokémon species can't be numbered 0 (PBS/pokemon.txt)") - end # Skip empty optional properties, or raise an error if a required # property is empty. if !contents[key] || contents[key]=="" @@ -854,7 +869,6 @@ def pbCompilePokemonData end # Add prevolution data to all species as the first "evolution method". for sp in 1..maxValue - next if !evolutions[sp] preSpecies = -1 evoData = nil # Check for another species that evolves into sp. @@ -870,6 +884,7 @@ def pbCompilePokemonData end next if !evoData # evoData[1]=method, evoData[2]=level - both are unused # Found a species that evolves into e, record it as a prevolution. + evolutions[sp] = [] if !evolutions[sp] evolutions[sp] = [[preSpecies,evoData[1],evoData[2],true]].concat(evolutions[sp]) end # Save evolutions data. @@ -1162,6 +1177,9 @@ def pbCompileMachines if !line[/^\#/] && !line[/^\s*$/] if line[/^\s*\[\s*(.*)\s*\]\s*$/] sectionname = parseMove($~[1]) + if sections[sectionname] + raise _INTL("TM section [{1}] is defined twice.\r\n{2}",sectionname,FileLineData.linereport) + end sections[sectionname] = WordArray.new havesection = true else @@ -1261,13 +1279,16 @@ def pbCompileEncounters mapid = line[/^\d+$/] if mapid lastmapid = mapid + if encounters[mapid.to_i] + raise _INTL("Encounters for map ID '{1}' are defined twice.\r\n{2}",mapid,FileLineData.linereport) + end if thisenc && (thisenc[1][EncounterTypes::Land] || thisenc[1][EncounterTypes::LandMorning] || thisenc[1][EncounterTypes::LandDay] || thisenc[1][EncounterTypes::LandNight] || thisenc[1][EncounterTypes::BugContest]) && thisenc[1][EncounterTypes::Cave] - raise _INTL("Can't define both Land and Cave encounters in the same area (map ID {1})",mapid) + raise _INTL("Can't define both Land and Cave encounters in the same area (map ID '{1}')",mapid) end thisenc = [EncounterTypes::EnctypeDensities.clone,[]] encounters[mapid.to_i] = thisenc @@ -1393,10 +1414,10 @@ def pbCompileTrainers if line[/^\s*\[\s*(.+)\s*\]\s*$/] # Section [trainertype,trainername] or [trainertype,trainername,partyid] if oldcompilerline>0 - raise _INTL("Previous trainer not defined with as many Pokémon as expected\r\n{1}",FileLineData.linereport) + raise _INTL("Previous trainer not defined with as many Pokémon as expected.\r\n{1}",FileLineData.linereport) end if pokemonindex==-1 - raise _INTL("Started new trainer while previous trainer has no Pokémon\r\n{1}",FileLineData.linereport) + raise _INTL("Started new trainer while previous trainer has no Pokémon.\r\n{1}",FileLineData.linereport) end section = pbGetCsvRecord($~[1],lineno,[0,"esU",PBTrainers]) trainerindex += 1 @@ -1409,10 +1430,10 @@ def pbCompileTrainers elsif line[/^\s*(\w+)\s*=\s*(.*)$/] # XXX=YYY lines if trainerindex<0 - raise _INTL("Expected a section at the beginning of the file\r\n{1}",FileLineData.linereport) + raise _INTL("Expected a section at the beginning of the file.\r\n{1}",FileLineData.linereport) end if oldcompilerline>0 - raise _INTL("Previous trainer not defined with as many Pokémon as expected\r\n{1}",FileLineData.linereport) + raise _INTL("Previous trainer not defined with as many Pokémon as expected.\r\n{1}",FileLineData.linereport) end settingname = $~[1] schema = trainer_info_types[settingname] @@ -1429,7 +1450,7 @@ def pbCompileTrainers record.compact! when "Ability" if record>5 - raise _INTL("Bad ability flag: {1} (must be 0 or 1 or 2-5)\r\n{2}",record,FileLineData.linereport) + raise _INTL("Bad ability flag: {1} (must be 0 or 1 or 2-5).\r\n{2}",record,FileLineData.linereport) end when "IV" record = [record] if record.is_a?(Integer) diff --git a/Data/Scripts/022_Compiler/003_Compiler_MapsAndEvents.rb b/Data/Scripts/022_Compiler/003_Compiler_MapsAndEvents.rb index 4d027bcf4..29831d4cd 100644 --- a/Data/Scripts/022_Compiler/003_Compiler_MapsAndEvents.rb +++ b/Data/Scripts/022_Compiler/003_Compiler_MapsAndEvents.rb @@ -565,7 +565,7 @@ def pbConvertToTrainerEvent(event,trainerChecker) end pbPushScript(firstpage.list,"setBattleRule(\"double\")") if doublebattle pbPushScript(firstpage.list,sprintf("setBattleRule(\"backdrop\",\"%s\")",safequote(backdrop))) if backdrop - pbPushScript(firstpage.list,sprintf("setBattleRule(\"outcomeVar\",%d)",outcomeVar)) if outcome>1 + pbPushScript(firstpage.list,sprintf("setBattleRule(\"outcomeVar\",%d)",outcome)) if outcome>1 pbPushScript(firstpage.list,"setBattleRule(\"canLose\")") if continue espeech = (endspeeches[0]) ? sprintf("_I(\"%s\")",safequote2(endspeeches[0])) : "nil" if battleid>0 @@ -614,7 +614,7 @@ def pbConvertToTrainerEvent(event,trainerChecker) pbPushText(rematchpage.list,battles[i],1) pbPushScript(rematchpage.list,"setBattleRule(\"double\")",1) if doublebattle pbPushScript(rematchpage.list,sprintf("setBattleRule(\"backdrop\",%s)",safequote(backdrop)),1) if backdrop - pbPushScript(rematchpage.list,sprintf("setBattleRule(\"outcomeVar\",%d)",outcomeVar),1) if outcome>1 + pbPushScript(rematchpage.list,sprintf("setBattleRule(\"outcomeVar\",%d)",outcome),1) if outcome>1 pbPushScript(rematchpage.list,"setBattleRule(\"canLose\")",1) if continue espeech = nil if endspeeches.length>0 diff --git a/Data/Scripts/999_Main/999_Main.rb b/Data/Scripts/999_Main/999_Main.rb index 34c5d0b9a..f3ed485d1 100644 --- a/Data/Scripts/999_Main/999_Main.rb +++ b/Data/Scripts/999_Main/999_Main.rb @@ -1,7 +1,5 @@ pbCompiler - - class Scene_DebugIntro def main Graphics.transition(0) @@ -12,8 +10,6 @@ class Scene_DebugIntro end end - - def pbCallTitle return Scene_DebugIntro.new if $DEBUG # First parameter is an array of images in the Titles @@ -34,9 +30,9 @@ end def mainFunctionDebug begin - getCurrentProcess = Win32API.new("kernel32.dll","GetCurrentProcess","","l") - setPriorityClass = Win32API.new("kernel32.dll","SetPriorityClass",%w(l i),"") - setPriorityClass.call(getCurrentProcess.call(),32768) # "Above normal" priority class + getCurrentProcess = Win32API.new("kernel32.dll", "GetCurrentProcess", "", "l") + setPriorityClass = Win32API.new("kernel32.dll", "SetPriorityClass", %w(l i), "") + setPriorityClass.call(getCurrentProcess.call(), 32768) # "Above normal" priority class $data_animations = pbLoadRxData("Data/Animations") $data_tilesets = pbLoadRxData("Data/Tilesets") $data_common_events = pbLoadRxData("Data/CommonEvents") @@ -46,9 +42,7 @@ def mainFunctionDebug Graphics.update Graphics.freeze $scene = pbCallTitle - while $scene!=nil - $scene.main - end + $scene.main until $scene.nil? Graphics.transition(20) rescue Hangup pbPrintException($!) if !$DEBUG @@ -59,11 +53,11 @@ end loop do retval = mainFunction - if retval==0 # failed + if retval == 0 # failed loop do Graphics.update end - elsif retval==1 # ended successfully + elsif retval == 1 # ended successfully break end end diff --git a/PBS/Gen 5/pokemon.txt b/PBS/Gen 5/pokemon.txt index b4bf6a0f6..92179d286 100644 --- a/PBS/Gen 5/pokemon.txt +++ b/PBS/Gen 5/pokemon.txt @@ -815,7 +815,7 @@ Habitat = Forest RegionalNumbers = 25,22 Kind = Mouse Pokedex = It stores electricity in the electric sacs on its cheeks. When it releases pent-up energy in a burst, the electric power is equal to a lightning bolt. -WildItemuNCOMMON = LIGHTBALL +WildItemUncommon = LIGHTBALL BattlerPlayerX = -5 BattlerPlayerY = 0 BattlerEnemyX = 4 @@ -9618,7 +9618,7 @@ BattlerEnemyX = -1 BattlerEnemyY = 29 BattlerShadowX = 0 BattlerShadowSize = 2 -Evolutions = NINJASK,Ninjask,20,SHEDINJA,Shedinja,20 +Evolutions = NINJASK,Ninjask,20,SHEDINJA,Shedinja, #------------------------------- [291] Name = Ninjask diff --git a/PBS/Gen 7/moves.txt b/PBS/Gen 7/moves.txt index 65e379cae..0108b952f 100644 --- a/PBS/Gen 7/moves.txt +++ b/PBS/Gen 7/moves.txt @@ -122,16 +122,16 @@ 116,DISARMINGVOICE,Disarming Voice,0A5,40,FAIRY,Special,0,15,0,AllNearFoes,0,befk,"Letting out a charming cry, the user does emotional damage to foes. This attack never misses." 117,FAIRYWIND,Fairy Wind,000,40,FAIRY,Special,100,30,0,NearOther,0,bef,"The user stirs up a fairy wind and strikes the target with it." 118,AROMATICMIST,Aromatic Mist,138,0,FAIRY,Status,0,20,0,NearAlly,0,,"The user raises the Sp. Def stat of an ally Pokémon by using a mysterious aroma." -119,BABYDOLLEYES,Baby-Doll Eyes,042,0,FAIRY,Status,100,30,0,NearOther,1,bce,"The user stares with its baby-doll eyes, which lowers the target's Attack stat. Always goes first." -120,CHARM,Charm,04B,0,FAIRY,Status,100,20,0,NearOther,0,bce,"The user charmingly gazes at the foe, making it less wary. The target's Attack is harshly lowered." -121,CRAFTYSHIELD,Crafty Shield,14A,0,FAIRY,Status,0,10,0,UserSide,3,,"The user protects itself and its allies from status moves with a mysterious power." -122,FAIRYLOCK,Fairy Lock,152,0,FAIRY,Status,0,10,0,BothSides,0,e,"By locking down the battlefield, the user keeps all Pokémon from fleeing during the next turn." -123,FLORALHEALING,Floral Healing,16E,0,FAIRY,Status,0,10,0,NearOther,0,bc,"The user restores the target's HP by up to half of its max HP. It restores more HP when the terrain is grass." -124,FLOWERSHIELD,Flower Shield,13F,0,FAIRY,Status,0,10,0,AllBattlers,0,,"The user raises the Defense stats of all Grass-type Pokémon in battle with a mysterious power." -125,GEOMANCY,Geomancy,14E,0,FAIRY,Status,0,10,0,User,0,,"The user absorbs energy and sharply raises its Sp. Atk, Sp. Def, and Speed stats on the next turn." -126,MISTYTERRAIN,Misty Terrain,156,0,FAIRY,Status,0,10,0,BothSides,0,,"The user covers the ground with mist for five turns. Grounded Pokémon can't gain status conditions." -127,MOONLIGHT,Moonlight,0D8,0,FAIRY,Status,0,5,0,User,0,d,"The user restores its own HP. The amount of HP regained varies with the weather." -128,NATURESMADNESS,Nature's Madness,06C,0,FAIRY,Status,90,10,0,NearOther,0,bef,"The user hits the target with the force of nature. It halves the target's HP." +119,NATURESMADNESS,Nature's Madness,06C,1,FAIRY,Special,90,10,0,NearOther,0,bef,"The user hits the target with the force of nature. It halves the target's HP." +120,BABYDOLLEYES,Baby-Doll Eyes,042,0,FAIRY,Status,100,30,0,NearOther,1,bce,"The user stares with its baby-doll eyes, which lowers the target's Attack stat. Always goes first." +121,CHARM,Charm,04B,0,FAIRY,Status,100,20,0,NearOther,0,bce,"The user charmingly gazes at the foe, making it less wary. The target's Attack is harshly lowered." +122,CRAFTYSHIELD,Crafty Shield,14A,0,FAIRY,Status,0,10,0,UserSide,3,,"The user protects itself and its allies from status moves with a mysterious power." +123,FAIRYLOCK,Fairy Lock,152,0,FAIRY,Status,0,10,0,BothSides,0,e,"By locking down the battlefield, the user keeps all Pokémon from fleeing during the next turn." +124,FLORALHEALING,Floral Healing,16E,0,FAIRY,Status,0,10,0,NearOther,0,bc,"The user restores the target's HP by up to half of its max HP. It restores more HP when the terrain is grass." +125,FLOWERSHIELD,Flower Shield,13F,0,FAIRY,Status,0,10,0,AllBattlers,0,,"The user raises the Defense stats of all Grass-type Pokémon in battle with a mysterious power." +126,GEOMANCY,Geomancy,14E,0,FAIRY,Status,0,10,0,User,0,,"The user absorbs energy and sharply raises its Sp. Atk, Sp. Def, and Speed stats on the next turn." +127,MISTYTERRAIN,Misty Terrain,156,0,FAIRY,Status,0,10,0,BothSides,0,,"The user covers the ground with mist for five turns. Grounded Pokémon can't gain status conditions." +128,MOONLIGHT,Moonlight,0D8,0,FAIRY,Status,0,5,0,User,0,d,"The user restores its own HP. The amount of HP regained varies with the weather." 129,SWEETKISS,Sweet Kiss,013,0,FAIRY,Status,75,10,0,NearOther,0,bce,"The user kisses the target with a sweet, angelic cuteness that causes confusion." #------------------------------- 130,FOCUSPUNCH,Focus Punch,115,150,FIGHTING,Physical,100,20,0,NearOther,-3,abfj,"The user focuses its mind before launching a punch. It will fail if the user is hit before it is used." @@ -161,7 +161,7 @@ 154,STORMTHROW,Storm Throw,0A0,60,FIGHTING,Physical,100,10,0,NearOther,0,abef,"The user strikes the target with a fierce blow. This attack always results in a critical hit." 155,KARATECHOP,Karate Chop,000,50,FIGHTING,Physical,100,25,0,NearOther,0,abefh,"The target is attacked with a sharp chop. Critical hits land more easily." 156,MACHPUNCH,Mach Punch,000,40,FIGHTING,Physical,100,30,0,NearOther,1,abefj,"The user throws a punch at blinding speed. It is certain to strike first." -157,POWERUPPUNCH,Power-Up Punch,01C,40,FIGHTING,Physical,100,20,0,NearOther,0,abefj,"Striking opponents repeatedly makes the user's fists harder, raising the user's Attack stat." +157,POWERUPPUNCH,Power-Up Punch,01C,40,FIGHTING,Physical,100,20,100,NearOther,0,abefj,"Striking opponents repeatedly makes the user's fists harder, raising the user's Attack stat." 158,ROCKSMASH,Rock Smash,043,40,FIGHTING,Physical,100,15,50,NearOther,0,abef,"The user attacks with a punch that can shatter a rock. It may also lower the foe's Defense stat." 159,VACUUMWAVE,Vacuum Wave,000,40,FIGHTING,Special,100,30,0,NearOther,1,bef,"The user whirls its fists to send a wave of pure vacuum at the target. This move always goes first." 160,DOUBLEKICK,Double Kick,0BD,30,FIGHTING,Physical,100,30,0,NearOther,0,abef,"The target is quickly kicked twice in succession using both feet." diff --git a/PBS/Gen 7/pokemon.txt b/PBS/Gen 7/pokemon.txt index 3c94d507a..c600d0905 100644 --- a/PBS/Gen 7/pokemon.txt +++ b/PBS/Gen 7/pokemon.txt @@ -816,6 +816,7 @@ Habitat = Forest RegionalNumbers = 25,22 Kind = Mouse Pokedex = It stores electricity in the electric sacs on its cheeks. When it releases pent-up energy in a burst, the electric power is equal to a lightning bolt. +WildItemUncommon = LIGHTBALL BattlerPlayerX = -5 BattlerPlayerY = 0 BattlerEnemyX = 4 @@ -9617,7 +9618,7 @@ BattlerEnemyX = -1 BattlerEnemyY = 29 BattlerShadowX = 0 BattlerShadowSize = 2 -Evolutions = NINJASK,Ninjask,20,SHEDINJA,Shedinja,20 +Evolutions = NINJASK,Ninjask,20,SHEDINJA,Shedinja, #------------------------------- [291] Name = Ninjask diff --git a/PBS/Gen 7/pokemonforms.txt b/PBS/Gen 7/pokemonforms.txt index c2a447c58..730a072e4 100644 --- a/PBS/Gen 7/pokemonforms.txt +++ b/PBS/Gen 7/pokemonforms.txt @@ -150,7 +150,6 @@ Moves = 0,DAZZLINGGLEAM,1,DAZZLINGGLEAM,1,IMPRISON,1,NASTYPLOT,1,ICEBEAM,1,ICESH Color = Blue Pokedex = It lives on mountains perpetually covered in snow and is revered as a deity incarnate. It appears draped in a blizzard. WildItemUncommon = SNOWBALL -Evolutions = NINETALES,Item,ICESTONE #------------------------------- [DIGLETT,1] FormName = Alolan diff --git a/PBS/moves.txt b/PBS/moves.txt index 65e379cae..2ee7c9697 100644 --- a/PBS/moves.txt +++ b/PBS/moves.txt @@ -121,17 +121,17 @@ 115,DRAININGKISS,Draining Kiss,14F,50,FAIRY,Special,100,10,0,NearOther,0,abef,"The user steals the target's HP with a kiss. The user's HP is restored by over half of the damage dealt." 116,DISARMINGVOICE,Disarming Voice,0A5,40,FAIRY,Special,0,15,0,AllNearFoes,0,befk,"Letting out a charming cry, the user does emotional damage to foes. This attack never misses." 117,FAIRYWIND,Fairy Wind,000,40,FAIRY,Special,100,30,0,NearOther,0,bef,"The user stirs up a fairy wind and strikes the target with it." -118,AROMATICMIST,Aromatic Mist,138,0,FAIRY,Status,0,20,0,NearAlly,0,,"The user raises the Sp. Def stat of an ally Pokémon by using a mysterious aroma." -119,BABYDOLLEYES,Baby-Doll Eyes,042,0,FAIRY,Status,100,30,0,NearOther,1,bce,"The user stares with its baby-doll eyes, which lowers the target's Attack stat. Always goes first." -120,CHARM,Charm,04B,0,FAIRY,Status,100,20,0,NearOther,0,bce,"The user charmingly gazes at the foe, making it less wary. The target's Attack is harshly lowered." -121,CRAFTYSHIELD,Crafty Shield,14A,0,FAIRY,Status,0,10,0,UserSide,3,,"The user protects itself and its allies from status moves with a mysterious power." -122,FAIRYLOCK,Fairy Lock,152,0,FAIRY,Status,0,10,0,BothSides,0,e,"By locking down the battlefield, the user keeps all Pokémon from fleeing during the next turn." -123,FLORALHEALING,Floral Healing,16E,0,FAIRY,Status,0,10,0,NearOther,0,bc,"The user restores the target's HP by up to half of its max HP. It restores more HP when the terrain is grass." -124,FLOWERSHIELD,Flower Shield,13F,0,FAIRY,Status,0,10,0,AllBattlers,0,,"The user raises the Defense stats of all Grass-type Pokémon in battle with a mysterious power." -125,GEOMANCY,Geomancy,14E,0,FAIRY,Status,0,10,0,User,0,,"The user absorbs energy and sharply raises its Sp. Atk, Sp. Def, and Speed stats on the next turn." -126,MISTYTERRAIN,Misty Terrain,156,0,FAIRY,Status,0,10,0,BothSides,0,,"The user covers the ground with mist for five turns. Grounded Pokémon can't gain status conditions." -127,MOONLIGHT,Moonlight,0D8,0,FAIRY,Status,0,5,0,User,0,d,"The user restores its own HP. The amount of HP regained varies with the weather." -128,NATURESMADNESS,Nature's Madness,06C,0,FAIRY,Status,90,10,0,NearOther,0,bef,"The user hits the target with the force of nature. It halves the target's HP." +118,NATURESMADNESS,Nature's Madness,06C,1,FAIRY,Special,90,10,0,NearOther,0,bef,"The user hits the target with the force of nature. It halves the target's HP." +119,AROMATICMIST,Aromatic Mist,138,0,FAIRY,Status,0,20,0,NearAlly,0,,"The user raises the Sp. Def stat of an ally Pokémon by using a mysterious aroma." +120,BABYDOLLEYES,Baby-Doll Eyes,042,0,FAIRY,Status,100,30,0,NearOther,1,bce,"The user stares with its baby-doll eyes, which lowers the target's Attack stat. Always goes first." +121,CHARM,Charm,04B,0,FAIRY,Status,100,20,0,NearOther,0,bce,"The user charmingly gazes at the foe, making it less wary. The target's Attack is harshly lowered." +122,CRAFTYSHIELD,Crafty Shield,14A,0,FAIRY,Status,0,10,0,UserSide,3,,"The user protects itself and its allies from status moves with a mysterious power." +123,FAIRYLOCK,Fairy Lock,152,0,FAIRY,Status,0,10,0,BothSides,0,e,"By locking down the battlefield, the user keeps all Pokémon from fleeing during the next turn." +124,FLORALHEALING,Floral Healing,16E,0,FAIRY,Status,0,10,0,NearOther,0,bc,"The user restores the target's HP by up to half of its max HP. It restores more HP when the terrain is grass." +125,FLOWERSHIELD,Flower Shield,13F,0,FAIRY,Status,0,10,0,AllBattlers,0,,"The user raises the Defense stats of all Grass-type Pokémon in battle with a mysterious power." +126,GEOMANCY,Geomancy,14E,0,FAIRY,Status,0,10,0,User,0,,"The user absorbs energy and sharply raises its Sp. Atk, Sp. Def, and Speed stats on the next turn." +127,MISTYTERRAIN,Misty Terrain,156,0,FAIRY,Status,0,10,0,BothSides,0,,"The user covers the ground with mist for five turns. Grounded Pokémon can't gain status conditions." +128,MOONLIGHT,Moonlight,0D8,0,FAIRY,Status,0,5,0,User,0,d,"The user restores its own HP. The amount of HP regained varies with the weather." 129,SWEETKISS,Sweet Kiss,013,0,FAIRY,Status,75,10,0,NearOther,0,bce,"The user kisses the target with a sweet, angelic cuteness that causes confusion." #------------------------------- 130,FOCUSPUNCH,Focus Punch,115,150,FIGHTING,Physical,100,20,0,NearOther,-3,abfj,"The user focuses its mind before launching a punch. It will fail if the user is hit before it is used." @@ -161,7 +161,7 @@ 154,STORMTHROW,Storm Throw,0A0,60,FIGHTING,Physical,100,10,0,NearOther,0,abef,"The user strikes the target with a fierce blow. This attack always results in a critical hit." 155,KARATECHOP,Karate Chop,000,50,FIGHTING,Physical,100,25,0,NearOther,0,abefh,"The target is attacked with a sharp chop. Critical hits land more easily." 156,MACHPUNCH,Mach Punch,000,40,FIGHTING,Physical,100,30,0,NearOther,1,abefj,"The user throws a punch at blinding speed. It is certain to strike first." -157,POWERUPPUNCH,Power-Up Punch,01C,40,FIGHTING,Physical,100,20,0,NearOther,0,abefj,"Striking opponents repeatedly makes the user's fists harder, raising the user's Attack stat." +157,POWERUPPUNCH,Power-Up Punch,01C,40,FIGHTING,Physical,100,20,100,NearOther,0,abefj,"Striking opponents repeatedly makes the user's fists harder, raising the user's Attack stat." 158,ROCKSMASH,Rock Smash,043,40,FIGHTING,Physical,100,15,50,NearOther,0,abef,"The user attacks with a punch that can shatter a rock. It may also lower the foe's Defense stat." 159,VACUUMWAVE,Vacuum Wave,000,40,FIGHTING,Special,100,30,0,NearOther,1,bef,"The user whirls its fists to send a wave of pure vacuum at the target. This move always goes first." 160,DOUBLEKICK,Double Kick,0BD,30,FIGHTING,Physical,100,30,0,NearOther,0,abef,"The target is quickly kicked twice in succession using both feet." diff --git a/PBS/pokemon.txt b/PBS/pokemon.txt index 3c94d507a..c600d0905 100644 --- a/PBS/pokemon.txt +++ b/PBS/pokemon.txt @@ -816,6 +816,7 @@ Habitat = Forest RegionalNumbers = 25,22 Kind = Mouse Pokedex = It stores electricity in the electric sacs on its cheeks. When it releases pent-up energy in a burst, the electric power is equal to a lightning bolt. +WildItemUncommon = LIGHTBALL BattlerPlayerX = -5 BattlerPlayerY = 0 BattlerEnemyX = 4 @@ -9617,7 +9618,7 @@ BattlerEnemyX = -1 BattlerEnemyY = 29 BattlerShadowX = 0 BattlerShadowSize = 2 -Evolutions = NINJASK,Ninjask,20,SHEDINJA,Shedinja,20 +Evolutions = NINJASK,Ninjask,20,SHEDINJA,Shedinja, #------------------------------- [291] Name = Ninjask diff --git a/PBS/pokemonforms.txt b/PBS/pokemonforms.txt index c2a447c58..730a072e4 100644 --- a/PBS/pokemonforms.txt +++ b/PBS/pokemonforms.txt @@ -150,7 +150,6 @@ Moves = 0,DAZZLINGGLEAM,1,DAZZLINGGLEAM,1,IMPRISON,1,NASTYPLOT,1,ICEBEAM,1,ICESH Color = Blue Pokedex = It lives on mountains perpetually covered in snow and is revered as a deity incarnate. It appears draped in a blizzard. WildItemUncommon = SNOWBALL -Evolutions = NINETALES,Item,ICESTONE #------------------------------- [DIGLETT,1] FormName = Alolan