Merge branch 'dev' into ai

This commit is contained in:
Maruno17
2022-10-04 22:56:27 +01:00
56 changed files with 2341 additions and 912 deletions

View File

@@ -154,7 +154,7 @@ Style/SymbolArray:
Style/WordArray: Style/WordArray:
EnforcedStyle: brackets EnforcedStyle: brackets
# Patentheses around the condition in a ternary operator helps to differentiate # Parentheses around the condition in a ternary operator helps to differentiate
# it from the true/false results. # it from the true/false results.
Style/TernaryParentheses: Style/TernaryParentheses:
EnforcedStyle: require_parentheses EnforcedStyle: require_parentheses

View File

@@ -359,7 +359,7 @@ class CallbackWrapper
def execute(given_block = nil, *args) def execute(given_block = nil, *args)
execute_block = given_block || @code_block execute_block = given_block || @code_block
@params.each do |key, value| @params.each do |key, value|
args.instance_variable_set("@#{key.to_s}", value) args.instance_variable_set("@#{key}", value)
end end
args.instance_eval(&execute_block) args.instance_eval(&execute_block)
end end

View File

@@ -627,7 +627,11 @@ module PluginManager
# get the order of plugins to interpret # get the order of plugins to interpret
order, plugins = self.getPluginOrder order, plugins = self.getPluginOrder
# compile if necessary # compile if necessary
self.compilePlugins(order, plugins) if self.needCompiling?(order, plugins) if self.needCompiling?(order, plugins)
self.compilePlugins(order, plugins)
else
Console.echoln_li "Plugins were not compiled."
end
# load plugins # load plugins
scripts = load_data("Data/PluginScripts.rxdata") scripts = load_data("Data/PluginScripts.rxdata")
echoed_plugins = [] echoed_plugins = []

View File

@@ -79,19 +79,4 @@ module SaveData
end end
return hash return hash
end end
# Moves a save file from the old Saved Games folder to the new
# location specified by {FILE_PATH}. Does nothing if a save file
# already exists in {FILE_PATH}.
def self.move_old_windows_save
return if File.file?(FILE_PATH)
game_title = System.game_title.gsub(/[^\w ]/, "_")
home = ENV["HOME"] || ENV["HOMEPATH"]
return if home.nil?
old_location = File.join(home, "Saved Games", game_title)
return unless File.directory?(old_location)
old_file = File.join(old_location, "Game.rxdata")
return unless File.file?(old_file)
File.move(old_file, FILE_PATH)
end
end end

View File

@@ -202,7 +202,7 @@ module SaveData
validate id => Symbol validate id => Symbol
@values.delete_if { |value| value.id == id } @values.delete_if { |value| value.id == id }
end end
# @param save_data [Hash] save data to validate # @param save_data [Hash] save data to validate
# @return [Boolean] whether the given save data is valid # @return [Boolean] whether the given save data is valid
def self.valid?(save_data) def self.valid?(save_data)

View File

@@ -19,7 +19,6 @@ module Game
# Loads bootup data from save file (if it exists) or creates bootup data (if # Loads bootup data from save file (if it exists) or creates bootup data (if
# it doesn't). # it doesn't).
def self.set_up_system def self.set_up_system
SaveData.move_old_windows_save if System.platform[/Windows/]
save_data = (SaveData.exists?) ? SaveData.read_from_file(SaveData::FILE_PATH) : {} save_data = (SaveData.exists?) ? SaveData.read_from_file(SaveData::FILE_PATH) : {}
if save_data.empty? if save_data.empty?
SaveData.initialize_bootup_values SaveData.initialize_bootup_values

View File

@@ -474,7 +474,7 @@ class Game_Player < Game_Character
if !@moved_last_frame || @stopped_last_frame # Started a new step if !@moved_last_frame || @stopped_last_frame # Started a new step
if pbTerrainTag.ice if pbTerrainTag.ice
set_movement_type(:ice_sliding) set_movement_type(:ice_sliding)
else#if !@move_route_forcing else
faster = can_run? faster = can_run?
if $PokemonGlobal&.diving if $PokemonGlobal&.diving
set_movement_type((faster) ? :diving_fast : :diving) set_movement_type((faster) ? :diving_fast : :diving)

View File

@@ -278,14 +278,8 @@ class Game_FollowerFactory
facing_tile = $map_factory.getFacingTile facing_tile = $map_factory.getFacingTile
# Assumes player is 1x1 tile in size # Assumes player is 1x1 tile in size
each_follower do |event, follower| each_follower do |event, follower|
if event.at_coordinate?($game_player.x, $game_player.y) # Underneath player next if !facing_tile || event.map.map_id != facing_tile[0] ||
next if !event.over_trigger? !event.at_coordinate?(facing_tile[1], facing_tile[2]) # Not on facing tile
elsif facing_tile && event.map.map_id == facing_tile[0] &&
event.at_coordinate?(facing_tile[1], facing_tile[2]) # On facing tile
next if event.over_trigger?
else # Somewhere else
next
end
next if event.jumping? next if event.jumping?
follower.interact(event) follower.interact(event)
end end

View File

@@ -37,23 +37,38 @@ class TileDrawingHelper
36, 24, 36, 24, 21, 6, 21, 4, 36, 24, 36, 24, 20, 2, 20, 0 36, 24, 36, 24, 21, 6, 21, 4, 36, 24, 36, 24, 20, 2, 20, 0
] ]
def self.tableNeighbors(data, x, y) def self.tableNeighbors(data, x, y, layer = nil)
return 0 if x < 0 || x >= data.xsize return 0 if x < 0 || x >= data.xsize
return 0 if y < 0 || y >= data.ysize return 0 if y < 0 || y >= data.ysize
t = data[x, y] if layer.nil?
t = data[x, y]
else
t = data[x, y, layer]
end
xp1 = [x + 1, data.xsize - 1].min xp1 = [x + 1, data.xsize - 1].min
yp1 = [y + 1, data.ysize - 1].min yp1 = [y + 1, data.ysize - 1].min
xm1 = [x - 1, 0].max xm1 = [x - 1, 0].max
ym1 = [y - 1, 0].max ym1 = [y - 1, 0].max
i = 0 i = 0
i |= 0x01 if data[x, ym1] == t # N if layer.nil?
i |= 0x02 if data[xp1, ym1] == t # NE i |= 0x01 if data[ x, ym1] == t # N
i |= 0x04 if data[xp1, y] == t # E i |= 0x02 if data[xp1, ym1] == t # NE
i |= 0x08 if data[xp1, yp1] == t # SE i |= 0x04 if data[xp1, y] == t # E
i |= 0x10 if data[x, yp1] == t # S i |= 0x08 if data[xp1, yp1] == t # SE
i |= 0x20 if data[xm1, yp1] == t # SW i |= 0x10 if data[ x, yp1] == t # S
i |= 0x40 if data[xm1, y] == t # W i |= 0x20 if data[xm1, yp1] == t # SW
i |= 0x80 if data[xm1, ym1] == t # NW i |= 0x40 if data[xm1, y] == t # W
i |= 0x80 if data[xm1, ym1] == t # NW
else
i |= 0x01 if data[ x, ym1, layer] == t # N
i |= 0x02 if data[xp1, ym1, layer] == t # NE
i |= 0x04 if data[xp1, y, layer] == t # E
i |= 0x08 if data[xp1, yp1, layer] == t # SE
i |= 0x10 if data[ x, yp1, layer] == t # S
i |= 0x20 if data[xm1, yp1, layer] == t # SW
i |= 0x40 if data[xm1, y, layer] == t # W
i |= 0x80 if data[xm1, ym1, layer] == t # NW
end
return i return i
end end

View File

@@ -935,58 +935,67 @@ def drawBitmapBuffer(chars)
end end
def drawSingleFormattedChar(bitmap, ch) def drawSingleFormattedChar(bitmap, ch)
if ch[5] # If a graphic if ch[5] # If a graphic
graphic = Bitmap.new(ch[0]) graphic = Bitmap.new(ch[0])
graphicRect = ch[15] graphicRect = ch[15]
bitmap.blt(ch[1], ch[2], graphic, graphicRect, ch[8].alpha) bitmap.blt(ch[1], ch[2], graphic, graphicRect, ch[8].alpha)
graphic.dispose graphic.dispose
return
end
bitmap.font.bold = ch[6] if bitmap.font.bold != ch[6]
bitmap.font.italic = ch[7] if bitmap.font.italic != ch[7]
bitmap.font.name = ch[12] if bitmap.font.name != ch[12]
bitmap.font.size = ch[13] if bitmap.font.size != ch[13]
if ch[9] # shadow
if ch[10] # underline
bitmap.fill_rect(ch[1], ch[2] + ch[4] - [(ch[4] - bitmap.font.size) / 2, 0].max - 2,
ch[3], 4, ch[9])
end
if ch[11] # strikeout
bitmap.fill_rect(ch[1], ch[2] + 2 + (ch[4] / 2), ch[3], 4, ch[9])
end
end
if ch[0] == "\n" || ch[0] == "\r" || ch[0] == " " || isWaitChar(ch[0])
bitmap.font.color = ch[8] if bitmap.font.color != ch[8]
else else
bitmap.font.size = ch[13] if bitmap.font.size != ch[13] offset = 0
if ch[0] != "\n" && ch[0] != "\r" && ch[0] != " " && !isWaitChar(ch[0]) if ch[9] # shadow
bitmap.font.bold = ch[6] if bitmap.font.bold != ch[6] bitmap.font.color = ch[9]
bitmap.font.italic = ch[7] if bitmap.font.italic != ch[7] if (ch[16] & 1) != 0 # outline
bitmap.font.name = ch[12] if bitmap.font.name != ch[12] offset = 1
offset = 0 bitmap.draw_text(ch[1], ch[2], ch[3] + 2, ch[4], ch[0])
if ch[9] # shadow bitmap.draw_text(ch[1], ch[2] + 1, ch[3] + 2, ch[4], ch[0])
bitmap.font.color = ch[9] bitmap.draw_text(ch[1], ch[2] + 2, ch[3] + 2, ch[4], ch[0])
if (ch[16] & 1) != 0 # outline bitmap.draw_text(ch[1] + 1, ch[2], ch[3] + 2, ch[4], ch[0])
offset = 1 bitmap.draw_text(ch[1] + 1, ch[2] + 2, ch[3] + 2, ch[4], ch[0])
bitmap.draw_text(ch[1], ch[2], ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2], ch[3] + 2, ch[4], ch[0])
bitmap.draw_text(ch[1], ch[2] + 1, ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2] + 1, ch[3] + 2, ch[4], ch[0])
bitmap.draw_text(ch[1], ch[2] + 2, ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2] + 2, ch[3] + 2, ch[4], ch[0])
bitmap.draw_text(ch[1] + 1, ch[2], ch[3] + 2, ch[4], ch[0]) elsif (ch[16] & 2) != 0 # outline 2
bitmap.draw_text(ch[1] + 1, ch[2] + 2, ch[3] + 2, ch[4], ch[0]) offset = 2
bitmap.draw_text(ch[1] + 2, ch[2], ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1], ch[2], ch[3] + 4, ch[4], ch[0])
bitmap.draw_text(ch[1] + 2, ch[2] + 1, ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1], ch[2] + 2, ch[3] + 4, ch[4], ch[0])
bitmap.draw_text(ch[1] + 2, ch[2] + 2, ch[3] + 2, ch[4], ch[0]) bitmap.draw_text(ch[1], ch[2] + 4, ch[3] + 4, ch[4], ch[0])
elsif (ch[16] & 2) != 0 # outline 2 bitmap.draw_text(ch[1] + 2, ch[2], ch[3] + 4, ch[4], ch[0])
offset = 2 bitmap.draw_text(ch[1] + 2, ch[2] + 4, ch[3] + 4, ch[4], ch[0])
bitmap.draw_text(ch[1], ch[2], ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1] + 4, ch[2], ch[3] + 4, ch[4], ch[0])
bitmap.draw_text(ch[1], ch[2] + 2, ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1] + 4, ch[2] + 2, ch[3] + 4, ch[4], ch[0])
bitmap.draw_text(ch[1], ch[2] + 4, ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1] + 4, ch[2] + 4, ch[3] + 4, ch[4], ch[0])
bitmap.draw_text(ch[1] + 2, ch[2], ch[3] + 4, ch[4], ch[0]) else
bitmap.draw_text(ch[1] + 2, ch[2] + 4, ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2], ch[3] + 2, ch[4], ch[0])
bitmap.draw_text(ch[1] + 4, ch[2], ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1], ch[2] + 2, ch[3] + 2, ch[4], ch[0])
bitmap.draw_text(ch[1] + 4, ch[2] + 2, ch[3] + 4, ch[4], ch[0]) bitmap.draw_text(ch[1] + 2, ch[2] + 2, ch[3] + 2, ch[4], ch[0])
bitmap.draw_text(ch[1] + 4, ch[2] + 4, ch[3] + 4, ch[4], ch[0])
else
bitmap.draw_text(ch[1] + 2, ch[2], ch[3] + 2, ch[4], ch[0])
bitmap.draw_text(ch[1], ch[2] + 2, ch[3] + 2, ch[4], ch[0])
bitmap.draw_text(ch[1] + 2, ch[2] + 2, ch[3] + 2, ch[4], ch[0])
end
end end
bitmap.font.color = ch[8] if bitmap.font.color != ch[8]
bitmap.draw_text(ch[1] + offset, ch[2] + offset, ch[3], ch[4], ch[0])
elsif bitmap.font.color != ch[8]
bitmap.font.color = ch[8]
end
if ch[10] # underline
bitmap.fill_rect(ch[1], ch[2] + ch[4] - 4 - [(ch[4] - bitmap.font.size) / 2, 0].max - 2,
ch[3] - 2, 2, ch[8])
end
if ch[11] # strikeout
bitmap.fill_rect(ch[1], ch[2] + (ch[4] / 2) - 4, ch[3] - 2, 2, ch[8])
end end
bitmap.font.color = ch[8] if bitmap.font.color != ch[8]
bitmap.draw_text(ch[1] + offset, ch[2] + offset, ch[3], ch[4], ch[0])
end
if ch[10] # underline
bitmap.fill_rect(ch[1], ch[2] + ch[4] - [(ch[4] - bitmap.font.size) / 2, 0].max - 2,
ch[3] - 2, 2, ch[8])
end
if ch[11] # strikeout
bitmap.fill_rect(ch[1], ch[2] + 2 + (ch[4] / 2), ch[3] - 2, 2, ch[8])
end end
end end

