This commit is contained in:
2026-03-29 18:31:54 -04:00
parent 877adc8090
commit aad68eb52a
53 changed files with 2035 additions and 886 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Data/Map028.rxdata Normal file

Binary file not shown.

BIN
Data/Map029.rxdata Normal file

Binary file not shown.

BIN
Data/Map030.rxdata Normal file

Binary file not shown.

BIN
Data/Map031.rxdata Normal file

Binary file not shown.

BIN
Data/Map032.rxdata Normal file

Binary file not shown.

BIN
Data/Map033.rxdata Normal file

Binary file not shown.

BIN
Data/Map034.rxdata Normal file

Binary file not shown.

BIN
Data/Map035.rxdata Normal file

Binary file not shown.

BIN
Data/Map036.rxdata Normal file

Binary file not shown.

BIN
Data/Map037.rxdata Normal file

Binary file not shown.

BIN
Data/Map038.rxdata Normal file

Binary file not shown.

BIN
Data/Map039.rxdata Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 490 KiB

After

Width:  |  Height:  |  Size: 494 KiB

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View 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

View File

@@ -0,0 +1,5 @@
Name = Marin's Footprints
Version = 2.0
Essentials = 21.1
Credits = Marin, Jony
Link = https://reliccastle.com/resources/165/

View File

@@ -0,0 +1,5 @@
Name = Marin's Scripting Utilities
Version = 2.0
Essentials = 20
Credits = Marin
Link = https://reliccastle.com/resources/165/

View 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

View File

@@ -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

View File

@@ -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 cant 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 cant 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

View File

@@ -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

View File

@@ -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"/>&nbsp;
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"/>&nbsp;
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>