mirror of
https://github.com/Maruno17/pokemon-essentials.git
synced 2025-09-24 18:41:27 +02:00
Rewrote the random dungeon generator code
This commit is contained in:
@@ -37,23 +37,38 @@ class TileDrawingHelper
|
||||
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 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
|
||||
yp1 = [y + 1, data.ysize - 1].min
|
||||
xm1 = [x - 1, 0].max
|
||||
ym1 = [y - 1, 0].max
|
||||
i = 0
|
||||
i |= 0x01 if data[x, ym1] == t # N
|
||||
i |= 0x02 if data[xp1, ym1] == t # NE
|
||||
i |= 0x04 if data[xp1, y] == t # E
|
||||
i |= 0x08 if data[xp1, yp1] == t # SE
|
||||
i |= 0x10 if data[x, yp1] == t # S
|
||||
i |= 0x20 if data[xm1, yp1] == t # SW
|
||||
i |= 0x40 if data[xm1, y] == t # W
|
||||
i |= 0x80 if data[xm1, ym1] == t # NW
|
||||
if layer.nil?
|
||||
i |= 0x01 if data[ x, ym1] == t # N
|
||||
i |= 0x02 if data[xp1, ym1] == t # NE
|
||||
i |= 0x04 if data[xp1, y] == t # E
|
||||
i |= 0x08 if data[xp1, yp1] == t # SE
|
||||
i |= 0x10 if data[ x, yp1] == t # S
|
||||
i |= 0x20 if data[xm1, yp1] == t # SW
|
||||
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
|
||||
end
|
||||
|
||||
|
@@ -240,6 +240,8 @@ module GameData
|
||||
Metadata.load
|
||||
PlayerMetadata.load
|
||||
MapMetadata.load
|
||||
DungeonTileset.load
|
||||
DungeonParameters.load
|
||||
PhoneMessage.load
|
||||
end
|
||||
end
|
||||
|
209
Data/Scripts/010_Data/002_PBS data/018_DungeonTileset.rb
Normal file
209
Data/Scripts/010_Data/002_PBS data/018_DungeonTileset.rb
Normal 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
|
138
Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb
Normal file
138
Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb
Normal 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
|
File diff suppressed because it is too large
Load Diff
@@ -516,7 +516,6 @@ class Phone
|
||||
else
|
||||
# Standard messages
|
||||
if messages.body1 && messages.body2 && (!messages.body || rand(100) < 75)
|
||||
echoln messages.body2
|
||||
# Choose random pair of body messages
|
||||
ret += get_random_message.call(messages.body1)
|
||||
ret += "\\m"
|
||||
|
@@ -79,7 +79,6 @@ class BugContestState
|
||||
@contestMaps.push(map)
|
||||
end
|
||||
end
|
||||
echoln "contest maps: #{@contestMaps}"
|
||||
end
|
||||
|
||||
# Reception map is handled separately from contest map since the reception map
|
||||
@@ -94,7 +93,6 @@ class BugContestState
|
||||
@reception.push(map)
|
||||
end
|
||||
end
|
||||
echoln "reception maps: #{@reception}"
|
||||
end
|
||||
|
||||
def pbOffLimits?(map)
|
||||
|
@@ -70,7 +70,32 @@ def toCelsius(fahrenheit)
|
||||
return ((fahrenheit - 32) * 5.0 / 9.0).round
|
||||
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
|
||||
@@ -125,8 +150,6 @@ def getConstantNameOrValue(mod, value)
|
||||
return value.inspect
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Event utilities
|
||||
#===============================================================================
|
||||
@@ -196,8 +219,6 @@ def pbNoticePlayer(event)
|
||||
pbMoveTowardPlayer(event)
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Player-related utilities, random name generator
|
||||
#===============================================================================
|
||||
@@ -339,8 +360,6 @@ def getRandomName(maxLength = 100)
|
||||
return getRandomNameEx(2, nil, nil, maxLength)
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Regional and National Pokédexes utilities
|
||||
#===============================================================================
|
||||
@@ -387,8 +406,6 @@ def pbGetRegionalDexLength(region_dex)
|
||||
return (dex_list) ? dex_list.length : 0
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Other utilities
|
||||
#===============================================================================
|
||||
|
@@ -1128,6 +1128,8 @@ MenuHandlers.add(:debug_menu, :create_pbs_files, {
|
||||
"abilities.txt",
|
||||
"battle_facility_lists.txt",
|
||||
"berry_plants.txt",
|
||||
"dungeon_parameters.txt",
|
||||
"dungeon_tilesets.txt",
|
||||
"encounters.txt",
|
||||
"items.txt",
|
||||
"map_connections.txt",
|
||||
@@ -1153,23 +1155,25 @@ MenuHandlers.add(:debug_menu, :create_pbs_files, {
|
||||
when 1 then Compiler.write_abilities
|
||||
when 2 then Compiler.write_trainer_lists
|
||||
when 3 then Compiler.write_berry_plants
|
||||
when 4 then Compiler.write_encounters
|
||||
when 5 then Compiler.write_items
|
||||
when 6 then Compiler.write_connections
|
||||
when 7 then Compiler.write_map_metadata
|
||||
when 8 then Compiler.write_metadata
|
||||
when 9 then Compiler.write_moves
|
||||
when 10 then Compiler.write_phone
|
||||
when 11 then Compiler.write_pokemon
|
||||
when 12 then Compiler.write_pokemon_forms
|
||||
when 13 then Compiler.write_pokemon_metrics
|
||||
when 14 then Compiler.write_regional_dexes
|
||||
when 15 then Compiler.write_ribbons
|
||||
when 16 then Compiler.write_shadow_pokemon
|
||||
when 17 then Compiler.write_town_map
|
||||
when 18 then Compiler.write_trainer_types
|
||||
when 19 then Compiler.write_trainers
|
||||
when 20 then Compiler.write_types
|
||||
when 4 then Compiler.write_dungeon_parameters
|
||||
when 5 then Compiler.write_dungeon_tilesets
|
||||
when 6 then Compiler.write_encounters
|
||||
when 7 then Compiler.write_items
|
||||
when 8 then Compiler.write_connections
|
||||
when 9 then Compiler.write_map_metadata
|
||||
when 10 then Compiler.write_metadata
|
||||
when 11 then Compiler.write_moves
|
||||
when 12 then Compiler.write_phone
|
||||
when 13 then Compiler.write_pokemon
|
||||
when 14 then Compiler.write_pokemon_forms
|
||||
when 15 then Compiler.write_pokemon_metrics
|
||||
when 16 then Compiler.write_regional_dexes
|
||||
when 17 then Compiler.write_ribbons
|
||||
when 18 then Compiler.write_shadow_pokemon
|
||||
when 19 then Compiler.write_town_map
|
||||
when 20 then Compiler.write_trainer_types
|
||||
when 21 then Compiler.write_trainers
|
||||
when 22 then Compiler.write_types
|
||||
else break
|
||||
end
|
||||
pbMessage(_INTL("File written."))
|
||||
|
@@ -774,6 +774,8 @@ module Compiler
|
||||
compile_trainer_lists # Depends on TrainerType
|
||||
compile_metadata # Depends on TrainerType
|
||||
compile_map_metadata
|
||||
compile_dungeon_tilesets
|
||||
compile_dungeon_parameters
|
||||
compile_phone # Depends on TrainerType
|
||||
end
|
||||
|
||||
@@ -805,6 +807,8 @@ module Compiler
|
||||
dataFiles = [
|
||||
"abilities.dat",
|
||||
"berry_plants.dat",
|
||||
"dungeon_parameters.dat",
|
||||
"dungeon_tilesets.dat",
|
||||
"encounters.dat",
|
||||
"items.dat",
|
||||
"map_connections.dat",
|
||||
@@ -828,6 +832,8 @@ module Compiler
|
||||
"abilities.txt",
|
||||
"battle_facility_lists.txt",
|
||||
"berry_plants.txt",
|
||||
"dungeon_parameters.txt",
|
||||
"dungeon_tilesets.txt",
|
||||
"encounters.txt",
|
||||
"items.txt",
|
||||
"map_connections.txt",
|
||||
|
@@ -1848,6 +1848,110 @@ module Compiler
|
||||
process_pbs_file_message_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
|
||||
#=============================================================================
|
||||
|
@@ -873,6 +873,91 @@ module Compiler
|
||||
process_pbs_file_message_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
|
||||
#=============================================================================
|
||||
@@ -897,6 +982,8 @@ module Compiler
|
||||
write_trainer_lists
|
||||
write_metadata
|
||||
write_map_metadata
|
||||
write_dungeon_tilesets
|
||||
write_dungeon_parameters
|
||||
write_phone
|
||||
echoln ""
|
||||
Console.echo_h2("Successfully rewrote all PBS files", text: :green)
|
||||
|
30
PBS/dungeon_parameters.txt
Normal file
30
PBS/dungeon_parameters.txt
Normal 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
28
PBS/dungeon_tilesets.txt
Normal 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
|
Reference in New Issue
Block a user