View File

@@ -819,7 +819,7 @@ def pbShowCommandsWithHelp(msgwindow, commands, help, cmdIfCancel = 0, defaultCm
Input.update Input.update
end end
msgwin.letterbyletter = oldlbl msgwin.letterbyletter = oldlbl
msgwin.dispose if !msgwindow pbDisposeMessageWindow(msgwin) if !msgwindow
return ret return ret
end end

View File

@@ -240,5 +240,8 @@ module GameData
Metadata.load Metadata.load
PlayerMetadata.load PlayerMetadata.load
MapMetadata.load MapMetadata.load
DungeonTileset.load
DungeonParameters.load
PhoneMessage.load
end end
end end

View File

@@ -3,7 +3,6 @@
#=============================================================================== #===============================================================================
class Game_Temp class Game_Temp
attr_accessor :town_map_data attr_accessor :town_map_data
attr_accessor :phone_messages_data
attr_accessor :regional_dexes_data attr_accessor :regional_dexes_data
attr_accessor :battle_animations_data attr_accessor :battle_animations_data
attr_accessor :move_to_battle_animation_data attr_accessor :move_to_battle_animation_data
@@ -13,7 +12,6 @@ end
def pbClearData def pbClearData
if $game_temp if $game_temp
$game_temp.town_map_data = nil $game_temp.town_map_data = nil
$game_temp.phone_messages_data = nil
$game_temp.regional_dexes_data = nil $game_temp.regional_dexes_data = nil
$game_temp.battle_animations_data = nil $game_temp.battle_animations_data = nil
$game_temp.move_to_battle_animation_data = nil $game_temp.move_to_battle_animation_data = nil
@@ -37,17 +35,6 @@ def pbLoadTownMapData
return $game_temp.town_map_data return $game_temp.town_map_data
end end
#===============================================================================
# Method to get phone call data.
#===============================================================================
def pbLoadPhoneData
$game_temp = Game_Temp.new if !$game_temp
if !$game_temp.phone_messages_data && pbRgssExists?("Data/phone.dat")
$game_temp.phone_messages_data = load_data("Data/phone.dat")
end
return $game_temp.phone_messages_data
end
#=============================================================================== #===============================================================================
# Method to get Regional Dexes data. # Method to get Regional Dexes data.
#=============================================================================== #===============================================================================

View File

@@ -1,24 +0,0 @@
#===============================================================================
# Phone data
#===============================================================================
class PhoneDatabase
attr_accessor :generics
attr_accessor :greetings
attr_accessor :greetingsMorning
attr_accessor :greetingsEvening
attr_accessor :bodies1
attr_accessor :bodies2
attr_accessor :battleRequests
attr_accessor :trainers
def initialize
@generics = []
@greetings = []
@greetingsMorning = []
@greetingsEvening = []
@bodies1 = []
@bodies2 = []
@battleRequests = []
@trainers = []
end
end

View File

@@ -57,6 +57,11 @@ module GameData
return (ret) ? ret : pbResolveBitmap("Graphics/Pokemon/Eggs/000") return (ret) ? ret : pbResolveBitmap("Graphics/Pokemon/Eggs/000")
end end
def self.egg_cracks_sprite_filename(species, form)
ret = self.check_egg_graphic_file("Graphics/Pokemon/Eggs/", species, form, "_cracks")
return (ret) ? ret : pbResolveBitmap("Graphics/Pokemon/Eggs/000_cracks")
end
def self.sprite_filename(species, form = 0, gender = 0, shiny = false, shadow = false, back = false, egg = false) def self.sprite_filename(species, form = 0, gender = 0, shiny = false, shadow = false, back = false, egg = false)
return self.egg_sprite_filename(species, form) if egg return self.egg_sprite_filename(species, form) if egg
return self.back_sprite_filename(species, form, gender, shiny, shadow) if back return self.back_sprite_filename(species, form, gender, shiny, shadow) if back

View File

@@ -0,0 +1,209 @@
module GameData
class DungeonTileset
attr_reader :id
attr_reader :tile_type_ids
attr_reader :snap_to_large_grid # "large" means 2x2 tiles
attr_reader :large_void_tiles # "large" means 2x2 tiles
attr_reader :large_wall_tiles # "large" means 1x2 or 2x1 tiles depending on side
attr_reader :large_floor_tiles # "large" means 2x2 tiles
attr_reader :double_walls
attr_reader :floor_patch_under_walls
attr_reader :thin_north_wall_offset
attr_reader :flags
DATA = {}
DATA_FILENAME = "dungeon_tilesets.dat"
SCHEMA = {
"Autotile" => [:autotile, "us"],
"Tile" => [:tile, "us"],
"SnapToLargeGrid" => [:snap_to_large_grid, "b"],
"LargeVoidTiles" => [:large_void_tiles, "b"],
"LargeWallTiles" => [:large_wall_tiles, "b"],
"LargeFloorTiles" => [:large_floor_tiles, "b"],
"DoubleWalls" => [:double_walls, "b"],
"FloorPatchUnderWalls" => [:floor_patch_under_walls, "b"],
"ThinNorthWallOffset" => [:thin_north_wall_offset, "i"],
"Flags" => [:flags, "*s"]
}
extend ClassMethodsIDNumbers
include InstanceMethods
# @param other [self, Integer]
# @return [self]
def self.try_get(other)
validate other => [Integer, self]
return other if other.is_a?(self)
return (self::DATA.has_key?(other)) ? self::DATA[other] : self.get(self::DATA.keys.first)
end
def initialize(hash)
@id = hash[:id]
@snap_to_large_grid = hash[:snap_to_large_grid] || false
@large_void_tiles = hash[:large_void_tiles] || false
@large_wall_tiles = hash[:large_wall_tiles] || false
@large_floor_tiles = hash[:large_floor_tiles] || false
@double_walls = hash[:double_walls] || false
@floor_patch_under_walls = hash[:floor_patch_under_walls] || false
@thin_north_wall_offset = hash[:thin_north_wall_offset] || 0
@flags = hash[:flags] || []
@tile_type_ids = {}
set_tile_type_ids(hash)
end
def set_tile_type_ids(hash)
[hash[:autotile], hash[:tile]].each_with_index do |array, i|
array.each do |tile_info|
next if !tile_info
tile_type = tile_info[1].downcase.to_sym
if tile_type == :walls
if @double_walls
if @large_wall_tiles
push_tile(:wall_1, 384 + tile_info[0] + 33)
push_tile(:wall_2, 384 + tile_info[0] + 34)
push_tile(:wall_3, 384 + tile_info[0] + 36)
push_tile(:wall_4, 384 + tile_info[0] + 17)
push_tile(:wall_6, 384 + tile_info[0] + 20)
push_tile(:wall_7, 384 + tile_info[0] + 9)
push_tile(:wall_8, 384 + tile_info[0] + 10)
push_tile(:wall_9, 384 + tile_info[0] + 12)
push_tile(:wall_in_1, 384 + tile_info[0] + 23)
push_tile(:wall_in_3, 384 + tile_info[0] + 22)
push_tile(:wall_in_7, 384 + tile_info[0] + 31)
push_tile(:wall_in_9, 384 + tile_info[0] + 30)
push_tile(:upper_wall_1, 384 + tile_info[0] + 40)
push_tile(:upper_wall_2, 384 + tile_info[0] + 42)
push_tile(:upper_wall_3, 384 + tile_info[0] + 45)
push_tile(:upper_wall_4, 384 + tile_info[0] + 16)
push_tile(:upper_wall_6, 384 + tile_info[0] + 21)
push_tile(:upper_wall_7, 384 + tile_info[0] + 0)
push_tile(:upper_wall_8, 384 + tile_info[0] + 2)
push_tile(:upper_wall_9, 384 + tile_info[0] + 5)
push_tile(:upper_wall_in_1, 384 + tile_info[0] + 7)
push_tile(:upper_wall_in_3, 384 + tile_info[0] + 6)
push_tile(:upper_wall_in_7, 384 + tile_info[0] + 15)
push_tile(:upper_wall_in_9, 384 + tile_info[0] + 14)
else
push_tile(:wall_1, 384 + tile_info[0] + 25)
push_tile(:wall_2, 384 + tile_info[0] + 26)
push_tile(:wall_3, 384 + tile_info[0] + 27)
push_tile(:wall_4, 384 + tile_info[0] + 17)
push_tile(:wall_6, 384 + tile_info[0] + 19)
push_tile(:wall_7, 384 + tile_info[0] + 9)
push_tile(:wall_8, 384 + tile_info[0] + 10)
push_tile(:wall_9, 384 + tile_info[0] + 11)
push_tile(:wall_in_1, 384 + tile_info[0] + 22)
push_tile(:wall_in_3, 384 + tile_info[0] + 21)
push_tile(:wall_in_7, 384 + tile_info[0] + 30)
push_tile(:wall_in_9, 384 + tile_info[0] + 29)
push_tile(:upper_wall_1, 384 + tile_info[0] + 32)
push_tile(:upper_wall_2, 384 + tile_info[0] + 34)
push_tile(:upper_wall_3, 384 + tile_info[0] + 36)
push_tile(:upper_wall_4, 384 + tile_info[0] + 16)
push_tile(:upper_wall_6, 384 + tile_info[0] + 20)
push_tile(:upper_wall_7, 384 + tile_info[0] + 0)
push_tile(:upper_wall_8, 384 + tile_info[0] + 2)
push_tile(:upper_wall_9, 384 + tile_info[0] + 4)
push_tile(:upper_wall_in_1, 384 + tile_info[0] + 6)
push_tile(:upper_wall_in_3, 384 + tile_info[0] + 5)
push_tile(:upper_wall_in_7, 384 + tile_info[0] + 14)
push_tile(:upper_wall_in_9, 384 + tile_info[0] + 13)
end
elsif @large_wall_tiles
push_tile(:wall_1, 384 + tile_info[0] + 24)
push_tile(:wall_2, 384 + tile_info[0] + 25)
push_tile(:wall_3, 384 + tile_info[0] + 27)
push_tile(:wall_4, 384 + tile_info[0] + 8)
push_tile(:wall_6, 384 + tile_info[0] + 11)
push_tile(:wall_7, 384 + tile_info[0] + 0)
push_tile(:wall_8, 384 + tile_info[0] + 1)
push_tile(:wall_9, 384 + tile_info[0] + 3)
push_tile(:wall_in_1, 384 + tile_info[0] + 5)
push_tile(:wall_in_3, 384 + tile_info[0] + 4)
push_tile(:wall_in_7, 384 + tile_info[0] + 13)
push_tile(:wall_in_9, 384 + tile_info[0] + 12)
else
push_tile(:wall_1, 384 + tile_info[0] + 16)
push_tile(:wall_2, 384 + tile_info[0] + 17)
push_tile(:wall_3, 384 + tile_info[0] + 18)
push_tile(:wall_4, 384 + tile_info[0] + 8)
push_tile(:wall_6, 384 + tile_info[0] + 10)
push_tile(:wall_7, 384 + tile_info[0] + 0)
push_tile(:wall_8, 384 + tile_info[0] + 1)
push_tile(:wall_9, 384 + tile_info[0] + 2)
push_tile(:wall_in_1, 384 + tile_info[0] + 4)
push_tile(:wall_in_3, 384 + tile_info[0] + 3)
push_tile(:wall_in_7, 384 + tile_info[0] + 12)
push_tile(:wall_in_9, 384 + tile_info[0] + 11)
end
end
id = (i == 0) ? tile_info[0] * 48 : 384 + tile_info[0]
push_tile(tile_type, id, false)
end
end
end
def push_tile(tile_type, id, auto = true)
@tile_type_ids[tile_type] ||= []
@tile_type_ids[tile_type].push([id, auto])
end
def has_flag?(flag)
return @flags.any? { |f| f.downcase == flag.downcase }
end
def has_decoration?(deco)
return @tile_type_ids.include?(deco) && @tile_type_ids[deco].length > 0
end
def get_random_tile_of_type(tile_type, dungeon, x, y, layer)
tiles = @tile_type_ids[tile_type]
return 0 if !tiles || tiles.empty?
ret = tiles.sample[0]
if ret < 384 # Autotile
nb = TileDrawingHelper.tableNeighbors(dungeon, x, y, layer)
variant = TileDrawingHelper::NEIGHBORS_TO_AUTOTILE_INDEX[nb]
ret += variant
else
case tile_type
when :void
if @large_void_tiles
ret += 1 if x.odd?
ret += 8 if y.odd?
end
when :floor
if large_floor_tiles
ret += 1 if x.odd?
ret += 8 if y.odd?
end
when :wall_2, :wall_8, :wall_top
ret += 1 if @large_wall_tiles && x.odd?
when :wall_4, :wall_6
ret += 8 if @large_wall_tiles && y.odd?
end
# Different wall tiles for northern walls if there's another wall directly
# north of them (i.e. tree tiles that shouldn't have shaded grass because
# there isn't a tree-enclosed area there)
if @thin_north_wall_offset != 0 && [:wall_7, :wall_8, :wall_9].include?(tile_type)
ret += @thin_north_wall_offset if dungeon.tile_is_wall?(dungeon[x, y - 1, 1])
end
end
return ret
end
def property_from_string(str)
case str
when "SnapToLargeGrid" then return @snap_to_large_grid
when "LargeVoidTiles" then return @large_void_tiles
when "LargeWallTiles" then return @large_wall_tiles
when "LargeFloorTiles" then return @large_floor_tiles
when "DoubleWalls" then return @double_walls
when "FloorPatchUnderWalls" then return @floor_patch_under_walls
when "ThinNorthWallOffset" then return @thin_north_wall_offset
when "Flags" then return @flags
end
return nil
end
end
end

View File

@@ -0,0 +1,138 @@
# TODO: Add tileset number in here?
module GameData
class DungeonParameters
attr_reader :id, :area, :version
attr_reader :cell_count_x, :cell_count_y
attr_reader :cell_width, :cell_height
attr_reader :room_min_width, :room_min_height
attr_reader :room_max_width, :room_max_height
attr_reader :corridor_width, :random_corridor_shift
# Layouts:
# :full - every node in the map
# :no_corners - every node except for one in each corner
# :ring - every node around the edge of the map
# :antiring - every node except one that touches an edge of the map
# :plus - every node in a plus (+) shape
# :diagonal_up - every node in a line from bottom left to top right (/)
# :diagonal_down - every node in a line from top left to bottom right (\)
# :cross - every node in a cross (x) shape
# :quadrants - every node except the middles of each edge (i.e. each corner bulges out)
attr_reader :node_layout, :room_layout
attr_reader :room_chance # Percentage of active roomable nodes that will become rooms
attr_reader :extra_connections_count
attr_reader :floor_patch_radius, :floor_patch_chance, :floor_patch_smooth_rate
attr_reader :floor_decoration_density, :floor_decoration_large_density
attr_reader :void_decoration_density, :void_decoration_large_density
attr_reader :rng_seed
attr_reader :flags
DATA = {}
DATA_FILENAME = "dungeon_parameters.dat"
SCHEMA = {
"DungeonSize" => [:dungeon_size, "vv"],
"CellSize" => [:cell_size, "vv"],
"MinRoomSize" => [:min_room_size, "vv"],
"MaxRoomSize" => [:max_room_size, "vv"],
"CorridorWidth" => [:corridor_width, "v"],
"ShiftCorridors" => [:shift_corridors, "b"],
"NodeLayout" => [:node_layout, "s"],
"RoomLayout" => [:room_layout, "s"],
"RoomChance" => [:room_chance, "v"],
"ExtraConnections" => [:extra_connections_count, "u"],
"FloorPatches" => [:floor_patches, "vvu"],
"FloorDecorations" => [:floor_decorations, "uu"],
"VoidDecorations" => [:void_decorations, "uu"],
"RNGSeed" => [:rng_seed, "u"],
"Flags" => [:flags, "*s"]
}
extend ClassMethodsSymbols
include InstanceMethods
# @param other [Symbol, String, self]
# @param version [Integer]
# @return [self]
def self.try_get(area, version = 0)
validate area => [Symbol, self, String]
validate version => Integer
area = area.id if area.is_a?(self)
area = area.to_sym if area.is_a?(String)
trial = sprintf("%s_%d", area, version).to_sym
area_version = (DATA[trial].nil?) ? area : trial
return (DATA.has_key?(area_version)) ? DATA[area_version] : self.new({})
end
def initialize(hash)
@id = hash[:id]
@area = hash[:area]
@version = hash[:version] || 0
@cell_count_x = (hash[:dungeon_size]) ? hash[:dungeon_size][0] : 5
@cell_count_y = (hash[:dungeon_size]) ? hash[:dungeon_size][1] : 5
@cell_width = (hash[:cell_size]) ? hash[:cell_size][0] : 10
@cell_height = (hash[:cell_size]) ? hash[:cell_size][1] : 10
@room_min_width = (hash[:min_room_size]) ? hash[:min_room_size][0] : 5
@room_min_height = (hash[:min_room_size]) ? hash[:min_room_size][1] : 5
@room_max_width = (hash[:max_room_size]) ? hash[:max_room_size][0] : @cell_width - 1
@room_max_height = (hash[:max_room_size]) ? hash[:max_room_size][1] : @cell_height - 1
@corridor_width = hash[:corridor_width] || 2
@random_corridor_shift = hash[:shift_corridors]
@node_layout = hash[:node_layout]&.downcase&.to_sym || :full
@room_layout = hash[:room_layout]&.downcase&.to_sym || :full
@room_chance = hash[:room_chance] || 70
@extra_connections_count = hash[:extra_connections_count] || 2
@floor_patch_radius = (hash[:floor_patches]) ? hash[:floor_patches][0] : 3
@floor_patch_chance = (hash[:floor_patches]) ? hash[:floor_patches][1] : 75
@floor_patch_smooth_rate = (hash[:floor_patches]) ? hash[:floor_patches][2] : 25
@floor_decoration_density = (hash[:floor_decorations]) ? hash[:floor_decorations][0] : 50
@floor_decoration_large_density = (hash[:floor_decorations]) ? hash[:floor_decorations][1] : 200
@void_decoration_density = (hash[:void_decorations]) ? hash[:void_decorations][0] : 50
@void_decoration_large_density = (hash[:void_decorations]) ? hash[:void_decorations][1] : 200
@rng_seed = hash[:rng_seed]
@flags = hash[:flags] || []
end
def has_flag?(flag)
return @flags.any? { |f| f.downcase == flag.downcase }
end
def rand_cell_center
x = (@cell_width / 2) + rand(-2..2)
y = (@cell_height / 2) + rand(-2..2)
return x, y
end
def rand_room_size
width = @room_min_width
if @room_max_width > @room_min_width
width = rand(@room_min_width..@room_max_width)
end
height = @room_min_height
if @room_max_height > @room_min_height
height = rand(@room_min_height..@room_max_height)
end
return width, height
end
def property_from_string(str)
case str
when "DungeonSize" then return [@cell_count_x, @cell_count_y]
when "CellSize" then return [@cell_width, @cell_height]
when "MinRoomSize" then return [@room_min_width, @room_min_height]
when "MaxRoomSize" then return [@room_max_width, @room_max_height]
when "CorridorWidth" then return @corridor_width
when "ShiftCorridors" then return @random_corridor_shift
when "NodeLayout" then return @node_layout
when "RoomLayout" then return @room_layout
when "RoomChance" then return @room_chance
when "ExtraConnections" then return @extra_connections_count
when "FloorPatches" then return [@floor_patch_radius, @floor_patch_chance, @floor_patch_smooth_rate]
when "FloorDecorations" then return [@floor_decoration_density, @floor_decoration_large_density]
when "VoidDecorations" then return [@void_decoration_density, @void_decoration_large_density]
when "RNGSeed" then return @rng_seed
when "Flags" then return @flags
end
return nil
end
end
end

View File

@@ -0,0 +1,96 @@
module GameData
class PhoneMessage
attr_reader :id
attr_reader :trainer_type, :real_name, :version
attr_reader :intro, :intro_morning, :intro_afternoon, :intro_evening
attr_reader :body, :body1, :body2
attr_reader :battle_request, :battle_remind
attr_reader :end
DATA = {}
DATA_FILENAME = "phone.dat"
SCHEMA = {
"Intro" => [:intro, "q"],
"IntroMorning" => [:intro_morning, "q"],
"IntroAfternoon" => [:intro_afternoon, "q"],
"IntroEvening" => [:intro_evening, "q"],
"Body" => [:body, "q"],
"Body1" => [:body1, "q"],
"Body2" => [:body2, "q"],
"BattleRequest" => [:battle_request, "q"],
"BattleRemind" => [:battle_remind, "q"],
"End" => [:end, "q"]
}
extend ClassMethodsSymbols
include InstanceMethods
# @param tr_type [Symbol, String]
# @param tr_name [String]
# @param tr_version [Integer, nil]
# @return [Boolean] whether the given other is defined as a self
def self.exists?(tr_type, tr_name, tr_version = 0)
validate tr_type => [Symbol, String]
validate tr_name => [String]
key = [tr_type.to_sym, tr_name, tr_version]
return !self::DATA[key].nil?
end
# @param tr_type [Symbol, String]
# @param tr_name [String]
# @param tr_version [Integer, nil]
# @return [self]
def self.get(tr_type, tr_name, tr_version = 0)
validate tr_type => [Symbol, String]
validate tr_name => [String]
key = [tr_type.to_sym, tr_name, tr_version]
raise "Phone messages not found for #{tr_type} #{tr_name} #{tr_version}." unless self::DATA.has_key?(key)
return self::DATA[key]
end
# @param tr_type [Symbol, String]
# @param tr_name [String]
# @param tr_version [Integer, nil]
# @return [self, nil]
def self.try_get(tr_type, tr_name, tr_version = 0)
validate tr_type => [Symbol, String]
validate tr_name => [String]
key = [tr_type.to_sym, tr_name, tr_version]
return (self::DATA.has_key?(key)) ? self::DATA[key] : nil
end
def initialize(hash)
@id = hash[:id]
@trainer_type = hash[:trainer_type]
@real_name = hash[:name]
@version = hash[:version] || 0
@intro = hash[:intro]
@intro_morning = hash[:intro_morning]
@intro_afternoon = hash[:intro_afternoon]
@intro_evening = hash[:intro_evening]
@body = hash[:body]
@body1 = hash[:body1]
@body2 = hash[:body2]
@battle_request = hash[:battle_request]
@battle_remind = hash[:battle_remind]
@end = hash[:end]
end
def property_from_string(str)
case str
when "Intro" then return @intro
when "IntroMorning" then return @intro_morning
when "IntroAfternoon" then return @intro_afternoon
when "IntroEvening" then return @intro_evening
when "Body" then return @body
when "Body1" then return @body1
when "Body2" then return @body2
when "BattleRequest" then return @battle_request
when "BattleRemind" then return @battle_remind
when "End" then return @end
end
return nil
end
end
end

View File

@@ -21,6 +21,36 @@ class Battle
return true return true
end end
# Return values:
# -1: Chose not to end the battle via Debug means
# 0: Couldn't end the battle via Debug means; carry on trying to run
# 1: Ended the battle via Debug means
def pbDebugRun
return 0 if !$DEBUG || !Input.press?(Input::CTRL)
commands = [_INTL("Treat as a win"), _INTL("Treat as a loss"),
_INTL("Treat as a draw"), _INTL("Treat as running away/forfeit")]
commands.push(_INTL("Treat as a capture")) if wildBattle?
commands.push(_INTL("Cancel"))
case pbShowCommands(_INTL("Choose the outcome of this battle."), commands)
when 0 # Win
@decision = 1
when 1 # Loss
@decision = 2
when 2 # Draw
@decision = 5
when 3 # Run away/forfeit
pbSEPlay("Battle flee")
pbDisplayPaused(_INTL("You got away safely!"))
@decision = 3
when 4 # Capture
return -1 if trainerBattle?
@decision = 4
else
return -1
end
return 1
end
# Return values: # Return values:
# -1: Failed fleeing # -1: Failed fleeing
# 0: Wasn't possible to attempt fleeing, continue choosing action for the round # 0: Wasn't possible to attempt fleeing, continue choosing action for the round
@@ -36,17 +66,12 @@ class Battle
@choices[idxBattler][2] = nil @choices[idxBattler][2] = nil
return -1 return -1
end end
# Fleeing from trainer battles # Debug ending the battle
debug_ret = pbDebugRun
return debug_ret if debug_ret != 0
# Running from trainer battles
if trainerBattle? if trainerBattle?
if $DEBUG && Input.press?(Input::CTRL) if @internalBattle
if pbDisplayConfirm(_INTL("Treat this battle as a win?"))
@decision = 1
return 1
elsif pbDisplayConfirm(_INTL("Treat this battle as a loss?"))
@decision = 2
return 1
end
elsif @internalBattle
pbDisplayPaused(_INTL("No! There's no running from a Trainer battle!")) pbDisplayPaused(_INTL("No! There's no running from a Trainer battle!"))
elsif pbDisplayConfirm(_INTL("Would you like to forfeit the match and quit now?")) elsif pbDisplayConfirm(_INTL("Would you like to forfeit the match and quit now?"))
pbSEPlay("Battle flee") pbSEPlay("Battle flee")
@@ -56,13 +81,6 @@ class Battle
end end
return 0 return 0
end end
# Fleeing from wild battles
if $DEBUG && Input.press?(Input::CTRL)
pbSEPlay("Battle flee")
pbDisplayPaused(_INTL("You got away safely!"))
@decision = 3
return 1
end
if !@canRun if !@canRun
pbDisplayPaused(_INTL("You can't escape!")) pbDisplayPaused(_INTL("You can't escape!"))
return 0 return 0

View File

@@ -36,6 +36,9 @@ class Battle
end end
def pbCall(idxBattler) def pbCall(idxBattler)
# Debug ending the battle
return if pbDebugRun != 0
# Call the battler
battler = @battlers[idxBattler] battler = @battlers[idxBattler]
trainerName = pbGetOwnerName(idxBattler) trainerName = pbGetOwnerName(idxBattler)
pbDisplay(_INTL("{1} called {2}!", trainerName, battler.pbThis(true))) pbDisplay(_INTL("{1} called {2}!", trainerName, battler.pbThis(true)))

View File

@@ -24,7 +24,7 @@ class Battle::Battler
def pbCanInflictStatus?(newStatus, user, showMessages, move = nil, ignoreStatus = false) def pbCanInflictStatus?(newStatus, user, showMessages, move = nil, ignoreStatus = false)
return false if fainted? return false if fainted?
selfInflicted = (user && user.index == @index) self_inflicted = (user && user.index == @index) # Rest and Flame Orb/Toxic Orb only
# Already have that status problem # Already have that status problem
if self.status == newStatus && !ignoreStatus if self.status == newStatus && !ignoreStatus
if showMessages if showMessages
@@ -41,13 +41,13 @@ class Battle::Battler
return false return false
end end
# Trying to replace a status problem with another one # Trying to replace a status problem with another one
if self.status != :NONE && !ignoreStatus && !selfInflicted if self.status != :NONE && !ignoreStatus && !(self_inflicted && move) # Rest can replace a status problem
@battle.pbDisplay(_INTL("It doesn't affect {1}...", pbThis(true))) if showMessages @battle.pbDisplay(_INTL("It doesn't affect {1}...", pbThis(true))) if showMessages
return false return false
end end
# Trying to inflict a status problem on a Pokémon behind a substitute # Trying to inflict a status problem on a Pokémon behind a substitute
if @effects[PBEffects::Substitute] > 0 && !(move && move.ignoresSubstitute?(user)) && if @effects[PBEffects::Substitute] > 0 && !(move && move.ignoresSubstitute?(user)) &&
!selfInflicted !self_inflicted
@battle.pbDisplay(_INTL("It doesn't affect {1}...", pbThis(true))) if showMessages @battle.pbDisplay(_INTL("It doesn't affect {1}...", pbThis(true))) if showMessages
return false return false
end end
@@ -105,7 +105,7 @@ class Battle::Battler
immAlly = nil immAlly = nil
if Battle::AbilityEffects.triggerStatusImmunityNonIgnorable(self.ability, self, newStatus) if Battle::AbilityEffects.triggerStatusImmunityNonIgnorable(self.ability, self, newStatus)
immuneByAbility = true immuneByAbility = true
elsif selfInflicted || !@battle.moldBreaker elsif self_inflicted || !@battle.moldBreaker
if abilityActive? && Battle::AbilityEffects.triggerStatusImmunity(self.ability, self, newStatus) if abilityActive? && Battle::AbilityEffects.triggerStatusImmunity(self.ability, self, newStatus)
immuneByAbility = true immuneByAbility = true
else else
@@ -163,7 +163,7 @@ class Battle::Battler
return false return false
end end
# Safeguard immunity # Safeguard immunity
if pbOwnSide.effects[PBEffects::Safeguard] > 0 && !selfInflicted && move && if pbOwnSide.effects[PBEffects::Safeguard] > 0 && !self_inflicted && move &&
!(user && user.hasActiveAbility?(:INFILTRATOR)) !(user && user.hasActiveAbility?(:INFILTRATOR))
@battle.pbDisplay(_INTL("{1}'s team is protected by Safeguard!", pbThis)) if showMessages @battle.pbDisplay(_INTL("{1}'s team is protected by Safeguard!", pbThis)) if showMessages
return false return false

View File

@@ -496,6 +496,12 @@ Battle::AbilityEffects::StatusImmunityFromAlly.add(:FLOWERVEIL,
} }
) )
Battle::AbilityEffects::StatusImmunityFromAlly.add(:PASTELVEIL,
proc { |ability, battler, status|
next true if status == :POISON
}
)
Battle::AbilityEffects::StatusImmunityFromAlly.add(:SWEETVEIL, Battle::AbilityEffects::StatusImmunityFromAlly.add(:SWEETVEIL,
proc { |ability, battler, status| proc { |ability, battler, status|
next true if status == :SLEEP next true if status == :SLEEP
@@ -561,6 +567,8 @@ Battle::AbilityEffects::StatusCure.add(:IMMUNITY,
} }
) )
Battle::AbilityEffects::StatusCure.copy(:IMMUNITY, :PASTELVEIL)
Battle::AbilityEffects::StatusCure.add(:INSOMNIA, Battle::AbilityEffects::StatusCure.add(:INSOMNIA,
proc { |ability, battler| proc { |ability, battler|
next if battler.status != :SLEEP next if battler.status != :SLEEP

View File

@@ -32,10 +32,10 @@ EventHandlers.add(:on_wild_pokemon_created, :level_depends_on_party,
# Note that you can only modify a partner trainer's Pokémon, and not the trainer # Note that you can only modify a partner trainer's Pokémon, and not the trainer
# themselves nor their items this way, as those are generated from scratch # themselves nor their items this way, as those are generated from scratch
# before each battle. # before each battle.
#EventHandlers.add(:on_trainer_load, :put_a_name_here, # EventHandlers.add(:on_trainer_load, :put_a_name_here,
# proc { |trainer| # proc { |trainer|
# if trainer # An NPCTrainer object containing party/items/lose text, etc. # if trainer # An NPCTrainer object containing party/items/lose text, etc.
# YOUR CODE HERE # YOUR CODE HERE
# end # end
# } # }
#) # )

View File

@@ -259,7 +259,8 @@ class BerryPlantSprite
when 2 then @event.turn_down # X sprouted when 2 then @event.turn_down # X sprouted
when 3 then @event.turn_left # X taller when 3 then @event.turn_left # X taller
when 4 then @event.turn_right # X flowering when 4 then @event.turn_right # X flowering
when 5 then @event.turn_up # X berries else
@event.turn_up if berry_plant.growth_stage >= 5 # X berries
end end
else else
@event.character_name = "Object ball" @event.character_name = "Object ball"

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,25 @@
# TODO: Add an information window with details of the person in a phone call. # TODO: Add an information window with details of the person in a phone call.
# Make this work with common event calls (create and dispose the info # Make this work with common event calls (create and dispose the info
# window in start_message and end_message). # window in start_message and end_message).
# TODO: Rewrite the Phone UI. Have more than one method. Choosable icons/marks # TODO: Look at the "ready to rematch" timers to see if they can be improved?
# for each contact? Show an icon representing phone signal. # Should they be limited to one trainer becoming ready every ~5 minutes?
# Should a rematch-ready contact become unready again after some time if
# they haven't told the player they're ready?
# TODO: See if incoming phone calls can be made optional somehow. Maybe just
# interrupt as normal with the start of the call and ask if the player
# wants to answer? Wait for a couple of seconds before asking to make sure
# the player doesn't accidentally skip/answer a call they didn't want to.
# TODO: Add a Debug way of upgrading old phone script calls to new ones, or at
# least to find events using old phone scripts for the dev to update.
# TODO: More Debug control over contacts (changing their "time to rebattle",
# unhiding hidden contacts, etc.) and the phone (time until next call).
# TODO: Add a trainer comment for giving a trainer a common event ID.
# TODO: Add calling a contact at a particular time forcing rematch readiness. # TODO: Add calling a contact at a particular time forcing rematch readiness.
# Add trainer comments for this. # Add trainer comments for this.
# TODO: Allow individual trainers to never arrange a rematch by themself, thus # TODO: Allow individual trainers to never arrange a rematch by themself, thus
# requiring the player to call them at their particular time of day/week. # requiring the player to call them at their particular time of day/week.
# TODO: Be able to put the Phone on silent mode (prevent all phone calls from # TODO: Be able to put the Phone on silent mode (prevent all phone calls from
# trainers, but allow scripted calls as normal). # trainers, but allow scripted calls as normal).
# TODO: Better messages, more customisation of messages.
# TODO: Add a Debug way of upgrading old phone script calls to new ones, or at
# least to find events using old phone scripts for the dev to update.
#=============================================================================== #===============================================================================
# #
#=============================================================================== #===============================================================================
@@ -70,8 +75,8 @@ class Phone
return true return true
end end
# Event, trainer type, name, versions_count = 1, start_version = 0 # Event, trainer type, name, versions_count = 1, start_version = 0, common event ID = 0
# Map ID, event ID, trainer type, name, versions_count = 1, start_version = 0 # Map ID, event ID, trainer type, name, versions_count = 1, start_version = 0, common event ID = 0
# Map ID, name, common event ID # Map ID, name, common event ID
def add(*args) def add(*args)
if args[0].is_a?(Game_Event) if args[0].is_a?(Game_Event)
@@ -82,9 +87,11 @@ class Phone
contact = get(true, trainer_type, name, args[3] || 0) contact = get(true, trainer_type, name, args[3] || 0)
if contact if contact
contact.visible = true contact.visible = true
@contacts.delete(contact)
@contacts.push(contact)
else else
contact = Contact.new(true, args[0].map_id, args[0].id, contact = Contact.new(true, args[0].map_id, args[0].id,
trainer_type, name, args[3] || 1, args[4] || 0) trainer_type, name, args[3], args[4], args[5])
contact.increment_version contact.increment_version
@contacts.push(contact) @contacts.push(contact)
end end
@@ -96,9 +103,11 @@ class Phone
contact = get(true, trainer_type, name, args[4] || 0) contact = get(true, trainer_type, name, args[4] || 0)
if contact if contact
contact.visible = true contact.visible = true
@contacts.delete(contact)
@contacts.push(contact)
else else
contact = Contact.new(true, args[0], args[1], contact = Contact.new(true, args[0], args[1],
trainer_type, name, args[4] || 1, args[5] || 0) trainer_type, name, args[4], args[5], args[6])
contact.increment_version contact.increment_version
@contacts.push(contact) @contacts.push(contact)
end end
@@ -108,14 +117,30 @@ class Phone
contact = get(false, name) contact = get(false, name)
if contact if contact
contact.visible = true contact.visible = true
@contacts.delete(contact)
@contacts.push(contact)
else else
contact = Contact.new(false, *args) contact = Contact.new(false, *args)
@contacts.push(contact) @contacts.push(contact)
end end
end end
sort_contacts
return true return true
end end
# Rearranges the list of phone contacts to put all visible contacts first,
# followed by all invisible contacts.
def sort_contacts
new_contacts = []
2.times do |i|
@contacts.each do |con|
next if (i == 0 && !con.visible?) || (i == 1 && con.visible?)
new_contacts.push(con)
end
end
@contacts = new_contacts
end
#============================================================================= #=============================================================================
# Checks once every second. # Checks once every second.
@@ -233,7 +258,7 @@ class Phone
attr_accessor :trainer_type, :start_version, :versions_count, :version attr_accessor :trainer_type, :start_version, :versions_count, :version
attr_accessor :time_to_ready, :rematch_flag, :variant_beaten attr_accessor :time_to_ready, :rematch_flag, :variant_beaten
attr_accessor :common_event_id attr_accessor :common_event_id
attr_accessor :visible attr_reader :visible
# Map ID, event ID, trainer type, name, versions count = 1, start version = 0 # Map ID, event ID, trainer type, name, versions count = 1, start version = 0
# Map ID, name, common event ID # Map ID, name, common event ID
@@ -251,7 +276,7 @@ class Phone
@variant_beaten = 0 @variant_beaten = 0
@time_to_ready = 0 @time_to_ready = 0
@rematch_flag = 0 # 0=counting down, 1=ready for rematch, 2=ready and told player @rematch_flag = 0 # 0=counting down, 1=ready for rematch, 2=ready and told player
@common_event_id = 0 @common_event_id = args[6] || 0
else else
# Non-trainer # Non-trainer
@map_id = args[0] @map_id = args[0]
@@ -280,6 +305,10 @@ class Phone
end end
end end
def can_hide?
return trainer?
end
def common_event_call? def common_event_call?
return @common_event_id > 0 return @common_event_id > 0
end end
@@ -373,7 +402,13 @@ class Phone
def make_incoming def make_incoming
return if !can_make? return if !can_make?
contact = get_random_trainer_for_incoming_call contact = get_random_trainer_for_incoming_call
if contact return if !contact
if contact.common_event_call?
if !pbCommonEvent(contact.common_event_id)
pbMessage(_INTL("{1}'s messages not defined.\nCouldn't call common event {2}.",
contact.display_name, contact.common_event_id))
end
else
call = generate_trainer_dialogue(contact) call = generate_trainer_dialogue(contact)
play(call, contact) play(call, contact)
end end
@@ -403,7 +438,7 @@ class Phone
end end
end end
def start_message(contact) def start_message(contact = nil)
pbMessage(_INTL("......\\wt[5] ......\\1")) pbMessage(_INTL("......\\wt[5] ......\\1"))
end end
@@ -434,7 +469,7 @@ class Phone
end_message(contact) end_message(contact)
end end
def end_message(contact) def end_message(contact = nil)
pbMessage(_INTL("Click!\\wt[10]\n......\\wt[5] ......\\1")) pbMessage(_INTL("Click!\\wt[10]\n......\\wt[5] ......\\1"))
end end
@@ -442,36 +477,58 @@ class Phone
def generate_trainer_dialogue(contact) def generate_trainer_dialogue(contact)
validate contact => Phone::Contact validate contact => Phone::Contact
# Get the set of messages to be used by the contact
messages = GameData::PhoneMessage.try_get(contact.trainer_type, contact.name, contact.version)
messages = GameData::PhoneMessage.try_get(contact.trainer_type, contact.name, contact.start_version) if !messages
messages = GameData::PhoneMessage::DATA["default"] if !messages
# Create lambda for choosing a random message and translating it
get_random_message = lambda do |messages| get_random_message = lambda do |messages|
return "" if !messages
msg = messages.sample msg = messages.sample
return "" if !msg return "" if !msg
return pbGetMessageFromHash(MessageTypes::PhoneMessages, msg) return pbGetMessageFromHash(MessageTypes::PhoneMessages, msg)
end end
phone_data = pbLoadPhoneData
# Choose random greeting depending on time of day # Choose random greeting depending on time of day
ret = get_random_message.call(phone_data.greetings) ret = get_random_message.call(messages.intro)
time = pbGetTimeNow time = pbGetTimeNow
if PBDayNight.isMorning?(time) if PBDayNight.isMorning?(time)
modcall = get_random_message.call(phone_data.greetingsMorning) mod_call = get_random_message.call(messages.intro_morning)
ret = modcall if !nil_or_empty?(modcall) ret = mod_call if !nil_or_empty?(mod_call)
elsif PBDayNight.isAfternoon?(time)
mod_call = get_random_message.call(messages.intro_afternoon)
ret = mod_call if !nil_or_empty?(mod_call)
elsif PBDayNight.isEvening?(time) elsif PBDayNight.isEvening?(time)
modcall = get_random_message.call(phone_data.greetingsEvening) mod_call = get_random_message.call(messages.intro_evening)
ret = modcall if !nil_or_empty?(modcall) ret = mod_call if !nil_or_empty?(mod_call)
end end
ret += "\\m" ret += "\\m"
if Phone.rematches_enabled && (contact.rematch_flag == 1 || # Choose main message set
(contact.rematch_flag == 2 && rand(100) < 50)) if Phone.rematches_enabled && contact.rematch_flag > 0
# If ready for rematch, tell the player (50% chance to remind the player) # Trainer is ready for a rematch, so tell/remind the player
ret += get_random_message.call(phone_data.battleRequests) if contact.rematch_flag == 1 # Tell the player
contact.rematch_flag = 2 # Ready for rematch and told player ret += get_random_message.call(messages.battle_request)
elsif rand(100) < 75 contact.rematch_flag = 2 # Ready for rematch and told player
# Choose random body elsif contact.rematch_flag == 2 # Remind the player
ret += get_random_message.call(phone_data.bodies1) if messages.battle_remind
ret += "\\m" ret += get_random_message.call(messages.battle_remind)
ret += get_random_message.call(phone_data.bodies2) else
ret += get_random_message.call(messages.battle_request)
end
end
else else
# Choose random generic # Standard messages
ret += get_random_message.call(phone_data.generics) if messages.body1 && messages.body2 && (!messages.body || rand(100) < 75)
# Choose random pair of body messages
ret += get_random_message.call(messages.body1)
ret += "\\m"
ret += get_random_message.call(messages.body2)
else
# Choose random full body message
ret += get_random_message.call(messages.body)
end
# Choose end message
mod_call = get_random_message.call(messages.end)
ret += "\\m" + mod_call if !nil_or_empty?(mod_call)
end end
return ret return ret
end end

View File

@@ -28,9 +28,7 @@ class PokemonEggHatch_Scene
@pokemon.form, @pokemon.shiny?, @pokemon.form, @pokemon.shiny?,
false, false, true) # Egg sprite false, false, true) # Egg sprite
# Load egg cracks bitmap # Load egg cracks bitmap
crackfilename = sprintf("Graphics/Pokemon/Eggs/%s_cracks", @pokemon.species) crackfilename = GameData::Species.egg_cracks_sprite_filename(@pokemon.species, @pokemon.form)
crackfilename = sprintf("Graphics/Pokemon/Eggs/000_cracks") if !pbResolveBitmap(crackfilename)
crackfilename = pbResolveBitmap(crackfilename)
@hatchSheet = AnimatedBitmap.new(crackfilename) @hatchSheet = AnimatedBitmap.new(crackfilename)
# Create egg cracks sprite # Create egg cracks sprite
@sprites["hatch"] = Sprite.new(@viewport) @sprites["hatch"] = Sprite.new(@viewport)

View File

@@ -811,6 +811,7 @@ class PokemonParty_Scene
currentsel = Settings::MAX_PARTY_SIZE currentsel = Settings::MAX_PARTY_SIZE
elsif currentsel == numsprites elsif currentsel == numsprites
currentsel = 0 currentsel = 0
currentsel = numsprites - 1 if currentsel >= @party.length
end end
when Input::UP when Input::UP
if currentsel >= Settings::MAX_PARTY_SIZE if currentsel >= Settings::MAX_PARTY_SIZE
@@ -818,6 +819,7 @@ class PokemonParty_Scene
while currentsel > 0 && currentsel < Settings::MAX_PARTY_SIZE && !@party[currentsel] while currentsel > 0 && currentsel < Settings::MAX_PARTY_SIZE && !@party[currentsel]
currentsel -= 1 currentsel -= 1
end end
currentsel = numsprites - 1 if currentsel >= @party.length
else else
loop do loop do
currentsel -= 2 currentsel -= 2
@@ -839,6 +841,7 @@ class PokemonParty_Scene
currentsel = Settings::MAX_PARTY_SIZE currentsel = Settings::MAX_PARTY_SIZE
elsif currentsel >= numsprites elsif currentsel >= numsprites
currentsel = 0 currentsel = 0
currentsel = numsprites - 1 if currentsel >= @party.length
end end
end end
return currentsel return currentsel
@@ -853,7 +856,7 @@ class PokemonParty_Scene
@sprites["pokemon#{i}"].dispose @sprites["pokemon#{i}"].dispose
end end
lastselected = @party.length - 1 if lastselected >= @party.length lastselected = @party.length - 1 if lastselected >= @party.length
lastselected = 0 if lastselected < 0 lastselected = Settings::MAX_PARTY_SIZE if lastselected < 0
Settings::MAX_PARTY_SIZE.times do |i| Settings::MAX_PARTY_SIZE.times do |i|
if @party[i] if @party[i]
@sprites["pokemon#{i}"] = PokemonPartyPanel.new(@party[i], i, @viewport) @sprites["pokemon#{i}"] = PokemonPartyPanel.new(@party[i], i, @viewport)

View File

@@ -182,7 +182,11 @@ MenuHandlers.add(:pokegear_menu, :phone, {
"order" => 20, "order" => 20,
# "condition" => proc { next $PokemonGlobal.phone && $PokemonGlobal.phone.contacts.length > 0 }, # "condition" => proc { next $PokemonGlobal.phone && $PokemonGlobal.phone.contacts.length > 0 },
"effect" => proc { |menu| "effect" => proc { |menu|
pbFadeOutIn { PokemonPhoneScene.new.start } pbFadeOutIn {
scene = PokemonPhone_Scene.new
screen = PokemonPhoneScreen.new(scene)
screen.pbStartScreen
}
next false next false
} }
}) })

View File

@@ -1,10 +1,13 @@
# TODO: Choosable icons/marks for each contact? Add a "sort by" option for these.
#=============================================================================== #===============================================================================
# Phone screen # Phone list of contacts
#=============================================================================== #===============================================================================
class Window_PhoneList < Window_CommandPokemon class Window_PhoneList < Window_CommandPokemon
attr_accessor :switching
def drawCursor(index, rect) def drawCursor(index, rect)
selarrow = AnimatedBitmap.new("Graphics/UI/Phone/cursor")
if self.index == index if self.index == index
selarrow = AnimatedBitmap.new("Graphics/UI/Phone/cursor")
pbCopyBitmap(self.contents, selarrow.bitmap, rect.x, rect.y + 2) pbCopyBitmap(self.contents, selarrow.bitmap, rect.x, rect.y + 2)
end end
return Rect.new(rect.x + 28, rect.y + 8, rect.width - 16, rect.height) return Rect.new(rect.x + 28, rect.y + 8, rect.width - 16, rect.height)
@@ -12,7 +15,13 @@ class Window_PhoneList < Window_CommandPokemon
def drawItem(index, count, rect) def drawItem(index, count, rect)
return if index >= self.top_row + self.page_item_max return if index >= self.top_row + self.page_item_max
super if self.index == index && @switching
rect = drawCursor(index, rect)
pbDrawShadowText(self.contents, rect.x, rect.y + (self.contents.text_offset_y || 0),
rect.width, rect.height, @commands[index], Color.new(224, 0, 0), Color.new(224, 144, 144))
else
super
end
drawCursor(index - 1, itemRect(index - 1)) drawCursor(index - 1, itemRect(index - 1))
end end
end end
@@ -20,17 +29,57 @@ end
#=============================================================================== #===============================================================================
# #
#=============================================================================== #===============================================================================
class PokemonPhoneScene class PokemonPhone_Scene
def start def pbStartScene
# Get list of contacts @sprites = {}
# Create viewport
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
@viewport.z = 99999
# Background
addBackgroundPlane(@sprites, "bg", "Phone/bg", @viewport)
# List of contacts
@sprites["list"] = Window_PhoneList.newEmpty(152, 32, Graphics.width - 142, Graphics.height - 80, @viewport)
@sprites["list"].windowskin = nil
# Rematch readiness icons
if Phone.rematches_enabled
@sprites["list"].page_item_max.times do |i|
@sprites["rematch_#{i}"] = IconSprite.new(468, 62 + (i * 32), @viewport)
end
end
# Phone signal icon
@sprites["signal"] = IconSprite.new(Graphics.width - 32, 0, @viewport)
if Phone::Call.can_make?
@sprites["signal"].setBitmap("Graphics/UI/Phone/icon_signal")
else
@sprites["signal"].setBitmap("Graphics/UI/Phone/icon_nosignal")
end
# Title text
@sprites["header"] = Window_UnformattedTextPokemon.newWithSize(
_INTL("Phone"), 2, -18, 128, 64, @viewport
)
@sprites["header"].baseColor = Color.new(248, 248, 248)
@sprites["header"].shadowColor = Color.black
@sprites["header"].windowskin = nil
# Info text about all contacts
@sprites["info"] = Window_AdvancedTextPokemon.newWithSize("", -8, 224, 180, 160, @viewport)
@sprites["info"].windowskin = nil
# Portrait of contact
@sprites["icon"] = IconSprite.new(70, 102, @viewport)
# Contact's location text
@sprites["bottom"] = Window_AdvancedTextPokemon.newWithSize(
"", 162, Graphics.height - 64, Graphics.width - 158, 64, @viewport
)
@sprites["bottom"].windowskin = nil
# Start scene
pbRefreshList
pbFadeInAndShow(@sprites) { pbUpdate }
end
def pbRefreshList
@contacts = [] @contacts = []
$PokemonGlobal.phone.contacts.each do |contact| $PokemonGlobal.phone.contacts.each do |contact|
@contacts.push(contact) if contact.visible? @contacts.push(contact) if contact.visible?
end end
if @contacts.length == 0
pbMessage(_INTL("There are no phone numbers stored."))
return
end
# Create list of commands (display names of contacts) and count rematches # Create list of commands (display names of contacts) and count rematches
commands = [] commands = []
rematch_count = 0 rematch_count = 0
@@ -38,95 +87,186 @@ class PokemonPhoneScene
commands.push(contact.display_name) commands.push(contact.display_name)
rematch_count += 1 if contact.can_rematch? rematch_count += 1 if contact.can_rematch?
end end
# Create viewport and sprites # Set list's commands
@sprites = {}
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
@viewport.z = 99999
addBackgroundPlane(@sprites, "bg", "Phone/bg", @viewport)
@sprites["list"] = Window_PhoneList.newEmpty(152, 32, Graphics.width - 142, Graphics.height - 80, @viewport)
@sprites["list"].windowskin = nil
@sprites["list"].commands = commands @sprites["list"].commands = commands
@sprites["list"].page_item_max.times do |i| @sprites["list"].index = commands.length - 1 if @sprites["list"].index >= commands.length
@sprites["rematch[#{i}]"] = IconSprite.new(468, 62 + (i * 32), @viewport) if @sprites["list"].top_row > @sprites["list"].itemCount - @sprites["list"].page_item_max
j = i + @sprites["list"].top_item @sprites["list"].top_row = @sprites["list"].itemCount - @sprites["list"].page_item_max
if j < @contacts.length && @contacts[j].can_rematch?
@sprites["rematch[#{i}]"].setBitmap("Graphics/UI/Phone/icon_rematch")
end
end end
@sprites["header"] = Window_UnformattedTextPokemon.newWithSize( # Set info text
_INTL("Phone"), 2, -18, 128, 64, @viewport
)
@sprites["header"].baseColor = Color.new(248, 248, 248)
@sprites["header"].shadowColor = Color.black
@sprites["header"].windowskin = nil
@sprites["bottom"] = Window_AdvancedTextPokemon.newWithSize(
"", 162, Graphics.height - 64, Graphics.width - 158, 64, @viewport
)
@sprites["bottom"].windowskin = nil
map_name = (@contacts[0].map_id > 0) ? pbGetMapNameFromId(@contacts[0].map_id) : ""
@sprites["bottom"].text = "<ac>" + map_name
@sprites["info"] = Window_AdvancedTextPokemon.newWithSize("", -8, 224, 180, 160, @viewport)
@sprites["info"].windowskin = nil
infotext = _INTL("Registered<br>") infotext = _INTL("Registered<br>")
infotext += _INTL(" <r>{1}<br>", @sprites["list"].commands.length) infotext += _INTL(" <r>{1}<br>", @sprites["list"].commands.length)
infotext += _INTL("Waiting for a rematch<r>{1}", rematch_count) infotext += _INTL("Waiting for a rematch<r>{1}", rematch_count)
@sprites["info"].text = infotext @sprites["info"].text = infotext
@sprites["icon"] = IconSprite.new(70, 102, @viewport) pbRefreshScreen
if @contacts[0].trainer? end
filename = GameData::TrainerType.charset_filename(@contacts[0].trainer_type)
else def pbRefreshScreen
filename = sprintf("Graphics/Characters/phone%03d", @contacts[0].common_event_id) @sprites["list"].refresh
# Redraw rematch readiness icons
if @sprites["rematch_0"]
@sprites["list"].page_item_max.times do |i|
@sprites["rematch_#{i}"].clearBitmaps
j = i + @sprites["list"].top_item
if j < @contacts.length && @contacts[j].can_rematch?
@sprites["rematch_#{i}"].setBitmap("Graphics/UI/Phone/icon_rematch")
end
end
end end
@sprites["icon"].setBitmap(filename) # Get the selected contact
charwidth = @sprites["icon"].bitmap.width contact = @contacts[@sprites["list"].index]
charheight = @sprites["icon"].bitmap.height if contact
@sprites["icon"].x = 86 - (charwidth / 8) # Redraw contact's portrait
@sprites["icon"].y = 134 - (charheight / 8) if contact.trainer?
@sprites["icon"].src_rect = Rect.new(0, 0, charwidth / 4, charheight / 4) filename = GameData::TrainerType.charset_filename(contact.trainer_type)
# Start scene else
pbFadeInAndShow(@sprites) filename = sprintf("Graphics/Characters/phone%03d", contact.common_event_id)
end
@sprites["icon"].setBitmap(filename)
charwidth = @sprites["icon"].bitmap.width
charheight = @sprites["icon"].bitmap.height
@sprites["icon"].x = 86 - (charwidth / 8)
@sprites["icon"].y = 134 - (charheight / 8)
@sprites["icon"].src_rect = Rect.new(0, 0, charwidth / 4, charheight / 4)
# Redraw contact's location text
map_name = (contact.map_id > 0) ? pbGetMapNameFromId(contact.map_id) : ""
@sprites["bottom"].text = "<ac>" + map_name
else
@sprites["icon"].setBitmap(nil)
@sprites["bottom"].text = ""
end
end
def pbChooseContact
pbActivateWindow(@sprites, "list") { pbActivateWindow(@sprites, "list") {
oldindex = -1 index = -1
switch_index = -1
loop do loop do
Graphics.update Graphics.update
Input.update Input.update
pbUpdateSpriteHash(@sprites) pbUpdateSpriteHash(@sprites)
# Cursor moved, update display # Cursor moved, update display
if @sprites["list"].index != oldindex if @sprites["list"].index != index
contact = @contacts[@sprites["list"].index] if switch_index >= 0
if contact.trainer? real_contacts = $PokemonGlobal.phone.contacts
filename = GameData::TrainerType.charset_filename(contact.trainer_type) real_contacts.insert(@sprites["list"].index, real_contacts.delete_at(index))
pbRefreshList
else else
filename = sprintf("Graphics/Characters/phone%03d", contact.common_event_id) pbRefreshScreen
end
@sprites["icon"].setBitmap(filename)
charwidth = @sprites["icon"].bitmap.width
charheight = @sprites["icon"].bitmap.height
@sprites["icon"].x = 86 - (charwidth / 8)
@sprites["icon"].y = 134 - (charheight / 8)
@sprites["icon"].src_rect = Rect.new(0, 0, charwidth / 4, charheight / 4)
map_name = (contact.map_id > 0) ? pbGetMapNameFromId(contact.map_id) : ""
@sprites["bottom"].text = "<ac>" + map_name
@sprites["list"].page_item_max.times do |i|
@sprites["rematch[#{i}]"].clearBitmaps
j = i + @sprites["list"].top_item
if j < @contacts.length && @contacts[j].can_rematch?
@sprites["rematch[#{i}]"].setBitmap("Graphics/UI/Phone/icon_rematch")
end
end end
end end
index = @sprites["list"].index
# Get inputs # Get inputs
if Input.trigger?(Input::BACK) if switch_index >= 0
pbPlayCloseMenuSE if Input.trigger?(Input::ACTION) ||
break Input.trigger?(Input::USE)
elsif Input.trigger?(Input::USE) pbPlayDecisionSE
index = @sprites["list"].index @sprites["list"].switching = false
Phone::Call.make_outgoing(@contacts[index]) if index >= 0 switch_index = -1
pbRefreshScreen
elsif Input.trigger?(Input::BACK)
pbPlayCancelSE
real_contacts = $PokemonGlobal.phone.contacts
real_contacts.insert(switch_index, real_contacts.delete_at(@sprites["list"].index))
@sprites["list"].index = switch_index
@sprites["list"].switching = false
switch_index = -1
pbRefreshList
end
else
if Input.trigger?(Input::ACTION)
switch_index = @sprites["list"].index
@sprites["list"].switching = true
pbRefreshScreen
elsif Input.trigger?(Input::BACK)
pbPlayCloseMenuSE
return nil
elsif Input.trigger?(Input::USE)
return @contacts[index] if index >= 0
end
end end
end end
} }
pbFadeOutAndHide(@sprites) end
def pbEndScene
pbFadeOutAndHide(@sprites) { pbUpdate }
pbDisposeSpriteHash(@sprites) pbDisposeSpriteHash(@sprites)
@viewport.dispose @viewport.dispose
end end
def pbUpdate
pbUpdateSpriteHash(@sprites)
end
end
#===============================================================================
#
#===============================================================================
class PokemonPhoneScreen
def initialize(scene)
@scene = scene
end
def pbStartScreen
if $PokemonGlobal.phone.contacts.none? { |con| con.visible? }
pbMessage(_INTL("There are no phone numbers stored."))
return
end
@scene.pbStartScene
loop do
contact = @scene.pbChooseContact
break if !contact
commands = []
commands.push(_INTL("Call"))
commands.push(_INTL("Delete")) if contact.can_hide?
commands.push(_INTL("Sort Contacts"))
commands.push(_INTL("Cancel"))
cmd = pbShowCommands(nil, commands, -1)
cmd += 1 if cmd >=1 && !contact.can_hide?
case cmd
when 0 # Call
Phone::Call.make_outgoing(contact)
when 1 # Delete
name = contact.display_name
if pbConfirmMessage(_INTL("Are you sure you want to delete {1} from your phone?", name))
contact.visible = false
$PokemonGlobal.phone.sort_contacts
@scene.pbRefreshList
pbMessage(_INTL("{1} was deleted from your phone contacts.", name))
if $PokemonGlobal.phone.contacts.none? { |con| con.visible? }
pbMessage(_INTL("There are no phone numbers stored."))
break
end
end
when 2 # Sort Contacts
case pbMessage(_INTL("How do you want to sort the contacts?"),
[_INTL("By name"),
_INTL("By Trainer type"),
_INTL("Special contacts first"),
_INTL("Cancel")], -1, nil, 0)
when 0 # By name
$PokemonGlobal.phone.contacts.sort! { |a, b| a.name <=> b.name }
$PokemonGlobal.phone.sort_contacts
@scene.pbRefreshList
when 1 # By trainer type
$PokemonGlobal.phone.contacts.sort! { |a, b| a.display_name <=> b.display_name }
$PokemonGlobal.phone.sort_contacts
@scene.pbRefreshList
when 2 # Special contacts first
new_contacts = []
2.times do |i|
$PokemonGlobal.phone.contacts.each do |con|
next if (i == 0 && con.trainer?) || (i == 1 && !con.trainer?)
new_contacts.push(con)
end
end
$PokemonGlobal.phone.contacts = new_contacts
$PokemonGlobal.phone.sort_contacts
@scene.pbRefreshList
end
end
end
@scene.pbEndScene
end
end end

View File

@@ -79,7 +79,6 @@ class BugContestState
@contestMaps.push(map) @contestMaps.push(map)
end end
end end
echoln "contest maps: #{@contestMaps}"
end end
# Reception map is handled separately from contest map since the reception map # Reception map is handled separately from contest map since the reception map
@@ -94,7 +93,6 @@ class BugContestState
@reception.push(map) @reception.push(map)
end end
end end
echoln "reception maps: #{@reception}"
end end
def pbOffLimits?(map) def pbOffLimits?(map)

View File

@@ -70,7 +70,32 @@ def toCelsius(fahrenheit)
return ((fahrenheit - 32) * 5.0 / 9.0).round return ((fahrenheit - 32) * 5.0 / 9.0).round
end end
#===============================================================================
# This class is designed to favor different values more than a uniform
# random generator does.
#===============================================================================
class AntiRandom
def initialize(size)
@old = []
@new = Array.new(size) { |i| i }
end
def get
if @new.length == 0 # No new values
@new = @old.clone
@old.clear
end
if @old.length > 0 && rand(7) == 0 # Get old value
return @old[rand(@old.length)]
end
if @new.length > 0 # Get new value
ret = @new.delete_at(rand(@new.length))
@old.push(ret)
return ret
end
return @old[rand(@old.length)] # Get old value
end
end
#=============================================================================== #===============================================================================
# Constants utilities # Constants utilities
@@ -125,8 +150,6 @@ def getConstantNameOrValue(mod, value)
return value.inspect return value.inspect
end end
#=============================================================================== #===============================================================================
# Event utilities # Event utilities
#=============================================================================== #===============================================================================
@@ -196,8 +219,6 @@ def pbNoticePlayer(event)
pbMoveTowardPlayer(event) pbMoveTowardPlayer(event)
end end
#=============================================================================== #===============================================================================
# Player-related utilities, random name generator # Player-related utilities, random name generator
#=============================================================================== #===============================================================================
@@ -339,8 +360,6 @@ def getRandomName(maxLength = 100)
return getRandomNameEx(2, nil, nil, maxLength) return getRandomNameEx(2, nil, nil, maxLength)
end end
#=============================================================================== #===============================================================================
# Regional and National Pokédexes utilities # Regional and National Pokédexes utilities
#=============================================================================== #===============================================================================
@@ -387,8 +406,6 @@ def pbGetRegionalDexLength(region_dex)
return (dex_list) ? dex_list.length : 0 return (dex_list) ? dex_list.length : 0
end end
#=============================================================================== #===============================================================================
# Other utilities # Other utilities
#=============================================================================== #===============================================================================

View File

@@ -233,7 +233,7 @@ MenuHandlers.add(:debug_menu, :test_wild_battle_advanced, {
params.setCancelValue(0) params.setCancelValue(0)
level = pbMessageChooseNumber(_INTL("Set the wild {1}'s level.", level = pbMessageChooseNumber(_INTL("Set the wild {1}'s level.",
GameData::Species.get(species).name), params) GameData::Species.get(species).name), params)
pkmn.push(Pokemon.new(species, level)) if level > 0 pkmn.push(pbGenerateWildPokemon(species, level)) if level > 0
end end
else # Edit a Pokémon else # Edit a Pokémon
if pbConfirmMessage(_INTL("Change this Pokémon?")) if pbConfirmMessage(_INTL("Change this Pokémon?"))
@@ -336,6 +336,7 @@ MenuHandlers.add(:debug_menu, :test_trainer_battle_advanced, {
trainerdata = pbListScreen(_INTL("CHOOSE A TRAINER"), TrainerBattleLister.new(0, false)) trainerdata = pbListScreen(_INTL("CHOOSE A TRAINER"), TrainerBattleLister.new(0, false))
if trainerdata if trainerdata
tr = pbLoadTrainer(trainerdata[0], trainerdata[1], trainerdata[2]) tr = pbLoadTrainer(trainerdata[0], trainerdata[1], trainerdata[2])
EventHandlers.trigger(:on_trainer_load, tr)
trainers.push([0, tr]) trainers.push([0, tr])
end end
else # Edit a trainer else # Edit a trainer
@@ -344,6 +345,7 @@ MenuHandlers.add(:debug_menu, :test_trainer_battle_advanced, {
TrainerBattleLister.new(trainers[trainerCmd][0], false)) TrainerBattleLister.new(trainers[trainerCmd][0], false))
if trainerdata if trainerdata
tr = pbLoadTrainer(trainerdata[0], trainerdata[1], trainerdata[2]) tr = pbLoadTrainer(trainerdata[0], trainerdata[1], trainerdata[2])
EventHandlers.trigger(:on_trainer_load, tr)
trainers[trainerCmd] = [0, tr] trainers[trainerCmd] = [0, tr]
end end
elsif pbConfirmMessage(_INTL("Delete this trainer?")) elsif pbConfirmMessage(_INTL("Delete this trainer?"))
@@ -386,6 +388,17 @@ MenuHandlers.add(:debug_menu, :reset_trainers, {
} }
}) })
MenuHandlers.add(:debug_menu, :toggle_rematches_possible, {
"name" => _INTL("Toggle Phone Rematches Possible"),
"parent" => :battle_menu,
"description" => _INTL("Toggles whether trainers in the phone can be rebattled."),
"effect" => proc {
Phone.rematches_enabled = !Phone.rematches_enabled
pbMessage(_INTL("Trainers in the phone can now be rebattled.")) if Phone.rematches_enabled
pbMessage(_INTL("Trainers in the phone cannot be rebattled.")) if !Phone.rematches_enabled
}
})
MenuHandlers.add(:debug_menu, :ready_rematches, { MenuHandlers.add(:debug_menu, :ready_rematches, {
"name" => _INTL("Ready All Phone Rematches"), "name" => _INTL("Ready All Phone Rematches"),
"parent" => :battle_menu, "parent" => :battle_menu,
@@ -1115,6 +1128,8 @@ MenuHandlers.add(:debug_menu, :create_pbs_files, {
"abilities.txt", "abilities.txt",
"battle_facility_lists.txt", "battle_facility_lists.txt",
"berry_plants.txt", "berry_plants.txt",
"dungeon_parameters.txt",
"dungeon_tilesets.txt",
"encounters.txt", "encounters.txt",
"items.txt", "items.txt",
"map_connections.txt", "map_connections.txt",
@@ -1140,23 +1155,25 @@ MenuHandlers.add(:debug_menu, :create_pbs_files, {
when 1 then Compiler.write_abilities when 1 then Compiler.write_abilities
when 2 then Compiler.write_trainer_lists when 2 then Compiler.write_trainer_lists
when 3 then Compiler.write_berry_plants when 3 then Compiler.write_berry_plants
when 4 then Compiler.write_encounters when 4 then Compiler.write_dungeon_parameters
when 5 then Compiler.write_items when 5 then Compiler.write_dungeon_tilesets
when 6 then Compiler.write_connections when 6 then Compiler.write_encounters
when 7 then Compiler.write_map_metadata when 7 then Compiler.write_items
when 8 then Compiler.write_metadata when 8 then Compiler.write_connections
when 9 then Compiler.write_moves when 9 then Compiler.write_map_metadata
when 10 then Compiler.write_phone when 10 then Compiler.write_metadata
when 11 then Compiler.write_pokemon when 11 then Compiler.write_moves
when 12 then Compiler.write_pokemon_forms when 12 then Compiler.write_phone
when 13 then Compiler.write_pokemon_metrics when 13 then Compiler.write_pokemon
when 14 then Compiler.write_regional_dexes when 14 then Compiler.write_pokemon_forms
when 15 then Compiler.write_ribbons when 15 then Compiler.write_pokemon_metrics
when 16 then Compiler.write_shadow_pokemon when 16 then Compiler.write_regional_dexes
when 17 then Compiler.write_town_map when 17 then Compiler.write_ribbons
when 18 then Compiler.write_trainer_types when 18 then Compiler.write_shadow_pokemon
when 19 then Compiler.write_trainers when 19 then Compiler.write_town_map
when 20 then Compiler.write_types when 20 then Compiler.write_trainer_types
when 21 then Compiler.write_trainers
when 22 then Compiler.write_types
else break else break
end end
pbMessage(_INTL("File written.")) pbMessage(_INTL("File written."))

View File

@@ -773,6 +773,11 @@ MenuHandlers.add(:pokemon_debug_menu, :species_and_form, {
end end
if formcmds[0].length <= 1 if formcmds[0].length <= 1
screen.pbDisplay(_INTL("Species {1} only has one form.", pkmn.speciesName)) screen.pbDisplay(_INTL("Species {1} only has one form.", pkmn.speciesName))
if pkmn.form != 0 && screen.pbConfirm(_INTL("Do you want to reset the form to 0?"))
pkmn.form = 0
$player.pokedex.register(pkmn) if !settingUpBattle && !pkmn.egg?
screen.pbRefreshSingle(pkmnid)
end
else else
cmd2 = screen.pbShowCommands(_INTL("Set the Pokémon's form."), formcmds[1], cmd2) cmd2 = screen.pbShowCommands(_INTL("Set the Pokémon's form."), formcmds[1], cmd2)
next if cmd2 < 0 next if cmd2 < 0

View File

@@ -757,7 +757,6 @@ module Compiler
modify_pbs_file_contents_before_compiling modify_pbs_file_contents_before_compiling
compile_town_map compile_town_map
compile_connections compile_connections
compile_phone
compile_types compile_types
compile_abilities compile_abilities
compile_moves # Depends on Type compile_moves # Depends on Type
@@ -775,12 +774,18 @@ module Compiler
compile_trainer_lists # Depends on TrainerType compile_trainer_lists # Depends on TrainerType
compile_metadata # Depends on TrainerType compile_metadata # Depends on TrainerType
compile_map_metadata compile_map_metadata
compile_dungeon_tilesets
compile_dungeon_parameters
compile_phone # Depends on TrainerType
end end
def compile_all(mustCompile) def compile_all(mustCompile)
return if !mustCompile if !mustCompile
Console.echo_h1(_INTL("Game did not compile data"))
return
end
FileLineData.clear FileLineData.clear
Console.echo_h1 _INTL("Starting full compile") Console.echo_h1 _INTL("Compiling all data")
compile_pbs_files compile_pbs_files
compile_animations compile_animations
compile_trainer_events(mustCompile) compile_trainer_events(mustCompile)
@@ -793,7 +798,7 @@ module Compiler
System.reload_cache System.reload_cache
Console.echo_done(true) Console.echo_done(true)
echoln "" echoln ""
Console.echo_h2("Successfully fully compiled", text: :green) Console.echo_h2("Successfully compiled all data", text: :green)
end end
def main def main
@@ -802,6 +807,8 @@ module Compiler
dataFiles = [ dataFiles = [
"abilities.dat", "abilities.dat",
"berry_plants.dat", "berry_plants.dat",
"dungeon_parameters.dat",
"dungeon_tilesets.dat",
"encounters.dat", "encounters.dat",
"items.dat", "items.dat",
"map_connections.dat", "map_connections.dat",
@@ -825,6 +832,8 @@ module Compiler
"abilities.txt", "abilities.txt",
"battle_facility_lists.txt", "battle_facility_lists.txt",
"berry_plants.txt", "berry_plants.txt",
"dungeon_parameters.txt",
"dungeon_tilesets.txt",
"encounters.txt", "encounters.txt",
"items.txt", "items.txt",
"map_connections.txt", "map_connections.txt",

View File

@@ -102,37 +102,69 @@ module Compiler
def compile_phone(path = "PBS/phone.txt") def compile_phone(path = "PBS/phone.txt")
return if !safeExists?(path) return if !safeExists?(path)
compile_pbs_file_message_start(path) compile_pbs_file_message_start(path)
database = PhoneDatabase.new GameData::PhoneMessage::DATA.clear
sections = [] schema = GameData::PhoneMessage::SCHEMA
File.open(path, "rb") { |f| messages = []
pbEachSection(f) { |section, name| contact_hash = nil
case name # Read each line of phone.txt at a time and compile it as a contact property
when "<Generics>" idx = 0
database.generics = section pbCompilerEachPreppedLine(path) { |line, line_no|
sections.concat(section) echo "." if idx % 50 == 0
when "<BattleRequests>" idx += 1
database.battleRequests = section Graphics.update if idx % 250 == 0
sections.concat(section) if line[/^\s*\[\s*(.+)\s*\]\s*$/]
when "<GreetingsMorning>" # New section [trainer_type, name] or [trainer_type, name, version]
database.greetingsMorning = section if contact_hash
sections.concat(section) # Add contact's data to records
when "<GreetingsEvening>" if contact_hash[:trainer_type] == "default"
database.greetingsEvening = section contact_hash[:id] = contact_hash[:trainer_type]
sections.concat(section) else
when "<Greetings>" contact_hash[:id] = [contact_hash[:trainer_type], contact_hash[:name], contact_hash[:version]]
database.greetings = section end
sections.concat(section) GameData::PhoneMessage.register(contact_hash)
when "<Bodies1>"
database.bodies1 = section
sections.concat(section)
when "<Bodies2>"
database.bodies2 = section
sections.concat(section)
end end
} # Construct contact hash
header = $~[1]
if header.strip.downcase == "default"
contact_hash = {
:trainer_type => "default"
}
else
line_data = pbGetCsvRecord($~[1], line_no, [0, "esU", :TrainerType])
contact_hash = {
:trainer_type => line_data[0],
:name => line_data[1],
:version => line_data[2] || 0
}
end
elsif line[/^\s*(\w+)\s*=\s*(.*)$/]
# XXX=YYY lines
if !contact_hash
raise _INTL("Expected a section at the beginning of the file.\r\n{1}", FileLineData.linereport)
end
property_name = $~[1]
line_schema = schema[property_name]
next if !line_schema
property_value = pbGetCsvRecord($~[2], line_no, line_schema)
# Record XXX=YYY setting
contact_hash[line_schema[0]] ||= []
contact_hash[line_schema[0]].push(property_value)
messages.push(property_value)
end
} }
MessageTypes.setMessagesAsHash(MessageTypes::PhoneMessages, sections) # Add last contact's data to records
save_data(database, "Data/phone.dat") if contact_hash
# Add contact's data to records
if contact_hash[:trainer_type] == "default"
contact_hash[:id] = contact_hash[:trainer_type]
else
contact_hash[:id] = [contact_hash[:trainer_type], contact_hash[:name], contact_hash[:version]]
end
GameData::PhoneMessage.register(contact_hash)
end
# Save all data
GameData::PhoneMessage.save
MessageTypes.setMessagesAsHash(MessageTypes::PhoneMessages, messages)
process_pbs_file_message_end process_pbs_file_message_end
end end
@@ -1816,6 +1848,110 @@ module Compiler
process_pbs_file_message_end process_pbs_file_message_end
end end
#=============================================================================
# Compile dungeon tileset data
#=============================================================================
def compile_dungeon_tilesets(path = "PBS/dungeon_tilesets.txt")
compile_pbs_file_message_start(path)
GameData::DungeonTileset::DATA.clear
schema = GameData::DungeonTileset::SCHEMA
tileset_hash = nil
# Read each line of dungeon_tilesets.txt at a time and compile it as a tileset property
idx = 0
pbCompilerEachPreppedLine(path) { |line, line_no|
echo "." if idx % 50 == 0
idx += 1
Graphics.update if idx % 250 == 0
if line[/^\s*\[\s*(.+)\s*\]\s*$/]
# New section
# Add tileset's data to records
GameData::DungeonTileset.register(tileset_hash) if tileset_hash
# Construct tileset hash
tileset_hash = {
:id => $~[1].to_i,
:tile => [],
:autotile => []
}
elsif line[/^\s*(\w+)\s*=\s*(.*)$/]
# XXX=YYY lines
if !tileset_hash
raise _INTL("Expected a section at the beginning of the file.\r\n{1}", FileLineData.linereport)
end
property_name = $~[1]
line_schema = schema[property_name]
next if !line_schema
property_value = pbGetCsvRecord($~[2], line_no, line_schema)
# Record XXX=YYY setting
case property_name
when "Tile", "Autotile"
tileset_hash[line_schema[0]].push(property_value)
else
tileset_hash[line_schema[0]] = property_value
end
end
}
# Add last tileset's data to records
GameData::DungeonTileset.register(tileset_hash) if tileset_hash
# Save all data
GameData::DungeonTileset.save
process_pbs_file_message_end
end
#=============================================================================
# Compile dungeon parameters data
#=============================================================================
def compile_dungeon_parameters(path = "PBS/dungeon_parameters.txt")
compile_pbs_file_message_start(path)
GameData::DungeonParameters::DATA.clear
schema = GameData::DungeonParameters::SCHEMA
# Read from PBS file
File.open(path, "rb") { |f|
FileLineData.file = path # For error reporting
# Read a whole section's lines at once, then run through this code.
# contents is a hash containing all the XXX=YYY lines in that section, where
# the keys are the XXX and the values are the YYY (as unprocessed strings).
idx = 0
pbEachFileSection(f) { |contents, section_name|
echo "." if idx % 50 == 0
idx += 1
Graphics.update if idx % 250 == 0
FileLineData.setSection(section_name, "header", nil) # For error reporting
# Split section_name into an area and version number
split_section_name = section_name.split(/[-,\s]/)
if split_section_name.length == 0 || split_section_name.length > 2
raise _INTL("Section name {1} is invalid ({2}). Expected syntax like [XXX] or [XXX,Y] (XXX=area, Y=version).", section_name, path)
end
area_symbol = split_section_name[0].downcase.to_sym
version = (split_section_name[1]) ? csvPosInt!(split_section_name[1]) : 0
# Construct parameters hash
area_version = (version > 0) ? sprintf("%s_%d", area_symbol.to_s, version).to_sym : area_symbol
parameters_hash = {
:id => area_version,
:area => area_symbol,
:version => version
}
# Go through schema hash of compilable data and compile this section
schema.each_key do |key|
# Skip empty properties (none are required)
if nil_or_empty?(contents[key])
contents[key] = nil
next
end
FileLineData.setSection(section_name, key, contents[key]) # For error reporting
# Compile value for key
value = pbGetCsvRecord(contents[key], key, schema[key])
value = nil if value.is_a?(Array) && value.length == 0
parameters_hash[schema[key][0]] = value
end
# Add parameters data to records
GameData::DungeonParameters.register(parameters_hash)
}
}
# Save all data
GameData::DungeonParameters.save
process_pbs_file_message_end
end
#============================================================================= #=============================================================================
# Compile battle animations # Compile battle animations
#============================================================================= #=============================================================================

View File

@@ -103,32 +103,26 @@ module Compiler
# Save phone messages to PBS file # Save phone messages to PBS file
#============================================================================= #=============================================================================
def write_phone(path = "PBS/phone.txt") def write_phone(path = "PBS/phone.txt")
data = load_data("Data/phone.dat") rescue nil
return if !data
write_pbs_file_message_start(path) write_pbs_file_message_start(path)
keys = GameData::PhoneMessage::SCHEMA.keys
File.open(path, "wb") { |f| File.open(path, "wb") { |f|
add_PBS_header_to_file(f) add_PBS_header_to_file(f)
f.write("\#-------------------------------\r\n") # Write message sets
f.write("[<Generics>]\r\n") GameData::PhoneMessage.each do |contact|
f.write(data.generics.join("\r\n") + "\r\n") f.write("\#-------------------------------\r\n")
f.write("\#-------------------------------\r\n") if contact.id == "default"
f.write("[<BattleRequests>]\r\n") f.write("[Default]\r\n")
f.write(data.battleRequests.join("\r\n") + "\r\n") elsif contact.version > 0
f.write("\#-------------------------------\r\n") f.write(sprintf("[%s,%s,%d]\r\n", contact.trainer_type, contact.real_name, contact.version))
f.write("[<GreetingsMorning>]\r\n") else
f.write(data.greetingsMorning.join("\r\n") + "\r\n") f.write(sprintf("[%s,%s]\r\n", contact.trainer_type, contact.real_name))
f.write("\#-------------------------------\r\n") end
f.write("[<GreetingsEvening>]\r\n") keys.each do |key|
f.write(data.greetingsEvening.join("\r\n") + "\r\n") msgs = contact.property_from_string(key)
f.write("\#-------------------------------\r\n") next if !msgs || msgs.length == 0
f.write("[<Greetings>]\r\n") msgs.each { |msg| f.write(key + " = " + msg + "\r\n") }
f.write(data.greetings.join("\r\n") + "\r\n") end
f.write("\#-------------------------------\r\n") end
f.write("[<Bodies1>]\r\n")
f.write(data.bodies1.join("\r\n") + "\r\n")
f.write("\#-------------------------------\r\n")
f.write("[<Bodies2>]\r\n")
f.write(data.bodies2.join("\r\n") + "\r\n")
} }
process_pbs_file_message_end process_pbs_file_message_end
end end
@@ -879,6 +873,91 @@ module Compiler
process_pbs_file_message_end process_pbs_file_message_end
end end
#=============================================================================
# Save dungeon tileset contents data to PBS file
#=============================================================================
def write_dungeon_tilesets(path = "PBS/dungeon_tilesets.txt")
write_pbs_file_message_start(path)
tilesets = load_data("Data/Tilesets.rxdata")
schema = GameData::DungeonTileset::SCHEMA
keys = schema.keys
File.open(path, "wb") { |f|
idx = 0
add_PBS_header_to_file(f)
GameData::DungeonTileset.each do |tileset_data|
echo "." if idx % 50 == 0
idx += 1
Graphics.update if idx % 250 == 0
f.write("\#-------------------------------\r\n")
tileset_name = (tilesets && tilesets[tileset_data.id]) ? tilesets[tileset_data.id].name : nil
if tileset_name
f.write(sprintf("[%d] # %s\r\n", tileset_data.id, tileset_name))
else
f.write(sprintf("[%d]\r\n", tileset_data.id))
end
keys.each do |key|
if ["Autotile", "Tile"].include?(key)
tiles = tileset_data.tile_type_ids
tiles.each do |tile_type, tile_ids|
tile_ids.each do |tile|
next if tile[1] # Tile was auto-generated from "walls" property
if tile[0] < 384
next if key == "Tile"
f.write(sprintf("Autotile = %i,%s", tile[0] / 48, tile_type.to_s))
else
next if key == "Autotile"
f.write(sprintf("Tile = %i,%s", tile[0] - 384, tile_type.to_s))
end
f.write("\r\n")
end
end
else
record = tileset_data.property_from_string(key)
next if record.nil? || (record.is_a?(Array) && record.empty?)
next if record == false || record == 0
f.write(sprintf("%s = ", key))
pbWriteCsvRecord(record, f, schema[key])
f.write("\r\n")
end
end
end
}
process_pbs_file_message_end
end
#=============================================================================
# Save dungeon parameters to PBS file
#=============================================================================
def write_dungeon_parameters(path = "PBS/dungeon_parameters.txt")
write_pbs_file_message_start(path)
schema = GameData::DungeonParameters::SCHEMA
keys = schema.keys
# Write file
File.open(path, "wb") { |f|
idx = 0
add_PBS_header_to_file(f)
GameData::DungeonParameters.each do |parameters_data|
echo "." if idx % 50 == 0
idx += 1
Graphics.update if idx % 250 == 0
f.write("\#-------------------------------\r\n")
if parameters_data.version > 0
f.write(sprintf("[%s,%d]\r\n", parameters_data.area, parameters_data.version))
else
f.write(sprintf("[%s]\r\n", parameters_data.area))
end
keys.each do |key|
value = parameters_data.property_from_string(key)
next if !value || (value.is_a?(Array) && value.length == 0)
f.write(sprintf("%s = ", key))
pbWriteCsvRecord(value, f, schema[key])
f.write("\r\n")
end
end
}
process_pbs_file_message_end
end
#============================================================================= #=============================================================================
# Save all data to PBS files # Save all data to PBS files
#============================================================================= #=============================================================================
@@ -886,7 +965,6 @@ module Compiler
Console.echo_h1 _INTL("Writing all PBS files") Console.echo_h1 _INTL("Writing all PBS files")
write_town_map write_town_map
write_connections write_connections
write_phone
write_types write_types
write_abilities write_abilities
write_moves write_moves
@@ -904,6 +982,9 @@ module Compiler
write_trainer_lists write_trainer_lists
write_metadata write_metadata
write_map_metadata write_map_metadata
write_dungeon_tilesets
write_dungeon_parameters
write_phone
echoln "" echoln ""
Console.echo_h2("Successfully rewrote all PBS files", text: :green) Console.echo_h2("Successfully rewrote all PBS files", text: :green)
end end

View File

@@ -506,7 +506,7 @@ module Compiler
end end
end end
# Compile the trainer comments # Compile the trainer comments
rewriteComments = true #false # You can change this rewriteComments = false # You can change this
battles = [] battles = []
trtype = nil trtype = nil
trname = nil trname = nil
@@ -519,6 +519,7 @@ module Compiler
endifswitch = [] endifswitch = []
vanishifswitch = [] vanishifswitch = []
regspeech = nil regspeech = nil
common_event = 0
commands.each do |command| commands.each do |command|
if command[/^Battle\:\s*([\s\S]+)$/i] if command[/^Battle\:\s*([\s\S]+)$/i]
battles.push($~[1]) battles.push($~[1])
@@ -558,6 +559,9 @@ module Compiler
elsif command[/^RegSpeech\:\s*([\s\S]+)$/i] elsif command[/^RegSpeech\:\s*([\s\S]+)$/i]
regspeech = $~[1].gsub(/^\s+/, "").gsub(/\s+$/, "") regspeech = $~[1].gsub(/^\s+/, "").gsub(/\s+$/, "")
push_comment(firstpage.list, command) if rewriteComments push_comment(firstpage.list, command) if rewriteComments
elsif command[/^CommonEvent\:\s*(\d+)$/i]
common_event = $~[1].to_i
push_comment(firstpage.list, command) if rewriteComments
end end
end end
return nil if battles.length <= 0 return nil if battles.length <= 0
@@ -600,10 +604,18 @@ module Compiler
push_text(firstpage.list, regspeech, 2) push_text(firstpage.list, regspeech, 2)
push_choices(firstpage.list, ["Yes", "No"], 2, 2) push_choices(firstpage.list, ["Yes", "No"], 2, 2)
push_choice(firstpage.list, 0, "Yes", 3) push_choice(firstpage.list, 0, "Yes", 3)
if battleid > 0 if common_event > 0
push_script(firstpage.list, sprintf("Phone.add(get_self,\n %s, %d, %d\n)", brieftrcombo, battles.length, battleid), 3) if battleid > 0
push_script(firstpage.list, sprintf("Phone.add(get_self,\n %s, %d, %d, %d\n)", brieftrcombo, battles.length, battleid, common_event), 3)
else
push_script(firstpage.list, sprintf("Phone.add(get_self,\n %s, %d, nil, %d\n)", brieftrcombo, battles.length, common_event), 3)
end
else else
push_script(firstpage.list, sprintf("Phone.add(get_self,\n %s, %d\n)", brieftrcombo, battles.length), 3) if battleid > 0
push_script(firstpage.list, sprintf("Phone.add(get_self,\n %s, %d, %d\n)", brieftrcombo, battles.length, battleid), 3)
else
push_script(firstpage.list, sprintf("Phone.add(get_self,\n %s, %d\n)", brieftrcombo, battles.length), 3)
end
end end
push_choice(firstpage.list, 1, "No", 3) push_choice(firstpage.list, 1, "No", 3)
push_choices_end(firstpage.list, 3) push_choices_end(firstpage.list, 3)
@@ -679,10 +691,18 @@ module Compiler
push_text(lastpage.list, regspeech, 1) push_text(lastpage.list, regspeech, 1)
push_choices(lastpage.list, ["Yes", "No"], 2, 1) push_choices(lastpage.list, ["Yes", "No"], 2, 1)
push_choice(lastpage.list, 0, "Yes", 2) push_choice(lastpage.list, 0, "Yes", 2)
if battleid > 0 if common_event > 0
push_script(lastpage.list, sprintf("Phone.add(get_self,\n %s, %d, %d\n)", brieftrcombo, battles.length, battleid), 2) if battleid > 0
push_script(lastpage.list, sprintf("Phone.add(get_self,\n %s, %d, %d, %d\n)", brieftrcombo, battles.length, battleid, common_event), 2)
else
push_script(lastpage.list, sprintf("Phone.add(get_self,\n %s, %d, nil, %d\n)", brieftrcombo, battles.length, common_event), 2)
end
else else
push_script(lastpage.list, sprintf("Phone.add(get_self,\n %s, %d\n)", brieftrcombo, battles.length), 2) if battleid > 0
push_script(lastpage.list, sprintf("Phone.add(get_self,\n %s, %d, %d\n)", brieftrcombo, battles.length, battleid), 2)
else
push_script(lastpage.list, sprintf("Phone.add(get_self,\n %s, %d\n)", brieftrcombo, battles.length), 2)
end
end end
push_choice(lastpage.list, 1, "No", 2) push_choice(lastpage.list, 1, "No", 2)
push_choices_end(lastpage.list, 2) push_choices_end(lastpage.list, 2)

View File

@@ -0,0 +1,30 @@
# See the documentation on the wiki to learn how to edit this file.
#-------------------------------
[cave]
DungeonSize = 5,4
CellSize = 10,10
MinRoomSize = 5,5
MaxRoomSize = 9,9
CorridorWidth = 2
ShiftCorridors = true
NodeLayout = full
RoomLayout = full
RoomChance = 70
ExtraConnections = 2
FloorPatches = 2,50,25
FloorDecorations = 50,200
VoidDecorations = 50,200
#-------------------------------
[forest]
DungeonSize = 5,4
CellSize = 10,10
MinRoomSize = 4,4
MaxRoomSize = 8,8
CorridorWidth = 2
NodeLayout = full
RoomLayout = full
RoomChance = 70
ExtraConnections = 2
FloorPatches = 3,75,25
FloorDecorations = 50,200
VoidDecorations = 50,200

28
PBS/dungeon_tilesets.txt Normal file
View File

@@ -0,0 +1,28 @@
# See the documentation on the wiki to learn how to edit this file.
#-------------------------------
[7] # Dungeon cave
Autotile = 1,floor_patch
Tile = 40,void
Tile = 41,void_decoration
Tile = 48,void_decoration_large
Tile = 42,floor
Tile = 50,floor_decoration_large
Tile = 0,walls
DoubleWalls = true
FloorPatchUnderWalls = true
#-------------------------------
[23] # Dungeon forest
Autotile = 1,floor_decoration
Tile = 40,void
Tile = 42,floor
Tile = 43,floor
Tile = 44,floor
Tile = 45,floor
Tile = 46,floor
Tile = 47,floor_patch
Tile = 8,walls
Tile = 25,wall_top
SnapToLargeGrid = true
LargeVoidTiles = true
LargeWallTiles = true
ThinNorthWallOffset = -8

View File

@@ -1,34 +1,48 @@
# See the documentation on the wiki to learn how to edit this file. # See the documentation on the wiki to learn how to edit this file.
#------------------------------- #-------------------------------
[<Generics>] [Default]
How are your Pokémon doing?\mMy \TP's really energetic. It's a handful!\mOh yeah, I managed to beat a tough \TE.\mI need to make my party stronger. Intro = Hello. This is \TN.
My \TP's looking really awesome.\mI wish I could show you.\mHey, listen! I almost caught a \TE the other day.\mOh, it was sooooooo close, too! Intro = Good day, \PN! Hi. This is \TN.
Intro = How are you doing? \PN, howdy! This is \TN. Isn't it nice out?
Intro = \PN, good day! It's me, \TN. Got a minute?
Intro = Hello, \PN. This is \TN. How are things?
IntroMorning = Good morning, \PN. This is \TN. Did I wake you?
IntroAfternoon = Good afternoon, \PN! It's \TN here.
IntroEvening = \PN, good evening! Hi. This is \TN.
Body = How are your Pokémon doing?\mMy \TP's really energetic. It's a handful!\mOh yeah, I managed to beat a tough \TE.\mI need to make my party stronger.
Body = My \TP's looking really awesome. I wish I could show you.\mHey, listen! I almost caught a \TE the other day.\mOh, it was sooooooo close, too!
Body1 = How are your Pokémon doing?\mMy \TP's really energetic. It's a handful!
Body1 = How are your Pokémon doing?\mI always keep my \TP in top shape by going to Pokémon Centers.
Body1 = My \TP's looking really awesome. I wish I could show you.
Body1 = I dressed my \TP and it looks even cuter than before.
Body2 = Oh yeah, I managed to beat a tough \TE.\mI need to make my party stronger.
Body2 = You have to hear this! I battled \TE the other day.\mIt was easy! I had a type advantage.
Body2 = Hey, listen! I almost caught \TE the other day.\mOh, it was sooooooo close, too!
Body2 = Guess what happened the other day. I missed catching \TE again.\mMaybe I'm not very good at this.
BattleRequest = Want to battle? It's not going to be a repeat of the last time we met.\mI'll be waiting for you around \TM.
BattleRequest = Do you want to battle? I'm going to win this time!\mI'll be waiting for you around \TM.\mLook for me, OK? My \TP will be expecting you.
#------------------------------- #-------------------------------
[<BattleRequests>] [CAMPER,Jeff]
Want to battle? It's not going to be a repeat of the last time we met.\mI'll be waiting for you around \TM. Intro = Hello. This is \TN...\mHow's it going, \PN?
Do you want to battle? I'm going to win this time!\mI'll be waiting for you around \TM.\mLook for me, OK? My \TP will be expecting you. Body1 = My \TP is looking more and more like me. It's getting cuter!
Body2 = And you know? Now we can KO \TE easily.\mI should challenge the Cedolan Gym.
Body2 = And you know? We just failed to beat \TE by a tiny margin.\mI'm guessing my Pokémon's levels aren't high enough yet...
BattleRequest = You must be a lot better now, huh?\mHow about showing me your technique in a real battle with me?\mI'll be waiting on \TM.
BattleReminder = Where are you? Let's have our battle soon!\mI'll be waiting on \TM.
End = See you later!
#------------------------------- #-------------------------------
[<GreetingsMorning>] [PICNICKER,Susie]
Good morning, \PN.\mThis is \TN. Did I wake you? Intro = This is \TN!
#------------------------------- Intro = Hi, this is \TN!
[<GreetingsEvening>] IntroMorning = This is \TN! Good morning, \PN!
\PN, good evening! Hi.\mThis is \TN. IntroMorning = Hi, this is \TN! Good morning, \PN!
#------------------------------- IntroAfternoon = This is \TN! Good afternoon, \PN!
[<Greetings>] IntroAfternoon = Hi, this is \TN! Good afternoon, \PN!
Hello. This is \TN. IntroEvening = This is \TN! Good evening, \PN!
Good day, \PN! Hi. This is \TN. IntroEvening = Hi, this is \TN! Good evening, \PN!
How are you doing? \PN, howdy! This is \TN. Isn't it nice out? Body1 = My \TP and I are getting more in sync with each other.
\PN, good day! It's me, \TN. Got a minute? Body2 = We battled a wild \TE and managed to beat it in a close match.\mWe're getting into the groove!
Hello, \PN. This is \TN. How are things? Body2 = But, you know what? I still haven't caught \TE.\mIt's getting beyond frustrating...
#------------------------------- BattleRequest = Would you be my practice partner again sometime?\mI'll be waiting on \TM...\mCould you take it a little easier on me next time?
[<Bodies1>] BattleReminder = How soon can I expect to see you?\mDon't forget, \TM!
How are your Pokémon doing?\mMy \TP's really energetic. It's a handful! End = Bye! Let's chat again!
How are your Pokémon doing?\mI always keep my \TP in top shape by going to Pokémon Centers.
My \TP's looking really awesome. I wish I could show you.
I dressed my \TP and it looks even cuter than before.
#-------------------------------
[<Bodies2>]
Oh yeah, I managed to beat a tough \TE.\mI need to make my party stronger.
You have to hear this! I battled \TE the other day.\mIt was easy! I had a type advantage.
Hey, listen! I almost caught \TE the other day.\mOh, it was sooooooo close, too!
Guess what happened the other day. I missed catching \TE again.\mMaybe I'm not very good at this.