eg
BIN
Data/Map028.rxdata
Normal file
BIN
Data/Map029.rxdata
Normal file
BIN
Data/Map030.rxdata
Normal file
BIN
Data/Map031.rxdata
Normal file
BIN
Data/Map032.rxdata
Normal file
BIN
Data/Map033.rxdata
Normal file
BIN
Data/Map034.rxdata
Normal file
BIN
Data/Map035.rxdata
Normal file
BIN
Data/Map036.rxdata
Normal file
BIN
Data/Map037.rxdata
Normal file
BIN
Data/Map038.rxdata
Normal file
BIN
Data/Map039.rxdata
Normal file
BIN
Graphics/Autotiles/HoennSand shore1.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
Graphics/Autotiles/Sand Water Edge-test.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
Graphics/Characters/Hoenn Object Fountain.png
Normal file
|
After Width: | Height: | Size: 978 B |
BIN
Graphics/Characters/HoennObjectTree.png
Normal file
|
After Width: | Height: | Size: 923 B |
BIN
Graphics/Characters/MSteps/stepsDown.png
Normal file
|
After Width: | Height: | Size: 239 B |
BIN
Graphics/Characters/MSteps/stepsDownBike.png
Normal file
|
After Width: | Height: | Size: 208 B |
BIN
Graphics/Characters/MSteps/stepsLeft.png
Normal file
|
After Width: | Height: | Size: 226 B |
BIN
Graphics/Characters/MSteps/stepsLeftBike.png
Normal file
|
After Width: | Height: | Size: 196 B |
BIN
Graphics/Characters/MSteps/stepsRight.png
Normal file
|
After Width: | Height: | Size: 228 B |
BIN
Graphics/Characters/MSteps/stepsRightBike.png
Normal file
|
After Width: | Height: | Size: 196 B |
BIN
Graphics/Characters/MSteps/stepsUp.png
Normal file
|
After Width: | Height: | Size: 237 B |
BIN
Graphics/Characters/MSteps/stepsUpBike.png
Normal file
|
After Width: | Height: | Size: 208 B |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 490 KiB After Width: | Height: | Size: 494 KiB |
@@ -1,29 +1,47 @@
|
||||
# See the documentation on the wiki to learn how to edit this file.
|
||||
#-------------------------------
|
||||
# Route 101 (6) - Route 104 (33)
|
||||
6,North,0,33,South,112
|
||||
# Rt101-102Tree (14) - Route 104 (33)
|
||||
14,North,0,33,South,70
|
||||
# Petalburg City (15) - Route 104 (33)
|
||||
15,West,0,33,East,50
|
||||
# Rt101-102Tree3 (17) - Route 104 (33)
|
||||
17,West,0,33,East,80
|
||||
# Rt101-102Tree4 (18) - Route 104 (33)
|
||||
18,West,0,33,East,34
|
||||
# Rustboro City (37) - Route 104 (33)
|
||||
37,South,0,33,North,0
|
||||
# Littleroot Town (2) - Route 101 (6)
|
||||
2,North,0,6,South,0
|
||||
# Rt101-102Tree (14) - Littleroot Town (2)
|
||||
14,East,20,2,West,0
|
||||
# Rt101-102Tree2 (16) - Littleroot Town (2)
|
||||
16,East,60,2,West,0
|
||||
# Route 101 (6) - Route 102 (12)
|
||||
6,North,0,12,South,42
|
||||
# Rt101-102Tree (14) - Route 101 (6)
|
||||
14,East,0,6,West,0
|
||||
# Oldale Town (7) - Route 101 (6)
|
||||
7,South,0,6,North,8
|
||||
# Route 102 (12) - Route 101 (6)
|
||||
12,South,42,6,North,0
|
||||
# Petalburg City (15) - Route 101 (6)
|
||||
15,South,72,6,North,0
|
||||
# Rt101-102Tree2 (16) - Route 101 (6)
|
||||
16,East,40,6,West,0
|
||||
# Oldale Town (7) - Route 102 (12)
|
||||
7,West,0,12,East,5
|
||||
# Rt101-102Tree (14) - Littleroot Town (2)
|
||||
14,East,20,2,West,0
|
||||
# Rt101-102Tree2 (16) - Littleroot Town (2)
|
||||
16,East,60,2,West,0
|
||||
# Oldale Town (7) - Rt101-102Tree (14)
|
||||
7,South,0,14,North,50
|
||||
# Route 102 (12) - Rt101-102Tree (14)
|
||||
12,South,0,14,North,0
|
||||
# Petalburg City (15) - Rt101-102Tree (14)
|
||||
15,East,30,14,West,0
|
||||
# Rt101-102Tree3 (17) - Rt101-102Tree (14)
|
||||
17,East,0,14,West,0
|
||||
# Rt101-102Tree4 (18) - Rt101-102Tree (14)
|
||||
18,East,46,14,West,0
|
||||
# Route 102 (12) - Oldale Town (7)
|
||||
12,East,5,7,West,0
|
||||
# Rt101-102Tree3 (17) - Oldale Town (7)
|
||||
17,North,80,7,South,0
|
||||
# Rt101-102Tree (14) - Route 102 (12)
|
||||
14,North,0,12,South,0
|
||||
# Petalburg City (15) - Route 102 (12)
|
||||
15,East,5,12,West,0
|
||||
# Rt101-102Tree3 (17) - Route 102 (12)
|
||||
@@ -32,21 +50,21 @@
|
||||
16,South,0,12,North,0
|
||||
# Rt101-102Tree4 (18) - Route 102 (12)
|
||||
18,East,21,12,West,0
|
||||
# Route 102 (12) - Rt101-102Tree5 (19)
|
||||
12,0,70,19,19,0
|
||||
# Petalburg City (15) - Rt101-102Tree (14)
|
||||
15,East,30,14,West,0
|
||||
# Rt101-102Tree3 (17) - Rt101-102Tree (14)
|
||||
17,East,0,14,West,0
|
||||
# Rt101-102Tree4 (18) - Rt101-102Tree (14)
|
||||
18,East,46,14,West,0
|
||||
# Rt101-102Tree3 (17) - Petalburg City (15)
|
||||
17,North,0,15,South,0
|
||||
# Rt101-102Tree2 (16) - Petalburg City (15)
|
||||
16,West,10,15,East,0
|
||||
# Rt101-102Tree4 (18) - Petalburg City (15)
|
||||
18,South,0,15,North,0
|
||||
# Rustboro City (37) - Petalburg City (15)
|
||||
37,East,110,15,West,0
|
||||
# Rt101-102Tree2 (16) - Rt101-102Tree3 (17)
|
||||
16,West,40,17,East,0
|
||||
# Rustboro City (37) - Rt101-102Tree3 (17)
|
||||
37,East,140,17,West,0
|
||||
# Rt101-102Tree4 (18) - Rt101-102Tree2 (16)
|
||||
18,East,6,16,West,0
|
||||
# Rustboro City (37) - Rt101-102Tree4 (18)
|
||||
37,East,94,18,West,0
|
||||
# Route 104 (33) - Rt101-102Tree5 (19)
|
||||
33,51,125,19,0,0
|
||||
|
||||
@@ -64,4 +64,13 @@ HealingSpot = 15,20,16
|
||||
MapPosition = 2,2,11
|
||||
#-------------------------------
|
||||
[020] # Petalburg Poké Center
|
||||
Name = Petalburg Poké Center
|
||||
MapPosition = 2,2,11
|
||||
#-------------------------------
|
||||
[037] # Rustboro City
|
||||
Name = Rustboro City
|
||||
Outdoor = true
|
||||
ShowArea = true
|
||||
Bicycle = true
|
||||
HealingSpot = 37,16,38
|
||||
MapPosition = 2,1,8
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
[RAPTORCH]
|
||||
Name = Raptorch
|
||||
Types = FIRE,GROUND
|
||||
BaseStats = 40,55,45,65,50,70
|
||||
GenderRatio = FemaleOneEighth
|
||||
GrowthRate = Medium
|
||||
BaseExp = 65
|
||||
EVs = SPEED,1
|
||||
CatchRate = 45
|
||||
Happiness = 70
|
||||
Abilities = FLAMEBODY
|
||||
HiddenAbilities = BLAZE
|
||||
Moves = 1,SCRATCH,1,GROWL,5,EMBER,13,MUDSLAP,19,FLAMEWHEEL
|
||||
# TutorMoves =
|
||||
# EggMoves =
|
||||
EggGroups = Monster,Dragon
|
||||
HatchSteps = 5120
|
||||
Height = 0.8
|
||||
Weight = 10.5
|
||||
Color = Black
|
||||
Shape = Bipedal
|
||||
Habitat = Rare
|
||||
# Category =
|
||||
Pokedex = Raptorch are energetic Pokémon that require constant attention, or they will start setting their surroundings on fire.
|
||||
# Evolutions = IVYSAUR,Level,16
|
||||
[RAPTORCH]
|
||||
Name = Raptorch
|
||||
Types = FIRE,GROUND
|
||||
BaseStats = 40,55,45,65,50,70
|
||||
GenderRatio = FemaleOneEighth
|
||||
GrowthRate = Medium
|
||||
BaseExp = 65
|
||||
EVs = SPEED,1
|
||||
CatchRate = 45
|
||||
Happiness = 70
|
||||
Abilities = FLAMEBODY
|
||||
HiddenAbilities = BLAZE
|
||||
Moves = 1,SCRATCH,1,GROWL,5,EMBER,13,MUDSLAP,19,FLAMEWHEEL
|
||||
# TutorMoves =
|
||||
# EggMoves =
|
||||
EggGroups = Monster,Dragon
|
||||
HatchSteps = 5120
|
||||
Height = 0.8
|
||||
Weight = 10.5
|
||||
Color = Black
|
||||
Shape = Bipedal
|
||||
Habitat = Rare
|
||||
# Category =
|
||||
Pokedex = Raptorch are energetic Pokémon that require constant attention, or they will start setting their surroundings on fire.
|
||||
# Evolutions = IVYSAUR,Level,16
|
||||
|
||||
@@ -44,3 +44,9 @@ Point = 5,11,Oldale Town,,7,6,17,
|
||||
Point = 4,11,Route 102,,,,,
|
||||
Point = 3,11,Route 102,,,,,
|
||||
Point = 2,11,Petalburg City,Petalburg Gym,15,20,17,
|
||||
Point = 1,11,Route 104,,,,,
|
||||
Point = 1,10,Route 104,,,,,
|
||||
Point = 1,9,Route 104,,,,,
|
||||
Point = 1,8,Rustboro City,Rustboro Gym,37,16,39,
|
||||
Point = 1,7,Rustboro City,Rustboro Gym,37,16,39,
|
||||
|
||||
|
||||
181
Plugins/Marin's Footprints/MFootprints.rb
Normal file
@@ -0,0 +1,181 @@
|
||||
#==============================================================================#
|
||||
# Footprints #
|
||||
# by Marin #
|
||||
#==============================================================================#
|
||||
# If an event walks on a tile with terrain tag 3 (Sand), it will produce #
|
||||
# visual footprints. Works with Following Pokémon. #
|
||||
#==============================================================================#
|
||||
# Please give credit when using this. #
|
||||
#==============================================================================#
|
||||
|
||||
class Sprite_Character
|
||||
# This is the amount the opacity is lowered per frame. It needs to go 256 -> 0,
|
||||
# which means setting this to 4 would make each step pair last 64 frames (~1.5s)
|
||||
FADE_OUT_SPEED = 2
|
||||
|
||||
# Set here the terrain tag for footprints, 3 is sand
|
||||
TERRAIN_FOOT = 3
|
||||
|
||||
# A configurable X/Y offset for the step sprites, in case they don't align
|
||||
# nicely with the player's graphic.
|
||||
WALK_X_OFFSET = 0
|
||||
WALK_Y_OFFSET = 0
|
||||
|
||||
# A configurable X/Y offset for bike print sprites, in case they don't align
|
||||
# nicely with the player's graphic.
|
||||
BIKE_X_OFFSET = -8
|
||||
BIKE_Y_OFFSET = 0
|
||||
|
||||
# If true, both the player AND the follower will create footprints.
|
||||
# If false, only the follower will create footprints.
|
||||
DUPLICATE_FOOTSTEPS_WITH_FOLLOWER = false
|
||||
|
||||
# If the event name includes any of these strings, it will not produce
|
||||
# footprints.
|
||||
EVENTNAME_MAY_NOT_INCLUDE = [
|
||||
"NoFootprint",
|
||||
".noprint",
|
||||
".nostep",
|
||||
".nofootprint",
|
||||
".nofootstep"
|
||||
]
|
||||
|
||||
# If the filename (graphic) includes any of these strings, it will not produce
|
||||
# footprints. Works on top of the event name list.
|
||||
FILENAME_MAY_NOT_INCLUDE = [
|
||||
|
||||
]
|
||||
|
||||
attr_accessor :steps
|
||||
attr_reader :follower
|
||||
|
||||
alias footsteps_initialize initialize
|
||||
def initialize(*args)
|
||||
footsteps_initialize(*args)
|
||||
if $PokemonGlobal && $PokemonGlobal.respond_to?(:dependentEvents) &&
|
||||
$PokemonGlobal.dependentEvents && $PokemonGlobal.dependentEvents.respond_to?(:realEvents) &&
|
||||
$PokemonGlobal.dependentEvents.realEvents.is_a?(Array) &&
|
||||
$PokemonGlobal.dependentEvents.realEvents.include?(@character)
|
||||
@follower = true
|
||||
end
|
||||
@steps = []
|
||||
end
|
||||
|
||||
alias footsteps_dispose dispose
|
||||
def dispose
|
||||
@steps.each { |e| e[0].dispose }
|
||||
footsteps_dispose
|
||||
end
|
||||
|
||||
alias footsteps_update update
|
||||
def update
|
||||
footsteps_update
|
||||
@old_x ||= @character.x
|
||||
@old_y ||= @character.y
|
||||
if (@character.x != @old_x || @character.y != @old_y) && !["", "nil"].include?(@character.character_name)
|
||||
if @character == $game_player && $PokemonGlobal.dependentEvents &&
|
||||
$PokemonGlobal.dependentEvents.respond_to?(:realEvents) &&
|
||||
$PokemonGlobal.dependentEvents.realEvents.select { |e| !["", "nil"].include?(e.character_name) }.size > 0 &&
|
||||
!DUPLICATE_FOOTSTEPS_WITH_FOLLOWER
|
||||
if !EVENTNAME_MAY_NOT_INCLUDE.include?($PokemonGlobal.dependentEvents.realEvents[0].name) &&
|
||||
!FILENAME_MAY_NOT_INCLUDE.include?($PokemonGlobal.dependentEvents.realEvents[0].character_name)
|
||||
make_steps = false
|
||||
else
|
||||
make_steps = true
|
||||
end
|
||||
elsif (!@character.respond_to?(:name) || !EVENTNAME_MAY_NOT_INCLUDE.include?(@character.name)) &&
|
||||
!FILENAME_MAY_NOT_INCLUDE.include?(@character.character_name)
|
||||
tilesetid = @character.map.instance_eval { @map.tileset_id }
|
||||
make_steps = [2,1,0].any? do |e|
|
||||
tile_id = @character.map.data[@old_x, @old_y, e]
|
||||
next false if tile_id.nil?
|
||||
next $data_tilesets[tilesetid].terrain_tags[tile_id] == TERRAIN_FOOT
|
||||
end
|
||||
end
|
||||
if make_steps
|
||||
fstep = Sprite.new(self.viewport)
|
||||
fstep.z = 0
|
||||
dirs = [nil,"DownLeft","Down","DownRight","Left","Still","Right","UpLeft",
|
||||
"Up", "UpRight"]
|
||||
if @character == $game_player && $PokemonGlobal.bicycle
|
||||
fstep.bmp("Graphics/Characters/MSteps/steps#{dirs[@character.direction]}Bike")
|
||||
else
|
||||
fstep.bmp("Graphics/Characters/MSteps/steps#{dirs[@character.direction]}")
|
||||
end
|
||||
@steps ||= []
|
||||
if @character == $game_player && $PokemonGlobal.bicycle
|
||||
x = BIKE_X_OFFSET
|
||||
y = BIKE_Y_OFFSET
|
||||
else
|
||||
x = WALK_X_OFFSET
|
||||
y = WALK_Y_OFFSET
|
||||
end
|
||||
@steps << [fstep, @character.map, @old_x + x / Game_Map::TILE_WIDTH.to_f, @old_y + y / Game_Map::TILE_HEIGHT.to_f]
|
||||
end
|
||||
end
|
||||
@old_x = @character.x
|
||||
@old_y = @character.y
|
||||
update_footsteps
|
||||
end
|
||||
|
||||
def update_footsteps
|
||||
if @steps
|
||||
for i in 0...@steps.size
|
||||
next unless @steps[i]
|
||||
sprite, map, x, y, ox = @steps[i]
|
||||
sprite.x = -map.display_x / Game_Map::X_SUBPIXELS + x * Game_Map::TILE_WIDTH
|
||||
sprite.y = -map.display_y / Game_Map::Y_SUBPIXELS + (y + 1) * Game_Map::TILE_HEIGHT
|
||||
sprite.y -= Game_Map::TILE_HEIGHT
|
||||
sprite.opacity -= FADE_OUT_SPEED
|
||||
if sprite.opacity <= 0
|
||||
sprite.dispose
|
||||
@steps[i] = nil
|
||||
end
|
||||
end
|
||||
@steps.compact!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class DependentEventSprites
|
||||
attr_accessor :sprites
|
||||
|
||||
def refresh
|
||||
steps = []
|
||||
for sprite in @sprites
|
||||
steps << sprite.steps
|
||||
if sprite.follower
|
||||
$FollowerSteps = sprite.steps
|
||||
end
|
||||
sprite.steps = []
|
||||
sprite.dispose
|
||||
end
|
||||
@sprites.clear
|
||||
$PokemonGlobal.dependentEvents.eachEvent do |event, data|
|
||||
if data[0] == @map.map_id # Check original map
|
||||
#@map.events[data[1]].erase
|
||||
end
|
||||
if data[2] == @map.map_id # Check current map
|
||||
spr = Sprite_Character.new(@viewport, event)
|
||||
if spr.follower
|
||||
spr.steps = $FollowerSteps
|
||||
$FollowerSteps = nil
|
||||
end
|
||||
@sprites.push(spr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Spriteset_Map
|
||||
alias footsteps_update update
|
||||
def update
|
||||
footsteps_update
|
||||
# Only update events that are on-screen
|
||||
for sprite in @character_sprites
|
||||
if sprite.character.is_a?(Game_Event)
|
||||
sprite.update_footsteps
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
5
Plugins/Marin's Footprints/meta.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Name = Marin's Footprints
|
||||
Version = 2.0
|
||||
Essentials = 21.1
|
||||
Credits = Marin, Jony
|
||||
Link = https://reliccastle.com/resources/165/
|
||||
5
Plugins/Marin's Scripting Utilities/meta.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Name = Marin's Scripting Utilities
|
||||
Version = 2.0
|
||||
Essentials = 20
|
||||
Credits = Marin
|
||||
Link = https://reliccastle.com/resources/165/
|
||||
925
Plugins/Marin's Scripting Utilities/script.rb
Normal file
@@ -0,0 +1,925 @@
|
||||
class Object
|
||||
def get_variables
|
||||
return self.instance_variables.map { |v| [v,self.method(v.to_s.gsub(/@/, "").to_sym).call] }
|
||||
end
|
||||
|
||||
def set_variables(vars)
|
||||
vars.each do |v|
|
||||
self.method((v[0].to_s.gsub(/@/, "") + "=").to_sym).call(v[1])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# E.g. PokeBattle_Pokemon -> to_sym -> :PokeBattle_Pokemon
|
||||
class Class
|
||||
def to_sym
|
||||
return self.to_s.to_sym
|
||||
end
|
||||
end
|
||||
|
||||
class NilClass
|
||||
def empty?
|
||||
return true
|
||||
end
|
||||
|
||||
def numeric?
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
# Dir class extensions
|
||||
class Dir
|
||||
class << Dir
|
||||
alias marin_delete delete
|
||||
end
|
||||
|
||||
# Returns all files in the targeted path
|
||||
def self.get_files(path, recursive = true)
|
||||
return Dir.get_all(path, recursive).select { |path| File.file?(path) }
|
||||
end
|
||||
|
||||
# Returns all directories in the targeted path
|
||||
def self.get_dirs(path, recursive = true)
|
||||
return Dir.get_all(path, recursive).select { |path| File.directory?(path) }
|
||||
end
|
||||
|
||||
# Returns all files and directories in the targeted path
|
||||
def self.get_all(path, recursive = true)
|
||||
files = []
|
||||
Dir.foreach(path) do |f|
|
||||
next if f == "." || f == ".."
|
||||
if File.directory?(path + "/" + f) && recursive
|
||||
files.concat(Dir.get_files(path + "/" + f))
|
||||
end
|
||||
files << path + "/" + f
|
||||
end
|
||||
return files
|
||||
end
|
||||
end
|
||||
|
||||
class Numeric
|
||||
# Formats the number nicely (e.g. 1234567890 -> format() -> 1,234,567,890)
|
||||
def format(separator = ',')
|
||||
a = self.to_s.split('').reverse.breakup(3)
|
||||
return a.map { |e| e.join('') }.join(separator).reverse
|
||||
end
|
||||
|
||||
# Makes sure the returned string is at least n characters long
|
||||
# (e.g. 4 -> to_digits -> "004")
|
||||
# (e.g. 19 -> to_digits -> "019")
|
||||
# (e.g. 123 -> to_digits -> "123")
|
||||
def to_digits(n = 3)
|
||||
str = self.to_s
|
||||
return str if str.size >= n
|
||||
ret = ""
|
||||
(n - str.size).times { ret += "0" }
|
||||
return ret + str
|
||||
end
|
||||
|
||||
# n root of self. Defaults to 2 => square root.
|
||||
def root(n = 2)
|
||||
return (self ** (1.0 / n))
|
||||
end
|
||||
|
||||
# Factorial
|
||||
# 4 -> fact -> (4 * 3 * 2 * 1) -> 24
|
||||
def fact
|
||||
raise ArgumentError, "Cannot execute factorial on negative numerics" if self < 0
|
||||
tot = 1
|
||||
for i in 2..self
|
||||
tot *= i
|
||||
end
|
||||
return tot
|
||||
end
|
||||
|
||||
# Combinations
|
||||
def ncr(k)
|
||||
return (self.fact / (k.fact * (self - k).fact))
|
||||
end
|
||||
|
||||
# k permutations of n (self)
|
||||
def npr(k)
|
||||
return (self.fact / (self - k).fact)
|
||||
end
|
||||
|
||||
# Converts number to binary number (returns as string)
|
||||
def to_b
|
||||
return self.to_s(2)
|
||||
end
|
||||
|
||||
def empty?
|
||||
return false
|
||||
end
|
||||
|
||||
def numeric?
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
class NilClass
|
||||
def numeric?
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
# Calculates the total amount of elements in an Enumerable. Example:
|
||||
# ["one","two","three"].fullsize #=> 11
|
||||
module Enumerable
|
||||
def fullsize
|
||||
n = 0
|
||||
for e in self
|
||||
if e.is_a?(String)
|
||||
n += e.size
|
||||
elsif e.respond_to?(:fullsize)
|
||||
n += e.fullsize
|
||||
elsif e.respond_to?(:size) && !e.is_a?(Numeric)
|
||||
n += e.size
|
||||
else
|
||||
n += 1
|
||||
end
|
||||
end
|
||||
return n
|
||||
end
|
||||
end
|
||||
|
||||
class Array
|
||||
# Returns a random element of the array
|
||||
def random
|
||||
return self[Object.method(:rand).call(self.size)]
|
||||
end
|
||||
|
||||
# Returns whether or not the array is empty.
|
||||
def empty?
|
||||
return self.size == 0
|
||||
end
|
||||
|
||||
# Shuffles the order of the array
|
||||
def shuffle
|
||||
indexes = []
|
||||
new = []
|
||||
while new.size != self.size
|
||||
# Weird way of calling rand for compatibility
|
||||
# with Luka's scripting utilities
|
||||
i = Object.method(:rand).call(self.size)
|
||||
if !indexes.include?(i)
|
||||
indexes << i
|
||||
new << self[i]
|
||||
end
|
||||
end
|
||||
return new
|
||||
end
|
||||
|
||||
# Shuffles the order of the array and replaces itself
|
||||
def shuffle!
|
||||
self.replace(shuffle)
|
||||
end
|
||||
|
||||
# Breaks the array up every n elements
|
||||
def breakup(n)
|
||||
ret = []
|
||||
for i in 0...self.size
|
||||
ret[(i / n).floor] ||= []
|
||||
ret[(i / n).floor] << self[i]
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
# Breaks the array up every n elements and replaces itself
|
||||
def breakup!(n)
|
||||
self.replace(breakup(n))
|
||||
end
|
||||
|
||||
# Swaps two elements' indexes
|
||||
def swap(index1, index2)
|
||||
new = self.clone
|
||||
tmp = new[index2].clone
|
||||
new[index2] = new[index1]
|
||||
new[index1] = tmp
|
||||
return new
|
||||
end
|
||||
|
||||
# Swaps two elements' indexes and replaces itself
|
||||
def swap!(index1, index2)
|
||||
self.replace(swap(index1, index2))
|
||||
end
|
||||
|
||||
# Returns whether or not the first element is equal to the passed argument
|
||||
def starts_with?(e)
|
||||
return self.first == e
|
||||
end
|
||||
|
||||
# Returns whether or not the last element is equal to the passed argument
|
||||
def ends_with?(e)
|
||||
return self.last == e
|
||||
end
|
||||
|
||||
# Converts itself to a hash where possible
|
||||
def to_hash(delete_nil_entries = false)
|
||||
ret = {}
|
||||
for i in 0...self.size
|
||||
next if self[i].nil? && delete_nil_entries
|
||||
ret[i] = self[i]
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
# If you have 8 elements, if true, grabs the 5th element, the 4th if false.
|
||||
# If you have 7 elements, grabs the 4th.
|
||||
def mid(round_up = true)
|
||||
i = (self.size - 1) / 2.0
|
||||
i = i.ceil if round_up
|
||||
return self[i].floor
|
||||
end
|
||||
|
||||
# Returns the average of all elements in the array. Will throw errors on non-numerics.
|
||||
# Skips <nil> entries.
|
||||
def average
|
||||
total = 0
|
||||
self.each { |n| total += n unless n.nil? }
|
||||
return total / self.compact.size.to_f
|
||||
end
|
||||
|
||||
# Adds some aliases for <include?>: <has?>, <includes?>, <contains?>
|
||||
alias has? include?
|
||||
alias includes? include?
|
||||
alias contains? include?
|
||||
|
||||
# Evaluates the block you pass it for every number between 0 and "slots".
|
||||
# Example usage:
|
||||
# Array.make_table { |i| i ** 2 }
|
||||
# => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
|
||||
# Array.make_table(10..16) { |i| i.to_s(2) }
|
||||
# => ["1010", "1011", "1100", "1101", "1110", "1111", "10000"]
|
||||
# (you can also pass it an array of values to iterate over)
|
||||
def self.make_table(range = 1..10, &proc)
|
||||
return range.map { |n| next proc.call(n) }
|
||||
end
|
||||
|
||||
# If true:
|
||||
# [0, 1, 3, 4, 5] -- etc
|
||||
# If false:
|
||||
# [0,1,2,3,4,5] -- etc
|
||||
Json_Extra_Space_After_Entry = false
|
||||
|
||||
# Converts _self_ to a JSON string with an indent of Json_Indent_Width per layer.
|
||||
def to_json(indent = Hash::Json_Indent_Width, inline = false)
|
||||
return "[]" unless self.size > 0
|
||||
full = "["
|
||||
for i in 0...self.size
|
||||
nl = false
|
||||
if self[i].is_a?(Hash) || self[i].is_a?(Array)
|
||||
val = self[i].to_json(indent + Hash::Json_Indent_Width, i == 0)
|
||||
nl = !(inline && i == 0)
|
||||
else
|
||||
val = self[i]
|
||||
val = "\"#{val}\"" if val.is_a?(String)
|
||||
nl = (self.fullsize > 24 || self.map { |e| e.class.to_sym }.include?(:Hash))
|
||||
end
|
||||
full += "\n" + " " * indent if nl
|
||||
full += val.to_s + ","
|
||||
full += " " if Json_Extra_Space_After_Entry
|
||||
end
|
||||
i = 2 + Json_Extra_Space_After_Entry.to_i
|
||||
full = full[0..(-i)]
|
||||
full += "\n#{" " * (indent - Hash::Json_Indent_Width)}" if self.fullsize > 24 ||
|
||||
self.map { |e| e.class.to_sym }.include?(:Hash)
|
||||
full += "]"
|
||||
return full
|
||||
end
|
||||
end
|
||||
|
||||
class Hash
|
||||
# Converts itself to an array where possible
|
||||
def to_array(delete_nil_entries = false)
|
||||
ret = []
|
||||
keys = self.keys.sort
|
||||
for key in keys
|
||||
next if self[key].nil? && delete_nil_entries
|
||||
ret[key] = self[key]
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def compact
|
||||
new = {}
|
||||
for key in self.keys
|
||||
new[key] = self[key] unless self[key].nil?
|
||||
end
|
||||
return new
|
||||
end
|
||||
|
||||
def compact!
|
||||
self.replace(compact)
|
||||
end
|
||||
|
||||
# Amount of spaces per "layer" in the JSON.
|
||||
Json_Indent_Width = 4
|
||||
|
||||
# Converts _self_ to a JSON string with an indent of Json_Indent_Width per layer.
|
||||
def to_json(indent = Json_Indent_Width, _ = nil)
|
||||
return "{}" if self.size == 0
|
||||
full = "{"
|
||||
keys = self.keys.sort do |a,b|
|
||||
if $JSON_Sort_Order
|
||||
if $JSON_Sort_Order.include?(a)
|
||||
if $JSON_Sort_Order.include?(b)
|
||||
next $JSON_Sort_Order.index(a) <=> $JSON_Sort_Order.index(b)
|
||||
else
|
||||
next -1
|
||||
end
|
||||
else
|
||||
if $JSON_Sort_Order.include?(b)
|
||||
next 1
|
||||
end
|
||||
# If neither are in the key, go alphabetical
|
||||
end
|
||||
end
|
||||
if a.numeric?
|
||||
if b.numeric?
|
||||
next a <=> b
|
||||
else
|
||||
next -1
|
||||
end
|
||||
else
|
||||
if b.numeric?
|
||||
next 1
|
||||
else
|
||||
next a <=> b
|
||||
end
|
||||
end
|
||||
end
|
||||
for key in keys
|
||||
if self[key].is_a?(Hash) || self[key].is_a?(Array)
|
||||
val = self[key].to_json(indent + Json_Indent_Width, key == self.keys[0])
|
||||
else
|
||||
val = self[key]
|
||||
val = "\"#{val}\"" if val.is_a?(String)
|
||||
end
|
||||
full += "\n#{" " * indent}\"#{key}\": #{val},"
|
||||
end
|
||||
full = full[0..-2]
|
||||
full += "\n#{" " * (indent - Json_Indent_Width)}}"
|
||||
return full
|
||||
end
|
||||
end
|
||||
|
||||
# String class extensions
|
||||
class String
|
||||
# Converts to bits
|
||||
def to_b
|
||||
return self.unpack('b*')[0]
|
||||
end
|
||||
|
||||
# Converts to bits and replaces itself
|
||||
def to_b!
|
||||
self.replace(to_b)
|
||||
end
|
||||
|
||||
# Converts from bits
|
||||
def from_b
|
||||
return [self].pack('b*')
|
||||
end
|
||||
|
||||
# Convert from bits and replaces itself
|
||||
def from_b!
|
||||
self.replace(from_b)
|
||||
end
|
||||
|
||||
# Returns a random character from the string
|
||||
def random
|
||||
return self[rand(self.size)]
|
||||
end
|
||||
|
||||
# Shuffles the order of the characters
|
||||
def shuffle
|
||||
return self.split("").shuffle.join("")
|
||||
end
|
||||
|
||||
# Breaks the string up every _n_ characters
|
||||
def breakup(n)
|
||||
new = []
|
||||
for i in 0...self.size
|
||||
new[(i / n).floor] ||= ""
|
||||
new[(i / n).floor] += self[i]
|
||||
end
|
||||
return new
|
||||
end
|
||||
|
||||
def empty?
|
||||
return (self.size == 0)
|
||||
end
|
||||
|
||||
def numeric?
|
||||
i = 0
|
||||
for e in self.split("")
|
||||
next if i == 0 && e == "-"
|
||||
return false unless [0,1,2,3,4,5,6,7,8,9].map { |n| n.to_s }.include?(e)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# Deflates itself and returns the result
|
||||
def deflate
|
||||
return Zlib::Deflate.deflate(self)
|
||||
end
|
||||
|
||||
# Deflates and replaces itself
|
||||
def deflate!
|
||||
self.replace(deflate)
|
||||
end
|
||||
|
||||
# Inflates itself and returns the result
|
||||
def inflate
|
||||
return Zlib::Inflate.inflate(self)
|
||||
end
|
||||
|
||||
# Inflates and replaces itself
|
||||
def inflate!
|
||||
self.replace(inflate)
|
||||
end
|
||||
|
||||
# Adds some aliases for <include?>: <has?>, <includes?>, <contains?>
|
||||
alias has? include?
|
||||
alias includes? include?
|
||||
alias contains? include?
|
||||
end
|
||||
|
||||
# Sprite class extensions
|
||||
class Sprite
|
||||
# Shorthand for initializing a bitmap by path, bitmap, or width/height:
|
||||
# -> bmp("Graphics/Pictures/bag")
|
||||
# -> bmp(32, 32)
|
||||
# -> bmp(some_other_bitmap)
|
||||
def bmp(arg1 = nil, arg2 = nil)
|
||||
if arg1
|
||||
if arg2
|
||||
arg1 = Graphics.width if arg1 == -1
|
||||
arg2 = Graphics.height if arg2 == -1
|
||||
self.bitmap = Bitmap.new(arg1, arg2)
|
||||
elsif arg1.is_a?(Bitmap)
|
||||
self.bitmap = arg1.clone
|
||||
else
|
||||
self.bitmap = Bitmap.new(arg1)
|
||||
end
|
||||
else
|
||||
return self.bitmap
|
||||
end
|
||||
end
|
||||
|
||||
# Alternative to bmp(path):
|
||||
# -> bmp = "Graphics/Pictures/bag"
|
||||
def bmp=(arg1)
|
||||
bmp(arg1)
|
||||
end
|
||||
|
||||
# Usage:
|
||||
# -> [x] # Sets sprite.x to x
|
||||
# -> [x,y] # Sets sprite.x to x and sprite.y to y
|
||||
# -> [x,y,z] # Sets sprite.x to x and sprite.y to y and sprite.z to z
|
||||
# -> [nil,y] # Sets sprite.y to y
|
||||
# -> [nil,nil,z] # Sets sprite.z to z
|
||||
# -> [x,nil,z] # Sets sprite.x to x and sprite.z to z
|
||||
# Etc.
|
||||
def xyz=(args)
|
||||
self.x = args[0] || self.x
|
||||
self.y = args[1] || self.y
|
||||
self.z = args[2] || self.z
|
||||
end
|
||||
|
||||
# Returns the x, y, and z coordinates in the xyz=(args) format, [x,y,z]
|
||||
def xyz
|
||||
return [self.x,self.y,self.z]
|
||||
end
|
||||
|
||||
# Centers the sprite by setting the origin points to half the width and height
|
||||
def center_origins
|
||||
return if !self.bitmap
|
||||
self.ox = self.bitmap.width / 2
|
||||
self.oy = self.bitmap.height / 2
|
||||
end
|
||||
|
||||
# Returns the sprite's full width, taking zoom_x into account
|
||||
def fullwidth
|
||||
return self.bitmap.width.to_f * self.zoom_x
|
||||
end
|
||||
|
||||
# Returns the sprite's full height, taking zoom_y into account
|
||||
def fullheight
|
||||
return self.bitmap.height.to_f * self.zoom_y
|
||||
end
|
||||
end
|
||||
|
||||
class TextSprite < Sprite
|
||||
# Sets up the sprite and bitmap. You can also pass text to draw
|
||||
# either an array of arrays, or an array containing the normal "parameters"
|
||||
# for drawing text:
|
||||
# [text,x,y,align,basecolor,shadowcolor]
|
||||
def initialize(viewport = nil, text = nil, width = -1, height = -1)
|
||||
super(viewport)
|
||||
@width = width
|
||||
@height = height
|
||||
self.bmp(@width, @height)
|
||||
pbSetSystemFont(self.bmp)
|
||||
if text.is_a?(Array)
|
||||
if text[0].is_a?(Array)
|
||||
pbDrawTextPositions(self.bmp,text)
|
||||
else
|
||||
pbDrawTextPositions(self.bmp,[text])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Clears the bitmap (and thus all drawn text)
|
||||
def clear
|
||||
self.bmp.clear
|
||||
pbSetSystemFont(self.bmp)
|
||||
end
|
||||
|
||||
# You can also pass text to draw either an array of arrays, or an array
|
||||
# containing the normal "parameters" for drawing text:
|
||||
# [text,x,y,align,basecolor,shadowcolor]
|
||||
def draw(text, clear = false)
|
||||
self.clear if clear
|
||||
if text[0].is_a?(Array)
|
||||
pbDrawTextPositions(self.bmp,text)
|
||||
else
|
||||
pbDrawTextPositions(self.bmp,[text])
|
||||
end
|
||||
end
|
||||
|
||||
# Draws text with outline
|
||||
# [text,x,y,align,basecolor,shadowcolor]
|
||||
def draw_outline(text, clear = false)
|
||||
self.clear if clear
|
||||
if text[0].is_a?(Array)
|
||||
for e in text
|
||||
e[2] -= 224
|
||||
pbDrawOutlineText(self.bmp,e[1],e[2],640,480,e[0],e[4],e[5],e[3])
|
||||
end
|
||||
else
|
||||
e = text
|
||||
e[2] -= 224
|
||||
pbDrawOutlineText(self.bmp,e[1],e[2],640,480,e[0],e[4],e[5],e[3])
|
||||
end
|
||||
end
|
||||
|
||||
# Draws and breaks a line if the width is exceeded
|
||||
# [text,x,y,width,numlines,basecolor,shadowcolor]
|
||||
def draw_ex(text, clear = false)
|
||||
self.clear if clear
|
||||
if text[0].is_a?(Array)
|
||||
for e in text
|
||||
drawTextEx(self.bmp,e[1],e[2],e[3],e[4],e[0],e[5],e[6])
|
||||
end
|
||||
else
|
||||
e = text
|
||||
drawTextEx(self.bmp,e[1],e[2],e[3],e[4],e[0],e[5],e[6])
|
||||
end
|
||||
end
|
||||
|
||||
# Clears and disposes the sprite
|
||||
def dispose
|
||||
clear
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# A better alternative to the typical @sprites = {}
|
||||
class SpriteHash
|
||||
attr_reader :x
|
||||
attr_reader :y
|
||||
attr_reader :z
|
||||
attr_reader :visible
|
||||
attr_reader :opacity
|
||||
|
||||
def initialize
|
||||
@hash = {}
|
||||
@x = 0
|
||||
@y = 0
|
||||
@z = 0
|
||||
@visible = true
|
||||
@opacity = 255
|
||||
end
|
||||
|
||||
# Returns the object in the specified key
|
||||
def [](key)
|
||||
key = key.to_sym if key.respond_to?(:to_sym) && !key.is_a?(Numeric)
|
||||
return @hash[key]
|
||||
end
|
||||
|
||||
# Sets an object in specified key to the specified value
|
||||
def []=(key, value)
|
||||
key = key.to_sym if key.respond_to?(:to_sym) && !key.is_a?(Numeric)
|
||||
add(key, value)
|
||||
end
|
||||
|
||||
# Returns the raw hash
|
||||
def raw
|
||||
return @hash
|
||||
end
|
||||
|
||||
# Returns the keys in the hash
|
||||
def keys
|
||||
return @hash.keys
|
||||
end
|
||||
|
||||
def length; return self.size; end
|
||||
def count; return self.size; end
|
||||
|
||||
# Returns the amount of keys in the hash
|
||||
def size
|
||||
return @hash.keys.size
|
||||
end
|
||||
|
||||
# Clones the hash
|
||||
def clone
|
||||
return @hash.clone
|
||||
end
|
||||
|
||||
# Adds an object to the specified key
|
||||
def add(key, value)
|
||||
clear_disposed
|
||||
key = key.to_sym if key.respond_to?(:to_sym) && !key.is_a?(Numeric)
|
||||
@hash[key] if @hash[key] && @hash[key].respond_to?(:dispose)
|
||||
@hash[key] = value
|
||||
clear_disposed
|
||||
end
|
||||
|
||||
# Deletes an object in the specified key
|
||||
def delete(key)
|
||||
key = key.to_sym if key.respond_to?(:to_sym) && !key.is_a?(Numeric)
|
||||
@hash[key] = nil
|
||||
clear_disposed
|
||||
end
|
||||
|
||||
# Iterates over all sprites
|
||||
def each
|
||||
clear_disposed
|
||||
@hash.each { |s| yield s[1] if block_given? }
|
||||
end
|
||||
|
||||
# Updates all sprites
|
||||
def update
|
||||
clear_disposed
|
||||
for key in @hash.keys
|
||||
@hash[key].update if @hash[key].respond_to?(:update)
|
||||
end
|
||||
end
|
||||
|
||||
# Disposes all sprites
|
||||
def dispose
|
||||
clear_disposed
|
||||
for key in @hash.keys
|
||||
@hash[key].dispose if @hash[key].respond_to?(:dispose)
|
||||
end
|
||||
clear_disposed
|
||||
end
|
||||
|
||||
# Compatibility
|
||||
def disposed?
|
||||
return false
|
||||
end
|
||||
|
||||
# Changes x on all sprites
|
||||
def x=(value)
|
||||
clear_disposed
|
||||
for key in @hash.keys
|
||||
@hash[key].x += value - @x
|
||||
end
|
||||
@x = value
|
||||
end
|
||||
|
||||
# Changes y on all sprites
|
||||
def y=(value)
|
||||
clear_disposed
|
||||
for key in @hash.keys
|
||||
@hash[key].y += value - @y
|
||||
end
|
||||
@y = value
|
||||
end
|
||||
|
||||
# Changes z on all sprites
|
||||
def z=(value)
|
||||
clear_disposed
|
||||
for key in @hash.keys
|
||||
@hash[key].z += value - @z
|
||||
end
|
||||
@z = value
|
||||
end
|
||||
|
||||
# Changes visibility on all sprites
|
||||
def visible=(value)
|
||||
clear_disposed
|
||||
for key in @hash.keys
|
||||
@hash[key].visible = value
|
||||
end
|
||||
end
|
||||
|
||||
# Changes opacity on all sprites
|
||||
def opacity=(value)
|
||||
clear_disposed
|
||||
for key in @hash.keys
|
||||
@hash[key].opacity += value - @opacity
|
||||
end
|
||||
@opacity = [0,value,255].sort[1]
|
||||
end
|
||||
|
||||
# Fades out all sprites
|
||||
def hide(frames = 16)
|
||||
clear_disposed
|
||||
frames.times do
|
||||
Graphics.update
|
||||
Input.update
|
||||
for key in @hash.keys
|
||||
@hash[key].opacity -= 255 / frames.to_f
|
||||
end
|
||||
end
|
||||
@opacity = 0
|
||||
end
|
||||
|
||||
# Fades in all sprites
|
||||
def show(frames = 16)
|
||||
clear_disposed
|
||||
frames.times do
|
||||
Graphics.update
|
||||
Input.update
|
||||
for key in @hash.keys
|
||||
@hash[key].opacity += 255 / frames.to_f
|
||||
end
|
||||
end
|
||||
@opacity = 255
|
||||
end
|
||||
|
||||
# Deletes all disposed sprites from the hash
|
||||
def clear_disposed
|
||||
for key in @hash.keys
|
||||
if (@hash[key].disposed? rescue true)
|
||||
@hash[key] = nil
|
||||
@hash.delete(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Renames the old key to the new key
|
||||
def rename(old, new)
|
||||
self[new] = self[old]
|
||||
delete(old)
|
||||
end
|
||||
end
|
||||
|
||||
class ByteWriter
|
||||
def initialize(filename)
|
||||
@file = File.new(filename, "wb")
|
||||
end
|
||||
|
||||
def <<(*data)
|
||||
write(*data)
|
||||
end
|
||||
|
||||
def write(*data)
|
||||
data.each do |e|
|
||||
if e.is_a?(Array) || e.is_a?(Enumerator)
|
||||
e.each { |item| write(item) }
|
||||
elsif e.is_a?(Numeric)
|
||||
@file.putc e
|
||||
else
|
||||
raise "Invalid data for writing.\nData type: #{e.class}\nData: #{e.inspect[0..100]}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def write_int(int)
|
||||
self << ByteWriter.to_bytes(int)
|
||||
end
|
||||
|
||||
def close
|
||||
@file.close
|
||||
@file = nil
|
||||
end
|
||||
|
||||
def self.to_bytes(int)
|
||||
return [
|
||||
(int >> 24) & 0xFF,
|
||||
(int >> 16) & 0xFF,
|
||||
(int >> 8) & 0xFF,
|
||||
int & 0xFF
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
class Bitmap
|
||||
def save_to_png(filename)
|
||||
f = ByteWriter.new(filename)
|
||||
|
||||
#============================= Writing header ===============================#
|
||||
# PNG signature
|
||||
f << [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]
|
||||
# Header length
|
||||
f << [0x00, 0x00, 0x00, 0x0D]
|
||||
# IHDR
|
||||
headertype = [0x49, 0x48, 0x44, 0x52]
|
||||
f << headertype
|
||||
|
||||
# Width, height, compression, filter, interlacing
|
||||
headerdata = ByteWriter.to_bytes(self.width).
|
||||
concat(ByteWriter.to_bytes(self.height)).
|
||||
concat([0x08, 0x06, 0x00, 0x00, 0x00])
|
||||
f << headerdata
|
||||
|
||||
# CRC32 checksum
|
||||
sum = headertype.concat(headerdata)
|
||||
f.write_int Zlib::crc32(sum.pack("C*"))
|
||||
|
||||
#============================== Writing data ================================#
|
||||
data = []
|
||||
for y in 0...self.height
|
||||
# Start scanline
|
||||
data << 0x00 # Filter: None
|
||||
for x in 0...self.width
|
||||
px = self.get_pixel(x, y)
|
||||
# Write raw RGBA pixels
|
||||
data << px.red
|
||||
data << px.green
|
||||
data << px.blue
|
||||
data << px.alpha
|
||||
end
|
||||
end
|
||||
# Zlib deflation
|
||||
smoldata = Zlib::Deflate.deflate(data.pack("C*")).bytes
|
||||
# data chunk length
|
||||
f.write_int smoldata.size
|
||||
# IDAT
|
||||
f << [0x49, 0x44, 0x41, 0x54]
|
||||
f << smoldata
|
||||
# CRC32 checksum
|
||||
f.write_int Zlib::crc32([0x49, 0x44, 0x41, 0x54].concat(smoldata).pack("C*"))
|
||||
|
||||
#============================== End Of File =================================#
|
||||
# Empty chunk
|
||||
f << [0x00, 0x00, 0x00, 0x00]
|
||||
# IEND
|
||||
f << [0x49, 0x45, 0x4E, 0x44]
|
||||
# CRC32 checksum
|
||||
f.write_int Zlib::crc32([0x49, 0x45, 0x4E, 0x44].pack("C*"))
|
||||
f.close
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Stand-alone methods
|
||||
|
||||
# Fades in a black overlay
|
||||
def showBlk(n = 16)
|
||||
return if $blkVp || $blk
|
||||
$blkVp = Viewport.new(0,0,Settings::SCREEN_WIDTH,Settings::SCREEN_HEIGHT)
|
||||
$blkVp.z = 9999999
|
||||
$blk = Sprite.new($blkVp)
|
||||
$blk.bmp(-1,-1)
|
||||
$blk.bitmap.fill_rect(0,0,Settings::SCREEN_WIDTH,Settings::SCREEN_HEIGHT,Color.new(0,0,0))
|
||||
$blk.opacity = 0
|
||||
for i in 0...(n + 1)
|
||||
Graphics.update
|
||||
Input.update
|
||||
yield i if block_given?
|
||||
$blk.opacity += 256 / n.to_f
|
||||
end
|
||||
end
|
||||
|
||||
# Fades out and disposes a black overlay
|
||||
def hideBlk(n = 16)
|
||||
return if !$blk || !$blkVp
|
||||
for i in 0...(n + 1)
|
||||
Graphics.update
|
||||
Input.update
|
||||
yield i if block_given?
|
||||
$blk.opacity -= 256 / n.to_f
|
||||
end
|
||||
$blk.dispose
|
||||
$blk = nil
|
||||
$blkVp.dispose
|
||||
$blkVp = nil
|
||||
end
|
||||
|
||||
def pbGetActiveEventPage(event, mapid = nil)
|
||||
mapid ||= event.map.map_id if event.respond_to?(:map)
|
||||
pages = (event.is_a?(RPG::Event) ? event.pages : event.instance_eval { @event.pages })
|
||||
for i in 0...pages.size
|
||||
c = pages[pages.size - 1 - i].condition
|
||||
ss = !(c.self_switch_valid && !$game_self_switches[[mapid,
|
||||
event.id,c.self_switch_ch]])
|
||||
sw1 = !(c.switch1_valid && !$game_switches[c.switch1_id])
|
||||
sw2 = !(c.switch2_valid && !$game_switches[c.switch2_id])
|
||||
var = true
|
||||
if c.variable_valid
|
||||
if !c.variable_value || !$game_variables[c.variable_id].is_a?(Numeric) ||
|
||||
$game_variables[c.variable_id] < c.variable_value
|
||||
var = false
|
||||
end
|
||||
end
|
||||
if ss && sw1 && sw2 && var # All conditions are met
|
||||
return pages[pages.size - 1 - i]
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
@@ -1,119 +1,119 @@
|
||||
#===============================================================================
|
||||
# Pokémon Vault – Core Storage System
|
||||
#===============================================================================
|
||||
# External, cross-save, cross-game Pokémon storage.
|
||||
#===============================================================================
|
||||
|
||||
module PokemonVault
|
||||
VAULT_FOLDER_NAME = "Pokemon Vault"
|
||||
VAULT_FILE = "vault.dat"
|
||||
MAX_BOXES = 400
|
||||
BOX_SIZE = 30
|
||||
|
||||
module_function
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Vault Data
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def vault_directory
|
||||
parent = File.dirname(System.data_directory)
|
||||
dir = File.join(parent, VAULT_FOLDER_NAME)
|
||||
Dir.mkdir(dir) unless Dir.exist?(dir)
|
||||
return dir
|
||||
end
|
||||
|
||||
def vault_path
|
||||
File.join(vault_directory, VAULT_FILE)
|
||||
end
|
||||
|
||||
def empty_vault
|
||||
Array.new(MAX_BOXES) { Array.new(BOX_SIZE) }
|
||||
end
|
||||
|
||||
def valid_vault?(vault)
|
||||
return false if !vault.is_a?(Array)
|
||||
return false if vault.length != MAX_BOXES
|
||||
vault.all? { |box| box.is_a?(Array) && box.length == BOX_SIZE }
|
||||
end
|
||||
|
||||
def load_vault
|
||||
path = vault_path
|
||||
return empty_vault if !File.exist?(path)
|
||||
data = Marshal.load(File.binread(path))
|
||||
return valid_vault?(data) ? data : empty_vault
|
||||
rescue
|
||||
return empty_vault
|
||||
end
|
||||
|
||||
def save_vault(vault)
|
||||
File.binwrite(vault_path, Marshal.dump(vault))
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Eligibility Rules
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def storable_pokemon?(pkmn)
|
||||
return false if !pkmn
|
||||
return false if pkmn.egg?
|
||||
|
||||
species = pkmn.species_data
|
||||
return false if species.has_flag?("NotTradeable")
|
||||
return false if species.has_flag?("NotStorable")
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Vault Operations
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def first_empty_slot(vault)
|
||||
vault.each_with_index do |box, b|
|
||||
box.each_with_index do |slot, s|
|
||||
return [b, s] if slot.nil?
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def add_pokemon(pkmn)
|
||||
return false if !storable_pokemon?(pkmn)
|
||||
vault = load_vault
|
||||
pos = first_empty_slot(vault)
|
||||
return false if !pos
|
||||
|
||||
b, s = pos
|
||||
vault[b][s] = pkmn
|
||||
save_vault(vault)
|
||||
true
|
||||
end
|
||||
|
||||
def remove_pokemon(box, slot)
|
||||
vault = load_vault
|
||||
return nil if !vault.dig(box, slot)
|
||||
|
||||
pkmn = vault[box][slot]
|
||||
vault[box][slot] = nil
|
||||
save_vault(vault)
|
||||
pkmn
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Remove/Add From PC
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def remove_from_pc(box, slot)
|
||||
pkmn = $PokemonStorage[box, slot]
|
||||
return nil if !storable_pokemon?(pkmn)
|
||||
|
||||
$PokemonStorage[box, slot] = nil
|
||||
pkmn
|
||||
end
|
||||
|
||||
def add_to_pc(pkmn)
|
||||
return false if !pkmn
|
||||
return !$PokemonStorage.pbStoreCaught(pkmn).nil?
|
||||
end
|
||||
end
|
||||
#===============================================================================
|
||||
# Pokémon Vault – Core Storage System
|
||||
#===============================================================================
|
||||
# External, cross-save, cross-game Pokémon storage.
|
||||
#===============================================================================
|
||||
|
||||
module PokemonVault
|
||||
VAULT_FOLDER_NAME = "Pokemon Vault"
|
||||
VAULT_FILE = "vault.dat"
|
||||
MAX_BOXES = 400
|
||||
BOX_SIZE = 30
|
||||
|
||||
module_function
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Vault Data
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def vault_directory
|
||||
parent = File.dirname(System.data_directory)
|
||||
dir = File.join(parent, VAULT_FOLDER_NAME)
|
||||
Dir.mkdir(dir) unless Dir.exist?(dir)
|
||||
return dir
|
||||
end
|
||||
|
||||
def vault_path
|
||||
File.join(vault_directory, VAULT_FILE)
|
||||
end
|
||||
|
||||
def empty_vault
|
||||
Array.new(MAX_BOXES) { Array.new(BOX_SIZE) }
|
||||
end
|
||||
|
||||
def valid_vault?(vault)
|
||||
return false if !vault.is_a?(Array)
|
||||
return false if vault.length != MAX_BOXES
|
||||
vault.all? { |box| box.is_a?(Array) && box.length == BOX_SIZE }
|
||||
end
|
||||
|
||||
def load_vault
|
||||
path = vault_path
|
||||
return empty_vault if !File.exist?(path)
|
||||
data = Marshal.load(File.binread(path))
|
||||
return valid_vault?(data) ? data : empty_vault
|
||||
rescue
|
||||
return empty_vault
|
||||
end
|
||||
|
||||
def save_vault(vault)
|
||||
File.binwrite(vault_path, Marshal.dump(vault))
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Eligibility Rules
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def storable_pokemon?(pkmn)
|
||||
return false if !pkmn
|
||||
return false if pkmn.egg?
|
||||
|
||||
species = pkmn.species_data
|
||||
return false if species.has_flag?("NotTradeable")
|
||||
return false if species.has_flag?("NotStorable")
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Vault Operations
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def first_empty_slot(vault)
|
||||
vault.each_with_index do |box, b|
|
||||
box.each_with_index do |slot, s|
|
||||
return [b, s] if slot.nil?
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def add_pokemon(pkmn)
|
||||
return false if !storable_pokemon?(pkmn)
|
||||
vault = load_vault
|
||||
pos = first_empty_slot(vault)
|
||||
return false if !pos
|
||||
|
||||
b, s = pos
|
||||
vault[b][s] = pkmn
|
||||
save_vault(vault)
|
||||
true
|
||||
end
|
||||
|
||||
def remove_pokemon(box, slot)
|
||||
vault = load_vault
|
||||
return nil if !vault.dig(box, slot)
|
||||
|
||||
pkmn = vault[box][slot]
|
||||
vault[box][slot] = nil
|
||||
save_vault(vault)
|
||||
pkmn
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Remove/Add From PC
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def remove_from_pc(box, slot)
|
||||
pkmn = $PokemonStorage[box, slot]
|
||||
return nil if !storable_pokemon?(pkmn)
|
||||
|
||||
$PokemonStorage[box, slot] = nil
|
||||
pkmn
|
||||
end
|
||||
|
||||
def add_to_pc(pkmn)
|
||||
return false if !pkmn
|
||||
return !$PokemonStorage.pbStoreCaught(pkmn).nil?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,301 +1,301 @@
|
||||
#===============================================================================
|
||||
# PC Shit
|
||||
#===============================================================================
|
||||
|
||||
class PokemonStorageScreen
|
||||
def pbChoosePokemonForVault(eligibility_proc = nil, helptext = nil)
|
||||
$game_temp.in_storage = true
|
||||
@scene.pbStartBox(self, 0)
|
||||
chosen = nil
|
||||
|
||||
loop do
|
||||
selected = @scene.pbSelectBox(@storage.party)
|
||||
|
||||
# Close PC
|
||||
if selected && selected[0] == -3
|
||||
break if pbConfirmMessage(_INTL("Exit the PC?"))
|
||||
next
|
||||
end
|
||||
|
||||
break if selected.nil?
|
||||
|
||||
box, slot = selected
|
||||
pkmn = @storage[box, slot]
|
||||
next if !pkmn
|
||||
|
||||
if eligibility_proc && !eligibility_proc.call(pkmn)
|
||||
pbMessage(_INTL("That Pokémon can’t be stored in the Vault."))
|
||||
next
|
||||
end
|
||||
|
||||
if box < 0
|
||||
pbMessage(_INTL("You can only select Pokémon from PC Boxes."))
|
||||
next
|
||||
end
|
||||
|
||||
commands = [
|
||||
_INTL("Select"),
|
||||
_INTL("Summary"),
|
||||
_INTL("Cancel")
|
||||
]
|
||||
|
||||
command = pbShowCommands(helptext || _INTL("{1} is selected.", pkmn.name), commands)
|
||||
|
||||
case command
|
||||
when 0 # Select
|
||||
chosen = [pkmn, box, slot]
|
||||
break
|
||||
when 1 # Summary
|
||||
pbSummary(selected, nil)
|
||||
end
|
||||
end
|
||||
|
||||
@scene.pbCloseBox
|
||||
$game_temp.in_storage = false
|
||||
return chosen
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Placeholder UI (Fuck This)
|
||||
#===============================================================================
|
||||
|
||||
module PokemonVault
|
||||
module_function
|
||||
|
||||
def open_menu
|
||||
loop do
|
||||
choice = pbMessage(
|
||||
_INTL("Pokémon Vault"),
|
||||
[
|
||||
_INTL("Upload Pokémon"),
|
||||
_INTL("Upload Box"),
|
||||
_INTL("Download Pokémon"),
|
||||
_INTL("Download Box"),
|
||||
_INTL("Quit")
|
||||
]
|
||||
)
|
||||
|
||||
case choice
|
||||
when 0
|
||||
upload_single_pokemon
|
||||
when 1
|
||||
upload_entire_box
|
||||
when 2
|
||||
download_single_pokemon
|
||||
when 3
|
||||
download_entire_box
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module PokemonVault
|
||||
module_function
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Upload From PC
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def choose_pokemon_from_pc(eligibility_proc = nil, helptext = nil)
|
||||
chosen = nil
|
||||
pbFadeOutIn do
|
||||
scene = PokemonStorageScene.new
|
||||
screen = PokemonStorageScreen.new(scene, $PokemonStorage)
|
||||
chosen = screen.pbChoosePokemonForVault(eligibility_proc, helptext)
|
||||
end
|
||||
return chosen
|
||||
end
|
||||
|
||||
def upload_single_pokemon
|
||||
chosen = choose_pokemon_from_pc(
|
||||
proc { |pkmn| storable_pokemon?(pkmn) },
|
||||
_INTL("Choose a Pokémon to upload.")
|
||||
)
|
||||
|
||||
return if !chosen
|
||||
|
||||
pkmn, box, slot = chosen
|
||||
|
||||
return if !pbConfirmMessage(
|
||||
_INTL("Upload {1} to the Pokémon Vault?", pkmn.name)
|
||||
)
|
||||
|
||||
removed = remove_from_pc(box, slot)
|
||||
|
||||
if add_pokemon(removed)
|
||||
pbMessage(_INTL("{1} was uploaded to the Vault.", removed.name))
|
||||
Game.save
|
||||
pbMEPlay("GUI save game")
|
||||
else
|
||||
pbMessage(_INTL("The Vault is full."))
|
||||
add_to_pc(removed)
|
||||
end
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Upload PC Box
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def upload_entire_box
|
||||
box = pbMessage(
|
||||
_INTL("Which box do you want to upload?"),
|
||||
(1..Settings::NUM_STORAGE_BOXES).map { |i| _INTL("Box {1}", i) }
|
||||
)
|
||||
return if box < 0
|
||||
|
||||
box_index = box
|
||||
uploaded = 0
|
||||
skipped = 0
|
||||
|
||||
BOX_SIZE.times do |slot|
|
||||
pkmn = $PokemonStorage[box_index, slot]
|
||||
next if !storable_pokemon?(pkmn)
|
||||
|
||||
if add_pokemon(pkmn)
|
||||
$PokemonStorage[box_index, slot] = nil
|
||||
uploaded += 1
|
||||
else
|
||||
skipped += 1
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
pbMessage(
|
||||
_INTL(
|
||||
"Uploaded {1} Pokémon.\nSkipped {2}.",
|
||||
uploaded,
|
||||
skipped
|
||||
)
|
||||
)
|
||||
|
||||
Game.save if uploaded > 0
|
||||
pbMEPlay("GUI save game") if uploaded > 0
|
||||
end
|
||||
end
|
||||
|
||||
module PokemonVault
|
||||
module_function
|
||||
|
||||
def choose_pokemon_from_vault
|
||||
vault = load_vault
|
||||
entries = []
|
||||
|
||||
vault.each_with_index do |box, b|
|
||||
box.each_with_index do |pkmn, s|
|
||||
next if !pkmn
|
||||
entries << [pkmn, b, s]
|
||||
end
|
||||
end
|
||||
|
||||
if entries.empty?
|
||||
pbMessage(_INTL("The Pokémon Vault is empty."))
|
||||
return nil
|
||||
end
|
||||
|
||||
commands = entries.map.with_index do |(pkmn, b, s), i|
|
||||
_INTL("{1}. {2} (Box {3}, Slot {4})",
|
||||
i + 1,
|
||||
pkmn.name,
|
||||
b + 1,
|
||||
s + 1
|
||||
)
|
||||
end
|
||||
|
||||
commands << _INTL("Cancel")
|
||||
|
||||
choice = pbMessage(
|
||||
_INTL("Choose a Pokémon to download."),
|
||||
commands
|
||||
)
|
||||
|
||||
return nil if choice < 0 || choice >= entries.length
|
||||
|
||||
return entries[choice] # [pkmn, box, slot]
|
||||
end
|
||||
end
|
||||
|
||||
module PokemonVault
|
||||
module_function
|
||||
|
||||
def download_single_pokemon
|
||||
chosen = choose_pokemon_from_vault
|
||||
return if !chosen
|
||||
|
||||
pkmn, box, slot = chosen
|
||||
|
||||
return if !pbConfirmMessage(
|
||||
_INTL("Download {1} from the Pokémon Vault?", pkmn.name)
|
||||
)
|
||||
|
||||
removed = remove_pokemon(box, slot)
|
||||
return if !removed
|
||||
|
||||
# Attempt to store in PC
|
||||
if add_to_pc(removed)
|
||||
pbMessage(_INTL("{1} was downloaded to your PC.", removed.name))
|
||||
Game.save
|
||||
pbMEPlay("GUI save game")
|
||||
else
|
||||
pbMessage(_INTL("Your PC Boxes are full."))
|
||||
add_pokemon(removed) # rollback safely into Vault
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def download_entire_box
|
||||
vault = load_vault
|
||||
box_choices = []
|
||||
|
||||
vault.each_with_index do |box, i|
|
||||
count = box.compact.length
|
||||
next if count == 0
|
||||
box_choices << [i, count]
|
||||
end
|
||||
|
||||
if box_choices.empty?
|
||||
pbMessage(_INTL("The Pokémon Vault is empty."))
|
||||
return
|
||||
end
|
||||
|
||||
commands = box_choices.map do |(b, count)|
|
||||
_INTL("Vault Box {1} ({2} Pokémon)", b + 1, count)
|
||||
end
|
||||
commands << _INTL("Cancel")
|
||||
|
||||
choice = pbMessage(_INTL("Choose a Vault box to download."), commands)
|
||||
return if choice < 0 || choice >= box_choices.length
|
||||
|
||||
box_index, _ = box_choices[choice]
|
||||
|
||||
downloaded = 0
|
||||
skipped = 0
|
||||
|
||||
vault[box_index].each_with_index do |pkmn, slot|
|
||||
next if !pkmn
|
||||
|
||||
# Attempt to store in PC
|
||||
if add_to_pc(pkmn)
|
||||
vault[box_index][slot] = nil
|
||||
downloaded += 1
|
||||
else
|
||||
skipped += 1
|
||||
break # PC is full; stop downloading this box
|
||||
end
|
||||
end
|
||||
|
||||
save_vault(vault)
|
||||
|
||||
pbMessage(
|
||||
_INTL("Downloaded {1} Pokémon.\nSkipped {2}.",
|
||||
downloaded,
|
||||
skipped
|
||||
)
|
||||
)
|
||||
Game.save if downloaded > 0
|
||||
pbMEPlay("GUI save game") if downloaded > 0
|
||||
#===============================================================================
|
||||
# PC Shit
|
||||
#===============================================================================
|
||||
|
||||
class PokemonStorageScreen
|
||||
def pbChoosePokemonForVault(eligibility_proc = nil, helptext = nil)
|
||||
$game_temp.in_storage = true
|
||||
@scene.pbStartBox(self, 0)
|
||||
chosen = nil
|
||||
|
||||
loop do
|
||||
selected = @scene.pbSelectBox(@storage.party)
|
||||
|
||||
# Close PC
|
||||
if selected && selected[0] == -3
|
||||
break if pbConfirmMessage(_INTL("Exit the PC?"))
|
||||
next
|
||||
end
|
||||
|
||||
break if selected.nil?
|
||||
|
||||
box, slot = selected
|
||||
pkmn = @storage[box, slot]
|
||||
next if !pkmn
|
||||
|
||||
if eligibility_proc && !eligibility_proc.call(pkmn)
|
||||
pbMessage(_INTL("That Pokémon can’t be stored in the Vault."))
|
||||
next
|
||||
end
|
||||
|
||||
if box < 0
|
||||
pbMessage(_INTL("You can only select Pokémon from PC Boxes."))
|
||||
next
|
||||
end
|
||||
|
||||
commands = [
|
||||
_INTL("Select"),
|
||||
_INTL("Summary"),
|
||||
_INTL("Cancel")
|
||||
]
|
||||
|
||||
command = pbShowCommands(helptext || _INTL("{1} is selected.", pkmn.name), commands)
|
||||
|
||||
case command
|
||||
when 0 # Select
|
||||
chosen = [pkmn, box, slot]
|
||||
break
|
||||
when 1 # Summary
|
||||
pbSummary(selected, nil)
|
||||
end
|
||||
end
|
||||
|
||||
@scene.pbCloseBox
|
||||
$game_temp.in_storage = false
|
||||
return chosen
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Placeholder UI (Fuck This)
|
||||
#===============================================================================
|
||||
|
||||
module PokemonVault
|
||||
module_function
|
||||
|
||||
def open_menu
|
||||
loop do
|
||||
choice = pbMessage(
|
||||
_INTL("Pokémon Vault"),
|
||||
[
|
||||
_INTL("Upload Pokémon"),
|
||||
_INTL("Upload Box"),
|
||||
_INTL("Download Pokémon"),
|
||||
_INTL("Download Box"),
|
||||
_INTL("Quit")
|
||||
]
|
||||
)
|
||||
|
||||
case choice
|
||||
when 0
|
||||
upload_single_pokemon
|
||||
when 1
|
||||
upload_entire_box
|
||||
when 2
|
||||
download_single_pokemon
|
||||
when 3
|
||||
download_entire_box
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module PokemonVault
|
||||
module_function
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Upload From PC
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def choose_pokemon_from_pc(eligibility_proc = nil, helptext = nil)
|
||||
chosen = nil
|
||||
pbFadeOutIn do
|
||||
scene = PokemonStorageScene.new
|
||||
screen = PokemonStorageScreen.new(scene, $PokemonStorage)
|
||||
chosen = screen.pbChoosePokemonForVault(eligibility_proc, helptext)
|
||||
end
|
||||
return chosen
|
||||
end
|
||||
|
||||
def upload_single_pokemon
|
||||
chosen = choose_pokemon_from_pc(
|
||||
proc { |pkmn| storable_pokemon?(pkmn) },
|
||||
_INTL("Choose a Pokémon to upload.")
|
||||
)
|
||||
|
||||
return if !chosen
|
||||
|
||||
pkmn, box, slot = chosen
|
||||
|
||||
return if !pbConfirmMessage(
|
||||
_INTL("Upload {1} to the Pokémon Vault?", pkmn.name)
|
||||
)
|
||||
|
||||
removed = remove_from_pc(box, slot)
|
||||
|
||||
if add_pokemon(removed)
|
||||
pbMessage(_INTL("{1} was uploaded to the Vault.", removed.name))
|
||||
Game.save
|
||||
pbMEPlay("GUI save game")
|
||||
else
|
||||
pbMessage(_INTL("The Vault is full."))
|
||||
add_to_pc(removed)
|
||||
end
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Upload PC Box
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def upload_entire_box
|
||||
box = pbMessage(
|
||||
_INTL("Which box do you want to upload?"),
|
||||
(1..Settings::NUM_STORAGE_BOXES).map { |i| _INTL("Box {1}", i) }
|
||||
)
|
||||
return if box < 0
|
||||
|
||||
box_index = box
|
||||
uploaded = 0
|
||||
skipped = 0
|
||||
|
||||
BOX_SIZE.times do |slot|
|
||||
pkmn = $PokemonStorage[box_index, slot]
|
||||
next if !storable_pokemon?(pkmn)
|
||||
|
||||
if add_pokemon(pkmn)
|
||||
$PokemonStorage[box_index, slot] = nil
|
||||
uploaded += 1
|
||||
else
|
||||
skipped += 1
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
pbMessage(
|
||||
_INTL(
|
||||
"Uploaded {1} Pokémon.\nSkipped {2}.",
|
||||
uploaded,
|
||||
skipped
|
||||
)
|
||||
)
|
||||
|
||||
Game.save if uploaded > 0
|
||||
pbMEPlay("GUI save game") if uploaded > 0
|
||||
end
|
||||
end
|
||||
|
||||
module PokemonVault
|
||||
module_function
|
||||
|
||||
def choose_pokemon_from_vault
|
||||
vault = load_vault
|
||||
entries = []
|
||||
|
||||
vault.each_with_index do |box, b|
|
||||
box.each_with_index do |pkmn, s|
|
||||
next if !pkmn
|
||||
entries << [pkmn, b, s]
|
||||
end
|
||||
end
|
||||
|
||||
if entries.empty?
|
||||
pbMessage(_INTL("The Pokémon Vault is empty."))
|
||||
return nil
|
||||
end
|
||||
|
||||
commands = entries.map.with_index do |(pkmn, b, s), i|
|
||||
_INTL("{1}. {2} (Box {3}, Slot {4})",
|
||||
i + 1,
|
||||
pkmn.name,
|
||||
b + 1,
|
||||
s + 1
|
||||
)
|
||||
end
|
||||
|
||||
commands << _INTL("Cancel")
|
||||
|
||||
choice = pbMessage(
|
||||
_INTL("Choose a Pokémon to download."),
|
||||
commands
|
||||
)
|
||||
|
||||
return nil if choice < 0 || choice >= entries.length
|
||||
|
||||
return entries[choice] # [pkmn, box, slot]
|
||||
end
|
||||
end
|
||||
|
||||
module PokemonVault
|
||||
module_function
|
||||
|
||||
def download_single_pokemon
|
||||
chosen = choose_pokemon_from_vault
|
||||
return if !chosen
|
||||
|
||||
pkmn, box, slot = chosen
|
||||
|
||||
return if !pbConfirmMessage(
|
||||
_INTL("Download {1} from the Pokémon Vault?", pkmn.name)
|
||||
)
|
||||
|
||||
removed = remove_pokemon(box, slot)
|
||||
return if !removed
|
||||
|
||||
# Attempt to store in PC
|
||||
if add_to_pc(removed)
|
||||
pbMessage(_INTL("{1} was downloaded to your PC.", removed.name))
|
||||
Game.save
|
||||
pbMEPlay("GUI save game")
|
||||
else
|
||||
pbMessage(_INTL("Your PC Boxes are full."))
|
||||
add_pokemon(removed) # rollback safely into Vault
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def download_entire_box
|
||||
vault = load_vault
|
||||
box_choices = []
|
||||
|
||||
vault.each_with_index do |box, i|
|
||||
count = box.compact.length
|
||||
next if count == 0
|
||||
box_choices << [i, count]
|
||||
end
|
||||
|
||||
if box_choices.empty?
|
||||
pbMessage(_INTL("The Pokémon Vault is empty."))
|
||||
return
|
||||
end
|
||||
|
||||
commands = box_choices.map do |(b, count)|
|
||||
_INTL("Vault Box {1} ({2} Pokémon)", b + 1, count)
|
||||
end
|
||||
commands << _INTL("Cancel")
|
||||
|
||||
choice = pbMessage(_INTL("Choose a Vault box to download."), commands)
|
||||
return if choice < 0 || choice >= box_choices.length
|
||||
|
||||
box_index, _ = box_choices[choice]
|
||||
|
||||
downloaded = 0
|
||||
skipped = 0
|
||||
|
||||
vault[box_index].each_with_index do |pkmn, slot|
|
||||
next if !pkmn
|
||||
|
||||
# Attempt to store in PC
|
||||
if add_to_pc(pkmn)
|
||||
vault[box_index][slot] = nil
|
||||
downloaded += 1
|
||||
else
|
||||
skipped += 1
|
||||
break # PC is full; stop downloading this box
|
||||
end
|
||||
end
|
||||
|
||||
save_vault(vault)
|
||||
|
||||
pbMessage(
|
||||
_INTL("Downloaded {1} Pokémon.\nSkipped {2}.",
|
||||
downloaded,
|
||||
skipped
|
||||
)
|
||||
)
|
||||
Game.save if downloaded > 0
|
||||
pbMEPlay("GUI save game") if downloaded > 0
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
Name = Pokémon Vault
|
||||
Version = 1.0.1
|
||||
Essentials = 21.1
|
||||
Requires = v21.1 Hotfixes,1.0.9
|
||||
Website = https://eeveeexpo.com/resources/1828/
|
||||
Name = Pokémon Vault
|
||||
Version = 1.0.1
|
||||
Essentials = 21.1
|
||||
Requires = v21.1 Hotfixes,1.0.9
|
||||
Website = https://eeveeexpo.com/resources/1828/
|
||||
Credits = ReallyBoredCoder
|
||||
@@ -1,420 +1,420 @@
|
||||
<body>
|
||||
<div>
|
||||
<u>Town Map Generator</u>
|
||||
</div>
|
||||
<form name="mf" action="javascript:void(null)">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Filename:</td>
|
||||
<td><input type="text" name="filename" value="mapRegion0.png"/></td>
|
||||
<td><input type="button" name="btnChange" value="Change"/></td>
|
||||
<td>Name of the region graphic (in Graphics/UI/Town Map/)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name:</td>
|
||||
<td><input type="text" name="name" value="Sample Region"/></td>
|
||||
<td><input type="button" name="btnChange2" value="Change"/></td>
|
||||
<td>Name of the region</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Square width:</td>
|
||||
<td><input type="text" name="sqwidth" size="4" min="1" max="16" value="16"/></td>
|
||||
<td><input type="button" name="btnRefreshWidth" value="Refresh"/></td>
|
||||
<td>Width of each point in the Town Map (in pixels)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Square height:</td>
|
||||
<td><input type="text" name="sqheight" size="4" min="1" max="16" value="16"/></td>
|
||||
<td><input type="button" name="btnRefreshHeight" value="Refresh"/></td>
|
||||
<td>Height of each point in the Town Map (in pixels)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<hr/>
|
||||
<div>
|
||||
<u>Edit point properties</u><br />
|
||||
Click on a point in the Town Map to edit its properties.
|
||||
</div>
|
||||
<div id="map">
|
||||
<img name="map" src="Graphics/UI/Town Map/mapRegion0.png" alt="" width="480" height="320"/>
|
||||
</div>
|
||||
<form name="f" action="javascript:void(null)">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Co-ordinates:</td>
|
||||
<td><input type="text" name="curpos" readonly="readonly"/></td>
|
||||
<td>X and Y co-ordinates of this point in the Town Map (click in the map above)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name:</td>
|
||||
<td><input type="text" name="locname"/></td>
|
||||
<td>Name of this location</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Landmark:</td>
|
||||
<td><input type="text" name="poi"/></td>
|
||||
<td>Name of a landmark found in this location</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Fly destination:</td>
|
||||
<td><input type="text" name="healing"/></td>
|
||||
<td>Map ID, X and Y tile co-ordinates the player will appear at when Flying to this location</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Switch:</td>
|
||||
<td><input type="text" name="swtch"/></td>
|
||||
<td>Number of a Game Switch that needs to be ON to see this point's name/landmark and to Fly to this location</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div>
|
||||
<input type="button" name="btnSave" value="Save" disabled="disabled"/>
|
||||
<input type="button" name="btnCancel" value="Cancel"/><br/ >
|
||||
<hr/>
|
||||
<u>PBS file "town_map.txt" text for this region</u><br />
|
||||
<textarea name="data" rows="10" cols="70"></textarea><br/ >
|
||||
<input type="button" name="btnLoad" value="Load into map"/>
|
||||
Apply the data in this box to the map above<br/ >
|
||||
When you're done, copy this text into "town_map.txt". Remember that it needs a section line (a number in square brackets).
|
||||
</div>
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
choiceX=-1
|
||||
choiceY=-1
|
||||
mappoints=[]
|
||||
mpelements=[]
|
||||
|
||||
function target(event){
|
||||
return event.target||event.srcElement
|
||||
}
|
||||
|
||||
function addChild(e){
|
||||
if(document.documentElement){
|
||||
document.documentElement.appendChild(e)
|
||||
} else{
|
||||
document.body.appendChild(e)
|
||||
}
|
||||
}
|
||||
|
||||
function removeChild(e){
|
||||
if(document.documentElement){
|
||||
document.documentElement.removeChild(e)
|
||||
} else{
|
||||
document.body.removeChild(e)
|
||||
}
|
||||
}
|
||||
|
||||
function positionedOffset(element) {
|
||||
var valueT = 0, valueL = 0;
|
||||
do {
|
||||
valueT += element.offsetTop || 0;
|
||||
valueL += element.offsetLeft || 0;
|
||||
element = element.offsetParent;
|
||||
if (element) {
|
||||
p = element.style.position;
|
||||
if (p == 'relative' || p == 'absolute') break;
|
||||
}
|
||||
} while (element);
|
||||
return [valueL, valueT];
|
||||
}
|
||||
|
||||
function pointerX(event) {
|
||||
return event.pageX || (event.clientX +
|
||||
(document.documentElement.scrollLeft || document.body.scrollLeft));
|
||||
}
|
||||
|
||||
function pointerY(event) {
|
||||
return event.pageY || (event.clientY +
|
||||
(document.documentElement.scrollTop || document.body.scrollTop));
|
||||
}
|
||||
|
||||
function elementPos(event){
|
||||
t=target(event)
|
||||
po=positionedOffset(t)
|
||||
return [(pointerX(event))-po[0],(pointerY(event))-po[1]]
|
||||
}
|
||||
|
||||
function elementPosObject(event,other){
|
||||
t=other
|
||||
po=positionedOffset(t)
|
||||
return [(pointerX(event))-po[0],(pointerY(event))-po[1]]
|
||||
}
|
||||
|
||||
function attachEvent(element,name,observer,useCapture){
|
||||
if (element.addEventListener) {
|
||||
element.addEventListener(name, observer, useCapture||false);
|
||||
} else if (element.attachEvent) {
|
||||
element.attachEvent('on' + name, observer);
|
||||
}
|
||||
}
|
||||
|
||||
function qstr(text){
|
||||
var temp;
|
||||
temp = text.toString();
|
||||
while (true){
|
||||
if (temp == '') return text;
|
||||
if (temp.indexOf("'") >= 0) break;
|
||||
if (temp.indexOf('"') >= 0) break;
|
||||
if (temp.indexOf(' ') >= 0) break;
|
||||
if (temp.indexOf(',') >= 0) break;
|
||||
return temp;
|
||||
}
|
||||
// temp = temp.replace(/\'/g,"''");
|
||||
// temp = temp.replace(/\"/g,"\"\"");
|
||||
return temp
|
||||
// return "\"" + temp + "\"";
|
||||
}
|
||||
|
||||
function CsvNextToken(dataobj){
|
||||
var i;
|
||||
var text;
|
||||
var c,n;
|
||||
var inside;
|
||||
var value;
|
||||
var q = '';
|
||||
inside = false;
|
||||
value = '';
|
||||
var skip = false;
|
||||
var data=dataobj[0]
|
||||
if (data == '') return '';
|
||||
text = '';
|
||||
for (i = 0; i < data.length; ++i){
|
||||
if (skip){
|
||||
skip = false;
|
||||
continue;
|
||||
}
|
||||
c = data.charAt(i);
|
||||
n = '';
|
||||
if (inside){
|
||||
if (c == q) {
|
||||
if (i < data.length-1) n = data.charAt(i+1);
|
||||
if (n == q){
|
||||
value = value + c;
|
||||
skip = true;
|
||||
continue;
|
||||
}
|
||||
inside = false;
|
||||
continue;
|
||||
}
|
||||
value = value + c;
|
||||
continue;
|
||||
}
|
||||
// if ((c == '"') || (c == "'")){
|
||||
// inside = true;
|
||||
// q = c;
|
||||
// continue;
|
||||
// }
|
||||
if (c == ',') break;
|
||||
value = value + c;
|
||||
}
|
||||
if (i >= (data.length-1)) { dataobj[0]= ''; }
|
||||
else{dataobj[0]=data.substr(i+1);}
|
||||
dataobj[0]=dataobj[0].replace(/^\s+/,"").replace(/\s+$/,"")
|
||||
return value;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
function loadMapPoints(){
|
||||
mappoints=[]
|
||||
lines=document.f.data.value.split("\n")
|
||||
for(var i=0;i<lines.length;i++){
|
||||
lines[i]=lines[i].replace(/\s+$/,"")
|
||||
if(!/^\#/.test(lines[i])&&!/^\s*$/.test(lines[i])){
|
||||
esec=/^\s*\[\s*\d+\s*\]\s*$/.exec(lines[i])
|
||||
if(esec){
|
||||
continue;
|
||||
}
|
||||
e=/^\s*(\w+)\s*=\s*(.*)$/.exec(lines[i])
|
||||
if(!e){
|
||||
alert("Bad line syntax in line "+(i+1))
|
||||
}
|
||||
if(e[1]=="Filename"){
|
||||
o=document.getElementById("map")
|
||||
o.innerHTML='<img name="map" src="Graphics/UI/Town Map/'+e[2]+'" alt="" width="480" height="320"/'+'>'
|
||||
document.mf.filename.value=e[2]
|
||||
} else if(e[1]=="Name"){
|
||||
document.mf.name.value=e[2]
|
||||
} else if(e[1]=="Point"){
|
||||
data=[e[2]]
|
||||
mappt=[]
|
||||
mappt[0]=parseInt(CsvNextToken(data),10)
|
||||
mappt[1]=parseInt(CsvNextToken(data),10)
|
||||
mappt[2]=CsvNextToken(data)
|
||||
mappt[3]=CsvNextToken(data)
|
||||
mappt[4]=[CsvNextToken(data),CsvNextToken(data),CsvNextToken(data)]
|
||||
mappt[5]=CsvNextToken(data)
|
||||
mappoints[mappoints.length]=mappt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createMapPoint(imgfile,x,y){
|
||||
e=document.createElement("div")
|
||||
if(imgfile=="selpoint.bmp"){
|
||||
e.innerHTML="<img src='data:image/bmp;base64,Qk32AAAAAAAAADYAAAAoAAAACAAAAAgAAAABABgAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAAADAAADAAADAAADAAADAAADAAADAAADAAADA////////////////////////AADAAADA////////////////////////AADAAADA////////AADAAADA////////AADAAADA////////AADAAADA////////AADAAADA////////////////////////AADAAADA////////////////////////AADAAADAAADAAADAAADAAADAAADAAADAAAD=' alt=''/>"
|
||||
}
|
||||
if(imgfile=="knownpoint.bmp"){
|
||||
e.innerHTML="<img src='data:image/bmp;base64,Qk32AAAAAAAAADYAAAAoAAAACAAAAAgAAAABABgAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgICA////////////////////////gICAgICA////////////////////////gICAgICA////////////////////////gICAgICA////////////////////////gICAgICA////////////////////////gICAgICA////////////////////////gICAgICAgICAgICAgICAgICAgICAgICAgIC=' alt=''/>"
|
||||
}
|
||||
// e.innerHTML="<img src='"+imgfile+"' alt=''/>"
|
||||
e.style.left=elempos[0]+x*document.mf.sqwidth.value+(document.mf.sqwidth.value-8)/2
|
||||
e.style.top=elempos[1]+y*document.mf.sqheight.value+(document.mf.sqheight.value-8)/2
|
||||
e.style.position="absolute"
|
||||
attachEvent(e,"mousemove",MapMouseMove)
|
||||
attachEvent(e,"click",MapClick)
|
||||
return e
|
||||
}
|
||||
|
||||
function showMapPoints(){
|
||||
for(var i=0;i < mpelements.length ; i++){ //>
|
||||
removeChild(mpelements[i])
|
||||
}
|
||||
mpelements=[]
|
||||
elempos=positionedOffset(document.images.map)
|
||||
for(var i=0;i<mappoints.length;i++){//>
|
||||
e=createMapPoint("knownpoint.bmp",mappoints[i][0],mappoints[i][1])
|
||||
addChild(e)
|
||||
mpelements[mpelements.length]=e
|
||||
}
|
||||
if(choiceX!=-1 || choiceY!=-1){
|
||||
e=createMapPoint("selpoint.bmp",choiceX,choiceY)
|
||||
addChild(e)
|
||||
mpelements[mpelements.length]=e
|
||||
}
|
||||
}
|
||||
|
||||
function MapMouseMove(e){
|
||||
if(choiceX==-1 && choiceY==-1){
|
||||
elempos=elementPosObject(e,document.getElementById("map"))
|
||||
if (elempos[0]>=0 && elempos[0]<480 && elempos[1]>=0 && elempos[1]<320){
|
||||
setMapPoint(Math.floor(elempos[0]/document.mf.sqwidth.value),
|
||||
Math.floor(elempos[1]/document.mf.sqheight.value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function MapClick(e){
|
||||
elempos=elementPosObject(e,document.getElementById("map"))
|
||||
if(elempos[0]>=0 && elempos[0]<480 && elempos[1]>=0 && elempos[1]<320){
|
||||
choiceX=Math.floor(elempos[0]/document.mf.sqwidth.value)
|
||||
choiceY=Math.floor(elempos[1]/document.mf.sqheight.value)
|
||||
setMapPoint(Math.floor(elempos[0]/document.mf.sqwidth.value),
|
||||
Math.floor(elempos[1]/document.mf.sqheight.value))
|
||||
document.f.btnSave.disabled=false
|
||||
showMapPoints()
|
||||
}
|
||||
}
|
||||
|
||||
function getbase(fn){
|
||||
if(fn.lastIndexOf("/")>=0){
|
||||
fn=fn.substr(fn.lastIndexOf("/")+1)
|
||||
}
|
||||
if(fn.lastIndexOf("\\")>=0){
|
||||
fn=fn.substr(fn.lastIndexOf("\\")+1)
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
function genMapPoints(){
|
||||
ret=""
|
||||
ret+="Filename = "+qstr(getbase(document.images.map.src))+"\r\n"
|
||||
ret+="Name = "+qstr(document.mf.name.value)+"\r\n"
|
||||
for(var i=0;i<mappoints.length;i++){
|
||||
ret+="Point = "+[mappoints[i][0],mappoints[i][1],
|
||||
qstr(mappoints[i][2]),qstr(mappoints[i][3]),
|
||||
mappoints[i][4][0]!=null?mappoints[i][4][0]:"",
|
||||
mappoints[i][4][1]!=null?mappoints[i][4][1]:"",
|
||||
mappoints[i][4][2]!=null?mappoints[i][4][2]:"",
|
||||
mappoints[i][5]]+"\r\n"
|
||||
}
|
||||
document.f.data.value=ret
|
||||
showMapPoints()
|
||||
}
|
||||
|
||||
function setMapPoint(x,y){
|
||||
document.f.curpos.value=[x,y]
|
||||
for(var i=0;i<mappoints.length;i++){
|
||||
if(mappoints[i][0]==x && mappoints[i][1]==y){
|
||||
document.f.locname.value=mappoints[i][2]
|
||||
document.f.poi.value=mappoints[i][3]
|
||||
document.f.healing.value=mappoints[i][4]
|
||||
document.f.swtch.value=mappoints[i][5]
|
||||
return
|
||||
}
|
||||
}
|
||||
document.f.locname.value=""
|
||||
document.f.poi.value=""
|
||||
document.f.healing.value=""
|
||||
document.f.swtch.value=""
|
||||
}
|
||||
|
||||
function addMapPoint(x,y){
|
||||
for(var i=0;i<mappoints.length;i++){
|
||||
if(mappoints[i][0]==x && mappoints[i][1]==y){
|
||||
mappoints[i][2]=document.f.locname.value
|
||||
mappoints[i][3]=document.f.poi.value
|
||||
mappoints[i][4]=document.f.healing.value.split(",")
|
||||
mappoints[i][5]=document.f.swtch.value
|
||||
return
|
||||
}
|
||||
}
|
||||
mappoints[mappoints.length]=[x,y,
|
||||
document.f.locname.value,
|
||||
document.f.poi.value,
|
||||
document.f.healing.value.split(","),
|
||||
document.f.swtch.value,
|
||||
]
|
||||
}
|
||||
|
||||
attachEvent(window,"load",function(e){
|
||||
genMapPoints()
|
||||
attachEvent(document.images.map,"mouseout",function(e){
|
||||
if(choiceX==-1 && choiceY==-1){
|
||||
document.f.curpos.value=""
|
||||
}
|
||||
})
|
||||
attachEvent(document.getElementById("map"),"mousemove",MapMouseMove)
|
||||
attachEvent(document.getElementById("map"),"click",MapClick)
|
||||
attachEvent(document.f.btnSave,"click",function(e){
|
||||
if(choiceX!=-1 || choiceY!=-1){
|
||||
addMapPoint(choiceX,choiceY)
|
||||
genMapPoints()
|
||||
target(e).disabled=true
|
||||
choiceX=choiceY=-1
|
||||
showMapPoints()
|
||||
}
|
||||
})
|
||||
attachEvent(document.f.btnCancel,"click",function(e){
|
||||
if(choiceX!=-1||choiceY!=-1){
|
||||
setMapPoint(choiceX,choiceY)
|
||||
choiceX=choiceY=-1
|
||||
showMapPoints()
|
||||
}
|
||||
})
|
||||
attachEvent(document.f.btnLoad,"click",function(e){
|
||||
loadMapPoints()
|
||||
genMapPoints()
|
||||
choiceX=choiceY=-1
|
||||
showMapPoints()
|
||||
})
|
||||
attachEvent(document.mf.btnChange,"click",function(e){
|
||||
document.images.map.src="Graphics/UI/Town Map/"+document.mf.filename.value
|
||||
genMapPoints()
|
||||
showMapPoints()
|
||||
})
|
||||
attachEvent(document.mf.btnChange2,"click",function(e){
|
||||
genMapPoints()
|
||||
showMapPoints()
|
||||
})
|
||||
attachEvent(document.mf.btnRefreshWidth,"click",function(e){
|
||||
choiceX=choiceY=-1
|
||||
document.f.curpos.value=""
|
||||
showMapPoints()
|
||||
})
|
||||
attachEvent(document.mf.btnRefreshHeight,"click",function(e){
|
||||
choiceX=choiceY=-1
|
||||
document.f.curpos.value=""
|
||||
showMapPoints()
|
||||
})
|
||||
})
|
||||
<body>
|
||||
<div>
|
||||
<u>Town Map Generator</u>
|
||||
</div>
|
||||
<form name="mf" action="javascript:void(null)">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Filename:</td>
|
||||
<td><input type="text" name="filename" value="mapRegion0.png"/></td>
|
||||
<td><input type="button" name="btnChange" value="Change"/></td>
|
||||
<td>Name of the region graphic (in Graphics/UI/Town Map/)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name:</td>
|
||||
<td><input type="text" name="name" value="Sample Region"/></td>
|
||||
<td><input type="button" name="btnChange2" value="Change"/></td>
|
||||
<td>Name of the region</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Square width:</td>
|
||||
<td><input type="text" name="sqwidth" size="4" min="1" max="16" value="16"/></td>
|
||||
<td><input type="button" name="btnRefreshWidth" value="Refresh"/></td>
|
||||
<td>Width of each point in the Town Map (in pixels)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Square height:</td>
|
||||
<td><input type="text" name="sqheight" size="4" min="1" max="16" value="16"/></td>
|
||||
<td><input type="button" name="btnRefreshHeight" value="Refresh"/></td>
|
||||
<td>Height of each point in the Town Map (in pixels)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<hr/>
|
||||
<div>
|
||||
<u>Edit point properties</u><br />
|
||||
Click on a point in the Town Map to edit its properties.
|
||||
</div>
|
||||
<div id="map">
|
||||
<img name="map" src="Graphics/UI/Town Map/mapRegion0.png" alt="" width="480" height="320"/>
|
||||
</div>
|
||||
<form name="f" action="javascript:void(null)">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Co-ordinates:</td>
|
||||
<td><input type="text" name="curpos" readonly="readonly"/></td>
|
||||
<td>X and Y co-ordinates of this point in the Town Map (click in the map above)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name:</td>
|
||||
<td><input type="text" name="locname"/></td>
|
||||
<td>Name of this location</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Landmark:</td>
|
||||
<td><input type="text" name="poi"/></td>
|
||||
<td>Name of a landmark found in this location</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Fly destination:</td>
|
||||
<td><input type="text" name="healing"/></td>
|
||||
<td>Map ID, X and Y tile co-ordinates the player will appear at when Flying to this location</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Switch:</td>
|
||||
<td><input type="text" name="swtch"/></td>
|
||||
<td>Number of a Game Switch that needs to be ON to see this point's name/landmark and to Fly to this location</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div>
|
||||
<input type="button" name="btnSave" value="Save" disabled="disabled"/>
|
||||
<input type="button" name="btnCancel" value="Cancel"/><br/ >
|
||||
<hr/>
|
||||
<u>PBS file "town_map.txt" text for this region</u><br />
|
||||
<textarea name="data" rows="10" cols="70"></textarea><br/ >
|
||||
<input type="button" name="btnLoad" value="Load into map"/>
|
||||
Apply the data in this box to the map above<br/ >
|
||||
When you're done, copy this text into "town_map.txt". Remember that it needs a section line (a number in square brackets).
|
||||
</div>
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
choiceX=-1
|
||||
choiceY=-1
|
||||
mappoints=[]
|
||||
mpelements=[]
|
||||
|
||||
function target(event){
|
||||
return event.target||event.srcElement
|
||||
}
|
||||
|
||||
function addChild(e){
|
||||
if(document.documentElement){
|
||||
document.documentElement.appendChild(e)
|
||||
} else{
|
||||
document.body.appendChild(e)
|
||||
}
|
||||
}
|
||||
|
||||
function removeChild(e){
|
||||
if(document.documentElement){
|
||||
document.documentElement.removeChild(e)
|
||||
} else{
|
||||
document.body.removeChild(e)
|
||||
}
|
||||
}
|
||||
|
||||
function positionedOffset(element) {
|
||||
var valueT = 0, valueL = 0;
|
||||
do {
|
||||
valueT += element.offsetTop || 0;
|
||||
valueL += element.offsetLeft || 0;
|
||||
element = element.offsetParent;
|
||||
if (element) {
|
||||
p = element.style.position;
|
||||
if (p == 'relative' || p == 'absolute') break;
|
||||
}
|
||||
} while (element);
|
||||
return [valueL, valueT];
|
||||
}
|
||||
|
||||
function pointerX(event) {
|
||||
return event.pageX || (event.clientX +
|
||||
(document.documentElement.scrollLeft || document.body.scrollLeft));
|
||||
}
|
||||
|
||||
function pointerY(event) {
|
||||
return event.pageY || (event.clientY +
|
||||
(document.documentElement.scrollTop || document.body.scrollTop));
|
||||
}
|
||||
|
||||
function elementPos(event){
|
||||
t=target(event)
|
||||
po=positionedOffset(t)
|
||||
return [(pointerX(event))-po[0],(pointerY(event))-po[1]]
|
||||
}
|
||||
|
||||
function elementPosObject(event,other){
|
||||
t=other
|
||||
po=positionedOffset(t)
|
||||
return [(pointerX(event))-po[0],(pointerY(event))-po[1]]
|
||||
}
|
||||
|
||||
function attachEvent(element,name,observer,useCapture){
|
||||
if (element.addEventListener) {
|
||||
element.addEventListener(name, observer, useCapture||false);
|
||||
} else if (element.attachEvent) {
|
||||
element.attachEvent('on' + name, observer);
|
||||
}
|
||||
}
|
||||
|
||||
function qstr(text){
|
||||
var temp;
|
||||
temp = text.toString();
|
||||
while (true){
|
||||
if (temp == '') return text;
|
||||
if (temp.indexOf("'") >= 0) break;
|
||||
if (temp.indexOf('"') >= 0) break;
|
||||
if (temp.indexOf(' ') >= 0) break;
|
||||
if (temp.indexOf(',') >= 0) break;
|
||||
return temp;
|
||||
}
|
||||
// temp = temp.replace(/\'/g,"''");
|
||||
// temp = temp.replace(/\"/g,"\"\"");
|
||||
return temp
|
||||
// return "\"" + temp + "\"";
|
||||
}
|
||||
|
||||
function CsvNextToken(dataobj){
|
||||
var i;
|
||||
var text;
|
||||
var c,n;
|
||||
var inside;
|
||||
var value;
|
||||
var q = '';
|
||||
inside = false;
|
||||
value = '';
|
||||
var skip = false;
|
||||
var data=dataobj[0]
|
||||
if (data == '') return '';
|
||||
text = '';
|
||||
for (i = 0; i < data.length; ++i){
|
||||
if (skip){
|
||||
skip = false;
|
||||
continue;
|
||||
}
|
||||
c = data.charAt(i);
|
||||
n = '';
|
||||
if (inside){
|
||||
if (c == q) {
|
||||
if (i < data.length-1) n = data.charAt(i+1);
|
||||
if (n == q){
|
||||
value = value + c;
|
||||
skip = true;
|
||||
continue;
|
||||
}
|
||||
inside = false;
|
||||
continue;
|
||||
}
|
||||
value = value + c;
|
||||
continue;
|
||||
}
|
||||
// if ((c == '"') || (c == "'")){
|
||||
// inside = true;
|
||||
// q = c;
|
||||
// continue;
|
||||
// }
|
||||
if (c == ',') break;
|
||||
value = value + c;
|
||||
}
|
||||
if (i >= (data.length-1)) { dataobj[0]= ''; }
|
||||
else{dataobj[0]=data.substr(i+1);}
|
||||
dataobj[0]=dataobj[0].replace(/^\s+/,"").replace(/\s+$/,"")
|
||||
return value;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
function loadMapPoints(){
|
||||
mappoints=[]
|
||||
lines=document.f.data.value.split("\n")
|
||||
for(var i=0;i<lines.length;i++){
|
||||
lines[i]=lines[i].replace(/\s+$/,"")
|
||||
if(!/^\#/.test(lines[i])&&!/^\s*$/.test(lines[i])){
|
||||
esec=/^\s*\[\s*\d+\s*\]\s*$/.exec(lines[i])
|
||||
if(esec){
|
||||
continue;
|
||||
}
|
||||
e=/^\s*(\w+)\s*=\s*(.*)$/.exec(lines[i])
|
||||
if(!e){
|
||||
alert("Bad line syntax in line "+(i+1))
|
||||
}
|
||||
if(e[1]=="Filename"){
|
||||
o=document.getElementById("map")
|
||||
o.innerHTML='<img name="map" src="Graphics/UI/Town Map/'+e[2]+'" alt="" width="480" height="320"/'+'>'
|
||||
document.mf.filename.value=e[2]
|
||||
} else if(e[1]=="Name"){
|
||||
document.mf.name.value=e[2]
|
||||
} else if(e[1]=="Point"){
|
||||
data=[e[2]]
|
||||
mappt=[]
|
||||
mappt[0]=parseInt(CsvNextToken(data),10)
|
||||
mappt[1]=parseInt(CsvNextToken(data),10)
|
||||
mappt[2]=CsvNextToken(data)
|
||||
mappt[3]=CsvNextToken(data)
|
||||
mappt[4]=[CsvNextToken(data),CsvNextToken(data),CsvNextToken(data)]
|
||||
mappt[5]=CsvNextToken(data)
|
||||
mappoints[mappoints.length]=mappt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createMapPoint(imgfile,x,y){
|
||||
e=document.createElement("div")
|
||||
if(imgfile=="selpoint.bmp"){
|
||||
e.innerHTML="<img src='data:image/bmp;base64,Qk32AAAAAAAAADYAAAAoAAAACAAAAAgAAAABABgAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAAADAAADAAADAAADAAADAAADAAADAAADAAADA////////////////////////AADAAADA////////////////////////AADAAADA////////AADAAADA////////AADAAADA////////AADAAADA////////AADAAADA////////////////////////AADAAADA////////////////////////AADAAADAAADAAADAAADAAADAAADAAADAAAD=' alt=''/>"
|
||||
}
|
||||
if(imgfile=="knownpoint.bmp"){
|
||||
e.innerHTML="<img src='data:image/bmp;base64,Qk32AAAAAAAAADYAAAAoAAAACAAAAAgAAAABABgAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgICA////////////////////////gICAgICA////////////////////////gICAgICA////////////////////////gICAgICA////////////////////////gICAgICA////////////////////////gICAgICA////////////////////////gICAgICAgICAgICAgICAgICAgICAgICAgIC=' alt=''/>"
|
||||
}
|
||||
// e.innerHTML="<img src='"+imgfile+"' alt=''/>"
|
||||
e.style.left=elempos[0]+x*document.mf.sqwidth.value+(document.mf.sqwidth.value-8)/2
|
||||
e.style.top=elempos[1]+y*document.mf.sqheight.value+(document.mf.sqheight.value-8)/2
|
||||
e.style.position="absolute"
|
||||
attachEvent(e,"mousemove",MapMouseMove)
|
||||
attachEvent(e,"click",MapClick)
|
||||
return e
|
||||
}
|
||||
|
||||
function showMapPoints(){
|
||||
for(var i=0;i < mpelements.length ; i++){ //>
|
||||
removeChild(mpelements[i])
|
||||
}
|
||||
mpelements=[]
|
||||
elempos=positionedOffset(document.images.map)
|
||||
for(var i=0;i<mappoints.length;i++){//>
|
||||
e=createMapPoint("knownpoint.bmp",mappoints[i][0],mappoints[i][1])
|
||||
addChild(e)
|
||||
mpelements[mpelements.length]=e
|
||||
}
|
||||
if(choiceX!=-1 || choiceY!=-1){
|
||||
e=createMapPoint("selpoint.bmp",choiceX,choiceY)
|
||||
addChild(e)
|
||||
mpelements[mpelements.length]=e
|
||||
}
|
||||
}
|
||||
|
||||
function MapMouseMove(e){
|
||||
if(choiceX==-1 && choiceY==-1){
|
||||
elempos=elementPosObject(e,document.getElementById("map"))
|
||||
if (elempos[0]>=0 && elempos[0]<480 && elempos[1]>=0 && elempos[1]<320){
|
||||
setMapPoint(Math.floor(elempos[0]/document.mf.sqwidth.value),
|
||||
Math.floor(elempos[1]/document.mf.sqheight.value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function MapClick(e){
|
||||
elempos=elementPosObject(e,document.getElementById("map"))
|
||||
if(elempos[0]>=0 && elempos[0]<480 && elempos[1]>=0 && elempos[1]<320){
|
||||
choiceX=Math.floor(elempos[0]/document.mf.sqwidth.value)
|
||||
choiceY=Math.floor(elempos[1]/document.mf.sqheight.value)
|
||||
setMapPoint(Math.floor(elempos[0]/document.mf.sqwidth.value),
|
||||
Math.floor(elempos[1]/document.mf.sqheight.value))
|
||||
document.f.btnSave.disabled=false
|
||||
showMapPoints()
|
||||
}
|
||||
}
|
||||
|
||||
function getbase(fn){
|
||||
if(fn.lastIndexOf("/")>=0){
|
||||
fn=fn.substr(fn.lastIndexOf("/")+1)
|
||||
}
|
||||
if(fn.lastIndexOf("\\")>=0){
|
||||
fn=fn.substr(fn.lastIndexOf("\\")+1)
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
function genMapPoints(){
|
||||
ret=""
|
||||
ret+="Filename = "+qstr(getbase(document.images.map.src))+"\r\n"
|
||||
ret+="Name = "+qstr(document.mf.name.value)+"\r\n"
|
||||
for(var i=0;i<mappoints.length;i++){
|
||||
ret+="Point = "+[mappoints[i][0],mappoints[i][1],
|
||||
qstr(mappoints[i][2]),qstr(mappoints[i][3]),
|
||||
mappoints[i][4][0]!=null?mappoints[i][4][0]:"",
|
||||
mappoints[i][4][1]!=null?mappoints[i][4][1]:"",
|
||||
mappoints[i][4][2]!=null?mappoints[i][4][2]:"",
|
||||
mappoints[i][5]]+"\r\n"
|
||||
}
|
||||
document.f.data.value=ret
|
||||
showMapPoints()
|
||||
}
|
||||
|
||||
function setMapPoint(x,y){
|
||||
document.f.curpos.value=[x,y]
|
||||
for(var i=0;i<mappoints.length;i++){
|
||||
if(mappoints[i][0]==x && mappoints[i][1]==y){
|
||||
document.f.locname.value=mappoints[i][2]
|
||||
document.f.poi.value=mappoints[i][3]
|
||||
document.f.healing.value=mappoints[i][4]
|
||||
document.f.swtch.value=mappoints[i][5]
|
||||
return
|
||||
}
|
||||
}
|
||||
document.f.locname.value=""
|
||||
document.f.poi.value=""
|
||||
document.f.healing.value=""
|
||||
document.f.swtch.value=""
|
||||
}
|
||||
|
||||
function addMapPoint(x,y){
|
||||
for(var i=0;i<mappoints.length;i++){
|
||||
if(mappoints[i][0]==x && mappoints[i][1]==y){
|
||||
mappoints[i][2]=document.f.locname.value
|
||||
mappoints[i][3]=document.f.poi.value
|
||||
mappoints[i][4]=document.f.healing.value.split(",")
|
||||
mappoints[i][5]=document.f.swtch.value
|
||||
return
|
||||
}
|
||||
}
|
||||
mappoints[mappoints.length]=[x,y,
|
||||
document.f.locname.value,
|
||||
document.f.poi.value,
|
||||
document.f.healing.value.split(","),
|
||||
document.f.swtch.value,
|
||||
]
|
||||
}
|
||||
|
||||
attachEvent(window,"load",function(e){
|
||||
genMapPoints()
|
||||
attachEvent(document.images.map,"mouseout",function(e){
|
||||
if(choiceX==-1 && choiceY==-1){
|
||||
document.f.curpos.value=""
|
||||
}
|
||||
})
|
||||
attachEvent(document.getElementById("map"),"mousemove",MapMouseMove)
|
||||
attachEvent(document.getElementById("map"),"click",MapClick)
|
||||
attachEvent(document.f.btnSave,"click",function(e){
|
||||
if(choiceX!=-1 || choiceY!=-1){
|
||||
addMapPoint(choiceX,choiceY)
|
||||
genMapPoints()
|
||||
target(e).disabled=true
|
||||
choiceX=choiceY=-1
|
||||
showMapPoints()
|
||||
}
|
||||
})
|
||||
attachEvent(document.f.btnCancel,"click",function(e){
|
||||
if(choiceX!=-1||choiceY!=-1){
|
||||
setMapPoint(choiceX,choiceY)
|
||||
choiceX=choiceY=-1
|
||||
showMapPoints()
|
||||
}
|
||||
})
|
||||
attachEvent(document.f.btnLoad,"click",function(e){
|
||||
loadMapPoints()
|
||||
genMapPoints()
|
||||
choiceX=choiceY=-1
|
||||
showMapPoints()
|
||||
})
|
||||
attachEvent(document.mf.btnChange,"click",function(e){
|
||||
document.images.map.src="Graphics/UI/Town Map/"+document.mf.filename.value
|
||||
genMapPoints()
|
||||
showMapPoints()
|
||||
})
|
||||
attachEvent(document.mf.btnChange2,"click",function(e){
|
||||
genMapPoints()
|
||||
showMapPoints()
|
||||
})
|
||||
attachEvent(document.mf.btnRefreshWidth,"click",function(e){
|
||||
choiceX=choiceY=-1
|
||||
document.f.curpos.value=""
|
||||
showMapPoints()
|
||||
})
|
||||
attachEvent(document.mf.btnRefreshHeight,"click",function(e){
|
||||
choiceX=choiceY=-1
|
||||
document.f.curpos.value=""
|
||||
showMapPoints()
|
||||
})
|
||||
})
|
||||
</script>
|
||||