mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-06 06:01:46 +00:00
6.4 update (minus sprites)
This commit is contained in:
@@ -106,13 +106,15 @@ class DoublePreviewScreen
|
||||
body_pokemon = getBodyID(dexNumber)
|
||||
head_pokemon = getHeadID(dexNumber, body_pokemon)
|
||||
|
||||
picturePath = getPicturePath(head_pokemon, body_pokemon)
|
||||
bitmap = AnimatedBitmap.new(picturePath)
|
||||
# picturePath = getPicturePath(head_pokemon, body_pokemon)
|
||||
# bitmap = AnimatedBitmap.new(picturePath)
|
||||
spriteLoader = BattleSpriteLoader.new
|
||||
bitmap = spriteLoader.load_fusion_sprite(head_pokemon,body_pokemon)
|
||||
bitmap.scale_bitmap(Settings::FRONTSPRITE_SCALE)
|
||||
|
||||
#hasCustom = picturePath.include?("CustomBattlers")
|
||||
hasCustom = customSpriteExistsBase(body_pokemon,head_pokemon)
|
||||
|
||||
#hasCustom = customSpriteExistsBase(body_pokemon,head_pokemon)
|
||||
hasCustom = customSpriteExists(body_pokemon,head_pokemon)
|
||||
previewwindow = PictureWindow.new(bitmap)
|
||||
previewwindow.x = x
|
||||
previewwindow.y = y
|
||||
@@ -131,10 +133,6 @@ class DoublePreviewScreen
|
||||
end
|
||||
|
||||
|
||||
def getPicturePath(head_pokemon, body_pokemon)
|
||||
return get_fusion_sprite_path(head_pokemon,body_pokemon)
|
||||
end
|
||||
|
||||
def drawFusionInformation(fusedDexNum, level, x = 0)
|
||||
viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
|
||||
@typewindows << drawPokemonType(fusedDexNum, viewport, x + 55, 220) if @draw_types
|
||||
|
||||
@@ -97,11 +97,11 @@ module GameData
|
||||
end
|
||||
|
||||
def get_body_species
|
||||
return @body_pokemon
|
||||
return @body_pokemon.id_number
|
||||
end
|
||||
|
||||
def get_head_species
|
||||
return @head_pokemon
|
||||
return @head_pokemon.id_number
|
||||
end
|
||||
|
||||
def adjust_stats_with_evs
|
||||
@@ -309,7 +309,7 @@ module GameData
|
||||
end
|
||||
|
||||
def calculate_growth_rate
|
||||
growth_rate_priority = [:Slow, :Erratic, :Fluctuating, :Parabolic, :Medium, :Fast] #todo rearrange order for balance?
|
||||
growth_rate_priority = [:Fast, :Medium, :Parabolic, :Fluctuating, :Erratic, :Slow] #todo rearrange order for balance?
|
||||
body_growth_rate = @body_pokemon.growth_rate
|
||||
head_growth_rate = @head_pokemon.growth_rate
|
||||
base_growth_rates = [body_growth_rate, head_growth_rate]
|
||||
|
||||
@@ -430,14 +430,14 @@ class PokemonFusionScene
|
||||
dna_splicer.z = 0
|
||||
duration = Graphics.frame_rate * nb_seconds
|
||||
direction = 1
|
||||
dna_splicer.bitmap = pbBitmap("Graphics/Items/POTION")
|
||||
#dna_splicer.bitmap = pbBitmap("Graphics/Items/POTION")
|
||||
|
||||
for j in 0...Graphics.frame_rate * 50
|
||||
if j % 2 ==0
|
||||
dna_splicer.bitmap = pbBitmap("Graphics/Items/SUPERSPLICERS")
|
||||
else
|
||||
dna_splicer.bitmap = pbBitmap("Graphics/Items/DNASPLICERS")
|
||||
end
|
||||
# if j % 2 ==0
|
||||
# dna_splicer.bitmap = pbBitmap("Graphics/Items/SUPERSPLICERS")
|
||||
# else
|
||||
# dna_splicer.bitmap = pbBitmap("Graphics/Items/DNASPLICERS")
|
||||
# end
|
||||
|
||||
if j % 5 == 0
|
||||
dna_splicer.y += direction
|
||||
@@ -500,9 +500,16 @@ class PokemonFusionScene
|
||||
#
|
||||
# #sprite_body.mirror if sprite_body_angle == 0 || sprite_body_angle == Math::PI
|
||||
#
|
||||
# update_sprite_color(sprite_body,j)
|
||||
# update_sprite_color(sprite_head,j)
|
||||
#
|
||||
#
|
||||
# sprite_head.update
|
||||
# sprite_fused.update
|
||||
# sprite_body.update
|
||||
#
|
||||
#
|
||||
#
|
||||
# end
|
||||
# sprite_head.opacity = 0
|
||||
# sprite_body.opacity = 0
|
||||
@@ -513,9 +520,22 @@ class PokemonFusionScene
|
||||
# @metafile3 = sprite_body
|
||||
# end
|
||||
|
||||
|
||||
def update_sprite_color(sprite,current_frame)
|
||||
start_tone_change = 100 #frame at which the tone starts to change
|
||||
return if current_frame < start_tone_change
|
||||
new_tone = current_frame-start_tone_change
|
||||
sprite.tone=Tone.new(new_tone,new_tone,new_tone)
|
||||
if current_frame %2 ==0
|
||||
#sprite.opacity-= 1
|
||||
end
|
||||
end
|
||||
# def pbGenerateMetafiles(nb_seconds,ellipse_center_x,ellipse_center_y,ellipse_major_axis_length,ellipse_minor_axis_length)
|
||||
|
||||
#def pbGenerateMetafiles(s1x, s1y, s2x, s2y, s3x, s3y, sxx, s3xx)
|
||||
|
||||
|
||||
#OLD ANIMATION
|
||||
def pbGenerateMetafiles(nb_seconds,ellipse_center_x,ellipse_center_y,ellipse_major_axis_length,ellipse_minor_axis_length)
|
||||
|
||||
@sprites["rsprite1"].ox = @sprites["rsprite1"].bitmap.width / 2
|
||||
@@ -643,19 +663,19 @@ class PokemonFusionScene
|
||||
|
||||
# Starts the fusion screen
|
||||
|
||||
def pbStartScreen(pokemon1, pokemon2, newspecies,splicerItem)
|
||||
def pbStartScreen(pokemon_body, pokemon_head, newspecies,splicerItem)
|
||||
@sprites = {}
|
||||
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
|
||||
@viewport.z = 99999
|
||||
@pokemon1 = pokemon1
|
||||
@pokemon2 = pokemon2
|
||||
@pokemon1 = pokemon_body
|
||||
@pokemon2 = pokemon_head
|
||||
|
||||
@newspecies = newspecies
|
||||
addBackgroundOrColoredPlane(@sprites, "background", "DNAbg",
|
||||
Color.new(248, 248, 248), @viewport)
|
||||
|
||||
poke1_number = GameData::Species.get(@pokemon1.species).id_number
|
||||
poke2_number = GameData::Species.get(@pokemon2.species).id_number
|
||||
poke_body_number = GameData::Species.get(@pokemon1.species).id_number
|
||||
poke_head_number = GameData::Species.get(@pokemon2.species).id_number
|
||||
|
||||
@sprites["rsprite1"] = PokemonSprite.new(@viewport)
|
||||
@sprites["rsprite2"] = PokemonSprite.new(@viewport)
|
||||
@@ -665,10 +685,15 @@ class PokemonFusionScene
|
||||
@sprites["dnasplicer"].y=(Graphics.height/2)-50
|
||||
@sprites["dnasplicer"].opacity=0
|
||||
|
||||
@sprites["rsprite1"].setPokemonBitmapFromId(poke1_number, false, pokemon1.shiny?)
|
||||
@sprites["rsprite3"].setPokemonBitmapFromId(poke2_number, false, pokemon2.shiny?)
|
||||
@sprites["rsprite1"].setPokemonBitmapFromId(poke_body_number, false, pokemon_head.shiny?)
|
||||
@sprites["rsprite3"].setPokemonBitmapFromId(poke_head_number, false, pokemon_head.shiny?)
|
||||
|
||||
@sprites["rsprite2"].setPokemonBitmapFromId(@newspecies, false, pokemon1.shiny? || pokemon2.shiny?, pokemon1.shiny?, pokemon2.shiny?)
|
||||
|
||||
spriteLoader = BattleSpriteLoader.new
|
||||
@fusion_pif_sprite = spriteLoader.obtain_fusion_pif_sprite(poke_head_number,poke_body_number)
|
||||
|
||||
#this will use the sprite that is set when we call obtain_fusion_pif_sprite, and apply the shiny effect
|
||||
@sprites["rsprite2"].setPokemonBitmapFromId(@newspecies, false, pokemon_head.shiny? || pokemon_body.shiny?, pokemon_head.shiny?, pokemon_body.shiny?)
|
||||
|
||||
splicer_bitmap = _INTL("Graphics/Items/{1}",splicerItem)
|
||||
@sprites["dnasplicer"].setBitmap(splicer_bitmap)
|
||||
@@ -722,8 +747,8 @@ class PokemonFusionScene
|
||||
####FUSION MULTIPLIER
|
||||
|
||||
#####LEVELS
|
||||
level1 = pokemon1.level
|
||||
level2 = pokemon2.level
|
||||
level1 = pokemon_head.level
|
||||
level2 = pokemon_body.level
|
||||
|
||||
####LEVEL DIFFERENCE
|
||||
if (level1 >= level2) then
|
||||
@@ -788,7 +813,7 @@ class PokemonFusionScene
|
||||
metaplayer1.play
|
||||
metaplayer2.play
|
||||
metaplayer3.play
|
||||
#metaplayer4.play
|
||||
metaplayer4.play
|
||||
pbBGMStop()
|
||||
pbPlayCry(@pokemon)
|
||||
Kernel.pbMessageDisplay(@sprites["msgwindow"],
|
||||
@@ -839,7 +864,8 @@ class PokemonFusionScene
|
||||
overlay = BitmapSprite.new(Graphics.width, Graphics.height, @viewport).bitmap
|
||||
|
||||
sprite_bitmap = @sprites["rsprite2"].getBitmap
|
||||
drawSpriteCredits(sprite_bitmap.filename, sprite_bitmap.path, @viewport)
|
||||
|
||||
drawSpriteCredits(@fusion_pif_sprite, @viewport)
|
||||
pbBGMPlay(pbGetWildVictoryME)
|
||||
Kernel.pbMessageDisplay(@sprites["msgwindow"],
|
||||
_INTL("\\se[]Congratulations! Your Pokémon were fused into {2}!\\wt[80]", @pokemon1.name, newspeciesname))
|
||||
@@ -925,13 +951,13 @@ class PokemonFusionScene
|
||||
end
|
||||
end
|
||||
|
||||
def drawSpriteCredits(filename, path, viewport)
|
||||
def drawSpriteCredits(pif_sprite, viewport)
|
||||
overlay = BitmapSprite.new(Graphics.width, Graphics.height, @viewport).bitmap
|
||||
|
||||
return if path.start_with?(Settings::BATTLERS_FOLDER)
|
||||
return if pif_sprite.type == :AUTOGEN
|
||||
x = Graphics.width / 2
|
||||
y = 240
|
||||
spritename = File.basename(filename, '.*')
|
||||
spritename = pif_sprite.to_filename()
|
||||
spritename = File.basename(spritename, '.*')
|
||||
|
||||
discord_name = getSpriteCredits(spritename)
|
||||
return if !discord_name
|
||||
@@ -948,6 +974,9 @@ def drawSpriteCredits(filename, path, viewport)
|
||||
pbDrawTextPositions(overlay, textpos)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def clearUIForMoves
|
||||
addBackgroundOrColoredPlane(@sprites, "background", "DNAbg",
|
||||
Color.new(248, 248, 248), @viewport)
|
||||
|
||||
@@ -380,8 +380,8 @@ module GameData
|
||||
["Regi", "rock"],
|
||||
["Regi", "ice"],
|
||||
["Regi", "steel"],
|
||||
["Latia", "tias"],
|
||||
["Latio", "tios"],
|
||||
["La", "tias"],
|
||||
["La", "tios"],
|
||||
["Kyo", "ogre"],
|
||||
["Grou", "don"],
|
||||
["Ray", "quaza"],
|
||||
@@ -559,11 +559,11 @@ module GameData
|
||||
["Marac", "actus"],
|
||||
["Dweb", "ebble"],
|
||||
["Crust", "ustle"],
|
||||
["Scrag", "aggy"],
|
||||
["Scraft", "afty"],
|
||||
["Scra", "ggy"],
|
||||
["Scraf", "ty"],
|
||||
["Sigi", "lyph"],
|
||||
["Ya", "mask"],
|
||||
["Cofag", "grigus"],
|
||||
["Cofa", "grigus"],
|
||||
["Tirt", "touga"],
|
||||
["Carra", "costa"],
|
||||
["Arch", "chen"],
|
||||
@@ -650,15 +650,15 @@ module GameData
|
||||
["Kel", "deo"],
|
||||
["Melo", "etta"],
|
||||
["Gene", "esect"],
|
||||
["Chesp", "spin"],
|
||||
["Quill", "ladin"],
|
||||
["Chesn", "naught"],
|
||||
["Ches", "pin"],
|
||||
["Quil", "ladin"],
|
||||
["Ches", "naught"],
|
||||
["Fenne", "kin"],
|
||||
["Braix", "xen"],
|
||||
["Delph", "phox"],
|
||||
["Brai", "xen"],
|
||||
["Del", "phox"],
|
||||
["Froa", "kie"],
|
||||
["Froga", "dier"],
|
||||
["Gren", "ninja"],
|
||||
["Frog", "adier"],
|
||||
["Gre", "ninja"],
|
||||
["Bunnel", "elby"],
|
||||
["Diggers", "ersby"],
|
||||
["Fletch", "ling"],
|
||||
@@ -684,8 +684,8 @@ module GameData
|
||||
["Aegi", "slash"],
|
||||
["Spritz", "itzee"],
|
||||
["Aroma", "tisse"],
|
||||
["Swirl", "irlix"],
|
||||
["Slurp", "urpuff"],
|
||||
["Swir", "lix"],
|
||||
["Slur", "puff"],
|
||||
["Ink", "kay"],
|
||||
["Mala", "lamar"],
|
||||
["Bin", "nacle"],
|
||||
@@ -703,7 +703,7 @@ module GameData
|
||||
["Syl", "veon"],
|
||||
["Hawl", "lucha"],
|
||||
["Deden", "denne"],
|
||||
["Carb", "bink"],
|
||||
["Car", "bink"],
|
||||
["Goo", "my"],
|
||||
["Sli", "goo"],
|
||||
["Goo", "dra"],
|
||||
@@ -711,7 +711,7 @@ module GameData
|
||||
["Phant", "tump"],
|
||||
["Tre", "venant"],
|
||||
["Pump", "kaboo"],
|
||||
["Gourg", "urgeist"],
|
||||
["Gour", "geist"],
|
||||
["Berg", "mite"],
|
||||
["Ava", "lugg"],
|
||||
["Noi", "bat"],
|
||||
@@ -719,7 +719,7 @@ module GameData
|
||||
["Xern", "neas"],
|
||||
["Yvel", "veltal"],
|
||||
["Zyga", "garde"],
|
||||
["Dian", "ancie"],
|
||||
["Dian", "cie"],
|
||||
["Hoop", "oopa"],
|
||||
["Volcan", "canion"],
|
||||
["Rowl", "owlet"],
|
||||
@@ -754,7 +754,7 @@ module GameData
|
||||
["Dew", "pider"],
|
||||
["Ara", "quanid"],
|
||||
["Fo", "mantis"],
|
||||
["Lur", "antis"],
|
||||
["Lu", "rantis"],
|
||||
["More", "lull"],
|
||||
["Shii", "notic"],
|
||||
["Salan", "dit"],
|
||||
@@ -767,8 +767,8 @@ module GameData
|
||||
["Com", "fey"],
|
||||
["Oran", "guru"],
|
||||
["Pass", "simian"],
|
||||
["Wimp", "pod"],
|
||||
["Goliso", "sopod"],
|
||||
["Wim", "pod"],
|
||||
["Goli", "sopod"],
|
||||
["Sandy", "gast"],
|
||||
["Palo", "sand"],
|
||||
["Pyuku", "muku"],
|
||||
@@ -781,10 +781,10 @@ module GameData
|
||||
["Mimi", "kyu"],
|
||||
["Brux", "ish"],
|
||||
["Dram", "ampa"],
|
||||
["Dhelm", "helmise"],
|
||||
["Jang", "angmo-o"],
|
||||
["Haka", "akamo-o"],
|
||||
["Komm", "mo-o"],
|
||||
["Dhel", "mise"],
|
||||
["Jang", "mo-o"],
|
||||
["Haka", "mo-o"],
|
||||
["Kom", "mo-o"],
|
||||
["Tapu Ko", " Koko"],
|
||||
["Tapu Le", " Lele"],
|
||||
["Tapu Bu", " Bulu"],
|
||||
@@ -1129,6 +1129,37 @@ module GameData
|
||||
468 => 488,
|
||||
469 => 779,
|
||||
470 => 800,
|
||||
471 => 782,
|
||||
472 => 783,
|
||||
473 => 784,
|
||||
474 => 767,
|
||||
475 => 768,
|
||||
476 => 753,
|
||||
477 => 754,
|
||||
478 => 703,
|
||||
479 => 650,
|
||||
480 => 651,
|
||||
481 => 652,
|
||||
482 => 653,
|
||||
483 => 654,
|
||||
484 => 655,
|
||||
485 => 656,
|
||||
486 => 657,
|
||||
487 => 658,
|
||||
488 => 324,
|
||||
489 => 710,
|
||||
490 => 711,
|
||||
491 => 684,
|
||||
492 => 685,
|
||||
493 => 559,
|
||||
494 => 560,
|
||||
495 => 270,
|
||||
496 => 271,
|
||||
497 => 272,
|
||||
498 => 774,
|
||||
499 => 774,
|
||||
500 => 719,
|
||||
501 => 370,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
52
Data/Scripts/048_Fusion/Sprites/001_PifSpriteBitmapCache.rb
Normal file
52
Data/Scripts/048_Fusion/Sprites/001_PifSpriteBitmapCache.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
class SpritesBitmapCache
|
||||
@@cache = {} # Cache storage for individual sprites
|
||||
@@usage_order = [] # Tracks usage order for LRU eviction
|
||||
|
||||
def getCache()
|
||||
return @@cache
|
||||
end
|
||||
|
||||
def get_bitmap(pif_sprite)
|
||||
sprite_key = get_cache_key(pif_sprite)
|
||||
if @@cache.key?(sprite_key)
|
||||
mark_key_as_recently_used(sprite_key)
|
||||
return @@cache[sprite_key].clone
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def mark_key_as_recently_used(sprite_key)
|
||||
@@usage_order.delete(sprite_key)
|
||||
@@usage_order << sprite_key
|
||||
end
|
||||
|
||||
#Keys format: [type]_B[body]H[head]_letter
|
||||
# ex:
|
||||
# AUTOGEN_B12H12_
|
||||
# CUSTOM_B12H12_a
|
||||
# BASE_BH12_a
|
||||
# etc.
|
||||
def get_cache_key(pif_sprite)
|
||||
return "#{pif_sprite.type.to_s}_B#{pif_sprite.body_id}H#{pif_sprite.head_id}_#{pif_sprite.alt_letter}".to_sym
|
||||
end
|
||||
|
||||
#Keys format: AUTOGEN_B12H12_a
|
||||
def add(pif_sprite,bitmap)
|
||||
sprite_key = get_cache_key(pif_sprite)
|
||||
echoln "adding key #{sprite_key} to cache"
|
||||
@@cache[sprite_key] = bitmap.clone
|
||||
|
||||
if @@cache.size >= Settings::SPRITE_CACHE_MAX_NB
|
||||
# Evict least recently used (first in order)
|
||||
oldest_key = @@usage_order.shift
|
||||
@@cache.delete(oldest_key)
|
||||
echoln "Evicted: #{oldest_key} from sprite cache"
|
||||
end
|
||||
@@usage_order << sprite_key
|
||||
end
|
||||
|
||||
def clear
|
||||
@@cache = {}
|
||||
@@usage_order = []
|
||||
end
|
||||
end
|
||||
125
Data/Scripts/048_Fusion/Sprites/002_PIFSpriteExtracter.rb
Normal file
125
Data/Scripts/048_Fusion/Sprites/002_PIFSpriteExtracter.rb
Normal file
@@ -0,0 +1,125 @@
|
||||
class PIFSpriteExtracter
|
||||
COLUMNS = 20 # Number of columns in the spritesheet
|
||||
@@spritesheet_cache = SpritesBitmapCache.new
|
||||
|
||||
def load_sprite(pif_sprite,download_allowed=true)
|
||||
begin
|
||||
start_time = Time.now
|
||||
bitmap = @@spritesheet_cache.get_bitmap(pif_sprite)
|
||||
loaded_from_spritesheet=false
|
||||
|
||||
if !bitmap
|
||||
download_new_spritesheet(pif_sprite) if should_update_spritesheet?(pif_sprite) && download_allowed
|
||||
if pbResolveBitmap(getSpritesheetPath(pif_sprite))
|
||||
bitmap = load_bitmap_from_spritesheet(pif_sprite)
|
||||
loaded_from_spritesheet=true
|
||||
@@spritesheet_cache.add(pif_sprite, bitmap)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
sprite_bitmap = AnimatedBitmap.from_bitmap(bitmap)
|
||||
end_time = Time.now
|
||||
source = loaded_from_spritesheet ? :"spritesheet" : "cache"
|
||||
echoln "Loaded sprite for <head:#{pif_sprite.head_id}, body: #{pif_sprite.body_id}, variant: #{pif_sprite.alt_letter}> from #{source} in #{end_time - start_time} seconds"
|
||||
return sprite_bitmap
|
||||
rescue Exception
|
||||
e = $!
|
||||
echoln "Error loading sprite: #{e}" if bitmap
|
||||
end
|
||||
end
|
||||
|
||||
def download_new_spritesheet(pif_sprite)
|
||||
spritesheet_file = getSpritesheetPath(pif_sprite)
|
||||
if download_spritesheet(pif_sprite,spritesheet_file)
|
||||
$updated_spritesheets << spritesheet_file
|
||||
update_downloaded_spritesheets_list()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def update_downloaded_spritesheets_list()
|
||||
File.open(Settings::UPDATED_SPRITESHEETS_CACHE, "w") do |file|
|
||||
$updated_spritesheets.each { |line| file.puts(line) }
|
||||
end
|
||||
end
|
||||
|
||||
def get_sprite_position_on_spritesheet(body_id,sprite_size,nb_column)
|
||||
row = body_id / nb_column
|
||||
col = body_id % nb_column
|
||||
# echoln "(#{col},#{row})"
|
||||
# Define the area of the sprite on the spritesheet
|
||||
sprite_x_position = col * sprite_size
|
||||
sprite_y_position = row * sprite_size
|
||||
return sprite_x_position, sprite_y_position
|
||||
end
|
||||
|
||||
|
||||
def extract_bitmap_to_file(pif_sprite, dest_folder)
|
||||
# Create the directory if it doesn't exist
|
||||
Dir.mkdir(dest_folder) unless Dir.exist?(dest_folder)
|
||||
single_sprite_bitmap=load_sprite(pif_sprite)
|
||||
|
||||
# Save the single sprite bitmap to a file
|
||||
file_path = "#{dest_folder}/#{head_id}.#{body_id}.png"
|
||||
single_sprite_bitmap.save_to_png(file_path)
|
||||
|
||||
# Dispose of the single sprite bitmap
|
||||
single_sprite_bitmap.dispose
|
||||
|
||||
# Return the path to the saved PNG file
|
||||
return file_path
|
||||
end
|
||||
|
||||
#Implemented for base and custom, not autogen
|
||||
def should_update_spritesheet?(spritesheet_file)
|
||||
return false
|
||||
end
|
||||
|
||||
def getSpritesheetPath(pif_sprite)
|
||||
return nil #implement in subclasses
|
||||
end
|
||||
|
||||
def clear_cache()
|
||||
@@spritesheet_cache.clear
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class PokemonGlobalMetadata
|
||||
attr_accessor :current_spritepack_date
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# class SpritesBitmapCache
|
||||
# @@cache = {} # Cache storage for spritesheets
|
||||
# @@usage_order = [] # Tracks usage order for LRU eviction
|
||||
#
|
||||
# def self.fetch(key)
|
||||
# if @@cache.key?(key)
|
||||
# # Move key to the end to mark it as recently used
|
||||
# @@usage_order.delete(key)
|
||||
# @@usage_order << key
|
||||
# return @@cache[key]
|
||||
# end
|
||||
#
|
||||
# # Load spritesheet via block if not found in cache
|
||||
# spritesheet = yield
|
||||
#
|
||||
# if @@cache.size >= Settings::SPRITE_CACHE_MAX_NB
|
||||
# # Evict least recently used (first in order)
|
||||
# oldest_key = @@usage_order.shift
|
||||
# @@cache.delete(oldest_key)
|
||||
# echoln "Evicted: #{oldest_key} from spritesheet cache"
|
||||
# end
|
||||
#
|
||||
# # Add new spritesheet to cache and track its usage
|
||||
# @@cache[key] = spritesheet
|
||||
# @@usage_order << key
|
||||
# spritesheet
|
||||
# end
|
||||
# end
|
||||
157
Data/Scripts/048_Fusion/Sprites/AutogenExtracter.rb
Normal file
157
Data/Scripts/048_Fusion/Sprites/AutogenExtracter.rb
Normal file
@@ -0,0 +1,157 @@
|
||||
class AutogenExtracter < PIFSpriteExtracter
|
||||
SPRITESHEET_FOLDER_PATH = "Graphics\\Battlers\\spritesheets_autogen\\"
|
||||
SPRITE_SIZE = 288 # Each sprite is 288x288 pixels
|
||||
COLUMNS = 10 # Number of columns in the spritesheet
|
||||
SHEET_WIDTH = SPRITE_SIZE * COLUMNS # 2880 pixels wide spritesheet
|
||||
|
||||
@instance = new
|
||||
def self.instance
|
||||
@@instance ||= new # If @@instance is nil, create a new instance
|
||||
@@instance # Return the existing or new instance
|
||||
end
|
||||
|
||||
def load_bitmap_from_spritesheet(pif_sprite)
|
||||
body_id = pif_sprite.body_id
|
||||
spritesheet_file = getSpritesheetPath(pif_sprite)
|
||||
spritesheet_bitmap = AnimatedBitmap.new(spritesheet_file).bitmap
|
||||
|
||||
# Extract individual sprite
|
||||
sprite_x_position, sprite_y_position = get_sprite_position_on_spritesheet(body_id, SPRITE_SIZE, COLUMNS)
|
||||
src_rect = Rect.new(sprite_x_position, sprite_y_position, SPRITE_SIZE, SPRITE_SIZE)
|
||||
|
||||
bitmap = Bitmap.new(SPRITE_SIZE, SPRITE_SIZE)
|
||||
bitmap.blt(0, 0, spritesheet_bitmap, src_rect)
|
||||
|
||||
# Dispose of spritesheet if it's no longer needed
|
||||
spritesheet_bitmap.dispose
|
||||
return bitmap
|
||||
end
|
||||
|
||||
def getSpritesheetPath(pif_sprite)
|
||||
head_id = pif_sprite.head_id
|
||||
return "#{SPRITESHEET_FOLDER_PATH}#{head_id}.png"
|
||||
end
|
||||
|
||||
#
|
||||
# # Check cache before loading from disk
|
||||
# sprite_bitmap = @@spritesheet_cache.fetch(pif_sprite) do
|
||||
# # Load spritesheet from disk if necessary
|
||||
# echoln "Loading spritesheet from disk: #{spritesheet_file}"
|
||||
# spritesheet_bitmap = AnimatedBitmap.new(spritesheet_file).bitmap
|
||||
#
|
||||
# # Extract individual sprite
|
||||
# sprite_x_position, sprite_y_position = get_sprite_position_on_spritesheet(body_id, SPRITE_SIZE, COLUMNS)
|
||||
# src_rect = Rect.new(sprite_x_position, sprite_y_position, SPRITE_SIZE, SPRITE_SIZE)
|
||||
#
|
||||
# sprite = Bitmap.new(SPRITE_SIZE, SPRITE_SIZE)
|
||||
# sprite.blt(0, 0, spritesheet_bitmap, src_rect)
|
||||
#
|
||||
# # Dispose of spritesheet if it's no longer needed
|
||||
# spritesheet_bitmap.dispose
|
||||
#
|
||||
# sprite
|
||||
# end
|
||||
# animatedBitmap = AnimatedBitmap.from_bitmap(sprite_bitmap)
|
||||
#
|
||||
# end_time = Time.now
|
||||
# echoln "finished load sprite in #{end_time - start_time} seconds"
|
||||
# echoln animatedBitmap
|
||||
# return animatedBitmap
|
||||
# end
|
||||
|
||||
def load_sprite_with_spritesheet_cache(pif_sprite)
|
||||
start_time = Time.now
|
||||
head_id = pif_sprite.head_id
|
||||
body_id = pif_sprite.body_id
|
||||
spritesheet_file = "#{SPRITESHEET_FOLDER_PATH}#{head_id}.png"
|
||||
|
||||
# Check cache before loading from disk
|
||||
spritesheet_bitmap = @@spritesheet_cache.fetch(spritesheet_file) do
|
||||
echoln "Loading spritesheet from disk: #{spritesheet_file}"
|
||||
AnimatedBitmap.new(spritesheet_file).bitmap
|
||||
end
|
||||
|
||||
sprite_x_position, sprite_y_position = get_sprite_position_on_spritesheet(body_id, SPRITE_SIZE, COLUMNS)
|
||||
src_rect = Rect.new(sprite_x_position, sprite_y_position, SPRITE_SIZE, SPRITE_SIZE)
|
||||
|
||||
sprite_bitmap = Bitmap.new(SPRITE_SIZE, SPRITE_SIZE)
|
||||
sprite_bitmap.blt(0, 0, spritesheet_bitmap, src_rect)
|
||||
|
||||
#spritesheet_bitmap.dispose # Dispose since not needed
|
||||
|
||||
animatedBitmap = AnimatedBitmap.from_bitmap(sprite_bitmap)
|
||||
|
||||
end_time = Time.now
|
||||
echoln "finished load sprite in #{end_time - start_time} seconds"
|
||||
|
||||
return animatedBitmap
|
||||
end
|
||||
end
|
||||
|
||||
# def extract_bitmap_to_file(head_id, body_id, folder)
|
||||
# # Create the directory if it doesn't exist
|
||||
# Dir.mkdir(folder) unless Dir.exist?(folder)
|
||||
#
|
||||
# # Load the entire spritesheet
|
||||
# spritesheet_file = "#{SPRITESHEET_FOLDER_PATH}#{head_id}.png"
|
||||
# spritesheet_bitmap = AnimatedBitmap.new(spritesheet_file).bitmap
|
||||
#
|
||||
# # Calculate the 0-based row and column from the sprite index
|
||||
# zero_index = body_id - 1
|
||||
# row = zero_index / COLUMNS
|
||||
# col = zero_index % COLUMNS
|
||||
#
|
||||
# # Define the area of the sprite on the spritesheet
|
||||
# sprite_x_position = col * SPRITE_SIZE
|
||||
# sprite_y_position = row * SPRITE_SIZE
|
||||
#
|
||||
# # Create a new bitmap for the single sprite
|
||||
# single_sprite_bitmap = Bitmap.new(SPRITE_SIZE, SPRITE_SIZE)
|
||||
# single_sprite_bitmap.blt(0, 0, spritesheet_bitmap, Rect.new(sprite_x_position, sprite_y_position, SPRITE_SIZE, SPRITE_SIZE))
|
||||
#
|
||||
# # Dispose of the spritesheet bitmap if it’s no longer needed
|
||||
# spritesheet_bitmap.dispose
|
||||
#
|
||||
# # Save the single sprite bitmap to a file
|
||||
# file_path = "#{folder}/#{head_id}.#{body_id}.png"
|
||||
# single_sprite_bitmap.save_to_png(file_path)
|
||||
#
|
||||
# # Dispose of the single sprite bitmap
|
||||
# single_sprite_bitmap.dispose
|
||||
#
|
||||
# # Return the path to the saved PNG file
|
||||
# return file_path
|
||||
# end
|
||||
#end
|
||||
#
|
||||
#
|
||||
# class SpritesBitmapCache
|
||||
# @@cache = {} # Cache storage for individual sprites
|
||||
# @@usage_order = [] # Tracks usage order for LRU eviction
|
||||
#
|
||||
# def self.fetch(pif_sprite)
|
||||
# sprite_key = "B#{pif_sprite.body_id}H#{pif_sprite.head_id}".to_sym
|
||||
# if @@cache.key?(sprite_key)
|
||||
# # Move key to the end to mark it as recently used
|
||||
# @@usage_order.delete(sprite_key)
|
||||
# @@usage_order << sprite_key
|
||||
# return @@cache[sprite_key]
|
||||
# end
|
||||
#
|
||||
# # Load sprite via block if not found in cache
|
||||
# sprite_bitmap = yield
|
||||
#
|
||||
# if @@cache.size >= Settings::SPRITE_CACHE_MAX_NB
|
||||
# # Evict least recently used (first in order)
|
||||
# oldest_key = @@usage_order.shift
|
||||
# @@cache.delete(oldest_key)
|
||||
# echoln "Evicted: #{oldest_key} from sprite cache"
|
||||
# end
|
||||
#
|
||||
# # Add new sprite to cache and track its usage
|
||||
# @@cache[sprite_key] = sprite_bitmap
|
||||
# @@usage_order << sprite_key
|
||||
# sprite_bitmap
|
||||
# echoln @@cache
|
||||
# end
|
||||
# end
|
||||
58
Data/Scripts/048_Fusion/Sprites/BaseSpriteExtracter.rb
Normal file
58
Data/Scripts/048_Fusion/Sprites/BaseSpriteExtracter.rb
Normal file
@@ -0,0 +1,58 @@
|
||||
class BaseSpriteExtracter < PIFSpriteExtracter
|
||||
@instance = new
|
||||
|
||||
def self.instance
|
||||
@@instance ||= new # If @@instance is nil, create a new instance
|
||||
@@instance # Return the existing or new instance
|
||||
end
|
||||
|
||||
SPRITESHEET_FOLDER_PATH = "Graphics/CustomBattlers/spritesheets/spritesheets_base/"
|
||||
SPRITE_SIZE = 288 # Original sprite size
|
||||
SCALED_SIZE = 288 # Scaled sprite size
|
||||
NB_COLUMNS_BASESPRITES = 10
|
||||
SHEET_WIDTH = SPRITE_SIZE * NB_COLUMNS_BASESPRITES # 2880 pixels wide spritesheet
|
||||
def load_bitmap_from_spritesheet(pif_sprite)
|
||||
alt_letter = pif_sprite.alt_letter
|
||||
spritesheet_file = getSpritesheetPath(pif_sprite)
|
||||
spritesheet_bitmap = AnimatedBitmap.new(spritesheet_file).bitmap
|
||||
|
||||
letter_index = letters_to_index(alt_letter)
|
||||
sprite_x_position, sprite_y_position = get_sprite_position_on_spritesheet(letter_index, SPRITE_SIZE, NB_COLUMNS_BASESPRITES)
|
||||
src_rect = Rect.new(sprite_x_position, sprite_y_position, SPRITE_SIZE, SPRITE_SIZE)
|
||||
|
||||
sprite_bitmap = Bitmap.new(SPRITE_SIZE, SPRITE_SIZE)
|
||||
sprite_bitmap.blt(0, 0, spritesheet_bitmap, src_rect)
|
||||
spritesheet_bitmap.dispose # Dispose since not needed
|
||||
|
||||
return sprite_bitmap
|
||||
end
|
||||
|
||||
def letters_to_index(letters)
|
||||
letters = letters.downcase # Ensure input is case-insensitive
|
||||
index = 0
|
||||
letters.each_char do |char|
|
||||
index = index * 26 + (char.ord - 'a'.ord + 1)
|
||||
end
|
||||
#echoln "index: #{index}"
|
||||
return index
|
||||
end
|
||||
|
||||
def load_sprite_directly(head_id, body_id, alt_letter = "")
|
||||
load_sprite(PIFSprite.new(:CUSTOM, head_id, body_id, alt_letter))
|
||||
end
|
||||
|
||||
def getSpritesheetPath(pif_sprite)
|
||||
dex_number = getDexNumberForSpecies(pif_sprite.head_id)
|
||||
return "#{SPRITESHEET_FOLDER_PATH}#{dex_number}.png"
|
||||
end
|
||||
|
||||
def should_update_spritesheet?(pif_sprite)
|
||||
return false if !$updated_spritesheets
|
||||
return false if !downloadAllowed?()
|
||||
return false if requestRateExceeded?(Settings::CUSTOMSPRITES_RATE_LOG_FILE,Settings::CUSTOMSPRITES_ENTRIES_RATE_TIME_WINDOW,Settings::CUSTOMSPRITES_RATE_MAX_NB_REQUESTS,false)
|
||||
spritesheet_file = getSpritesheetPath(pif_sprite)
|
||||
return true if !pbResolveBitmap(spritesheet_file)
|
||||
|
||||
return !$updated_spritesheets.include?(spritesheet_file)
|
||||
end
|
||||
end
|
||||
266
Data/Scripts/048_Fusion/Sprites/BattleSpriteLoader.rb
Normal file
266
Data/Scripts/048_Fusion/Sprites/BattleSpriteLoader.rb
Normal file
@@ -0,0 +1,266 @@
|
||||
class BattleSpriteLoader
|
||||
def initialize
|
||||
@download_allowed = true
|
||||
end
|
||||
|
||||
def load_pif_sprite_directly(pif_sprite)
|
||||
extractor = get_sprite_extractor_instance(pif_sprite.type)
|
||||
return extractor.load_sprite(pif_sprite)
|
||||
end
|
||||
|
||||
#random alt
|
||||
def load_pif_sprite(pif_sprite)
|
||||
case pif_sprite.type
|
||||
when :CUSTOM, :AUTOGEN
|
||||
load_fusion_sprite(pif_sprite.head_id, pif_sprite.body_id)
|
||||
when :BASE
|
||||
load_base_sprite(pif_sprite.head_id)
|
||||
end
|
||||
end
|
||||
|
||||
# Only preloads if the pokemon's sprite has been assigned an alt letter
|
||||
def preload_sprite_from_pokemon(pokemon)
|
||||
return if !pokemon
|
||||
substitution_id = get_sprite_substitution_id_from_dex_number(pokemon.species)
|
||||
echoln substitution_id
|
||||
echoln $PokemonGlobal.alt_sprite_substitutions
|
||||
pif_sprite = $PokemonGlobal.alt_sprite_substitutions[substitution_id] if $PokemonGlobal
|
||||
if !pif_sprite
|
||||
pif_sprite = get_pif_sprite_from_species(pokemon.species)
|
||||
end
|
||||
preload(pif_sprite)
|
||||
end
|
||||
|
||||
#loads a sprite into cache without actually returning it
|
||||
# Does not download spritesheet
|
||||
def preload(pif_sprite)
|
||||
echoln "preloading"
|
||||
previous_download_allowed = @download_allowed
|
||||
@download_allowed = false
|
||||
load_pif_sprite(pif_sprite)
|
||||
@download_allowed = previous_download_allowed
|
||||
end
|
||||
|
||||
def clear_sprites_cache(type)
|
||||
extractor = get_sprite_extractor_instance(type)
|
||||
extractor.clear_cache
|
||||
end
|
||||
|
||||
def load_from_dex_number(dex_number)
|
||||
if dex_number > NB_POKEMON
|
||||
if dex_number > ZAPMOLCUNO_NB #Triple Fusion
|
||||
return load_triple_fusion_sprite(dex_number)
|
||||
else
|
||||
#Regular fusion
|
||||
body_id = getBodyID(dex_number)
|
||||
head_id = getHeadID(dex_number, body_id)
|
||||
return load_fusion_sprite(head_id, body_id)
|
||||
end
|
||||
else
|
||||
#base pokemon
|
||||
return load_base_sprite(dex_number)
|
||||
end
|
||||
end
|
||||
|
||||
def obtain_fusion_pif_sprite(head_id,body_id)
|
||||
substitution_id = get_sprite_substitution_id_for_fusion(head_id, body_id)
|
||||
pif_sprite = $PokemonGlobal.alt_sprite_substitutions[substitution_id] if $PokemonGlobal
|
||||
if !pif_sprite
|
||||
pif_sprite = select_new_pif_fusion_sprite(head_id, body_id)
|
||||
substitution_id = get_sprite_substitution_id_for_fusion(head_id, body_id)
|
||||
$PokemonGlobal.alt_sprite_substitutions[substitution_id] = pif_sprite if $PokemonGlobal
|
||||
end
|
||||
return pif_sprite
|
||||
end
|
||||
|
||||
def load_fusion_sprite(head_id, body_id)
|
||||
pif_sprite = obtain_fusion_pif_sprite(head_id,body_id)
|
||||
local_path = check_for_local_sprite(pif_sprite)
|
||||
if local_path
|
||||
return AnimatedBitmap.new(local_path)
|
||||
end
|
||||
extractor = get_sprite_extractor_instance(pif_sprite.type)
|
||||
loaded_sprite = extractor.load_sprite(pif_sprite, @download_allowed)
|
||||
if !loaded_sprite
|
||||
loaded_sprite = handle_unloaded_sprites(extractor,pif_sprite)
|
||||
end
|
||||
return loaded_sprite
|
||||
end
|
||||
|
||||
def load_base_sprite(dex_number)
|
||||
substitution_id = get_sprite_substitution_id_from_dex_number(dex_number)
|
||||
pif_sprite = $PokemonGlobal.alt_sprite_substitutions[substitution_id] if $PokemonGlobal
|
||||
if !pif_sprite
|
||||
pif_sprite = select_new_pif_base_sprite(dex_number)
|
||||
$PokemonGlobal.alt_sprite_substitutions[substitution_id] = pif_sprite if $PokemonGlobal
|
||||
end
|
||||
local_path = check_for_local_sprite(pif_sprite)
|
||||
if local_path
|
||||
return AnimatedBitmap.new(local_path)
|
||||
end
|
||||
extractor = get_sprite_extractor_instance(pif_sprite.type)
|
||||
loaded_sprite = extractor.load_sprite(pif_sprite)
|
||||
if !loaded_sprite
|
||||
loaded_sprite = handle_unloaded_sprites(extractor,pif_sprite)
|
||||
end
|
||||
return loaded_sprite
|
||||
end
|
||||
|
||||
def handle_unloaded_sprites(extractor,pif_sprite)
|
||||
if(extractor.is_a?(CustomSpriteExtracter)) #Custom failed to load, load an autogen (which should always be there)
|
||||
new_extractor = get_sprite_extractor_instance(:AUTOGEN)
|
||||
return new_extractor.load_sprite(pif_sprite)
|
||||
else
|
||||
#If autogen or base sprite aren't able to load a sprite then we have nothing else to load -> show a ? instead.
|
||||
return AnimatedBitmap.new(Settings::DEFAULT_SPRITE_PATH)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#Always loaded from local individual sprites
|
||||
def load_triple_fusion_sprite(dex_number)
|
||||
sprite_path = getSpecialSpriteName(dex_number)
|
||||
return AnimatedBitmap.new(sprite_path)
|
||||
end
|
||||
|
||||
def get_sprite_extractor_instance(type)
|
||||
case type
|
||||
when :AUTOGEN
|
||||
return AutogenExtracter.instance
|
||||
when :CUSTOM
|
||||
return CustomSpriteExtracter.instance
|
||||
when :BASE
|
||||
return BaseSpriteExtracter.instance
|
||||
else
|
||||
raise ArgumentError, "Unknown sprite type: #{type}"
|
||||
end
|
||||
end
|
||||
|
||||
def check_for_local_sprite(pif_sprite)
|
||||
if pif_sprite.type == :BASE
|
||||
sprite_path = "#{Settings::CUSTOM_BASE_SPRITES_FOLDER}#{pif_sprite.head_id}#{pif_sprite.alt_letter}.png"
|
||||
else
|
||||
sprite_path = "#{Settings::CUSTOM_BATTLERS_FOLDER_INDEXED}#{pif_sprite.head_id}/#{pif_sprite.head_id}.#{pif_sprite.body_id}#{pif_sprite.alt_letter}.png"
|
||||
end
|
||||
return pbResolveBitmap(sprite_path)
|
||||
end
|
||||
|
||||
def get_pif_sprite_from_species(species)
|
||||
species = GameData::Species.get(species)
|
||||
head_id = species.get_head_species
|
||||
body_id = species.get_body_species
|
||||
|
||||
substitution_id = get_sprite_substitution_id_for_fusion(head_id, body_id)
|
||||
pif_sprite = $PokemonGlobal.alt_sprite_substitutions[substitution_id] if $PokemonGlobal
|
||||
return pif_sprite if pif_sprite
|
||||
if species.id_number <= NB_POKEMON #base pokemon
|
||||
return select_new_pif_base_sprite(head_id)
|
||||
else #isFusion
|
||||
return select_new_pif_fusion_sprite(head_id, body_id)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Flow:
|
||||
# # if none found, look for custom sprite in custom spritesheet (download if can't find spritesheet or new spritepack released)
|
||||
# if none found, load from autogen spritesheet
|
||||
|
||||
def select_new_pif_fusion_sprite(head_id, body_id)
|
||||
species_symbol = "B#{body_id}H#{head_id}".to_sym
|
||||
spritename = get_fusion_spritename(head_id,body_id)
|
||||
customSpritesList = $game_temp.custom_sprites_list[species_symbol]
|
||||
alt_letter = ""
|
||||
if customSpritesList
|
||||
alt_letter = get_random_alt_letter_for_custom(head_id,body_id,true)
|
||||
type = :CUSTOM
|
||||
type = :AUTOGEN if !alt_letter
|
||||
else
|
||||
type = :AUTOGEN
|
||||
end
|
||||
if $PokemonTemp.forced_alt_sprites && $PokemonTemp.forced_alt_sprites.include?(spritename)
|
||||
alt_letter = $PokemonTemp.forced_alt_sprites[spritename]
|
||||
end
|
||||
return PIFSprite.new(type, head_id, body_id, alt_letter)
|
||||
end
|
||||
|
||||
def select_new_pif_base_sprite(dex_number)
|
||||
random_alt = get_random_alt_letter_for_unfused(dex_number, true) #nil if no main
|
||||
random_alt = "" if !random_alt
|
||||
return PIFSprite.new(:BASE, dex_number, nil, random_alt)
|
||||
end
|
||||
|
||||
def getSpecialSpriteName(dexNum)
|
||||
base_path = "Graphics/Battlers/special/"
|
||||
case dexNum
|
||||
when Settings::ZAPMOLCUNO_NB
|
||||
return sprintf(base_path + "144.145.146")
|
||||
when Settings::ZAPMOLCUNO_NB + 1
|
||||
return sprintf(base_path + "144.145.146")
|
||||
when Settings::ZAPMOLCUNO_NB + 2
|
||||
return sprintf(base_path + "243.244.245")
|
||||
when Settings::ZAPMOLCUNO_NB + 3
|
||||
return sprintf(base_path +"340.341.342")
|
||||
when Settings::ZAPMOLCUNO_NB + 4
|
||||
return sprintf(base_path +"343.344.345")
|
||||
when Settings::ZAPMOLCUNO_NB + 5
|
||||
return sprintf(base_path +"349.350.351")
|
||||
when Settings::ZAPMOLCUNO_NB + 6
|
||||
return sprintf(base_path +"151.251.381")
|
||||
when Settings::ZAPMOLCUNO_NB + 11
|
||||
return sprintf(base_path +"150.348.380")
|
||||
#starters
|
||||
when Settings::ZAPMOLCUNO_NB + 7
|
||||
return sprintf(base_path +"3.6.9")
|
||||
when Settings::ZAPMOLCUNO_NB + 8
|
||||
return sprintf(base_path +"154.157.160")
|
||||
when Settings::ZAPMOLCUNO_NB + 9
|
||||
return sprintf(base_path +"278.281.284")
|
||||
when Settings::ZAPMOLCUNO_NB + 10
|
||||
return sprintf(base_path +"318.321.324")
|
||||
#starters prevos
|
||||
when Settings::ZAPMOLCUNO_NB + 12
|
||||
return sprintf(base_path +"1.4.7")
|
||||
when Settings::ZAPMOLCUNO_NB + 13
|
||||
return sprintf(base_path +"2.5.8")
|
||||
when Settings::ZAPMOLCUNO_NB + 14
|
||||
return sprintf(base_path +"152.155.158")
|
||||
when Settings::ZAPMOLCUNO_NB + 15
|
||||
return sprintf(base_path +"153.156.159")
|
||||
when Settings::ZAPMOLCUNO_NB + 16
|
||||
return sprintf(base_path +"276.279.282")
|
||||
when Settings::ZAPMOLCUNO_NB + 17
|
||||
return sprintf(base_path +"277.280.283")
|
||||
when Settings::ZAPMOLCUNO_NB + 18
|
||||
return sprintf(base_path +"316.319.322")
|
||||
when Settings::ZAPMOLCUNO_NB + 19
|
||||
return sprintf(base_path +"317.320.323")
|
||||
when Settings::ZAPMOLCUNO_NB + 20 #birdBoss Left
|
||||
return sprintf(base_path +"invisible")
|
||||
when Settings::ZAPMOLCUNO_NB + 21 #birdBoss middle
|
||||
return sprintf(base_path + "144.145.146")
|
||||
when Settings::ZAPMOLCUNO_NB + 22 #birdBoss right
|
||||
return sprintf(base_path +"invisible")
|
||||
when Settings::ZAPMOLCUNO_NB + 23 #sinnohboss left
|
||||
return sprintf(base_path +"invisible")
|
||||
when Settings::ZAPMOLCUNO_NB + 24 #sinnohboss middle
|
||||
return sprintf(base_path +"343.344.345")
|
||||
when Settings::ZAPMOLCUNO_NB + 25 #sinnohboss right
|
||||
return sprintf(base_path +"invisible")
|
||||
when Settings::ZAPMOLCUNO_NB + 25 #cardboard
|
||||
return sprintf(base_path +"invisible")
|
||||
when Settings::ZAPMOLCUNO_NB + 26 #cardboard
|
||||
return sprintf(base_path + "cardboard")
|
||||
when Settings::ZAPMOLCUNO_NB + 27 #Triple regi
|
||||
return sprintf(base_path + "447.448.449")
|
||||
#Triple Kalos 1
|
||||
when Settings::ZAPMOLCUNO_NB + 28
|
||||
return sprintf(base_path + "479.482.485")
|
||||
when Settings::ZAPMOLCUNO_NB + 29
|
||||
return sprintf(base_path + "480.483.486")
|
||||
when Settings::ZAPMOLCUNO_NB + 30
|
||||
return sprintf(base_path + "481.484.487")
|
||||
else
|
||||
return sprintf(base_path + "000")
|
||||
end
|
||||
end
|
||||
end
|
||||
102
Data/Scripts/048_Fusion/Sprites/CustomSpriteExtracter.rb
Normal file
102
Data/Scripts/048_Fusion/Sprites/CustomSpriteExtracter.rb
Normal file
@@ -0,0 +1,102 @@
|
||||
class CustomSpriteExtracter < PIFSpriteExtracter
|
||||
@instance = new
|
||||
def self.instance
|
||||
@@instance ||= new # If @@instance is nil, create a new instance
|
||||
@@instance # Return the existing or new instance
|
||||
end
|
||||
|
||||
SPRITESHEET_FOLDER_PATH = "Graphics/CustomBattlers/spritesheets/spritesheets_custom/"
|
||||
SPRITE_SIZE = 288 # Original sprite size
|
||||
SCALED_SIZE = 288 # Scaled sprite size
|
||||
SHEET_WIDTH = SPRITE_SIZE * COLUMNS # 2880 pixels wide spritesheet
|
||||
|
||||
def load_bitmap_from_spritesheet(pif_sprite)
|
||||
body_id = pif_sprite.body_id
|
||||
spritesheet_file = getSpritesheetPath(pif_sprite)
|
||||
spritesheet_bitmap = AnimatedBitmap.new(spritesheet_file).bitmap
|
||||
|
||||
sprite_x_position,sprite_y_position =get_sprite_position_on_spritesheet(body_id,SPRITE_SIZE,COLUMNS)
|
||||
src_rect = Rect.new(sprite_x_position, sprite_y_position, SPRITE_SIZE, SPRITE_SIZE)
|
||||
|
||||
sprite_bitmap = Bitmap.new(SPRITE_SIZE, SPRITE_SIZE)
|
||||
sprite_bitmap.blt(0, 0, spritesheet_bitmap, src_rect)
|
||||
spritesheet_bitmap.dispose # Dispose since not needed
|
||||
|
||||
return sprite_bitmap
|
||||
end
|
||||
|
||||
def load_sprite_to_file(pif_sprite)
|
||||
head_id = pif_sprite.head_id
|
||||
body_id = pif_sprite.body_id
|
||||
alt_letter = pif_sprite.alt_letter
|
||||
base_folder = "#{Settings::CUSTOM_BATTLERS_FOLDER_INDEXED}#{head_id}/"
|
||||
|
||||
individualSpriteFile = "#{base_folder}#{head_id}.#{body_id}#{alt_letter}.png"
|
||||
if !pbResolveBitmap(individualSpriteFile)
|
||||
animatedBitmap = load_sprite_from_spritesheet(pif_sprite)
|
||||
Dir.mkdir(base_folder) unless Dir.exist?(base_folder)
|
||||
animatedBitmap.bitmap.save_to_png(individualSpriteFile)
|
||||
end
|
||||
return AnimatedBitmap.new(individualSpriteFile)
|
||||
end
|
||||
|
||||
def getSpritesheetPath(pif_sprite)
|
||||
alt_letter = pif_sprite.alt_letter
|
||||
head_id = pif_sprite.head_id
|
||||
return "#{SPRITESHEET_FOLDER_PATH}#{head_id}/#{head_id}#{alt_letter}.png"
|
||||
end
|
||||
|
||||
def should_update_spritesheet?(pif_sprite)
|
||||
return false if !$updated_spritesheets
|
||||
return false if !downloadAllowed?()
|
||||
return false if requestRateExceeded?(Settings::CUSTOMSPRITES_RATE_LOG_FILE,Settings::CUSTOMSPRITES_ENTRIES_RATE_TIME_WINDOW,Settings::CUSTOMSPRITES_RATE_MAX_NB_REQUESTS,false)
|
||||
spritesheet_file = getSpritesheetPath(pif_sprite)
|
||||
return true if !pbResolveBitmap(spritesheet_file)
|
||||
return !$updated_spritesheets.include?(spritesheet_file)
|
||||
end
|
||||
|
||||
|
||||
def load_sprite_directly(head_id,body_id,alt_letter="")
|
||||
load_sprite(PIFSprite.new(:CUSTOM,head_id,body_id,alt_letter))
|
||||
end
|
||||
|
||||
#
|
||||
# def extract_bitmap_to_file(head_id, body_id, alt_letter, folder)
|
||||
# # Create the directory if it doesn't exist
|
||||
# Dir.mkdir(folder) unless Dir.exist?(folder)
|
||||
#
|
||||
# # Load the entire spritesheet
|
||||
# spritesheet_file = "#{SPRITESHEET_FOLDER_PATH}#{head_id}\\#{head_id}#{alt_letter}.png"
|
||||
# spritesheet_bitmap = AnimatedBitmap.new(spritesheet_file).bitmap
|
||||
#
|
||||
# # Calculate the 0-based row and column from the sprite index
|
||||
# index = body_id
|
||||
# row = index / COLUMNS
|
||||
# col = index % COLUMNS
|
||||
#
|
||||
# # Define the area of the sprite on the spritesheet
|
||||
# sprite_x_position = col * SPRITE_SIZE
|
||||
# sprite_y_position = row * SPRITE_SIZE
|
||||
#
|
||||
# # Create a new bitmap for the sprite at its original size
|
||||
# sprite_bitmap = Bitmap.new(SPRITE_SIZE, SPRITE_SIZE)
|
||||
#
|
||||
# # Copy the sprite from the spritesheet to the new bitmap
|
||||
# src_rect = Rect.new(sprite_x_position, sprite_y_position, SPRITE_SIZE, SPRITE_SIZE)
|
||||
# sprite_bitmap.blt(0, 0, spritesheet_bitmap, src_rect)
|
||||
#
|
||||
# # Dispose of the spritesheet bitmap if it’s no longer needed
|
||||
# spritesheet_bitmap.dispose
|
||||
#
|
||||
# # Save the sprite bitmap to a file
|
||||
# file_path = "#{folder}/#{head_id}.#{body_id}.png"
|
||||
# sprite_bitmap.save_to_png(file_path)
|
||||
#
|
||||
# # Dispose of the sprite bitmap
|
||||
# sprite_bitmap.dispose
|
||||
#
|
||||
# # Return the path to the saved PNG file
|
||||
# return file_path
|
||||
# end
|
||||
|
||||
end
|
||||
78
Data/Scripts/048_Fusion/Sprites/PIFSprite.rb
Normal file
78
Data/Scripts/048_Fusion/Sprites/PIFSprite.rb
Normal file
@@ -0,0 +1,78 @@
|
||||
#object representing a sprite which saves its position in the tileset
|
||||
class PIFSprite
|
||||
attr_accessor :type
|
||||
attr_accessor :head_id
|
||||
attr_accessor :body_id
|
||||
attr_accessor :alt_letter
|
||||
|
||||
#types:
|
||||
# :AUTOGEN, :CUSTOM, :BASE
|
||||
def initialize(type, head_id, body_id, alt_letter="")
|
||||
@type = type
|
||||
@head_id = head_id
|
||||
@body_id = body_id
|
||||
@alt_letter = alt_letter
|
||||
end
|
||||
|
||||
|
||||
#little hack for old methods that expect a filename for a sprite
|
||||
def to_filename()
|
||||
case @type
|
||||
when :CUSTOM
|
||||
return "#{@head_id}.#{@body_id}#{@alt_letter}.png"
|
||||
when :AUTOGEN
|
||||
return "#{@head_id}.#{@body_id}.png"
|
||||
when :BASE
|
||||
return "#{@head_id}#{@alt_letter}.png"
|
||||
end
|
||||
end
|
||||
|
||||
def setup_from_spritename(spritename,type)
|
||||
@type = type
|
||||
cleaned_name = spritename.gsub(".png","")
|
||||
if cleaned_name =~ /(\d+)\.(\d+)([a-zA-Z]*)/
|
||||
head_id = $1
|
||||
body_id = $2
|
||||
alt_letter = $3
|
||||
end
|
||||
@head_id = head_id
|
||||
@body_id = body_id
|
||||
@alt_letter = alt_letter
|
||||
end
|
||||
|
||||
def self.from_spritename(spritename,type)
|
||||
obj = allocate
|
||||
obj.send(:setup_from_spritename, spritename,type)
|
||||
obj
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
def new_pif_sprite_from_dex_num(type, dexNum,alt_letter)
|
||||
body_id = getBodyID(dexNum)
|
||||
head_id = getHeadID(dexNum,body_id)
|
||||
return PIFSprite.new(type,head_id,body_id,alt_letter)
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pif_sprite_from_spritename(spritename, autogen = false)
|
||||
spritename = spritename.split(".png")[0] #remove the extension
|
||||
if spritename =~ /^(\d+)\.(\d+)([a-zA-Z]*)$/ # Two numbers with optional letters
|
||||
type = :CUSTOM
|
||||
head_id = $1.to_i # Head (e.g., "1" in "1.2.png")
|
||||
body_id = $2.to_i # Body (e.g., "2" in "1.2.png")
|
||||
alt_letter = $3 # Optional trailing letter (e.g., "a" in "1.2a.png")
|
||||
|
||||
elsif spritename =~ /^(\d+)([a-zA-Z]*)$/ # One number with optional letters
|
||||
type = :BASE
|
||||
head_id = $1.to_i # Head (e.g., "1" in "1.png")
|
||||
alt_letter = $2 # Optional trailing letter (e.g., "a" in "1a.png")
|
||||
else
|
||||
echoln "Invalid sprite format: #{spritename}"
|
||||
return nil
|
||||
end
|
||||
type = :AUTOGEN if autogen
|
||||
return PIFSprite.new(type,head_id,body_id,alt_letter)
|
||||
end
|
||||
89
Data/Scripts/048_Fusion/Sprites/SpritesSubstitutions.rb
Normal file
89
Data/Scripts/048_Fusion/Sprites/SpritesSubstitutions.rb
Normal file
@@ -0,0 +1,89 @@
|
||||
def setSpriteSubstitution(pif_sprite)
|
||||
|
||||
end
|
||||
|
||||
def getSpriteSubstitutionForDex(dex_num)
|
||||
|
||||
end
|
||||
|
||||
|
||||
def setSpriteSubstitution(head,body)
|
||||
|
||||
end
|
||||
|
||||
def set_updated_spritesheets
|
||||
echoln
|
||||
end
|
||||
|
||||
def initialize_alt_sprite_substitutions()
|
||||
$PokemonGlobal.alt_sprite_substitutions = {} if !$PokemonGlobal.alt_sprite_substitutions
|
||||
migrate_sprites_substitutions()
|
||||
end
|
||||
|
||||
def get_sprite_substitution_id_for_fusion(head_id, body_id)
|
||||
species_symbol = "B#{body_id}H#{head_id}".to_sym
|
||||
return get_sprite_substitution_id_from_dex_number(species_symbol)
|
||||
end
|
||||
|
||||
def get_sprite_substitution_id_from_dex_number(species_symbol)
|
||||
species = GameData::Species.get(species_symbol)
|
||||
if species.is_fusion
|
||||
substitution_id = [species.get_head_species,species.get_body_species]
|
||||
else
|
||||
substitution_id= species.id_number
|
||||
end
|
||||
return substitution_id
|
||||
end
|
||||
|
||||
def migrate_sprites_substitutions
|
||||
return if $game_switches[SWITCH_UPDATED_TO_SPRITESHEETS_SPRITES]
|
||||
new_substitutions = {}
|
||||
old_number_pokemon = 470
|
||||
for dex_number_key in $PokemonGlobal.alt_sprite_substitutions.keys
|
||||
if $PokemonGlobal.alt_sprite_substitutions[dex_number_key].is_a?(String) && can_convert_to_int?(dex_number_key)
|
||||
old_dex_number = dex_number_key.to_i
|
||||
if old_dex_number > old_number_pokemon #fusion
|
||||
body_id = getBodyID(old_dex_number,old_number_pokemon)
|
||||
head_id = getHeadID(old_dex_number,body_id,old_number_pokemon)
|
||||
new_id = [head_id,body_id]
|
||||
type = :CUSTOM
|
||||
else
|
||||
new_id = old_dex_number
|
||||
head_id = old_dex_number
|
||||
body_id= nil
|
||||
type = :BASE
|
||||
end
|
||||
file_path = $PokemonGlobal.alt_sprite_substitutions[dex_number_key]
|
||||
alt_letter =get_alt_letter_from_path(file_path)
|
||||
|
||||
pif_sprite = PIFSprite.new(type,head_id,body_id,alt_letter)
|
||||
new_substitutions[new_id] = pif_sprite
|
||||
end
|
||||
end
|
||||
$PokemonGlobal.alt_sprite_substitutions = new_substitutions
|
||||
$game_switches[SWITCH_UPDATED_TO_SPRITESHEETS_SPRITES] = true
|
||||
end
|
||||
|
||||
def can_convert_to_int?(str)
|
||||
Integer(str)
|
||||
true
|
||||
rescue ArgumentError
|
||||
false
|
||||
end
|
||||
|
||||
def get_alt_letter_from_path(filename)
|
||||
# Remove the extension
|
||||
base_name = filename.sub(/\.png$/, '')
|
||||
|
||||
# Check the last character
|
||||
last_char = base_name[-1]
|
||||
|
||||
if last_char.match?(/\d/) # Check if the last character is a number
|
||||
alt_letter = ""
|
||||
else
|
||||
# Reverse the base name and capture all letters until the first number
|
||||
alt_letter = base_name.reverse[/[a-zA-Z]+/].reverse
|
||||
end
|
||||
|
||||
return alt_letter
|
||||
end
|
||||
Reference in New Issue
Block a user