diff --git a/Data/Scripts/001_Settings.rb b/Data/Scripts/001_Settings.rb index ba92a3b35..e29cd8d3d 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/004_Win32API.rb b/Data/Scripts/001_Technical/004_Win32API.rb index 821ed8dba..21fc9318f 100644 --- a/Data/Scripts/001_Technical/004_Win32API.rb +++ b/Data/Scripts/001_Technical/004_Win32API.rb @@ -100,5 +100,5 @@ end # Well done for finding this place. # DO NOT EDIT THESE -ESSENTIALS_VERSION = "18.dev" +ESSENTIALS_VERSION = "18.1.dev" ERROR_TEXT = "" diff --git a/Data/Scripts/003_Game classes/005_Game_Character.rb b/Data/Scripts/003_Game classes/005_Game_Character.rb index 8b895a858..029d260ee 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 @@ -648,12 +658,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 @@ -764,10 +780,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 +814,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 +833,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 +853,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 +861,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 +869,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 6b533ec47..ab48b7a64 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 @@ -128,6 +128,14 @@ class Game_Player < Game_Character end end + def turnGeneric(dir) + old_direction = @direction + super + if @direction != old_direction && !@move_route_forcing && !pbMapInterpreterRunning? + Events.onChangeDirection.trigger(self, self) + end + end + def pbTriggeredTrainerEvents(triggers,checkIfRunning=true) result = [] # If event is running @@ -380,7 +388,7 @@ class Game_Player < Game_Character unless pbMapInterpreterRunning? or $game_temp.message_window_showing or $PokemonTemp.miniupdate or $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==@lastdir && Graphics.frame_count-@lastdirframe>Graphics.frame_rate/20) case dir when 2; move_down when 4; move_left 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 ee7dae54b..79332ed2e 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 + self.move_speed = 5 # Cycling elsif pbCanRun? || $PokemonGlobal.surfing - self.move_speed = 5 # Running, surfing + self.move_speed = 4 # Running, surfing else - self.move_speed = 4 # Walking, diving + 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 acf9b2fa6..201dd9ebf 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 dbffba4cd..000000000 --- a/Data/Scripts/009_Objects and windows/005_SpriteWindow_sprites.rb +++ /dev/null @@ -1,1084 +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 - 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 - - - -#=============================================================================== -# 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 y0 && x+minTextSize.width>width x=0 -# y+=32 # (textheight==0) ? bitmap.text_size("X").height : textheight - y+=(textheight==0) ? bitmap.text_size("X").height+1 : textheight + y+=32 # (textheight==0) ? bitmap.text_size("X").height : textheight +# y+=(textheight==0) ? bitmap.text_size("X").height+1 : textheight textheight=0 end end -# textheight=32 # [textheight,textSize.height].max - textheight=[textheight,textSize.height+1].max + textheight=32 # [textheight,textSize.height].max +# textheight=[textheight,textSize.height+1].max ret.push([word,x,y,textwidth,textheight,color]) x+=textwidth dims[0]=x if dims && dims[0]") 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 @@ -1071,7 +1080,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]) @@ -1206,12 +1215,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/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/002_Move/006_Move_Effects_080-0FF.rb b/Data/Scripts/012_Battle/002_Move/006_Move_Effects_080-0FF.rb index 4f849d127..965ce843e 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 @@ -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, @@ -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 @@ -2403,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 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/004_AI/003_AI_Switch.rb b/Data/Scripts/012_Battle/004_AI/003_AI_Switch.rb index 427a103af..e24deca82 100644 --- a/Data/Scripts/012_Battle/004_AI/003_AI_Switch.rb +++ b/Data/Scripts/012_Battle/004_AI/003_AI_Switch.rb @@ -135,7 +135,7 @@ class PokeBattle_AI if @battle.pbRegisterSwitch(idxBattler,list[0]) PBDebug.log("[AI] #{battler.pbThis} (#{idxBattler}) will switch with " + "#{@battle.pbParty(idxBattler)[list[0]].name}") - return + return true end end end 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 0602ad6dc..7e24ce627 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_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/007_BattleHandlers_Abilities.rb b/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb index 3076e206a..1cae4d5ed 100644 --- a/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb +++ b/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb @@ -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 } ) @@ -1030,7 +1030,7 @@ BattleHandlers::DamageCalcUserAbility.add(:SHEERFORCE, BattleHandlers::DamageCalcUserAbility.add(:SLOWSTART, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] /= 2 if user.turnCount<=5 && move.physicalMove? + mults[ATK_MULT] /= 2 if user.effects[PBEffects::SlowStart]>0 && move.physicalMove? } ) @@ -2405,7 +2405,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/013_Overworld/002_PField_Field.rb b/Data/Scripts/013_Overworld/002_PField_Field.rb index 98477c671..53549cd9d 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 @@ -365,6 +370,12 @@ def pbOnStepTaken(eventTriggered) pbBattleOnStepTaken(repel) if !eventTriggered && !$game_temp.in_menu end +# 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 @@ -489,411 +500,6 @@ Events.onMapSceneChange += proc { |_sender,e| -#=============================================================================== -# Event movement -#=============================================================================== -module PBMoveRoute - Down = 1 - Left = 2 - Right = 3 - Up = 4 - LowerLeft = 5 - LowerRight = 6 - UpperLeft = 7 - UpperRight = 8 - Random = 9 - TowardPlayer = 10 - AwayFromPlayer = 11 - Forward = 12 - Backward = 13 - Jump = 14 # xoffset, yoffset - Wait = 15 # frames - TurnDown = 16 - TurnLeft = 17 - TurnRight = 18 - TurnUp = 19 - TurnRight90 = 20 - TurnLeft90 = 21 - Turn180 = 22 - TurnRightOrLeft90 = 23 - TurnRandom = 24 - TurnTowardPlayer = 25 - TurnAwayFromPlayer = 26 - SwitchOn = 27 # 1 param - SwitchOff = 28 # 1 param - ChangeSpeed = 29 # 1 param - ChangeFreq = 30 # 1 param - WalkAnimeOn = 31 - WalkAnimeOff = 32 - StepAnimeOn = 33 - StepAnimeOff = 34 - DirectionFixOn = 35 - DirectionFixOff = 36 - ThroughOn = 37 - ThroughOff = 38 - AlwaysOnTopOn = 39 - AlwaysOnTopOff = 40 - Graphic = 41 # Name, hue, direction, pattern - Opacity = 42 # 1 param - Blending = 43 # 1 param - PlaySE = 44 # 1 param - Script = 45 # 1 param - ScriptAsync = 101 # 1 param -end - - - -def pbMoveRoute(event,commands,waitComplete=false) - route = RPG::MoveRoute.new - route.repeat = false - route.skippable = true - route.list.clear - route.list.push(RPG::MoveCommand.new(PBMoveRoute::ThroughOn)) - i=0 - while i sy.abs - (sx > 0) ? event.turn_left : event.turn_right - else - (sy > 0) ? event.turn_up : event.turn_down - end -end - -def pbMoveTowardPlayer(event) - maxsize = [$game_map.width,$game_map.height].max - return if !pbEventCanReachPlayer?(event,$game_player,maxsize) - loop do - x = event.x - y = event.y - event.move_toward_player - break if event.x==x && event.y==y - while event.moving? - Graphics.update - Input.update - pbUpdateSceneMap - end - end - $PokemonMap.addMovedEvent(event.id) if $PokemonMap -end - -def pbJumpToward(dist=1,playSound=false,cancelSurf=false) - x = $game_player.x - y = $game_player.y - case $game_player.direction - when 2; $game_player.jump(0,dist) # down - when 4; $game_player.jump(-dist,0) # left - when 6; $game_player.jump(dist,0) # right - when 8; $game_player.jump(0,-dist) # up - end - if $game_player.x!=x || $game_player.y!=y - pbSEPlay("Player jump") if playSound - $PokemonEncounters.clearStepCount if cancelSurf - $PokemonTemp.endSurf = true if cancelSurf - while $game_player.jumping? - Graphics.update - Input.update - pbUpdateSceneMap - end - return true - end - return false -end - - - -#=============================================================================== -# Fishing -#=============================================================================== -def pbFishingBegin - $PokemonGlobal.fishing = true - if !pbCommonEvent(FISHING_BEGIN_COMMON_EVENT) - patternb = 2*$game_player.direction - 1 - meta = pbGetMetadata(0,Metadata::PLAYER_A+$PokemonGlobal.playerID) - num = ($PokemonGlobal.surfing) ? 7 : 6 - if meta && meta[num] && meta[num]!="" - charset = pbGetPlayerCharset(meta,num) - 4.times do |pattern| - $game_player.setDefaultCharName(charset,patternb-pattern,true) - (Graphics.frame_rate/20).times do - Graphics.update - Input.update - pbUpdateSceneMap - end - end - end - end -end - -def pbFishingEnd - if !pbCommonEvent(FISHING_END_COMMON_EVENT) - patternb = 2*($game_player.direction - 2) - meta = pbGetMetadata(0,Metadata::PLAYER_A+$PokemonGlobal.playerID) - num = ($PokemonGlobal.surfing) ? 7 : 6 - if meta && meta[num] && meta[num]!="" - charset = pbGetPlayerCharset(meta,num) - 4.times do |pattern| - $game_player.setDefaultCharName(charset,patternb+pattern,true) - (Graphics.frame_rate/20).times do - Graphics.update - Input.update - pbUpdateSceneMap - end - end - end - end - $PokemonGlobal.fishing = false -end - -def pbFishing(hasEncounter,rodType=1) - speedup = ($Trainer.firstPokemon && - (isConst?($Trainer.firstPokemon.ability,PBAbilities,:STICKYHOLD) || - isConst?($Trainer.firstPokemon.ability,PBAbilities,:SUCTIONCUPS))) - biteChance = 20+(25*rodType) # 45, 70, 95 - biteChance *= 1.5 if speedup # 67.5, 100, 100 - hookChance = 100 - oldpattern = $game_player.fullPattern - pbFishingBegin - msgWindow = pbCreateMessageWindow - ret = false - loop do - time = 5+rand(6) - time = [time,5+rand(6)].min if speedup - message = "" - time.times { message += ". " } - if pbWaitMessage(msgWindow,time) - pbFishingEnd - $game_player.setDefaultCharName(nil,oldpattern) - pbMessageDisplay(msgWindow,_INTL("Not even a nibble...")) - break - end - if hasEncounter && rand(100)0 - pbMessageDisplay(msgWindow,message,false) - periodTime.times do - Graphics.update - Input.update - pbUpdateSceneMap - if Input.trigger?(Input::C) || Input.trigger?(Input::B) - return true - end - end - end - return false -end - -# A Pokémon is biting, reflex test to reel it in -def pbWaitForInput(msgWindow,message,frames) - pbMessageDisplay(msgWindow,message,false) - numFrame = 0 - twitchFrame = 0 - twitchFrameTime = Graphics.frame_rate/10 # 0.1 seconds, 4 frames - loop do - Graphics.update - Input.update - pbUpdateSceneMap - # Twitch cycle: 1,0,1,0,0,0,0,0 - twitchFrame = (twitchFrame+1)%(twitchFrameTime*8) - case twitchFrame%twitchFrameTime - when 0, 2 - $game_player.pattern = 1 - else - $game_player.pattern = 0 - end - if Input.trigger?(Input::C) || Input.trigger?(Input::B) - $game_player.pattern = 0 - return true - end - break if !FISHING_AUTO_HOOK && numFrame>frames - numFrame += 1 - end - return false -end - - - -#=============================================================================== -# Bridges, cave escape points, and setting the heal point -#=============================================================================== -def pbBridgeOn(height=2) - $PokemonGlobal.bridge = height -end - -def pbBridgeOff - $PokemonGlobal.bridge = 0 -end - -def pbSetEscapePoint - $PokemonGlobal.escapePoint = [] if !$PokemonGlobal.escapePoint - xco = $game_player.x - yco = $game_player.y - case $game_player.direction - when 2; yco -= 1; dir = 8 # Down - when 4; xco += 1; dir = 6 # Left - when 6; xco -= 1; dir = 4 # Right - when 8; yco += 1; dir = 2 # Up - end - $PokemonGlobal.escapePoint = [$game_map.map_id,xco,yco,dir] -end - -def pbEraseEscapePoint - $PokemonGlobal.escapePoint = [] -end - -def pbSetPokemonCenter - $PokemonGlobal.pokecenterMapId = $game_map.map_id - $PokemonGlobal.pokecenterX = $game_player.x - $PokemonGlobal.pokecenterY = $game_player.y - $PokemonGlobal.pokecenterDirection = $game_player.direction -end - - - -#=============================================================================== -# Partner trainer -#=============================================================================== -def pbRegisterPartner(trainerid,trainername,partyid=0) - trainerid = getID(PBTrainers,trainerid) - pbCancelVehicles - trainer = pbLoadTrainer(trainerid,trainername,partyid) - Events.onTrainerPartyLoad.trigger(nil,trainer) - trainerobject = PokeBattle_Trainer.new(_INTL(trainer[0].name),trainerid) - trainerobject.setForeignID($Trainer) - for i in trainer[2] - i.owner = Pokemon::Owner.new_from_trainer(trainerobject) - i.calcStats - end - $PokemonGlobal.partner = [trainerid,trainerobject.name,trainerobject.id,trainer[2]] -end - -def pbDeregisterPartner - $PokemonGlobal.partner = nil -end - - - #=============================================================================== # Event locations, terrain tags #=============================================================================== @@ -1222,7 +828,7 @@ def pbCueBGM(bgm,seconds,volume=nil,pitch=nil) end def pbAutoplayOnTransition - surfbgm = pbGetMetadata(0,Metadata::SURF_BGM) + surfbgm = pbGetMetadata(0,MetadataSurfBGM) if $PokemonGlobal.surfing && surfbgm pbBGMPlay(surfbgm) else @@ -1231,7 +837,7 @@ def pbAutoplayOnTransition end def pbAutoplayOnSave - surfbgm = pbGetMetadata(0,Metadata::SURF_BGM) + surfbgm = pbGetMetadata(0,MetadataSurfBGM) if $PokemonGlobal.surfing && surfbgm pbBGMPlay(surfbgm) else @@ -1309,6 +915,412 @@ end +#=============================================================================== +# Event movement +#=============================================================================== +module PBMoveRoute + Down = 1 + Left = 2 + Right = 3 + Up = 4 + LowerLeft = 5 + LowerRight = 6 + UpperLeft = 7 + UpperRight = 8 + Random = 9 + TowardPlayer = 10 + AwayFromPlayer = 11 + Forward = 12 + Backward = 13 + Jump = 14 # xoffset, yoffset + Wait = 15 # frames + TurnDown = 16 + TurnLeft = 17 + TurnRight = 18 + TurnUp = 19 + TurnRight90 = 20 + TurnLeft90 = 21 + Turn180 = 22 + TurnRightOrLeft90 = 23 + TurnRandom = 24 + TurnTowardPlayer = 25 + TurnAwayFromPlayer = 26 + SwitchOn = 27 # 1 param + SwitchOff = 28 # 1 param + ChangeSpeed = 29 # 1 param + ChangeFreq = 30 # 1 param + WalkAnimeOn = 31 + WalkAnimeOff = 32 + StepAnimeOn = 33 + StepAnimeOff = 34 + DirectionFixOn = 35 + DirectionFixOff = 36 + ThroughOn = 37 + ThroughOff = 38 + AlwaysOnTopOn = 39 + AlwaysOnTopOff = 40 + Graphic = 41 # Name, hue, direction, pattern + Opacity = 42 # 1 param + Blending = 43 # 1 param + PlaySE = 44 # 1 param + Script = 45 # 1 param + ScriptAsync = 101 # 1 param +end + + + +def pbMoveRoute(event,commands,waitComplete=false) + route = RPG::MoveRoute.new + route.repeat = false + route.skippable = true + route.list.clear + route.list.push(RPG::MoveCommand.new(PBMoveRoute::ThroughOn)) + i=0 + while i sy.abs + (sx > 0) ? event.turn_left : event.turn_right + else + (sy > 0) ? event.turn_up : event.turn_down + end +end + +def pbMoveTowardPlayer(event) + maxsize = [$game_map.width,$game_map.height].max + return if !pbEventCanReachPlayer?(event,$game_player,maxsize) + loop do + x = event.x + y = event.y + event.move_toward_player + break if event.x==x && event.y==y + while event.moving? + Graphics.update + Input.update + pbUpdateSceneMap + end + end + $PokemonMap.addMovedEvent(event.id) if $PokemonMap +end + +def pbJumpToward(dist=1,playSound=false,cancelSurf=false) + x = $game_player.x + y = $game_player.y + case $game_player.direction + when 2; $game_player.jump(0,dist) # down + when 4; $game_player.jump(-dist,0) # left + when 6; $game_player.jump(dist,0) # right + when 8; $game_player.jump(0,-dist) # up + end + if $game_player.x!=x || $game_player.y!=y + pbSEPlay("Player jump") if playSound + $PokemonEncounters.clearStepCount if cancelSurf + $PokemonTemp.endSurf = true if cancelSurf + while $game_player.jumping? + Graphics.update + Input.update + pbUpdateSceneMap + end + return true + end + return false +end + + + +#=============================================================================== +# Fishing +#=============================================================================== +def pbFishingBegin + $PokemonGlobal.fishing = true + if !pbCommonEvent(FISHING_BEGIN_COMMON_EVENT) + patternb = 2*$game_player.direction - 1 + meta = pbGetMetadata(0,MetadataPlayerA+$PokemonGlobal.playerID) + num = ($PokemonGlobal.surfing) ? 7 : 6 + if meta && meta[num] && meta[num]!="" + charset = pbGetPlayerCharset(meta,num) + 4.times do |pattern| + $game_player.setDefaultCharName(charset,patternb-pattern,true) + (Graphics.frame_rate/20).times do + Graphics.update + Input.update + pbUpdateSceneMap + end + end + end + end +end + +def pbFishingEnd + if !pbCommonEvent(FISHING_END_COMMON_EVENT) + patternb = 2*($game_player.direction - 2) + meta = pbGetMetadata(0,MetadataPlayerA+$PokemonGlobal.playerID) + num = ($PokemonGlobal.surfing) ? 7 : 6 + if meta && meta[num] && meta[num]!="" + charset = pbGetPlayerCharset(meta,num) + 4.times do |pattern| + $game_player.setDefaultCharName(charset,patternb+pattern,true) + (Graphics.frame_rate/20).times do + Graphics.update + Input.update + pbUpdateSceneMap + end + end + end + end + $PokemonGlobal.fishing = false +end + +def pbFishing(hasEncounter,rodType=1) + speedup = ($Trainer.firstPokemon && + (isConst?($Trainer.firstPokemon.ability,PBAbilities,:STICKYHOLD) || + isConst?($Trainer.firstPokemon.ability,PBAbilities,:SUCTIONCUPS))) + biteChance = 20+(25*rodType) # 45, 70, 95 + biteChance *= 1.5 if speedup # 67.5, 100, 100 + hookChance = 100 + oldpattern = $game_player.fullPattern + pbFishingBegin + msgWindow = pbCreateMessageWindow + ret = false + loop do + time = 5+rand(6) + time = [time,5+rand(6)].min if speedup + message = "" + time.times { message += ". " } + if pbWaitMessage(msgWindow,time) + pbFishingEnd + $game_player.setDefaultCharName(nil,oldpattern) + pbMessageDisplay(msgWindow,_INTL("Not even a nibble...")) + break + end + if hasEncounter && rand(100)0 + pbMessageDisplay(msgWindow,message,false) + periodTime.times do + Graphics.update + Input.update + pbUpdateSceneMap + if Input.trigger?(Input::C) || Input.trigger?(Input::B) + return true + end + end + end + return false +end + +# A Pokémon is biting, reflex test to reel it in +def pbWaitForInput(msgWindow,message,frames) + pbMessageDisplay(msgWindow,message,false) + numFrame = 0 + twitchFrame = 0 + twitchFrameTime = Graphics.frame_rate/10 # 0.1 seconds, 4 frames + loop do + Graphics.update + Input.update + pbUpdateSceneMap + # Twitch cycle: 1,0,1,0,0,0,0,0 + twitchFrame = (twitchFrame+1)%(twitchFrameTime*8) + case twitchFrame%twitchFrameTime + when 0, 2 + $game_player.pattern = 1 + else + $game_player.pattern = 0 + end + if Input.trigger?(Input::C) || Input.trigger?(Input::B) + $game_player.pattern = 0 + return true + end + break if !FISHING_AUTO_HOOK && numFrame>frames + numFrame += 1 + end + return false +end + + + +#=============================================================================== +# Bridges, cave escape points, and setting the heal point +#=============================================================================== +def pbBridgeOn(height=2) + $PokemonGlobal.bridge = height +end + +def pbBridgeOff + $PokemonGlobal.bridge = 0 +end + +def pbSetEscapePoint + $PokemonGlobal.escapePoint = [] if !$PokemonGlobal.escapePoint + xco = $game_player.x + yco = $game_player.y + case $game_player.direction + when 2; yco -= 1; dir = 8 # Down + when 4; xco += 1; dir = 6 # Left + when 6; xco -= 1; dir = 4 # Right + when 8; yco += 1; dir = 2 # Up + end + $PokemonGlobal.escapePoint = [$game_map.map_id,xco,yco,dir] +end + +def pbEraseEscapePoint + $PokemonGlobal.escapePoint = [] +end + +def pbSetPokemonCenter + $PokemonGlobal.pokecenterMapId = $game_map.map_id + $PokemonGlobal.pokecenterX = $game_player.x + $PokemonGlobal.pokecenterY = $game_player.y + $PokemonGlobal.pokecenterDirection = $game_player.direction +end + + + +#=============================================================================== +# Partner trainer +#=============================================================================== +def pbRegisterPartner(trainerid,trainername,partyid=0) + trainerid = getID(PBTrainers,trainerid) + pbCancelVehicles + trainer = pbLoadTrainer(trainerid,trainername,partyid) + Events.onTrainerPartyLoad.trigger(nil,trainer) + trainerobject = PokeBattle_Trainer.new(_INTL(trainer[0].name),trainerid) + trainerobject.setForeignID($Trainer) + for i in trainer[2] + i.trainerID = trainerobject.id + i.ot = trainerobject.name + i.calcStats + end + $PokemonGlobal.partner = [trainerid,trainerobject.name,trainerobject.id,trainer[2]] +end + +def pbDeregisterPartner + $PokemonGlobal.partner = nil +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 5f2a513d8..5d329aed3 100644 --- a/Data/Scripts/013_Overworld/003_PField_Visuals.rb +++ b/Data/Scripts/013_Overworld/003_PField_Visuals.rb @@ -1,227 +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.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 #=============================================================================== @@ -540,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 24f533c3f..b79764075 100644 --- a/Data/Scripts/013_Overworld/006_PField_Battles.rb +++ b/Data/Scripts/013_Overworld/006_PField_Battles.rb @@ -34,8 +34,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 +45,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 +64,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 diff --git a/Data/Scripts/013_Overworld/009_PField_RoamingPokemon.rb b/Data/Scripts/013_Overworld/009_PField_RoamingPokemon.rb index 1d35cf544..48d8626ed 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/015_Items/002_PItem_ItemEffects.rb b/Data/Scripts/015_Items/002_PItem_ItemEffects.rb index b40202189..214071145 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) || diff --git a/Data/Scripts/016_Pokemon/002_Pokemon_Forms.rb b/Data/Scripts/016_Pokemon/002_Pokemon_Forms.rb index ace7ad2ab..3e85fc919 100644 --- a/Data/Scripts/016_Pokemon/002_Pokemon_Forms.rb +++ b/Data/Scripts/016_Pokemon/002_Pokemon_Forms.rb @@ -37,15 +37,6 @@ class 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 ad6854aca..b03c3acbf 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/005_PSystem_Utilities.rb b/Data/Scripts/020_System and utilities/005_PSystem_Utilities.rb index 492b1de99..89fec7703 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/002_Debug_Actions.rb b/Data/Scripts/021_Debug/002_Debug_Actions.rb index b265f3c08..581627d9b 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] diff --git a/Data/Scripts/021_Debug/005_Editor_SaveData.rb b/Data/Scripts/021_Debug/005_Editor_SaveData.rb index 0b16dad84..89752ab46 100644 --- a/Data/Scripts/021_Debug/005_Editor_SaveData.rb +++ b/Data/Scripts/021_Debug/005_Editor_SaveData.rb @@ -557,7 +557,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) diff --git a/Data/Scripts/021_Debug/013_Editor_BattleAnimationEditor.rb b/Data/Scripts/021_Debug/013_Editor_BattleAnimationEditor.rb index 84d43cb98..5294a6aed 100644 --- a/Data/Scripts/021_Debug/013_Editor_BattleAnimationEditor.rb +++ b/Data/Scripts/021_Debug/013_Editor_BattleAnimationEditor.rb @@ -3093,8 +3093,8 @@ class PointPath return ret end step=1.0/frames - t=0.0; - for i in 0..frames+1 + t=0.0 + (frames+2).times do point=pointOnPath(t) if roundValues ret.addPoint(point[0].round,point[1].round) diff --git a/Data/Scripts/999_Main/999_Main.rb b/Data/Scripts/999_Main/999_Main.rb index 5b9865924..2b6f285cb 100644 --- a/Data/Scripts/999_Main/999_Main.rb +++ b/Data/Scripts/999_Main/999_Main.rb @@ -1,8 +1,6 @@ pbSetUpSystem Compiler.main - - class Scene_DebugIntro def main Graphics.transition(0) @@ -13,8 +11,6 @@ class Scene_DebugIntro end end - - def pbCallTitle return Scene_DebugIntro.new if $DEBUG # First parameter is an array of images in the Titles @@ -35,9 +31,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") @@ -47,9 +43,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 @@ -60,11 +54,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 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/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."