From 2586c09c3c19c79190db31c0df3226a8d92acf73 Mon Sep 17 00:00:00 2001 From: Maruno17 Date: Mon, 11 Jan 2021 19:30:45 +0000 Subject: [PATCH] Refactoring and tidying --- Data/Scripts/001_Technical/005_Win32API.rb | 69 +- .../002_MessageConfig.rb | 6 - .../009_Objects and windows/011_Messages.rb | 38 +- .../002_Move/003_Move_Usage_Calculations.rb | 152 +- .../002_Move/006_Move_Effects_080-0FF.rb | 2 +- .../004_AI/006_AI_Move_Utilities.rb | 151 +- Data/Scripts/012_Battle/006_BattleHandlers.rb | 17 +- .../007_BattleHandlers_Abilities.rb | 156 +- .../012_Battle/008_BattleHandlers_Items.rb | 84 +- .../014_Trainers/002_PTrainer_NPCTrainers.rb | 4 +- Data/Scripts/016_Pokemon/001_Pokemon.rb | 6 +- Data/Scripts/017_UI/009_PScreen_RegionMap.rb | 8 +- .../005_PBattle_OrgBattleGenerator.rb | 5 +- .../001_PSystem_Controls.rb | 25 +- .../002_PSystem_System.rb | 10 - .../005_PSystem_Utilities.rb | 16 + .../{ => 001_Debug menus}/001_Debug_Menus.rb | 0 .../002_Debug_MenuCommands.rb} | 2 +- .../003_Debug_MenuExtraCode.rb} | 0 .../004_Debug_PokemonCommands.rb} | 0 .../001_AnimEditor_SceneElements.rb | 1031 +++++ .../002_AnimEditor_ControlsButtons.rb | 945 ++++ .../003_AnimEditor_Interpolation.rb | 444 ++ .../004_AnimEditor_ExportImport.rb | 144 + .../005_AnimEditor_Functions.rb | 1193 ++++++ Data/Scripts/021_Debug/004_Editor_Screens.rb | 14 +- Data/Scripts/021_Debug/005_Editor_SaveData.rb | 870 ---- .../021_Debug/006_Editor_DataFormatting.rb | 116 - .../Scripts/021_Debug/009_Editor_Utilities.rb | 104 - ...or.rb => 010_Editor_TilesetTerrainTags.rb} | 0 ...Editor.rb => 011_Editor_MapConnections.rb} | 5 +- ...tor.rb => 012_Editor_SpritePositioning.rb} | 8 +- .../013_Editor_BattleAnimationEditor.rb | 3786 ----------------- .../{002_Compiler.rb => 001_Compiler.rb} | 141 +- Data/Scripts/022_Compiler/001_Data_storage.rb | 305 -- ...iler_PBS.rb => 002_Compiler_CompilePBS.rb} | 560 ++- .../022_Compiler/003_Compiler_WritePBS.rb | 837 ++++ 37 files changed, 5288 insertions(+), 5966 deletions(-) rename Data/Scripts/021_Debug/{ => 001_Debug menus}/001_Debug_Menus.rb (100%) rename Data/Scripts/021_Debug/{001b_Debug_MenuCommands.rb => 001_Debug menus/002_Debug_MenuCommands.rb} (99%) rename Data/Scripts/021_Debug/{002_Debug_MenuExtraCode.rb => 001_Debug menus/003_Debug_MenuExtraCode.rb} (100%) rename Data/Scripts/021_Debug/{003_Debug_PokemonCommands.rb => 001_Debug menus/004_Debug_PokemonCommands.rb} (100%) create mode 100644 Data/Scripts/021_Debug/002_Animation editor/001_AnimEditor_SceneElements.rb create mode 100644 Data/Scripts/021_Debug/002_Animation editor/002_AnimEditor_ControlsButtons.rb create mode 100644 Data/Scripts/021_Debug/002_Animation editor/003_AnimEditor_Interpolation.rb create mode 100644 Data/Scripts/021_Debug/002_Animation editor/004_AnimEditor_ExportImport.rb create mode 100644 Data/Scripts/021_Debug/002_Animation editor/005_AnimEditor_Functions.rb delete mode 100644 Data/Scripts/021_Debug/005_Editor_SaveData.rb delete mode 100644 Data/Scripts/021_Debug/006_Editor_DataFormatting.rb rename Data/Scripts/021_Debug/{010_Editor_TilesetEditor.rb => 010_Editor_TilesetTerrainTags.rb} (100%) rename Data/Scripts/021_Debug/{011_Editor_MapConnectionEditor.rb => 011_Editor_MapConnections.rb} (99%) rename Data/Scripts/021_Debug/{012_Editor_SpritePosEditor.rb => 012_Editor_SpritePositioning.rb} (99%) delete mode 100644 Data/Scripts/021_Debug/013_Editor_BattleAnimationEditor.rb rename Data/Scripts/022_Compiler/{002_Compiler.rb => 001_Compiler.rb} (90%) delete mode 100644 Data/Scripts/022_Compiler/001_Data_storage.rb rename Data/Scripts/022_Compiler/{003_Compiler_PBS.rb => 002_Compiler_CompilePBS.rb} (97%) create mode 100644 Data/Scripts/022_Compiler/003_Compiler_WritePBS.rb diff --git a/Data/Scripts/001_Technical/005_Win32API.rb b/Data/Scripts/001_Technical/005_Win32API.rb index 5fc2c15b6..0b5b13836 100644 --- a/Data/Scripts/001_Technical/005_Win32API.rb +++ b/Data/Scripts/001_Technical/005_Win32API.rb @@ -4,7 +4,7 @@ class Win32API @@GetWindowThreadProcessId = Win32API.new('user32', 'GetWindowThreadProcessId', '%w(l p)', 'l') @@FindWindowEx = Win32API.new('user32', 'FindWindowEx', '%w(l l p p)', 'l') - # Added by Peter O. as a more reliable way to get the RGSS window + # Added by Peter O. as a more reliable way to get the RGSS window def Win32API.pbFindRgssWindow return @@RGSSWINDOW if @@RGSSWINDOW processid = [0].pack('l') @@ -32,73 +32,6 @@ class Win32API width,height = rect.unpack('l4')[2..3] return width,height end - -=begin - # Unused - def Win32API.SetWindowText(text) - hWnd = pbFindRgssWindow - swp = Win32API.new('user32','SetWindowTextA',%(l, p),'i') - swp.call(hWnd, text.to_s) - end - - # Unused - def Win32API.SetWindowPos(w, h) - hWnd = pbFindRgssWindow - windowrect = Win32API.GetWindowRect - clientsize = Win32API.client_size - xExtra = windowrect.width-clientsize[0] - yExtra = windowrect.height-clientsize[1] - swp = Win32API.new('user32','SetWindowPos',%(l,l,i,i,i,i,i),'i') - win = swp.call(hWnd,0,windowrect.x,windowrect.y,w+xExtra,h+yExtra,0) - return win - end - - # Unused - def Win32API.GetWindowRect - hWnd = pbFindRgssWindow - rect = [0,0,0,0].pack('l4') - Win32API.new('user32','GetWindowRect',%w(l p),'i').call(hWnd,rect) - x,y,width,height = rect.unpack('l4') - return Rect.new(x,y,width-x,height-y) - end - - # Unused - def Win32API.focusWindow - window = Win32API.new('user32','ShowWindow','LL','L') - hWnd = pbFindRgssWindow - window.call(hWnd,9) - end - - # Unused - def Win32API.fillScreen - setWindowLong = Win32API.new('user32','SetWindowLong','LLL','L') - setWindowPos = Win32API.new('user32','SetWindowPos','LLIIIII','I') - metrics = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I') - hWnd = pbFindRgssWindow - width = metrics.call(0) - height = metrics.call(1) - setWindowLong.call(hWnd,-16,0x00000000) - setWindowPos.call(hWnd,0,0,0,width,height,0) - Win32API.focusWindow - return [width,height] - end - - # Unused - def Win32API.restoreScreen - setWindowLong = Win32API.new('user32','SetWindowLong','LLL','L') - setWindowPos = Win32API.new('user32','SetWindowPos','LLIIIII','I') - metrics = Win32API.new('user32','GetSystemMetrics','I','I') - hWnd = pbFindRgssWindow - width = SCREEN_WIDTH - height = SCREEN_HEIGHT - x = [(metrics.call(0)-width)/2,0].max - y = [(metrics.call(1)-height)/2,0].max - setWindowLong.call(hWnd,-16,0x14CA0000) - setWindowPos.call(hWnd,0,x,y,width+6,height+29,0) - Win32API.focusWindow - return [width,height] - end -=end end diff --git a/Data/Scripts/009_Objects and windows/002_MessageConfig.rb b/Data/Scripts/009_Objects and windows/002_MessageConfig.rb index b03136c28..22073df17 100644 --- a/Data/Scripts/009_Objects and windows/002_MessageConfig.rb +++ b/Data/Scripts/009_Objects and windows/002_MessageConfig.rb @@ -219,12 +219,6 @@ def pbRepositionMessageWindow(msgwindow, linecount=2) msgwindow.opacity = 0 end end - if $game_message - case $game_message.background - when 1 then msgwindow.opacity=0 # dim - when 2 then msgwindow.opacity=0 # transparent - end - end end # internal function diff --git a/Data/Scripts/009_Objects and windows/011_Messages.rb b/Data/Scripts/009_Objects and windows/011_Messages.rb index 20c34ebd9..385c6c8c1 100644 --- a/Data/Scripts/009_Objects and windows/011_Messages.rb +++ b/Data/Scripts/009_Objects and windows/011_Messages.rb @@ -1,30 +1,11 @@ -#=============================================================================== -# Message variables -#=============================================================================== -class Game_Message - attr_writer :visible - attr_writer :background - - def visible - return @visible || false - end - - def background - return @background || 0 - end -end - - - #=============================================================================== # #=============================================================================== class Scene_Map def updatemini oldmws=$game_temp.message_window_showing - oldvis=$game_message ? $game_message.visible : false + oldvis=false $game_temp.message_window_showing=true - $game_message.visible=true if $game_message loop do $game_map.update $game_player.update @@ -39,7 +20,6 @@ class Scene_Map break if $game_temp.transition_processing end $game_temp.message_window_showing=oldmws - $game_message.visible=oldvis if $game_message @spriteset.update if @spriteset @message_window.update if @message_window end @@ -52,10 +32,6 @@ class Scene_Battle if self.respond_to?("update_basic") update_basic(true) update_info_viewport # Update information viewport - if $game_message && $game_message.visible - @info_viewport.visible = false - @message_window.visible = true - end else oldmws=$game_temp.message_window_showing $game_temp.message_window_showing=true @@ -507,7 +483,6 @@ def pbCreateMessageWindow(viewport=nil,skin=nil) msgwindow.back_opacity=MessageConfig::WindowOpacity pbBottomLeftLines(msgwindow,2) $game_temp.message_window_showing=true if $game_temp - $game_message.visible=true if $game_message skin=MessageConfig.pbGetSpeechFrame() if !skin msgwindow.setSkin(skin) return msgwindow @@ -515,7 +490,6 @@ end def pbDisposeMessageWindow(msgwindow) $game_temp.message_window_showing=false if $game_temp - $game_message.visible=false if $game_message msgwindow.dispose end @@ -592,9 +566,8 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil) break if text == last_text end colortag = "" - if ($game_message && $game_message.background>0) || - ($game_system && $game_system.respond_to?("message_frame") && - $game_system.message_frame != 0) + if $game_system && $game_system.respond_to?("message_frame") && + $game_system.message_frame != 0 colortag = getSkinColor(msgwindow.windowskin,0,true) else colortag = getSkinColor(msgwindow.windowskin,0,isDarkSkin) @@ -674,11 +647,6 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil) end ########## Position message window ############## pbRepositionMessageWindow(msgwindow,linecount) - if $game_message && $game_message.background==1 - msgback = IconSprite.new(0,msgwindow.y,msgwindow.viewport) - msgback.z = msgwindow.z-1 - msgback.setBitmap("Graphics/System/MessageBack") - end if facewindow pbPositionNearMsgWindow(facewindow,msgwindow,:left) facewindow.viewport = msgwindow.viewport diff --git a/Data/Scripts/012_Battle/002_Move/003_Move_Usage_Calculations.rb b/Data/Scripts/012_Battle/002_Move/003_Move_Usage_Calculations.rb index 64fa912d5..6543307de 100644 --- a/Data/Scripts/012_Battle/002_Move/003_Move_Usage_Calculations.rb +++ b/Data/Scripts/012_Battle/002_Move/003_Move_Usage_Calculations.rb @@ -88,27 +88,27 @@ class PokeBattle_Move baseAcc = pbBaseAccuracy(user,target) return true if baseAcc==0 # Calculate all multiplier effects - modifiers = [] - modifiers[BASE_ACC] = baseAcc - modifiers[ACC_STAGE] = user.stages[PBStats::ACCURACY] - modifiers[EVA_STAGE] = target.stages[PBStats::EVASION] - modifiers[ACC_MULT] = 1.0 - modifiers[EVA_MULT] = 1.0 + modifiers = {} + modifiers[:base_accuracy] = baseAcc + modifiers[:accuracy_stage] = user.stages[PBStats::ACCURACY] + modifiers[:evasion_stage] = target.stages[PBStats::EVASION] + modifiers[:accuracy_multiplier] = 1.0 + modifiers[:evasion_multiplier] = 1.0 pbCalcAccuracyModifiers(user,target,modifiers) # Check if move can't miss - return true if modifiers[BASE_ACC]==0 + return true if modifiers[:base_accuracy] == 0 # Calculation - accStage = [[modifiers[ACC_STAGE],-6].max,6].min + 6 - evaStage = [[modifiers[EVA_STAGE],-6].max,6].min + 6 + accStage = [[modifiers[:accuracy_stage], -6].max, 6].min + 6 + evaStage = [[modifiers[:evasion_stage], -6].max, 6].min + 6 stageMul = [3,3,3,3,3,3, 3, 4,5,6,7,8,9] stageDiv = [9,8,7,6,5,4, 3, 3,3,3,3,3,3] accuracy = 100.0 * stageMul[accStage] / stageDiv[accStage] evasion = 100.0 * stageMul[evaStage] / stageDiv[evaStage] - accuracy = (accuracy * modifiers[ACC_MULT]).round - evasion = (evasion * modifiers[EVA_MULT]).round - evasion = 1 if evasion<1 + accuracy = (accuracy * modifiers[:accuracy_multiplier]).round + evasion = (evasion * modifiers[:evasion_multiplier]).round + evasion = 1 if evasion < 1 # Calculation - return @battle.pbRandom(100) < modifiers[BASE_ACC] * accuracy / evasion + return @battle.pbRandom(100) < modifiers[:base_accuracy] * accuracy / evasion end def pbCalcAccuracyModifiers(user,target,modifiers) @@ -135,16 +135,17 @@ class PokeBattle_Move BattleHandlers.triggerAccuracyCalcTargetItem(target.item, modifiers,user,target,self,@calcType) end - # Other effects, inc. ones that set ACC_MULT or EVA_STAGE to specific values - if @battle.field.effects[PBEffects::Gravity]>0 - modifiers[ACC_MULT] *= 5/3.0 + # Other effects, inc. ones that set accuracy_multiplier or evasion_stage to + # specific values + if @battle.field.effects[PBEffects::Gravity] > 0 + modifiers[:accuracy_multiplier] *= 5 / 3.0 end if user.effects[PBEffects::MicleBerry] user.effects[PBEffects::MicleBerry] = false - modifiers[ACC_MULT] *= 1.2 + modifiers[:accuracy_multiplier] *= 1.2 end - modifiers[EVA_STAGE] = 0 if target.effects[PBEffects::Foresight] && modifiers[EVA_STAGE]>0 - modifiers[EVA_STAGE] = 0 if target.effects[PBEffects::MiracleEye] && modifiers[EVA_STAGE]>0 + modifiers[:evasion_stage] = 0 if target.effects[PBEffects::Foresight] && modifiers[:evasion_stage] > 0 + modifiers[:evasion_stage] = 0 if target.effects[PBEffects::MiracleEye] && modifiers[:evasion_stage] > 0 end #============================================================================= @@ -241,14 +242,19 @@ class PokeBattle_Move defense = (defense.to_f*stageMul[defStage]/stageDiv[defStage]).floor end # Calculate all multiplier effects - multipliers = [1.0, 1.0, 1.0, 1.0] + multipliers = { + :base_damage_multiplier => 1.0, + :attack_multiplier => 1.0, + :defense_multiplier => 1.0, + :final_damage_multiplier => 1.0 + } pbCalcDamageMultipliers(user,target,numTargets,type,baseDmg,multipliers) # Main damage calculation - baseDmg = [(baseDmg * multipliers[BASE_DMG_MULT]).round, 1].max - atk = [(atk * multipliers[ATK_MULT]).round, 1].max - defense = [(defense * multipliers[DEF_MULT]).round, 1].max + baseDmg = [(baseDmg * multipliers[:base_damage_multiplier]).round, 1].max + atk = [(atk * multipliers[:attack_multiplier]).round, 1].max + defense = [(defense * multipliers[:defense_multiplier]).round, 1].max damage = (((2.0 * user.level / 5 + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2 - damage = [(damage * multipliers[FINAL_DMG_MULT]).round, 1].max + damage = [(damage * multipliers[:final_damage_multiplier]).round, 1].max target.damageState.calcDamage = damage end @@ -257,9 +263,9 @@ class PokeBattle_Move if (@battle.pbCheckGlobalAbility(:DARKAURA) && type == :DARK) || (@battle.pbCheckGlobalAbility(:FAIRYAURA) && type == :FAIRY) if @battle.pbCheckGlobalAbility(:AURABREAK) - multipliers[BASE_DMG_MULT] *= 2/3.0 + multipliers[:base_damage_multiplier] *= 2 / 3.0 else - multipliers[BASE_DMG_MULT] *= 4/3.0 + multipliers[:base_damage_multiplier] *= 4 / 3.0 end end # Ability effects that alter damage @@ -299,154 +305,154 @@ class PokeBattle_Move end # Parental Bond's second attack if user.effects[PBEffects::ParentalBond]==1 - multipliers[BASE_DMG_MULT] /= 4 + multipliers[:base_damage_multiplier] /= 4 end # Other if user.effects[PBEffects::MeFirst] - multipliers[BASE_DMG_MULT] *= 1.5 + multipliers[:base_damage_multiplier] *= 1.5 end if user.effects[PBEffects::HelpingHand] && !self.is_a?(PokeBattle_Confusion) - multipliers[BASE_DMG_MULT] *= 1.5 + multipliers[:base_damage_multiplier] *= 1.5 end if user.effects[PBEffects::Charge]>0 && type == :ELECTRIC - multipliers[BASE_DMG_MULT] *= 2 + multipliers[:base_damage_multiplier] *= 2 end # Mud Sport if type == :ELECTRIC @battle.eachBattler do |b| next if !b.effects[PBEffects::MudSport] - multipliers[BASE_DMG_MULT] /= 3 + multipliers[:base_damage_multiplier] /= 3 break end if @battle.field.effects[PBEffects::MudSportField]>0 - multipliers[BASE_DMG_MULT] /= 3 + multipliers[:base_damage_multiplier] /= 3 end end # Water Sport if type == :FIRE @battle.eachBattler do |b| next if !b.effects[PBEffects::WaterSport] - multipliers[BASE_DMG_MULT] /= 3 + multipliers[:base_damage_multiplier] /= 3 break end if @battle.field.effects[PBEffects::WaterSportField]>0 - multipliers[BASE_DMG_MULT] /= 3 + multipliers[:base_damage_multiplier] /= 3 end end # Terrain moves if user.affectedByTerrain? case @battle.field.terrain when PBBattleTerrains::Electric - multipliers[BASE_DMG_MULT] *= 1.5 if type == :ELECTRIC + multipliers[:base_damage_multiplier] *= 1.5 if type == :ELECTRIC when PBBattleTerrains::Grassy - multipliers[BASE_DMG_MULT] *= 1.5 if type == :GRASS + multipliers[:base_damage_multiplier] *= 1.5 if type == :GRASS when PBBattleTerrains::Psychic - multipliers[BASE_DMG_MULT] *= 1.5 if type == :PSYCHIC + multipliers[:base_damage_multiplier] *= 1.5 if type == :PSYCHIC end end if @battle.field.terrain==PBBattleTerrains::Misty && target.affectedByTerrain? && type == :DRAGON - multipliers[BASE_DMG_MULT] /= 2 + multipliers[:base_damage_multiplier] /= 2 end # Badge multipliers if @battle.internalBattle if user.pbOwnedByPlayer? - if physicalMove? && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_ATTACK - multipliers[ATK_MULT] *= 1.1 - elsif specialMove? && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_SPATK - multipliers[ATK_MULT] *= 1.1 + if physicalMove? && @battle.pbPlayer.numbadges >= NUM_BADGES_BOOST_ATTACK + multipliers[:attack_multiplier] *= 1.1 + elsif specialMove? && @battle.pbPlayer.numbadges >= NUM_BADGES_BOOST_SPATK + multipliers[:attack_multiplier] *= 1.1 end end if target.pbOwnedByPlayer? - if physicalMove? && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_DEFENSE - multipliers[DEF_MULT] *= 1.1 - elsif specialMove? && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_SPDEF - multipliers[DEF_MULT] *= 1.1 + if physicalMove? && @battle.pbPlayer.numbadges >= NUM_BADGES_BOOST_DEFENSE + multipliers[:defense_multiplier] *= 1.1 + elsif specialMove? && @battle.pbPlayer.numbadges >= NUM_BADGES_BOOST_SPDEF + multipliers[:defense_multiplier] *= 1.1 end end end # Multi-targeting attacks if numTargets>1 - multipliers[FINAL_DMG_MULT] *= 0.75 + multipliers[:final_damage_multiplier] *= 0.75 end # Weather case @battle.pbWeather when PBWeather::Sun, PBWeather::HarshSun if type == :FIRE - multipliers[FINAL_DMG_MULT] *= 1.5 + multipliers[:final_damage_multiplier] *= 1.5 elsif type == :WATER - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 end when PBWeather::Rain, PBWeather::HeavyRain if type == :FIRE - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 elsif type == :WATER - multipliers[FINAL_DMG_MULT] *= 1.5 + multipliers[:final_damage_multiplier] *= 1.5 end when PBWeather::Sandstorm - if target.pbHasType?(:ROCK) && specialMove? && @function!="122" # Psyshock - multipliers[DEF_MULT] *= 1.5 + if target.pbHasType?(:ROCK) && specialMove? && @function != "122" # Psyshock + multipliers[:defense_multiplier] *= 1.5 end end # Critical hits if target.damageState.critical if NEW_CRITICAL_HIT_RATE_MECHANICS - multipliers[FINAL_DMG_MULT] *= 1.5 + multipliers[:final_damage_multiplier] *= 1.5 else - multipliers[FINAL_DMG_MULT] *= 2 + multipliers[:final_damage_multiplier] *= 2 end end # Random variance if !self.is_a?(PokeBattle_Confusion) random = 85+@battle.pbRandom(16) - multipliers[FINAL_DMG_MULT] *= random/100.0 + multipliers[:final_damage_multiplier] *= random / 100.0 end # STAB if type && user.pbHasType?(type) if user.hasActiveAbility?(:ADAPTABILITY) - multipliers[FINAL_DMG_MULT] *= 2 + multipliers[:final_damage_multiplier] *= 2 else - multipliers[FINAL_DMG_MULT] *= 1.5 + multipliers[:final_damage_multiplier] *= 1.5 end end # Type effectiveness - multipliers[FINAL_DMG_MULT] *= target.damageState.typeMod.to_f/PBTypeEffectiveness::NORMAL_EFFECTIVE + multipliers[:final_damage_multiplier] *= target.damageState.typeMod.to_f / PBTypeEffectiveness::NORMAL_EFFECTIVE # Burn if user.status==PBStatuses::BURN && physicalMove? && damageReducedByBurn? && !user.hasActiveAbility?(:GUTS) - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 end # Aurora Veil, Reflect, Light Screen if !ignoresReflect? && !target.damageState.critical && !user.hasActiveAbility?(:INFILTRATOR) - if target.pbOwnSide.effects[PBEffects::AuroraVeil]>0 + if target.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] *= 2/3.0 + multipliers[:final_damage_multiplier] *= 2 / 3.0 else - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 end - elsif target.pbOwnSide.effects[PBEffects::Reflect]>0 && physicalMove? + elsif target.pbOwnSide.effects[PBEffects::Reflect] > 0 && physicalMove? if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] *= 2/3.0 + multipliers[:final_damage_multiplier] *= 2 / 3.0 else - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 end - elsif target.pbOwnSide.effects[PBEffects::LightScreen]>0 && specialMove? - if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] *= 2/3.0 + elsif target.pbOwnSide.effects[PBEffects::LightScreen] > 0 && specialMove? + if @battle.pbSideBattlerCount(target) > 1 + multipliers[:final_damage_multiplier] *= 2 / 3.0 else - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 end end end # Minimize if target.effects[PBEffects::Minimize] && tramplesMinimize?(2) - multipliers[FINAL_DMG_MULT] *= 2 + multipliers[:final_damage_multiplier] *= 2 end # Move-specific base damage modifiers - multipliers[BASE_DMG_MULT] = pbBaseDamageMultiplier(multipliers[BASE_DMG_MULT],user,target) + multipliers[:base_damage_multiplier] = pbBaseDamageMultiplier(multipliers[:base_damage_multiplier], user, target) # Move-specific final damage modifiers - multipliers[FINAL_DMG_MULT] = pbModifyDamage(multipliers[FINAL_DMG_MULT],user,target) + multipliers[:final_damage_multiplier] = pbModifyDamage(multipliers[:final_damage_multiplier], user, target) end #============================================================================= diff --git a/Data/Scripts/012_Battle/002_Move/006_Move_Effects_080-0FF.rb b/Data/Scripts/012_Battle/002_Move/006_Move_Effects_080-0FF.rb index e58ae3dcd..007bf7f86 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 @@ -1035,7 +1035,7 @@ end class PokeBattle_Move_0A9 < PokeBattle_Move def pbCalcAccuracyMultipliers(user,target,multipliers) super - modifiers[EVA_STAGE] = 0 # Accuracy stat stage + modifiers[:evasion_stage] = 0 end def pbGetDefenseStats(user,target) diff --git a/Data/Scripts/012_Battle/004_AI/006_AI_Move_Utilities.rb b/Data/Scripts/012_Battle/004_AI/006_AI_Move_Utilities.rb index 0e8df431e..d41f3a4eb 100644 --- a/Data/Scripts/012_Battle/004_AI/006_AI_Move_Utilities.rb +++ b/Data/Scripts/012_Battle/004_AI/006_AI_Move_Utilities.rb @@ -274,7 +274,12 @@ class PokeBattle_AI defense = pbRoughStat(target,PBStats::SPDEF,skill) end ##### Calculate all multiplier effects ##### - multipliers = [1.0, 1.0, 1.0, 1.0] + multipliers = { + :base_damage_multiplier => 1.0, + :attack_multiplier => 1.0, + :defense_multiplier => 1.0, + :final_damage_multiplier => 1.0 + } # Ability effects that alter damage moldBreaker = false if skill>=PBTrainerAI.highSkill && target.hasMoldBreaker? @@ -349,15 +354,15 @@ class PokeBattle_AI if (@battle.pbCheckGlobalAbility(:DARKAURA) && type == :DARK) || (@battle.pbCheckGlobalAbility(:FAIRYAURA) && type == :FAIRY) if @battle.pbCheckGlobalAbility(:AURABREAK) - multipliers[BASE_DMG_MULT] *= 2/3 + multipliers[:base_damage_multiplier] *= 2 / 3.0 else - multipliers[BASE_DMG_MULT] *= 4/3 + multipliers[:base_damage_multiplier] *= 4 / 3.0 end end end # Parental Bond if skill>=PBTrainerAI.mediumSkill && user.hasActiveAbility?(:PARENTALBOND) - multipliers[BASE_DMG_MULT] *= 1.25 + multipliers[:base_damage_multiplier] *= 1.25 end # Me First # TODO @@ -365,7 +370,7 @@ class PokeBattle_AI # Charge if skill>=PBTrainerAI.mediumSkill if user.effects[PBEffects::Charge]>0 && type == :ELECTRIC - multipliers[BASE_DMG_MULT] *= 2 + multipliers[:base_damage_multiplier] *= 2 end end # Mud Sport and Water Sport @@ -373,21 +378,21 @@ class PokeBattle_AI if type == :ELECTRIC @battle.eachBattler do |b| next if !b.effects[PBEffects::MudSport] - multipliers[BASE_DMG_MULT] /= 3 + multipliers[:base_damage_multiplier] /= 3 break end if @battle.field.effects[PBEffects::MudSportField]>0 - multipliers[BASE_DMG_MULT] /= 3 + multipliers[:base_damage_multiplier] /= 3 end end if type == :FIRE @battle.eachBattler do |b| next if !b.effects[PBEffects::WaterSport] - multipliers[BASE_DMG_MULT] /= 3 + multipliers[:base_damage_multiplier] /= 3 break end if @battle.field.effects[PBEffects::WaterSportField]>0 - multipliers[BASE_DMG_MULT] /= 3 + multipliers[:base_damage_multiplier] /= 3 end end end @@ -395,16 +400,16 @@ class PokeBattle_AI if user.affectedByTerrain? && skill>=PBTrainerAI.mediumSkill case @battle.field.terrain when PBBattleTerrains::Electric - multipliers[BASE_DMG_MULT] *= 1.5 if type == :ELECTRIC + multipliers[:base_damage_multiplier] *= 1.5 if type == :ELECTRIC when PBBattleTerrains::Grassy - multipliers[BASE_DMG_MULT] *= 1.5 if type == :GRASS + multipliers[:base_damage_multiplier] *= 1.5 if type == :GRASS when PBBattleTerrains::Psychic - multipliers[BASE_DMG_MULT] *= 1.5 if type == :PSYCHIC + multipliers[:base_damage_multiplier] *= 1.5 if type == :PSYCHIC end end if target.affectedByTerrain? && skill>=PBTrainerAI.mediumSkill if @battle.field.terrain==PBBattleTerrains::Misty && type == :DRAGON - multipliers[BASE_DMG_MULT] /= 2 + multipliers[:base_damage_multiplier] /= 2 end end # Badge multipliers @@ -413,10 +418,10 @@ class PokeBattle_AI # Don't need to check the Atk/Sp Atk-boosting badges because the AI # won't control the player's Pokémon. if target.pbOwnedByPlayer? - if move.physicalMove?(type) && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_DEFENSE - multipliers[DEF_MULT] *= 1.1 - elsif move.specialMove?(type) && @battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_SPDEF - multipliers[DEF_MULT] *= 1.1 + if move.physicalMove?(type) && @battle.pbPlayer.numbadges >= NUM_BADGES_BOOST_DEFENSE + multipliers[:defense_multiplier] *= 1.1 + elsif move.specialMove?(type) && @battle.pbPlayer.numbadges >= NUM_BADGES_BOOST_SPDEF + multipliers[:defense_multiplier] *= 1.1 end end end @@ -424,7 +429,7 @@ class PokeBattle_AI # Multi-targeting attacks if skill>=PBTrainerAI.highSkill if pbTargetsMultiple?(move,user) - multipliers[FINAL_DMG_MULT] *= 0.75 + multipliers[:final_damage_multiplier] *= 0.75 end end # Weather @@ -432,19 +437,19 @@ class PokeBattle_AI case @battle.pbWeather when PBWeather::Sun, PBWeather::HarshSun if type == :FIRE - multipliers[FINAL_DMG_MULT] *= 1.5 + multipliers[:final_damage_multiplier] *= 1.5 elsif type == :WATER - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 end when PBWeather::Rain, PBWeather::HeavyRain if type == :FIRE - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 elsif type == :WATER - multipliers[FINAL_DMG_MULT] *= 1.5 + multipliers[:final_damage_multiplier] *= 1.5 end when PBWeather::Sandstorm - if target.pbHasType?(:ROCK) && move.specialMove?(type) && move.function!="122" # Psyshock - multipliers[DEF_MULT] *= 1.5 + if target.pbHasType?(:ROCK) && move.specialMove?(type) && move.function != "122" # Psyshock + multipliers[:defense_multiplier] *= 1.5 end end end @@ -454,45 +459,45 @@ class PokeBattle_AI if skill>=PBTrainerAI.mediumSkill if type && user.pbHasType?(type) if user.hasActiveAbility?(:ADAPTABILITY) - multipliers[FINAL_DMG_MULT] *= 2 + multipliers[:final_damage_multiplier] *= 2 else - multipliers[FINAL_DMG_MULT] *= 1.5 + multipliers[:final_damage_multiplier] *= 1.5 end end end # Type effectiveness if skill>=PBTrainerAI.mediumSkill typemod = pbCalcTypeMod(type,user,target) - multipliers[FINAL_DMG_MULT] *= typemod.to_f/PBTypeEffectiveness::NORMAL_EFFECTIVE + multipliers[:final_damage_multiplier] *= typemod.to_f / PBTypeEffectiveness::NORMAL_EFFECTIVE end # Burn if skill>=PBTrainerAI.highSkill if user.status==PBStatuses::BURN && move.physicalMove?(type) && !user.hasActiveAbility?(:GUTS) && !(MECHANICS_GENERATION >= 6 && move.function == "07E") # Facade - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 end end # Aurora Veil, Reflect, Light Screen if skill>=PBTrainerAI.highSkill if !move.ignoresReflect? && !user.hasActiveAbility?(:INFILTRATOR) - if target.pbOwnSide.effects[PBEffects::AuroraVeil]>0 - if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] *= 2/3.0 + if target.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 + if @battle.pbSideBattlerCount(target) > 1 + multipliers[:final_damage_multiplier] *= 2 / 3.0 else - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 end - elsif target.pbOwnSide.effects[PBEffects::Reflect]>0 && move.physicalMove?(type) - if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] *= 2/3.0 + elsif target.pbOwnSide.effects[PBEffects::Reflect] > 0 && move.physicalMove?(type) + if @battle.pbSideBattlerCount(target) > 1 + multipliers[:final_damage_multiplier] *= 2 / 3.0 else - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 end - elsif target.pbOwnSide.effects[PBEffects::LightScreen]>0 && move.specialMove?(type) - if @battle.pbSideBattlerCount(target)>1 - multipliers[FINAL_DMG_MULT] *= 2/3.0 + elsif target.pbOwnSide.effects[PBEffects::LightScreen] > 0 && move.specialMove?(type) + if @battle.pbSideBattlerCount(target) > 1 + multipliers[:final_damage_multiplier] *= 2 / 3.0 else - multipliers[FINAL_DMG_MULT] /= 2 + multipliers[:final_damage_multiplier] /= 2 end end end @@ -500,7 +505,7 @@ class PokeBattle_AI # Minimize if skill>=PBTrainerAI.highSkill if target.effects[PBEffects::Minimize] && move.tramplesMinimize?(2) - multipliers[FINAL_DMG_MULT] *= 2 + multipliers[:final_damage_multiplier] *= 2 end end # Move-specific base damage modifiers @@ -508,11 +513,11 @@ class PokeBattle_AI # Move-specific final damage modifiers # TODO ##### Main damage calculation ##### - baseDmg = [(baseDmg * multipliers[BASE_DMG_MULT]).round, 1].max - atk = [(atk * multipliers[ATK_MULT]).round, 1].max - defense = [(defense * multipliers[DEF_MULT]).round, 1].max + baseDmg = [(baseDmg * multipliers[:base_damage_multiplier]).round, 1].max + atk = [(atk * multipliers[:attack_multiplier]).round, 1].max + defense = [(defense * multipliers[:defense_multiplier]).round, 1].max damage = (((2.0 * user.level / 5 + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2 - damage = [(damage * multipliers[FINAL_DMG_MULT]).round, 1].max + damage = [(damage * multipliers[:final_damage_multiplier]).round, 1].max # "AI-specific calculations below" # Increased critical hit rates if skill>=PBTrainerAI.mediumSkill @@ -567,26 +572,26 @@ class PokeBattle_AI # Get the move's type type = pbRoughType(move,user,skill) # Calculate all modifier effects - modifiers = [] - modifiers[BASE_ACC] = baseAcc - modifiers[ACC_STAGE] = user.stages[PBStats::ACCURACY] - modifiers[EVA_STAGE] = target.stages[PBStats::EVASION] - modifiers[ACC_MULT] = 1.0 - modifiers[EVA_MULT] = 1.0 + modifiers = {} + modifiers[:base_accuracy] = baseAcc + modifiers[:accuracy_stage] = user.stages[PBStats::ACCURACY] + modifiers[:evasion_stage] = target.stages[PBStats::EVASION] + modifiers[:accuracy_multiplier] = 1.0 + modifiers[:evasion_multiplier] = 1.0 pbCalcAccuracyModifiers(user,target,modifiers,move,type,skill) # Check if move can't miss - return 125 if modifiers[BASE_ACC]==0 + return 125 if modifiers[:base_accuracy]==0 # Calculation - accStage = [[modifiers[ACC_STAGE],-6].max,6].min + 6 - evaStage = [[modifiers[EVA_STAGE],-6].max,6].min + 6 + accStage = [[modifiers[:accuracy_stage], -6].max, 6].min + 6 + evaStage = [[modifiers[:evasion_stage], -6].max, 6].min + 6 stageMul = [3,3,3,3,3,3, 3, 4,5,6,7,8,9] stageDiv = [9,8,7,6,5,4, 3, 3,3,3,3,3,3] accuracy = 100.0 * stageMul[accStage] / stageDiv[accStage] evasion = 100.0 * stageMul[evaStage] / stageDiv[evaStage] - accuracy = (accuracy * modifiers[ACC_MULT]).round - evasion = (evasion * modifiers[EVA_MULT]).round + accuracy = (accuracy * modifiers[:accuracy_multiplier]).round + evasion = (evasion * modifiers[:evasion_multiplier]).round evasion = 1 if evasion<1 - return modifiers[BASE_ACC] * accuracy / evasion + return modifiers[:base_accuracy] * accuracy / evasion end def pbCalcAccuracyModifiers(user,target,modifiers,move,type,skill) @@ -625,35 +630,35 @@ class PokeBattle_AI modifiers,user,target,move,type) end end - # Other effects, inc. ones that set ACC_MULT or EVA_STAGE to specific values + # Other effects, inc. ones that set accuracy_multiplier or evasion_stage to specific values if skill>=PBTrainerAI.mediumSkill - if @battle.field.effects[PBEffects::Gravity]>0 - modifiers[ACC_MULT] *= 5/3.0 + if @battle.field.effects[PBEffects::Gravity] > 0 + modifiers[:accuracy_multiplier] *= 5/3.0 end if user.effects[PBEffects::MicleBerry] - modifiers[ACC_MULT] *= 1.2 + modifiers[:accuracy_multiplier] *= 1.2 end - modifiers[EVA_STAGE] = 0 if target.effects[PBEffects::Foresight] && modifiers[EVA_STAGE]>0 - modifiers[EVA_STAGE] = 0 if target.effects[PBEffects::MiracleEye] && modifiers[EVA_STAGE]>0 + modifiers[:evasion_stage] = 0 if target.effects[PBEffects::Foresight] && modifiers[:evasion_stage] > 0 + modifiers[:evasion_stage] = 0 if target.effects[PBEffects::MiracleEye] && modifiers[:evasion_stage] > 0 end # "AI-specific calculations below" if skill>=PBTrainerAI.mediumSkill - modifiers[EVA_STAGE] = 0 if move.function=="0A9" # Chip Away - modifiers[BASE_ACC] = 0 if ["0A5","139","13A","13B","13C", # "Always hit" - "147"].include?(move.function) - modifiers[BASE_ACC] = 0 if user.effects[PBEffects::LockOn]>0 && - user.effects[PBEffects::LockOnPos]==target.index + modifiers[:evasion_stage] = 0 if move.function == "0A9" # Chip Away + modifiers[:base_accuracy] = 0 if ["0A5", "139", "13A", "13B", "13C", # "Always hit" + "147"].include?(move.function) + modifiers[:base_accuracy] = 0 if user.effects[PBEffects::LockOn]>0 && + user.effects[PBEffects::LockOnPos]==target.index end if skill>=PBTrainerAI.highSkill if move.function=="006" # Toxic - modifiers[BASE_ACC] = 0 if MORE_TYPE_EFFECTS && move.statusMove? && - user.pbHasType?(:POISON) + modifiers[:base_accuracy] = 0 if MORE_TYPE_EFFECTS && move.statusMove? && + user.pbHasType?(:POISON) end if move.function=="070" # OHKO moves - modifiers[BASE_ACC] = move.accuracy+user.level-target.level - modifiers[ACC_MULT] = 0 if target.level>user.level + modifiers[:base_accuracy] = move.accuracy + user.level - target.level + modifiers[:accuracy_multiplier] = 0 if target.level > user.level if skill>=PBTrainerAI.bestSkill - modifiers[ACC_MULT] = 0 if target.hasActiveAbility?(:STURDY) + modifiers[:accuracy_multiplier] = 0 if target.hasActiveAbility?(:STURDY) end end end diff --git a/Data/Scripts/012_Battle/006_BattleHandlers.rb b/Data/Scripts/012_Battle/006_BattleHandlers.rb index 3db630399..06ff07aa1 100644 --- a/Data/Scripts/012_Battle/006_BattleHandlers.rb +++ b/Data/Scripts/012_Battle/006_BattleHandlers.rb @@ -478,17 +478,6 @@ end -BASE_ACC = 0 -ACC_STAGE = 1 -EVA_STAGE = 2 -ACC_MULT = 3 -EVA_MULT = 4 - -BASE_DMG_MULT = 0 -ATK_MULT = 1 -DEF_MULT = 2 -FINAL_DMG_MULT = 3 - def pbBattleConfusionBerry(battler,battle,item,forced,flavor,confuseMsg) return false if !forced && !battler.canHeal? return false if !forced && !battler.canConsumePinchBerry?(MECHANICS_GENERATION >= 7) @@ -582,16 +571,16 @@ def pbBattleGem(user,type,move,mults,moveType) return if moveType != type user.effects[PBEffects::GemConsumed] = user.item_id if MECHANICS_GENERATION >= 6 - mults[BASE_DMG_MULT] *= 1.3 + mults[:base_damage_multiplier] *= 1.3 else - mults[BASE_DMG_MULT] *= 1.5 + mults[:base_damage_multiplier] *= 1.5 end end def pbBattleTypeWeakingBerry(type,moveType,target,mults) return if moveType != type return if PBTypeEffectiveness.resistant?(target.damageState.typeMod) && moveType != :NORMAL - mults[FINAL_DMG_MULT] /= 2 + mults[:final_damage_multiplier] /= 2 target.damageState.berryWeakened = true target.battle.pbCommonAnimation("EatBerry",target) end diff --git a/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb b/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb index 2248586ac..0f8f8e6c7 100644 --- a/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb +++ b/Data/Scripts/012_Battle/007_BattleHandlers_Abilities.rb @@ -768,37 +768,37 @@ BattleHandlers::MoveBaseTypeModifierAbility.add(:REFRIGERATE, BattleHandlers::AccuracyCalcUserAbility.add(:COMPOUNDEYES, proc { |ability,mods,user,target,move,type| - mods[ACC_MULT] *= 1.3 + mods[:accuracy_multiplier] *= 1.3 } ) BattleHandlers::AccuracyCalcUserAbility.add(:HUSTLE, proc { |ability,mods,user,target,move,type| - mods[ACC_MULT] *= 0.8 if move.physicalMove? + mods[:accuracy_multiplier] *= 0.8 if move.physicalMove? } ) BattleHandlers::AccuracyCalcUserAbility.add(:KEENEYE, proc { |ability,mods,user,target,move,type| - mods[EVA_STAGE] = 0 if mods[EVA_STAGE]>0 && MECHANICS_GENERATION >= 6 + mods[:evasion_stage] = 0 if mods[:evasion_stage] > 0 && MECHANICS_GENERATION >= 6 } ) BattleHandlers::AccuracyCalcUserAbility.add(:NOGUARD, proc { |ability,mods,user,target,move,type| - mods[BASE_ACC] = 0 + mods[:base_accuracy] = 0 } ) BattleHandlers::AccuracyCalcUserAbility.add(:UNAWARE, proc { |ability,mods,user,target,move,type| - mods[EVA_STAGE] = 0 if move.damagingMove? + mods[:evasion_stage] = 0 if move.damagingMove? } ) BattleHandlers::AccuracyCalcUserAbility.add(:VICTORYSTAR, proc { |ability,mods,user,target,move,type| - mods[ACC_MULT] *= 1.1 + mods[:accuracy_multiplier] *= 1.1 } ) @@ -808,7 +808,7 @@ BattleHandlers::AccuracyCalcUserAbility.add(:VICTORYSTAR, BattleHandlers::AccuracyCalcUserAllyAbility.add(:VICTORYSTAR, proc { |ability,mods,user,target,move,type| - mods[ACC_MULT] *= 1.1 + mods[:accuracy_multiplier] *= 1.1 } ) @@ -818,20 +818,20 @@ BattleHandlers::AccuracyCalcUserAllyAbility.add(:VICTORYSTAR, BattleHandlers::AccuracyCalcTargetAbility.add(:LIGHTNINGROD, proc { |ability,mods,user,target,move,type| - mods[BASE_ACC] = 0 if type == :ELECTRIC + mods[:base_accuracy] = 0 if type == :ELECTRIC } ) BattleHandlers::AccuracyCalcTargetAbility.add(:NOGUARD, proc { |ability,mods,user,target,move,type| - mods[BASE_ACC] = 0 + mods[:base_accuracy] = 0 } ) BattleHandlers::AccuracyCalcTargetAbility.add(:SANDVEIL, proc { |ability,mods,user,target,move,type| if target.battle.pbWeather==PBWeather::Sandstorm - mods[EVA_MULT] *= 1.25 + mods[:evasion_multiplier] *= 1.25 end } ) @@ -839,33 +839,33 @@ BattleHandlers::AccuracyCalcTargetAbility.add(:SANDVEIL, BattleHandlers::AccuracyCalcTargetAbility.add(:SNOWCLOAK, proc { |ability,mods,user,target,move,type| if target.battle.pbWeather==PBWeather::Hail - mods[EVA_MULT] *= 1.25 + mods[:evasion_multiplier] *= 1.25 end } ) BattleHandlers::AccuracyCalcTargetAbility.add(:STORMDRAIN, proc { |ability,mods,user,target,move,type| - mods[BASE_ACC] = 0 if type == :WATER + mods[:base_accuracy] = 0 if type == :WATER } ) BattleHandlers::AccuracyCalcTargetAbility.add(:TANGLEDFEET, proc { |ability,mods,user,target,move,type| - mods[ACC_MULT] /= 2 if target.effects[PBEffects::Confusion]>0 + mods[:accuracy_multiplier] /= 2 if target.effects[PBEffects::Confusion] > 0 } ) BattleHandlers::AccuracyCalcTargetAbility.add(:UNAWARE, proc { |ability,mods,user,target,move,type| - mods[ACC_STAGE] = 0 if move.damagingMove? + mods[:accuracy_stage] = 0 if move.damagingMove? } ) BattleHandlers::AccuracyCalcTargetAbility.add(:WONDERSKIN, proc { |ability,mods,user,target,move,type| if move.statusMove? && user.opposes?(target) - mods[BASE_ACC] = 0 if mods[BASE_ACC]>50 + mods[:base_accuracy] = 0 if mods[:base_accuracy] > 50 end } ) @@ -876,7 +876,7 @@ BattleHandlers::AccuracyCalcTargetAbility.add(:WONDERSKIN, BattleHandlers::DamageCalcUserAbility.add(:AERILATE, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if move.powerBoost + mults[:base_damage_multiplier] *= 1.2 if move.powerBoost } ) @@ -887,29 +887,29 @@ BattleHandlers::DamageCalcUserAbility.add(:ANALYTIC, if (target.battle.choices[target.index][0]!=:UseMove && target.battle.choices[target.index][0]!=:Shift) || target.movedThisRound? - mults[BASE_DMG_MULT] *= 1.3 + mults[:base_damage_multiplier] *= 1.3 end } ) BattleHandlers::DamageCalcUserAbility.add(:BLAZE, proc { |ability,user,target,move,mults,baseDmg,type| - if user.hp<=user.totalhp/3 && type == :FIRE - mults[ATK_MULT] *= 1.5 + if user.hp <= user.totalhp / 3 && type == :FIRE + mults[:attack_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:DEFEATIST, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] /= 2 if user.hp<=user.totalhp/2 + mults[:attack_multiplier] /= 2 if user.hp <= user.totalhp / 2 } ) BattleHandlers::DamageCalcUserAbility.add(:FLAREBOOST, proc { |ability,user,target,move,mults,baseDmg,type| if user.burned? && move.specialMove? - mults[BASE_DMG_MULT] *= 1.5 + mults[:base_damage_multiplier] *= 1.5 end } ) @@ -917,7 +917,7 @@ BattleHandlers::DamageCalcUserAbility.add(:FLAREBOOST, BattleHandlers::DamageCalcUserAbility.add(:FLASHFIRE, proc { |ability,user,target,move,mults,baseDmg,type| if user.effects[PBEffects::FlashFire] && type == :FIRE - mults[ATK_MULT] *= 1.5 + mults[:attack_multiplier] *= 1.5 end } ) @@ -926,7 +926,7 @@ BattleHandlers::DamageCalcUserAbility.add(:FLOWERGIFT, proc { |ability,user,target,move,mults,baseDmg,type| w = user.battle.pbWeather if move.physicalMove? && (w==PBWeather::Sun || w==PBWeather::HarshSun) - mults[ATK_MULT] *= 1.5 + mults[:attack_multiplier] *= 1.5 end } ) @@ -934,14 +934,14 @@ BattleHandlers::DamageCalcUserAbility.add(:FLOWERGIFT, BattleHandlers::DamageCalcUserAbility.add(:GUTS, proc { |ability,user,target,move,mults,baseDmg,type| if user.pbHasAnyStatus? && move.physicalMove? - mults[ATK_MULT] *= 1.5 + mults[:attack_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:HUGEPOWER, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] *= 2 if move.physicalMove? + mults[:attack_multiplier] *= 2 if move.physicalMove? } ) @@ -949,19 +949,19 @@ BattleHandlers::DamageCalcUserAbility.copy(:HUGEPOWER,:PUREPOWER) BattleHandlers::DamageCalcUserAbility.add(:HUSTLE, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] *= 1.5 if move.physicalMove? + mults[:attack_multiplier] *= 1.5 if move.physicalMove? } ) BattleHandlers::DamageCalcUserAbility.add(:IRONFIST, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if move.punchingMove? + mults[:base_damage_multiplier] *= 1.2 if move.punchingMove? } ) BattleHandlers::DamageCalcUserAbility.add(:MEGALAUNCHER, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.5 if move.pulseMove? + mults[:base_damage_multiplier] *= 1.5 if move.pulseMove? } ) @@ -969,8 +969,8 @@ BattleHandlers::DamageCalcUserAbility.add(:MINUS, proc { |ability,user,target,move,mults,baseDmg,type| next if !move.specialMove? user.eachAlly do |b| - next if !b.hasActiveAbility?([:MINUS,:PLUS]) - mults[ATK_MULT] *= 1.5 + next if !b.hasActiveAbility?([:MINUS, :PLUS]) + mults[:attack_multiplier] *= 1.5 break end } @@ -981,22 +981,22 @@ BattleHandlers::DamageCalcUserAbility.copy(:MINUS,:PLUS) BattleHandlers::DamageCalcUserAbility.add(:NEUROFORCE, proc { |ability,user,target,move,mults,baseDmg,type| if PBTypeEffectiveness.superEffective?(target.damageState.typeMod) - mults[FINAL_DMG_MULT] *= 1.25 + mults[:final_damage_multiplier] *= 1.25 end } ) BattleHandlers::DamageCalcUserAbility.add(:OVERGROW, proc { |ability,user,target,move,mults,baseDmg,type| - if user.hp<=user.totalhp/3 && type == :GRASS - mults[ATK_MULT] *= 1.5 + if user.hp <= user.totalhp / 3 && type == :GRASS + mults[:attack_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:RECKLESS, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if move.recoilMove? + mults[:base_damage_multiplier] *= 1.2 if move.recoilMove? } ) @@ -1004,9 +1004,9 @@ BattleHandlers::DamageCalcUserAbility.add(:RIVALRY, proc { |ability,user,target,move,mults,baseDmg,type| if user.gender!=2 && target.gender!=2 if user.gender==target.gender - mults[BASE_DMG_MULT] *= 1.25 + mults[:base_damage_multiplier] *= 1.25 else - mults[BASE_DMG_MULT] *= 0.75 + mults[:base_damage_multiplier] *= 0.75 end end } @@ -1016,28 +1016,28 @@ BattleHandlers::DamageCalcUserAbility.add(:SANDFORCE, proc { |ability,user,target,move,mults,baseDmg,type| if user.battle.pbWeather==PBWeather::Sandstorm && [:ROCK, :GROUND, :STEEL].include?(type) - mults[BASE_DMG_MULT] *= 1.3 + mults[:base_damage_multiplier] *= 1.3 end } ) BattleHandlers::DamageCalcUserAbility.add(:SHEERFORCE, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.3 if move.addlEffect>0 + mults[:base_damage_multiplier] *= 1.3 if move.addlEffect > 0 } ) BattleHandlers::DamageCalcUserAbility.add(:SLOWSTART, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] /= 2 if user.effects[PBEffects::SlowStart]>0 && move.physicalMove? + mults[:attack_multiplier] /= 2 if user.effects[PBEffects::SlowStart] > 0 && move.physicalMove? } ) BattleHandlers::DamageCalcUserAbility.add(:SOLARPOWER, proc { |ability,user,target,move,mults,baseDmg,type| w = user.battle.pbWeather - if move.specialMove? && (w==PBWeather::Sun || w==PBWeather::HarshSun) - mults[ATK_MULT] *= 1.5 + if move.specialMove? && (w == PBWeather::Sun || w == PBWeather::HarshSun) + mults[:attack_multiplier] *= 1.5 end } ) @@ -1045,77 +1045,77 @@ BattleHandlers::DamageCalcUserAbility.add(:SOLARPOWER, BattleHandlers::DamageCalcUserAbility.add(:SNIPER, proc { |ability,user,target,move,mults,baseDmg,type| if target.damageState.critical - mults[FINAL_DMG_MULT] *= 1.5 + mults[:final_damage_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:STAKEOUT, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] *= 2 if target.battle.choices[target.index][0]==:SwitchOut + mults[:attack_multiplier] *= 2 if target.battle.choices[target.index][0] == :SwitchOut } ) BattleHandlers::DamageCalcUserAbility.add(:STEELWORKER, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] *= 1.5 if type == :STEEL + mults[:attack_multiplier] *= 1.5 if type == :STEEL } ) BattleHandlers::DamageCalcUserAbility.add(:STRONGJAW, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.5 if move.bitingMove? + mults[:base_damage_multiplier] *= 1.5 if move.bitingMove? } ) BattleHandlers::DamageCalcUserAbility.add(:SWARM, proc { |ability,user,target,move,mults,baseDmg,type| - if user.hp<=user.totalhp/3 && type == :BUG - mults[ATK_MULT] *= 1.5 + if user.hp <= user.totalhp / 3 && type == :BUG + mults[:attack_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:TECHNICIAN, proc { |ability,user,target,move,mults,baseDmg,type| - if user.index!=target.index && move && move.id != :STRUGGLE && - baseDmg*mults[BASE_DMG_MULT]<=60 - mults[BASE_DMG_MULT] *= 1.5 + if user.index != target.index && move && move.id != :STRUGGLE && + baseDmg * mults[:base_damage_multiplier] <= 60 + mults[:base_damage_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:TINTEDLENS, proc { |ability,user,target,move,mults,baseDmg,type| - mults[FINAL_DMG_MULT] *= 2 if PBTypeEffectiveness.resistant?(target.damageState.typeMod) + mults[:final_damage_multiplier] *= 2 if PBTypeEffectiveness.resistant?(target.damageState.typeMod) } ) BattleHandlers::DamageCalcUserAbility.add(:TORRENT, proc { |ability,user,target,move,mults,baseDmg,type| - if user.hp<=user.totalhp/3 && type == :WATER - mults[ATK_MULT] *= 1.5 + if user.hp <= user.totalhp / 3 && type == :WATER + mults[:attack_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:TOUGHCLAWS, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 4/3.0 if move.contactMove? + mults[:base_damage_multiplier] *= 4 / 3.0 if move.contactMove? } ) BattleHandlers::DamageCalcUserAbility.add(:TOXICBOOST, proc { |ability,user,target,move,mults,baseDmg,type| if user.poisoned? && move.physicalMove? - mults[BASE_DMG_MULT] *= 1.5 + mults[:base_damage_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcUserAbility.add(:WATERBUBBLE, proc { |ability,user,target,move,mults,baseDmg,type| - mults[ATK_MULT] *= 2 if type == :WATER + mults[:attack_multiplier] *= 2 if type == :WATER } ) @@ -1126,15 +1126,15 @@ BattleHandlers::DamageCalcUserAbility.add(:WATERBUBBLE, BattleHandlers::DamageCalcUserAllyAbility.add(:BATTERY, proc { |ability,user,target,move,mults,baseDmg,type| next if !move.specialMove? - mults[FINAL_DMG_MULT] *= 1.3 + mults[:final_damage_multiplier] *= 1.3 } ) BattleHandlers::DamageCalcUserAllyAbility.add(:FLOWERGIFT, proc { |ability,user,target,move,mults,baseDmg,type| w = user.battle.pbWeather - if move.physicalMove? && (w==PBWeather::Sun || w==PBWeather::HarshSun) - mults[ATK_MULT] *= 1.5 + if move.physicalMove? && (w == PBWeather::Sun || w == PBWeather::HarshSun) + mults[:attack_multiplier] *= 1.5 end } ) @@ -1145,14 +1145,14 @@ BattleHandlers::DamageCalcUserAllyAbility.add(:FLOWERGIFT, BattleHandlers::DamageCalcTargetAbility.add(:DRYSKIN, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.25 if type == :FIRE + mults[:base_damage_multiplier] *= 1.25 if type == :FIRE } ) BattleHandlers::DamageCalcTargetAbility.add(:FILTER, proc { |ability,user,target,move,mults,baseDmg,type| if PBTypeEffectiveness.superEffective?(target.damageState.typeMod) - mults[FINAL_DMG_MULT] *= 0.75 + mults[:final_damage_multiplier] *= 0.75 end } ) @@ -1162,62 +1162,62 @@ BattleHandlers::DamageCalcTargetAbility.copy(:FILTER,:SOLIDROCK) BattleHandlers::DamageCalcTargetAbility.add(:FLOWERGIFT, proc { |ability,user,target,move,mults,baseDmg,type| w = user.battle.pbWeather - if move.specialMove? && (w==PBWeather::Sun || w==PBWeather::HarshSun) - mults[DEF_MULT] *= 1.5 + if move.specialMove? && (w == PBWeather::Sun || w == PBWeather::HarshSun) + mults[:defense_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcTargetAbility.add(:FLUFFY, proc { |ability,user,target,move,mults,baseDmg,type| - mults[FINAL_DMG_MULT] *= 2 if move.calcType == :FIRE - mults[FINAL_DMG_MULT] /= 2 if move.contactMove? + mults[:final_damage_multiplier] *= 2 if move.calcType == :FIRE + mults[:final_damage_multiplier] /= 2 if move.contactMove? } ) BattleHandlers::DamageCalcTargetAbility.add(:FURCOAT, proc { |ability,user,target,move,mults,baseDmg,type| - mults[DEF_MULT] *= 2 if move.physicalMove? || move.function=="122" # Psyshock + mults[:defense_multiplier] *= 2 if move.physicalMove? || move.function == "122" # Psyshock } ) BattleHandlers::DamageCalcTargetAbility.add(:GRASSPELT, proc { |ability,user,target,move,mults,baseDmg,type| - if user.battle.field.terrain==PBBattleTerrains::Grassy - mults[DEF_MULT] *= 1.5 + if user.battle.field.terrain == PBBattleTerrains::Grassy + mults[:defense_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcTargetAbility.add(:HEATPROOF, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] /= 2 if type == :FIRE + mults[:base_damage_multiplier] /= 2 if type == :FIRE } ) BattleHandlers::DamageCalcTargetAbility.add(:MARVELSCALE, proc { |ability,user,target,move,mults,baseDmg,type| if target.pbHasAnyStatus? && move.physicalMove? - mults[DEF_MULT] *= 1.5 + mults[:defense_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcTargetAbility.add(:MULTISCALE, proc { |ability,user,target,move,mults,baseDmg,type| - mults[FINAL_DMG_MULT] /= 2 if target.hp==target.totalhp + mults[:final_damage_multiplier] /= 2 if target.hp == target.totalhp } ) BattleHandlers::DamageCalcTargetAbility.add(:THICKFAT, proc { |ability,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] /= 2 if type == :FIRE || type == :ICE + mults[:base_damage_multiplier] /= 2 if type == :FIRE || type == :ICE } ) BattleHandlers::DamageCalcTargetAbility.add(:WATERBUBBLE, proc { |ability,user,target,move,mults,baseDmg,type| - mults[FINAL_DMG_MULT] /= 2 if type == :FIRE + mults[:final_damage_multiplier] /= 2 if type == :FIRE } ) @@ -1228,7 +1228,7 @@ BattleHandlers::DamageCalcTargetAbility.add(:WATERBUBBLE, BattleHandlers::DamageCalcTargetAbilityNonIgnorable.add(:PRISMARMOR, proc { |ability,user,target,move,mults,baseDmg,type| if PBTypeEffectiveness.superEffective?(target.damageState.typeMod) - mults[FINAL_DMG_MULT] *= 0.75 + mults[:final_damage_multiplier] *= 0.75 end } ) @@ -1236,7 +1236,7 @@ BattleHandlers::DamageCalcTargetAbilityNonIgnorable.add(:PRISMARMOR, BattleHandlers::DamageCalcTargetAbilityNonIgnorable.add(:SHADOWSHIELD, proc { |ability,user,target,move,mults,baseDmg,type| if target.hp==target.totalhp - mults[FINAL_DMG_MULT] /= 2 + mults[:final_damage_multiplier] /= 2 end } ) @@ -1248,15 +1248,15 @@ BattleHandlers::DamageCalcTargetAbilityNonIgnorable.add(:SHADOWSHIELD, BattleHandlers::DamageCalcTargetAllyAbility.add(:FLOWERGIFT, proc { |ability,user,target,move,mults,baseDmg,type| w = user.battle.pbWeather - if move.specialMove? && (w==PBWeather::Sun || w==PBWeather::HarshSun) - mults[DEF_MULT] *= 1.5 + if move.specialMove? && (w == PBWeather::Sun || w == PBWeather::HarshSun) + mults[:defense_multiplier] *= 1.5 end } ) BattleHandlers::DamageCalcTargetAllyAbility.add(:FRIENDGUARD, proc { |ability,user,target,move,mults,baseDmg,type| - mults[FINAL_DMG_MULT] *= 0.75 + mults[:final_damage_multiplier] *= 0.75 } ) diff --git a/Data/Scripts/012_Battle/008_BattleHandlers_Items.rb b/Data/Scripts/012_Battle/008_BattleHandlers_Items.rb index 20c3a6b3a..e448bca13 100644 --- a/Data/Scripts/012_Battle/008_BattleHandlers_Items.rb +++ b/Data/Scripts/012_Battle/008_BattleHandlers_Items.rb @@ -412,7 +412,7 @@ BattleHandlers::PriorityBracketUseItem.add(:QUICKCLAW, BattleHandlers::AccuracyCalcUserItem.add(:WIDELENS, proc { |item,mods,user,target,move,type| - mods[ACC_MULT] *= 1.1 + mods[:accuracy_multiplier] *= 1.1 } ) @@ -421,7 +421,7 @@ BattleHandlers::AccuracyCalcUserItem.add(:ZOOMLENS, if (target.battle.choices[target.index][0]!=:UseMove && target.battle.choices[target.index][0]!=:Shift) || target.movedThisRound? - mods[ACC_MULT] *= 1.2 + mods[:accuracy_multiplier] *= 1.2 end } ) @@ -432,7 +432,7 @@ BattleHandlers::AccuracyCalcUserItem.add(:ZOOMLENS, BattleHandlers::AccuracyCalcTargetItem.add(:BRIGHTPOWDER, proc { |item,mods,user,target,move,type| - mods[ACC_MULT] *= 0.9 + mods[:accuracy_multiplier] *= 0.9 } ) @@ -445,14 +445,14 @@ BattleHandlers::AccuracyCalcTargetItem.copy(:BRIGHTPOWDER,:LAXINCENSE) BattleHandlers::DamageCalcUserItem.add(:ADAMANTORB, proc { |item,user,target,move,mults,baseDmg,type| if user.isSpecies?(:DIALGA) && (type == :DRAGON || type == :STEEL) - mults[BASE_DMG_MULT] *= 1.2 + mults[:base_damage_multiplier] *= 1.2 end } ) BattleHandlers::DamageCalcUserItem.add(:BLACKBELT, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :FIGHTING + mults[:base_damage_multiplier] *= 1.2 if type == :FIGHTING } ) @@ -460,7 +460,7 @@ BattleHandlers::DamageCalcUserItem.copy(:BLACKBELT,:FISTPLATE) BattleHandlers::DamageCalcUserItem.add(:BLACKGLASSES, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :DARK + mults[:base_damage_multiplier] *= 1.2 if type == :DARK } ) @@ -474,7 +474,7 @@ BattleHandlers::DamageCalcUserItem.add(:BUGGEM, BattleHandlers::DamageCalcUserItem.add(:CHARCOAL, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :FIRE + mults[:base_damage_multiplier] *= 1.2 if type == :FIRE } ) @@ -482,13 +482,13 @@ BattleHandlers::DamageCalcUserItem.copy(:CHARCOAL,:FLAMEPLATE) BattleHandlers::DamageCalcUserItem.add(:CHOICEBAND, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.5 if move.physicalMove? + mults[:base_damage_multiplier] *= 1.5 if move.physicalMove? } ) BattleHandlers::DamageCalcUserItem.add(:CHOICESPECS, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.5 if move.specialMove? + mults[:base_damage_multiplier] *= 1.5 if move.specialMove? } ) @@ -501,14 +501,14 @@ BattleHandlers::DamageCalcUserItem.add(:DARKGEM, BattleHandlers::DamageCalcUserItem.add(:DEEPSEATOOTH, proc { |item,user,target,move,mults,baseDmg,type| if user.isSpecies?(:CLAMPERL) && move.specialMove? - mults[ATK_MULT] *= 2 + mults[:attack_multiplier] *= 2 end } ) BattleHandlers::DamageCalcUserItem.add(:DRAGONFANG, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :DRAGON + mults[:base_damage_multiplier] *= 1.2 if type == :DRAGON } ) @@ -529,7 +529,7 @@ BattleHandlers::DamageCalcUserItem.add(:ELECTRICGEM, BattleHandlers::DamageCalcUserItem.add(:EXPERTBELT, proc { |item,user,target,move,mults,baseDmg,type| if PBTypeEffectiveness.superEffective?(target.damageState.typeMod) - mults[FINAL_DMG_MULT] *= 1.2 + mults[:final_damage_multiplier] *= 1.2 end } ) @@ -573,7 +573,7 @@ BattleHandlers::DamageCalcUserItem.add(:GRASSGEM, BattleHandlers::DamageCalcUserItem.add(:GRISEOUSORB, proc { |item,user,target,move,mults,baseDmg,type| if user.isSpecies?(:GIRATINA) && (type == :DRAGON || type == :GHOST) - mults[BASE_DMG_MULT] *= 1.2 + mults[:base_damage_multiplier] *= 1.2 end } ) @@ -586,7 +586,7 @@ BattleHandlers::DamageCalcUserItem.add(:GROUNDGEM, BattleHandlers::DamageCalcUserItem.add(:HARDSTONE, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :ROCK + mults[:base_damage_multiplier] *= 1.2 if type == :ROCK } ) @@ -601,7 +601,7 @@ BattleHandlers::DamageCalcUserItem.add(:ICEGEM, BattleHandlers::DamageCalcUserItem.add(:LIFEORB, proc { |item,user,target,move,mults,baseDmg,type| if !move.is_a?(PokeBattle_Confusion) - mults[FINAL_DMG_MULT] *= 1.3 + mults[:final_damage_multiplier] *= 1.3 end } ) @@ -609,7 +609,7 @@ BattleHandlers::DamageCalcUserItem.add(:LIFEORB, BattleHandlers::DamageCalcUserItem.add(:LIGHTBALL, proc { |item,user,target,move,mults,baseDmg,type| if user.isSpecies?(:PIKACHU) - mults[ATK_MULT] *= 2 + mults[:attack_multiplier] *= 2 end } ) @@ -617,14 +617,14 @@ BattleHandlers::DamageCalcUserItem.add(:LIGHTBALL, BattleHandlers::DamageCalcUserItem.add(:LUSTROUSORB, proc { |item,user,target,move,mults,baseDmg,type| if user.isSpecies?(:PALKIA) && (type == :DRAGON || type == :WATER) - mults[BASE_DMG_MULT] *= 1.2 + mults[:base_damage_multiplier] *= 1.2 end } ) BattleHandlers::DamageCalcUserItem.add(:MAGNET, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :ELECTRIC + mults[:base_damage_multiplier] *= 1.2 if type == :ELECTRIC } ) @@ -632,7 +632,7 @@ BattleHandlers::DamageCalcUserItem.copy(:MAGNET,:ZAPPLATE) BattleHandlers::DamageCalcUserItem.add(:METALCOAT, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :STEEL + mults[:base_damage_multiplier] *= 1.2 if type == :STEEL } ) @@ -640,14 +640,14 @@ BattleHandlers::DamageCalcUserItem.copy(:METALCOAT,:IRONPLATE) BattleHandlers::DamageCalcUserItem.add(:METRONOME, proc { |item,user,target,move,mults,baseDmg,type| - met = 1+0.2*[user.effects[PBEffects::Metronome],5].min - mults[FINAL_DMG_MULT] *= met + met = 1 + 0.2 * [user.effects[PBEffects::Metronome], 5].min + mults[:final_damage_multiplier] *= met } ) BattleHandlers::DamageCalcUserItem.add(:MIRACLESEED, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :GRASS + mults[:base_damage_multiplier] *= 1.2 if type == :GRASS } ) @@ -655,13 +655,13 @@ BattleHandlers::DamageCalcUserItem.copy(:MIRACLESEED,:MEADOWPLATE,:ROSEINCENSE) BattleHandlers::DamageCalcUserItem.add(:MUSCLEBAND, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.1 if move.physicalMove? + mults[:base_damage_multiplier] *= 1.1 if move.physicalMove? } ) BattleHandlers::DamageCalcUserItem.add(:MYSTICWATER, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :WATER + mults[:base_damage_multiplier] *= 1.2 if type == :WATER } ) @@ -669,7 +669,7 @@ BattleHandlers::DamageCalcUserItem.copy(:MYSTICWATER,:SPLASHPLATE,:SEAINCENSE,:W BattleHandlers::DamageCalcUserItem.add(:NEVERMELTICE, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :ICE + mults[:base_damage_multiplier] *= 1.2 if type == :ICE } ) @@ -683,13 +683,13 @@ BattleHandlers::DamageCalcUserItem.add(:NORMALGEM, BattleHandlers::DamageCalcUserItem.add(:PIXIEPLATE, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :FAIRY + mults[:base_damage_multiplier] *= 1.2 if type == :FAIRY } ) BattleHandlers::DamageCalcUserItem.add(:POISONBARB, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :POISON + mults[:base_damage_multiplier] *= 1.2 if type == :POISON } ) @@ -715,7 +715,7 @@ BattleHandlers::DamageCalcUserItem.add(:ROCKGEM, BattleHandlers::DamageCalcUserItem.add(:SHARPBEAK, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :FLYING + mults[:base_damage_multiplier] *= 1.2 if type == :FLYING } ) @@ -723,13 +723,13 @@ BattleHandlers::DamageCalcUserItem.copy(:SHARPBEAK,:SKYPLATE) BattleHandlers::DamageCalcUserItem.add(:SILKSCARF, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :NORMAL + mults[:base_damage_multiplier] *= 1.2 if type == :NORMAL } ) BattleHandlers::DamageCalcUserItem.add(:SILVERPOWDER, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :BUG + mults[:base_damage_multiplier] *= 1.2 if type == :BUG } ) @@ -737,7 +737,7 @@ BattleHandlers::DamageCalcUserItem.copy(:SILVERPOWDER,:INSECTPLATE) BattleHandlers::DamageCalcUserItem.add(:SOFTSAND, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :GROUND + mults[:base_damage_multiplier] *= 1.2 if type == :GROUND } ) @@ -747,10 +747,10 @@ BattleHandlers::DamageCalcUserItem.add(:SOULDEW, proc { |item,user,target,move,mults,baseDmg,type| next if !user.isSpecies?(:LATIAS) && !user.isSpecies?(:LATIOS) if SOUL_DEW_POWERS_UP_TYPES - mults[FINAL_DMG_MULT] *= 1.2 if type == :PSYCHIC || type == :DRAGON + mults[:final_damage_multiplier] *= 1.2 if type == :PSYCHIC || type == :DRAGON else if move.specialMove? && !user.battle.rules["souldewclause"] - mults[ATK_MULT] *= 1.5 + mults[:attack_multiplier] *= 1.5 end end } @@ -758,7 +758,7 @@ BattleHandlers::DamageCalcUserItem.add(:SOULDEW, BattleHandlers::DamageCalcUserItem.add(:SPELLTAG, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :GHOST + mults[:base_damage_multiplier] *= 1.2 if type == :GHOST } ) @@ -773,14 +773,14 @@ BattleHandlers::DamageCalcUserItem.add(:STEELGEM, BattleHandlers::DamageCalcUserItem.add(:THICKCLUB, proc { |item,user,target,move,mults,baseDmg,type| if (user.isSpecies?(:CUBONE) || user.isSpecies?(:MAROWAK)) && move.physicalMove? - mults[ATK_MULT] *= 2 + mults[:attack_multiplier] *= 2 end } ) BattleHandlers::DamageCalcUserItem.add(:TWISTEDSPOON, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.2 if type == :PSYCHIC + mults[:base_damage_multiplier] *= 1.2 if type == :PSYCHIC } ) @@ -794,7 +794,7 @@ BattleHandlers::DamageCalcUserItem.add(:WATERGEM, BattleHandlers::DamageCalcUserItem.add(:WISEGLASSES, proc { |item,user,target,move,mults,baseDmg,type| - mults[BASE_DMG_MULT] *= 1.1 if move.specialMove? + mults[:base_damage_multiplier] *= 1.1 if move.specialMove? } ) @@ -807,7 +807,7 @@ BattleHandlers::DamageCalcUserItem.add(:WISEGLASSES, BattleHandlers::DamageCalcTargetItem.add(:ASSAULTVEST, proc { |item,user,target,move,mults,baseDmg,type| - mults[DEF_MULT] *= 1.5 if move.specialMove? + mults[:defense_multiplier] *= 1.5 if move.specialMove? } ) @@ -850,7 +850,7 @@ BattleHandlers::DamageCalcTargetItem.add(:COLBURBERRY, BattleHandlers::DamageCalcTargetItem.add(:DEEPSEASCALE, proc { |item,user,target,move,mults,baseDmg,type| if target.isSpecies?(:CLAMPERL) && move.specialMove? - mults[DEF_MULT] *= 2 + mults[:defense_multiplier] *= 2 end } ) @@ -863,7 +863,7 @@ BattleHandlers::DamageCalcTargetItem.add(:EVIOLITE, # affected by Eviolite. evos = target.pokemon.species_data.evolutions if evos.any? { |e| e[1] != PBEvolution::None && !e[3] } # Not a "None", not a prevolution - mults[DEF_MULT] *= 1.5 if evos && evos.length > 0 + mults[:defense_multiplier] *= 1.5 end } ) @@ -889,7 +889,7 @@ BattleHandlers::DamageCalcTargetItem.add(:KEBIABERRY, BattleHandlers::DamageCalcTargetItem.add(:METALPOWDER, proc { |item,user,target,move,mults,baseDmg,type| if target.isSpecies?(:DITTO) && !target.effects[PBEffects::Transform] - mults[DEF_MULT] *= 1.5 + mults[:defense_multiplier] *= 1.5 end } ) @@ -935,7 +935,7 @@ BattleHandlers::DamageCalcTargetItem.add(:SOULDEW, next if SOUL_DEW_POWERS_UP_TYPES next if !target.isSpecies?(:LATIAS) && !target.isSpecies?(:LATIOS) if move.specialMove? && !user.battle.rules["souldewclause"] - mults[DEF_MULT] *= 1.5 + mults[:defense_multiplier] *= 1.5 end } ) diff --git a/Data/Scripts/014_Trainers/002_PTrainer_NPCTrainers.rb b/Data/Scripts/014_Trainers/002_PTrainer_NPCTrainers.rb index d3e708f9d..0471698ad 100644 --- a/Data/Scripts/014_Trainers/002_PTrainer_NPCTrainers.rb +++ b/Data/Scripts/014_Trainers/002_PTrainer_NPCTrainers.rb @@ -130,8 +130,8 @@ def pbConvertTrainerData tr_type_names[t.id_number] = t.real_name end MessageTypes.setMessages(MessageTypes::TrainerTypes, tr_type_names) - pbSaveTrainerTypes - pbSaveTrainerBattles + Compiler.write_trainer_types + Compiler.write_trainers end def pbNewTrainer(tr_type, tr_name, tr_id, savechanges = true) diff --git a/Data/Scripts/016_Pokemon/001_Pokemon.rb b/Data/Scripts/016_Pokemon/001_Pokemon.rb index e6153be0b..bd3d225c4 100644 --- a/Data/Scripts/016_Pokemon/001_Pokemon.rb +++ b/Data/Scripts/016_Pokemon/001_Pokemon.rb @@ -406,7 +406,7 @@ class Pokemon return @moves.length end - # @param move [Integer, Symbol, String] ID of the move to check + # @param move_id [Integer, Symbol, String] ID of the move to check # @return [Boolean] whether the Pokémon knows the given move def hasMove?(move_id) move_data = GameData::Move.try_get(move_id) @@ -503,7 +503,7 @@ class Pokemon @firstmoves = [] end - # @param move [Integer, Symbol, String] ID of the move to check + # @param move_id [Integer, Symbol, String] ID of the move to check # @return [Boolean] whether the Pokémon is compatible with the given move def compatibleWithMove?(move_id) move_data = GameData::Move.try_get(move_id) @@ -821,7 +821,7 @@ class Pokemon calcStats end - # @param species [Integer, Symbol, String] id of the species to check for + # @param check_species [Integer, Symbol, String] id of the species to check for # @return [Boolean] whether this Pokémon is of the specified species def isSpecies?(check_species) return @species == check_species || @species == GameData::Species.get(check_species).species diff --git a/Data/Scripts/017_UI/009_PScreen_RegionMap.rb b/Data/Scripts/017_UI/009_PScreen_RegionMap.rb index b41d499c0..863729532 100644 --- a/Data/Scripts/017_UI/009_PScreen_RegionMap.rb +++ b/Data/Scripts/017_UI/009_PScreen_RegionMap.rb @@ -167,6 +167,7 @@ class PokemonRegionMap_Scene return true end + # TODO: Why is this PBS file writer here? def pbSaveMapData File.open("PBS/townmap.txt","wb") { |f| f.write(0xEF.chr) @@ -179,10 +180,11 @@ class PokemonRegionMap_Scene 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]))) + f.write(sprintf("Name = %s\r\nFilename = %s\r\n", + Compiler.csvQuote(map[0]), Compiler.csvQuote(map[1]))) for loc in map[2] - f.write("Point=") - pbWriteCsvRecord(loc,f,[nil,"uussUUUU"]) + f.write("Point = ") + Compiler.pbWriteCsvRecord(loc,f,[nil,"uussUUUU"]) f.write("\r\n") end end diff --git a/Data/Scripts/019_Other battles/005_PBattle_OrgBattleGenerator.rb b/Data/Scripts/019_Other battles/005_PBattle_OrgBattleGenerator.rb index b7e3fb1e0..46730afd2 100644 --- a/Data/Scripts/019_Other battles/005_PBattle_OrgBattleGenerator.rb +++ b/Data/Scripts/019_Other battles/005_PBattle_OrgBattleGenerator.rb @@ -1059,7 +1059,7 @@ def pbTrainerInfo(pokemonlist,trfile,rules) yield(nil) if block_given? save_data(trlists,"Data/trainer_lists.dat") yield(nil) if block_given? - pbSaveTrainerLists() + Compiler.write_trainer_lists yield(nil) if block_given? end @@ -1298,8 +1298,7 @@ def pbWriteCup(id,rules) trlists[cmd][2].push(id) if !trlists[cmd][5] save_data(trlists,"Data/trainer_lists.dat") Graphics.update - pbSaveTrainerLists - Graphics.update + Compiler.write_trainer_lists end return # Yes, use new diff --git a/Data/Scripts/020_System and utilities/001_PSystem_Controls.rb b/Data/Scripts/020_System and utilities/001_PSystem_Controls.rb index 75a8e1a7b..034ee375c 100644 --- a/Data/Scripts/020_System and utilities/001_PSystem_Controls.rb +++ b/Data/Scripts/020_System and utilities/001_PSystem_Controls.rb @@ -251,11 +251,6 @@ module Mouse @ReleaseCapture = Win32API.new('user32','ReleaseCapture','','i') module_function - def getMouseGlobalPos - pos = [0, 0].pack('ll') - return (@GetCursorPos.call(pos)!=0) ? pos.unpack('ll') : [nil,nil] - end - def screen_to_client(x, y) return nil unless x and y screenToClient = Win32API.new('user32','ScreenToClient',%w(l p),'i') @@ -264,12 +259,9 @@ module Mouse return nil end - def setCapture - @SetCapture.call(Win32API.pbFindRgssWindow) - end - - def releaseCapture - @ReleaseCapture.call + def getMouseGlobalPos + pos = [0, 0].pack('ll') + return (@GetCursorPos.call(pos)!=0) ? pos.unpack('ll') : [nil,nil] end # Returns the position of the mouse relative to the game window. @@ -283,6 +275,17 @@ module Mouse return nil end + # Unused + def setCapture + @SetCapture.call(Win32API.pbFindRgssWindow) + end + + # Unused + def releaseCapture + @ReleaseCapture.call + end + + # Unused def del return if @oldcursor==nil @SetClassLong.call(Win32API.pbFindRgssWindow,-12,@oldcursor) diff --git a/Data/Scripts/020_System and utilities/002_PSystem_System.rb b/Data/Scripts/020_System and utilities/002_PSystem_System.rb index 7ba70172a..7610465e3 100644 --- a/Data/Scripts/020_System and utilities/002_PSystem_System.rb +++ b/Data/Scripts/020_System and utilities/002_PSystem_System.rb @@ -63,16 +63,6 @@ def pbSetUpSystem pbSetResizeFactor([$PokemonSystem.screensize, 4].min) end # Load constants - begin - consts = pbSafeLoad("Data/Constants.rxdata") - consts = [] if !consts - rescue - consts = [] - end - for script in consts - next if !script - eval(Zlib::Inflate.inflate(script[2]),nil,script[1]) - end GameData.load_all if LANGUAGES.length>=2 pokemonSystem.language = pbChooseLanguage if !havedata 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 b52a3dfa6..225d66d86 100644 --- a/Data/Scripts/020_System and utilities/005_PSystem_Utilities.rb +++ b/Data/Scripts/020_System and utilities/005_PSystem_Utilities.rb @@ -235,6 +235,22 @@ def getID(mod,constant) return constant end +def getConstantName(mod,value) + mod = Object.const_get(mod) if mod.is_a?(Symbol) + for c in mod.constants + return c if mod.const_get(c.to_sym)==value + end + raise _INTL("Value {1} not defined by a constant in {2}",value,mod.name) +end + +def getConstantNameOrValue(mod,value) + mod = Object.const_get(mod) if mod.is_a?(Symbol) + for c in mod.constants + return c if mod.const_get(c.to_sym)==value + end + return value.inspect +end + #=============================================================================== diff --git a/Data/Scripts/021_Debug/001_Debug_Menus.rb b/Data/Scripts/021_Debug/001_Debug menus/001_Debug_Menus.rb similarity index 100% rename from Data/Scripts/021_Debug/001_Debug_Menus.rb rename to Data/Scripts/021_Debug/001_Debug menus/001_Debug_Menus.rb diff --git a/Data/Scripts/021_Debug/001b_Debug_MenuCommands.rb b/Data/Scripts/021_Debug/001_Debug menus/002_Debug_MenuCommands.rb similarity index 99% rename from Data/Scripts/021_Debug/001b_Debug_MenuCommands.rb rename to Data/Scripts/021_Debug/001_Debug menus/002_Debug_MenuCommands.rb index 4c93c92fe..9658ba945 100644 --- a/Data/Scripts/021_Debug/001b_Debug_MenuCommands.rb +++ b/Data/Scripts/021_Debug/001_Debug menus/002_Debug_MenuCommands.rb @@ -896,7 +896,7 @@ DebugMenuCommands.register("setencounters", { end save_data(encdata, "Data/encounters.dat") $PokemonTemp.encountersData = nil - pbSaveEncounterData # Rewrite PBS file encounters.txt + Compiler.write_encounters # Rewrite PBS file encounters.txt } }) diff --git a/Data/Scripts/021_Debug/002_Debug_MenuExtraCode.rb b/Data/Scripts/021_Debug/001_Debug menus/003_Debug_MenuExtraCode.rb similarity index 100% rename from Data/Scripts/021_Debug/002_Debug_MenuExtraCode.rb rename to Data/Scripts/021_Debug/001_Debug menus/003_Debug_MenuExtraCode.rb diff --git a/Data/Scripts/021_Debug/003_Debug_PokemonCommands.rb b/Data/Scripts/021_Debug/001_Debug menus/004_Debug_PokemonCommands.rb similarity index 100% rename from Data/Scripts/021_Debug/003_Debug_PokemonCommands.rb rename to Data/Scripts/021_Debug/001_Debug menus/004_Debug_PokemonCommands.rb diff --git a/Data/Scripts/021_Debug/002_Animation editor/001_AnimEditor_SceneElements.rb b/Data/Scripts/021_Debug/002_Animation editor/001_AnimEditor_SceneElements.rb new file mode 100644 index 000000000..319b05822 --- /dev/null +++ b/Data/Scripts/021_Debug/002_Animation editor/001_AnimEditor_SceneElements.rb @@ -0,0 +1,1031 @@ +################################################################################ +# Controls +################################################################################ +class Window_Menu < Window_CommandPokemon + def initialize(commands,x,y) + tempbitmap=Bitmap.new(32,32) + w=0 + for i in commands + width=tempbitmap.text_size(i).width + w=width if w=self.x && x=self.y && y64 && !usealpha + height=64 if height>64 && !usealpha + else + xwidth=0 + xheight=0 + end + width=sprite.bitmap.width if width>sprite.bitmap.width + height=sprite.bitmap.height if height>sprite.bitmap.height + if usealpha + spritex=sprite.x-(sprite.ox*sprite.zoom_x) + spritey=sprite.y-(sprite.oy*sprite.zoom_y) + width*=sprite.zoom_x + height*=sprite.zoom_y + else + spritex=sprite.x-sprite.ox + spritey=sprite.y-sprite.oy + spritex+=xwidth/2 + spritey+=xheight/2 + end + if !(x>=spritex && x<=spritex+width && y>=spritey && y<=spritey+height) + return false + end + if usealpha + # TODO: This should account for sprite.angle as well + bitmapX=sprite.src_rect.x + bitmapY=sprite.src_rect.y + bitmapX+=sprite.ox + bitmapY+=sprite.oy + bitmapX+=(x-sprite.x)/sprite.zoom_x if sprite.zoom_x>0 + bitmapY+=(y-sprite.y)/sprite.zoom_y if sprite.zoom_y>0 + bitmapX=bitmapX.round + bitmapY=bitmapY.round + if sprite.mirror + xmirror=bitmapX-sprite.src_rect.x + bitmapX=sprite.src_rect.x+192-xmirror + end + color=sprite.bitmap.get_pixel(bitmapX,bitmapY) + return false if (color.alpha==0) + end + return true +end + +def pbTrackPopupMenu(commands) + mousepos=Mouse::getMousePos + return -1 if !mousepos + menuwindow=Window_Menu.new(commands,mousepos[0],mousepos[1]) + menuwindow.z=99999 + loop do + Graphics.update + Input.update + menuwindow.update + hit=menuwindow.hittest + menuwindow.index=hit if hit>=0 + if Input.triggerex?(Input::LeftMouseKey) || Input.triggerex?(Input::RightMouseKey) # Left or right button + menuwindow.dispose + return hit + end + if Input.trigger?(Input::C) + hit=menuwindow.index + menuwindow.dispose + return hit + end + if Input.trigger?(Input::B) # Escape + break + end + end + menuwindow.dispose + return -1 +end + + + +################################################################################ +# Sprite sheet scrolling bar +################################################################################ +class AnimationWindow < SpriteWrapper + attr_reader :animbitmap + attr_reader :start + attr_reader :selected + NUMFRAMES=5 + + def initialize(x,y,width,height,viewport=nil) + super(viewport) + @animbitmap=nil + @arrows=AnimatedBitmap.new("Graphics/Pictures/arrows") + self.x=x + self.y=y + @start=0 + @selected=0 + @contents=Bitmap.new(width,height) + self.bitmap=@contents + refresh + end + + def animbitmap=(val) + @animbitmap=val + @start=0 + refresh + end + + def selected=(val) + @selected=val + refresh + end + + def dispose + @contents.dispose + @arrows.dispose + @start=0 + @selected=0 + @changed=false + super + end + + def drawrect(bm,x,y,width,height,color) + bm.fill_rect(x,y,width,1,color) + bm.fill_rect(x,y+height-1,width,1,color) + bm.fill_rect(x,y,1,height,color) + bm.fill_rect(x+width-1,y,1,height,color) + end + + def drawborder(bm,x,y,width,height,color) + bm.fill_rect(x,y,width,2,color) + bm.fill_rect(x,y+height-2,width,2,color) + bm.fill_rect(x,y,2,height,color) + bm.fill_rect(x+width-2,y,2,height,color) + end + + def refresh + arrowwidth=@arrows.bitmap.width/2 + @contents.clear + @contents.fill_rect(0,0,@contents.width,@contents.height,Color.new(180,180,180)) + @contents.blt(0,0,@arrows.bitmap,Rect.new(0,0,arrowwidth,96)) + @contents.blt(arrowwidth+NUMFRAMES*96,0,@arrows.bitmap, + Rect.new(arrowwidth,0,arrowwidth,96)) + havebitmap=(self.animbitmap && !self.animbitmap.disposed?) + if havebitmap + rect=Rect.new(0,0,0,0) + rectdst=Rect.new(0,0,0,0) + x=arrowwidth + for i in 0...NUMFRAMES + j=i+@start + rect.set((j%5)*192,(j/5)*192,192,192) + rectdst.set(x,0,96,96) + @contents.stretch_blt(rectdst,self.animbitmap,rect) + x+=96 + end + end + for i in 0...NUMFRAMES + drawrect(@contents,arrowwidth+i*96,0,96,96,Color.new(100,100,100)) + if @start+i==@selected && havebitmap + drawborder(@contents,arrowwidth+i*96,0,96,96,Color.new(255,0,0)) + end + end + end + + def changed? + return @changed + end + + def update + mousepos=Mouse::getMousePos + @changed=false + return if !Input.repeatex?(Input::LeftMouseKey) + return if !mousepos + return if !self.animbitmap + arrowwidth=@arrows.bitmap.width/2 + maxindex=(self.animbitmap.height/192)*5 + left=Rect.new(0,0,arrowwidth,96) + right=Rect.new(arrowwidth+NUMFRAMES*96,0,arrowwidth,96) + left.x+=self.x + left.y+=self.y + right.x+=self.x + right.y+=self.y + swatchrects=[] + for i in 0...NUMFRAMES + swatchrects.push(Rect.new(arrowwidth+i*96+self.x,self.y,96,96)) + end + for i in 0...NUMFRAMES + if swatchrects[i].contains(mousepos[0],mousepos[1]) + @selected=@start+i + @changed=true + refresh + return + end + end + # Left arrow + if left.contains(mousepos[0],mousepos[1]) + if Input.repeatcount(Input::LeftMouseKey)>30 + @start-=3 + else + @start-=1 + end + @start=0 if @start<0 + refresh + end + # Right arrow + if right.contains(mousepos[0],mousepos[1]) + if Input.repeatcount(Input::LeftMouseKey)>30 + @start+=3 + else + @start+=1 + end + @start=maxindex if @start>=maxindex + refresh + end + end +end + + + +class CanvasAnimationWindow < AnimationWindow + def animbitmap + return @canvas.animbitmap + end + + def initialize(canvas,x,y,width,height,viewport=nil) + @canvas=canvas + super(x,y,width,height,viewport) + end +end + + + +################################################################################ +# Cel sprite +################################################################################ +class InvalidatableSprite < Sprite + def initialize(viewport=nil) + super(viewport) + @invalid=false + end + +# Marks that the control must be redrawn to reflect current logic. + def invalidate + @invalid=true + end + +# Determines whether the control is invalid + def invalid? + return @invalid + end + +# Marks that the control is valid. Normally called only by repaint. + def validate + @invalid=false + end + +# Redraws the sprite only if it is invalid, and then revalidates the sprite + def repaint + if self.invalid? + refresh + validate + end + end + + # Redraws the sprite. This method should not check whether + # the sprite is invalid, to allow it to be explicitly called. + def refresh + end + + # Updates the logic on the sprite, for example, in response + # to user input, and invalidates it if necessary. This should + # be called only once per frame. + def update + super + end +end + + + +class SpriteFrame < InvalidatableSprite + attr_reader :id + attr_reader :locked + attr_reader :selected + attr_reader :sprite + NUM_ROWS = (PBAnimation::MAX_SPRITES.to_f/10).ceil # 10 frame number icons in each row + + def initialize(id,sprite,viewport,previous=false) + super(viewport) + @id=id + @sprite=sprite + @previous=previous + @locked=false + @selected=false + @selcolor=Color.new(0,0,0) + @unselcolor=Color.new(220,220,220) + @prevcolor=Color.new(64,128,192) + @contents=Bitmap.new(64,64) + self.z = (@previous) ? 49 : 50 + @iconbitmap=AnimatedBitmap.new("Graphics/Pictures/animFrameIcon") + self.bitmap=@contents + self.invalidate + end + + def dispose + @contents.dispose + super + end + + def sprite=(value) + @sprite=value + self.invalidate + end + + def locked=(value) + @locked=value + self.invalidate + end + + def selected=(value) + @selected=value + self.invalidate + end + + def refresh + @contents.clear + self.z = (@previous) ? 49 : (@selected) ? 51 : 50 + # Draw frame + color=(@previous) ? @prevcolor : (@selected) ? @selcolor : @unselcolor + @contents.fill_rect(0,0,64,1,color) + @contents.fill_rect(0,63,64,1,color) + @contents.fill_rect(0,0,1,64,color) + @contents.fill_rect(63,0,1,64,color) + # Determine frame number graphic to use from @iconbitmap + yoffset = (@previous) ? (NUM_ROWS+1)*16 : 0 # 1 is for padlock icon + bmrect=Rect.new((@id%10)*16,yoffset+(@id/10)*16,16,16) + @contents.blt(0,0,@iconbitmap.bitmap,bmrect) + # Draw padlock if frame is locked + if @locked && !@previous + bmrect=Rect.new(0,NUM_ROWS*16,16,16) + @contents.blt(16,0,@iconbitmap.bitmap,bmrect) + end + end +end + + + +################################################################################ +# Canvas +################################################################################ +class AnimationCanvas < Sprite + attr_reader :viewport + attr_reader :sprites + attr_reader :currentframe # Currently active frame + attr_reader :currentcel + attr_reader :animation # Currently selected animation + attr_reader :animbitmap # Currently selected animation bitmap + attr_accessor :pattern # Currently selected pattern + BORDERSIZE=64 + + def initialize(animation,viewport=nil) + super(viewport) + @currentframe=0 + @currentcel=-1 + @pattern=0 + @sprites={} + @celsprites=[] + @framesprites=[] + @lastframesprites=[] + @dirty=[] + @viewport=viewport + @selecting=false + @selectOffsetX=0 + @selectOffsetY=0 + @playing=false + @playingframe=0 + @player=nil + @battle=MiniBattle.new + @user=AnimatedBitmap.new("Graphics/Pictures/testback").deanimate + @target=AnimatedBitmap.new("Graphics/Pictures/testfront").deanimate + @testscreen=AnimatedBitmap.new("Graphics/Pictures/testscreen") + self.bitmap=@testscreen.bitmap + for i in 0...PBAnimation::MAX_SPRITES + @lastframesprites[i]=SpriteFrame.new(i,@celsprites[i],viewport,true) + @lastframesprites[i].selected=false + @lastframesprites[i].visible=false + end + for i in 0...PBAnimation::MAX_SPRITES + @celsprites[i]=Sprite.new(viewport) + @celsprites[i].visible=false + @celsprites[i].src_rect=Rect.new(0,0,0,0) + @celsprites[i].bitmap=nil + @framesprites[i]=SpriteFrame.new(i,@celsprites[i],viewport) + @framesprites[i].selected=false + @framesprites[i].visible=false + @dirty[i]=true + end + loadAnimation(animation) + end + + def loadAnimation(anim) + @animation=anim + @animbitmap.dispose if @animbitmap + if @animation.graphic=="" + @animbitmap=nil + else + begin + @animbitmap=AnimatedBitmap.new("Graphics/Animations/"+@animation.graphic, + @animation.hue).deanimate + rescue + @animbitmap=nil + end + end + @currentcel=-1 + self.currentframe=0 + @selecting=false + @pattern=0 + self.invalidate + end + + def animbitmap=(value) + @animbitmap.dispose if @animbitmap + @animbitmap=value + for i in 2...PBAnimation::MAX_SPRITES + @celsprites[i].bitmap=@animbitmap if @celsprites[i] + end + self.invalidate + end + + def dispose + @user.dispose + @target.dispose + @animbitmap.dispose if @animbitmap + @selectedbitmap.dispose if @selectedbitmap + @celbitmap.dispose if @celbitmap + self.bitmap.dispose if self.bitmap + for i in 0...PBAnimation::MAX_SPRITES + @celsprites[i].dispose if @celsprites[i] + end + super + end + + def play(oppmove=false) + if !@playing + @sprites["pokemon_0"]=Sprite.new(@viewport) + @sprites["pokemon_0"].bitmap=@user + @sprites["pokemon_0"].z=21 + @sprites["pokemon_1"]=Sprite.new(@viewport) + @sprites["pokemon_1"].bitmap=@target + @sprites["pokemon_1"].z=16 + pbSpriteSetAnimFrame(@sprites["pokemon_0"], + pbCreateCel(PokeBattle_SceneConstants::FOCUSUSER_X, + PokeBattle_SceneConstants::FOCUSUSER_Y,-1,2), + @sprites["pokemon_0"],@sprites["pokemon_1"]) + pbSpriteSetAnimFrame(@sprites["pokemon_1"], + pbCreateCel(PokeBattle_SceneConstants::FOCUSTARGET_X, + PokeBattle_SceneConstants::FOCUSTARGET_Y,-2,1), + @sprites["pokemon_0"],@sprites["pokemon_1"]) + usersprite=@sprites["pokemon_#{oppmove ? 1 : 0}"] + targetsprite=@sprites["pokemon_#{oppmove ? 0 : 1}"] + olduserx=usersprite ? usersprite.x : 0 + oldusery=usersprite ? usersprite.y : 0 + oldtargetx=targetsprite ? targetsprite.x : 0 + oldtargety=targetsprite ? targetsprite.y : 0 + @player=PBAnimationPlayerX.new(@animation, + @battle.battlers[oppmove ? 1 : 0],@battle.battlers[oppmove ? 0 : 1],self,oppmove,true) + @player.setLineTransform( + PokeBattle_SceneConstants::FOCUSUSER_X,PokeBattle_SceneConstants::FOCUSUSER_Y, + PokeBattle_SceneConstants::FOCUSTARGET_X,PokeBattle_SceneConstants::FOCUSTARGET_Y, + olduserx,oldusery, + oldtargetx,oldtargety) + @player.start + @playing=true + @sprites["pokemon_0"].x+=BORDERSIZE + @sprites["pokemon_0"].y+=BORDERSIZE + @sprites["pokemon_1"].x+=BORDERSIZE + @sprites["pokemon_1"].y+=BORDERSIZE + oldstate=[] + for i in 0...PBAnimation::MAX_SPRITES + oldstate.push([@celsprites[i].visible,@framesprites[i].visible,@lastframesprites[i].visible]) + @celsprites[i].visible=false + @framesprites[i].visible=false + @lastframesprites[i].visible=false + end + loop do + Graphics.update + self.update + break if !@playing + end + for i in 0...PBAnimation::MAX_SPRITES + @celsprites[i].visible=oldstate[i][0] + @framesprites[i].visible=oldstate[i][1] + @lastframesprites[i].visible=oldstate[i][2] + end + @sprites["pokemon_0"].dispose + @sprites["pokemon_1"].dispose + @player.dispose + @player=nil + end + end + + def invalidate + for i in 0...PBAnimation::MAX_SPRITES + invalidateCel(i) + end + end + + def invalidateCel(i) + @dirty[i]=true + end + + def currentframe=(value) + @currentframe=value + invalidate + end + + def getCurrentFrame + return nil if @currentframe>=@animation.length + return @animation[@currentframe] + end + + def setFrame(i) + if @celsprites[i] + @framesprites[i].ox=32 + @framesprites[i].oy=32 + @framesprites[i].selected=(i==@currentcel) + @framesprites[i].locked=self.locked?(i) + @framesprites[i].x=@celsprites[i].x + @framesprites[i].y=@celsprites[i].y + @framesprites[i].visible=@celsprites[i].visible + @framesprites[i].repaint + end + end + + def setPreviousFrame(i) + if @currentframe>0 + cel=@animation[@currentframe-1][i] + if cel!=nil + @lastframesprites[i].ox=32 + @lastframesprites[i].oy=32 + @lastframesprites[i].selected=false + @lastframesprites[i].locked=false + @lastframesprites[i].x=cel[AnimFrame::X]+64 + @lastframesprites[i].y=cel[AnimFrame::Y]+64 + @lastframesprites[i].visible=true + @lastframesprites[i].repaint + else + @lastframesprites[i].visible=false + end + else + @lastframesprites[i].visible=false + end + end + + def offsetFrame(frame,ox,oy) + if frame>=0 && frame<@animation.length + for i in 0...PBAnimation::MAX_SPRITES + if !self.locked?(i) && @animation[frame][i] + @animation[frame][i][AnimFrame::X]+=ox + @animation[frame][i][AnimFrame::Y]+=oy + end + @dirty[i]=true if frame==@currentframe + end + end + end + + # Clears all items in the frame except locked items + def clearFrame(frame) + if frame>=0 && frame<@animation.length + for i in 0...PBAnimation::MAX_SPRITES + if self.deletable?(i) + @animation[frame][i]=nil + else + pbResetCel(@animation[frame][i]) + end + @dirty[i]=true if frame==@currentframe + end + end + end + + def insertFrame(frame) + return if frame>=@animation.length + @animation.insert(frame,@animation[frame].clone) + self.invalidate + end + + def copyFrame(src,dst) + return if dst>=@animation.length + for i in 0...PBAnimation::MAX_SPRITES + clonedframe=@animation[src][i] + clonedframe=clonedframe.clone if clonedframe && clonedframe!=true + @animation[dst][i]=clonedframe + end + self.invalidate if dst==@currentframe + end + + def pasteFrame(frame) + return if frame <0 || frame>=@animation.length + return if Clipboard.typekey!="PBAnimFrame" + @animation[frame]=Clipboard.data + self.invalidate if frame==@currentframe + end + + def deleteFrame(frame) + return if frame<0 || frame>=@animation.length || @animation.length<=1 + self.currentframe-=1 if frame==@animation.length-1 + @animation.delete_at(frame) + @currentcel=-1 + self.invalidate + end + + # This frame becomes a copy of the previous frame + def pasteLast + copyFrame(@currentframe-1,@currentframe) if @currentframe>0 + end + + def currentCel + return nil if @currentcel<0 + return nil if @currentframe>=@animation.length + return @animation[@currentframe][@currentcel] + end + + def pasteCel(x,y) + return if @currentframe>=@animation.length + return if Clipboard.typekey!="PBAnimCel" + for i in 0...PBAnimation::MAX_SPRITES + next if @animation[@currentframe][i] + @animation[@currentframe][i]=Clipboard.data + cel=@animation[@currentframe][i] + cel[AnimFrame::X]=x + cel[AnimFrame::Y]=y + cel[AnimFrame::LOCKED]=0 + @celsprites[i].bitmap=@user if cel[AnimFrame::PATTERN]==-1 + @celsprites[i].bitmap=@target if cel[AnimFrame::PATTERN]==-2 + @currentcel=i + break + end + invalidate + end + + def deleteCel(cel) + return if cel<0 + return if @currentframe <0 || @currentframe>=@animation.length + return if !deletable?(cel) + @animation[@currentframe][cel]=nil + @dirty[cel]=true + end + + def swapCels(cel1,cel2) + return if cel1<0 || cel2<0 + return if @currentframe<0 || @currentframe>=@animation.length + t=@animation[@currentframe][cel1] + @animation[@currentframe][cel1]=@animation[@currentframe][cel2] + @animation[@currentframe][cel2]=t + @currentcel=cel2 + @dirty[cel1]=true + @dirty[cel2]=true + end + + def locked?(celindex) + cel=@animation[self.currentframe] + return false if !cel + cel=cel[celindex] + return cel ? (cel[AnimFrame::LOCKED]!=0) : false + end + + def deletable?(celindex) + cel=@animation[self.currentframe] + return true if !cel + cel=cel[celindex] + return true if !cel + return false if cel[AnimFrame::LOCKED]!=0 + if cel[AnimFrame::PATTERN]<0 + count=0 + pattern=cel[AnimFrame::PATTERN] + for i in 0...PBAnimation::MAX_SPRITES + othercel=@animation[self.currentframe][i] + count+=1 if othercel && othercel[AnimFrame::PATTERN]==pattern + end + return false if count<=1 + end + return true + end + + def setBitmap(i,frame) + if @celsprites[i] + cel=@animation[frame][i] + @celsprites[i].bitmap=@animbitmap + if cel + @celsprites[i].bitmap=@user if cel[AnimFrame::PATTERN]==-1 + @celsprites[i].bitmap=@target if cel[AnimFrame::PATTERN]==-2 + end + end + end + + def setSpriteBitmap(sprite,cel) + if sprite && !sprite.disposed? + sprite.bitmap=@animbitmap + if cel + sprite.bitmap=@user if cel[AnimFrame::PATTERN]==-1 + sprite.bitmap=@target if cel[AnimFrame::PATTERN]==-2 + end + end + end + + def addSprite(x,y) + return false if @currentframe>=@animation.length + for i in 0...PBAnimation::MAX_SPRITES + next if @animation[@currentframe][i] + @animation[@currentframe][i]=pbCreateCel(x,y,@pattern,@animation.position) + @dirty[i]=true + @currentcel=i + return true + end + return false + end + + def updateInput + cel=currentCel + mousepos=Mouse::getMousePos + if mousepos && pbSpriteHitTest(self,mousepos[0],mousepos[1],false,true) + if Input.triggerex?(Input::LeftMouseKey) # Left mouse button + selectedcel=-1 + usealpha=(Input.press?(Input::ALT)) ? true : false + for j in 0...PBAnimation::MAX_SPRITES + if pbSpriteHitTest(@celsprites[j],mousepos[0],mousepos[1],usealpha,false) + selectedcel=j + end + end + if selectedcel<0 + if @animbitmap && addSprite(mousepos[0]-BORDERSIZE,mousepos[1]-BORDERSIZE) + @selecting=true if !self.locked?(@currentcel) + @selectOffsetX=0 + @selectOffsetY=0 + cel=currentCel + invalidate + end + else + @currentcel=selectedcel + @selecting=true if !self.locked?(@currentcel) + cel=currentCel + @selectOffsetX=cel[AnimFrame::X]-mousepos[0]+BORDERSIZE + @selectOffsetY=cel[AnimFrame::Y]-mousepos[1]+BORDERSIZE + invalidate + end + end + end + currentFrame=getCurrentFrame + if currentFrame && !@selecting && Input.repeat?(Input::TAB) + currentFrame.length.times { + @currentcel+=1 + @currentcel=0 if @currentcel>=currentFrame.length + break if currentFrame[@currentcel] + } + invalidate + return + end + if cel && @selecting && mousepos + cel[AnimFrame::X]=mousepos[0]-BORDERSIZE+@selectOffsetX + cel[AnimFrame::Y]=mousepos[1]-BORDERSIZE+@selectOffsetY + @dirty[@currentcel]=true + end + if !Input.getstate(Input::LeftMouseKey) && @selecting + @selecting=false + end + if cel + if Input.repeat?(Input::DELETE) && self.deletable?(@currentcel) + @animation[@currentframe][@currentcel]=nil + @dirty[@currentcel]=true + return + end + if Input.repeatex?(0x50) # "P" for properties + pbCellProperties(self) + @dirty[@currentcel]=true + return + end + if Input.repeatex?(0x4C) # "L" for lock + cel[AnimFrame::LOCKED]=(cel[AnimFrame::LOCKED]==0) ? 1 : 0 + @dirty[@currentcel]=true + end + if Input.repeatex?(0x52) # "R" for rotate right + cel[AnimFrame::ANGLE]+=10 + cel[AnimFrame::ANGLE]%=360 + @dirty[@currentcel]=true + end + if Input.repeatex?(0x45) # "E" for rotate left + cel[AnimFrame::ANGLE]-=10 + cel[AnimFrame::ANGLE]%=360 + @dirty[@currentcel]=true + end + if Input.repeatex?(0x6B) # "+" for zoom in + cel[AnimFrame::ZOOMX]+=10 + cel[AnimFrame::ZOOMX]=1000 if cel[AnimFrame::ZOOMX]>1000 + cel[AnimFrame::ZOOMY]+=10 + cel[AnimFrame::ZOOMY]=1000 if cel[AnimFrame::ZOOMY]>1000 + @dirty[@currentcel]=true + end + if Input.repeatex?(0x6D) # "-" for zoom in + cel[AnimFrame::ZOOMX]-=10 + cel[AnimFrame::ZOOMX]=10 if cel[AnimFrame::ZOOMX]<10 + cel[AnimFrame::ZOOMY]-=10 + cel[AnimFrame::ZOOMY]=10 if cel[AnimFrame::ZOOMY]<10 + @dirty[@currentcel]=true + end + if !self.locked?(@currentcel) + if Input.repeat?(Input::UP) + increment=(Input.press?(Input::ALT)) ? 1 : 8 + cel[AnimFrame::Y]-=increment + @dirty[@currentcel]=true + end + if Input.repeat?(Input::DOWN) + increment=(Input.press?(Input::ALT)) ? 1 : 8 + cel[AnimFrame::Y]+=increment + @dirty[@currentcel]=true + end + if Input.repeat?(Input::LEFT) + increment=(Input.press?(Input::ALT)) ? 1 : 8 + cel[AnimFrame::X]-=increment + @dirty[@currentcel]=true + end + if Input.repeat?(Input::RIGHT) + increment=(Input.press?(Input::ALT)) ? 1 : 8 + cel[AnimFrame::X]+=increment + @dirty[@currentcel]=true + end + end + end + end + + def update + super + if @playing + if @player.animDone? + @playing=false + invalidate + else + @player.update + end + return + end + updateInput +# @testscreen.update +# self.bitmap=@testscreen.bitmap + if @currentframe < @animation.length + for i in 0...PBAnimation::MAX_SPRITES + if @dirty[i] + if @celsprites[i] + setBitmap(i,@currentframe) + pbSpriteSetAnimFrame(@celsprites[i],@animation[@currentframe][i],@celsprites[0],@celsprites[1],true) + @celsprites[i].x+=BORDERSIZE + @celsprites[i].y+=BORDERSIZE + end + setPreviousFrame(i) + setFrame(i) + @dirty[i]=false + end + end + else + for i in 0...PBAnimation::MAX_SPRITES + pbSpriteSetAnimFrame(@celsprites[i],nil,@celsprites[0],@celsprites[1],true) + @celsprites[i].x+=BORDERSIZE + @celsprites[i].y+=BORDERSIZE + setPreviousFrame(i) + setFrame(i) + @dirty[i]=false + end + end + end +end + + + +################################################################################ +# Window classes +################################################################################ +class BitmapDisplayWindow < SpriteWindow_Base + attr_reader :bitmapname + attr_reader :hue + + def initialize(x,y,width,height) + super(x,y,width,height) + @bitmapname="" + @hue=0 + self.contents=Bitmap.new(width-32,height-32) + end + + def bitmapname=(value) + if @bitmapname!=value + @bitmapname=value + refresh + end + end + + def hue=(value) + if @hue!=value + @hue=value + refresh + end + end + + def refresh + self.contents.clear + bmap=AnimatedBitmap.new("Graphics/Animations/"+@bitmapname,@hue).deanimate + return if !bmap + ww=bmap.width + wh=bmap.height + sx=self.contents.width*1.0/ww + sy=self.contents.height*1.0/wh + if sx>sy + ww=sy*ww + wh=self.contents.height + else + wh=sx*wh + ww=self.contents.width + end + dest=Rect.new( + (self.contents.width-ww)/2, + (self.contents.height-wh)/2, + ww,wh) + src=Rect.new(0,0,bmap.width,bmap.height) + self.contents.stretch_blt(dest,bmap,src) + bmap.dispose + end +end + + + +class AnimationNameWindow + def initialize(canvas,x,y,width,height,viewport=nil) + @canvas=canvas + @oldname=nil + @window=Window_UnformattedTextPokemon.newWithSize( + _INTL("Name: {1}",@canvas.animation.name),x,y,width,height,viewport) + end + + def viewport=(value); @window.viewport=value; end + + def update + newtext=_INTL("Name: {1}",@canvas.animation.name) + if @oldname!=newtext + @window.text=newtext + @oldname=newtext + end + @window.update + end + + def refresh; @window.refresh; end + def dispose; @window.dispose; end + def disposed; @window.disposed?; end +end diff --git a/Data/Scripts/021_Debug/002_Animation editor/002_AnimEditor_ControlsButtons.rb b/Data/Scripts/021_Debug/002_Animation editor/002_AnimEditor_ControlsButtons.rb new file mode 100644 index 000000000..f856f0f84 --- /dev/null +++ b/Data/Scripts/021_Debug/002_Animation editor/002_AnimEditor_ControlsButtons.rb @@ -0,0 +1,945 @@ +module ShadowText + def shadowtext(bitmap,x,y,w,h,t,disabled=false,align=0) + width=bitmap.text_size(t).width + if align==2 + x+=(w-width) + elsif align==1 + x+=(w/2)-(width/2) + end + pbDrawShadowText(bitmap,x,y+6,w,h,t, + disabled ? Color.new(26*8,26*8,25*8) : Color.new(12*8,12*8,12*8), + Color.new(26*8,26*8,25*8)) + end +end + + + +class UIControl + include ShadowText + attr_accessor :bitmap + attr_accessor :label + attr_accessor :x + attr_accessor :y + attr_accessor :width + attr_accessor :height + attr_accessor :changed + attr_accessor :parent + attr_accessor :disabled + + def text + return self.label + end + + def text=(value) + self.label=value + end + + def initialize(label) + @label=label + @x=0 + @y=0 + @width=0 + @height=0 + @changed=false + @disabled=false + @invalid=true + end + + def toAbsoluteRect(rc) + return Rect.new( + rc.x+self.parentX, + rc.y+self.parentY, + rc.width,rc.height) + end + + def parentX + return 0 if !self.parent + return self.parent.x+self.parent.leftEdge if self.parent.is_a?(SpriteWindow) + return self.parent.x+16 if self.parent.is_a?(Window) + return self.parent.x + end + + def parentY + return 0 if !self.parent + return self.parent.y+self.parent.topEdge if self.parent.is_a?(SpriteWindow) + return self.parent.y+16 if self.parent.is_a?(Window) + return self.parent.y + end + + def invalid? + return @invalid + end + + def invalidate # Marks that the control must be redrawn to reflect current logic + @invalid=true + end + + def update # Updates the logic on the control, invalidating it if necessary + end + + def refresh # Redraws the control + end + + def validate # Makes the control no longer invalid + @invalid=false + end + + def repaint # Redraws the control only if it is invalid + if self.invalid? + self.refresh + self.validate + end + end +end + + + +class Label < UIControl + def text=(value) + self.label=value + refresh + end + + def refresh + bitmap=self.bitmap + bitmap.fill_rect(self.x,self.y,self.width,self.height,Color.new(0,0,0,0)) + size=bitmap.text_size(self.label).width + shadowtext(bitmap,self.x+4,self.y,size,self.height,self.label,@disabled) + end +end + + + +class Button < UIControl + attr_accessor :label + + def initialize(label) + super + @captured=false + @label=label + end + + def update + mousepos=Mouse::getMousePos + self.changed=false + return if !mousepos + rect=Rect.new(self.x+1,self.y+1,self.width-2,self.height-2) + rect=toAbsoluteRect(rect) + if Input.triggerex?(Input::LeftMouseKey) && + rect.contains(mousepos[0],mousepos[1]) && !@captured + @captured=true + self.invalidate + end + if Input.releaseex?(Input::LeftMouseKey) && @captured + self.changed=true if rect.contains(mousepos[0],mousepos[1]) + @captured=false + self.invalidate + end + end + + def refresh + bitmap=self.bitmap + x=self.x + y=self.y + width=self.width + height=self.height + color=Color.new(120,120,120) + bitmap.fill_rect(x+1,y+1,width-2,height-2,color) + ret=Rect.new(x+1,y+1,width-2,height-2) + if !@captured + bitmap.fill_rect(x+2,y+2,width-4,height-4,Color.new(0,0,0,0)) + else + bitmap.fill_rect(x+2,y+2,width-4,height-4,Color.new(120,120,120,80)) + end + size=bitmap.text_size(self.label).width + shadowtext(bitmap,x+4,y,size,height,self.label,@disabled) + return ret + end +end + + + +class Checkbox < Button + attr_reader :checked + + def curvalue + return self.checked + end + + def curvalue=(value) + self.checked=value + end + + def checked=(value) + @checked=value + invalidate + end + + def initialize(label) + super + @checked=false + end + + def update + super + if self.changed + @checked=!@checked + self.invalidate + end + end + + def refresh + bitmap=self.bitmap + x=self.x + y=self.y + width=[self.width,32].min + height=[self.height,32].min + color=Color.new(120,120,120) + bitmap.fill_rect(x+2,y+2,self.width-4,self.height-4,Color.new(0,0,0,0)) + bitmap.fill_rect(x+1,y+1,width-2,height-2,color) + ret=Rect.new(x+1,y+1,width-2,height-2) + if !@captured + bitmap.fill_rect(x+2,y+2,width-4,height-4,Color.new(0,0,0,0)) + else + bitmap.fill_rect(x+2,y+2,width-4,height-4,Color.new(120,120,120,80)) + end + if self.checked + shadowtext(bitmap,x,y,32,32,"X",@disabled,1) + end + size=bitmap.text_size(self.label).width + shadowtext(bitmap,x+36,y,size,height,self.label,@disabled) + return ret + end +end + + + +class TextField < UIControl + attr_accessor :label + attr_reader :text + + def text=(value) + @text=value + self.invalidate + end + + def initialize(label,text) + super(label) + @frame=0 + @label=label + @text=text + @cursor=text.scan(/./m).length + end + + def insert(ch) + chars=self.text.scan(/./m) + chars.insert(@cursor,ch) + @text="" + for ch in chars + @text+=ch + end + @cursor+=1 + @frame=0 + self.changed=true + self.invalidate + end + + def delete + chars=self.text.scan(/./m) + chars.delete_at(@cursor-1) + @text="" + for ch in chars + @text+=ch + end + @cursor-=1 + @frame=0 + self.changed=true + self.invalidate + end + + def update + @frame+=1 + @frame%=20 + self.changed=false + self.invalidate if ((@frame%10)==0) + # Moving cursor + if Input.repeat?(Input::LEFT) + if @cursor > 0 + @cursor-=1 + @frame=0 + self.invalidate + end + return + end + if Input.repeat?(Input::RIGHT) + if @cursor < self.text.scan(/./m).length + @cursor+=1 + @frame=0 + self.invalidate + end + return + end + # Backspace + if Input.repeat?(Input::BACKSPACE) || Input.repeat?(Input::DELETE) + self.delete if @cursor > 0 + return + end + # Letter keys + for i in 65..90 + if Input.repeatex?(i) + shift=(Input.press?(Input::SHIFT)) ? 0x41 : 0x61 + insert((shift+i-65).chr) + return + end + end + # Number keys + shifted=")!@\#$%^&*(" + unshifted="0123456789" + for i in 48..57 + if Input.repeatex?(i) + insert((Input.press?(Input::SHIFT)) ? shifted[i-48].chr : unshifted[i-48].chr) + return + end + end + keys=[ + [32," "," "], + [106,"*","*"], + [107,"+","+"], + [109,"-","-"], + [111,"/","/"], + [186,";",":"], + [187,"=","+"], + [188,",","<"], + [189,"-","_"], + [190,".",">"], + [191,"/","?"], + [219,"[","{"], + [220,"\\","|"], + [221,"]","}"], + [222,"\"","'"] + ] + for i in keys + if Input.repeatex?(i[0]) + insert((Input.press?(Input::SHIFT)) ? i[2] : i[1]) + return + end + end + end + + def refresh + bitmap=self.bitmap + x=self.x + y=self.y + width=self.width + height=self.height + color=Color.new(120,120,120) + bitmap.font.color=color + bitmap.fill_rect(x,y,width,height,Color.new(0,0,0,0)) + size=bitmap.text_size(self.label).width + shadowtext(bitmap,x,y,size,height,self.label) + x+=size + width-=size + bitmap.fill_rect(x+1,y+1,width-2,height-2,color) + ret=Rect.new(x+1,y+1,width-2,height-2) + if !@captured + bitmap.fill_rect(x+2,y+2,width-4,height-4,Color.new(0,0,0,0)) + else + bitmap.fill_rect(x+2,y+2,width-4,height-4,Color.new(120,120,120,80)) + end + x+=4 + textscan=self.text.scan(/./m) + scanlength=textscan.length + @cursor=scanlength if @cursor>scanlength + @cursor=0 if @cursor<0 + startpos=@cursor + fromcursor=0 + while (startpos>0) + c=textscan[startpos-1] + fromcursor+=bitmap.text_size(c).width + break if fromcursor>width-4 + startpos-=1 + end + for i in startpos...scanlength + c=textscan[i] + textwidth=bitmap.text_size(c).width + next if c=="\n" + # Draw text + shadowtext(bitmap,x,y, textwidth+4, 32, c) + # Draw cursor if necessary + if ((@frame/10)&1) == 0 && i==@cursor + bitmap.fill_rect(x,y+4,2,24,Color.new(120,120,120)) + end + # Add x to drawn text width + x += textwidth + end + if ((@frame/10)&1) == 0 && textscan.length==@cursor + bitmap.fill_rect(x,y+4,2,24,Color.new(120,120,120)) + end + return ret + end +end + + + +class Slider < UIControl + attr_reader :minvalue + attr_reader :maxvalue + attr_reader :curvalue + attr_accessor :label + + def curvalue=(value) + @curvalue=value + @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue + self.invalidate + end + + def minvalue=(value) + @minvalue=value + @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue + self.invalidate + end + + def maxvalue=(value) + @maxvalue=value + @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue + self.invalidate + end + + def initialize(label,minvalue,maxvalue,curval) + super(label) + @minvalue=minvalue + @maxvalue=maxvalue + @curvalue=curval + @label=label + @leftarrow=Rect.new(0,0,0,0) + @rightarrow=Rect.new(0,0,0,0) + self.minvalue=minvalue + self.maxvalue=maxvalue + self.curvalue=curval + end + + def update + mousepos=Mouse::getMousePos + self.changed=false + if self.minvalue100 + self.curvalue-=10 + self.curvalue=self.curvalue.floor + elsif Input.repeatcount(Input::LeftMouseKey)>50 + self.curvalue-=5 + self.curvalue=self.curvalue.floor + else + self.curvalue-=1 + self.curvalue=self.curvalue.floor + end + self.changed=(self.curvalue!=oldvalue) + self.invalidate + end + #Right arrow + if right.contains(mousepos[0],mousepos[1]) + if Input.repeatcount(Input::LeftMouseKey)>100 + self.curvalue+=10 + self.curvalue=self.curvalue.floor + elsif Input.repeatcount(Input::LeftMouseKey)>50 + self.curvalue+=5 + self.curvalue=self.curvalue.floor + else + self.curvalue+=1 + self.curvalue=self.curvalue.floor + end + self.changed=(self.curvalue!=oldvalue) + self.invalidate + end + end + + def refresh + bitmap=self.bitmap + x=self.x + y=self.y + width=self.width + height=self.height + color=Color.new(120,120,120) + bitmap.fill_rect(x,y,width,height,Color.new(0,0,0,0)) + size=bitmap.text_size(self.label).width + leftarrows=bitmap.text_size(_INTL(" << ")) + numbers=bitmap.text_size(" XXXX ").width + rightarrows=bitmap.text_size(_INTL(" >> ")) + bitmap.font.color=color + shadowtext(bitmap,x,y,size,height,self.label) + x+=size + shadowtext(bitmap,x,y,leftarrows.width,height,_INTL(" << "), + self.disabled || self.curvalue==self.minvalue) + @leftarrow=Rect.new(x,y,leftarrows.width,height) + x+=leftarrows.width + if !self.disabled + bitmap.font.color=color + shadowtext(bitmap,x,y,numbers,height," #{self.curvalue} ",false,1) + end + x+=numbers + shadowtext(bitmap,x,y,rightarrows.width,height,_INTL(" >> "), + self.disabled || self.curvalue==self.maxvalue) + @rightarrow=Rect.new(x,y,rightarrows.width,height) + end +end + + + +class OptionalSlider < Slider + def initialize(label,minvalue,maxvalue,curvalue) + @slider=Slider.new(label,minvalue,maxvalue,curvalue) + @checkbox=Checkbox.new("") + end + + def curvalue + return @checkbox.checked ? @slider.curvalue : nil + end + + def curvalue=(value) + slider.curvalue=value + end + + def checked + return @checkbox.checked + end + + def checked=(value) + @checkbox.checked=value + end + + def invalid? + return @slider.invalid? || @checkbox.invalid? + end + + def invalidate + @slider.invalidate + @checkbox.invalidate + end + + def validate? + @slider.validate + @checkbox.validate + end + + def changed + return @slider.changed || @checkbox.changed + end + + def minvalue + return @slider.minvalue + end + + def minvalue=(value) + slider.minvalue=value + end + + def maxvalue + return @slider.maxvalue + end + + def maxvalue=(value) + slider.maxvalue=value + end + + def update + updatedefs + @slider.update + @checkbox.update + end + + def refresh + updatedefs + @slider.refresh + @checkbox.refresh + end + + private + + def updatedefs + checkboxwidth=32 + @slider.bitmap=self.bitmap + @slider.parent=self.parent + @checkbox.x=self.x + @checkbox.y=self.y + @checkbox.width=checkboxwidth + @checkbox.height=self.height + @checkbox.bitmap=self.bitmap + @checkbox.parent=self.parent + @slider.x=self.x+checkboxwidth+4 + @slider.y=self.y + @slider.width=self.width-checkboxwidth + @slider.height=self.height + @slider.disabled=!@checkbox.checked + end +end + + + +class ArrayCountSlider < Slider + def maxvalue + return @array.length-1 + end + + def initialize(array,label) + @array=array + super(label,0,canvas.animation.length-1,0) + end +end + + + +class FrameCountSlider < Slider + def maxvalue + return @canvas.animation.length + end + + def initialize(canvas) + @canvas=canvas + super(_INTL("Frame:"),1,canvas.animation.length,0) + end +end + + + +class FrameCountButton < Button + def label + return _INTL("Total Frames: {1}",@canvas.animation.length) + end + + def initialize(canvas) + @canvas=canvas + super(self.label) + end +end + + + +class TextSlider < UIControl + attr_reader :minvalue + attr_reader :maxvalue + attr_reader :curvalue + attr_accessor :label + attr_accessor :options + attr_accessor :maxoptionwidth + + def curvalue=(value) + @curvalue=value + @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue + self.invalidate + end + + def minvalue=(value) + @minvalue=value + @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue + self.invalidate + end + + def maxvalue=(value) + @maxvalue=value + @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue + self.invalidate + end + + def initialize(label,options,curval) + super(label) + @label=label + @options=options + @minvalue=0 + @maxvalue=options.length-1 + @curvalue=curval + @leftarrow=Rect.new(0,0,0,0) + @rightarrow=Rect.new(0,0,0,0) + self.minvalue=@minvalue + self.maxvalue=@maxvalue + self.curvalue=@curvalue + end + + def update + mousepos=Mouse::getMousePos + self.changed=false + if self.minvalue100 + self.curvalue-=10 + elsif Input.repeatcount(Input::LeftMouseKey)>50 + self.curvalue-=5 + else + self.curvalue-=1 + end + self.changed=(self.curvalue!=oldvalue) + self.invalidate + end + # Right arrow + if right.contains(mousepos[0],mousepos[1]) + if Input.repeatcount(Input::LeftMouseKey)>100 + self.curvalue+=10 + elsif Input.repeatcount(Input::LeftMouseKey)>50 + self.curvalue+=5 + else + self.curvalue+=1 + end + self.changed=(self.curvalue!=oldvalue) + self.invalidate + end + end + + def refresh + bitmap=self.bitmap + if @maxoptionwidth==nil + for i in 0...@options.length + w=self.bitmap.text_size(" "+@options[i]+" ").width + @maxoptionwidth=w if !@maxoptionwidth || @maxoptionwidth> ")) + bitmap.font.color=color + shadowtext(bitmap,x,y,size,height,self.label) + x+=size + shadowtext(bitmap,x,y,leftarrows.width,height,_INTL(" << "), + self.disabled || self.curvalue==self.minvalue) + @leftarrow=Rect.new(x,y,leftarrows.width,height) + x+=leftarrows.width + if !self.disabled + bitmap.font.color=color + shadowtext(bitmap,x,y,@maxoptionwidth,height," #{@options[self.curvalue]} ",false,1) + end + x+=@maxoptionwidth + shadowtext(bitmap,x,y,rightarrows.width,height,_INTL(" >> "), + self.disabled || self.curvalue==self.maxvalue) + @rightarrow=Rect.new(x,y,rightarrows.width,height) + end +end + + + +class OptionalTextSlider < TextSlider + def initialize(label,options,curval) + @slider=TextSlider.new(label,options,curval) + @checkbox=Checkbox.new("") + end + + def curvalue + return @checkbox.checked ? @slider.curvalue : nil + end + + def curvalue=(value) + slider.curvalue=value + end + + def checked + return @checkbox.checked + end + + def checked=(value) + @checkbox.checked=value + end + + def invalid? + return @slider.invalid? || @checkbox.invalid? + end + + def invalidate + @slider.invalidate + @checkbox.invalidate + end + + def validate? + @slider.validate + @checkbox.validate + end + + def changed + return @slider.changed || @checkbox.changed + end + + def minvalue + return @slider.minvalue + end + + def minvalue=(value) + slider.minvalue=value + end + + def maxvalue + return @slider.maxvalue + end + + def maxvalue=(value) + slider.maxvalue=value + end + + def update + updatedefs + @slider.update + @checkbox.update + end + + def refresh + updatedefs + @slider.refresh + @checkbox.refresh + end + + private + + def updatedefs + checkboxwidth=32 + @slider.bitmap=self.bitmap + @slider.parent=self.parent + @checkbox.x=self.x + @checkbox.y=self.y + @checkbox.width=checkboxwidth + @checkbox.height=self.height + @checkbox.bitmap=self.bitmap + @checkbox.parent=self.parent + @slider.x=self.x+checkboxwidth+4 + @slider.y=self.y + @slider.width=self.width-checkboxwidth + @slider.height=self.height + @slider.disabled=!@checkbox.checked + end +end + + +class ControlWindow < SpriteWindow_Base + attr_reader :controls + + def initialize(x,y,width,height) + super(x,y,width,height) + self.contents=Bitmap.new(width-32,height-32) + pbSetNarrowFont(self.contents) + @controls=[] + end + + def dispose + self.contents.dispose + super + end + + def refresh + for i in 0...@controls.length + @controls[i].refresh + end + end + + def repaint + for i in 0...@controls.length + @controls[i].repaint + end + end + + def invalidate + for i in 0...@controls.length + @controls[i].invalidate + end + end + + def hittest?(i) + mousepos=Mouse::getMousePos + return false if !mousepos + return false if i<0 || i>=@controls.length + rc=Rect.new( + @controls[i].parentX, + @controls[i].parentY, + @controls[i].width, + @controls[i].height + ) + return rc.contains(mousepos[0],mousepos[1]) + end + + def addControl(control) + i=@controls.length + @controls[i]=control + @controls[i].x=0 + @controls[i].y=i*32 + @controls[i].width=self.contents.width + @controls[i].height=32 + @controls[i].parent=self + @controls[i].bitmap=self.contents + @controls[i].invalidate + refresh + return i + end + + def addLabel(label) + return addControl(Label.new(label)) + end + + def addButton(label) + return addControl(Button.new(label)) + end + + def addSlider(label,minvalue,maxvalue,curvalue) + return addControl(Slider.new(label,minvalue,maxvalue,curvalue)) + end + + def addOptionalSlider(label,minvalue,maxvalue,curvalue) + return addControl(OptionalSlider.new(label,minvalue,maxvalue,curvalue)) + end + + def addTextSlider(label,options,curvalue) + return addControl(TextSlider.new(label,options,curvalue)) + end + + def addOptionalTextSlider(label,options,curvalue) + return addControl(OptionalTextSlider.new(label,options,curvalue)) + end + + def addCheckbox(label) + return addControl(Checkbox.new(label)) + end + + def addSpace + return addControl(UIControl.new("")) + end + + def update + super + for i in 0...@controls.length + @controls[i].update + end + repaint + end + + def changed?(i) + return false if i<0 + return @controls[i].changed + end + + def value(i) + return false if i<0 + return @controls[i].curvalue + end +end diff --git a/Data/Scripts/021_Debug/002_Animation editor/003_AnimEditor_Interpolation.rb b/Data/Scripts/021_Debug/002_Animation editor/003_AnimEditor_Interpolation.rb new file mode 100644 index 000000000..da381eb65 --- /dev/null +++ b/Data/Scripts/021_Debug/002_Animation editor/003_AnimEditor_Interpolation.rb @@ -0,0 +1,444 @@ +################################################################################ +# Paths and interpolation +################################################################################ +class ControlPointSprite < SpriteWrapper + attr_accessor :dragging + + def initialize(red,viewport=nil) + super(viewport) + self.bitmap=Bitmap.new(6,6) + self.bitmap.fill_rect(0,0,6,1,Color.new(0,0,0)) + self.bitmap.fill_rect(0,0,1,6,Color.new(0,0,0)) + self.bitmap.fill_rect(0,5,6,1,Color.new(0,0,0)) + self.bitmap.fill_rect(5,0,1,6,Color.new(0,0,0)) + color=(red) ? Color.new(255,0,0) : Color.new(0,0,0) + self.bitmap.fill_rect(2,2,2,2,color) + self.x=-6 + self.y=-6 + self.visible=false + @dragging=false + end + + def mouseover + if Input.repeatcount(Input::LeftMouseKey)==0 || !@dragging + @dragging=false + return + end + mouse=Mouse::getMousePos(true) + return if !mouse + self.x=[[mouse[0],0].max,512].min + self.y=[[mouse[1],0].max,384].min + end + + def hittest? + return true if !self.visible + mouse=Mouse::getMousePos(true) + return false if !mouse + return mouse[0]>=self.x && mouse[0]=self.y && mouse[1]1 + len=@points.length + dx=@points[len-2][0]-@points[len-1][0] + dy=@points[len-2][1]-@points[len-1][1] + dist=Math.sqrt(dx*dx+dy*dy) + @distances.push(dist) + @totaldist+=dist + end + end + + def clear + @points.clear + @distances.clear + @totaldist=0 + end + + def smoothPointPath(frames,roundValues=false) + if frames<0 + raise ArgumentError.new("frames out of range: #{frames}") + end + ret=PointPath.new + if @points.length==0 + return ret + end + step=1.0/frames + t=0.0 + (frames+2).times do + point=pointOnPath(t) + if roundValues + ret.addPoint(point[0].round,point[1].round) + else + ret.addPoint(point[0],point[1]) + end + t+=step + t=[1.0,t].min + end + return ret + end + + def pointOnPath(t) + if t<0 || t>1 + raise ArgumentError.new("t out of range for pointOnPath: #{t}") + end + return nil if @points.length==0 + ret=@points[@points.length-1].clone + if @points.length==1 + return ret + end + curdist=0 + distForT=@totaldist*t + i=0 + for dist in @distances + curdist+=dist + if dist>0.0 + if curdist>=distForT + distT=1.0-((curdist-distForT)/dist) + dx=@points[i+1][0]-@points[i][0] + dy=@points[i+1][1]-@points[i][1] + ret=[@points[i][0]+dx*distT, + @points[i][1]+dy*distT] + break + end + end + i+=1 + end + return ret + end +end + + + +def catmullRom(p1,p2,p3,p4,t) + # p1=prevPoint, p2=startPoint, p3=endPoint, p4=nextPoint, t is from 0 through 1 + t2=t*t + t3=t2*t + return 0.5*(2*p2+t*(p3-p1) + + t2*(2*p1-5*p2+4*p3-p4)+ + t3*(p4-3*p3+3*p2-p1)) +end + +def getCatmullRomPoint(src,t) + x=0,y=0 + t*=3.0 + if t<1.0 + x=catmullRom(src[0].x,src[0].x,src[1].x,src[2].x,t) + y=catmullRom(src[0].y,src[0].y,src[1].y,src[2].y,t) + elsif t<2.0 + t-=1.0 + x=catmullRom(src[0].x,src[1].x,src[2].x,src[3].x,t) + y=catmullRom(src[0].y,src[1].y,src[2].y,src[3].y,t) + else + t-=2.0 + x=catmullRom(src[1].x,src[2].x,src[3].x,src[3].x,t) + y=catmullRom(src[1].y,src[2].y,src[3].y,src[3].y,t) + end + return [x,y] +end + +def getCurvePoint(src,t) + return getCatmullRomPoint(src,t) +end + +def curveToPointPath(curve,numpoints) + if numpoints<2 + return nil + end + path=PointPath.new + step=1.0/(numpoints-1) + t=0.0 + numpoints.times do + point=getCurvePoint(curve,t) + path.addPoint(point[0],point[1]) + t+=step + end + return path +end + +def pbDefinePath(canvas) + sliderwin2=ControlWindow.new(0,0,320,320) + sliderwin2.viewport=canvas.viewport + sliderwin2.addSlider(_INTL("Number of frames:"),2,500,20) + sliderwin2.opacity=200 + defcurvebutton=sliderwin2.addButton(_INTL("Define Smooth Curve")) + defpathbutton=sliderwin2.addButton(_INTL("Define Freehand Path")) + okbutton=sliderwin2.addButton(_INTL("OK")) + cancelbutton=sliderwin2.addButton(_INTL("Cancel")) + points=[] + path=nil + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(0) # Number of frames + if path + path=path.smoothPointPath(sliderwin2.value(0),false) + i=0 + for point in path + if icanvas.animation.length + canvas.animation.resize(neededsize) + end + thiscel=canvas.currentCel + celnumber=canvas.currentcel + for i in canvas.currentframe...neededsize + cel=canvas.animation[i][celnumber] + if !canvas.animation[i][celnumber] + cel=pbCreateCel(0,0,thiscel[AnimFrame::PATTERN],canvas.animation.position) + canvas.animation[i][celnumber]=cel + end + cel[AnimFrame::X]=path[i-canvas.currentframe][0] + cel[AnimFrame::Y]=path[i-canvas.currentframe][1] + end + break + elsif sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) + break + end + end + # dispose all points + for point in points + point.dispose + end + points.clear + sliderwin2.dispose + return +end diff --git a/Data/Scripts/021_Debug/002_Animation editor/004_AnimEditor_ExportImport.rb b/Data/Scripts/021_Debug/002_Animation editor/004_AnimEditor_ExportImport.rb new file mode 100644 index 000000000..720b2d06d --- /dev/null +++ b/Data/Scripts/021_Debug/002_Animation editor/004_AnimEditor_ExportImport.rb @@ -0,0 +1,144 @@ +################################################################################ +# Importing and exporting +################################################################################ +def pbRgssChdir(dir) + RTP.eachPathFor(dir) { |path| Dir.chdir(path) { yield } } +end + +def tryLoadData(file) + begin + return load_data(file) + rescue + return nil + end +end + +def dumpBase64Anim(s) + return [Zlib::Deflate.deflate(Marshal.dump(s))].pack("m").gsub(/\n/,"\r\n") +end + +def loadBase64Anim(s) + return Marshal.restore(StringInput.new(Zlib::Inflate.inflate(s.unpack("m")[0]))) +end + +def pbExportAnim(animations) + filename=pbMessageFreeText(_INTL("Enter a filename."),"",false,32) + if filename!="" + begin + filename+=".anm" + File.open(filename,"wb") { |f| + f.write(dumpBase64Anim(animations[animations.selected])) + } + failed=false + rescue + pbMessage(_INTL("Couldn't save the animation to {1}.",filename)) + failed=true + end + if !failed + pbMessage(_INTL("Animation was saved to {1} in the game folder.",filename)) + pbMessage(_INTL("It's a text file, so it can be transferred to others easily.")) + end + end +end + +def pbImportAnim(animations,canvas,animwin) + animfiles=[] + pbRgssChdir(".") { + animfiles.concat(Dir.glob("*.anm")) + } + cmdwin=pbListWindow(animfiles,320) + cmdwin.opacity=200 + cmdwin.height=480 + cmdwin.viewport=canvas.viewport + loop do + Graphics.update + Input.update + cmdwin.update + if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) && animfiles.length>0 + begin + textdata=loadBase64Anim(IO.read(animfiles[cmdwin.index])) + throw "Bad data" if !textdata.is_a?(PBAnimation) + textdata.id=-1 # this is not an RPG Maker XP animation + pbConvertAnimToNewFormat(textdata) + animations[animations.selected]=textdata + rescue + pbMessage(_INTL("The animation is invalid or could not be loaded.")) + next + end + graphic=animations[animations.selected].graphic + graphic="Graphics/Animations/#{graphic}" + if graphic && graphic!="" && !FileTest.image_exist?(graphic) + pbMessage(_INTL("The animation file {1} was not found. The animation will load anyway.",graphic)) + end + canvas.loadAnimation(animations[animations.selected]) + animwin.animbitmap=canvas.animbitmap + break + end + if Input.trigger?(Input::B) + break + end + end + cmdwin.dispose + return +end + +################################################################################ +# Format conversion +################################################################################ +def pbConvertAnimToNewFormat(textdata) + needconverting=false + for i in 0...textdata.length + next if !textdata[i] + for j in 0...PBAnimation::MAX_SPRITES + next if !textdata[i][j] + needconverting=true if textdata[i][j][AnimFrame::FOCUS]==nil + break if needconverting + end + break if needconverting + end + if needconverting + for i in 0...textdata.length + next if !textdata[i] + for j in 0...PBAnimation::MAX_SPRITES + next if !textdata[i][j] + textdata[i][j][AnimFrame::PRIORITY]=1 if textdata[i][j][AnimFrame::PRIORITY]==nil + if j==0 # User battler + textdata[i][j][AnimFrame::FOCUS]=2 + textdata[i][j][AnimFrame::X]=PokeBattle_SceneConstants::FOCUSUSER_X + textdata[i][j][AnimFrame::Y]=PokeBattle_SceneConstants::FOCUSUSER_Y + elsif j==1 # Target battler + textdata[i][j][AnimFrame::FOCUS]=1 + textdata[i][j][AnimFrame::X]=PokeBattle_SceneConstants::FOCUSTARGET_X + textdata[i][j][AnimFrame::Y]=PokeBattle_SceneConstants::FOCUSTARGET_Y + else + textdata[i][j][AnimFrame::FOCUS]=(textdata.position || 4) + if textdata.position==1 + textdata[i][j][AnimFrame::X]+=PokeBattle_SceneConstants::FOCUSTARGET_X + textdata[i][j][AnimFrame::Y]+=PokeBattle_SceneConstants::FOCUSTARGET_Y-2 + end + end + end + end + end + return needconverting +end + +def pbConvertAnimsToNewFormat + pbMessage(_INTL("Will convert animations now.")) + count=0 + animations=pbLoadBattleAnimations + if !animations || !animations[0] + pbMessage(_INTL("No animations exist.")) + return + end + for k in 0...animations.length + next if !animations[k] + ret=pbConvertAnimToNewFormat(animations[k]) + count+=1 if ret + end + if count>0 + save_data(animations,"Data/PkmnAnimations.rxdata") + $PokemonTemp.battleAnims = nil + end + pbMessage(_INTL("{1} animations converted to new format.",count)) +end diff --git a/Data/Scripts/021_Debug/002_Animation editor/005_AnimEditor_Functions.rb b/Data/Scripts/021_Debug/002_Animation editor/005_AnimEditor_Functions.rb new file mode 100644 index 000000000..c083ac7bd --- /dev/null +++ b/Data/Scripts/021_Debug/002_Animation editor/005_AnimEditor_Functions.rb @@ -0,0 +1,1193 @@ +################################################################################ +# Mini battle scene +################################################################################ +class MiniBattler + attr_accessor :index + attr_accessor :pokemon + + def initialize(index); self.index=index; end +end + + + +class MiniBattle + attr_accessor :battlers + + def initialize + @battlers=[] + for i in 0...4; @battlers[i]=MiniBattler.new(i); end + end +end + + + +################################################################################ +# Pop-up menus for buttons in bottom menu +################################################################################ +def pbSelectAnim(canvas,animwin) + animfiles=[] + pbRgssChdir(".\\Graphics\\Animations\\") { + animfiles.concat(Dir.glob("*.png")) + } + cmdwin=pbListWindow(animfiles,320) + cmdwin.opacity=200 + cmdwin.height=512 + bmpwin=BitmapDisplayWindow.new(320,0,320,448) + ctlwin=ControlWindow.new(320,448,320,64) + cmdwin.viewport=canvas.viewport + bmpwin.viewport=canvas.viewport + ctlwin.viewport=canvas.viewport + ctlwin.addSlider(_INTL("Hue:"),0,359,0) + loop do + bmpwin.bitmapname=cmdwin.commands[cmdwin.index] + Graphics.update + Input.update + cmdwin.update + bmpwin.update + ctlwin.update + bmpwin.hue=ctlwin.value(0) if ctlwin.changed?(0) + if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) && animfiles.length>0 + bitmap=AnimatedBitmap.new("Graphics/Animations/"+cmdwin.commands[cmdwin.index],ctlwin.value(0)).deanimate + canvas.animation.graphic=cmdwin.commands[cmdwin.index] + canvas.animation.hue=ctlwin.value(0) + canvas.animbitmap=bitmap + animwin.animbitmap=bitmap + break + end + if Input.trigger?(Input::B) + break + end + end + bmpwin.dispose + cmdwin.dispose + ctlwin.dispose + return +end + +def pbChangeMaximum(canvas) + sliderwin2=ControlWindow.new(0,0,320,32*4) + sliderwin2.viewport=canvas.viewport + sliderwin2.addSlider(_INTL("Frames:"),1,1000,canvas.animation.length) + okbutton=sliderwin2.addButton(_INTL("OK")) + cancelbutton=sliderwin2.addButton(_INTL("Cancel")) + sliderwin2.opacity=200 + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + canvas.animation.resize(sliderwin2.value(0)) + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) + break + end + end + sliderwin2.dispose + return +end + +def pbAnimName(animation,cmdwin) + window=ControlWindow.new(320,128,320,32*4) + window.z=99999 + window.addControl(TextField.new(_INTL("New Name:"),animation.name)) + okbutton=window.addButton(_INTL("OK")) + cancelbutton=window.addButton(_INTL("Cancel")) + window.opacity=224 + loop do + Graphics.update + Input.update + window.update + if window.changed?(okbutton) || Input.trigger?(Input::ENTER) + cmdwin.commands[cmdwin.index]=_INTL("{1} {2}",cmdwin.index,window.controls[0].text) + animation.name=window.controls[0].text + break + end + if window.changed?(cancelbutton) || Input.trigger?(Input::ESC) + break + end + end + window.dispose + return +end + +def pbAnimList(animations,canvas,animwin) + commands=[] + for i in 0...animations.length + animations[i]=PBAnimation.new if !animations[i] + commands[commands.length]=_INTL("{1} {2}",i,animations[i].name) + end + cmdwin=pbListWindow(commands,320) + cmdwin.height=416 + cmdwin.opacity=224 + cmdwin.index=animations.selected + cmdwin.viewport=canvas.viewport + helpwindow=Window_UnformattedTextPokemon.newWithSize( + _INTL("C: Load/rename an animation\nEsc: Cancel"), + 320,0,320,128,canvas.viewport) + maxsizewindow=ControlWindow.new(0,416,320,32*3) + maxsizewindow.addSlider(_INTL("Total Animations:"),1,2000,animations.length) + maxsizewindow.addButton(_INTL("Resize Animation List")) + maxsizewindow.opacity=224 + maxsizewindow.viewport=canvas.viewport + loop do + Graphics.update + Input.update + cmdwin.update + maxsizewindow.update + helpwindow.update + if maxsizewindow.changed?(1) + newsize=maxsizewindow.value(0) + animations.resize(newsize) + commands.clear + for i in 0...animations.length + commands[commands.length]=_INTL("{1} {2}",i,animations[i].name) + end + cmdwin.commands=commands + cmdwin.index=animations.selected + next + end + if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) && animations.length>0 + cmd2=pbShowCommands(helpwindow,[ + _INTL("Load Animation"), + _INTL("Rename"), + _INTL("Delete") + ],-1) + if cmd2==0 # Load Animation + canvas.loadAnimation(animations[cmdwin.index]) + animwin.animbitmap=canvas.animbitmap + animations.selected=cmdwin.index + break + elsif cmd2==1 # Rename + pbAnimName(animations[cmdwin.index],cmdwin) + cmdwin.refresh + elsif cmd2==2 # Delete + if pbConfirmMessage(_INTL("Are you sure you want to delete this animation?")) + animations[cmdwin.index]=PBAnimation.new + cmdwin.commands[cmdwin.index]=_INTL("{1} {2}",cmdwin.index,animations[cmdwin.index].name) + cmdwin.refresh + end + end + end + if Input.trigger?(Input::B) + break + end + end + helpwindow.dispose + maxsizewindow.dispose + cmdwin.dispose +end + +################################################################################ +# Pop-up menus for individual cels +################################################################################ +def pbChooseNum(cel) + ret=cel + sliderwin2=ControlWindow.new(0,0,320,32*5) + sliderwin2.z=99999 + sliderwin2.addLabel(_INTL("Old Number: {1}",cel)) + sliderwin2.addSlider(_INTL("New Number:"),2,PBAnimation::MAX_SPRITES,cel) + okbutton=sliderwin2.addButton(_INTL("OK")) + cancelbutton=sliderwin2.addButton(_INTL("Cancel")) + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + ret=sliderwin2.value(1) + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) + ret=-1 + break + end + end + sliderwin2.dispose + return ret +end + +def pbSetTone(cel,previewsprite) + sliderwin2=ControlWindow.new(0,0,320,320) + sliderwin2.z=99999 + sliderwin2.addSlider(_INTL("Red Offset:"),-255,255,cel[AnimFrame::TONERED]) + sliderwin2.addSlider(_INTL("Green Offset:"),-255,255,cel[AnimFrame::TONEGREEN]) + sliderwin2.addSlider(_INTL("Blue Offset:"),-255,255,cel[AnimFrame::TONEBLUE]) + sliderwin2.addSlider(_INTL("Gray Tone:"),0,255,cel[AnimFrame::TONEGRAY]) + okbutton=sliderwin2.addButton(_INTL("OK")) + cancelbutton=sliderwin2.addButton(_INTL("Cancel")) + loop do + previewsprite.tone.set( + sliderwin2.value(0), + sliderwin2.value(1), + sliderwin2.value(2), + sliderwin2.value(3) + ) + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + cel[AnimFrame::TONERED]=sliderwin2.value(0) + cel[AnimFrame::TONEGREEN]=sliderwin2.value(1) + cel[AnimFrame::TONEBLUE]=sliderwin2.value(2) + cel[AnimFrame::TONEGRAY]=sliderwin2.value(3) + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) + break + end + end + sliderwin2.dispose + return +end + +def pbSetFlash(cel,previewsprite) + sliderwin2=ControlWindow.new(0,0,320,320) + sliderwin2.z=99999 + sliderwin2.addSlider(_INTL("Red:"),0,255,cel[AnimFrame::COLORRED]) + sliderwin2.addSlider(_INTL("Green:"),0,255,cel[AnimFrame::COLORGREEN]) + sliderwin2.addSlider(_INTL("Blue:"),0,255,cel[AnimFrame::COLORBLUE]) + sliderwin2.addSlider(_INTL("Alpha:"),0,255,cel[AnimFrame::COLORALPHA]) + okbutton=sliderwin2.addButton(_INTL("OK")) + cancelbutton=sliderwin2.addButton(_INTL("Cancel")) + loop do + previewsprite.tone.set( + sliderwin2.value(0), + sliderwin2.value(1), + sliderwin2.value(2), + sliderwin2.value(3) + ) + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + cel[AnimFrame::COLORRED]=sliderwin2.value(0) + cel[AnimFrame::COLORGREEN]=sliderwin2.value(1) + cel[AnimFrame::COLORBLUE]=sliderwin2.value(2) + cel[AnimFrame::COLORALPHA]=sliderwin2.value(3) + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) + break + end + end + sliderwin2.dispose + return +end + +def pbCellProperties(canvas) + cel=canvas.currentCel.clone # Clone cell, in case operation is canceled + return if !cel + sliderwin2=ControlWindow.new(0,0,320,32*16) + previewwin=ControlWindow.new(320,0,192,192) + sliderwin2.viewport=canvas.viewport + previewwin.viewport=canvas.viewport + previewsprite=Sprite.new(canvas.viewport) + previewsprite.bitmap=canvas.animbitmap + previewsprite.z=previewwin.z+1 + sliderwin2.z=previewwin.z+2 + set0=sliderwin2.addSlider(_INTL("Pattern:"),-2,1000,cel[AnimFrame::PATTERN]) + set1=sliderwin2.addSlider(_INTL("X:"),-64,512+64,cel[AnimFrame::X]) + set2=sliderwin2.addSlider(_INTL("Y:"),-64,384+64,cel[AnimFrame::Y]) + set3=sliderwin2.addSlider(_INTL("Zoom X:"),5,1000,cel[AnimFrame::ZOOMX]) + set4=sliderwin2.addSlider(_INTL("Zoom Y:"),5,1000,cel[AnimFrame::ZOOMY]) + set5=sliderwin2.addSlider(_INTL("Angle:"),0,359,cel[AnimFrame::ANGLE]) + set6=sliderwin2.addSlider(_INTL("Opacity:"),0,255,cel[AnimFrame::OPACITY]) + set7=sliderwin2.addSlider(_INTL("Blending:"),0,2,cel[AnimFrame::BLENDTYPE]) + set8=sliderwin2.addTextSlider(_INTL("Flip:"),[_INTL("False"),_INTL("True")],cel[AnimFrame::MIRROR]) + prio=[_INTL("Back"),_INTL("Front"),_INTL("Behind focus"),_INTL("Above focus")] + set9=sliderwin2.addTextSlider(_INTL("Priority:"),prio,cel[AnimFrame::PRIORITY] || 1) + foc=[_INTL("User"),_INTL("Target"),_INTL("User and target"),_INTL("Screen")] + curfoc=[3,1,0,2,3][cel[AnimFrame::FOCUS] || canvas.animation.position || 4] + set10=sliderwin2.addTextSlider(_INTL("Focus:"),foc,curfoc) + flashbutton=sliderwin2.addButton(_INTL("Set Blending Color")) + tonebutton=sliderwin2.addButton(_INTL("Set Color Tone")) + okbutton=sliderwin2.addButton(_INTL("OK")) + cancelbutton=sliderwin2.addButton(_INTL("Cancel")) + # Set X and Y for preview sprite + cel[AnimFrame::X]=320+96 + cel[AnimFrame::Y]=96 + canvas.setSpriteBitmap(previewsprite,cel) + pbSpriteSetAnimFrame(previewsprite,cel,nil,nil) + previewsprite.z=previewwin.z+1 + sliderwin2.opacity=200 + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(set0) || + sliderwin2.changed?(set3) || + sliderwin2.changed?(set4) || + sliderwin2.changed?(set5) || + sliderwin2.changed?(set6) || + sliderwin2.changed?(set7) || + sliderwin2.changed?(set8) || + sliderwin2.changed?(set9) || + sliderwin2.changed?(set10) + # Update preview sprite + cel[AnimFrame::PATTERN]=sliderwin2.value(set0) if set0>=0 + cel[AnimFrame::ZOOMX]=sliderwin2.value(set3) + cel[AnimFrame::ZOOMY]=sliderwin2.value(set4) + cel[AnimFrame::ANGLE]=sliderwin2.value(set5) + cel[AnimFrame::OPACITY]=sliderwin2.value(set6) + cel[AnimFrame::BLENDTYPE]=sliderwin2.value(set7) + cel[AnimFrame::MIRROR]=sliderwin2.value(set8) + cel[AnimFrame::PRIORITY]=sliderwin2.value(set9) + cel[AnimFrame::FOCUS]=[2,1,3,4][sliderwin2.value(set10)] + canvas.setSpriteBitmap(previewsprite,cel) + pbSpriteSetAnimFrame(previewsprite,cel,nil,nil) + previewsprite.z=previewwin.z+1 + end + if sliderwin2.changed?(flashbutton) + pbSetFlash(cel,previewsprite) + pbSpriteSetAnimFrame(previewsprite,cel,nil,nil) + previewsprite.z=previewwin.z+1 + end + if sliderwin2.changed?(tonebutton) + pbSetTone(cel,previewsprite) + pbSpriteSetAnimFrame(previewsprite,cel,nil,nil) + previewsprite.z=previewwin.z+1 + end + if sliderwin2.changed?(okbutton) + cel[AnimFrame::PATTERN]=sliderwin2.value(set0) if set0>=0 + cel[AnimFrame::X]=sliderwin2.value(set1) + cel[AnimFrame::Y]=sliderwin2.value(set2) + cel[AnimFrame::ZOOMX]=sliderwin2.value(set3) + cel[AnimFrame::ZOOMY]=sliderwin2.value(set4) + cel[AnimFrame::ANGLE]=sliderwin2.value(set5) + cel[AnimFrame::OPACITY]=sliderwin2.value(set6) + cel[AnimFrame::BLENDTYPE]=sliderwin2.value(set7) + cel[AnimFrame::MIRROR]=sliderwin2.value(set8) + cel[AnimFrame::PRIORITY]=sliderwin2.value(set9) + cel[AnimFrame::FOCUS]=[2,1,3,4][sliderwin2.value(set10)] + thiscel=canvas.currentCel + # Save by replacing current cell + thiscel[0,thiscel.length]=cel + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) + break + end + end + previewwin.dispose + previewsprite.dispose + sliderwin2.dispose + return +end + +################################################################################ +# Pop-up menus for buttons in right hand menu +################################################################################ +def pbTimingList(canvas) + commands=[] + cmdNewSound=-1 + cmdNewBG=-1 + cmdEditBG=-1 + cmdNewFO=-1 + cmdEditFO=-1 + for i in canvas.animation.timing + commands.push(sprintf("%s",i)) + end + commands[cmdNewSound=commands.length]=_INTL("Add: Play Sound...") + commands[cmdNewBG=commands.length]=_INTL("Add: Set Background Graphic...") + commands[cmdEditBG=commands.length]=_INTL("Add: Edit Background Color/Location...") + commands[cmdNewFO=commands.length]=_INTL("Add: Set Foreground Graphic...") + commands[cmdEditFO=commands.length]=_INTL("Add: Edit Foreground Color/Location...") + cmdwin=pbListWindow(commands,480) + cmdwin.x=0 + cmdwin.y=0 + cmdwin.width=640 + cmdwin.height=384 + cmdwin.opacity=200 + cmdwin.viewport=canvas.viewport + framewindow=ControlWindow.new(0,384,640,32*4) + framewindow.addSlider(_INTL("Frame:"),1,canvas.animation.length,canvas.currentframe+1) + framewindow.addButton(_INTL("Set Frame")) + framewindow.addButton(_INTL("Delete Timing")) + framewindow.opacity=200 + framewindow.viewport=canvas.viewport + loop do + Graphics.update + Input.update + cmdwin.update + framewindow.update + if cmdwin.index!=cmdNewSound && + cmdwin.index!=cmdNewBG && + cmdwin.index!=cmdEditBG && + cmdwin.index!=cmdNewFO && + cmdwin.index!=cmdEditFO + if framewindow.changed?(1) # Set Frame + canvas.animation.timing[cmdwin.index].frame=framewindow.value(0)-1 + cmdwin.commands[cmdwin.index]=sprintf("%s",canvas.animation.timing[cmdwin.index]) + cmdwin.refresh + next + end + if framewindow.changed?(2) # Delete Timing + canvas.animation.timing.delete_at(cmdwin.index) + cmdwin.commands.delete_at(cmdwin.index) + cmdNewSound-=1 if cmdNewSound>=0 + cmdNewBG-=1 if cmdNewBG>=0 + cmdEditBG-=1 if cmdEditBG>=0 + cmdNewFO-=1 if cmdNewFO>=0 + cmdEditFO-=1 if cmdEditFO>=0 + cmdwin.refresh + next + end + end + if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) + redrawcmds=false + if cmdwin.index==cmdNewSound # Add new sound + newaudio=PBAnimTiming.new(0) + if pbSelectSE(canvas,newaudio) + newaudio.frame=framewindow.value(0)-1 + canvas.animation.timing.push(newaudio) + redrawcmds=true + end + elsif cmdwin.index==cmdNewBG # Add new background graphic set + newtiming=PBAnimTiming.new(1) + if pbSelectBG(canvas,newtiming) + newtiming.frame=framewindow.value(0)-1 + canvas.animation.timing.push(newtiming) + redrawcmds=true + end + elsif cmdwin.index==cmdEditBG # Add new background edit + newtiming=PBAnimTiming.new(2) + if pbEditBG(canvas,newtiming) + newtiming.frame=framewindow.value(0)-1 + canvas.animation.timing.push(newtiming) + redrawcmds=true + end + elsif cmdwin.index==cmdNewFO # Add new foreground graphic set + newtiming=PBAnimTiming.new(3) + if pbSelectBG(canvas,newtiming) + newtiming.frame=framewindow.value(0)-1 + canvas.animation.timing.push(newtiming) + redrawcmds=true + end + elsif cmdwin.index==cmdEditFO # Add new foreground edit + newtiming=PBAnimTiming.new(4) + if pbEditBG(canvas,newtiming) + newtiming.frame=framewindow.value(0)-1 + canvas.animation.timing.push(newtiming) + redrawcmds=true + end + else + # Edit a timing here + case canvas.animation.timing[cmdwin.index].timingType + when 0 + pbSelectSE(canvas,canvas.animation.timing[cmdwin.index]) + when 1, 3 + pbSelectBG(canvas,canvas.animation.timing[cmdwin.index]) + when 2, 4 + pbEditBG(canvas,canvas.animation.timing[cmdwin.index]) + end + cmdwin.commands[cmdwin.index]=sprintf("%s",canvas.animation.timing[cmdwin.index]) + cmdwin.refresh + end + if redrawcmds + cmdwin.commands[cmdNewSound]=nil if cmdNewSound>=0 + cmdwin.commands[cmdNewBG]=nil if cmdNewBG>=0 + cmdwin.commands[cmdEditBG]=nil if cmdEditBG>=0 + cmdwin.commands[cmdNewFO]=nil if cmdNewFO>=0 + cmdwin.commands[cmdEditFO]=nil if cmdEditFO>=0 + cmdwin.commands.compact! + cmdwin.commands.push(sprintf("%s",canvas.animation.timing[canvas.animation.timing.length-1])) + cmdwin.commands[cmdNewSound=cmdwin.commands.length]=_INTL("Add: Play Sound...") + cmdwin.commands[cmdNewBG=cmdwin.commands.length]=_INTL("Add: Set Background Graphic...") + cmdwin.commands[cmdEditBG=cmdwin.commands.length]=_INTL("Add: Edit Background Color/Location...") + cmdwin.commands[cmdNewFO=cmdwin.commands.length]=_INTL("Add: Set Foreground Graphic...") + cmdwin.commands[cmdEditFO=cmdwin.commands.length]=_INTL("Add: Edit Foreground Color/Location...") + cmdwin.refresh + end + elsif Input.trigger?(Input::B) + break + end + end + cmdwin.dispose + framewindow.dispose + return +end + +def pbSelectSE(canvas,audio) + filename=(audio.name!="") ? audio.name : "" + displayname=(filename!="") ? filename : _INTL("") + animfiles=[] + ret=false + pbRgssChdir(".\\Audio\\SE\\Anim\\") { + animfiles.concat(Dir.glob("*.wav")) + animfiles.concat(Dir.glob("*.mp3")) + animfiles.concat(Dir.glob("*.ogg")) + animfiles.concat(Dir.glob("*.wma")) + } + animfiles.sort! { |a,b| a.upcase<=>b.upcase } + animfiles=[_INTL("[Play user's cry]")]+animfiles + cmdwin=pbListWindow(animfiles,320) + cmdwin.height=480 + cmdwin.opacity=200 + cmdwin.viewport=canvas.viewport + maxsizewindow=ControlWindow.new(320,0,320,32*8) + maxsizewindow.addLabel(_INTL("File: \"{1}\"",displayname)) + maxsizewindow.addSlider(_INTL("Volume:"),0,100,audio.volume) + maxsizewindow.addSlider(_INTL("Pitch:"),20,250,audio.pitch) + maxsizewindow.addButton(_INTL("Play Sound")) + maxsizewindow.addButton(_INTL("Stop Sound")) + maxsizewindow.addButton(_INTL("OK")) + maxsizewindow.addButton(_INTL("Cancel")) + maxsizewindow.opacity=200 + maxsizewindow.viewport=canvas.viewport + loop do + Graphics.update + Input.update + cmdwin.update + maxsizewindow.update + if maxsizewindow.changed?(3) && animfiles.length>0 # Play Sound + fname = (cmdwin.index==0) ? "Cries/001Cry" : "Anim/"+filename + pbSEPlay(RPG::AudioFile.new(fname,maxsizewindow.value(1),maxsizewindow.value(2))) + end + if maxsizewindow.changed?(4) && animfiles.length>0 # Stop Sound + pbSEStop + end + if maxsizewindow.changed?(5) # OK + filename = File.basename(filename,".wav") + filename = File.basename(filename,".mp3") + filename = File.basename(filename,".ogg") + filename = File.basename(filename,".wma") + audio.name=filename + audio.volume=maxsizewindow.value(1) + audio.pitch=maxsizewindow.value(2) + ret=true + break + end + if maxsizewindow.changed?(6) # Cancel + break + end + if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) && animfiles.length>0 + filename=(cmdwin.index==0) ? "" : cmdwin.commands[cmdwin.index] + displayname=(filename!="") ? filename : _INTL("") + maxsizewindow.controls[0].text=_INTL("File: \"{1}\"",displayname) + elsif Input.trigger?(Input::B) + break + end + end + cmdwin.dispose + maxsizewindow.dispose + return ret +end + +def pbSelectBG(canvas,timing) + filename=timing.name + cmdErase=-1 + animfiles=[] + animfiles[cmdErase=animfiles.length]=_INTL("[Erase background graphic]") + ret=false + pbRgssChdir(".\\Graphics\\Animations\\") { + animfiles.concat(Dir.glob("*.bmp")) + animfiles.concat(Dir.glob("*.png")) + animfiles.concat(Dir.glob("*.jpg")) + animfiles.concat(Dir.glob("*.jpeg")) + animfiles.concat(Dir.glob("*.gif")) + } + cmdwin=pbListWindow(animfiles,320) + cmdwin.height=480 + cmdwin.opacity=200 + cmdwin.viewport=canvas.viewport + maxsizewindow=ControlWindow.new(320,0,320,32*11) + maxsizewindow.addLabel(_INTL("File: \"{1}\"",filename)) + maxsizewindow.addSlider(_INTL("X:"),-500,500,timing.bgX || 0) + maxsizewindow.addSlider(_INTL("Y:"),-500,500,timing.bgY || 0) + maxsizewindow.addSlider(_INTL("Opacity:"),0,255,timing.opacity || 0) + maxsizewindow.addSlider(_INTL("Red:"),0,255,timing.colorRed || 0) + maxsizewindow.addSlider(_INTL("Green:"),0,255,timing.colorGreen || 0) + maxsizewindow.addSlider(_INTL("Blue:"),0,255,timing.colorBlue || 0) + maxsizewindow.addSlider(_INTL("Alpha:"),0,255,timing.colorAlpha || 0) + maxsizewindow.addButton(_INTL("OK")) + maxsizewindow.addButton(_INTL("Cancel")) + maxsizewindow.opacity=200 + maxsizewindow.viewport=canvas.viewport + loop do + Graphics.update + Input.update + cmdwin.update + maxsizewindow.update + if maxsizewindow.changed?(8) # OK + timing.name=filename + timing.bgX=maxsizewindow.value(1) + timing.bgY=maxsizewindow.value(2) + timing.opacity=maxsizewindow.value(3) + timing.colorRed=maxsizewindow.value(4) + timing.colorGreen=maxsizewindow.value(5) + timing.colorBlue=maxsizewindow.value(6) + timing.colorAlpha=maxsizewindow.value(7) + ret=true + break + end + if maxsizewindow.changed?(9) # Cancel + break + end + if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) && animfiles.length>0 + filename=(cmdwin.index==cmdErase) ? "" : cmdwin.commands[cmdwin.index] + maxsizewindow.controls[0].text=_INTL("File: \"{1}\"",filename) + elsif Input.trigger?(Input::B) + break + end + end + cmdwin.dispose + maxsizewindow.dispose + return ret +end + +def pbEditBG(canvas,timing) + ret=false + maxsizewindow=ControlWindow.new(0,0,320,32*11) + maxsizewindow.addSlider(_INTL("Duration:"),0,50,timing.duration) + maxsizewindow.addOptionalSlider(_INTL("X:"),-500,500,timing.bgX || 0) + maxsizewindow.addOptionalSlider(_INTL("Y:"),-500,500,timing.bgY || 0) + maxsizewindow.addOptionalSlider(_INTL("Opacity:"),0,255,timing.opacity || 0) + maxsizewindow.addOptionalSlider(_INTL("Red:"),0,255,timing.colorRed || 0) + maxsizewindow.addOptionalSlider(_INTL("Green:"),0,255,timing.colorGreen || 0) + maxsizewindow.addOptionalSlider(_INTL("Blue:"),0,255,timing.colorBlue || 0) + maxsizewindow.addOptionalSlider(_INTL("Alpha:"),0,255,timing.colorAlpha || 0) + maxsizewindow.addButton(_INTL("OK")) + maxsizewindow.addButton(_INTL("Cancel")) + maxsizewindow.controls[1].checked=(timing.bgX!=nil) + maxsizewindow.controls[2].checked=(timing.bgY!=nil) + maxsizewindow.controls[3].checked=(timing.opacity!=nil) + maxsizewindow.controls[4].checked=(timing.colorRed!=nil) + maxsizewindow.controls[5].checked=(timing.colorGreen!=nil) + maxsizewindow.controls[6].checked=(timing.colorBlue!=nil) + maxsizewindow.controls[7].checked=(timing.colorAlpha!=nil) + maxsizewindow.opacity=200 + maxsizewindow.viewport=canvas.viewport + loop do + Graphics.update + Input.update + maxsizewindow.update + if maxsizewindow.changed?(8) # OK + if maxsizewindow.controls[1].checked || + maxsizewindow.controls[2].checked || + maxsizewindow.controls[3].checked || + maxsizewindow.controls[4].checked || + maxsizewindow.controls[5].checked || + maxsizewindow.controls[6].checked || + maxsizewindow.controls[7].checked + timing.duration=maxsizewindow.value(0) + timing.bgX=maxsizewindow.value(1) + timing.bgY=maxsizewindow.value(2) + timing.opacity=maxsizewindow.value(3) + timing.colorRed=maxsizewindow.value(4) + timing.colorGreen=maxsizewindow.value(5) + timing.colorBlue=maxsizewindow.value(6) + timing.colorAlpha=maxsizewindow.value(7) + ret=true + break + else + break + end + end + if maxsizewindow.changed?(9) # Cancel + break + end + if Input.trigger?(Input::B) + break + end + end + maxsizewindow.dispose + return ret +end + +def pbCopyFrames(canvas) + sliderwin2=ControlWindow.new(0,0,320,32*6) + sliderwin2.viewport=canvas.viewport + sliderwin2.addSlider(_INTL("First Frame:"),1,canvas.animation.length,1) + sliderwin2.addSlider(_INTL("Last Frame:"),1,canvas.animation.length,canvas.animation.length) + sliderwin2.addSlider(_INTL("Copy to:"),1,canvas.animation.length,canvas.currentframe+1) + okbutton=sliderwin2.addButton(_INTL("OK")) + cancelbutton=sliderwin2.addButton(_INTL("Cancel")) + sliderwin2.opacity=200 + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + startvalue=sliderwin2.value(0)-1 + endvalue=sliderwin2.value(1)-1 + dstvalue=sliderwin2.value(2)-1 + length=(endvalue-startvalue)+1 + if length>0 # Ensure correct overlap handling + if (startvalue=endframe + frames=endframe-startframe + startcel=sliderwin2.value(s1set2) + endcel=sliderwin2.value(s1set3) + for j in startcel..endcel + cel1=canvas.animation[startframe][j] + cel2=canvas.animation[endframe][j] + next if !cel1||!cel2 + diffPattern=cel2[AnimFrame::PATTERN]-cel1[AnimFrame::PATTERN] + diffX=cel2[AnimFrame::X]-cel1[AnimFrame::X] + diffY=cel2[AnimFrame::Y]-cel1[AnimFrame::Y] + diffZoomX=cel2[AnimFrame::ZOOMX]-cel1[AnimFrame::ZOOMX] + diffZoomY=cel2[AnimFrame::ZOOMY]-cel1[AnimFrame::ZOOMY] + diffAngle=cel2[AnimFrame::ANGLE]-cel1[AnimFrame::ANGLE] + diffOpacity=cel2[AnimFrame::OPACITY]-cel1[AnimFrame::OPACITY] + diffBlend=cel2[AnimFrame::BLENDTYPE]-cel1[AnimFrame::BLENDTYPE] + startPattern=cel1[AnimFrame::PATTERN] + startX=cel1[AnimFrame::X] + startY=cel1[AnimFrame::Y] + startZoomX=cel1[AnimFrame::ZOOMX] + startZoomY=cel1[AnimFrame::ZOOMY] + startAngle=cel1[AnimFrame::ANGLE] + startOpacity=cel1[AnimFrame::OPACITY] + startBlend=cel1[AnimFrame::BLENDTYPE] + for k in 0..frames + cel=canvas.animation[startframe+k][j] + curcel=cel + if !cel + cel=pbCreateCel(0,0,0) + canvas.animation[startframe+k][j]=cel + end + if sliderwin2.value(set0) || !curcel + cel[AnimFrame::PATTERN]=startPattern+(diffPattern*k/frames) + end + if sliderwin2.value(set1) || !curcel + cel[AnimFrame::X]=startX+(diffX*k/frames) + cel[AnimFrame::Y]=startY+(diffY*k/frames) + cel[AnimFrame::ZOOMX]=startZoomX+(diffZoomX*k/frames) + cel[AnimFrame::ZOOMY]=startZoomY+(diffZoomY*k/frames) + cel[AnimFrame::ANGLE]=startAngle+(diffAngle*k/frames) + end + if sliderwin2.value(set2) || !curcel + cel[AnimFrame::OPACITY]=startOpacity+(diffOpacity*k/frames) + cel[AnimFrame::BLENDTYPE]=startBlend+(diffBlend*k/frames) + end + end + end + canvas.invalidate + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) + break + end + end + sliderwin2.dispose +end + +def pbCellBatch(canvas) + sliderwin1=ControlWindow.new(0,0,300,32*5) + sliderwin1.viewport=canvas.viewport + sliderwin1.opacity=200 + s1set0=sliderwin1.addSlider(_INTL("First Frame:"),1,canvas.animation.length,1) + s1set1=sliderwin1.addSlider(_INTL("Last Frame:"),1,canvas.animation.length,canvas.animation.length) + s1set2=sliderwin1.addSlider(_INTL("First Cel:"),0,PBAnimation::MAX_SPRITES-1,0) + s1set3=sliderwin1.addSlider(_INTL("Last Cel:"),0,PBAnimation::MAX_SPRITES-1,PBAnimation::MAX_SPRITES-1) + sliderwin2=ControlWindow.new(300,0,340,32*14) + sliderwin2.viewport=canvas.viewport + sliderwin2.opacity=200 + set0=sliderwin2.addOptionalSlider(_INTL("Pattern:"),-2,1000,0) + set1=sliderwin2.addOptionalSlider(_INTL("X:"),-64,512+64,0) + set2=sliderwin2.addOptionalSlider(_INTL("Y:"),-64,384+64,0) + set3=sliderwin2.addOptionalSlider(_INTL("Zoom X:"),5,1000,100) + set4=sliderwin2.addOptionalSlider(_INTL("Zoom Y:"),5,1000,100) + set5=sliderwin2.addOptionalSlider(_INTL("Angle:"),0,359,0) + set6=sliderwin2.addOptionalSlider(_INTL("Opacity:"),0,255,255) + set7=sliderwin2.addOptionalSlider(_INTL("Blending:"),0,2,0) + set8=sliderwin2.addOptionalTextSlider(_INTL("Flip:"),[_INTL("False"),_INTL("True")],0) + prio=[_INTL("Back"),_INTL("Front"),_INTL("Behind focus"),_INTL("Above focus")] + set9=sliderwin2.addOptionalTextSlider(_INTL("Priority:"),prio,1) + foc=[_INTL("User"),_INTL("Target"),_INTL("User and target"),_INTL("Screen")] + curfoc=[3,1,0,2,3][canvas.animation.position || 4] + set10=sliderwin2.addOptionalTextSlider(_INTL("Focus:"),foc,curfoc) + okbutton=sliderwin2.addButton(_INTL("OK")) + cancelbutton=sliderwin2.addButton(_INTL("Cancel")) + loop do + Graphics.update + Input.update + sliderwin1.update + sliderwin2.update + if sliderwin2.changed?(okbutton) || Input.trigger?(Input::C) + startframe=sliderwin1.value(s1set0)-1 + endframe=sliderwin1.value(s1set1)-1 + startcel=sliderwin1.value(s1set2) + endcel=sliderwin1.value(s1set3) + for i in startframe..endframe + for j in startcel..endcel + next if !canvas.animation[i][j] + cel=canvas.animation[i][j] + cel[AnimFrame::PATTERN]=sliderwin2.value(set0) if sliderwin2.value(set0) + cel[AnimFrame::X]=sliderwin2.value(set1) if sliderwin2.value(set1) + cel[AnimFrame::Y]=sliderwin2.value(set2) if sliderwin2.value(set2) + cel[AnimFrame::ZOOMX]=sliderwin2.value(set3) if sliderwin2.value(set3) + cel[AnimFrame::ZOOMY]=sliderwin2.value(set4) if sliderwin2.value(set4) + cel[AnimFrame::ANGLE]=sliderwin2.value(set5) if sliderwin2.value(set5) + cel[AnimFrame::OPACITY]=sliderwin2.value(set6) if sliderwin2.value(set6) + cel[AnimFrame::BLENDTYPE]=sliderwin2.value(set7) if sliderwin2.value(set7) + cel[AnimFrame::MIRROR]=sliderwin2.value(set8) if sliderwin2.value(set8) + cel[AnimFrame::PRIORITY]=sliderwin2.value(set9) if sliderwin2.value(set9) + cel[AnimFrame::FOCUS]=[2,1,3,4][sliderwin2.value(set10)] if sliderwin2.value(set10) + end + end + canvas.invalidate + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) + break + end + end + sliderwin1.dispose + sliderwin2.dispose +end + +def pbEntireSlide(canvas) + sliderwin2=ControlWindow.new(0,0,320,32*7) + sliderwin2.viewport=canvas.viewport + sliderwin2.addSlider(_INTL("First Frame:"),1,canvas.animation.length,1) + sliderwin2.addSlider(_INTL("Last Frame:"),1,canvas.animation.length,canvas.animation.length) + sliderwin2.addSlider(_INTL("X-Axis Movement"),-500,500,0) + sliderwin2.addSlider(_INTL("Y-Axis Movement"),-500,500,0) + okbutton=sliderwin2.addButton(_INTL("OK")) + cancelbutton=sliderwin2.addButton(_INTL("Cancel")) + sliderwin2.opacity=200 + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + startvalue=sliderwin2.value(0)-1 + endvalue=sliderwin2.value(1)-1 + xoffset=sliderwin2.value(2) + yoffset=sliderwin2.value(3) + for i in startvalue..endvalue + canvas.offsetFrame(i,xoffset,yoffset) + end + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) + break + end + end + sliderwin2.dispose + return +end + +def pbAnimEditorHelpWindow + helptext=""+ + "To add a cel to the scene, click on the canvas. The selected cel will have a black "+ + "frame. After a cel is selected, you can modify its properties using the keyboard:\n"+ + "E, R - Rotate left/right;\nP - Open properties screen;\nArrow keys - Move cel 8 pixels "+ + "(hold ALT for 2 pixels);\n+/- : Zoom in/out;\nL - Lock a cel. Locking a cel prevents it "+ + "from being moved or deleted.\nDEL - Deletes the cel.\nAlso press TAB to switch the selected cel." + cmdwin=Window_UnformattedTextPokemon.newWithSize("",0,0,640,512) + cmdwin.opacity=224 + cmdwin.z=99999 + cmdwin.text=helptext + loop do + Graphics.update + Input.update + cmdwin.update + break if Input.trigger?(Input::B) || Input.trigger?(Input::C) + end + cmdwin.dispose +end + +################################################################################ +# Main +################################################################################ +def animationEditorMain(animation) + viewport=Viewport.new(0, 0, SCREEN_WIDTH + 288, SCREEN_HEIGHT + 288) + viewport.z=99999 + # Canvas + canvas=AnimationCanvas.new(animation[animation.selected],viewport) + # Right hand menu + sidewin=ControlWindow.new(512+128,0,160,384+128) + sidewin.addButton(_INTL("SE and BG...")) + sidewin.addButton(_INTL("Cel Focus...")) + sidewin.addSpace + sidewin.addButton(_INTL("Paste Last")) + sidewin.addButton(_INTL("Copy Frames...")) + sidewin.addButton(_INTL("Clear Frames...")) + sidewin.addButton(_INTL("Tweening...")) + sidewin.addButton(_INTL("Cel Batch...")) + sidewin.addButton(_INTL("Entire Slide...")) + sidewin.addSpace + sidewin.addButton(_INTL("Play Animation")) + sidewin.addButton(_INTL("Play Opp Anim")) + sidewin.addButton(_INTL("Import Anim...")) + sidewin.addButton(_INTL("Export Anim...")) + sidewin.addButton(_INTL("Help")) + sidewin.viewport=canvas.viewport + # Bottom left menu + sliderwin=ControlWindow.new(0,384+128,240,160) + sliderwin.addControl(FrameCountSlider.new(canvas)) + sliderwin.addControl(FrameCountButton.new(canvas)) + sliderwin.addButton(_INTL("Set Animation Sheet")) + sliderwin.addButton(_INTL("List of Animations")) + sliderwin.viewport=canvas.viewport + # Animation sheet window + animwin=CanvasAnimationWindow.new(canvas,240,384+128,512,96,canvas.viewport) + # Name window + bottomwindow=AnimationNameWindow.new(canvas,240,384+128+96,512,64,canvas.viewport) + loop do + Graphics.update + Input.update + sliderwin.update + canvas.update + sidewin.update + animwin.update + bottomwindow.update + if animwin.changed? + canvas.pattern=animwin.selected + end + if Input.trigger?(Input::B) + if pbConfirmMessage(_INTL("Save changes?")) + save_data(animation,"Data/PkmnAnimations.rxdata") + $PokemonTemp.battleAnims = nil + end + if pbConfirmMessage(_INTL("Exit from the editor?")) + break + end + end + if Input.trigger?(Input::ONLYF5) + pbAnimEditorHelpWindow + next + elsif Input.triggerex?(Input::RightMouseKey) && sliderwin.hittest?(0) # Right mouse button + commands=[ + _INTL("Copy Frame"), + _INTL("Paste Frame"), + _INTL("Clear Frame"), + _INTL("Insert Frame"), + _INTL("Delete Frame") + ] + hit=pbTrackPopupMenu(commands) + case hit + when 0 # Copy + if canvas.currentframe>=0 + Clipboard.setData(canvas.animation[canvas.currentframe],"PBAnimFrame") + end + when 1 # Paste + if canvas.currentframe>=0 + canvas.pasteFrame(canvas.currentframe) + end + when 2 # Clear Frame + canvas.clearFrame(canvas.currentframe) + when 3 # Insert Frame + canvas.insertFrame(canvas.currentframe) + sliderwin.invalidate + when 4 # Delete Frame + canvas.deleteFrame(canvas.currentframe) + sliderwin.controls[0].curvalue=canvas.currentframe+1 + sliderwin.invalidate + end + next + elsif Input.triggerex?(0x51) # Q + if canvas.currentCel + pbDefinePath(canvas) + sliderwin.invalidate + end + next + elsif Input.triggerex?(Input::RightMouseKey) # Right mouse button + mousepos=Mouse::getMousePos + mousepos=[0,0] if !mousepos + commands=[ + _INTL("Properties..."), + _INTL("Cut"), + _INTL("Copy"), + _INTL("Paste"), + _INTL("Delete"), + _INTL("Renumber..."), + _INTL("Extrapolate Path...") + ] + hit=pbTrackPopupMenu(commands) + case hit + when 0 # Properties + if canvas.currentCel + pbCellProperties(canvas) + canvas.invalidateCel(canvas.currentcel) + end + when 1 # Cut + if canvas.currentCel + Clipboard.setData(canvas.currentCel,"PBAnimCel") + canvas.deleteCel(canvas.currentcel) + end + when 2 # Copy + if canvas.currentCel + Clipboard.setData(canvas.currentCel,"PBAnimCel") + end + when 3 # Paste + canvas.pasteCel(mousepos[0],mousepos[1]) + when 4 # Delete + canvas.deleteCel(canvas.currentcel) + when 5 # Renumber + if canvas.currentcel && canvas.currentcel>=2 + cel1=canvas.currentcel + cel2=pbChooseNum(cel1) + if cel2>=2 && cel1!=cel2 + canvas.swapCels(cel1,cel2) + end + end + when 6 # Extrapolate Path + if canvas.currentCel + pbDefinePath(canvas) + sliderwin.invalidate + end + end + next + end + if sliderwin.changed?(0) # Current frame changed + canvas.currentframe=sliderwin.value(0)-1 + end + if sliderwin.changed?(1) # Change frame count + pbChangeMaximum(canvas) + sliderwin.refresh + end + if sliderwin.changed?(2) # Set Animation Sheet + pbSelectAnim(canvas,animwin) + animwin.refresh + sliderwin.refresh + end + if sliderwin.changed?(3) # List of Animations + pbAnimList(animation,canvas,animwin) + sliderwin.controls[0].curvalue=canvas.currentframe+1 + bottomwindow.refresh + animwin.refresh + sliderwin.refresh + end + pbTimingList(canvas) if sidewin.changed?(0) + if sidewin.changed?(1) + positions=[_INTL("User"),_INTL("Target"),_INTL("User and target"),_INTL("Screen")] + indexes=[2,1,3,4] # Keeping backwards compatibility + for i in 0...positions.length + selected="[ ]" + if animation[animation.selected].position==indexes[i] + selected="[x]" + end + positions[i]=sprintf("%s %s",selected,positions[i]) + end + pos=pbShowCommands(nil,positions,-1) + if pos>=0 + animation[animation.selected].position=indexes[pos] + canvas.update + end + end + canvas.pasteLast if sidewin.changed?(3) + pbCopyFrames(canvas) if sidewin.changed?(4) + pbClearFrames(canvas) if sidewin.changed?(5) + pbTweening(canvas) if sidewin.changed?(6) + pbCellBatch(canvas) if sidewin.changed?(7) + pbEntireSlide(canvas) if sidewin.changed?(8) + canvas.play if sidewin.changed?(10) + canvas.play(true) if sidewin.changed?(11) + if sidewin.changed?(12) + pbImportAnim(animation,canvas,animwin) + sliderwin.controls[0].curvalue=canvas.currentframe+1 + bottomwindow.refresh + animwin.refresh + sliderwin.refresh + end + if sidewin.changed?(13) + pbExportAnim(animation) + bottomwindow.refresh + animwin.refresh + sliderwin.refresh + end + pbAnimEditorHelpWindow if sidewin.changed?(14) + end + canvas.dispose + animwin.dispose + sliderwin.dispose + sidewin.dispose + bottomwindow.dispose + viewport.dispose + GC.start +end + +################################################################################ +# Start +################################################################################ +def pbAnimationEditor + pbBGMStop() + animation=pbLoadBattleAnimations + if !animation || !animation[0] + animation=PBAnimations.new + animation[0].graphic="" + end + Graphics.resize_screen(SCREEN_WIDTH + 288, SCREEN_HEIGHT + 288) + pbSetResizeFactor(1) + animationEditorMain(animation) + Graphics.resize_screen(SCREEN_WIDTH, SCREEN_HEIGHT) + pbSetResizeFactor($PokemonSystem.screensize) + $game_map.autoplay if $game_map +end diff --git a/Data/Scripts/021_Debug/004_Editor_Screens.rb b/Data/Scripts/021_Debug/004_Editor_Screens.rb index 1f8111846..0d93676d3 100644 --- a/Data/Scripts/021_Debug/004_Editor_Screens.rb +++ b/Data/Scripts/021_Debug/004_Editor_Screens.rb @@ -626,7 +626,7 @@ def pbEditMetadata(map_id = 0) GameData::MapMetadata::DATA[map_id] = GameData::MapMetadata.new(metadata_hash) GameData::MapMetadata.save end - pbSaveMetadata + Compiler.write_metadata end end @@ -671,7 +671,7 @@ def pbItemEditor GameData::Item::DATA.delete(item) GameData::Item::DATA.delete(id_number) GameData::Item.save - pbSaveItems + Compiler.write_items pbMessage(_INTL("The item was deleted.")) end end @@ -708,7 +708,7 @@ def pbItemEditor # Add item's data to records GameData::Item::DATA[itm.id_number] = GameData::Item::DATA[itm.id] = GameData::Item.new(item_hash) GameData::Item.save - pbSaveItems + Compiler.write_items end else # Add a new item pbItemEditorNew(nil) @@ -772,7 +772,7 @@ def pbItemEditorNew(default_name) # Add item's data to records GameData::Item::DATA[id_number] = GameData::Item::DATA[id.to_sym] = GameData::Item.new(item_hash) GameData::Item.save - pbSaveItems + Compiler.write_items pbMessage(_INTL("The item {1} was created (ID: {2}).", name, id.to_s)) pbMessage(_ISPRINTF("Put the item's graphic (item{1:s}.png or item{2:03d}.png) in Graphics/Icons, or it will be blank.", id, id_number)) @@ -857,7 +857,7 @@ def pbPokemonEditor GameData::Species::DATA.delete(species) GameData::Species::DATA.delete(id_number) GameData::Species.save - pbSavePokemonData + Compiler.write_pokemon pbMessage(_INTL("The species was deleted.")) end end @@ -971,7 +971,7 @@ def pbPokemonEditor # Add species' data to records GameData::Species::DATA[spec.id_number] = GameData::Species::DATA[spec.id] = GameData::Species.new(species_hash) GameData::Species.save - pbSavePokemonData + Compiler.write_pokemon pbMessage(_INTL("Data saved.")) end else @@ -1178,7 +1178,7 @@ def pbRegionalDexEditorMain when 0 # Save all changes to Dexes save_data(dex_lists, "Data/regional_dexes.dat") $PokemonTemp.regionalDexes = nil - pbSaveRegionalDexes + Compiler.write_regional_dexes pbMessage(_INTL("Data saved.")) break when 1 # Just quit diff --git a/Data/Scripts/021_Debug/005_Editor_SaveData.rb b/Data/Scripts/021_Debug/005_Editor_SaveData.rb deleted file mode 100644 index 8bdc94b5d..000000000 --- a/Data/Scripts/021_Debug/005_Editor_SaveData.rb +++ /dev/null @@ -1,870 +0,0 @@ -#=============================================================================== -# Save type data to PBS file -#=============================================================================== -def pbSaveTypes - File.open("PBS/types.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.") + "\r\n") - # Write each type in turn - GameData::Type.each do |type| - f.write("\#-------------------------------\r\n") - f.write("[#{type.id_number}]\r\n") - f.write("Name = #{type.real_name}\r\n") - f.write("InternalName = #{type.id.to_s}\r\n") - f.write("IsPseudoType = true\r\n") if type.pseudo_type - f.write("IsSpecialType = true\r\n") if type.special? - f.write("Weaknesses = #{type.weaknesses.join(",")}\r\n") if type.weaknesses.length > 0 - f.write("Resistances = #{type.resistances.join(",")}\r\n") if type.resistances.length > 0 - f.write("Immunities = #{type.immunities.join(",")}\r\n") if type.immunities.length > 0 - end - } -end - -#=============================================================================== -# Save ability data to PBS file -#=============================================================================== -def pbSaveAbilities - File.open("PBS/abilities.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.") + "\r\n") - f.write("\#-------------------------------\r\n") - GameData::Ability.each do |a| - f.write(sprintf("%d,%s,%s,%s\r\n", - a.id_number, - csvQuote(a.id.to_s), - csvQuote(a.real_name), - csvQuoteAlways(a.real_description) - )) - end - } -end - -#=============================================================================== -# Save move data to PBS file -#=============================================================================== -def pbSaveMoveData - File.open("PBS/moves.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.") + "\r\n") - current_type = -1 - GameData::Move.each do |m| - if current_type != m.type - current_type = m.type - f.write("\#-------------------------------\r\n") - end - f.write(sprintf("%d,%s,%s,%s,%d,%s,%s,%d,%d,%d,%s,%d,%s,%s\r\n", - m.id_number, - csvQuote(m.id.to_s), - csvQuote(m.real_name), - csvQuote(m.function_code), - m.base_damage, - m.type.to_s, - ["Physical", "Special", "Status"][m.category], - m.accuracy, - m.total_pp, - m.effect_chance, - (getConstantName(PBTargets, m.target) rescue sprintf("%d", m.target)), - m.priority, - csvQuote(m.flags), - csvQuoteAlways(m.real_description) - )) - end - } -end - -#=============================================================================== -# Save map connection data to PBS file -#=============================================================================== -def normalizeConnectionPoint(conn) - ret = conn.clone - if conn[1]<0 && conn[4]<0 - elsif conn[1]<0 || conn[4]<0 - ret[4] = -conn[1] - ret[1] = -conn[4] - end - if conn[2]<0 && conn[5]<0 - elsif conn[2]<0 || conn[5]<0 - ret[5] = -conn[2] - ret[2] = -conn[5] - end - return ret -end - -def writeConnectionPoint(map1,x1,y1,map2,x2,y2) - dims1 = MapFactoryHelper.getMapDims(map1) - dims2 = MapFactoryHelper.getMapDims(map2) - if x1==0 && x2==dims2[0] - return sprintf("%d,West,%d,%d,East,%d",map1,y1,map2,y2) - elsif y1==0 && y2==dims2[1] - return sprintf("%d,North,%d,%d,South,%d",map1,x1,map2,x2) - elsif x1==dims1[0] && x2==0 - return sprintf("%d,East,%d,%d,West,%d",map1,y1,map2,y2) - elsif y1==dims1[1] && y2==0 - return sprintf("%d,South,%d,%d,North,%d",map1,x1,map2,x2) - end - return sprintf("%d,%d,%d,%d,%d,%d",map1,x1,y1,map2,x2,y2) -end - -def pbSerializeConnectionData(conndata,mapinfos) - File.open("PBS/connections.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.") + "\r\n") - f.write("\#-------------------------------\r\n") - for conn in conndata - if mapinfos - # Skip if map no longer exists - next if !mapinfos[conn[0]] || !mapinfos[conn[3]] - f.write(sprintf("# %s (%d) - %s (%d)\r\n", - mapinfos[conn[0]] ? mapinfos[conn[0]].name : "???",conn[0], - mapinfos[conn[3]] ? mapinfos[conn[3]].name : "???",conn[3])) - end - if conn[1].is_a?(String) || conn[4].is_a?(String) - f.write(sprintf("%d,%s,%d,%d,%s,%d",conn[0],conn[1], - conn[2],conn[3],conn[4],conn[5])) - else - ret = normalizeConnectionPoint(conn) - f.write(writeConnectionPoint(ret[0],ret[1],ret[2],ret[3],ret[4],ret[5])) - end - f.write("\r\n") - end - } - save_data(conndata,"Data/map_connections.dat") -end - -def pbSaveConnectionData - data = load_data("Data/map_connections.dat") rescue nil - return if !data - pbSerializeConnectionData(data,pbLoadRxData("Data/MapInfos")) -end - -#=============================================================================== -# Save metadata data to PBS file -#=============================================================================== -def pbSaveMetadata - File.open("PBS/metadata.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.") + "\r\n") - # Write global metadata - f.write("\#-------------------------------\r\n") - f.write("[000]\r\n") - metadata = GameData::Metadata.get - schema = GameData::Metadata::SCHEMA - keys = schema.keys.sort {|a, b| schema[a][0] <=> schema[b][0] } - for key in keys - record = metadata.property_from_string(key) - next if record.nil? - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(record, f, schema[key]) - f.write("\r\n") - end - # Write map metadata - map_infos = pbLoadRxData("Data/MapInfos") - schema = GameData::MapMetadata::SCHEMA - keys = schema.keys.sort {|a, b| schema[a][0] <=> schema[b][0] } - GameData::MapMetadata.each do |map_data| - f.write("\#-------------------------------\r\n") - f.write(sprintf("[%03d]\r\n", map_data.id)) - if map_infos && map_infos[map_data.id] - f.write(sprintf("# %s\r\n", map_infos[map_data.id].name)) - end - for key in keys - record = map_data.property_from_string(key) - next if record.nil? - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(record, f, schema[key]) - f.write("\r\n") - end - end - } -end - -#=============================================================================== -# Save item data to PBS file -#=============================================================================== -def pbSaveItems - File.open("PBS/items.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.") + "\r\n") - current_pocket = 0 - GameData::Item.each do |i| - if current_pocket != i.pocket - current_pocket = i.pocket - f.write("\#-------------------------------\r\n") - end - move_name = (i.move) ? GameData::Move.get(i.move).id.to_s : "" - sprintf_text = "%d,%s,%s,%s,%d,%d,%s,%d,%d,%d\r\n" - sprintf_text = "%d,%s,%s,%s,%d,%d,%s,%d,%d,%d,%s\r\n" if move_name != "" - f.write(sprintf(sprintf_text, - i.id_number, - csvQuote(i.id.to_s), - csvQuote(i.real_name), - csvQuote(i.real_name_plural), - i.pocket, - i.price, - csvQuoteAlways(i.real_description), - i.field_use, - i.battle_use, - i.type, - csvQuote(move_name) - )) - end - } -end - -#=============================================================================== -# Save berry plant data to PBS file -#=============================================================================== -def pbSaveBerryPlants - File.open("PBS/berryplants.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.") + "\r\n") - f.write("\#-------------------------------\r\n") - GameData::BerryPlant.each do |bp| - f.write(sprintf("%s = %d,%d,%d,%d\r\n", - csvQuote(bp.id.to_s), - bp.hours_per_stage, - bp.drying_per_hour, - bp.minimum_yield, - bp.maximum_yield - )) - end - } -end - -#=============================================================================== -# Save trainer list data to PBS file -#=============================================================================== -def pbSaveTrainerLists - trainerlists = load_data("Data/trainer_lists.dat") rescue nil - return if !trainerlists - File.open("PBS/trainerlists.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.") + "\r\n") - for tr in trainerlists - f.write("\#-------------------------------\r\n") - f.write(((tr[5]) ? "[DefaultTrainerList]" : "[TrainerList]")+"\r\n") - f.write("Trainers = "+tr[3]+"\r\n") - f.write("Pokemon = "+tr[4]+"\r\n") - f.write("Challenges = "+tr[2].join(",")+"\r\n") if !tr[5] - pbSaveBTTrainers(tr[0],"PBS/"+tr[3]) - pbSaveBattlePokemon(tr[1],"PBS/"+tr[4]) - end - } -end - -#=============================================================================== -# Save wild encounter data to PBS file -#=============================================================================== -def pbSaveEncounterData - encdata = pbLoadEncountersData - return if !encdata - mapinfos = pbLoadRxData("Data/MapInfos") - File.open("PBS/encounters.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.") + "\r\n") - sortedkeys = encdata.keys.sort - for i in sortedkeys - next if !encdata[i] - e = encdata[i] - mapname = "" - if mapinfos[i] - map = mapinfos[i].name - mapname = " # #{map}" - end - f.write("\#-------------------------------\r\n") - f.write(sprintf("%03d%s\r\n",i,mapname)) - f.write(sprintf("%d,%d,%d\r\n",e[0][EncounterTypes::Land], - e[0][EncounterTypes::Cave],e[0][EncounterTypes::Water])) - for j in 0...e[1].length - enc = e[1][j] - next if !enc - f.write(sprintf("%s\r\n",EncounterTypes::Names[j])) - for k in 0...EncounterTypes::EnctypeChances[j].length - next if !enc[k] - encentry = enc[k] - if encentry[1]==encentry[2] - f.write(sprintf(" %s,%d\r\n",encentry[0],encentry[1])) - else - f.write(sprintf(" %s,%d,%d\r\n",encentry[0],encentry[1],encentry[2])) - end - end - end - end - } -end - -#=============================================================================== -# Save trainer type data to PBS file -#=============================================================================== -def pbSaveTrainerTypes - File.open("PBS/trainertypes.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.") + "\r\n") - f.write("\#-------------------------------\r\n") - GameData::TrainerType.each do |t| - f.write(sprintf("%d,%s,%s,%d,%s,%s,%s,%s,%s,%s\r\n", - t.id_number, - csvQuote(t.id.to_s), - csvQuote(t.real_name), - t.base_money, - csvQuote(t.battle_BGM), - csvQuote(t.victory_ME), - csvQuote(t.intro_ME), - ["Male", "Female", "Mixed"][t.gender], - (t.skill_level == t.base_money) ? "" : t.skill_level.to_s, - csvQuote(t.skill_code) - )) - end - } -end - -#=============================================================================== -# Save individual trainer data to PBS file -#=============================================================================== -def pbSaveTrainerBattles - data = pbLoadTrainersData - return if !data - File.open("PBS/trainers.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.") + "\r\n") - for trainer in data - trtypename = trainer[0].to_s - next if !trtypename - f.write("\#-------------------------------\r\n") - # Section - trainername = trainer[1] ? trainer[1].gsub(/,/,";") : "???" - if trainer[4]==0 - f.write(sprintf("[%s,%s]\r\n",trtypename,trainername)) - else - f.write(sprintf("[%s,%s,%d]\r\n",trtypename,trainername,trainer[4])) - end - # Trainer's items - if trainer[2] && trainer[2].length>0 - itemstring = "" - for i in 0...trainer[2].length - itemstring.concat(",") if i > 0 - itemstring.concat(trainer[2][i].to_s) - end - f.write(sprintf("Items = %s\r\n",itemstring)) if itemstring!="" - end - # Lose texts - if trainer[5] && trainer[5]!="" - f.write(sprintf("LoseText = %s\r\n",csvQuoteAlways(trainer[5]))) - end - # Pokémon - for poke in trainer[3] - f.write(sprintf("Pokemon = %s,%d\r\n",poke[TrainerData::SPECIES],poke[TrainerData::LEVEL])) - if poke[TrainerData::NAME] && poke[TrainerData::NAME]!="" - f.write(sprintf(" Name = %s\r\n",poke[TrainerData::NAME])) - end - if poke[TrainerData::FORM] - f.write(sprintf(" Form = %d\r\n",poke[TrainerData::FORM])) - end - if poke[TrainerData::GENDER] - f.write(sprintf(" Gender = %s\r\n",(poke[TrainerData::GENDER]==1) ? "female" : "male")) - end - if poke[TrainerData::SHINY] - f.write(" Shiny = yes\r\n") - end - if poke[TrainerData::SHADOW] - f.write(" Shadow = yes\r\n") - end - if poke[TrainerData::MOVES] && poke[TrainerData::MOVES].length>0 - movestring = "" - for i in 0...poke[TrainerData::MOVES].length - movename = GameData::Move.get(poke[TrainerData::MOVES][i]).id.to_s - next if !movename - movestring.concat(",") if i>0 - movestring.concat(movename) - end - f.write(sprintf(" Moves = %s\r\n",movestring)) if movestring!="" - end - if poke[TrainerData::ABILITY] - f.write(sprintf(" Ability = %s\r\n",poke[TrainerData::ABILITY].to_s)) - end - if poke[TrainerData::ITEM] - f.write(sprintf(" Item = %s\r\n",poke[TrainerData::ITEM].to_s)) - end - if poke[TrainerData::NATURE] - nature = getConstantName(PBNatures,poke[TrainerData::NATURE]) rescue nil - f.write(sprintf(" Nature = %s\r\n",nature)) if nature - end - if poke[TrainerData::IV] && poke[TrainerData::IV].length>0 - f.write(sprintf(" IV = %d",poke[TrainerData::IV][0])) - if poke[TrainerData::IV].length>1 - for i in 1...6 - f.write(sprintf(",%d",(i0 - f.write(sprintf(" EV = %d",poke[TrainerData::EV][0])) - if poke[TrainerData::EV].length>1 - for i in 1...6 - f.write(sprintf(",%d",(i]\r\n") - f.write(data.generics.join("\r\n")+"\r\n") - f.write("\#-------------------------------\r\n") - f.write("[]\r\n") - f.write(data.battleRequests.join("\r\n")+"\r\n") - f.write("\#-------------------------------\r\n") - f.write("[]\r\n") - f.write(data.greetingsMorning.join("\r\n")+"\r\n") - f.write("\#-------------------------------\r\n") - f.write("[]\r\n") - f.write(data.greetingsEvening.join("\r\n")+"\r\n") - f.write("\#-------------------------------\r\n") - f.write("[]\r\n") - f.write(data.greetings.join("\r\n")+"\r\n") - f.write("\#-------------------------------\r\n") - f.write("[]\r\n") - f.write(data.bodies1.join("\r\n")+"\r\n") - f.write("\#-------------------------------\r\n") - f.write("[]\r\n") - f.write(data.bodies2.join("\r\n")+"\r\n") - } -end - -#=============================================================================== -# Save Pokémon data to PBS file -#=============================================================================== -def pbSavePokemonData - File.open("PBS/pokemon.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.") + "\r\n") - GameData::Species.each do |species| - next if species.form != 0 - pbSetWindowText(_INTL("Writing species {1}...", species.id_number)) - Graphics.update if species.id_number % 50 == 0 - f.write("\#-------------------------------\r\n") - f.write(sprintf("[%d]\r\n", species.id_number)) - f.write(sprintf("Name = %s\r\n", species.real_name)) - f.write(sprintf("InternalName = %s\r\n", species.species)) - f.write(sprintf("Type1 = %s\r\n", species.type1)) - f.write(sprintf("Type2 = %s\r\n", species.type2)) if species.type2 != species.type1 - f.write(sprintf("BaseStats = %s\r\n", species.base_stats.join(","))) - f.write(sprintf("GenderRate = %s\r\n", getConstantName(PBGenderRates, species.gender_rate))) - f.write(sprintf("GrowthRate = %s\r\n", getConstantName(PBGrowthRates, species.growth_rate))) - f.write(sprintf("BaseEXP = %d\r\n", species.base_exp)) - f.write(sprintf("EffortPoints = %s\r\n", species.evs.join(","))) - f.write(sprintf("Rareness = %d\r\n", species.catch_rate)) - f.write(sprintf("Happiness = %d\r\n", species.happiness)) - if species.abilities.length > 0 - f.write(sprintf("Abilities = %s\r\n", species.abilities.join(","))) - end - if species.hidden_abilities.length > 0 - f.write(sprintf("HiddenAbility = %s\r\n", species.hidden_abilities.join(","))) - end - if species.moves.length > 0 - f.write(sprintf("Moves = %s\r\n", species.moves.join(","))) - end - if species.tutor_moves.length > 0 - f.write(sprintf("TutorMoves = %s\r\n", species.tutor_moves.join(","))) - end - if species.egg_moves.length > 0 - f.write(sprintf("EggMoves = %s\r\n", species.egg_moves.join(","))) - end - if species.egg_groups.length > 0 - f.write("Compatibility = ") - species.egg_groups.each_with_index do |group, i| - f.write(",") if i > 0 - f.write(getConstantName(PBEggGroups, group)) - end - f.write("\r\n") - end - f.write(sprintf("StepsToHatch = %d\r\n", species.hatch_steps)) - f.write(sprintf("Height = %.1f\r\n", species.height / 10.0)) - f.write(sprintf("Weight = %.1f\r\n", species.weight / 10.0)) - f.write(sprintf("Color = %s\r\n", getConstantName(PBColors, species.color))) - f.write(sprintf("Shape = %d\r\n", species.shape)) - f.write(sprintf("Habitat = %s\r\n", getConstantName(PBHabitats, species.habitat))) if species.habitat != PBHabitats::None - f.write(sprintf("Kind = %s\r\n", species.real_category)) - f.write(sprintf("Pokedex = %s\r\n", species.real_pokedex_entry)) - f.write(sprintf("FormName = %s\r\n", species.real_form_name)) if species.real_form_name && !species.real_form_name.empty? - f.write(sprintf("Generation = %d\r\n", species.generation)) if species.generation != 0 - f.write(sprintf("WildItemCommon = %s\r\n", species.wild_item_common)) if species.wild_item_common - f.write(sprintf("WildItemUncommon = %s\r\n", species.wild_item_uncommon)) if species.wild_item_uncommon - f.write(sprintf("WildItemRare = %s\r\n", species.wild_item_rare)) if species.wild_item_rare - f.write(sprintf("BattlerPlayerX = %d\r\n", species.back_sprite_x)) - f.write(sprintf("BattlerPlayerY = %d\r\n", species.back_sprite_y)) - f.write(sprintf("BattlerEnemyX = %d\r\n", species.front_sprite_x)) - f.write(sprintf("BattlerEnemyY = %d\r\n", species.front_sprite_y)) - f.write(sprintf("BattlerAltitude = %d\r\n", species.front_sprite_altitude)) if species.front_sprite_altitude != 0 - f.write(sprintf("BattlerShadowX = %d\r\n", species.shadow_x)) - f.write(sprintf("BattlerShadowSize = %d\r\n", species.shadow_size)) - if species.evolutions.any? { |evo| !evo[3] } - f.write("Evolutions = ") - need_comma = false - species.evolutions.each do |evo| - next if evo[3] # Skip prevolution entries - f.write(",") if need_comma - need_comma = true - f.write(sprintf("%s,%s,", evo[0], getConstantName(PBEvolution, evo[1]))) - param_type = PBEvolution.getFunction(evo[1], "parameterType") - has_param = !PBEvolution.hasFunction?(evo[1], "parameterType") || param_type != nil - next if !has_param - if param_type - if GameData.const_defined?(param_type.to_sym) - f.write(evo[2].to_s) - else - f.write(getConstantName(param_type, evo[2])) - end - else - f.write(evo[2].to_s) - end - end - f.write("\r\n") - end - f.write(sprintf("Incense = %s\r\n", species.incense)) if species.incense - end - } - Graphics.update -end - -#=============================================================================== -# Save Pokémon forms data to PBS file -#=============================================================================== -def pbSavePokemonFormsData - File.open("PBS/pokemonforms.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.") + "\r\n") - GameData::Species.each do |species| - next if species.form == 0 - base_species = GameData::Species.get(species.species) - pbSetWindowText(_INTL("Writing species {1}...", species.id_number)) - Graphics.update if species.id_number % 50 == 0 - f.write("\#-------------------------------\r\n") - f.write(sprintf("[%s,%d]\r\n", species.species, species.form)) - f.write(sprintf("FormName = %s\r\n", species.real_form_name)) if species.real_form_name && !species.real_form_name.empty? - f.write(sprintf("PokedexForm = %d\r\n", species.pokedex_form)) if species.pokedex_form != species.form - f.write(sprintf("MegaStone = %s\r\n", species.mega_stone)) if species.mega_stone - f.write(sprintf("MegaMove = %s\r\n", species.mega_move)) if species.mega_move - f.write(sprintf("UnmegaForm = %d\r\n", species.unmega_form)) if species.unmega_form != 0 - f.write(sprintf("MegaMessage = %d\r\n", species.mega_message)) if species.mega_message != 0 - if species.type1 != base_species.type1 || species.type2 != base_species.type2 - f.write(sprintf("Type1 = %s\r\n", species.type1)) - f.write(sprintf("Type2 = %s\r\n", species.type2)) if species.type2 != species.type1 - end - f.write(sprintf("BaseStats = %s\r\n", species.base_stats.join(","))) if species.base_stats != base_species.base_stats - f.write(sprintf("BaseEXP = %d\r\n", species.base_exp)) if species.base_exp != base_species.base_exp - f.write(sprintf("EffortPoints = %s\r\n", species.evs.join(","))) if species.evs != base_species.evs - f.write(sprintf("Rareness = %d\r\n", species.catch_rate)) if species.catch_rate != base_species.catch_rate - f.write(sprintf("Happiness = %d\r\n", species.happiness)) if species.happiness != base_species.happiness - if species.abilities.length > 0 && species.abilities != base_species.abilities - f.write(sprintf("Abilities = %s\r\n", species.abilities.join(","))) - end - if species.hidden_abilities.length > 0 && species.hidden_abilities != base_species.hidden_abilities - f.write(sprintf("HiddenAbility = %s\r\n", species.hidden_abilities.join(","))) - end - if species.moves.length > 0 && species.moves != base_species.moves - f.write(sprintf("Moves = %s\r\n", species.moves.join(","))) - end - if species.tutor_moves.length > 0 && species.tutor_moves != base_species.tutor_moves - f.write(sprintf("TutorMoves = %s\r\n", species.tutor_moves.join(","))) - end - if species.egg_moves.length > 0 && species.egg_moves != base_species.egg_moves - f.write(sprintf("EggMoves = %s\r\n", species.egg_moves.join(","))) - end - if species.egg_groups.length > 0 && species.egg_groups != base_species.egg_groups - f.write("Compatibility = ") - species.egg_groups.each_with_index do |group, i| - f.write(",") if i > 0 - f.write(getConstantName(PBEggGroups, group)) - end - f.write("\r\n") - end - f.write(sprintf("StepsToHatch = %d\r\n", species.hatch_steps)) if species.hatch_steps != base_species.hatch_steps - f.write(sprintf("Height = %.1f\r\n", species.height / 10.0)) if species.height != base_species.height - f.write(sprintf("Weight = %.1f\r\n", species.weight / 10.0)) if species.weight != base_species.weight - f.write(sprintf("Color = %s\r\n", getConstantName(PBColors, species.color))) if species.color != base_species.color - f.write(sprintf("Shape = %d\r\n", species.shape)) if species.shape != base_species.shape - if species.habitat != PBHabitats::None && species.habitat != base_species.habitat - f.write(sprintf("Habitat = %s\r\n", getConstantName(PBHabitats, species.habitat))) - end - f.write(sprintf("Kind = %s\r\n", species.real_category)) if species.real_category != base_species.real_category - f.write(sprintf("Pokedex = %s\r\n", species.real_pokedex_entry)) if species.real_pokedex_entry != base_species.real_pokedex_entry - f.write(sprintf("Generation = %d\r\n", species.generation)) if species.generation != base_species.generation - if species.wild_item_common != base_species.wild_item_common || - species.wild_item_uncommon != base_species.wild_item_uncommon || - species.wild_item_rare != base_species.wild_item_rare - f.write(sprintf("WildItemCommon = %s\r\n", species.wild_item_common)) if species.wild_item_common - f.write(sprintf("WildItemUncommon = %s\r\n", species.wild_item_uncommon)) if species.wild_item_uncommon - f.write(sprintf("WildItemRare = %s\r\n", species.wild_item_rare)) if species.wild_item_rare - end - f.write(sprintf("BattlerPlayerX = %d\r\n", species.back_sprite_x)) if species.back_sprite_x != base_species.back_sprite_x - f.write(sprintf("BattlerPlayerY = %d\r\n", species.back_sprite_y)) if species.back_sprite_y != base_species.back_sprite_y - f.write(sprintf("BattlerEnemyX = %d\r\n", species.front_sprite_x)) if species.front_sprite_x != base_species.front_sprite_x - f.write(sprintf("BattlerEnemyY = %d\r\n", species.front_sprite_y)) if species.front_sprite_y != base_species.front_sprite_y - f.write(sprintf("BattlerAltitude = %d\r\n", species.front_sprite_altitude)) if species.front_sprite_altitude != base_species.front_sprite_altitude - f.write(sprintf("BattlerShadowX = %d\r\n", species.shadow_x)) if species.shadow_x != base_species.shadow_x - f.write(sprintf("BattlerShadowSize = %d\r\n", species.shadow_size)) if species.shadow_size != base_species.shadow_size - if species.evolutions != base_species.evolutions && species.evolutions.any? { |evo| !evo[3] } - f.write("Evolutions = ") - need_comma = false - species.evolutions.each do |evo| - next if evo[3] # Skip prevolution entries - f.write(",") if need_comma - need_comma = true - f.write(sprintf("%s,%s,", evo[0], getConstantName(PBEvolution, evo[1]))) - param_type = PBEvolution.getFunction(evo[1], "parameterType") - has_param = !PBEvolution.hasFunction?(evo[1], "parameterType") || param_type != nil - next if !has_param - if param_type - if GameData.const_defined?(param_type.to_sym) - f.write(evo[2].to_s) - else - f.write(getConstantName(param_type, evo[2])) - end - else - f.write(evo[2].to_s) - end - end - f.write("\r\n") - end - end - } - Graphics.update -end - -#=============================================================================== -# Save Shadow move data to PBS file -#=============================================================================== -def pbSaveShadowMoves - shadow_movesets = pbLoadShadowMovesets - File.open("PBS/shadowmoves.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.") + "\r\n") - f.write("\#-------------------------------\r\n") - GameData::Species.each do |species_data| - moveset = shadow_movesets[species_data.id] - next if !moveset || moveset.length == 0 - f.write(sprintf("%s = %s\r\n", species_data.id, moveset.join(","))) - end - } -end - -#=============================================================================== -# Save Regional Dexes data to PBS file -#=============================================================================== -def pbSaveRegionalDexes - dex_lists = pbLoadRegionalDexes - File.open("PBS/regionaldexes.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.") + "\r\n") - # Write each Dex list in turn - dex_lists.each_with_index do |list, index| - f.write("\#-------------------------------\r\n") - f.write("[#{index}]") - comma = false - current_family = nil - list.each do |species| - next if !species - if current_family && current_family.include?(species) - f.write(",") if comma - else - current_family = EvolutionHelper.all_related_species(species) - comma = false - f.write("\r\n") - end - f.write(species) - comma = true - end - f.write("\r\n") - end - } -end - -#=============================================================================== -# Save Battle Tower trainer data to PBS file -#=============================================================================== -def pbSaveBTTrainers(bttrainers,filename) - return if !bttrainers || !filename - btTrainersRequiredTypes = { - "Type" => [0,"e",nil], # Specifies a trainer - "Name" => [1,"s"], - "BeginSpeech" => [2,"s"], - "EndSpeechWin" => [3,"s"], - "EndSpeechLose" => [4,"s"], - "PokemonNos" => [5,"*u"] - } - File.open(filename,"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.") + "\r\n") - for i in 0...bttrainers.length - next if !bttrainers[i] - f.write("\#-------------------------------\r\n") - f.write(sprintf("[%03d]\r\n",i)) - for key in btTrainersRequiredTypes.keys - schema = btTrainersRequiredTypes[key] - record = bttrainers[i][schema[0]] - next if record==nil - f.write(sprintf("%s = ",key)) - if key=="Type" - f.write(record.to_s) - elsif key=="PokemonNos" - f.write(record.join(",")) # pbWriteCsvRecord somehow won't work here - else - pbWriteCsvRecord(record,f,schema) - end - f.write(sprintf("\r\n")) - end - end - } -end - -#=============================================================================== -# Save Battle Tower Pokémon data to PBS file -#=============================================================================== -def pbSaveBattlePokemon(btpokemon,filename) - return if !btpokemon || !filename - species = {0=>""} - moves = {0=>""} - items = {0=>""} - natures = {} - File.open(filename,"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.") + "\r\n") - f.write("\#-------------------------------\r\n") - for i in 0...btpokemon.length - Graphics.update if i%500==0 - pkmn = btpokemon[i] - f.write(pbFastInspect(pkmn,moves,species,items,natures)) - f.write("\r\n") - end - } -end - -def pbFastInspect(pkmn,moves,species,items,natures) - c1 = (species[pkmn.species]) ? species[pkmn.species] : (species[pkmn.species] = GameData::Species.get(pkmn.species).species.to_s) - c2 = (items[pkmn.item]) ? items[pkmn.item] : (items[pkmn.item] = GameData::Item.get(pkmn.item).id.to_s) - c3 = (natures[pkmn.nature]) ? natures[pkmn.nature] : - (natures[pkmn.nature] = getConstantName(PBNatures,pkmn.nature)) - evlist = "" - ev = pkmn.ev - evs = ["HP","ATK","DEF","SPD","SA","SD"] - for i in 0...ev - if ((ev&(1<0 - evlist += evs[i] - end - end - c4 = (moves[pkmn.move1]) ? moves[pkmn.move1] : (moves[pkmn.move1] = GameData::Move.get(pkmn.move1).id.to_s) - c5 = (moves[pkmn.move2]) ? moves[pkmn.move2] : (moves[pkmn.move2] = GameData::Move.get(pkmn.move2).id.to_s) - c6 = (moves[pkmn.move3]) ? moves[pkmn.move3] : (moves[pkmn.move3] = GameData::Move.get(pkmn.move3).id.to_s) - c7 = (moves[pkmn.move4]) ? moves[pkmn.move4] : (moves[pkmn.move4] = GameData::Move.get(pkmn.move4).id.to_s) - return "#{c1};#{c2};#{c3};#{evlist};#{c4},#{c5},#{c6},#{c7}" -end - -#=============================================================================== -# Save all data to PBS files -#=============================================================================== -def pbSaveAllData - pbSaveTypes; Graphics.update - pbSaveAbilities; Graphics.update - pbSaveMoveData; Graphics.update - pbSaveConnectionData; Graphics.update - pbSaveMetadata; Graphics.update - pbSaveItems; Graphics.update - pbSaveBerryPlants; Graphics.update - pbSaveTrainerLists; Graphics.update - pbSaveEncounterData; Graphics.update - pbSaveTrainerTypes; Graphics.update - pbSaveTrainerBattles; Graphics.update - pbSaveTownMap; Graphics.update - pbSavePhoneData; Graphics.update - pbSavePokemonData; Graphics.update - pbSavePokemonFormsData; Graphics.update - pbSaveShadowMoves; Graphics.update - pbSaveRegionalDexes; Graphics.update -end diff --git a/Data/Scripts/021_Debug/006_Editor_DataFormatting.rb b/Data/Scripts/021_Debug/006_Editor_DataFormatting.rb deleted file mode 100644 index c5c38e68a..000000000 --- a/Data/Scripts/021_Debug/006_Editor_DataFormatting.rb +++ /dev/null @@ -1,116 +0,0 @@ -#=============================================================================== -# String formatting, conversion of value to string -#=============================================================================== -def csvQuote(str,always=false) - return "" if !str || str=="" - if always || str[/[,\"]/] # || str[/^\s/] || str[/\s$/] || str[/^#/] - str = str.gsub(/[\"]/,"\\\"") - str = "\"#{str}\"" - end - return str -end - -def csvQuoteAlways(str) - return csvQuote(str,true) -end - -def pbWriteCsvRecord(record,file,schema) - rec = (record.is_a?(Array)) ? record.clone : [record] - for i in 0...schema[1].length - chr = schema[1][i,1] - file.write(",") if i>0 - if rec[i].nil? - # do nothing - elsif rec[i].is_a?(String) - file.write(csvQuote(rec[i])) - elsif rec[i].is_a?(Symbol) - file.write(csvQuote(rec[i].to_s)) - elsif rec[i]==true - file.write("true") - elsif rec[i]==false - file.write("false") - elsif rec[i].is_a?(Numeric) - case chr - when "e", "E" # Enumerable - enumer = schema[2+i] - if enumer.is_a?(Array) - file.write(enumer[rec[i]]) - elsif enumer.is_a?(Symbol) || enumer.is_a?(String) - mod = Object.const_get(enumer.to_sym) - file.write(getConstantName(mod,rec[i])) - elsif enumer.is_a?(Module) - file.write(getConstantName(enumer,rec[i])) - elsif enumer.is_a?(Hash) - for key in enumer.keys - if enumer[key]==rec[i] - file.write(key) - break - end - end - end - when "y", "Y" # Enumerable or integer - enumer = schema[2+i] - if enumer.is_a?(Array) - if enumer[rec[i]]!=nil - file.write(enumer[rec[i]]) - else - file.write(rec[i]) - end - elsif enumer.is_a?(Symbol) || enumer.is_a?(String) - mod = Object.const_get(enumer.to_sym) - file.write(getConstantNameOrValue(mod,rec[i])) - elsif enumer.is_a?(Module) - file.write(getConstantNameOrValue(enumer,rec[i])) - elsif enumer.is_a?(Hash) - hasenum = false - for key in enumer.keys - if enumer[key]==rec[i] - file.write(key) - hasenum = true; break - end - end - file.write(rec[i]) unless hasenum - end - else # Any other record type - file.write(rec[i].inspect) - end - else - file.write(rec[i].inspect) - end - end - return record -end - -#=============================================================================== -# Enum const manipulators and parsers -#=============================================================================== -def getConstantName(mod,value) - mod = Object.const_get(mod) if mod.is_a?(Symbol) - for c in mod.constants - return c if mod.const_get(c.to_sym)==value - end - raise _INTL("Value {1} not defined by a constant in {2}",value,mod.name) -end - -def getConstantNameOrValue(mod,value) - mod = Object.const_get(mod) if mod.is_a?(Symbol) - for c in mod.constants - return c if mod.const_get(c.to_sym)==value - end - return value.inspect -end - -def setConstantName(mod,value,name) - mod = Object.const_get(mod) if mod.is_a?(Symbol) - for c in mod.constants - mod.send(:remove_const,c.to_sym) if mod.const_get(c.to_sym)==value - end - mod.const_set(name,value) -end - -def removeConstantValue(mod,value) - mod = Object.const_get(mod) if mod.is_a?(Symbol) - for c in mod.constants - mod.send(:remove_const,c.to_sym) if mod.const_get(c.to_sym)==value - end -end diff --git a/Data/Scripts/021_Debug/009_Editor_Utilities.rb b/Data/Scripts/021_Debug/009_Editor_Utilities.rb index b2e6eb9b8..090a9dca4 100644 --- a/Data/Scripts/021_Debug/009_Editor_Utilities.rb +++ b/Data/Scripts/021_Debug/009_Editor_Utilities.rb @@ -108,110 +108,6 @@ def pbMapTree return retarray end - - -#=============================================================================== -# Make up internal names for things based on their actual names -#=============================================================================== -module MakeshiftConsts - @@consts = [] - - def self.get(c,i,modname=nil) - @@consts[c] = [] if !@@consts[c] - return @@consts[c][i] if @@consts[c][i] - if modname - v = getConstantName(modname,i) rescue nil - if v - @@consts[c][i] = v - return v - end - end - trname = pbGetMessage(c,i) - trconst = trname.gsub(/é/,"e") - trconst = trconst.upcase - trconst = trconst.gsub(/♀/,"fE") - trconst = trconst.gsub(/♂/,"mA") - trconst = trconst.gsub(/[^A-Za-z0-9_]/,"") - if trconst.length==0 - return nil if trname.length==0 - trconst = sprintf("T_%03d",i) - elsif !trconst[0,1][/[A-Z]/] - trconst = "T_"+trconst - end - while @@consts[c].include?(trconst) - trconst = sprintf("%s_%03d",trconst,i) - end - @@consts[c][i] = trconst - return trconst - end -end - - - -def pbGetEvolutionConst(i) - ret = MakeshiftConsts.get(50,i,PBEvolution) - if !ret - ret = ["None", - "Happiness","HappinessDay","HappinessNight","Level","Trade", - "TradeItem","Item","AttackGreater","AtkDefEqual","DefenseGreater", - "Silcoon","Cascoon","Ninjask","Shedinja","Beauty", - "ItemMale","ItemFemale","DayHoldItem","NightHoldItem","HasMove", - "HasInParty","LevelMale","LevelFemale","Location","TradeSpecies", - "Custom1","Custom2","Custom3","Custom4","Custom5"] - i = 0 if i>=ret.length || i<0 - ret = ret[i] - end - return ret -end - -def pbGetEggGroupConst(i) - ret = MakeshiftConsts.get(51,i,PBEggGroups) - if !ret - ret = ["Undiscovered", - "Monster","Water1","Bug","Flying","Field", - "Fairy","Grass","Humanlike","Water3","Mineral", - "Amorphous","Water2","Ditto","Dragon"][i] - i = 0 if i>=ret.length || i<0 - ret = ret[i] - end - return ret -end - -def pbGetColorConst(i) - ret = MakeshiftConsts.get(52,i,PBColors) - if !ret - ret = ["Red","Blue","Yellow","Green","Black","Brown","Purple","Gray","White","Pink"] - i = 0 if i>=ret.length || i<0 - ret = ret[i] - end - return ret -end - -def pbGetGenderConst(i) - ret = MakeshiftConsts.get(53,i,PBGenderRates) - if !ret - ret = ["Genderless","AlwaysMale","FemaleOneEighth","Female25Percent", - "Female50Percent","Female75Percent","FemaleSevenEighths", - "AlwaysFemale"] - i = 0 if i>=ret.length || i<0 - ret = ret[i] - end - return ret -end - -def pbGetHabitatConst(i) - ret = MakeshiftConsts.get(54,i,PBHabitats) - if !ret - ret = ["","Grassland","Forest","WatersEdge","Sea","Cave","Mountain", - "RoughTerrain","Urban","Rare"] - i = 0 if i>=ret.length || i<0 - ret = ret[i] - end - return ret -end - - - #=============================================================================== # List all members of a class #=============================================================================== diff --git a/Data/Scripts/021_Debug/010_Editor_TilesetEditor.rb b/Data/Scripts/021_Debug/010_Editor_TilesetTerrainTags.rb similarity index 100% rename from Data/Scripts/021_Debug/010_Editor_TilesetEditor.rb rename to Data/Scripts/021_Debug/010_Editor_TilesetTerrainTags.rb diff --git a/Data/Scripts/021_Debug/011_Editor_MapConnectionEditor.rb b/Data/Scripts/021_Debug/011_Editor_MapConnections.rb similarity index 99% rename from Data/Scripts/021_Debug/011_Editor_MapConnectionEditor.rb rename to Data/Scripts/021_Debug/011_Editor_MapConnections.rb index 70455d7ff..2d6e2f05a 100644 --- a/Data/Scripts/021_Debug/011_Editor_MapConnectionEditor.rb +++ b/Data/Scripts/021_Debug/011_Editor_MapConnections.rb @@ -284,7 +284,8 @@ class MapScreenScene def serializeConnectionData conndata=generateConnectionData() - pbSerializeConnectionData(conndata,@mapinfos) + save_data(conndata, "Data/map_connections.dat") + Compiler.write_connections @mapconns=conndata end @@ -575,7 +576,7 @@ class MapScreenScene MapFactoryHelper.clear save_data(@encdata,"Data/encounters.dat") $PokemonTemp.encountersData = nil - pbSaveEncounterData + Compiler.write_encounters end break if pbConfirmMessage(_INTL("Exit from the editor?")) end diff --git a/Data/Scripts/021_Debug/012_Editor_SpritePosEditor.rb b/Data/Scripts/021_Debug/012_Editor_SpritePositioning.rb similarity index 99% rename from Data/Scripts/021_Debug/012_Editor_SpritePosEditor.rb rename to Data/Scripts/021_Debug/012_Editor_SpritePositioning.rb index 435a82a3a..257d23b5f 100644 --- a/Data/Scripts/021_Debug/012_Editor_SpritePosEditor.rb +++ b/Data/Scripts/021_Debug/012_Editor_SpritePositioning.rb @@ -32,8 +32,8 @@ def pbAutoPositionAll bitmap2.dispose if bitmap2 end GameData::Species.save - pbSavePokemonData - pbSavePokemonFormsData + Compiler.write_pokemon + Compiler.write_pokemon_forms end #=============================================================================== @@ -97,8 +97,8 @@ class SpritePositioner def pbSaveMetrics GameData::Species.save - pbSavePokemonData - pbSavePokemonFormsData + Compiler.write_pokemon + Compiler.write_pokemon_forms end def update diff --git a/Data/Scripts/021_Debug/013_Editor_BattleAnimationEditor.rb b/Data/Scripts/021_Debug/013_Editor_BattleAnimationEditor.rb deleted file mode 100644 index f4dd5248c..000000000 --- a/Data/Scripts/021_Debug/013_Editor_BattleAnimationEditor.rb +++ /dev/null @@ -1,3786 +0,0 @@ -################################################################################ -# Controls -################################################################################ -class Window_Menu < Window_CommandPokemon - def initialize(commands,x,y) - tempbitmap=Bitmap.new(32,32) - w=0 - for i in commands - width=tempbitmap.text_size(i).width - w=width if w 0 - @cursor-=1 - @frame=0 - self.invalidate - end - return - end - if Input.repeat?(Input::RIGHT) - if @cursor < self.text.scan(/./m).length - @cursor+=1 - @frame=0 - self.invalidate - end - return - end - # Backspace - if Input.repeat?(Input::BACKSPACE) || Input.repeat?(Input::DELETE) - self.delete if @cursor > 0 - return - end - # Letter keys - for i in 65..90 - if Input.repeatex?(i) - shift=(Input.press?(Input::SHIFT)) ? 0x41 : 0x61 - insert((shift+i-65).chr) - return - end - end - # Number keys - shifted=")!@\#$%^&*(" - unshifted="0123456789" - for i in 48..57 - if Input.repeatex?(i) - insert((Input.press?(Input::SHIFT)) ? shifted[i-48].chr : unshifted[i-48].chr) - return - end - end - keys=[ - [32," "," "], - [106,"*","*"], - [107,"+","+"], - [109,"-","-"], - [111,"/","/"], - [186,";",":"], - [187,"=","+"], - [188,",","<"], - [189,"-","_"], - [190,".",">"], - [191,"/","?"], - [219,"[","{"], - [220,"\\","|"], - [221,"]","}"], - [222,"\"","'"] - ] - for i in keys - if Input.repeatex?(i[0]) - insert((Input.press?(Input::SHIFT)) ? i[2] : i[1]) - return - end - end - end - - def refresh - bitmap=self.bitmap - x=self.x - y=self.y - width=self.width - height=self.height - color=Color.new(120,120,120) - bitmap.font.color=color - bitmap.fill_rect(x,y,width,height,Color.new(0,0,0,0)) - size=bitmap.text_size(self.label).width - shadowtext(bitmap,x,y,size,height,self.label) - x+=size - width-=size - bitmap.fill_rect(x+1,y+1,width-2,height-2,color) - ret=Rect.new(x+1,y+1,width-2,height-2) - if !@captured - bitmap.fill_rect(x+2,y+2,width-4,height-4,Color.new(0,0,0,0)) - else - bitmap.fill_rect(x+2,y+2,width-4,height-4,Color.new(120,120,120,80)) - end - x+=4 - textscan=self.text.scan(/./m) - scanlength=textscan.length - @cursor=scanlength if @cursor>scanlength - @cursor=0 if @cursor<0 - startpos=@cursor - fromcursor=0 - while (startpos>0) - c=textscan[startpos-1] - fromcursor+=bitmap.text_size(c).width - break if fromcursor>width-4 - startpos-=1 - end - for i in startpos...scanlength - c=textscan[i] - textwidth=bitmap.text_size(c).width - next if c=="\n" - # Draw text - shadowtext(bitmap,x,y, textwidth+4, 32, c) - # Draw cursor if necessary - if ((@frame/10)&1) == 0 && i==@cursor - bitmap.fill_rect(x,y+4,2,24,Color.new(120,120,120)) - end - # Add x to drawn text width - x += textwidth - end - if ((@frame/10)&1) == 0 && textscan.length==@cursor - bitmap.fill_rect(x,y+4,2,24,Color.new(120,120,120)) - end - return ret - end -end - - - -class Slider < UIControl - attr_reader :minvalue - attr_reader :maxvalue - attr_reader :curvalue - attr_accessor :label - - def curvalue=(value) - @curvalue=value - @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue - self.invalidate - end - - def minvalue=(value) - @minvalue=value - @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue - self.invalidate - end - - def maxvalue=(value) - @maxvalue=value - @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue - self.invalidate - end - - def initialize(label,minvalue,maxvalue,curval) - super(label) - @minvalue=minvalue - @maxvalue=maxvalue - @curvalue=curval - @label=label - @leftarrow=Rect.new(0,0,0,0) - @rightarrow=Rect.new(0,0,0,0) - self.minvalue=minvalue - self.maxvalue=maxvalue - self.curvalue=curval - end - - def update - mousepos=Mouse::getMousePos - self.changed=false - if self.minvalue100 - self.curvalue-=10 - self.curvalue=self.curvalue.floor - elsif Input.repeatcount(Input::LeftMouseKey)>50 - self.curvalue-=5 - self.curvalue=self.curvalue.floor - else - self.curvalue-=1 - self.curvalue=self.curvalue.floor - end - self.changed=(self.curvalue!=oldvalue) - self.invalidate - end - #Right arrow - if right.contains(mousepos[0],mousepos[1]) - if Input.repeatcount(Input::LeftMouseKey)>100 - self.curvalue+=10 - self.curvalue=self.curvalue.floor - elsif Input.repeatcount(Input::LeftMouseKey)>50 - self.curvalue+=5 - self.curvalue=self.curvalue.floor - else - self.curvalue+=1 - self.curvalue=self.curvalue.floor - end - self.changed=(self.curvalue!=oldvalue) - self.invalidate - end - end - - def refresh - bitmap=self.bitmap - x=self.x - y=self.y - width=self.width - height=self.height - color=Color.new(120,120,120) - bitmap.fill_rect(x,y,width,height,Color.new(0,0,0,0)) - size=bitmap.text_size(self.label).width - leftarrows=bitmap.text_size(_INTL(" << ")) - numbers=bitmap.text_size(" XXXX ").width - rightarrows=bitmap.text_size(_INTL(" >> ")) - bitmap.font.color=color - shadowtext(bitmap,x,y,size,height,self.label) - x+=size - shadowtext(bitmap,x,y,leftarrows.width,height,_INTL(" << "), - self.disabled || self.curvalue==self.minvalue) - @leftarrow=Rect.new(x,y,leftarrows.width,height) - x+=leftarrows.width - if !self.disabled - bitmap.font.color=color - shadowtext(bitmap,x,y,numbers,height," #{self.curvalue} ",false,1) - end - x+=numbers - shadowtext(bitmap,x,y,rightarrows.width,height,_INTL(" >> "), - self.disabled || self.curvalue==self.maxvalue) - @rightarrow=Rect.new(x,y,rightarrows.width,height) - end -end - - - -class OptionalSlider < Slider - def initialize(label,minvalue,maxvalue,curvalue) - @slider=Slider.new(label,minvalue,maxvalue,curvalue) - @checkbox=Checkbox.new("") - end - - def curvalue - return @checkbox.checked ? @slider.curvalue : nil - end - - def curvalue=(value) - slider.curvalue=value - end - - def checked - return @checkbox.checked - end - - def checked=(value) - @checkbox.checked=value - end - - def invalid? - return @slider.invalid? || @checkbox.invalid? - end - - def invalidate - @slider.invalidate - @checkbox.invalidate - end - - def validate? - @slider.validate - @checkbox.validate - end - - def changed - return @slider.changed || @checkbox.changed - end - - def minvalue - return @slider.minvalue - end - - def minvalue=(value) - slider.minvalue=value - end - - def maxvalue - return @slider.maxvalue - end - - def maxvalue=(value) - slider.maxvalue=value - end - - def update - updatedefs - @slider.update - @checkbox.update - end - - def refresh - updatedefs - @slider.refresh - @checkbox.refresh - end - - private - - def updatedefs - checkboxwidth=32 - @slider.bitmap=self.bitmap - @slider.parent=self.parent - @checkbox.x=self.x - @checkbox.y=self.y - @checkbox.width=checkboxwidth - @checkbox.height=self.height - @checkbox.bitmap=self.bitmap - @checkbox.parent=self.parent - @slider.x=self.x+checkboxwidth+4 - @slider.y=self.y - @slider.width=self.width-checkboxwidth - @slider.height=self.height - @slider.disabled=!@checkbox.checked - end -end - - - -class ArrayCountSlider < Slider - def maxvalue - return @array.length-1 - end - - def initialize(array,label) - @array=array - super(label,0,canvas.animation.length-1,0) - end -end - - - -class FrameCountSlider < Slider - def maxvalue - return @canvas.animation.length - end - - def initialize(canvas) - @canvas=canvas - super(_INTL("Frame:"),1,canvas.animation.length,0) - end -end - - - -class FrameCountButton < Button - def label - return _INTL("Total Frames: {1}",@canvas.animation.length) - end - - def initialize(canvas) - @canvas=canvas - super(self.label) - end -end - - - -class TextSlider < UIControl - attr_reader :minvalue - attr_reader :maxvalue - attr_reader :curvalue - attr_accessor :label - attr_accessor :options - attr_accessor :maxoptionwidth - - def curvalue=(value) - @curvalue=value - @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue - self.invalidate - end - - def minvalue=(value) - @minvalue=value - @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue - self.invalidate - end - - def maxvalue=(value) - @maxvalue=value - @curvalue=self.minvalue if self.minvalue && @curvalueself.maxvalue - self.invalidate - end - - def initialize(label,options,curval) - super(label) - @label=label - @options=options - @minvalue=0 - @maxvalue=options.length-1 - @curvalue=curval - @leftarrow=Rect.new(0,0,0,0) - @rightarrow=Rect.new(0,0,0,0) - self.minvalue=@minvalue - self.maxvalue=@maxvalue - self.curvalue=@curvalue - end - - def update - mousepos=Mouse::getMousePos - self.changed=false - if self.minvalue100 - self.curvalue-=10 - elsif Input.repeatcount(Input::LeftMouseKey)>50 - self.curvalue-=5 - else - self.curvalue-=1 - end - self.changed=(self.curvalue!=oldvalue) - self.invalidate - end - # Right arrow - if right.contains(mousepos[0],mousepos[1]) - if Input.repeatcount(Input::LeftMouseKey)>100 - self.curvalue+=10 - elsif Input.repeatcount(Input::LeftMouseKey)>50 - self.curvalue+=5 - else - self.curvalue+=1 - end - self.changed=(self.curvalue!=oldvalue) - self.invalidate - end - end - - def refresh - bitmap=self.bitmap - if @maxoptionwidth==nil - for i in 0...@options.length - w=self.bitmap.text_size(" "+@options[i]+" ").width - @maxoptionwidth=w if !@maxoptionwidth || @maxoptionwidth> ")) - bitmap.font.color=color - shadowtext(bitmap,x,y,size,height,self.label) - x+=size - shadowtext(bitmap,x,y,leftarrows.width,height,_INTL(" << "), - self.disabled || self.curvalue==self.minvalue) - @leftarrow=Rect.new(x,y,leftarrows.width,height) - x+=leftarrows.width - if !self.disabled - bitmap.font.color=color - shadowtext(bitmap,x,y,@maxoptionwidth,height," #{@options[self.curvalue]} ",false,1) - end - x+=@maxoptionwidth - shadowtext(bitmap,x,y,rightarrows.width,height,_INTL(" >> "), - self.disabled || self.curvalue==self.maxvalue) - @rightarrow=Rect.new(x,y,rightarrows.width,height) - end -end - - - -class OptionalTextSlider < TextSlider - def initialize(label,options,curval) - @slider=TextSlider.new(label,options,curval) - @checkbox=Checkbox.new("") - end - - def curvalue - return @checkbox.checked ? @slider.curvalue : nil - end - - def curvalue=(value) - slider.curvalue=value - end - - def checked - return @checkbox.checked - end - - def checked=(value) - @checkbox.checked=value - end - - def invalid? - return @slider.invalid? || @checkbox.invalid? - end - - def invalidate - @slider.invalidate - @checkbox.invalidate - end - - def validate? - @slider.validate - @checkbox.validate - end - - def changed - return @slider.changed || @checkbox.changed - end - - def minvalue - return @slider.minvalue - end - - def minvalue=(value) - slider.minvalue=value - end - - def maxvalue - return @slider.maxvalue - end - - def maxvalue=(value) - slider.maxvalue=value - end - - def update - updatedefs - @slider.update - @checkbox.update - end - - def refresh - updatedefs - @slider.refresh - @checkbox.refresh - end - - private - - def updatedefs - checkboxwidth=32 - @slider.bitmap=self.bitmap - @slider.parent=self.parent - @checkbox.x=self.x - @checkbox.y=self.y - @checkbox.width=checkboxwidth - @checkbox.height=self.height - @checkbox.bitmap=self.bitmap - @checkbox.parent=self.parent - @slider.x=self.x+checkboxwidth+4 - @slider.y=self.y - @slider.width=self.width-checkboxwidth - @slider.height=self.height - @slider.disabled=!@checkbox.checked - end -end - - - -class ControlWindow < SpriteWindow_Base - attr_reader :controls - - def initialize(x,y,width,height) - super(x,y,width,height) - self.contents=Bitmap.new(width-32,height-32) - pbSetNarrowFont(self.contents) - @controls=[] - end - - def dispose - self.contents.dispose - super - end - - def refresh - for i in 0...@controls.length - @controls[i].refresh - end - end - - def repaint - for i in 0...@controls.length - @controls[i].repaint - end - end - - def invalidate - for i in 0...@controls.length - @controls[i].invalidate - end - end - - def hittest?(i) - mousepos=Mouse::getMousePos - return false if !mousepos - return false if i<0 || i>=@controls.length - rc=Rect.new( - @controls[i].parentX, - @controls[i].parentY, - @controls[i].width, - @controls[i].height - ) - return rc.contains(mousepos[0],mousepos[1]) - end - - def addControl(control) - i=@controls.length - @controls[i]=control - @controls[i].x=0 - @controls[i].y=i*32 - @controls[i].width=self.contents.width - @controls[i].height=32 - @controls[i].parent=self - @controls[i].bitmap=self.contents - @controls[i].invalidate - refresh - return i - end - - def addLabel(label) - return addControl(Label.new(label)) - end - - def addButton(label) - return addControl(Button.new(label)) - end - - def addSlider(label,minvalue,maxvalue,curvalue) - return addControl(Slider.new(label,minvalue,maxvalue,curvalue)) - end - - def addOptionalSlider(label,minvalue,maxvalue,curvalue) - return addControl(OptionalSlider.new(label,minvalue,maxvalue,curvalue)) - end - - def addTextSlider(label,options,curvalue) - return addControl(TextSlider.new(label,options,curvalue)) - end - - def addOptionalTextSlider(label,options,curvalue) - return addControl(OptionalTextSlider.new(label,options,curvalue)) - end - - def addCheckbox(label) - return addControl(Checkbox.new(label)) - end - - def addSpace - return addControl(UIControl.new("")) - end - - def update - super - for i in 0...@controls.length - @controls[i].update - end - repaint - end - - def changed?(i) - return false if i<0 - return @controls[i].changed - end - - def value(i) - return false if i<0 - return @controls[i].curvalue - end -end - - - -################################################################################ -# Clipboard -################################################################################ -module Clipboard - @data=nil - @typekey="" - - def self.data - return nil if !@data - return Marshal::load(@data) - end - - def self.typekey - return @typekey - end - - def self.setData(data,key) - @data=Marshal.dump(data) - @typekey=key - end -end - - - -################################################################################ -# Collision testing -################################################################################ -class Rect < Object - def contains(x,y) - return x>=self.x && x=self.y && y64 && !usealpha - height=64 if height>64 && !usealpha - else - xwidth=0 - xheight=0 - end - width=sprite.bitmap.width if width>sprite.bitmap.width - height=sprite.bitmap.height if height>sprite.bitmap.height - if usealpha - spritex=sprite.x-(sprite.ox*sprite.zoom_x) - spritey=sprite.y-(sprite.oy*sprite.zoom_y) - width*=sprite.zoom_x - height*=sprite.zoom_y - else - spritex=sprite.x-sprite.ox - spritey=sprite.y-sprite.oy - spritex+=xwidth/2 - spritey+=xheight/2 - end - if !(x>=spritex && x<=spritex+width && y>=spritey && y<=spritey+height) - return false - end - if usealpha - # TODO: This should account for sprite.angle as well - bitmapX=sprite.src_rect.x - bitmapY=sprite.src_rect.y - bitmapX+=sprite.ox - bitmapY+=sprite.oy - bitmapX+=(x-sprite.x)/sprite.zoom_x if sprite.zoom_x>0 - bitmapY+=(y-sprite.y)/sprite.zoom_y if sprite.zoom_y>0 - bitmapX=bitmapX.round - bitmapY=bitmapY.round - if sprite.mirror - xmirror=bitmapX-sprite.src_rect.x - bitmapX=sprite.src_rect.x+192-xmirror - end - color=sprite.bitmap.get_pixel(bitmapX,bitmapY) - return false if (color.alpha==0) - end - return true -end - -def pbTrackPopupMenu(commands) - mousepos=Mouse::getMousePos - return -1 if !mousepos - menuwindow=Window_Menu.new(commands,mousepos[0],mousepos[1]) - menuwindow.z=99999 - loop do - Graphics.update - Input.update - menuwindow.update - hit=menuwindow.hittest - menuwindow.index=hit if hit>=0 - if Input.triggerex?(Input::LeftMouseKey) || Input.triggerex?(Input::RightMouseKey) # Left or right button - menuwindow.dispose - return hit - end - if Input.trigger?(Input::C) - hit=menuwindow.index - menuwindow.dispose - return hit - end - if Input.trigger?(Input::B) # Escape - break - end - end - menuwindow.dispose - return -1 -end - - - -################################################################################ -# Sprite sheet scrolling bar -################################################################################ -class AnimationWindow < SpriteWrapper - attr_reader :animbitmap - attr_reader :start - attr_reader :selected - NUMFRAMES=5 - - def initialize(x,y,width,height,viewport=nil) - super(viewport) - @animbitmap=nil - @arrows=AnimatedBitmap.new("Graphics/Pictures/arrows") - self.x=x - self.y=y - @start=0 - @selected=0 - @contents=Bitmap.new(width,height) - self.bitmap=@contents - refresh - end - - def animbitmap=(val) - @animbitmap=val - @start=0 - refresh - end - - def selected=(val) - @selected=val - refresh - end - - def dispose - @contents.dispose - @arrows.dispose - @start=0 - @selected=0 - @changed=false - super - end - - def drawrect(bm,x,y,width,height,color) - bm.fill_rect(x,y,width,1,color) - bm.fill_rect(x,y+height-1,width,1,color) - bm.fill_rect(x,y,1,height,color) - bm.fill_rect(x+width-1,y,1,height,color) - end - - def drawborder(bm,x,y,width,height,color) - bm.fill_rect(x,y,width,2,color) - bm.fill_rect(x,y+height-2,width,2,color) - bm.fill_rect(x,y,2,height,color) - bm.fill_rect(x+width-2,y,2,height,color) - end - - def refresh - arrowwidth=@arrows.bitmap.width/2 - @contents.clear - @contents.fill_rect(0,0,@contents.width,@contents.height,Color.new(180,180,180)) - @contents.blt(0,0,@arrows.bitmap,Rect.new(0,0,arrowwidth,96)) - @contents.blt(arrowwidth+NUMFRAMES*96,0,@arrows.bitmap, - Rect.new(arrowwidth,0,arrowwidth,96)) - havebitmap=(self.animbitmap && !self.animbitmap.disposed?) - if havebitmap - rect=Rect.new(0,0,0,0) - rectdst=Rect.new(0,0,0,0) - x=arrowwidth - for i in 0...NUMFRAMES - j=i+@start - rect.set((j%5)*192,(j/5)*192,192,192) - rectdst.set(x,0,96,96) - @contents.stretch_blt(rectdst,self.animbitmap,rect) - x+=96 - end - end - for i in 0...NUMFRAMES - drawrect(@contents,arrowwidth+i*96,0,96,96,Color.new(100,100,100)) - if @start+i==@selected && havebitmap - drawborder(@contents,arrowwidth+i*96,0,96,96,Color.new(255,0,0)) - end - end - end - - def changed? - return @changed - end - - def update - mousepos=Mouse::getMousePos - @changed=false - return if !Input.repeatex?(Input::LeftMouseKey) - return if !mousepos - return if !self.animbitmap - arrowwidth=@arrows.bitmap.width/2 - maxindex=(self.animbitmap.height/192)*5 - left=Rect.new(0,0,arrowwidth,96) - right=Rect.new(arrowwidth+NUMFRAMES*96,0,arrowwidth,96) - left.x+=self.x - left.y+=self.y - right.x+=self.x - right.y+=self.y - swatchrects=[] - for i in 0...NUMFRAMES - swatchrects.push(Rect.new(arrowwidth+i*96+self.x,self.y,96,96)) - end - for i in 0...NUMFRAMES - if swatchrects[i].contains(mousepos[0],mousepos[1]) - @selected=@start+i - @changed=true - refresh - return - end - end - # Left arrow - if left.contains(mousepos[0],mousepos[1]) - if Input.repeatcount(Input::LeftMouseKey)>30 - @start-=3 - else - @start-=1 - end - @start=0 if @start<0 - refresh - end - # Right arrow - if right.contains(mousepos[0],mousepos[1]) - if Input.repeatcount(Input::LeftMouseKey)>30 - @start+=3 - else - @start+=1 - end - @start=maxindex if @start>=maxindex - refresh - end - end -end - - - -class CanvasAnimationWindow < AnimationWindow - def animbitmap - return @canvas.animbitmap - end - - def initialize(canvas,x,y,width,height,viewport=nil) - @canvas=canvas - super(x,y,width,height,viewport) - end -end - - - -################################################################################ -# Cel sprite -################################################################################ -class InvalidatableSprite < Sprite - def initialize(viewport=nil) - super(viewport) - @invalid=false - end - -# Marks that the control must be redrawn to reflect current logic. - def invalidate - @invalid=true - end - -# Determines whether the control is invalid - def invalid? - return @invalid - end - -# Marks that the control is valid. Normally called only by repaint. - def validate - @invalid=false - end - -# Redraws the sprite only if it is invalid, and then revalidates the sprite - def repaint - if self.invalid? - refresh - validate - end - end - - # Redraws the sprite. This method should not check whether - # the sprite is invalid, to allow it to be explicitly called. - def refresh - end - - # Updates the logic on the sprite, for example, in response - # to user input, and invalidates it if necessary. This should - # be called only once per frame. - def update - super - end -end - - - -class SpriteFrame < InvalidatableSprite - attr_reader :id - attr_reader :locked - attr_reader :selected - attr_reader :sprite - NUM_ROWS = (PBAnimation::MAX_SPRITES.to_f/10).ceil # 10 frame number icons in each row - - def initialize(id,sprite,viewport,previous=false) - super(viewport) - @id=id - @sprite=sprite - @previous=previous - @locked=false - @selected=false - @selcolor=Color.new(0,0,0) - @unselcolor=Color.new(220,220,220) - @prevcolor=Color.new(64,128,192) - @contents=Bitmap.new(64,64) - self.z = (@previous) ? 49 : 50 - @iconbitmap=AnimatedBitmap.new("Graphics/Pictures/animFrameIcon") - self.bitmap=@contents - self.invalidate - end - - def dispose - @contents.dispose - super - end - - def sprite=(value) - @sprite=value - self.invalidate - end - - def locked=(value) - @locked=value - self.invalidate - end - - def selected=(value) - @selected=value - self.invalidate - end - - def refresh - @contents.clear - self.z = (@previous) ? 49 : (@selected) ? 51 : 50 - # Draw frame - color=(@previous) ? @prevcolor : (@selected) ? @selcolor : @unselcolor - @contents.fill_rect(0,0,64,1,color) - @contents.fill_rect(0,63,64,1,color) - @contents.fill_rect(0,0,1,64,color) - @contents.fill_rect(63,0,1,64,color) - # Determine frame number graphic to use from @iconbitmap - yoffset = (@previous) ? (NUM_ROWS+1)*16 : 0 # 1 is for padlock icon - bmrect=Rect.new((@id%10)*16,yoffset+(@id/10)*16,16,16) - @contents.blt(0,0,@iconbitmap.bitmap,bmrect) - # Draw padlock if frame is locked - if @locked && !@previous - bmrect=Rect.new(0,NUM_ROWS*16,16,16) - @contents.blt(16,0,@iconbitmap.bitmap,bmrect) - end - end -end - - - -################################################################################ -# Mini battle scene -################################################################################ -class MiniBattler - attr_accessor :index - attr_accessor :pokemon - - def initialize(index); self.index=index; end -end - - - -class MiniBattle - attr_accessor :battlers - - def initialize - @battlers=[] - for i in 0...4; @battlers[i]=MiniBattler.new(i); end - end -end - - - -################################################################################ -# Canvas -################################################################################ -class AnimationCanvas < Sprite - attr_reader :viewport - attr_reader :sprites - attr_reader :currentframe # Currently active frame - attr_reader :currentcel - attr_reader :animation # Currently selected animation - attr_reader :animbitmap # Currently selected animation bitmap - attr_accessor :pattern # Currently selected pattern - BORDERSIZE=64 - - def initialize(animation,viewport=nil) - super(viewport) - @currentframe=0 - @currentcel=-1 - @pattern=0 - @sprites={} - @celsprites=[] - @framesprites=[] - @lastframesprites=[] - @dirty=[] - @viewport=viewport - @selecting=false - @selectOffsetX=0 - @selectOffsetY=0 - @playing=false - @playingframe=0 - @player=nil - @battle=MiniBattle.new - @user=AnimatedBitmap.new("Graphics/Pictures/testback").deanimate - @target=AnimatedBitmap.new("Graphics/Pictures/testfront").deanimate - @testscreen=AnimatedBitmap.new("Graphics/Pictures/testscreen") - self.bitmap=@testscreen.bitmap - for i in 0...PBAnimation::MAX_SPRITES - @lastframesprites[i]=SpriteFrame.new(i,@celsprites[i],viewport,true) - @lastframesprites[i].selected=false - @lastframesprites[i].visible=false - end - for i in 0...PBAnimation::MAX_SPRITES - @celsprites[i]=Sprite.new(viewport) - @celsprites[i].visible=false - @celsprites[i].src_rect=Rect.new(0,0,0,0) - @celsprites[i].bitmap=nil - @framesprites[i]=SpriteFrame.new(i,@celsprites[i],viewport) - @framesprites[i].selected=false - @framesprites[i].visible=false - @dirty[i]=true - end - loadAnimation(animation) - end - - def loadAnimation(anim) - @animation=anim - @animbitmap.dispose if @animbitmap - if @animation.graphic=="" - @animbitmap=nil - else - begin - @animbitmap=AnimatedBitmap.new("Graphics/Animations/"+@animation.graphic, - @animation.hue).deanimate - rescue - @animbitmap=nil - end - end - @currentcel=-1 - self.currentframe=0 - @selecting=false - @pattern=0 - self.invalidate - end - - def animbitmap=(value) - @animbitmap.dispose if @animbitmap - @animbitmap=value - for i in 2...PBAnimation::MAX_SPRITES - @celsprites[i].bitmap=@animbitmap if @celsprites[i] - end - self.invalidate - end - - def dispose - @user.dispose - @target.dispose - @animbitmap.dispose if @animbitmap - @selectedbitmap.dispose if @selectedbitmap - @celbitmap.dispose if @celbitmap - self.bitmap.dispose if self.bitmap - for i in 0...PBAnimation::MAX_SPRITES - @celsprites[i].dispose if @celsprites[i] - end - super - end - - def play(oppmove=false) - if !@playing - @sprites["pokemon_0"]=Sprite.new(@viewport) - @sprites["pokemon_0"].bitmap=@user - @sprites["pokemon_0"].z=21 - @sprites["pokemon_1"]=Sprite.new(@viewport) - @sprites["pokemon_1"].bitmap=@target - @sprites["pokemon_1"].z=16 - pbSpriteSetAnimFrame(@sprites["pokemon_0"], - pbCreateCel(PokeBattle_SceneConstants::FOCUSUSER_X, - PokeBattle_SceneConstants::FOCUSUSER_Y,-1,2), - @sprites["pokemon_0"],@sprites["pokemon_1"]) - pbSpriteSetAnimFrame(@sprites["pokemon_1"], - pbCreateCel(PokeBattle_SceneConstants::FOCUSTARGET_X, - PokeBattle_SceneConstants::FOCUSTARGET_Y,-2,1), - @sprites["pokemon_0"],@sprites["pokemon_1"]) - usersprite=@sprites["pokemon_#{oppmove ? 1 : 0}"] - targetsprite=@sprites["pokemon_#{oppmove ? 0 : 1}"] - olduserx=usersprite ? usersprite.x : 0 - oldusery=usersprite ? usersprite.y : 0 - oldtargetx=targetsprite ? targetsprite.x : 0 - oldtargety=targetsprite ? targetsprite.y : 0 - @player=PBAnimationPlayerX.new(@animation, - @battle.battlers[oppmove ? 1 : 0],@battle.battlers[oppmove ? 0 : 1],self,oppmove,true) - @player.setLineTransform( - PokeBattle_SceneConstants::FOCUSUSER_X,PokeBattle_SceneConstants::FOCUSUSER_Y, - PokeBattle_SceneConstants::FOCUSTARGET_X,PokeBattle_SceneConstants::FOCUSTARGET_Y, - olduserx,oldusery, - oldtargetx,oldtargety) - @player.start - @playing=true - @sprites["pokemon_0"].x+=BORDERSIZE - @sprites["pokemon_0"].y+=BORDERSIZE - @sprites["pokemon_1"].x+=BORDERSIZE - @sprites["pokemon_1"].y+=BORDERSIZE - oldstate=[] - for i in 0...PBAnimation::MAX_SPRITES - oldstate.push([@celsprites[i].visible,@framesprites[i].visible,@lastframesprites[i].visible]) - @celsprites[i].visible=false - @framesprites[i].visible=false - @lastframesprites[i].visible=false - end - loop do - Graphics.update - self.update - break if !@playing - end - for i in 0...PBAnimation::MAX_SPRITES - @celsprites[i].visible=oldstate[i][0] - @framesprites[i].visible=oldstate[i][1] - @lastframesprites[i].visible=oldstate[i][2] - end - @sprites["pokemon_0"].dispose - @sprites["pokemon_1"].dispose - @player.dispose - @player=nil - end - end - - def invalidate - for i in 0...PBAnimation::MAX_SPRITES - invalidateCel(i) - end - end - - def invalidateCel(i) - @dirty[i]=true - end - - def currentframe=(value) - @currentframe=value - invalidate - end - - def getCurrentFrame - return nil if @currentframe>=@animation.length - return @animation[@currentframe] - end - - def setFrame(i) - if @celsprites[i] - @framesprites[i].ox=32 - @framesprites[i].oy=32 - @framesprites[i].selected=(i==@currentcel) - @framesprites[i].locked=self.locked?(i) - @framesprites[i].x=@celsprites[i].x - @framesprites[i].y=@celsprites[i].y - @framesprites[i].visible=@celsprites[i].visible - @framesprites[i].repaint - end - end - - def setPreviousFrame(i) - if @currentframe>0 - cel=@animation[@currentframe-1][i] - if cel!=nil - @lastframesprites[i].ox=32 - @lastframesprites[i].oy=32 - @lastframesprites[i].selected=false - @lastframesprites[i].locked=false - @lastframesprites[i].x=cel[AnimFrame::X]+64 - @lastframesprites[i].y=cel[AnimFrame::Y]+64 - @lastframesprites[i].visible=true - @lastframesprites[i].repaint - else - @lastframesprites[i].visible=false - end - else - @lastframesprites[i].visible=false - end - end - - def offsetFrame(frame,ox,oy) - if frame>=0 && frame<@animation.length - for i in 0...PBAnimation::MAX_SPRITES - if !self.locked?(i) && @animation[frame][i] - @animation[frame][i][AnimFrame::X]+=ox - @animation[frame][i][AnimFrame::Y]+=oy - end - @dirty[i]=true if frame==@currentframe - end - end - end - - # Clears all items in the frame except locked items - def clearFrame(frame) - if frame>=0 && frame<@animation.length - for i in 0...PBAnimation::MAX_SPRITES - if self.deletable?(i) - @animation[frame][i]=nil - else - pbResetCel(@animation[frame][i]) - end - @dirty[i]=true if frame==@currentframe - end - end - end - - def insertFrame(frame) - return if frame>=@animation.length - @animation.insert(frame,@animation[frame].clone) - self.invalidate - end - - def copyFrame(src,dst) - return if dst>=@animation.length - for i in 0...PBAnimation::MAX_SPRITES - clonedframe=@animation[src][i] - clonedframe=clonedframe.clone if clonedframe && clonedframe!=true - @animation[dst][i]=clonedframe - end - self.invalidate if dst==@currentframe - end - - def pasteFrame(frame) - return if frame <0 || frame>=@animation.length - return if Clipboard.typekey!="PBAnimFrame" - @animation[frame]=Clipboard.data - self.invalidate if frame==@currentframe - end - - def deleteFrame(frame) - return if frame<0 || frame>=@animation.length || @animation.length<=1 - self.currentframe-=1 if frame==@animation.length-1 - @animation.delete_at(frame) - @currentcel=-1 - self.invalidate - end - - # This frame becomes a copy of the previous frame - def pasteLast - copyFrame(@currentframe-1,@currentframe) if @currentframe>0 - end - - def currentCel - return nil if @currentcel<0 - return nil if @currentframe>=@animation.length - return @animation[@currentframe][@currentcel] - end - - def pasteCel(x,y) - return if @currentframe>=@animation.length - return if Clipboard.typekey!="PBAnimCel" - for i in 0...PBAnimation::MAX_SPRITES - next if @animation[@currentframe][i] - @animation[@currentframe][i]=Clipboard.data - cel=@animation[@currentframe][i] - cel[AnimFrame::X]=x - cel[AnimFrame::Y]=y - cel[AnimFrame::LOCKED]=0 - @celsprites[i].bitmap=@user if cel[AnimFrame::PATTERN]==-1 - @celsprites[i].bitmap=@target if cel[AnimFrame::PATTERN]==-2 - @currentcel=i - break - end - invalidate - end - - def deleteCel(cel) - return if cel<0 - return if @currentframe <0 || @currentframe>=@animation.length - return if !deletable?(cel) - @animation[@currentframe][cel]=nil - @dirty[cel]=true - end - - def swapCels(cel1,cel2) - return if cel1<0 || cel2<0 - return if @currentframe<0 || @currentframe>=@animation.length - t=@animation[@currentframe][cel1] - @animation[@currentframe][cel1]=@animation[@currentframe][cel2] - @animation[@currentframe][cel2]=t - @currentcel=cel2 - @dirty[cel1]=true - @dirty[cel2]=true - end - - def locked?(celindex) - cel=@animation[self.currentframe] - return false if !cel - cel=cel[celindex] - return cel ? (cel[AnimFrame::LOCKED]!=0) : false - end - - def deletable?(celindex) - cel=@animation[self.currentframe] - return true if !cel - cel=cel[celindex] - return true if !cel - return false if cel[AnimFrame::LOCKED]!=0 - if cel[AnimFrame::PATTERN]<0 - count=0 - pattern=cel[AnimFrame::PATTERN] - for i in 0...PBAnimation::MAX_SPRITES - othercel=@animation[self.currentframe][i] - count+=1 if othercel && othercel[AnimFrame::PATTERN]==pattern - end - return false if count<=1 - end - return true - end - - def setBitmap(i,frame) - if @celsprites[i] - cel=@animation[frame][i] - @celsprites[i].bitmap=@animbitmap - if cel - @celsprites[i].bitmap=@user if cel[AnimFrame::PATTERN]==-1 - @celsprites[i].bitmap=@target if cel[AnimFrame::PATTERN]==-2 - end - end - end - - def setSpriteBitmap(sprite,cel) - if sprite && !sprite.disposed? - sprite.bitmap=@animbitmap - if cel - sprite.bitmap=@user if cel[AnimFrame::PATTERN]==-1 - sprite.bitmap=@target if cel[AnimFrame::PATTERN]==-2 - end - end - end - - def addSprite(x,y) - return false if @currentframe>=@animation.length - for i in 0...PBAnimation::MAX_SPRITES - next if @animation[@currentframe][i] - @animation[@currentframe][i]=pbCreateCel(x,y,@pattern,@animation.position) - @dirty[i]=true - @currentcel=i - return true - end - return false - end - - def updateInput - cel=currentCel - mousepos=Mouse::getMousePos - if mousepos && pbSpriteHitTest(self,mousepos[0],mousepos[1],false,true) - if Input.triggerex?(Input::LeftMouseKey) # Left mouse button - selectedcel=-1 - usealpha=(Input.press?(Input::ALT)) ? true : false - for j in 0...PBAnimation::MAX_SPRITES - if pbSpriteHitTest(@celsprites[j],mousepos[0],mousepos[1],usealpha,false) - selectedcel=j - end - end - if selectedcel<0 - if @animbitmap && addSprite(mousepos[0]-BORDERSIZE,mousepos[1]-BORDERSIZE) - @selecting=true if !self.locked?(@currentcel) - @selectOffsetX=0 - @selectOffsetY=0 - cel=currentCel - invalidate - end - else - @currentcel=selectedcel - @selecting=true if !self.locked?(@currentcel) - cel=currentCel - @selectOffsetX=cel[AnimFrame::X]-mousepos[0]+BORDERSIZE - @selectOffsetY=cel[AnimFrame::Y]-mousepos[1]+BORDERSIZE - invalidate - end - end - end - currentFrame=getCurrentFrame - if currentFrame && !@selecting && Input.repeat?(Input::TAB) - currentFrame.length.times { - @currentcel+=1 - @currentcel=0 if @currentcel>=currentFrame.length - break if currentFrame[@currentcel] - } - invalidate - return - end - if cel && @selecting && mousepos - cel[AnimFrame::X]=mousepos[0]-BORDERSIZE+@selectOffsetX - cel[AnimFrame::Y]=mousepos[1]-BORDERSIZE+@selectOffsetY - @dirty[@currentcel]=true - end - if !Input.getstate(Input::LeftMouseKey) && @selecting - @selecting=false - end - if cel - if Input.repeat?(Input::DELETE) && self.deletable?(@currentcel) - @animation[@currentframe][@currentcel]=nil - @dirty[@currentcel]=true - return - end - if Input.repeatex?(0x50) # "P" for properties - pbCellProperties(self) - @dirty[@currentcel]=true - return - end - if Input.repeatex?(0x4C) # "L" for lock - cel[AnimFrame::LOCKED]=(cel[AnimFrame::LOCKED]==0) ? 1 : 0 - @dirty[@currentcel]=true - end - if Input.repeatex?(0x52) # "R" for rotate right - cel[AnimFrame::ANGLE]+=10 - cel[AnimFrame::ANGLE]%=360 - @dirty[@currentcel]=true - end - if Input.repeatex?(0x45) # "E" for rotate left - cel[AnimFrame::ANGLE]-=10 - cel[AnimFrame::ANGLE]%=360 - @dirty[@currentcel]=true - end - if Input.repeatex?(0x6B) # "+" for zoom in - cel[AnimFrame::ZOOMX]+=10 - cel[AnimFrame::ZOOMX]=1000 if cel[AnimFrame::ZOOMX]>1000 - cel[AnimFrame::ZOOMY]+=10 - cel[AnimFrame::ZOOMY]=1000 if cel[AnimFrame::ZOOMY]>1000 - @dirty[@currentcel]=true - end - if Input.repeatex?(0x6D) # "-" for zoom in - cel[AnimFrame::ZOOMX]-=10 - cel[AnimFrame::ZOOMX]=10 if cel[AnimFrame::ZOOMX]<10 - cel[AnimFrame::ZOOMY]-=10 - cel[AnimFrame::ZOOMY]=10 if cel[AnimFrame::ZOOMY]<10 - @dirty[@currentcel]=true - end - if !self.locked?(@currentcel) - if Input.repeat?(Input::UP) - increment=(Input.press?(Input::ALT)) ? 1 : 8 - cel[AnimFrame::Y]-=increment - @dirty[@currentcel]=true - end - if Input.repeat?(Input::DOWN) - increment=(Input.press?(Input::ALT)) ? 1 : 8 - cel[AnimFrame::Y]+=increment - @dirty[@currentcel]=true - end - if Input.repeat?(Input::LEFT) - increment=(Input.press?(Input::ALT)) ? 1 : 8 - cel[AnimFrame::X]-=increment - @dirty[@currentcel]=true - end - if Input.repeat?(Input::RIGHT) - increment=(Input.press?(Input::ALT)) ? 1 : 8 - cel[AnimFrame::X]+=increment - @dirty[@currentcel]=true - end - end - end - end - - def update - super - if @playing - if @player.animDone? - @playing=false - invalidate - else - @player.update - end - return - end - updateInput -# @testscreen.update -# self.bitmap=@testscreen.bitmap - if @currentframe < @animation.length - for i in 0...PBAnimation::MAX_SPRITES - if @dirty[i] - if @celsprites[i] - setBitmap(i,@currentframe) - pbSpriteSetAnimFrame(@celsprites[i],@animation[@currentframe][i],@celsprites[0],@celsprites[1],true) - @celsprites[i].x+=BORDERSIZE - @celsprites[i].y+=BORDERSIZE - end - setPreviousFrame(i) - setFrame(i) - @dirty[i]=false - end - end - else - for i in 0...PBAnimation::MAX_SPRITES - pbSpriteSetAnimFrame(@celsprites[i],nil,@celsprites[0],@celsprites[1],true) - @celsprites[i].x+=BORDERSIZE - @celsprites[i].y+=BORDERSIZE - setPreviousFrame(i) - setFrame(i) - @dirty[i]=false - end - end - end -end - - - -################################################################################ -# Pop-up menus for individual cels -################################################################################ -def pbChooseNum(cel) - ret=cel - sliderwin2=ControlWindow.new(0,0,320,32*5) - sliderwin2.z=99999 - sliderwin2.addLabel(_INTL("Old Number: {1}",cel)) - sliderwin2.addSlider(_INTL("New Number:"),2,PBAnimation::MAX_SPRITES,cel) - okbutton=sliderwin2.addButton(_INTL("OK")) - cancelbutton=sliderwin2.addButton(_INTL("Cancel")) - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - ret=sliderwin2.value(1) - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) - ret=-1 - break - end - end - sliderwin2.dispose - return ret -end - -def pbSetTone(cel,previewsprite) - sliderwin2=ControlWindow.new(0,0,320,320) - sliderwin2.z=99999 - sliderwin2.addSlider(_INTL("Red Offset:"),-255,255,cel[AnimFrame::TONERED]) - sliderwin2.addSlider(_INTL("Green Offset:"),-255,255,cel[AnimFrame::TONEGREEN]) - sliderwin2.addSlider(_INTL("Blue Offset:"),-255,255,cel[AnimFrame::TONEBLUE]) - sliderwin2.addSlider(_INTL("Gray Tone:"),0,255,cel[AnimFrame::TONEGRAY]) - okbutton=sliderwin2.addButton(_INTL("OK")) - cancelbutton=sliderwin2.addButton(_INTL("Cancel")) - loop do - previewsprite.tone.set( - sliderwin2.value(0), - sliderwin2.value(1), - sliderwin2.value(2), - sliderwin2.value(3) - ) - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - cel[AnimFrame::TONERED]=sliderwin2.value(0) - cel[AnimFrame::TONEGREEN]=sliderwin2.value(1) - cel[AnimFrame::TONEBLUE]=sliderwin2.value(2) - cel[AnimFrame::TONEGRAY]=sliderwin2.value(3) - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) - break - end - end - sliderwin2.dispose - return -end - -def pbSetFlash(cel,previewsprite) - sliderwin2=ControlWindow.new(0,0,320,320) - sliderwin2.z=99999 - sliderwin2.addSlider(_INTL("Red:"),0,255,cel[AnimFrame::COLORRED]) - sliderwin2.addSlider(_INTL("Green:"),0,255,cel[AnimFrame::COLORGREEN]) - sliderwin2.addSlider(_INTL("Blue:"),0,255,cel[AnimFrame::COLORBLUE]) - sliderwin2.addSlider(_INTL("Alpha:"),0,255,cel[AnimFrame::COLORALPHA]) - okbutton=sliderwin2.addButton(_INTL("OK")) - cancelbutton=sliderwin2.addButton(_INTL("Cancel")) - loop do - previewsprite.tone.set( - sliderwin2.value(0), - sliderwin2.value(1), - sliderwin2.value(2), - sliderwin2.value(3) - ) - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - cel[AnimFrame::COLORRED]=sliderwin2.value(0) - cel[AnimFrame::COLORGREEN]=sliderwin2.value(1) - cel[AnimFrame::COLORBLUE]=sliderwin2.value(2) - cel[AnimFrame::COLORALPHA]=sliderwin2.value(3) - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) - break - end - end - sliderwin2.dispose - return -end - -def pbCellProperties(canvas) - cel=canvas.currentCel.clone # Clone cell, in case operation is canceled - return if !cel - sliderwin2=ControlWindow.new(0,0,320,32*16) - previewwin=ControlWindow.new(320,0,192,192) - sliderwin2.viewport=canvas.viewport - previewwin.viewport=canvas.viewport - previewsprite=Sprite.new(canvas.viewport) - previewsprite.bitmap=canvas.animbitmap - previewsprite.z=previewwin.z+1 - sliderwin2.z=previewwin.z+2 - set0=sliderwin2.addSlider(_INTL("Pattern:"),-2,1000,cel[AnimFrame::PATTERN]) - set1=sliderwin2.addSlider(_INTL("X:"),-64,512+64,cel[AnimFrame::X]) - set2=sliderwin2.addSlider(_INTL("Y:"),-64,384+64,cel[AnimFrame::Y]) - set3=sliderwin2.addSlider(_INTL("Zoom X:"),5,1000,cel[AnimFrame::ZOOMX]) - set4=sliderwin2.addSlider(_INTL("Zoom Y:"),5,1000,cel[AnimFrame::ZOOMY]) - set5=sliderwin2.addSlider(_INTL("Angle:"),0,359,cel[AnimFrame::ANGLE]) - set6=sliderwin2.addSlider(_INTL("Opacity:"),0,255,cel[AnimFrame::OPACITY]) - set7=sliderwin2.addSlider(_INTL("Blending:"),0,2,cel[AnimFrame::BLENDTYPE]) - set8=sliderwin2.addTextSlider(_INTL("Flip:"),[_INTL("False"),_INTL("True")],cel[AnimFrame::MIRROR]) - prio=[_INTL("Back"),_INTL("Front"),_INTL("Behind focus"),_INTL("Above focus")] - set9=sliderwin2.addTextSlider(_INTL("Priority:"),prio,cel[AnimFrame::PRIORITY] || 1) - foc=[_INTL("User"),_INTL("Target"),_INTL("User and target"),_INTL("Screen")] - curfoc=[3,1,0,2,3][cel[AnimFrame::FOCUS] || canvas.animation.position || 4] - set10=sliderwin2.addTextSlider(_INTL("Focus:"),foc,curfoc) - flashbutton=sliderwin2.addButton(_INTL("Set Blending Color")) - tonebutton=sliderwin2.addButton(_INTL("Set Color Tone")) - okbutton=sliderwin2.addButton(_INTL("OK")) - cancelbutton=sliderwin2.addButton(_INTL("Cancel")) - # Set X and Y for preview sprite - cel[AnimFrame::X]=320+96 - cel[AnimFrame::Y]=96 - canvas.setSpriteBitmap(previewsprite,cel) - pbSpriteSetAnimFrame(previewsprite,cel,nil,nil) - previewsprite.z=previewwin.z+1 - sliderwin2.opacity=200 - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(set0) || - sliderwin2.changed?(set3) || - sliderwin2.changed?(set4) || - sliderwin2.changed?(set5) || - sliderwin2.changed?(set6) || - sliderwin2.changed?(set7) || - sliderwin2.changed?(set8) || - sliderwin2.changed?(set9) || - sliderwin2.changed?(set10) - # Update preview sprite - cel[AnimFrame::PATTERN]=sliderwin2.value(set0) if set0>=0 - cel[AnimFrame::ZOOMX]=sliderwin2.value(set3) - cel[AnimFrame::ZOOMY]=sliderwin2.value(set4) - cel[AnimFrame::ANGLE]=sliderwin2.value(set5) - cel[AnimFrame::OPACITY]=sliderwin2.value(set6) - cel[AnimFrame::BLENDTYPE]=sliderwin2.value(set7) - cel[AnimFrame::MIRROR]=sliderwin2.value(set8) - cel[AnimFrame::PRIORITY]=sliderwin2.value(set9) - cel[AnimFrame::FOCUS]=[2,1,3,4][sliderwin2.value(set10)] - canvas.setSpriteBitmap(previewsprite,cel) - pbSpriteSetAnimFrame(previewsprite,cel,nil,nil) - previewsprite.z=previewwin.z+1 - end - if sliderwin2.changed?(flashbutton) - pbSetFlash(cel,previewsprite) - pbSpriteSetAnimFrame(previewsprite,cel,nil,nil) - previewsprite.z=previewwin.z+1 - end - if sliderwin2.changed?(tonebutton) - pbSetTone(cel,previewsprite) - pbSpriteSetAnimFrame(previewsprite,cel,nil,nil) - previewsprite.z=previewwin.z+1 - end - if sliderwin2.changed?(okbutton) - cel[AnimFrame::PATTERN]=sliderwin2.value(set0) if set0>=0 - cel[AnimFrame::X]=sliderwin2.value(set1) - cel[AnimFrame::Y]=sliderwin2.value(set2) - cel[AnimFrame::ZOOMX]=sliderwin2.value(set3) - cel[AnimFrame::ZOOMY]=sliderwin2.value(set4) - cel[AnimFrame::ANGLE]=sliderwin2.value(set5) - cel[AnimFrame::OPACITY]=sliderwin2.value(set6) - cel[AnimFrame::BLENDTYPE]=sliderwin2.value(set7) - cel[AnimFrame::MIRROR]=sliderwin2.value(set8) - cel[AnimFrame::PRIORITY]=sliderwin2.value(set9) - cel[AnimFrame::FOCUS]=[2,1,3,4][sliderwin2.value(set10)] - thiscel=canvas.currentCel - # Save by replacing current cell - thiscel[0,thiscel.length]=cel - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) - break - end - end - previewwin.dispose - previewsprite.dispose - sliderwin2.dispose - return -end - -################################################################################ -# Pop-up menus for buttons in right hand menu -################################################################################ -def pbTimingList(canvas) - commands=[] - cmdNewSound=-1 - cmdNewBG=-1 - cmdEditBG=-1 - cmdNewFO=-1 - cmdEditFO=-1 - for i in canvas.animation.timing - commands.push(sprintf("%s",i)) - end - commands[cmdNewSound=commands.length]=_INTL("Add: Play Sound...") - commands[cmdNewBG=commands.length]=_INTL("Add: Set Background Graphic...") - commands[cmdEditBG=commands.length]=_INTL("Add: Edit Background Color/Location...") - commands[cmdNewFO=commands.length]=_INTL("Add: Set Foreground Graphic...") - commands[cmdEditFO=commands.length]=_INTL("Add: Edit Foreground Color/Location...") - cmdwin=pbListWindow(commands,480) - cmdwin.x=0 - cmdwin.y=0 - cmdwin.width=640 - cmdwin.height=384 - cmdwin.opacity=200 - cmdwin.viewport=canvas.viewport - framewindow=ControlWindow.new(0,384,640,32*4) - framewindow.addSlider(_INTL("Frame:"),1,canvas.animation.length,canvas.currentframe+1) - framewindow.addButton(_INTL("Set Frame")) - framewindow.addButton(_INTL("Delete Timing")) - framewindow.opacity=200 - framewindow.viewport=canvas.viewport - loop do - Graphics.update - Input.update - cmdwin.update - framewindow.update - if cmdwin.index!=cmdNewSound && - cmdwin.index!=cmdNewBG && - cmdwin.index!=cmdEditBG && - cmdwin.index!=cmdNewFO && - cmdwin.index!=cmdEditFO - if framewindow.changed?(1) # Set Frame - canvas.animation.timing[cmdwin.index].frame=framewindow.value(0)-1 - cmdwin.commands[cmdwin.index]=sprintf("%s",canvas.animation.timing[cmdwin.index]) - cmdwin.refresh - next - end - if framewindow.changed?(2) # Delete Timing - canvas.animation.timing.delete_at(cmdwin.index) - cmdwin.commands.delete_at(cmdwin.index) - cmdNewSound-=1 if cmdNewSound>=0 - cmdNewBG-=1 if cmdNewBG>=0 - cmdEditBG-=1 if cmdEditBG>=0 - cmdNewFO-=1 if cmdNewFO>=0 - cmdEditFO-=1 if cmdEditFO>=0 - cmdwin.refresh - next - end - end - if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) - redrawcmds=false - if cmdwin.index==cmdNewSound # Add new sound - newaudio=PBAnimTiming.new(0) - if pbSelectSE(canvas,newaudio) - newaudio.frame=framewindow.value(0)-1 - canvas.animation.timing.push(newaudio) - redrawcmds=true - end - elsif cmdwin.index==cmdNewBG # Add new background graphic set - newtiming=PBAnimTiming.new(1) - if pbSelectBG(canvas,newtiming) - newtiming.frame=framewindow.value(0)-1 - canvas.animation.timing.push(newtiming) - redrawcmds=true - end - elsif cmdwin.index==cmdEditBG # Add new background edit - newtiming=PBAnimTiming.new(2) - if pbEditBG(canvas,newtiming) - newtiming.frame=framewindow.value(0)-1 - canvas.animation.timing.push(newtiming) - redrawcmds=true - end - elsif cmdwin.index==cmdNewFO # Add new foreground graphic set - newtiming=PBAnimTiming.new(3) - if pbSelectBG(canvas,newtiming) - newtiming.frame=framewindow.value(0)-1 - canvas.animation.timing.push(newtiming) - redrawcmds=true - end - elsif cmdwin.index==cmdEditFO # Add new foreground edit - newtiming=PBAnimTiming.new(4) - if pbEditBG(canvas,newtiming) - newtiming.frame=framewindow.value(0)-1 - canvas.animation.timing.push(newtiming) - redrawcmds=true - end - else - # Edit a timing here - case canvas.animation.timing[cmdwin.index].timingType - when 0 - pbSelectSE(canvas,canvas.animation.timing[cmdwin.index]) - when 1, 3 - pbSelectBG(canvas,canvas.animation.timing[cmdwin.index]) - when 2, 4 - pbEditBG(canvas,canvas.animation.timing[cmdwin.index]) - end - cmdwin.commands[cmdwin.index]=sprintf("%s",canvas.animation.timing[cmdwin.index]) - cmdwin.refresh - end - if redrawcmds - cmdwin.commands[cmdNewSound]=nil if cmdNewSound>=0 - cmdwin.commands[cmdNewBG]=nil if cmdNewBG>=0 - cmdwin.commands[cmdEditBG]=nil if cmdEditBG>=0 - cmdwin.commands[cmdNewFO]=nil if cmdNewFO>=0 - cmdwin.commands[cmdEditFO]=nil if cmdEditFO>=0 - cmdwin.commands.compact! - cmdwin.commands.push(sprintf("%s",canvas.animation.timing[canvas.animation.timing.length-1])) - cmdwin.commands[cmdNewSound=cmdwin.commands.length]=_INTL("Add: Play Sound...") - cmdwin.commands[cmdNewBG=cmdwin.commands.length]=_INTL("Add: Set Background Graphic...") - cmdwin.commands[cmdEditBG=cmdwin.commands.length]=_INTL("Add: Edit Background Color/Location...") - cmdwin.commands[cmdNewFO=cmdwin.commands.length]=_INTL("Add: Set Foreground Graphic...") - cmdwin.commands[cmdEditFO=cmdwin.commands.length]=_INTL("Add: Edit Foreground Color/Location...") - cmdwin.refresh - end - elsif Input.trigger?(Input::B) - break - end - end - cmdwin.dispose - framewindow.dispose - return -end - -def pbSelectSE(canvas,audio) - filename=(audio.name!="") ? audio.name : "" - displayname=(filename!="") ? filename : _INTL("") - animfiles=[] - ret=false - pbRgssChdir(".\\Audio\\SE\\Anim\\") { - animfiles.concat(Dir.glob("*.wav")) - animfiles.concat(Dir.glob("*.mp3")) - animfiles.concat(Dir.glob("*.ogg")) - animfiles.concat(Dir.glob("*.wma")) - } - animfiles.sort! { |a,b| a.upcase<=>b.upcase } - animfiles=[_INTL("[Play user's cry]")]+animfiles - cmdwin=pbListWindow(animfiles,320) - cmdwin.height=480 - cmdwin.opacity=200 - cmdwin.viewport=canvas.viewport - maxsizewindow=ControlWindow.new(320,0,320,32*8) - maxsizewindow.addLabel(_INTL("File: \"{1}\"",displayname)) - maxsizewindow.addSlider(_INTL("Volume:"),0,100,audio.volume) - maxsizewindow.addSlider(_INTL("Pitch:"),20,250,audio.pitch) - maxsizewindow.addButton(_INTL("Play Sound")) - maxsizewindow.addButton(_INTL("Stop Sound")) - maxsizewindow.addButton(_INTL("OK")) - maxsizewindow.addButton(_INTL("Cancel")) - maxsizewindow.opacity=200 - maxsizewindow.viewport=canvas.viewport - loop do - Graphics.update - Input.update - cmdwin.update - maxsizewindow.update - if maxsizewindow.changed?(3) && animfiles.length>0 # Play Sound - fname = (cmdwin.index==0) ? "Cries/001Cry" : "Anim/"+filename - pbSEPlay(RPG::AudioFile.new(fname,maxsizewindow.value(1),maxsizewindow.value(2))) - end - if maxsizewindow.changed?(4) && animfiles.length>0 # Stop Sound - pbSEStop - end - if maxsizewindow.changed?(5) # OK - filename = File.basename(filename,".wav") - filename = File.basename(filename,".mp3") - filename = File.basename(filename,".ogg") - filename = File.basename(filename,".wma") - audio.name=filename - audio.volume=maxsizewindow.value(1) - audio.pitch=maxsizewindow.value(2) - ret=true - break - end - if maxsizewindow.changed?(6) # Cancel - break - end - if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) && animfiles.length>0 - filename=(cmdwin.index==0) ? "" : cmdwin.commands[cmdwin.index] - displayname=(filename!="") ? filename : _INTL("") - maxsizewindow.controls[0].text=_INTL("File: \"{1}\"",displayname) - elsif Input.trigger?(Input::B) - break - end - end - cmdwin.dispose - maxsizewindow.dispose - return ret -end - -def pbSelectBG(canvas,timing) - filename=timing.name - cmdErase=-1 - animfiles=[] - animfiles[cmdErase=animfiles.length]=_INTL("[Erase background graphic]") - ret=false - pbRgssChdir(".\\Graphics\\Animations\\") { - animfiles.concat(Dir.glob("*.bmp")) - animfiles.concat(Dir.glob("*.png")) - animfiles.concat(Dir.glob("*.jpg")) - animfiles.concat(Dir.glob("*.jpeg")) - animfiles.concat(Dir.glob("*.gif")) - } - cmdwin=pbListWindow(animfiles,320) - cmdwin.height=480 - cmdwin.opacity=200 - cmdwin.viewport=canvas.viewport - maxsizewindow=ControlWindow.new(320,0,320,32*11) - maxsizewindow.addLabel(_INTL("File: \"{1}\"",filename)) - maxsizewindow.addSlider(_INTL("X:"),-500,500,timing.bgX || 0) - maxsizewindow.addSlider(_INTL("Y:"),-500,500,timing.bgY || 0) - maxsizewindow.addSlider(_INTL("Opacity:"),0,255,timing.opacity || 0) - maxsizewindow.addSlider(_INTL("Red:"),0,255,timing.colorRed || 0) - maxsizewindow.addSlider(_INTL("Green:"),0,255,timing.colorGreen || 0) - maxsizewindow.addSlider(_INTL("Blue:"),0,255,timing.colorBlue || 0) - maxsizewindow.addSlider(_INTL("Alpha:"),0,255,timing.colorAlpha || 0) - maxsizewindow.addButton(_INTL("OK")) - maxsizewindow.addButton(_INTL("Cancel")) - maxsizewindow.opacity=200 - maxsizewindow.viewport=canvas.viewport - loop do - Graphics.update - Input.update - cmdwin.update - maxsizewindow.update - if maxsizewindow.changed?(8) # OK - timing.name=filename - timing.bgX=maxsizewindow.value(1) - timing.bgY=maxsizewindow.value(2) - timing.opacity=maxsizewindow.value(3) - timing.colorRed=maxsizewindow.value(4) - timing.colorGreen=maxsizewindow.value(5) - timing.colorBlue=maxsizewindow.value(6) - timing.colorAlpha=maxsizewindow.value(7) - ret=true - break - end - if maxsizewindow.changed?(9) # Cancel - break - end - if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) && animfiles.length>0 - filename=(cmdwin.index==cmdErase) ? "" : cmdwin.commands[cmdwin.index] - maxsizewindow.controls[0].text=_INTL("File: \"{1}\"",filename) - elsif Input.trigger?(Input::B) - break - end - end - cmdwin.dispose - maxsizewindow.dispose - return ret -end - -def pbEditBG(canvas,timing) - ret=false - maxsizewindow=ControlWindow.new(0,0,320,32*11) - maxsizewindow.addSlider(_INTL("Duration:"),0,50,timing.duration) - maxsizewindow.addOptionalSlider(_INTL("X:"),-500,500,timing.bgX || 0) - maxsizewindow.addOptionalSlider(_INTL("Y:"),-500,500,timing.bgY || 0) - maxsizewindow.addOptionalSlider(_INTL("Opacity:"),0,255,timing.opacity || 0) - maxsizewindow.addOptionalSlider(_INTL("Red:"),0,255,timing.colorRed || 0) - maxsizewindow.addOptionalSlider(_INTL("Green:"),0,255,timing.colorGreen || 0) - maxsizewindow.addOptionalSlider(_INTL("Blue:"),0,255,timing.colorBlue || 0) - maxsizewindow.addOptionalSlider(_INTL("Alpha:"),0,255,timing.colorAlpha || 0) - maxsizewindow.addButton(_INTL("OK")) - maxsizewindow.addButton(_INTL("Cancel")) - maxsizewindow.controls[1].checked=(timing.bgX!=nil) - maxsizewindow.controls[2].checked=(timing.bgY!=nil) - maxsizewindow.controls[3].checked=(timing.opacity!=nil) - maxsizewindow.controls[4].checked=(timing.colorRed!=nil) - maxsizewindow.controls[5].checked=(timing.colorGreen!=nil) - maxsizewindow.controls[6].checked=(timing.colorBlue!=nil) - maxsizewindow.controls[7].checked=(timing.colorAlpha!=nil) - maxsizewindow.opacity=200 - maxsizewindow.viewport=canvas.viewport - loop do - Graphics.update - Input.update - maxsizewindow.update - if maxsizewindow.changed?(8) # OK - if maxsizewindow.controls[1].checked || - maxsizewindow.controls[2].checked || - maxsizewindow.controls[3].checked || - maxsizewindow.controls[4].checked || - maxsizewindow.controls[5].checked || - maxsizewindow.controls[6].checked || - maxsizewindow.controls[7].checked - timing.duration=maxsizewindow.value(0) - timing.bgX=maxsizewindow.value(1) - timing.bgY=maxsizewindow.value(2) - timing.opacity=maxsizewindow.value(3) - timing.colorRed=maxsizewindow.value(4) - timing.colorGreen=maxsizewindow.value(5) - timing.colorBlue=maxsizewindow.value(6) - timing.colorAlpha=maxsizewindow.value(7) - ret=true - break - else - break - end - end - if maxsizewindow.changed?(9) # Cancel - break - end - if Input.trigger?(Input::B) - break - end - end - maxsizewindow.dispose - return ret -end - -def pbCopyFrames(canvas) - sliderwin2=ControlWindow.new(0,0,320,32*6) - sliderwin2.viewport=canvas.viewport - sliderwin2.addSlider(_INTL("First Frame:"),1,canvas.animation.length,1) - sliderwin2.addSlider(_INTL("Last Frame:"),1,canvas.animation.length,canvas.animation.length) - sliderwin2.addSlider(_INTL("Copy to:"),1,canvas.animation.length,canvas.currentframe+1) - okbutton=sliderwin2.addButton(_INTL("OK")) - cancelbutton=sliderwin2.addButton(_INTL("Cancel")) - sliderwin2.opacity=200 - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - startvalue=sliderwin2.value(0)-1 - endvalue=sliderwin2.value(1)-1 - dstvalue=sliderwin2.value(2)-1 - length=(endvalue-startvalue)+1 - if length>0 # Ensure correct overlap handling - if (startvalue=endframe - frames=endframe-startframe - startcel=sliderwin2.value(s1set2) - endcel=sliderwin2.value(s1set3) - for j in startcel..endcel - cel1=canvas.animation[startframe][j] - cel2=canvas.animation[endframe][j] - next if !cel1||!cel2 - diffPattern=cel2[AnimFrame::PATTERN]-cel1[AnimFrame::PATTERN] - diffX=cel2[AnimFrame::X]-cel1[AnimFrame::X] - diffY=cel2[AnimFrame::Y]-cel1[AnimFrame::Y] - diffZoomX=cel2[AnimFrame::ZOOMX]-cel1[AnimFrame::ZOOMX] - diffZoomY=cel2[AnimFrame::ZOOMY]-cel1[AnimFrame::ZOOMY] - diffAngle=cel2[AnimFrame::ANGLE]-cel1[AnimFrame::ANGLE] - diffOpacity=cel2[AnimFrame::OPACITY]-cel1[AnimFrame::OPACITY] - diffBlend=cel2[AnimFrame::BLENDTYPE]-cel1[AnimFrame::BLENDTYPE] - startPattern=cel1[AnimFrame::PATTERN] - startX=cel1[AnimFrame::X] - startY=cel1[AnimFrame::Y] - startZoomX=cel1[AnimFrame::ZOOMX] - startZoomY=cel1[AnimFrame::ZOOMY] - startAngle=cel1[AnimFrame::ANGLE] - startOpacity=cel1[AnimFrame::OPACITY] - startBlend=cel1[AnimFrame::BLENDTYPE] - for k in 0..frames - cel=canvas.animation[startframe+k][j] - curcel=cel - if !cel - cel=pbCreateCel(0,0,0) - canvas.animation[startframe+k][j]=cel - end - if sliderwin2.value(set0) || !curcel - cel[AnimFrame::PATTERN]=startPattern+(diffPattern*k/frames) - end - if sliderwin2.value(set1) || !curcel - cel[AnimFrame::X]=startX+(diffX*k/frames) - cel[AnimFrame::Y]=startY+(diffY*k/frames) - cel[AnimFrame::ZOOMX]=startZoomX+(diffZoomX*k/frames) - cel[AnimFrame::ZOOMY]=startZoomY+(diffZoomY*k/frames) - cel[AnimFrame::ANGLE]=startAngle+(diffAngle*k/frames) - end - if sliderwin2.value(set2) || !curcel - cel[AnimFrame::OPACITY]=startOpacity+(diffOpacity*k/frames) - cel[AnimFrame::BLENDTYPE]=startBlend+(diffBlend*k/frames) - end - end - end - canvas.invalidate - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) - break - end - end - sliderwin2.dispose -end - -def pbCellBatch(canvas) - sliderwin1=ControlWindow.new(0,0,300,32*5) - sliderwin1.viewport=canvas.viewport - sliderwin1.opacity=200 - s1set0=sliderwin1.addSlider(_INTL("First Frame:"),1,canvas.animation.length,1) - s1set1=sliderwin1.addSlider(_INTL("Last Frame:"),1,canvas.animation.length,canvas.animation.length) - s1set2=sliderwin1.addSlider(_INTL("First Cel:"),0,PBAnimation::MAX_SPRITES-1,0) - s1set3=sliderwin1.addSlider(_INTL("Last Cel:"),0,PBAnimation::MAX_SPRITES-1,PBAnimation::MAX_SPRITES-1) - sliderwin2=ControlWindow.new(300,0,340,32*14) - sliderwin2.viewport=canvas.viewport - sliderwin2.opacity=200 - set0=sliderwin2.addOptionalSlider(_INTL("Pattern:"),-2,1000,0) - set1=sliderwin2.addOptionalSlider(_INTL("X:"),-64,512+64,0) - set2=sliderwin2.addOptionalSlider(_INTL("Y:"),-64,384+64,0) - set3=sliderwin2.addOptionalSlider(_INTL("Zoom X:"),5,1000,100) - set4=sliderwin2.addOptionalSlider(_INTL("Zoom Y:"),5,1000,100) - set5=sliderwin2.addOptionalSlider(_INTL("Angle:"),0,359,0) - set6=sliderwin2.addOptionalSlider(_INTL("Opacity:"),0,255,255) - set7=sliderwin2.addOptionalSlider(_INTL("Blending:"),0,2,0) - set8=sliderwin2.addOptionalTextSlider(_INTL("Flip:"),[_INTL("False"),_INTL("True")],0) - prio=[_INTL("Back"),_INTL("Front"),_INTL("Behind focus"),_INTL("Above focus")] - set9=sliderwin2.addOptionalTextSlider(_INTL("Priority:"),prio,1) - foc=[_INTL("User"),_INTL("Target"),_INTL("User and target"),_INTL("Screen")] - curfoc=[3,1,0,2,3][canvas.animation.position || 4] - set10=sliderwin2.addOptionalTextSlider(_INTL("Focus:"),foc,curfoc) - okbutton=sliderwin2.addButton(_INTL("OK")) - cancelbutton=sliderwin2.addButton(_INTL("Cancel")) - loop do - Graphics.update - Input.update - sliderwin1.update - sliderwin2.update - if sliderwin2.changed?(okbutton) || Input.trigger?(Input::C) - startframe=sliderwin1.value(s1set0)-1 - endframe=sliderwin1.value(s1set1)-1 - startcel=sliderwin1.value(s1set2) - endcel=sliderwin1.value(s1set3) - for i in startframe..endframe - for j in startcel..endcel - next if !canvas.animation[i][j] - cel=canvas.animation[i][j] - cel[AnimFrame::PATTERN]=sliderwin2.value(set0) if sliderwin2.value(set0) - cel[AnimFrame::X]=sliderwin2.value(set1) if sliderwin2.value(set1) - cel[AnimFrame::Y]=sliderwin2.value(set2) if sliderwin2.value(set2) - cel[AnimFrame::ZOOMX]=sliderwin2.value(set3) if sliderwin2.value(set3) - cel[AnimFrame::ZOOMY]=sliderwin2.value(set4) if sliderwin2.value(set4) - cel[AnimFrame::ANGLE]=sliderwin2.value(set5) if sliderwin2.value(set5) - cel[AnimFrame::OPACITY]=sliderwin2.value(set6) if sliderwin2.value(set6) - cel[AnimFrame::BLENDTYPE]=sliderwin2.value(set7) if sliderwin2.value(set7) - cel[AnimFrame::MIRROR]=sliderwin2.value(set8) if sliderwin2.value(set8) - cel[AnimFrame::PRIORITY]=sliderwin2.value(set9) if sliderwin2.value(set9) - cel[AnimFrame::FOCUS]=[2,1,3,4][sliderwin2.value(set10)] if sliderwin2.value(set10) - end - end - canvas.invalidate - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) - break - end - end - sliderwin1.dispose - sliderwin2.dispose -end - -def pbEntireSlide(canvas) - sliderwin2=ControlWindow.new(0,0,320,32*7) - sliderwin2.viewport=canvas.viewport - sliderwin2.addSlider(_INTL("First Frame:"),1,canvas.animation.length,1) - sliderwin2.addSlider(_INTL("Last Frame:"),1,canvas.animation.length,canvas.animation.length) - sliderwin2.addSlider(_INTL("X-Axis Movement"),-500,500,0) - sliderwin2.addSlider(_INTL("Y-Axis Movement"),-500,500,0) - okbutton=sliderwin2.addButton(_INTL("OK")) - cancelbutton=sliderwin2.addButton(_INTL("Cancel")) - sliderwin2.opacity=200 - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - startvalue=sliderwin2.value(0)-1 - endvalue=sliderwin2.value(1)-1 - xoffset=sliderwin2.value(2) - yoffset=sliderwin2.value(3) - for i in startvalue..endvalue - canvas.offsetFrame(i,xoffset,yoffset) - end - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) - break - end - end - sliderwin2.dispose - return -end - -def pbHelpWindow - helptext=""+ - "To add a cel to the scene, click on the canvas. The selected cel will have a black "+ - "frame. After a cel is selected, you can modify its properties using the keyboard:\n"+ - "E, R - Rotate left/right;\nP - Open properties screen;\nArrow keys - Move cel 8 pixels "+ - "(hold ALT for 2 pixels);\n+/- : Zoom in/out;\nL - Lock a cel. Locking a cel prevents it "+ - "from being moved or deleted.\nDEL - Deletes the cel.\nAlso press TAB to switch the selected cel." - cmdwin=Window_UnformattedTextPokemon.newWithSize("",0,0,640,512) - cmdwin.opacity=224 - cmdwin.z=99999 - cmdwin.text=helptext - loop do - Graphics.update - Input.update - cmdwin.update - break if Input.trigger?(Input::B) || Input.trigger?(Input::C) - end - cmdwin.dispose -end - - - -################################################################################ -# Pop-up menus for buttons in bottom menu -################################################################################ -def pbSelectAnim(canvas,animwin) - animfiles=[] - pbRgssChdir(".\\Graphics\\Animations\\") { - animfiles.concat(Dir.glob("*.png")) - } - cmdwin=pbListWindow(animfiles,320) - cmdwin.opacity=200 - cmdwin.height=512 - bmpwin=BitmapDisplayWindow.new(320,0,320,448) - ctlwin=ControlWindow.new(320,448,320,64) - cmdwin.viewport=canvas.viewport - bmpwin.viewport=canvas.viewport - ctlwin.viewport=canvas.viewport - ctlwin.addSlider(_INTL("Hue:"),0,359,0) - loop do - bmpwin.bitmapname=cmdwin.commands[cmdwin.index] - Graphics.update - Input.update - cmdwin.update - bmpwin.update - ctlwin.update - bmpwin.hue=ctlwin.value(0) if ctlwin.changed?(0) - if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) && animfiles.length>0 - bitmap=AnimatedBitmap.new("Graphics/Animations/"+cmdwin.commands[cmdwin.index],ctlwin.value(0)).deanimate - canvas.animation.graphic=cmdwin.commands[cmdwin.index] - canvas.animation.hue=ctlwin.value(0) - canvas.animbitmap=bitmap - animwin.animbitmap=bitmap - break - end - if Input.trigger?(Input::B) - break - end - end - bmpwin.dispose - cmdwin.dispose - ctlwin.dispose - return -end - -def pbChangeMaximum(canvas) - sliderwin2=ControlWindow.new(0,0,320,32*4) - sliderwin2.viewport=canvas.viewport - sliderwin2.addSlider(_INTL("Frames:"),1,1000,canvas.animation.length) - okbutton=sliderwin2.addButton(_INTL("OK")) - cancelbutton=sliderwin2.addButton(_INTL("Cancel")) - sliderwin2.opacity=200 - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - canvas.animation.resize(sliderwin2.value(0)) - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) - break - end - end - sliderwin2.dispose - return -end - -def pbAnimName(animation,cmdwin) - window=ControlWindow.new(320,128,320,32*4) - window.z=99999 - window.addControl(TextField.new(_INTL("New Name:"),animation.name)) - okbutton=window.addButton(_INTL("OK")) - cancelbutton=window.addButton(_INTL("Cancel")) - window.opacity=224 - loop do - Graphics.update - Input.update - window.update - if window.changed?(okbutton) || Input.trigger?(Input::ENTER) - cmdwin.commands[cmdwin.index]=_INTL("{1} {2}",cmdwin.index,window.controls[0].text) - animation.name=window.controls[0].text - break - end - if window.changed?(cancelbutton) || Input.trigger?(Input::ESC) - break - end - end - window.dispose - return -end - -def pbAnimList(animations,canvas,animwin) - commands=[] - for i in 0...animations.length - animations[i]=PBAnimation.new if !animations[i] - commands[commands.length]=_INTL("{1} {2}",i,animations[i].name) - end - cmdwin=pbListWindow(commands,320) - cmdwin.height=416 - cmdwin.opacity=224 - cmdwin.index=animations.selected - cmdwin.viewport=canvas.viewport - helpwindow=Window_UnformattedTextPokemon.newWithSize( - _INTL("C: Load/rename an animation\nEsc: Cancel"), - 320,0,320,128,canvas.viewport) - maxsizewindow=ControlWindow.new(0,416,320,32*3) - maxsizewindow.addSlider(_INTL("Total Animations:"),1,2000,animations.length) - maxsizewindow.addButton(_INTL("Resize Animation List")) - maxsizewindow.opacity=224 - maxsizewindow.viewport=canvas.viewport - loop do - Graphics.update - Input.update - cmdwin.update - maxsizewindow.update - helpwindow.update - if maxsizewindow.changed?(1) - newsize=maxsizewindow.value(0) - animations.resize(newsize) - commands.clear - for i in 0...animations.length - commands[commands.length]=_INTL("{1} {2}",i,animations[i].name) - end - cmdwin.commands=commands - cmdwin.index=animations.selected - next - end - if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) && animations.length>0 - cmd2=pbShowCommands(helpwindow,[ - _INTL("Load Animation"), - _INTL("Rename"), - _INTL("Delete") - ],-1) - if cmd2==0 # Load Animation - canvas.loadAnimation(animations[cmdwin.index]) - animwin.animbitmap=canvas.animbitmap - animations.selected=cmdwin.index - break - elsif cmd2==1 # Rename - pbAnimName(animations[cmdwin.index],cmdwin) - cmdwin.refresh - elsif cmd2==2 # Delete - if pbConfirmMessage(_INTL("Are you sure you want to delete this animation?")) - animations[cmdwin.index]=PBAnimation.new - cmdwin.commands[cmdwin.index]=_INTL("{1} {2}",cmdwin.index,animations[cmdwin.index].name) - cmdwin.refresh - end - end - end - if Input.trigger?(Input::B) - break - end - end - helpwindow.dispose - maxsizewindow.dispose - cmdwin.dispose -end - -################################################################################ -# Importing and exporting -################################################################################ -def pbRgssChdir(dir) - RTP.eachPathFor(dir) { |path| Dir.chdir(path) { yield } } -end - -def tryLoadData(file) - begin - return load_data(file) - rescue - return nil - end -end - -def dumpBase64Anim(s) - return [Zlib::Deflate.deflate(Marshal.dump(s))].pack("m").gsub(/\n/,"\r\n") -end - -def loadBase64Anim(s) - return Marshal.restore(StringInput.new(Zlib::Inflate.inflate(s.unpack("m")[0]))) -end - -def pbExportAnim(animations) - filename=pbMessageFreeText(_INTL("Enter a filename."),"",false,32) - if filename!="" - begin - filename+=".anm" - File.open(filename,"wb") { |f| - f.write(dumpBase64Anim(animations[animations.selected])) - } - failed=false - rescue - pbMessage(_INTL("Couldn't save the animation to {1}.",filename)) - failed=true - end - if !failed - pbMessage(_INTL("Animation was saved to {1} in the game folder.",filename)) - pbMessage(_INTL("It's a text file, so it can be transferred to others easily.")) - end - end -end - -def pbImportAnim(animations,canvas,animwin) - animfiles=[] - pbRgssChdir(".") { - animfiles.concat(Dir.glob("*.anm")) - } - cmdwin=pbListWindow(animfiles,320) - cmdwin.opacity=200 - cmdwin.height=480 - cmdwin.viewport=canvas.viewport - loop do - Graphics.update - Input.update - cmdwin.update - if (Input.trigger?(Input::C) || (cmdwin.doubleclick? rescue false)) && animfiles.length>0 - begin - textdata=loadBase64Anim(IO.read(animfiles[cmdwin.index])) - throw "Bad data" if !textdata.is_a?(PBAnimation) - textdata.id=-1 # this is not an RPG Maker XP animation - pbConvertAnimToNewFormat(textdata) - animations[animations.selected]=textdata - rescue - pbMessage(_INTL("The animation is invalid or could not be loaded.")) - next - end - graphic=animations[animations.selected].graphic - graphic="Graphics/Animations/#{graphic}" - if graphic && graphic!="" && !FileTest.image_exist?(graphic) - pbMessage(_INTL("The animation file {1} was not found. The animation will load anyway.",graphic)) - end - canvas.loadAnimation(animations[animations.selected]) - animwin.animbitmap=canvas.animbitmap - break - end - if Input.trigger?(Input::B) - break - end - end - cmdwin.dispose - return -end - - - -################################################################################ -# Paths and interpolation -################################################################################ -class ControlPointSprite < SpriteWrapper - attr_accessor :dragging - - def initialize(red,viewport=nil) - super(viewport) - self.bitmap=Bitmap.new(6,6) - self.bitmap.fill_rect(0,0,6,1,Color.new(0,0,0)) - self.bitmap.fill_rect(0,0,1,6,Color.new(0,0,0)) - self.bitmap.fill_rect(0,5,6,1,Color.new(0,0,0)) - self.bitmap.fill_rect(5,0,1,6,Color.new(0,0,0)) - color=(red) ? Color.new(255,0,0) : Color.new(0,0,0) - self.bitmap.fill_rect(2,2,2,2,color) - self.x=-6 - self.y=-6 - self.visible=false - @dragging=false - end - - def mouseover - if Input.repeatcount(Input::LeftMouseKey)==0 || !@dragging - @dragging=false - return - end - mouse=Mouse::getMousePos(true) - return if !mouse - self.x=[[mouse[0],0].max,512].min - self.y=[[mouse[1],0].max,384].min - end - - def hittest? - return true if !self.visible - mouse=Mouse::getMousePos(true) - return false if !mouse - return mouse[0]>=self.x && mouse[0]=self.y && mouse[1]1 - len=@points.length - dx=@points[len-2][0]-@points[len-1][0] - dy=@points[len-2][1]-@points[len-1][1] - dist=Math.sqrt(dx*dx+dy*dy) - @distances.push(dist) - @totaldist+=dist - end - end - - def clear - @points.clear - @distances.clear - @totaldist=0 - end - - def smoothPointPath(frames,roundValues=false) - if frames<0 - raise ArgumentError.new("frames out of range: #{frames}") - end - ret=PointPath.new - if @points.length==0 - return ret - end - step=1.0/frames - t=0.0 - (frames+2).times do - point=pointOnPath(t) - if roundValues - ret.addPoint(point[0].round,point[1].round) - else - ret.addPoint(point[0],point[1]) - end - t+=step - t=[1.0,t].min - end - return ret - end - - def pointOnPath(t) - if t<0 || t>1 - raise ArgumentError.new("t out of range for pointOnPath: #{t}") - end - return nil if @points.length==0 - ret=@points[@points.length-1].clone - if @points.length==1 - return ret - end - curdist=0 - distForT=@totaldist*t - i=0 - for dist in @distances - curdist+=dist - if dist>0.0 - if curdist>=distForT - distT=1.0-((curdist-distForT)/dist) - dx=@points[i+1][0]-@points[i][0] - dy=@points[i+1][1]-@points[i][1] - ret=[@points[i][0]+dx*distT, - @points[i][1]+dy*distT] - break - end - end - i+=1 - end - return ret - end -end - - - -def catmullRom(p1,p2,p3,p4,t) - # p1=prevPoint, p2=startPoint, p3=endPoint, p4=nextPoint, t is from 0 through 1 - t2=t*t - t3=t2*t - return 0.5*(2*p2+t*(p3-p1) + - t2*(2*p1-5*p2+4*p3-p4)+ - t3*(p4-3*p3+3*p2-p1)) -end - -def getCatmullRomPoint(src,t) - x=0,y=0 - t*=3.0 - if t<1.0 - x=catmullRom(src[0].x,src[0].x,src[1].x,src[2].x,t) - y=catmullRom(src[0].y,src[0].y,src[1].y,src[2].y,t) - elsif t<2.0 - t-=1.0 - x=catmullRom(src[0].x,src[1].x,src[2].x,src[3].x,t) - y=catmullRom(src[0].y,src[1].y,src[2].y,src[3].y,t) - else - t-=2.0 - x=catmullRom(src[1].x,src[2].x,src[3].x,src[3].x,t) - y=catmullRom(src[1].y,src[2].y,src[3].y,src[3].y,t) - end - return [x,y] -end - -def getCurvePoint(src,t) - return getCatmullRomPoint(src,t) -end - -def curveToPointPath(curve,numpoints) - if numpoints<2 - return nil - end - path=PointPath.new - step=1.0/(numpoints-1) - t=0.0 - numpoints.times do - point=getCurvePoint(curve,t) - path.addPoint(point[0],point[1]) - t+=step - end - return path -end - -def pbDefinePath(canvas) - sliderwin2=ControlWindow.new(0,0,320,320) - sliderwin2.viewport=canvas.viewport - sliderwin2.addSlider(_INTL("Number of frames:"),2,500,20) - sliderwin2.opacity=200 - defcurvebutton=sliderwin2.addButton(_INTL("Define Smooth Curve")) - defpathbutton=sliderwin2.addButton(_INTL("Define Freehand Path")) - okbutton=sliderwin2.addButton(_INTL("OK")) - cancelbutton=sliderwin2.addButton(_INTL("Cancel")) - points=[] - path=nil - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(0) # Number of frames - if path - path=path.smoothPointPath(sliderwin2.value(0),false) - i=0 - for point in path - if icanvas.animation.length - canvas.animation.resize(neededsize) - end - thiscel=canvas.currentCel - celnumber=canvas.currentcel - for i in canvas.currentframe...neededsize - cel=canvas.animation[i][celnumber] - if !canvas.animation[i][celnumber] - cel=pbCreateCel(0,0,thiscel[AnimFrame::PATTERN],canvas.animation.position) - canvas.animation[i][celnumber]=cel - end - cel[AnimFrame::X]=path[i-canvas.currentframe][0] - cel[AnimFrame::Y]=path[i-canvas.currentframe][1] - end - break - elsif sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::B) - break - end - end - # dispose all points - for point in points - point.dispose - end - points.clear - sliderwin2.dispose - return -end - - - -################################################################################ -# Window classes -################################################################################ -class BitmapDisplayWindow < SpriteWindow_Base - attr_reader :bitmapname - attr_reader :hue - - def initialize(x,y,width,height) - super(x,y,width,height) - @bitmapname="" - @hue=0 - self.contents=Bitmap.new(width-32,height-32) - end - - def bitmapname=(value) - if @bitmapname!=value - @bitmapname=value - refresh - end - end - - def hue=(value) - if @hue!=value - @hue=value - refresh - end - end - - def refresh - self.contents.clear - bmap=AnimatedBitmap.new("Graphics/Animations/"+@bitmapname,@hue).deanimate - return if !bmap - ww=bmap.width - wh=bmap.height - sx=self.contents.width*1.0/ww - sy=self.contents.height*1.0/wh - if sx>sy - ww=sy*ww - wh=self.contents.height - else - wh=sx*wh - ww=self.contents.width - end - dest=Rect.new( - (self.contents.width-ww)/2, - (self.contents.height-wh)/2, - ww,wh) - src=Rect.new(0,0,bmap.width,bmap.height) - self.contents.stretch_blt(dest,bmap,src) - bmap.dispose - end -end - - - -class AnimationNameWindow - def initialize(canvas,x,y,width,height,viewport=nil) - @canvas=canvas - @oldname=nil - @window=Window_UnformattedTextPokemon.newWithSize( - _INTL("Name: {1}",@canvas.animation.name),x,y,width,height,viewport) - end - - def viewport=(value); @window.viewport=value; end - - def update - newtext=_INTL("Name: {1}",@canvas.animation.name) - if @oldname!=newtext - @window.text=newtext - @oldname=newtext - end - @window.update - end - - def refresh; @window.refresh; end - def dispose; @window.dispose; end - def disposed; @window.disposed?; end -end - - - -################################################################################ -# Main -################################################################################ -def animationEditorMain(animation) - viewport=Viewport.new(0, 0, SCREEN_WIDTH + 288, SCREEN_HEIGHT + 288) - viewport.z=99999 - # Canvas - canvas=AnimationCanvas.new(animation[animation.selected],viewport) - # Right hand menu - sidewin=ControlWindow.new(512+128,0,160,384+128) - sidewin.addButton(_INTL("SE and BG...")) - sidewin.addButton(_INTL("Cel Focus...")) - sidewin.addSpace - sidewin.addButton(_INTL("Paste Last")) - sidewin.addButton(_INTL("Copy Frames...")) - sidewin.addButton(_INTL("Clear Frames...")) - sidewin.addButton(_INTL("Tweening...")) - sidewin.addButton(_INTL("Cel Batch...")) - sidewin.addButton(_INTL("Entire Slide...")) - sidewin.addSpace - sidewin.addButton(_INTL("Play Animation")) - sidewin.addButton(_INTL("Play Opp Anim")) - sidewin.addButton(_INTL("Import Anim...")) - sidewin.addButton(_INTL("Export Anim...")) - sidewin.addButton(_INTL("Help")) - sidewin.viewport=canvas.viewport - # Bottom left menu - sliderwin=ControlWindow.new(0,384+128,240,160) - sliderwin.addControl(FrameCountSlider.new(canvas)) - sliderwin.addControl(FrameCountButton.new(canvas)) - sliderwin.addButton(_INTL("Set Animation Sheet")) - sliderwin.addButton(_INTL("List of Animations")) - sliderwin.viewport=canvas.viewport - # Animation sheet window - animwin=CanvasAnimationWindow.new(canvas,240,384+128,512,96,canvas.viewport) - # Name window - bottomwindow=AnimationNameWindow.new(canvas,240,384+128+96,512,64,canvas.viewport) - loop do - Graphics.update - Input.update - sliderwin.update - canvas.update - sidewin.update - animwin.update - bottomwindow.update - if animwin.changed? - canvas.pattern=animwin.selected - end - if Input.trigger?(Input::B) - if pbConfirmMessage(_INTL("Save changes?")) - save_data(animation,"Data/PkmnAnimations.rxdata") - $PokemonTemp.battleAnims = nil - end - if pbConfirmMessage(_INTL("Exit from the editor?")) - break - end - end - if Input.trigger?(Input::ONLYF5) - pbHelpWindow - next - elsif Input.triggerex?(Input::RightMouseKey) && sliderwin.hittest?(0) # Right mouse button - commands=[ - _INTL("Copy Frame"), - _INTL("Paste Frame"), - _INTL("Clear Frame"), - _INTL("Insert Frame"), - _INTL("Delete Frame") - ] - hit=pbTrackPopupMenu(commands) - case hit - when 0 # Copy - if canvas.currentframe>=0 - Clipboard.setData(canvas.animation[canvas.currentframe],"PBAnimFrame") - end - when 1 # Paste - if canvas.currentframe>=0 - canvas.pasteFrame(canvas.currentframe) - end - when 2 # Clear Frame - canvas.clearFrame(canvas.currentframe) - when 3 # Insert Frame - canvas.insertFrame(canvas.currentframe) - sliderwin.invalidate - when 4 # Delete Frame - canvas.deleteFrame(canvas.currentframe) - sliderwin.controls[0].curvalue=canvas.currentframe+1 - sliderwin.invalidate - end - next - elsif Input.triggerex?(0x51) # Q - if canvas.currentCel - pbDefinePath(canvas) - sliderwin.invalidate - end - next - elsif Input.triggerex?(Input::RightMouseKey) # Right mouse button - mousepos=Mouse::getMousePos - mousepos=[0,0] if !mousepos - commands=[ - _INTL("Properties..."), - _INTL("Cut"), - _INTL("Copy"), - _INTL("Paste"), - _INTL("Delete"), - _INTL("Renumber..."), - _INTL("Extrapolate Path...") - ] - hit=pbTrackPopupMenu(commands) - case hit - when 0 # Properties - if canvas.currentCel - pbCellProperties(canvas) - canvas.invalidateCel(canvas.currentcel) - end - when 1 # Cut - if canvas.currentCel - Clipboard.setData(canvas.currentCel,"PBAnimCel") - canvas.deleteCel(canvas.currentcel) - end - when 2 # Copy - if canvas.currentCel - Clipboard.setData(canvas.currentCel,"PBAnimCel") - end - when 3 # Paste - canvas.pasteCel(mousepos[0],mousepos[1]) - when 4 # Delete - canvas.deleteCel(canvas.currentcel) - when 5 # Renumber - if canvas.currentcel && canvas.currentcel>=2 - cel1=canvas.currentcel - cel2=pbChooseNum(cel1) - if cel2>=2 && cel1!=cel2 - canvas.swapCels(cel1,cel2) - end - end - when 6 # Extrapolate Path - if canvas.currentCel - pbDefinePath(canvas) - sliderwin.invalidate - end - end - next - end - if sliderwin.changed?(0) # Current frame changed - canvas.currentframe=sliderwin.value(0)-1 - end - if sliderwin.changed?(1) # Change frame count - pbChangeMaximum(canvas) - sliderwin.refresh - end - if sliderwin.changed?(2) # Set Animation Sheet - pbSelectAnim(canvas,animwin) - animwin.refresh - sliderwin.refresh - end - if sliderwin.changed?(3) # List of Animations - pbAnimList(animation,canvas,animwin) - sliderwin.controls[0].curvalue=canvas.currentframe+1 - bottomwindow.refresh - animwin.refresh - sliderwin.refresh - end - if sidewin.changed?(0) - pbTimingList(canvas) - end - if sidewin.changed?(1) - positions=[_INTL("User"),_INTL("Target"),_INTL("User and target"),_INTL("Screen")] - indexes=[2,1,3,4] # Keeping backwards compatibility - for i in 0...positions.length - selected="[ ]" - if animation[animation.selected].position==indexes[i] - selected="[x]" - end - positions[i]=sprintf("%s %s",selected,positions[i]) - end - pos=pbShowCommands(nil,positions,-1) - if pos>=0 - animation[animation.selected].position=indexes[pos] - canvas.update - end - end - if sidewin.changed?(3) - canvas.pasteLast - end - if sidewin.changed?(4) - pbCopyFrames(canvas) - end - if sidewin.changed?(5) - pbClearFrames(canvas) - end - if sidewin.changed?(6) - pbTweening(canvas) - end - if sidewin.changed?(7) - pbCellBatch(canvas) - end - if sidewin.changed?(8) - pbEntireSlide(canvas) - end - if sidewin.changed?(10) - canvas.play - end - if sidewin.changed?(11) - canvas.play(true) - end - if sidewin.changed?(12) - pbImportAnim(animation,canvas,animwin) - sliderwin.controls[0].curvalue=canvas.currentframe+1 - bottomwindow.refresh - animwin.refresh - sliderwin.refresh - end - if sidewin.changed?(13) - pbExportAnim(animation) - bottomwindow.refresh - animwin.refresh - sliderwin.refresh - end - if sidewin.changed?(14) - pbHelpWindow - end - end - canvas.dispose - animwin.dispose - sliderwin.dispose - sidewin.dispose - bottomwindow.dispose - viewport.dispose - GC.start -end - -def pbAnimationEditor - pbBGMStop() - animation=pbLoadBattleAnimations - if !animation || !animation[0] - animation=PBAnimations.new - animation[0].graphic="" - end - Graphics.resize_screen(SCREEN_WIDTH + 288, SCREEN_HEIGHT + 288) - pbSetResizeFactor(1) - animationEditorMain(animation) - Graphics.resize_screen(SCREEN_WIDTH, SCREEN_HEIGHT) - pbSetResizeFactor($PokemonSystem.screensize) - $game_map.autoplay if $game_map -end - -def pbConvertAnimToNewFormat(textdata) - needconverting=false - for i in 0...textdata.length - next if !textdata[i] - for j in 0...PBAnimation::MAX_SPRITES - next if !textdata[i][j] - needconverting=true if textdata[i][j][AnimFrame::FOCUS]==nil - break if needconverting - end - break if needconverting - end - if needconverting - for i in 0...textdata.length - next if !textdata[i] - for j in 0...PBAnimation::MAX_SPRITES - next if !textdata[i][j] - textdata[i][j][AnimFrame::PRIORITY]=1 if textdata[i][j][AnimFrame::PRIORITY]==nil - if j==0 # User battler - textdata[i][j][AnimFrame::FOCUS]=2 - textdata[i][j][AnimFrame::X]=PokeBattle_SceneConstants::FOCUSUSER_X - textdata[i][j][AnimFrame::Y]=PokeBattle_SceneConstants::FOCUSUSER_Y - elsif j==1 # Target battler - textdata[i][j][AnimFrame::FOCUS]=1 - textdata[i][j][AnimFrame::X]=PokeBattle_SceneConstants::FOCUSTARGET_X - textdata[i][j][AnimFrame::Y]=PokeBattle_SceneConstants::FOCUSTARGET_Y - else - textdata[i][j][AnimFrame::FOCUS]=(textdata.position || 4) - if textdata.position==1 - textdata[i][j][AnimFrame::X]+=PokeBattle_SceneConstants::FOCUSTARGET_X - textdata[i][j][AnimFrame::Y]+=PokeBattle_SceneConstants::FOCUSTARGET_Y-2 - end - end - end - end - end - return needconverting -end - -def pbConvertAnimsToNewFormat - pbMessage(_INTL("Will convert animations now.")) - count=0 - animations=pbLoadBattleAnimations - if !animations || !animations[0] - pbMessage(_INTL("No animations exist.")) - return - end - for k in 0...animations.length - next if !animations[k] - ret=pbConvertAnimToNewFormat(animations[k]) - count+=1 if ret - end - if count>0 - save_data(animations,"Data/PkmnAnimations.rxdata") - $PokemonTemp.battleAnims = nil - end - pbMessage(_INTL("{1} animations converted to new format.",count)) -end diff --git a/Data/Scripts/022_Compiler/002_Compiler.rb b/Data/Scripts/022_Compiler/001_Compiler.rb similarity index 90% rename from Data/Scripts/022_Compiler/002_Compiler.rb rename to Data/Scripts/022_Compiler/001_Compiler.rb index 0570d682f..ededc8951 100644 --- a/Data/Scripts/022_Compiler/002_Compiler.rb +++ b/Data/Scripts/022_Compiler/001_Compiler.rb @@ -76,6 +76,19 @@ module Compiler return line end + def csvQuote(str,always=false) + return "" if !str || str=="" + if always || str[/[,\"]/] # || str[/^\s/] || str[/\s$/] || str[/^#/] + str = str.gsub(/[\"]/,"\\\"") + str = "\"#{str}\"" + end + return str + end + + def csvQuoteAlways(str) + return csvQuote(str,true) + end + #============================================================================= # PBS file readers #============================================================================= @@ -115,7 +128,7 @@ module Compiler yield lastsection,sectionname if havesection end - # Used for pokemon.txt + # Used for types.txt, pokemon.txt, metadata.txt def pbEachFileSection(f) pbEachFileSectionEx(f) { |section,name| yield section,name.to_i if block_given? && name[/^\d+$/] @@ -201,7 +214,7 @@ module Compiler } end - # Used for connections.txt, abilities.txt, moves.txt, trainertypes.txt + # Used for connections.txt, abilities.txt, moves.txt, regionaldexes.txt def pbCompilerEachPreppedLine(filename) File.open(filename,"rb") { |f| FileLineData.file = filename @@ -514,34 +527,73 @@ module Compiler end #============================================================================= - # Check whether a number fits in a given numerical range (all unused) + # Write values to a file using a schema #============================================================================= - def pbCheckByte(x,valuename) - if x<0 || x>255 - raise _INTL("The value \"{1}\" must be from 0 through 255 (00-FF in hex), got a value of {2}\r\n{3}", - valuename,x,FileLineData.linereport) - end - end - - def pbCheckSignedByte(x,valuename) - if x<-128 || x>127 - raise _INTL("The value \"{1}\" must be from -128 through 127, got a value of {2}\r\n{3}", - valuename,x,FileLineData.linereport) - end - end - - def pbCheckWord(x,valuename) - if x<0 || x>65535 - raise _INTL("The value \"{1}\" must be from 0 through 65535 (0000-FFFF in hex), got a value of {2}\r\n{3}", - valuename,x,FileLineData.linereport) - end - end - - def pbCheckSignedWord(x,valuename) - if x<-32768 || x>32767 - raise _INTL("The value \"{1}\" must be from -32768 through 32767, got a value of {2}\r\n{3}", - valuename,x,FileLineData.linereport) + def pbWriteCsvRecord(record,file,schema) + rec = (record.is_a?(Array)) ? record.clone : [record] + for i in 0...schema[1].length + chr = schema[1][i,1] + file.write(",") if i>0 + if rec[i].nil? + # do nothing + elsif rec[i].is_a?(String) + file.write(csvQuote(rec[i])) + elsif rec[i].is_a?(Symbol) + file.write(csvQuote(rec[i].to_s)) + elsif rec[i]==true + file.write("true") + elsif rec[i]==false + file.write("false") + elsif rec[i].is_a?(Numeric) + case chr + when "e", "E" # Enumerable + enumer = schema[2+i] + if enumer.is_a?(Array) + file.write(enumer[rec[i]]) + elsif enumer.is_a?(Symbol) || enumer.is_a?(String) + mod = Object.const_get(enumer.to_sym) + file.write(getConstantName(mod,rec[i])) + elsif enumer.is_a?(Module) + file.write(getConstantName(enumer,rec[i])) + elsif enumer.is_a?(Hash) + for key in enumer.keys + if enumer[key]==rec[i] + file.write(key) + break + end + end + end + when "y", "Y" # Enumerable or integer + enumer = schema[2+i] + if enumer.is_a?(Array) + if enumer[rec[i]]!=nil + file.write(enumer[rec[i]]) + else + file.write(rec[i]) + end + elsif enumer.is_a?(Symbol) || enumer.is_a?(String) + mod = Object.const_get(enumer.to_sym) + file.write(getConstantNameOrValue(mod,rec[i])) + elsif enumer.is_a?(Module) + file.write(getConstantNameOrValue(enumer,rec[i])) + elsif enumer.is_a?(Hash) + hasenum = false + for key in enumer.keys + if enumer[key]==rec[i] + file.write(key) + hasenum = true; break + end + end + file.write(rec[i]) unless hasenum + end + else # Any other record type + file.write(rec[i].inspect) + end + else + file.write(rec[i].inspect) + end end + return record end #============================================================================= @@ -625,12 +677,14 @@ module Compiler MessageTypes.loadMessageFile("Data/messages.dat") end if mustCompile - yield(_INTL("Compiling type data")) - compile_types # No dependencies yield(_INTL("Compiling town map data")) compile_town_map # No dependencies yield(_INTL("Compiling map connection data")) compile_connections # No dependencies + yield(_INTL("Compiling phone data")) + compile_phone + yield(_INTL("Compiling type data")) + compile_types # No dependencies yield(_INTL("Compiling ability data")) compile_abilities # No dependencies yield(_INTL("Compiling move data")) @@ -645,22 +699,20 @@ module Compiler compile_pokemon_forms # Depends on Species, Move, Item, Type, Ability yield(_INTL("Compiling machine data")) compile_move_compatibilities # Depends on Species, Move - yield(_INTL("Compiling Trainer type data")) - compile_trainer_types # No dependencies - yield(_INTL("Compiling Trainer data")) - compile_trainers # Depends on Species, Item, Move - yield(_INTL("Compiling phone data")) - compile_phone - yield(_INTL("Compiling metadata")) - compile_metadata # Depends on TrainerType - yield(_INTL("Compiling battle Trainer data")) - compile_trainer_lists # Depends on TrainerType - yield(_INTL("Compiling encounter data")) - compile_encounters # Depends on Species yield(_INTL("Compiling shadow moveset data")) compile_shadow_movesets # Depends on Species, Move yield(_INTL("Compiling Regional Dexes")) compile_regional_dexes # Depends on Species + yield(_INTL("Compiling encounter data")) + compile_encounters # Depends on Species + yield(_INTL("Compiling Trainer type data")) + compile_trainer_types # No dependencies + yield(_INTL("Compiling Trainer data")) + compile_trainers # Depends on Species, Item, Move + yield(_INTL("Compiling battle Trainer data")) + compile_trainer_lists # Depends on TrainerType + yield(_INTL("Compiling metadata")) + compile_metadata # Depends on TrainerType yield(_INTL("Compiling animations")) compile_animations yield(_INTL("Converting events")) @@ -698,8 +750,7 @@ module Compiler "trainer_lists.dat", "trainer_types.dat", "trainers.dat", - "types.dat", - "Constants.rxdata" + "types.dat" ] textFiles = [ "abilities.txt", @@ -728,7 +779,7 @@ module Compiler # If no PBS file, create one and fill it, then recompile if !safeIsDirectory?("PBS") Dir.mkdir("PBS") rescue nil - pbSaveAllData + write_all mustCompile = true end # Should recompile if holding Ctrl diff --git a/Data/Scripts/022_Compiler/001_Data_storage.rb b/Data/Scripts/022_Compiler/001_Data_storage.rb deleted file mode 100644 index 8dc5de3cf..000000000 --- a/Data/Scripts/022_Compiler/001_Data_storage.rb +++ /dev/null @@ -1,305 +0,0 @@ -# NOTE: Everything in here is unused. -#=============================================================================== -# Serial record -#=============================================================================== -# Unused -module SerialRecords - class SerialRecord < Array - def bytesize - return SerialRecord.bytesize(self) - end - - def encode(strm) - return SerialRecord.encode(self,strm) - end - - def self.bytesize(arr) - ret = 0 - return 0 if !arr - for field in arr - if field==nil || field==true || field==false - ret += 1 - elsif field.is_a?(String) - ret += strSize(field)+1 - elsif field.is_a?(Numeric) - ret += intSize(field)+1 - end - end - return ret - end - - def self.encode(arr,strm) - return if !arr - for field in arr - if field==nil - strm.write("0") - elsif field==true - strm.write("T") - elsif field==false - strm.write("F") - elsif field.is_a?(String) - strm.write("\"") - encodeString(strm,field) - elsif field.is_a?(Numeric) - strm.write("i") - encodeInt(strm,field) - end - end - end - - def self.decode(strm,offset,length) - ret = SerialRecord.new - strm.pos = offset - while strm.pos>3 - curpos = 0 - numrec.times do - file.pos = curpos - offset = file.fgetdw - length = file.fgetdw - record = SerialRecord.decode(file,offset,length) - ret.push(record) - curpos += 8 - end - } - return ret - end - - def self.writeSerialRecords(filename,records) - File.open(filename,"wb") { |file| - totalsize = records.length*8 - for record in records - file.fputdw(totalsize) - bytesize = record.bytesize - file.fputdw(bytesize) - totalsize += bytesize - end - for record in records - record.encode(file) - end - } - end -end - -#=============================================================================== -# Data structures -#=============================================================================== -# Unused -class ByteArray - include Enumerable - - def initialize(data=nil) - @a = (data) ? data.unpack("C*") : [] - end - - def [](i); return @a[i]; end - def []=(i,value); @a[i] = value; end - - def length; @a.length; end - def size; @a.size; end - - def fillNils(length,value) - for i in 0...length - @a[i] = value if !@a[i] - end - end - - def each - @a.each { |i| yield i} - end - - def self._load(str) - return self.new(str) - end - - def _dump(_depth=100) - return @a.pack("C*") - end -end - -# Unused -class WordArray - include Enumerable - - def initialize(data=nil) - @a = (data) ? data.unpack("v*") : [] - end - - def [](i); return @a[i]; end - def []=(i,value); @a[i] = value; end - - def length; @a.length; end - def size; @a.size; end - - def fillNils(length,value) - for i in 0...length - @a[i] = value if !@a[i] - end - end - - def each - @a.each { |i| yield i} - end - - def self._load(str) - return self.new(str) - end - - def _dump(_depth=100) - return @a.pack("v*") - end -end - -# Unused -class SignedWordArray - include Enumerable - - def initialize(data=nil) - @a = (data) ? data.unpack("v*") : [] - end - - def []=(i,value) - @a[i] = value - end - - def [](i) - v = @a[i] - return 0 if !v - return (v<0x8000) ? v : -((~v)&0xFFFF)-1 - end - - def length; @a.length; end - def size; @a.size; end - - def fillNils(length,value) - for i in 0...length - @a[i] = value if !@a[i] - end - end - - def each - @a.each { |i| yield i} - end - - def self._load(str) - return self.new(str) - end - - def _dump(_depth=100) - return @a.pack("v*") - end -end - -#=============================================================================== -# Encoding and decoding -#=============================================================================== -# Unused -def intSize(value) - return 1 if value<0x80 - return 2 if value<0x4000 - return 3 if value<0x200000 - return 4 if value<0x10000000 - return 5 -end - -# Unused -def encodeInt(strm,value) - num = 0 - loop do - if value<0x80 - strm.fputb(value) - return num+1 - end - strm.fputb(0x80|(value&0x7F)) - value >>= 7 - num += 1 - end -end - -# Unused -def decodeInt(strm) - bits = 0 - curbyte = 0 - ret = 0 - begin - curbyte = strm.fgetb - ret += (curbyte&0x7F)<0)&&bits<0x1d - return ret -end - -# Unused -def strSize(str) - return str.length+intSize(str.length) -end - -# Unused -def encodeString(strm,str) - encodeInt(strm,str.length) - strm.write(str) -end - -# Unused -def decodeString(strm) - len = decodeInt(strm) - return strm.read(len) -end - -# Unused -def frozenArrayValue(arr) - typestring = "" - for i in 0...arr.length - if i>0 - typestring += ((i%20)==0) ? ",\r\n" : "," - end - typestring += arr[i].to_s - end - return "["+typestring+"].freeze" -end - -#=============================================================================== -# Scripted constants -#=============================================================================== -# Unused -def pbFindScript(a,name) - a.each { |i| - next if !i - return i if i[1]==name - } - return nil -end - -# Unused -def pbAddScript(script,sectionname) - begin - scripts = load_data("Data/Constants.rxdata") - scripts = [] if !scripts - rescue - scripts = [] - end - if false # s - s = pbFindScript(scripts,sectionname) - s[2]+=Zlib::Deflate.deflate("#{script}\r\n") - else - scripts.push([rand(100000000),sectionname,Zlib::Deflate.deflate("#{script}\r\n")]) - end - save_data(scripts,"Data/Constants.rxdata") -end diff --git a/Data/Scripts/022_Compiler/003_Compiler_PBS.rb b/Data/Scripts/022_Compiler/002_Compiler_CompilePBS.rb similarity index 97% rename from Data/Scripts/022_Compiler/003_Compiler_PBS.rb rename to Data/Scripts/022_Compiler/002_Compiler_CompilePBS.rb index 4d01e1fec..7975a0e13 100644 --- a/Data/Scripts/022_Compiler/003_Compiler_PBS.rb +++ b/Data/Scripts/022_Compiler/002_Compiler_CompilePBS.rb @@ -2,96 +2,7 @@ module Compiler module_function #============================================================================= - # Compile metadata - #============================================================================= - def compile_metadata - GameData::Metadata::DATA.clear - GameData::MapMetadata::DATA.clear - # Read from PBS file - File.open("PBS/metadata.txt", "rb") { |f| - FileLineData.file = "PBS/metadata.txt" # For error reporting - # Read a whole section's lines at once, then run through this code. - # contents is a hash containing all the XXX=YYY lines in that section, where - # the keys are the XXX and the values are the YYY (as unprocessed strings). - pbEachFileSection(f) { |contents, map_id| - schema = (map_id == 0) ? GameData::Metadata::SCHEMA : GameData::MapMetadata::SCHEMA - # Go through schema hash of compilable data and compile this section - for key in schema.keys - FileLineData.setSection(map_id, key, contents[key]) # For error reporting - # Skip empty properties, or raise an error if a required property is - # empty - if contents[key].nil? - if map_id == 0 && ["Home", "PlayerA"].include?(key) - raise _INTL("The entry {1} is required in PBS/metadata.txt section 0.", key) - end - next - end - # Compile value for key - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.length == 0 - contents[key] = value - end - if map_id == 0 # Global metadata - # Construct metadata hash - metadata_hash = { - :id => map_id, - :home => contents["Home"], - :wild_battle_BGM => contents["WildBattleBGM"], - :trainer_battle_BGM => contents["TrainerBattleBGM"], - :wild_victory_ME => contents["WildVictoryME"], - :trainer_victory_ME => contents["TrainerVictoryME"], - :wild_capture_ME => contents["WildCaptureME"], - :surf_BGM => contents["SurfBGM"], - :bicycle_BGM => contents["BicycleBGM"], - :player_A => contents["PlayerA"], - :player_B => contents["PlayerB"], - :player_C => contents["PlayerC"], - :player_D => contents["PlayerD"], - :player_E => contents["PlayerE"], - :player_F => contents["PlayerF"], - :player_G => contents["PlayerG"], - :player_H => contents["PlayerH"] - } - # Add metadata's data to records - GameData::Metadata::DATA[map_id] = GameData::Metadata.new(metadata_hash) - else # Map metadata - # Construct metadata hash - metadata_hash = { - :id => map_id, - :outdoor_map => contents["Outdoor"], - :announce_location => contents["ShowArea"], - :can_bicycle => contents["Bicycle"], - :always_bicycle => contents["BicycleAlways"], - :teleport_destination => contents["HealingSpot"], - :weather => contents["Weather"], - :town_map_position => contents["MapPosition"], - :dive_map_id => contents["DiveMap"], - :dark_map => contents["DarkMap"], - :safari_map => contents["SafariMap"], - :snap_edges => contents["SnapEdges"], - :random_dungeon => contents["Dungeon"], - :battle_background => contents["BattleBack"], - :wild_battle_BGM => contents["WildBattleBGM"], - :trainer_battle_BGM => contents["TrainerBattleBGM"], - :wild_victory_ME => contents["WildVictoryME"], - :trainer_victory_ME => contents["TrainerVictoryME"], - :wild_capture_ME => contents["WildCaptureME"], - :town_map_size => contents["MapSize"], - :battle_environment => contents["Environment"] - } - # Add metadata's data to records - GameData::MapMetadata::DATA[map_id] = GameData::MapMetadata.new(metadata_hash) - end - } - } - # Save all data - GameData::Metadata.save - GameData::MapMetadata.save - Graphics.update - end - - #============================================================================= - # Compile town map points + # Compile Town Map data #============================================================================= def compile_town_map nonglobaltypes = { @@ -182,36 +93,6 @@ module Compiler Graphics.update end - #============================================================================= - # Compile berry plants - #============================================================================= - def compile_berry_plants - GameData::BerryPlant::DATA.clear - pbCompilerEachCommentedLine("PBS/berryplants.txt") { |line, line_no| - if line[/^\s*(\w+)\s*=\s*(.*)$/] # Of the format XXX = YYY - key = $1 - value = $2 - item_symbol = parseItem(key) - item_number = GameData::Item.get(item_symbol).id_number - line = pbGetCsvRecord(value, line_no, [0, "vuuv"]) - # Construct berry plant hash - berry_plant_hash = { - :id => item_symbol, - :id_number => item_number, - :hours_per_stage => line[0], - :drying_per_hour => line[1], - :minimum_yield => line[2], - :maximum_yield => line[3] - } - # Add berry plant's data to records - GameData::BerryPlant::DATA[item_number] = GameData::BerryPlant::DATA[item_symbol] = GameData::BerryPlant.new(berry_plant_hash) - end - } - # Save all data - GameData::BerryPlant.save - Graphics.update - end - #============================================================================= # Compile phone messages #============================================================================= @@ -251,7 +132,7 @@ module Compiler end #============================================================================= - # Compile types + # Compile type data #============================================================================= def compile_types GameData::Type::DATA.clear @@ -325,7 +206,7 @@ module Compiler end #============================================================================= - # Compile abilities + # Compile ability data #============================================================================= def compile_abilities GameData::Ability::DATA.clear @@ -359,100 +240,6 @@ module Compiler Graphics.update end - #============================================================================= - # Compile items - #============================================================================= -=begin - class ItemList - include Enumerable - - def initialize; @list = []; end - def length; @list.length; end - def []=(x,v); @list[x] = v; end - - def [](x) - if !@list[x] - defrecord = SerialRecords::SerialRecord.new - defrecord.push(0) - defrecord.push("????????") - defrecord.push(0) - defrecord.push(0) - defrecord.push("????????") - @list[x] = defrecord - return defrecord - end - return @list[x] - end - - def each - for i in 0...self.length - yield self[i] - end - end - end - - def readItemList(filename) - ret = ItemList.new - return ret if !pbRgssExists?(filename) - pbRgssOpen(filename,"rb") { |file| - numrec = file.fgetdw>>3 - curpos = 0 - numrec.times do - file.pos = curpos - offset = file.fgetdw - length = file.fgetdw - record = SerialRecords::SerialRecord.decode(file,offset,length) - ret[record[0]] = record - curpos += 8 - end - } - return ret - end -=end - - def compile_items - GameData::Item::DATA.clear - item_names = [] - item_names_plural = [] - item_descriptions = [] - # Read each line of items.txt at a time and compile it into an item - pbCompilerEachCommentedLine("PBS/items.txt") { |line, line_no| - line = pbGetCsvRecord(line, line_no, [0, "vnssuusuuUN"]) - item_number = line[0] - item_symbol = line[1].to_sym - if GameData::Item::DATA[item_number] - raise _INTL("Item ID number '{1}' is used twice.\r\n{2}", item_number, FileLineData.linereport) - elsif GameData::Item::DATA[item_symbol] - raise _INTL("Item ID '{1}' is used twice.\r\n{2}", item_symbol, FileLineData.linereport) - end - # Construct item hash - item_hash = { - :id_number => item_number, - :id => item_symbol, - :name => line[2], - :name_plural => line[3], - :pocket => line[4], - :price => line[5], - :description => line[6], - :field_use => line[7], - :battle_use => line[8], - :type => line[9] - } - item_hash[:move] = parseMove(line[10]) if !nil_or_empty?(line[10]) - # Add item's data to records - GameData::Item::DATA[item_number] = GameData::Item::DATA[item_symbol] = GameData::Item.new(item_hash) - item_names[item_number] = item_hash[:name] - item_names_plural[item_number] = item_hash[:name_plural] - item_descriptions[item_number] = item_hash[:description] - } - # Save all data - GameData::Item.save - MessageTypes.setMessages(MessageTypes::Items, item_names) - MessageTypes.setMessages(MessageTypes::ItemPlurals, item_names_plural) - MessageTypes.setMessages(MessageTypes::ItemDescriptions, item_descriptions) - Graphics.update - end - #============================================================================= # Compile move data #============================================================================= @@ -510,49 +297,83 @@ module Compiler end #============================================================================= - # Compile battle animations + # Compile item data #============================================================================= - def compile_animations - begin - pbanims = load_data("Data/PkmnAnimations.rxdata") - rescue - pbanims = PBAnimations.new - end - move2anim = [[],[]] -=begin - anims = load_data("Data/Animations.rxdata") - for anim in anims - next if !anim || anim.frames.length==1 - found = false - for i in 0...pbanims.length - if pbanims[i] && pbanims[i].id==anim.id - found = true if pbanims[i].array.length>1 - break - end + def compile_items + GameData::Item::DATA.clear + item_names = [] + item_names_plural = [] + item_descriptions = [] + # Read each line of items.txt at a time and compile it into an item + pbCompilerEachCommentedLine("PBS/items.txt") { |line, line_no| + line = pbGetCsvRecord(line, line_no, [0, "vnssuusuuUN"]) + item_number = line[0] + item_symbol = line[1].to_sym + if GameData::Item::DATA[item_number] + raise _INTL("Item ID number '{1}' is used twice.\r\n{2}", item_number, FileLineData.linereport) + elsif GameData::Item::DATA[item_symbol] + raise _INTL("Item ID '{1}' is used twice.\r\n{2}", item_symbol, FileLineData.linereport) end - pbanims[anim.id] = pbConvertRPGAnimation(anim) if !found - end -=end - for i in 0...pbanims.length - next if !pbanims[i] - if pbanims[i].name[/^OppMove\:\s*(.*)$/] - if GameData::Move.exists?($~[1]) - moveid = GameData::Move.get($~[1]).id_number - move2anim[1][moveid] = i - end - elsif pbanims[i].name[/^Move\:\s*(.*)$/] - if GameData::Move.exists?($~[1]) - moveid = GameData::Move.get($~[1]).id_number - move2anim[0][moveid] = i - end - end - end - save_data(move2anim,"Data/move2anim.dat") - save_data(pbanims,"Data/PkmnAnimations.rxdata") + # Construct item hash + item_hash = { + :id_number => item_number, + :id => item_symbol, + :name => line[2], + :name_plural => line[3], + :pocket => line[4], + :price => line[5], + :description => line[6], + :field_use => line[7], + :battle_use => line[8], + :type => line[9] + } + item_hash[:move] = parseMove(line[10]) if !nil_or_empty?(line[10]) + # Add item's data to records + GameData::Item::DATA[item_number] = GameData::Item::DATA[item_symbol] = GameData::Item.new(item_hash) + item_names[item_number] = item_hash[:name] + item_names_plural[item_number] = item_hash[:name_plural] + item_descriptions[item_number] = item_hash[:description] + } + # Save all data + GameData::Item.save + MessageTypes.setMessages(MessageTypes::Items, item_names) + MessageTypes.setMessages(MessageTypes::ItemPlurals, item_names_plural) + MessageTypes.setMessages(MessageTypes::ItemDescriptions, item_descriptions) + Graphics.update end #============================================================================= - # Compile Pokémon + # Compile berry plant data + #============================================================================= + def compile_berry_plants + GameData::BerryPlant::DATA.clear + pbCompilerEachCommentedLine("PBS/berryplants.txt") { |line, line_no| + if line[/^\s*(\w+)\s*=\s*(.*)$/] # Of the format XXX = YYY + key = $1 + value = $2 + item_symbol = parseItem(key) + item_number = GameData::Item.get(item_symbol).id_number + line = pbGetCsvRecord(value, line_no, [0, "vuuv"]) + # Construct berry plant hash + berry_plant_hash = { + :id => item_symbol, + :id_number => item_number, + :hours_per_stage => line[0], + :drying_per_hour => line[1], + :minimum_yield => line[2], + :maximum_yield => line[3] + } + # Add berry plant's data to records + GameData::BerryPlant::DATA[item_number] = GameData::BerryPlant::DATA[item_symbol] = GameData::BerryPlant.new(berry_plant_hash) + end + } + # Save all data + GameData::BerryPlant.save + Graphics.update + end + + #============================================================================= + # Compile Pokémon data #============================================================================= def compile_pokemon GameData::Species::DATA.clear @@ -713,7 +534,7 @@ module Compiler end #============================================================================= - # Compile Pokémon forms + # Compile Pokémon forms data #============================================================================= def compile_pokemon_forms species_names = [] @@ -930,8 +751,8 @@ module Compiler species_hash[species_data.id].each { |move| species_data.tutor_moves.push(move) } end GameData::Species.save - pbSavePokemonData - pbSavePokemonFormsData + Compiler.write_pokemon + Compiler.write_pokemon_forms begin File.delete("PBS/tm.txt") rescue SystemCallError @@ -1003,7 +824,7 @@ module Compiler end #============================================================================= - # Compile wild encounters + # Compile wild encounter data #============================================================================= def compile_encounters lines = [] @@ -1110,7 +931,7 @@ module Compiler end #============================================================================= - # Compile trainer types + # Compile trainer type data #============================================================================= def compile_trainer_types GameData::TrainerType::DATA.clear @@ -1155,7 +976,7 @@ module Compiler end #============================================================================= - # Compile individual trainers + # Compile individual trainer data #============================================================================= def compile_trainers trainer_info_types = TrainerData::SCHEMA @@ -1355,52 +1176,11 @@ module Compiler #============================================================================= # Compile Battle Tower and other Cups trainers/Pokémon #============================================================================= - def compile_battle_tower_trainers(filename) - sections = [] - requiredtypes = { - "Type" => [0, "e", :TrainerType], - "Name" => [1, "s"], - "BeginSpeech" => [2, "s"], - "EndSpeechWin" => [3, "s"], - "EndSpeechLose" => [4, "s"], - "PokemonNos" => [5, "*u"] - } - trainernames = [] - beginspeech = [] - endspeechwin = [] - endspeechlose = [] - if safeExists?(filename) - File.open(filename,"rb") { |f| - FileLineData.file = filename - pbEachFileSectionEx(f) { |section,name| - rsection = [] - for key in section.keys - FileLineData.setSection(name,key,section[key]) - schema = requiredtypes[key] - next if !schema - record = pbGetCsvRecord(section[key],0,schema) - rsection[schema[0]] = record - end - trainernames.push(rsection[1]) - beginspeech.push(rsection[2]) - endspeechwin.push(rsection[3]) - endspeechlose.push(rsection[4]) - sections.push(rsection) - } - } - end - MessageTypes.addMessagesAsHash(MessageTypes::TrainerNames,trainernames) - MessageTypes.addMessagesAsHash(MessageTypes::BeginSpeech,beginspeech) - MessageTypes.addMessagesAsHash(MessageTypes::EndSpeechWin,endspeechwin) - MessageTypes.addMessagesAsHash(MessageTypes::EndSpeechLose,endspeechlose) - return sections - end - def compile_trainer_lists btTrainersRequiredTypes = { - "Trainers" => [0, "s"], - "Pokemon" => [1, "s"], - "Challenges" => [2, "*s"] + "Trainers" => [0, "s"], + "Pokemon" => [1, "s"], + "Challenges" => [2, "*s"] } if !safeExists?("PBS/trainerlists.txt") File.open("PBS/trainerlists.txt","wb") { |f| @@ -1462,4 +1242,176 @@ module Compiler } save_data(sections,"Data/trainer_lists.dat") end + + def compile_battle_tower_trainers(filename) + sections = [] + requiredtypes = { + "Type" => [0, "e", :TrainerType], + "Name" => [1, "s"], + "BeginSpeech" => [2, "s"], + "EndSpeechWin" => [3, "s"], + "EndSpeechLose" => [4, "s"], + "PokemonNos" => [5, "*u"] + } + trainernames = [] + beginspeech = [] + endspeechwin = [] + endspeechlose = [] + if safeExists?(filename) + File.open(filename,"rb") { |f| + FileLineData.file = filename + pbEachFileSectionEx(f) { |section,name| + rsection = [] + for key in section.keys + FileLineData.setSection(name,key,section[key]) + schema = requiredtypes[key] + next if !schema + record = pbGetCsvRecord(section[key],0,schema) + rsection[schema[0]] = record + end + trainernames.push(rsection[1]) + beginspeech.push(rsection[2]) + endspeechwin.push(rsection[3]) + endspeechlose.push(rsection[4]) + sections.push(rsection) + } + } + end + MessageTypes.addMessagesAsHash(MessageTypes::TrainerNames,trainernames) + MessageTypes.addMessagesAsHash(MessageTypes::BeginSpeech,beginspeech) + MessageTypes.addMessagesAsHash(MessageTypes::EndSpeechWin,endspeechwin) + MessageTypes.addMessagesAsHash(MessageTypes::EndSpeechLose,endspeechlose) + return sections + end + + #============================================================================= + # Compile metadata + #============================================================================= + def compile_metadata + GameData::Metadata::DATA.clear + GameData::MapMetadata::DATA.clear + # Read from PBS file + File.open("PBS/metadata.txt", "rb") { |f| + FileLineData.file = "PBS/metadata.txt" # For error reporting + # Read a whole section's lines at once, then run through this code. + # contents is a hash containing all the XXX=YYY lines in that section, where + # the keys are the XXX and the values are the YYY (as unprocessed strings). + pbEachFileSection(f) { |contents, map_id| + schema = (map_id == 0) ? GameData::Metadata::SCHEMA : GameData::MapMetadata::SCHEMA + # Go through schema hash of compilable data and compile this section + for key in schema.keys + FileLineData.setSection(map_id, key, contents[key]) # For error reporting + # Skip empty properties, or raise an error if a required property is + # empty + if contents[key].nil? + if map_id == 0 && ["Home", "PlayerA"].include?(key) + raise _INTL("The entry {1} is required in PBS/metadata.txt section 0.", key) + end + next + end + # Compile value for key + value = pbGetCsvRecord(contents[key], key, schema[key]) + value = nil if value.is_a?(Array) && value.length == 0 + contents[key] = value + end + if map_id == 0 # Global metadata + # Construct metadata hash + metadata_hash = { + :id => map_id, + :home => contents["Home"], + :wild_battle_BGM => contents["WildBattleBGM"], + :trainer_battle_BGM => contents["TrainerBattleBGM"], + :wild_victory_ME => contents["WildVictoryME"], + :trainer_victory_ME => contents["TrainerVictoryME"], + :wild_capture_ME => contents["WildCaptureME"], + :surf_BGM => contents["SurfBGM"], + :bicycle_BGM => contents["BicycleBGM"], + :player_A => contents["PlayerA"], + :player_B => contents["PlayerB"], + :player_C => contents["PlayerC"], + :player_D => contents["PlayerD"], + :player_E => contents["PlayerE"], + :player_F => contents["PlayerF"], + :player_G => contents["PlayerG"], + :player_H => contents["PlayerH"] + } + # Add metadata's data to records + GameData::Metadata::DATA[map_id] = GameData::Metadata.new(metadata_hash) + else # Map metadata + # Construct metadata hash + metadata_hash = { + :id => map_id, + :outdoor_map => contents["Outdoor"], + :announce_location => contents["ShowArea"], + :can_bicycle => contents["Bicycle"], + :always_bicycle => contents["BicycleAlways"], + :teleport_destination => contents["HealingSpot"], + :weather => contents["Weather"], + :town_map_position => contents["MapPosition"], + :dive_map_id => contents["DiveMap"], + :dark_map => contents["DarkMap"], + :safari_map => contents["SafariMap"], + :snap_edges => contents["SnapEdges"], + :random_dungeon => contents["Dungeon"], + :battle_background => contents["BattleBack"], + :wild_battle_BGM => contents["WildBattleBGM"], + :trainer_battle_BGM => contents["TrainerBattleBGM"], + :wild_victory_ME => contents["WildVictoryME"], + :trainer_victory_ME => contents["TrainerVictoryME"], + :wild_capture_ME => contents["WildCaptureME"], + :town_map_size => contents["MapSize"], + :battle_environment => contents["Environment"] + } + # Add metadata's data to records + GameData::MapMetadata::DATA[map_id] = GameData::MapMetadata.new(metadata_hash) + end + } + } + # Save all data + GameData::Metadata.save + GameData::MapMetadata.save + Graphics.update + end + + #============================================================================= + # Compile battle animations + #============================================================================= + def compile_animations + begin + pbanims = load_data("Data/PkmnAnimations.rxdata") + rescue + pbanims = PBAnimations.new + end + move2anim = [[],[]] +=begin + anims = load_data("Data/Animations.rxdata") + for anim in anims + next if !anim || anim.frames.length==1 + found = false + for i in 0...pbanims.length + if pbanims[i] && pbanims[i].id==anim.id + found = true if pbanims[i].array.length>1 + break + end + end + pbanims[anim.id] = pbConvertRPGAnimation(anim) if !found + end +=end + for i in 0...pbanims.length + next if !pbanims[i] + if pbanims[i].name[/^OppMove\:\s*(.*)$/] + if GameData::Move.exists?($~[1]) + moveid = GameData::Move.get($~[1]).id_number + move2anim[1][moveid] = i + end + elsif pbanims[i].name[/^Move\:\s*(.*)$/] + if GameData::Move.exists?($~[1]) + moveid = GameData::Move.get($~[1]).id_number + move2anim[0][moveid] = i + end + end + end + save_data(move2anim,"Data/move2anim.dat") + save_data(pbanims,"Data/PkmnAnimations.rxdata") + end end diff --git a/Data/Scripts/022_Compiler/003_Compiler_WritePBS.rb b/Data/Scripts/022_Compiler/003_Compiler_WritePBS.rb new file mode 100644 index 000000000..20a4021cd --- /dev/null +++ b/Data/Scripts/022_Compiler/003_Compiler_WritePBS.rb @@ -0,0 +1,837 @@ +module Compiler + module_function + + def add_PBS_header_to_file(file) + file.write(0xEF.chr) + file.write(0xBB.chr) + file.write(0xBF.chr) + file.write("\# " + _INTL("See the documentation on the wiki to learn how to edit this file.") + "\r\n") + end + + #============================================================================= + # Save Town Map data to PBS file + #============================================================================= + def write_town_map + mapdata = pbLoadTownMapData + return if !mapdata + File.open("PBS/townmap.txt","wb") { |f| + add_PBS_header_to_file(f) + for i in 0...mapdata.length + map = mapdata[i] + next if !map + f.write("\#-------------------------------\r\n") + f.write(sprintf("[%d]\r\n",i)) + rname = pbGetMessage(MessageTypes::RegionNames,i) + f.write(sprintf("Name = %s\r\nFilename = %s\r\n", + (rname && rname!="") ? rname : _INTL("Unnamed"), + csvQuote((map[1].is_a?(Array)) ? map[1][0] : map[1]))) + for loc in map[2] + f.write("Point = ") + pbWriteCsvRecord(loc,f,[nil,"uussUUUU"]) + f.write("\r\n") + end + end + } + Graphics.update + end + + #=============================================================================== + # Save map connections to PBS file + #=============================================================================== + def normalizeConnectionPoint(conn) + ret = conn.clone + if conn[1] < 0 && conn[4] < 0 + elsif conn[1] < 0 || conn[4] < 0 + ret[4] = -conn[1] + ret[1] = -conn[4] + end + if conn[2] < 0 && conn[5] < 0 + elsif conn[2] < 0 || conn[5] < 0 + ret[5] = -conn[2] + ret[2] = -conn[5] + end + return ret + end + + def writeConnectionPoint(map1, x1, y1, map2, x2, y2) + dims1 = MapFactoryHelper.getMapDims(map1) + dims2 = MapFactoryHelper.getMapDims(map2) + if x1 == 0 && x2 == dims2[0] + return sprintf("%d,West,%d,%d,East,%d", map1, y1, map2, y2) + elsif y1 == 0 && y2 == dims2[1] + return sprintf("%d,North,%d,%d,South,%d", map1, x1, map2, x2) + elsif x1 == dims1[0] && x2 == 0 + return sprintf("%d,East,%d,%d,West,%d", map1, y1, map2, y2) + elsif y1 == dims1[1] && y2 == 0 + return sprintf("%d,South,%d,%d,North,%d", map1, x1, map2, x2) + end + return sprintf("%d,%d,%d,%d,%d,%d", map1, x1, y1, map2, x2, y2) + end + + def write_connections + conndata = load_data("Data/map_connections.dat") rescue nil + return if !conndata + mapinfos = pbLoadRxData("Data/MapInfos") + File.open("PBS/connections.txt","wb") { |f| + add_PBS_header_to_file(f) + f.write("\#-------------------------------\r\n") + for conn in conndata + if mapinfos + # Skip if map no longer exists + next if !mapinfos[conn[0]] || !mapinfos[conn[3]] + f.write(sprintf("# %s (%d) - %s (%d)\r\n", + (mapinfos[conn[0]]) ? mapinfos[conn[0]].name : "???", conn[0], + (mapinfos[conn[3]]) ? mapinfos[conn[3]].name : "???", conn[3])) + end + if conn[1].is_a?(String) || conn[4].is_a?(String) + f.write(sprintf("%d,%s,%d,%d,%s,%d", conn[0], conn[1], conn[2], + conn[3], conn[4], conn[5])) + else + ret = normalizeConnectionPoint(conn) + f.write(writeConnectionPoint(ret[0], ret[1], ret[2], ret[3], ret[4], ret[5])) + end + f.write("\r\n") + end + } + Graphics.update + end + + #=============================================================================== + # Save phone messages to PBS file + #=============================================================================== + def write_phone + data = load_data("Data/phone.dat") rescue nil + return if !data + File.open("PBS/phone.txt", "wb") { |f| + add_PBS_header_to_file(f) + f.write("\#-------------------------------\r\n") + f.write("[]\r\n") + f.write(data.generics.join("\r\n") + "\r\n") + f.write("\#-------------------------------\r\n") + f.write("[]\r\n") + f.write(data.battleRequests.join("\r\n") + "\r\n") + f.write("\#-------------------------------\r\n") + f.write("[]\r\n") + f.write(data.greetingsMorning.join("\r\n") + "\r\n") + f.write("\#-------------------------------\r\n") + f.write("[]\r\n") + f.write(data.greetingsEvening.join("\r\n") + "\r\n") + f.write("\#-------------------------------\r\n") + f.write("[]\r\n") + f.write(data.greetings.join("\r\n") + "\r\n") + f.write("\#-------------------------------\r\n") + f.write("[]\r\n") + f.write(data.bodies1.join("\r\n") + "\r\n") + f.write("\#-------------------------------\r\n") + f.write("[]\r\n") + f.write(data.bodies2.join("\r\n") + "\r\n") + } + Graphics.update + end + + #=============================================================================== + # Save type data to PBS file + #=============================================================================== + def write_types + File.open("PBS/types.txt", "wb") { |f| + add_PBS_header_to_file(f) + # Write each type in turn + GameData::Type.each do |type| + f.write("\#-------------------------------\r\n") + f.write("[#{type.id_number}]\r\n") + f.write("Name = #{type.real_name}\r\n") + f.write("InternalName = #{type.id.to_s}\r\n") + f.write("IsPseudoType = true\r\n") if type.pseudo_type + f.write("IsSpecialType = true\r\n") if type.special? + f.write("Weaknesses = #{type.weaknesses.join(",")}\r\n") if type.weaknesses.length > 0 + f.write("Resistances = #{type.resistances.join(",")}\r\n") if type.resistances.length > 0 + f.write("Immunities = #{type.immunities.join(",")}\r\n") if type.immunities.length > 0 + end + } + Graphics.update + end + + #=============================================================================== + # Save ability data to PBS file + #=============================================================================== + def write_abilities + File.open("PBS/abilities.txt", "wb") { |f| + add_PBS_header_to_file(f) + f.write("\#-------------------------------\r\n") + GameData::Ability.each do |a| + f.write(sprintf("%d,%s,%s,%s\r\n", + a.id_number, + csvQuote(a.id.to_s), + csvQuote(a.real_name), + csvQuoteAlways(a.real_description) + )) + end + } + Graphics.update + end + + #=============================================================================== + # Save move data to PBS file + #=============================================================================== + def write_moves + File.open("PBS/moves.txt", "wb") { |f| + add_PBS_header_to_file(f) + current_type = -1 + GameData::Move.each do |m| + if current_type != m.type + current_type = m.type + f.write("\#-------------------------------\r\n") + end + f.write(sprintf("%d,%s,%s,%s,%d,%s,%s,%d,%d,%d,%s,%d,%s,%s\r\n", + m.id_number, + csvQuote(m.id.to_s), + csvQuote(m.real_name), + csvQuote(m.function_code), + m.base_damage, + m.type.to_s, + ["Physical", "Special", "Status"][m.category], + m.accuracy, + m.total_pp, + m.effect_chance, + (getConstantName(PBTargets, m.target) rescue sprintf("%d", m.target)), + m.priority, + csvQuote(m.flags), + csvQuoteAlways(m.real_description) + )) + end + } + Graphics.update + end + + #=============================================================================== + # Save item data to PBS file + #=============================================================================== + def write_items + File.open("PBS/items.txt", "wb") { |f| + add_PBS_header_to_file(f) + current_pocket = 0 + GameData::Item.each do |i| + if current_pocket != i.pocket + current_pocket = i.pocket + f.write("\#-------------------------------\r\n") + end + move_name = (i.move) ? GameData::Move.get(i.move).id.to_s : "" + sprintf_text = "%d,%s,%s,%s,%d,%d,%s,%d,%d,%d\r\n" + sprintf_text = "%d,%s,%s,%s,%d,%d,%s,%d,%d,%d,%s\r\n" if move_name != "" + f.write(sprintf(sprintf_text, + i.id_number, + csvQuote(i.id.to_s), + csvQuote(i.real_name), + csvQuote(i.real_name_plural), + i.pocket, + i.price, + csvQuoteAlways(i.real_description), + i.field_use, + i.battle_use, + i.type, + csvQuote(move_name) + )) + end + } + Graphics.update + end + + #=============================================================================== + # Save berry plant data to PBS file + #=============================================================================== + def write_berry_plants + File.open("PBS/berryplants.txt", "wb") { |f| + add_PBS_header_to_file(f) + f.write("\#-------------------------------\r\n") + GameData::BerryPlant.each do |bp| + f.write(sprintf("%s = %d,%d,%d,%d\r\n", + csvQuote(bp.id.to_s), + bp.hours_per_stage, + bp.drying_per_hour, + bp.minimum_yield, + bp.maximum_yield + )) + end + } + Graphics.update + end + + #=============================================================================== + # Save Pokémon data to PBS file + #=============================================================================== + def write_pokemon + File.open("PBS/pokemon.txt", "wb") { |f| + add_PBS_header_to_file(f) + GameData::Species.each do |species| + next if species.form != 0 + pbSetWindowText(_INTL("Writing species {1}...", species.id_number)) + Graphics.update if species.id_number % 50 == 0 + f.write("\#-------------------------------\r\n") + f.write(sprintf("[%d]\r\n", species.id_number)) + f.write(sprintf("Name = %s\r\n", species.real_name)) + f.write(sprintf("InternalName = %s\r\n", species.species)) + f.write(sprintf("Type1 = %s\r\n", species.type1)) + f.write(sprintf("Type2 = %s\r\n", species.type2)) if species.type2 != species.type1 + f.write(sprintf("BaseStats = %s\r\n", species.base_stats.join(","))) + f.write(sprintf("GenderRate = %s\r\n", getConstantName(PBGenderRates, species.gender_rate))) + f.write(sprintf("GrowthRate = %s\r\n", getConstantName(PBGrowthRates, species.growth_rate))) + f.write(sprintf("BaseEXP = %d\r\n", species.base_exp)) + f.write(sprintf("EffortPoints = %s\r\n", species.evs.join(","))) + f.write(sprintf("Rareness = %d\r\n", species.catch_rate)) + f.write(sprintf("Happiness = %d\r\n", species.happiness)) + if species.abilities.length > 0 + f.write(sprintf("Abilities = %s\r\n", species.abilities.join(","))) + end + if species.hidden_abilities.length > 0 + f.write(sprintf("HiddenAbility = %s\r\n", species.hidden_abilities.join(","))) + end + if species.moves.length > 0 + f.write(sprintf("Moves = %s\r\n", species.moves.join(","))) + end + if species.tutor_moves.length > 0 + f.write(sprintf("TutorMoves = %s\r\n", species.tutor_moves.join(","))) + end + if species.egg_moves.length > 0 + f.write(sprintf("EggMoves = %s\r\n", species.egg_moves.join(","))) + end + if species.egg_groups.length > 0 + f.write("Compatibility = ") + species.egg_groups.each_with_index do |group, i| + f.write(",") if i > 0 + f.write(getConstantName(PBEggGroups, group)) + end + f.write("\r\n") + end + f.write(sprintf("StepsToHatch = %d\r\n", species.hatch_steps)) + f.write(sprintf("Height = %.1f\r\n", species.height / 10.0)) + f.write(sprintf("Weight = %.1f\r\n", species.weight / 10.0)) + f.write(sprintf("Color = %s\r\n", getConstantName(PBColors, species.color))) + f.write(sprintf("Shape = %d\r\n", species.shape)) + f.write(sprintf("Habitat = %s\r\n", getConstantName(PBHabitats, species.habitat))) if species.habitat != PBHabitats::None + f.write(sprintf("Kind = %s\r\n", species.real_category)) + f.write(sprintf("Pokedex = %s\r\n", species.real_pokedex_entry)) + f.write(sprintf("FormName = %s\r\n", species.real_form_name)) if species.real_form_name && !species.real_form_name.empty? + f.write(sprintf("Generation = %d\r\n", species.generation)) if species.generation != 0 + f.write(sprintf("WildItemCommon = %s\r\n", species.wild_item_common)) if species.wild_item_common + f.write(sprintf("WildItemUncommon = %s\r\n", species.wild_item_uncommon)) if species.wild_item_uncommon + f.write(sprintf("WildItemRare = %s\r\n", species.wild_item_rare)) if species.wild_item_rare + f.write(sprintf("BattlerPlayerX = %d\r\n", species.back_sprite_x)) + f.write(sprintf("BattlerPlayerY = %d\r\n", species.back_sprite_y)) + f.write(sprintf("BattlerEnemyX = %d\r\n", species.front_sprite_x)) + f.write(sprintf("BattlerEnemyY = %d\r\n", species.front_sprite_y)) + f.write(sprintf("BattlerAltitude = %d\r\n", species.front_sprite_altitude)) if species.front_sprite_altitude != 0 + f.write(sprintf("BattlerShadowX = %d\r\n", species.shadow_x)) + f.write(sprintf("BattlerShadowSize = %d\r\n", species.shadow_size)) + if species.evolutions.any? { |evo| !evo[3] } + f.write("Evolutions = ") + need_comma = false + species.evolutions.each do |evo| + next if evo[3] # Skip prevolution entries + f.write(",") if need_comma + need_comma = true + f.write(sprintf("%s,%s,", evo[0], getConstantName(PBEvolution, evo[1]))) + param_type = PBEvolution.getFunction(evo[1], "parameterType") + has_param = !PBEvolution.hasFunction?(evo[1], "parameterType") || param_type != nil + next if !has_param + if param_type + if GameData.const_defined?(param_type.to_sym) + f.write(evo[2].to_s) + else + f.write(getConstantName(param_type, evo[2])) + end + else + f.write(evo[2].to_s) + end + end + f.write("\r\n") + end + f.write(sprintf("Incense = %s\r\n", species.incense)) if species.incense + end + } + Graphics.update + end + + #=============================================================================== + # Save Pokémon forms data to PBS file + #=============================================================================== + def write_pokemon_forms + File.open("PBS/pokemonforms.txt", "wb") { |f| + add_PBS_header_to_file(f) + GameData::Species.each do |species| + next if species.form == 0 + base_species = GameData::Species.get(species.species) + pbSetWindowText(_INTL("Writing species {1}...", species.id_number)) + Graphics.update if species.id_number % 50 == 0 + f.write("\#-------------------------------\r\n") + f.write(sprintf("[%s,%d]\r\n", species.species, species.form)) + f.write(sprintf("FormName = %s\r\n", species.real_form_name)) if species.real_form_name && !species.real_form_name.empty? + f.write(sprintf("PokedexForm = %d\r\n", species.pokedex_form)) if species.pokedex_form != species.form + f.write(sprintf("MegaStone = %s\r\n", species.mega_stone)) if species.mega_stone + f.write(sprintf("MegaMove = %s\r\n", species.mega_move)) if species.mega_move + f.write(sprintf("UnmegaForm = %d\r\n", species.unmega_form)) if species.unmega_form != 0 + f.write(sprintf("MegaMessage = %d\r\n", species.mega_message)) if species.mega_message != 0 + if species.type1 != base_species.type1 || species.type2 != base_species.type2 + f.write(sprintf("Type1 = %s\r\n", species.type1)) + f.write(sprintf("Type2 = %s\r\n", species.type2)) if species.type2 != species.type1 + end + f.write(sprintf("BaseStats = %s\r\n", species.base_stats.join(","))) if species.base_stats != base_species.base_stats + f.write(sprintf("BaseEXP = %d\r\n", species.base_exp)) if species.base_exp != base_species.base_exp + f.write(sprintf("EffortPoints = %s\r\n", species.evs.join(","))) if species.evs != base_species.evs + f.write(sprintf("Rareness = %d\r\n", species.catch_rate)) if species.catch_rate != base_species.catch_rate + f.write(sprintf("Happiness = %d\r\n", species.happiness)) if species.happiness != base_species.happiness + if species.abilities.length > 0 && species.abilities != base_species.abilities + f.write(sprintf("Abilities = %s\r\n", species.abilities.join(","))) + end + if species.hidden_abilities.length > 0 && species.hidden_abilities != base_species.hidden_abilities + f.write(sprintf("HiddenAbility = %s\r\n", species.hidden_abilities.join(","))) + end + if species.moves.length > 0 && species.moves != base_species.moves + f.write(sprintf("Moves = %s\r\n", species.moves.join(","))) + end + if species.tutor_moves.length > 0 && species.tutor_moves != base_species.tutor_moves + f.write(sprintf("TutorMoves = %s\r\n", species.tutor_moves.join(","))) + end + if species.egg_moves.length > 0 && species.egg_moves != base_species.egg_moves + f.write(sprintf("EggMoves = %s\r\n", species.egg_moves.join(","))) + end + if species.egg_groups.length > 0 && species.egg_groups != base_species.egg_groups + f.write("Compatibility = ") + species.egg_groups.each_with_index do |group, i| + f.write(",") if i > 0 + f.write(getConstantName(PBEggGroups, group)) + end + f.write("\r\n") + end + f.write(sprintf("StepsToHatch = %d\r\n", species.hatch_steps)) if species.hatch_steps != base_species.hatch_steps + f.write(sprintf("Height = %.1f\r\n", species.height / 10.0)) if species.height != base_species.height + f.write(sprintf("Weight = %.1f\r\n", species.weight / 10.0)) if species.weight != base_species.weight + f.write(sprintf("Color = %s\r\n", getConstantName(PBColors, species.color))) if species.color != base_species.color + f.write(sprintf("Shape = %d\r\n", species.shape)) if species.shape != base_species.shape + if species.habitat != PBHabitats::None && species.habitat != base_species.habitat + f.write(sprintf("Habitat = %s\r\n", getConstantName(PBHabitats, species.habitat))) + end + f.write(sprintf("Kind = %s\r\n", species.real_category)) if species.real_category != base_species.real_category + f.write(sprintf("Pokedex = %s\r\n", species.real_pokedex_entry)) if species.real_pokedex_entry != base_species.real_pokedex_entry + f.write(sprintf("Generation = %d\r\n", species.generation)) if species.generation != base_species.generation + if species.wild_item_common != base_species.wild_item_common || + species.wild_item_uncommon != base_species.wild_item_uncommon || + species.wild_item_rare != base_species.wild_item_rare + f.write(sprintf("WildItemCommon = %s\r\n", species.wild_item_common)) if species.wild_item_common + f.write(sprintf("WildItemUncommon = %s\r\n", species.wild_item_uncommon)) if species.wild_item_uncommon + f.write(sprintf("WildItemRare = %s\r\n", species.wild_item_rare)) if species.wild_item_rare + end + f.write(sprintf("BattlerPlayerX = %d\r\n", species.back_sprite_x)) if species.back_sprite_x != base_species.back_sprite_x + f.write(sprintf("BattlerPlayerY = %d\r\n", species.back_sprite_y)) if species.back_sprite_y != base_species.back_sprite_y + f.write(sprintf("BattlerEnemyX = %d\r\n", species.front_sprite_x)) if species.front_sprite_x != base_species.front_sprite_x + f.write(sprintf("BattlerEnemyY = %d\r\n", species.front_sprite_y)) if species.front_sprite_y != base_species.front_sprite_y + f.write(sprintf("BattlerAltitude = %d\r\n", species.front_sprite_altitude)) if species.front_sprite_altitude != base_species.front_sprite_altitude + f.write(sprintf("BattlerShadowX = %d\r\n", species.shadow_x)) if species.shadow_x != base_species.shadow_x + f.write(sprintf("BattlerShadowSize = %d\r\n", species.shadow_size)) if species.shadow_size != base_species.shadow_size + if species.evolutions != base_species.evolutions && species.evolutions.any? { |evo| !evo[3] } + f.write("Evolutions = ") + need_comma = false + species.evolutions.each do |evo| + next if evo[3] # Skip prevolution entries + f.write(",") if need_comma + need_comma = true + f.write(sprintf("%s,%s,", evo[0], getConstantName(PBEvolution, evo[1]))) + param_type = PBEvolution.getFunction(evo[1], "parameterType") + has_param = !PBEvolution.hasFunction?(evo[1], "parameterType") || param_type != nil + next if !has_param + if param_type + if GameData.const_defined?(param_type.to_sym) + f.write(evo[2].to_s) + else + f.write(getConstantName(param_type, evo[2])) + end + else + f.write(evo[2].to_s) + end + end + f.write("\r\n") + end + end + } + Graphics.update + end + + #=============================================================================== + # Save Shadow movesets to PBS file + #=============================================================================== + def write_shadow_movesets + shadow_movesets = pbLoadShadowMovesets + File.open("PBS/shadowmoves.txt", "wb") { |f| + add_PBS_header_to_file(f) + f.write("\#-------------------------------\r\n") + GameData::Species.each do |species_data| + moveset = shadow_movesets[species_data.id] + next if !moveset || moveset.length == 0 + f.write(sprintf("%s = %s\r\n", species_data.id, moveset.join(","))) + end + } + Graphics.update + end + + #=============================================================================== + # Save Regional Dexes to PBS file + #=============================================================================== + def write_regional_dexes + dex_lists = pbLoadRegionalDexes + File.open("PBS/regionaldexes.txt", "wb") { |f| + add_PBS_header_to_file(f) + # Write each Dex list in turn + dex_lists.each_with_index do |list, index| + f.write("\#-------------------------------\r\n") + f.write("[#{index}]") + comma = false + current_family = nil + list.each do |species| + next if !species + if current_family && current_family.include?(species) + f.write(",") if comma + else + current_family = EvolutionHelper.all_related_species(species) + comma = false + f.write("\r\n") + end + f.write(species) + comma = true + end + f.write("\r\n") + end + } + Graphics.update + end + + #=============================================================================== + # Save wild encounter data to PBS file + #=============================================================================== + def write_encounters + encdata = pbLoadEncountersData + return if !encdata + mapinfos = pbLoadRxData("Data/MapInfos") + File.open("PBS/encounters.txt","wb") { |f| + add_PBS_header_to_file(f) + sortedkeys = encdata.keys.sort + for i in sortedkeys + next if !encdata[i] + e = encdata[i] + mapname = "" + if mapinfos[i] + map = mapinfos[i].name + mapname = " # #{map}" + end + f.write("\#-------------------------------\r\n") + f.write(sprintf("%03d%s\r\n",i,mapname)) + f.write(sprintf("%d,%d,%d\r\n",e[0][EncounterTypes::Land], + e[0][EncounterTypes::Cave],e[0][EncounterTypes::Water])) + for j in 0...e[1].length + enc = e[1][j] + next if !enc + f.write(sprintf("%s\r\n",EncounterTypes::Names[j])) + for k in 0...EncounterTypes::EnctypeChances[j].length + next if !enc[k] + encentry = enc[k] + if encentry[1]==encentry[2] + f.write(sprintf(" %s,%d\r\n",encentry[0],encentry[1])) + else + f.write(sprintf(" %s,%d,%d\r\n",encentry[0],encentry[1],encentry[2])) + end + end + end + end + } + Graphics.update + end + + #=============================================================================== + # Save trainer type data to PBS file + #=============================================================================== + def write_trainer_types + File.open("PBS/trainertypes.txt", "wb") { |f| + add_PBS_header_to_file(f) + f.write("\#-------------------------------\r\n") + GameData::TrainerType.each do |t| + f.write(sprintf("%d,%s,%s,%d,%s,%s,%s,%s,%s,%s\r\n", + t.id_number, + csvQuote(t.id.to_s), + csvQuote(t.real_name), + t.base_money, + csvQuote(t.battle_BGM), + csvQuote(t.victory_ME), + csvQuote(t.intro_ME), + ["Male", "Female", "Mixed"][t.gender], + (t.skill_level == t.base_money) ? "" : t.skill_level.to_s, + csvQuote(t.skill_code) + )) + end + } + Graphics.update + end + + #=============================================================================== + # Save individual trainer data to PBS file + #=============================================================================== + def write_trainers + data = pbLoadTrainersData + return if !data + File.open("PBS/trainers.txt","wb") { |f| + add_PBS_header_to_file(f) + for trainer in data + trtypename = trainer[0].to_s + next if !trtypename + f.write("\#-------------------------------\r\n") + # Section + trainername = trainer[1] ? trainer[1].gsub(/,/,";") : "???" + if trainer[4]==0 + f.write(sprintf("[%s,%s]\r\n",trtypename,trainername)) + else + f.write(sprintf("[%s,%s,%d]\r\n",trtypename,trainername,trainer[4])) + end + # Trainer's items + if trainer[2] && trainer[2].length>0 + itemstring = "" + for i in 0...trainer[2].length + itemstring.concat(",") if i > 0 + itemstring.concat(trainer[2][i].to_s) + end + f.write(sprintf("Items = %s\r\n",itemstring)) if itemstring!="" + end + # Lose texts + if trainer[5] && trainer[5]!="" + f.write(sprintf("LoseText = %s\r\n",csvQuoteAlways(trainer[5]))) + end + # Pokémon + for poke in trainer[3] + f.write(sprintf("Pokemon = %s,%d\r\n",poke[TrainerData::SPECIES],poke[TrainerData::LEVEL])) + if poke[TrainerData::NAME] && poke[TrainerData::NAME]!="" + f.write(sprintf(" Name = %s\r\n",poke[TrainerData::NAME])) + end + if poke[TrainerData::FORM] + f.write(sprintf(" Form = %d\r\n",poke[TrainerData::FORM])) + end + if poke[TrainerData::GENDER] + f.write(sprintf(" Gender = %s\r\n",(poke[TrainerData::GENDER]==1) ? "female" : "male")) + end + if poke[TrainerData::SHINY] + f.write(" Shiny = yes\r\n") + end + if poke[TrainerData::SHADOW] + f.write(" Shadow = yes\r\n") + end + if poke[TrainerData::MOVES] && poke[TrainerData::MOVES].length>0 + movestring = "" + for i in 0...poke[TrainerData::MOVES].length + movename = GameData::Move.get(poke[TrainerData::MOVES][i]).id.to_s + next if !movename + movestring.concat(",") if i>0 + movestring.concat(movename) + end + f.write(sprintf(" Moves = %s\r\n",movestring)) if movestring!="" + end + if poke[TrainerData::ABILITY] + f.write(sprintf(" Ability = %s\r\n",poke[TrainerData::ABILITY].to_s)) + end + if poke[TrainerData::ITEM] + f.write(sprintf(" Item = %s\r\n",poke[TrainerData::ITEM].to_s)) + end + if poke[TrainerData::NATURE] + nature = getConstantName(PBNatures,poke[TrainerData::NATURE]) rescue nil + f.write(sprintf(" Nature = %s\r\n",nature)) if nature + end + if poke[TrainerData::IV] && poke[TrainerData::IV].length>0 + f.write(sprintf(" IV = %d",poke[TrainerData::IV][0])) + if poke[TrainerData::IV].length>1 + for i in 1...6 + f.write(sprintf(",%d",(i0 + f.write(sprintf(" EV = %d",poke[TrainerData::EV][0])) + if poke[TrainerData::EV].length>1 + for i in 1...6 + f.write(sprintf(",%d",(i [0, "e", nil], # Specifies a trainer + "Name" => [1, "s"], + "BeginSpeech" => [2, "s"], + "EndSpeechWin" => [3, "s"], + "EndSpeechLose" => [4, "s"], + "PokemonNos" => [5, "*u"] + } + File.open(filename,"wb") { |f| + add_PBS_header_to_file(f) + for i in 0...bttrainers.length + next if !bttrainers[i] + f.write("\#-------------------------------\r\n") + f.write(sprintf("[%03d]\r\n",i)) + for key in btTrainersRequiredTypes.keys + schema = btTrainersRequiredTypes[key] + record = bttrainers[i][schema[0]] + next if record==nil + f.write(sprintf("%s = ",key)) + if key=="Type" + f.write(record.to_s) + elsif key=="PokemonNos" + f.write(record.join(",")) # pbWriteCsvRecord somehow won't work here + else + pbWriteCsvRecord(record,f,schema) + end + f.write(sprintf("\r\n")) + end + end + } + Graphics.update + end + + #=============================================================================== + # Save Battle Tower Pokémon data to PBS file + #=============================================================================== + def write_battle_tower_pokemon(btpokemon,filename) + return if !btpokemon || !filename + species = {0=>""} + moves = {0=>""} + items = {0=>""} + natures = {} + File.open(filename,"wb") { |f| + add_PBS_header_to_file(f) + f.write("\#-------------------------------\r\n") + for i in 0...btpokemon.length + Graphics.update if i%500==0 + pkmn = btpokemon[i] + f.write(pbFastInspect(pkmn,moves,species,items,natures)) + f.write("\r\n") + end + } + Graphics.update + end + + def pbFastInspect(pkmn,moves,species,items,natures) + c1 = (species[pkmn.species]) ? species[pkmn.species] : (species[pkmn.species] = GameData::Species.get(pkmn.species).species.to_s) + c2 = (items[pkmn.item]) ? items[pkmn.item] : (items[pkmn.item] = GameData::Item.get(pkmn.item).id.to_s) + c3 = (natures[pkmn.nature]) ? natures[pkmn.nature] : + (natures[pkmn.nature] = getConstantName(PBNatures,pkmn.nature)) + evlist = "" + ev = pkmn.ev + evs = ["HP","ATK","DEF","SPD","SA","SD"] + for i in 0...ev + if ((ev&(1<0 + evlist += evs[i] + end + end + c4 = (moves[pkmn.move1]) ? moves[pkmn.move1] : (moves[pkmn.move1] = GameData::Move.get(pkmn.move1).id.to_s) + c5 = (moves[pkmn.move2]) ? moves[pkmn.move2] : (moves[pkmn.move2] = GameData::Move.get(pkmn.move2).id.to_s) + c6 = (moves[pkmn.move3]) ? moves[pkmn.move3] : (moves[pkmn.move3] = GameData::Move.get(pkmn.move3).id.to_s) + c7 = (moves[pkmn.move4]) ? moves[pkmn.move4] : (moves[pkmn.move4] = GameData::Move.get(pkmn.move4).id.to_s) + return "#{c1};#{c2};#{c3};#{evlist};#{c4},#{c5},#{c6},#{c7}" + end + + #=============================================================================== + # Save metadata data to PBS file + #=============================================================================== + def write_metadata + File.open("PBS/metadata.txt", "wb") { |f| + add_PBS_header_to_file(f) + # Write global metadata + f.write("\#-------------------------------\r\n") + f.write("[000]\r\n") + metadata = GameData::Metadata.get + schema = GameData::Metadata::SCHEMA + keys = schema.keys.sort {|a, b| schema[a][0] <=> schema[b][0] } + for key in keys + record = metadata.property_from_string(key) + next if record.nil? + f.write(sprintf("%s = ", key)) + pbWriteCsvRecord(record, f, schema[key]) + f.write("\r\n") + end + # Write map metadata + map_infos = pbLoadRxData("Data/MapInfos") + schema = GameData::MapMetadata::SCHEMA + keys = schema.keys.sort {|a, b| schema[a][0] <=> schema[b][0] } + GameData::MapMetadata.each do |map_data| + f.write("\#-------------------------------\r\n") + f.write(sprintf("[%03d]\r\n", map_data.id)) + if map_infos && map_infos[map_data.id] + f.write(sprintf("# %s\r\n", map_infos[map_data.id].name)) + end + for key in keys + record = map_data.property_from_string(key) + next if record.nil? + f.write(sprintf("%s = ", key)) + pbWriteCsvRecord(record, f, schema[key]) + f.write("\r\n") + end + end + } + Graphics.update + end + + #=============================================================================== + # Save all data to PBS files + #=============================================================================== + def write_all + write_town_map + write_connections + write_phone + write_types + write_abilities + write_moves + write_items + write_berry_plants + write_pokemon + write_pokemon_forms + write_shadow_movesets + write_regional_dexes + write_encounters + write_trainer_types + write_trainers + write_trainer_lists + write_metadata + end +end