mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-09 14:14:59 +00:00
Remove Scripts folder to convert to submodule
This commit is contained in:
@@ -1,518 +0,0 @@
|
||||
# All weather particles are assumed to start at the top/right and move to the
|
||||
# bottom/left. Particles are only reset if they are off-screen to the left or
|
||||
# bottom.
|
||||
module RPG
|
||||
class Weather
|
||||
attr_reader :type
|
||||
attr_reader :max
|
||||
attr_reader :ox
|
||||
attr_reader :oy
|
||||
MAX_SPRITES = 60
|
||||
FADE_OLD_TILES_START = 0
|
||||
FADE_OLD_TILES_END = 1
|
||||
FADE_OLD_TONE_START = 0
|
||||
FADE_OLD_TONE_END = 2
|
||||
FADE_OLD_PARTICLES_START = 1
|
||||
FADE_OLD_PARTICLES_END = 3
|
||||
FADE_NEW_PARTICLES_START = 2
|
||||
FADE_NEW_PARTICLES_END = 4
|
||||
FADE_NEW_TONE_START = 3 # Shouldn't be sooner than FADE_OLD_TONE_END + 1
|
||||
FADE_NEW_TONE_END = 5
|
||||
FADE_NEW_TILES_START = 4 # Shouldn't be sooner than FADE_OLD_TILES_END
|
||||
FADE_NEW_TILES_END = 5
|
||||
|
||||
def initialize(viewport = nil)
|
||||
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
|
||||
@viewport.z = viewport.z + 1
|
||||
@origViewport = viewport
|
||||
# [array of particle bitmaps, array of tile bitmaps,
|
||||
# +x per second (particle), +y per second (particle), +opacity per second (particle),
|
||||
# +x per second (tile), +y per second (tile)]
|
||||
@weatherTypes = {}
|
||||
@type = :None
|
||||
@max = 0
|
||||
@ox = 0
|
||||
@oy = 0
|
||||
@tiles_wide = 0
|
||||
@tiles_tall = 0
|
||||
@tile_x = 0.0
|
||||
@tile_y = 0.0
|
||||
@sun_magnitude = 0 # +/- maximum addition to sun tone
|
||||
@sun_strength = 0 # Current addition to sun tone (0 to @sun_magnitude)
|
||||
@time_until_flash = 0
|
||||
@sprites = []
|
||||
@sprite_lifetimes = []
|
||||
@tiles = []
|
||||
@new_sprites = []
|
||||
@new_sprite_lifetimes = []
|
||||
@fading = false
|
||||
end
|
||||
|
||||
def dispose
|
||||
@sprites.each { |sprite| sprite.dispose if sprite }
|
||||
@new_sprites.each { |sprite| sprite.dispose if sprite }
|
||||
@tiles.each { |sprite| sprite.dispose if sprite }
|
||||
@viewport.dispose
|
||||
@weatherTypes.each_value do |weather|
|
||||
next if !weather
|
||||
weather[1].each { |bitmap| bitmap.dispose if bitmap }
|
||||
weather[2].each { |bitmap| bitmap.dispose if bitmap }
|
||||
end
|
||||
end
|
||||
|
||||
def fade_in(new_type, new_max, duration = 1)
|
||||
return if @fading
|
||||
new_type = GameData::Weather.get(new_type).id
|
||||
new_max = 0 if new_type == :None
|
||||
return if @type == new_type && @max == new_max
|
||||
if duration > 0
|
||||
@target_type = new_type
|
||||
@target_max = new_max
|
||||
prepare_bitmaps(@target_type)
|
||||
@old_max = @max
|
||||
@new_max = 0 # Current number of new particles
|
||||
@old_tone = Tone.new(@viewport.tone.red, @viewport.tone.green,
|
||||
@viewport.tone.blue, @viewport.tone.gray)
|
||||
@target_tone = get_weather_tone(@target_type, @target_max)
|
||||
@fade_time = 0.0
|
||||
@time_shift = 0
|
||||
if @type == :None
|
||||
@time_shift += 2 # No previous weather to fade out first
|
||||
elsif !GameData::Weather.get(@type).has_tiles?
|
||||
@time_shift += 1 # No previous tiles to fade out first
|
||||
end
|
||||
@fading = true
|
||||
@new_sprites.each { |sprite| sprite.dispose if sprite }
|
||||
@new_sprites.clear
|
||||
ensureSprites
|
||||
@new_sprites.each_with_index { |sprite, i| set_sprite_bitmap(sprite, i, @target_type) }
|
||||
else
|
||||
self.type = new_type
|
||||
self.max = new_max
|
||||
end
|
||||
end
|
||||
|
||||
def type=(type)
|
||||
type = GameData::Weather.get(type).id
|
||||
return if @type == type
|
||||
if @fading
|
||||
@max = @target_max
|
||||
@fading = false
|
||||
end
|
||||
@type = type
|
||||
prepare_bitmaps(@type)
|
||||
if GameData::Weather.get(@type).has_tiles?
|
||||
w = @weatherTypes[@type][2][0].width
|
||||
h = @weatherTypes[@type][2][0].height
|
||||
@tiles_wide = (Graphics.width.to_f / w).ceil + 1
|
||||
@tiles_tall = (Graphics.height.to_f / h).ceil + 1
|
||||
else
|
||||
@tiles_wide = @tiles_tall = 0
|
||||
end
|
||||
ensureSprites
|
||||
@sprites.each_with_index { |sprite, i| set_sprite_bitmap(sprite, i, @type) }
|
||||
ensureTiles
|
||||
@tiles.each_with_index { |sprite, i| set_tile_bitmap(sprite, i, @type) }
|
||||
end
|
||||
|
||||
def max=(value)
|
||||
return if @max == value
|
||||
@max = value.clamp(0, MAX_SPRITES)
|
||||
ensureSprites
|
||||
for i in 0...MAX_SPRITES
|
||||
@sprites[i].visible = (i < @max) if @sprites[i]
|
||||
end
|
||||
end
|
||||
|
||||
def ox=(value)
|
||||
return if value == @ox
|
||||
@ox = value
|
||||
@sprites.each { |sprite| sprite.ox = @ox if sprite }
|
||||
@new_sprites.each { |sprite| sprite.ox = @ox if sprite }
|
||||
@tiles.each { |sprite| sprite.ox = @ox if sprite }
|
||||
end
|
||||
|
||||
def oy=(value)
|
||||
return if value == @oy
|
||||
@oy = value
|
||||
@sprites.each { |sprite| sprite.oy = @oy if sprite }
|
||||
@new_sprites.each { |sprite| sprite.oy = @oy if sprite }
|
||||
@tiles.each { |sprite| sprite.oy = @oy if sprite }
|
||||
end
|
||||
|
||||
def get_weather_tone(weather_type, maximum)
|
||||
return GameData::Weather.get(weather_type).tone(maximum)
|
||||
end
|
||||
|
||||
def prepare_bitmaps(new_type)
|
||||
weather_data = GameData::Weather.get(new_type)
|
||||
bitmap_names = weather_data.graphics
|
||||
@weatherTypes[new_type] = [weather_data, [], []]
|
||||
for i in 0...2 # 0=particles, 1=tiles
|
||||
next if !bitmap_names[i]
|
||||
bitmap_names[i].each do |name|
|
||||
bitmap = RPG::Cache.load_bitmap("Graphics/Weather/", name)
|
||||
@weatherTypes[new_type][i + 1].push(bitmap)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ensureSprites
|
||||
if @sprites.length < MAX_SPRITES && @weatherTypes[@type] && @weatherTypes[@type][1].length > 0
|
||||
for i in 0...MAX_SPRITES
|
||||
if !@sprites[i]
|
||||
sprite = Sprite.new(@origViewport)
|
||||
sprite.z = 1000
|
||||
sprite.ox = @ox
|
||||
sprite.oy = @oy
|
||||
sprite.opacity = 0
|
||||
@sprites[i] = sprite
|
||||
end
|
||||
@sprites[i].visible = (i < @max)
|
||||
@sprite_lifetimes[i] = 0
|
||||
end
|
||||
end
|
||||
if @fading && @new_sprites.length < MAX_SPRITES && @weatherTypes[@target_type] &&
|
||||
@weatherTypes[@target_type][1].length > 0
|
||||
for i in 0...MAX_SPRITES
|
||||
if !@new_sprites[i]
|
||||
sprite = Sprite.new(@origViewport)
|
||||
sprite.z = 1000
|
||||
sprite.ox = @ox
|
||||
sprite.oy = @oy
|
||||
sprite.opacity = 0
|
||||
@new_sprites[i] = sprite
|
||||
end
|
||||
@new_sprites[i].visible = (i < @new_max)
|
||||
@new_sprite_lifetimes[i] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ensureTiles
|
||||
return if @tiles.length >= @tiles_wide * @tiles_tall
|
||||
for i in 0...(@tiles_wide * @tiles_tall)
|
||||
if !@tiles[i]
|
||||
sprite = Sprite.new(@origViewport)
|
||||
sprite.z = 1000
|
||||
sprite.ox = @ox
|
||||
sprite.oy = @oy
|
||||
sprite.opacity = 0
|
||||
@tiles[i] = sprite
|
||||
end
|
||||
@tiles[i].visible = true
|
||||
end
|
||||
end
|
||||
|
||||
def set_sprite_bitmap(sprite, index, weather_type)
|
||||
return if !sprite
|
||||
weatherBitmaps = (@weatherTypes[weather_type]) ? @weatherTypes[weather_type][1] : nil
|
||||
if !weatherBitmaps || weatherBitmaps.length == 0
|
||||
sprite.bitmap = nil
|
||||
return
|
||||
end
|
||||
if @weatherTypes[weather_type][0].category == :Rain
|
||||
last_index = weatherBitmaps.length - 1 # Last sprite is a splash
|
||||
if (index % 2) == 0
|
||||
sprite.bitmap = weatherBitmaps[index % last_index]
|
||||
else
|
||||
sprite.bitmap = weatherBitmaps[last_index]
|
||||
end
|
||||
else
|
||||
sprite.bitmap = weatherBitmaps[index % weatherBitmaps.length]
|
||||
end
|
||||
end
|
||||
|
||||
def set_tile_bitmap(sprite, index, weather_type)
|
||||
return if !sprite || !weather_type
|
||||
weatherBitmaps = (@weatherTypes[weather_type]) ? @weatherTypes[weather_type][2] : nil
|
||||
if weatherBitmaps && weatherBitmaps.length > 0
|
||||
sprite.bitmap = weatherBitmaps[index % weatherBitmaps.length]
|
||||
else
|
||||
sprite.bitmap = nil
|
||||
end
|
||||
end
|
||||
|
||||
def reset_sprite_position(sprite, index, is_new_sprite = false)
|
||||
weather_type = (is_new_sprite) ? @target_type : @type
|
||||
lifetimes = (is_new_sprite) ? @new_sprite_lifetimes : @sprite_lifetimes
|
||||
if index < (is_new_sprite ? @new_max : @max)
|
||||
sprite.visible = true
|
||||
else
|
||||
sprite.visible = false
|
||||
lifetimes[index] = 0
|
||||
return
|
||||
end
|
||||
if @weatherTypes[weather_type][0].category == :Rain && (index % 2) != 0 # Splash
|
||||
sprite.x = @ox - sprite.bitmap.width + rand(Graphics.width + sprite.bitmap.width * 2)
|
||||
sprite.y = @oy - sprite.bitmap.height + rand(Graphics.height + sprite.bitmap.height * 2)
|
||||
lifetimes[index] = (30 + rand(20)) * 0.01 # 0.3-0.5 seconds
|
||||
else
|
||||
x_speed = @weatherTypes[weather_type][0].particle_delta_x
|
||||
y_speed = @weatherTypes[weather_type][0].particle_delta_y
|
||||
gradient = x_speed.to_f / y_speed
|
||||
if gradient.abs >= 1
|
||||
# Position sprite to the right of the screen
|
||||
sprite.x = @ox + Graphics.width + rand(Graphics.width)
|
||||
sprite.y = @oy + Graphics.height - rand(Graphics.height + sprite.bitmap.height - Graphics.width / gradient)
|
||||
distance_to_cover = sprite.x - @ox - Graphics.width / 2 + sprite.bitmap.width + rand(Graphics.width * 8 / 5)
|
||||
lifetimes[index] = (distance_to_cover.to_f / x_speed).abs
|
||||
else
|
||||
# Position sprite to the top of the screen
|
||||
sprite.x = @ox - sprite.bitmap.width + rand(Graphics.width + sprite.bitmap.width - gradient * Graphics.height)
|
||||
sprite.y = @oy - sprite.bitmap.height - rand(Graphics.height)
|
||||
distance_to_cover = @oy - sprite.y + Graphics.height / 2 + rand(Graphics.height * 8 / 5)
|
||||
lifetimes[index] = (distance_to_cover.to_f / y_speed).abs
|
||||
end
|
||||
end
|
||||
sprite.opacity = 255
|
||||
end
|
||||
|
||||
def update_sprite_position(sprite, index, is_new_sprite = false)
|
||||
return if !sprite || !sprite.bitmap || !sprite.visible
|
||||
delta_t = Graphics.delta_s
|
||||
lifetimes = (is_new_sprite) ? @new_sprite_lifetimes : @sprite_lifetimes
|
||||
if lifetimes[index] >= 0
|
||||
lifetimes[index] -= delta_t
|
||||
if lifetimes[index] <= 0
|
||||
reset_sprite_position(sprite, index, is_new_sprite)
|
||||
return
|
||||
end
|
||||
end
|
||||
# Determine which weather type this sprite is representing
|
||||
weather_type = (is_new_sprite) ? @target_type : @type
|
||||
# Update visibility/position/opacity of sprite
|
||||
if @weatherTypes[weather_type][0].category == :Rain && (index % 2) != 0 # Splash
|
||||
sprite.opacity = (lifetimes[index] < 0.4) ? 255 : 0 # 0.2 seconds
|
||||
else
|
||||
dist_x = @weatherTypes[weather_type][0].particle_delta_x * delta_t
|
||||
dist_y = @weatherTypes[weather_type][0].particle_delta_y * delta_t
|
||||
sprite.x += dist_x
|
||||
sprite.y += dist_y
|
||||
if weather_type == :Snow
|
||||
sprite.x += dist_x * (sprite.y - @oy) / (Graphics.height * 3) # Faster when further down screen
|
||||
sprite.x += [2, 1, 0, -1][rand(4)] * dist_x / 8 # Random movement
|
||||
sprite.y += [2, 1, 1, 0, 0, -1][index % 6] * dist_y / 10 # Variety
|
||||
end
|
||||
sprite.opacity += @weatherTypes[weather_type][0].particle_delta_opacity * delta_t
|
||||
x = sprite.x - @ox
|
||||
y = sprite.y - @oy
|
||||
# Check if sprite is off-screen; if so, reset it
|
||||
if sprite.opacity < 64 || x < -sprite.bitmap.width || y > Graphics.height
|
||||
reset_sprite_position(sprite, index, is_new_sprite)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def recalculate_tile_positions
|
||||
delta_t = Graphics.delta_s
|
||||
weather_type = @type
|
||||
if @fading && @fade_time >= [FADE_OLD_TONE_END - @time_shift, 0].max
|
||||
weather_type = @target_type
|
||||
end
|
||||
@tile_x += @weatherTypes[weather_type][0].tile_delta_x * delta_t
|
||||
@tile_y += @weatherTypes[weather_type][0].tile_delta_y * delta_t
|
||||
if @tile_x < -@tiles_wide * @weatherTypes[weather_type][2][0].width
|
||||
@tile_x += @tiles_wide * @weatherTypes[weather_type][2][0].width
|
||||
end
|
||||
if @tile_y > @tiles_tall * @weatherTypes[weather_type][2][0].height
|
||||
@tile_y -= @tiles_tall * @weatherTypes[weather_type][2][0].height
|
||||
end
|
||||
end
|
||||
|
||||
def update_tile_position(sprite, index)
|
||||
return if $PokemonSystem.on_mobile
|
||||
return if !sprite || !sprite.bitmap || !sprite.visible
|
||||
sprite.x = (@ox + @tile_x + (index % @tiles_wide) * sprite.bitmap.width).round
|
||||
sprite.y = (@oy + @tile_y + (index / @tiles_wide) * sprite.bitmap.height).round
|
||||
sprite.x += @tiles_wide * sprite.bitmap.width if sprite.x - @ox < -sprite.bitmap.width
|
||||
sprite.y -= @tiles_tall * sprite.bitmap.height if sprite.y - @oy > Graphics.height
|
||||
sprite.visible = true
|
||||
if @fading && @type != @target_type
|
||||
if @fade_time >= FADE_OLD_TILES_START && @fade_time < FADE_OLD_TILES_END
|
||||
if @time_shift == 0 # There were old tiles to fade out
|
||||
fraction = (@fade_time - [FADE_OLD_TILES_START - @time_shift, 0].max) / (FADE_OLD_TILES_END - FADE_OLD_TILES_START)
|
||||
sprite.opacity = 255 * (1 - fraction)
|
||||
end
|
||||
elsif @fade_time >= [FADE_NEW_TILES_START - @time_shift, 0].max &&
|
||||
@fade_time < [FADE_NEW_TILES_END - @time_shift, 0].max
|
||||
fraction = (@fade_time - [FADE_NEW_TILES_START - @time_shift, 0].max) / (FADE_NEW_TILES_END - FADE_NEW_TILES_START)
|
||||
sprite.opacity = 255 * fraction
|
||||
else
|
||||
sprite.opacity = 0
|
||||
end
|
||||
else
|
||||
sprite.opacity = (@max > 0) ? 255 : 0
|
||||
end
|
||||
end
|
||||
|
||||
# Set tone of viewport (general screen brightening/darkening)
|
||||
def update_screen_tone
|
||||
weather_type = @type
|
||||
weather_max = @max
|
||||
fraction = 1
|
||||
tone_red = 0
|
||||
tone_green = 0
|
||||
tone_blue = 0
|
||||
tone_gray = 0
|
||||
# Get base tone
|
||||
if @fading
|
||||
if @type == @target_type # Just changing max
|
||||
if @fade_time >= [FADE_NEW_TONE_START - @time_shift, 0].max &&
|
||||
@fade_time < [FADE_NEW_TONE_END - @time_shift, 0].max
|
||||
weather_max = @target_max
|
||||
fract = (@fade_time - [FADE_NEW_TONE_START - @time_shift, 0].max) / (FADE_NEW_TONE_END - FADE_NEW_TONE_START)
|
||||
tone_red = @target_tone.red + (1 - fract) * (@old_tone.red - @target_tone.red)
|
||||
tone_green = @target_tone.green + (1 - fract) * (@old_tone.green - @target_tone.green)
|
||||
tone_blue = @target_tone.blue + (1 - fract) * (@old_tone.blue - @target_tone.blue)
|
||||
tone_gray = @target_tone.gray + (1 - fract) * (@old_tone.gray - @target_tone.gray)
|
||||
else
|
||||
tone_red = @viewport.tone.red
|
||||
tone_green = @viewport.tone.green
|
||||
tone_blue = @viewport.tone.blue
|
||||
tone_gray = @viewport.tone.gray
|
||||
end
|
||||
elsif @time_shift < 2 && @fade_time >= FADE_OLD_TONE_START && @fade_time < FADE_OLD_TONE_END
|
||||
weather_max = @old_max
|
||||
fraction = ((@fade_time - FADE_OLD_TONE_START) / (FADE_OLD_TONE_END - FADE_OLD_TONE_START)).clamp(0, 1)
|
||||
fraction = 1 - fraction
|
||||
tone_red = @old_tone.red
|
||||
tone_green = @old_tone.green
|
||||
tone_blue = @old_tone.blue
|
||||
tone_gray = @old_tone.gray
|
||||
elsif @fade_time >= [FADE_NEW_TONE_START - @time_shift, 0].max
|
||||
weather_type = @target_type
|
||||
weather_max = @target_max
|
||||
fraction = ((@fade_time - [FADE_NEW_TONE_START - @time_shift, 0].max) / (FADE_NEW_TONE_END - FADE_NEW_TONE_START)).clamp(0, 1)
|
||||
tone_red = @target_tone.red
|
||||
tone_green = @target_tone.green
|
||||
tone_blue = @target_tone.blue
|
||||
tone_gray = @target_tone.gray
|
||||
end
|
||||
else
|
||||
base_tone = get_weather_tone(weather_type, weather_max)
|
||||
tone_red = base_tone.red
|
||||
tone_green = base_tone.green
|
||||
tone_blue = base_tone.blue
|
||||
tone_gray = base_tone.gray
|
||||
end
|
||||
# Modify base tone
|
||||
if weather_type == :Sun
|
||||
@sun_magnitude = weather_max if @sun_magnitude != weather_max && @sun_magnitude != -weather_max
|
||||
@sun_magnitude *= -1 if (@sun_magnitude > 0 && @sun_strength > @sun_magnitude) ||
|
||||
(@sun_magnitude < 0 && @sun_strength < 0)
|
||||
@sun_strength += @sun_magnitude.to_f * Graphics.delta_s / 0.4 # 0.4 seconds per half flash
|
||||
tone_red += @sun_strength
|
||||
tone_green += @sun_strength
|
||||
tone_blue += @sun_strength / 2
|
||||
end
|
||||
# Apply screen tone
|
||||
@viewport.tone.set(tone_red * fraction, tone_green * fraction,
|
||||
tone_blue * fraction, tone_gray * fraction)
|
||||
end
|
||||
|
||||
def update_fading
|
||||
return if !@fading
|
||||
old_fade_time = @fade_time
|
||||
@fade_time += Graphics.delta_s
|
||||
# Change tile bitmaps
|
||||
if @type != @target_type
|
||||
tile_change_threshold = [FADE_OLD_TONE_END - @time_shift, 0].max
|
||||
if old_fade_time <= tile_change_threshold && @fade_time > tile_change_threshold
|
||||
@tile_x = @tile_y = 0.0
|
||||
if @weatherTypes[@target_type] && @weatherTypes[@target_type][2].length > 0
|
||||
w = @weatherTypes[@target_type][2][0].width
|
||||
h = @weatherTypes[@target_type][2][0].height
|
||||
@tiles_wide = (Graphics.width.to_f / w).ceil + 1
|
||||
@tiles_tall = (Graphics.height.to_f / h).ceil + 1
|
||||
ensureTiles
|
||||
@tiles.each_with_index { |sprite, i| set_tile_bitmap(sprite, i, @target_type) }
|
||||
else
|
||||
@tiles_wide = @tiles_tall = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
# Reduce the number of old weather particles
|
||||
if @max > 0 && @fade_time >= [FADE_OLD_PARTICLES_START - @time_shift, 0].max
|
||||
fraction = (@fade_time - [FADE_OLD_PARTICLES_START - @time_shift, 0].max) / (FADE_OLD_PARTICLES_END - FADE_OLD_PARTICLES_START)
|
||||
@max = @old_max * (1 - fraction)
|
||||
# NOTE: Sprite visibilities aren't updated here; a sprite is allowed to
|
||||
# die off naturally in def reset_sprite_position.
|
||||
end
|
||||
# Increase the number of new weather particles
|
||||
if @new_max < @target_max && @fade_time >= [FADE_NEW_PARTICLES_START - @time_shift, 0].max
|
||||
fraction = (@fade_time - [FADE_NEW_PARTICLES_START - @time_shift, 0].max) / (FADE_NEW_PARTICLES_END - FADE_NEW_PARTICLES_START)
|
||||
@new_max = (@target_max * fraction).floor
|
||||
@new_sprites.each_with_index { |sprite, i| sprite.visible = (i < @new_max) if sprite }
|
||||
end
|
||||
# End fading
|
||||
if @fade_time >= ((@target_type == :None) ? FADE_OLD_PARTICLES_END : FADE_NEW_TILES_END) - @time_shift
|
||||
if !@sprites.any? { |sprite| sprite.visible }
|
||||
@type = @target_type
|
||||
@max = @target_max
|
||||
@target_type = nil
|
||||
@target_max = nil
|
||||
@old_max = nil
|
||||
@new_max = nil
|
||||
@old_tone = nil
|
||||
@target_tone = nil
|
||||
@fade_time = 0.0
|
||||
@time_shift = 0
|
||||
@sprites.each { |sprite| sprite.dispose if sprite }
|
||||
@sprites = @new_sprites
|
||||
@new_sprites = []
|
||||
@sprite_lifetimes = @new_sprite_lifetimes
|
||||
@new_sprite_lifetimes = []
|
||||
@fading = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
update_fading
|
||||
update_screen_tone
|
||||
# Storm flashes
|
||||
if @type == :Storm && !@fading
|
||||
if @time_until_flash > 0
|
||||
@time_until_flash -= Graphics.delta_s
|
||||
if @time_until_flash <= 0
|
||||
@viewport.flash(Color.new(255, 255, 255, 230), (2 + rand(3)) * 20)
|
||||
end
|
||||
end
|
||||
if @time_until_flash <= 0
|
||||
@time_until_flash = (1 + rand(12)) * 0.5 # 0.5-6 seconds
|
||||
end
|
||||
end
|
||||
@viewport.update
|
||||
# Update weather particles (raindrops, snowflakes, etc.)
|
||||
if @weatherTypes[@type] && @weatherTypes[@type][1].length > 0
|
||||
ensureSprites
|
||||
for i in 0...MAX_SPRITES
|
||||
update_sprite_position(@sprites[i], i, false)
|
||||
end
|
||||
elsif @sprites.length > 0
|
||||
@sprites.each { |sprite| sprite.dispose if sprite }
|
||||
@sprites.clear
|
||||
end
|
||||
# Update new weather particles (while fading in only)
|
||||
if @fading && @weatherTypes[@target_type] && @weatherTypes[@target_type][1].length > 0
|
||||
ensureSprites
|
||||
for i in 0...MAX_SPRITES
|
||||
update_sprite_position(@new_sprites[i], i, true)
|
||||
end
|
||||
elsif @new_sprites.length > 0
|
||||
@new_sprites.each { |sprite| sprite.dispose if sprite }
|
||||
@new_sprites.clear
|
||||
end
|
||||
# Update weather tiles (sandstorm/blizzard tiled overlay)
|
||||
if @tiles_wide > 0 && @tiles_tall > 0
|
||||
ensureTiles
|
||||
recalculate_tile_positions
|
||||
@tiles.each_with_index { |sprite, i| update_tile_position(sprite, i) }
|
||||
elsif @tiles.length > 0
|
||||
@tiles.each { |sprite| sprite.dispose if sprite }
|
||||
@tiles.clear
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,291 +0,0 @@
|
||||
#===============================================================================
|
||||
# Location signpost
|
||||
#===============================================================================
|
||||
class LocationWindow
|
||||
def initialize(name)
|
||||
@window = Window_AdvancedTextPokemon.new(name)
|
||||
@window.resizeToFit(name,Graphics.width)
|
||||
@window.x = 0
|
||||
@window.y = -@window.height
|
||||
@window.viewport = Viewport.new(0,0,Graphics.width,Graphics.height)
|
||||
@window.viewport.z = 99999
|
||||
@currentmap = $game_map.map_id
|
||||
@frames = 0
|
||||
end
|
||||
|
||||
def disposed?
|
||||
@window.disposed?
|
||||
end
|
||||
|
||||
def dispose
|
||||
@window.dispose
|
||||
end
|
||||
|
||||
def update
|
||||
return if @window.disposed?
|
||||
@window.update
|
||||
if $game_temp.message_window_showing || @currentmap!=$game_map.map_id
|
||||
@window.dispose
|
||||
return
|
||||
end
|
||||
if @frames > Graphics.frame_rate * 2
|
||||
@window.y -= 4
|
||||
@window.dispose if @window.y+@window.height<0
|
||||
else
|
||||
@window.y += 4 if @window.y<0
|
||||
@frames += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class NightmareSprite < SpriteWrapper
|
||||
attr_reader :radius
|
||||
|
||||
def initialize(viewport=nil)
|
||||
super(viewport)
|
||||
@darkness = BitmapWrapper.new(Graphics.width,Graphics.height)
|
||||
@radius = radiusMin
|
||||
self.bitmap = @darkness
|
||||
self.z = 99998
|
||||
refresh
|
||||
end
|
||||
|
||||
def dispose
|
||||
@darkness.dispose
|
||||
super
|
||||
end
|
||||
|
||||
def radiusMin; return 64; end # Before using Flash
|
||||
def radiusMax; return 176; end # After using Flash
|
||||
|
||||
def radius=(value)
|
||||
@radius = value
|
||||
refresh
|
||||
end
|
||||
|
||||
def refresh
|
||||
@darkness.fill_rect(0,0,Graphics.width,Graphics.height,Color.new(0,0,0,255))
|
||||
cx = Graphics.width/2
|
||||
cy = Graphics.height/2
|
||||
cradius = @radius
|
||||
numfades = 5
|
||||
for i in 1..numfades
|
||||
for j in cx-cradius..cx+cradius
|
||||
diff2 = (cradius * cradius) - ((j - cx) * (j - cx))
|
||||
diff = Math.sqrt(diff2)
|
||||
@darkness.fill_rect(j,cy-diff,1,diff*2,Color.new(0,0,0,255.0*(numfades-i)/numfades))
|
||||
end
|
||||
cradius = (cradius*0.9).floor
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Visibility circle in dark maps
|
||||
#===============================================================================
|
||||
class DarknessSprite < SpriteWrapper
|
||||
attr_reader :radius
|
||||
|
||||
def initialize(viewport=nil)
|
||||
super(viewport)
|
||||
@darkness = BitmapWrapper.new(Graphics.width,Graphics.height)
|
||||
@radius = radiusMin
|
||||
self.bitmap = @darkness
|
||||
self.z = 99998
|
||||
refresh
|
||||
end
|
||||
|
||||
def dispose
|
||||
@darkness.dispose
|
||||
super
|
||||
end
|
||||
|
||||
def radiusMin; return 64; end # Before using Flash
|
||||
def radiusMax; return 176; end # After using Flash
|
||||
|
||||
def radius=(value)
|
||||
@radius = value
|
||||
refresh
|
||||
end
|
||||
|
||||
def refresh
|
||||
@darkness.fill_rect(0,0,Graphics.width,Graphics.height,Color.new(0,0,0,255))
|
||||
cx = Graphics.width/2
|
||||
cy = Graphics.height/2
|
||||
cradius = @radius
|
||||
numfades = 5
|
||||
for i in 1..numfades
|
||||
for j in cx-cradius..cx+cradius
|
||||
diff2 = (cradius * cradius) - ((j - cx) * (j - cx))
|
||||
diff = Math.sqrt(diff2)
|
||||
@darkness.fill_rect(j,cy-diff,1,diff*2,Color.new(0,0,0,255.0*(numfades-i)/numfades))
|
||||
end
|
||||
cradius = (cradius*0.9).floor
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Light effects
|
||||
#===============================================================================
|
||||
class LightEffect
|
||||
def initialize(event,viewport=nil,map=nil,filename=nil)
|
||||
@light = IconSprite.new(0,0,viewport)
|
||||
if filename!=nil && filename!="" && pbResolveBitmap("Graphics/Pictures/"+filename)
|
||||
@light.setBitmap("Graphics/Pictures/"+filename)
|
||||
else
|
||||
@light.setBitmap("Graphics/Pictures/LE")
|
||||
end
|
||||
@light.z = 1000
|
||||
@event = event
|
||||
@map = (map) ? map : $game_map
|
||||
@disposed = false
|
||||
end
|
||||
|
||||
def opacity=(value)
|
||||
@light.opacity=value
|
||||
update
|
||||
end
|
||||
|
||||
def disposed?
|
||||
return @disposed
|
||||
end
|
||||
|
||||
def dispose
|
||||
@light.dispose
|
||||
@map = nil
|
||||
@event = nil
|
||||
@disposed = true
|
||||
end
|
||||
|
||||
def update
|
||||
@light.update
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class LightEffect_Lamp < LightEffect
|
||||
def initialize(event,viewport=nil,map=nil)
|
||||
lamp = AnimatedBitmap.new("Graphics/Pictures/LE")
|
||||
@light = Sprite.new(viewport)
|
||||
@light.bitmap = Bitmap.new(128,64)
|
||||
src_rect = Rect.new(0, 0, 64, 64)
|
||||
@light.bitmap.blt(0, 0, lamp.bitmap, src_rect)
|
||||
@light.bitmap.blt(20, 0, lamp.bitmap, src_rect)
|
||||
@light.visible = true
|
||||
@light.z = 1000
|
||||
lamp.dispose
|
||||
@map = (map) ? map : $game_map
|
||||
@event = event
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class LightEffect_Basic < LightEffect
|
||||
def update
|
||||
return if !@light || !@event
|
||||
super
|
||||
@light.opacity = 100
|
||||
@light.ox = 32
|
||||
@light.oy = 48
|
||||
if (Object.const_defined?(:ScreenPosHelper) rescue false)
|
||||
@light.x = ScreenPosHelper.pbScreenX(@event)
|
||||
@light.y = ScreenPosHelper.pbScreenY(@event)
|
||||
@light.zoom_x = ScreenPosHelper.pbScreenZoomX(@event)
|
||||
else
|
||||
@light.x = @event.screen_x
|
||||
@light.y = @event.screen_y
|
||||
@light.zoom_x = 1.0
|
||||
end
|
||||
@light.zoom_y = @light.zoom_x
|
||||
@light.tone = $game_screen.tone
|
||||
end
|
||||
end
|
||||
|
||||
class LightEffect_GlowPlant < LightEffect
|
||||
def update
|
||||
return if !darknessEffectOnCurrentMap()
|
||||
mt_moon_direction = getMtMoonDirection()
|
||||
#return if $game_player.direction != mt_moon_direction
|
||||
return if !@light || !@event
|
||||
super
|
||||
@light.opacity = $game_player.direction == mt_moon_direction ? 100 : 0
|
||||
@light.opacity = 150 if isInMtMoon()
|
||||
@light.ox = 32
|
||||
@light.oy = 48
|
||||
if (Object.const_defined?(:ScreenPosHelper) rescue false)
|
||||
@light.x = ScreenPosHelper.pbScreenX(@event)
|
||||
@light.y = ScreenPosHelper.pbScreenY(@event)
|
||||
@light.zoom_x = ScreenPosHelper.pbScreenZoomX(@event)
|
||||
else
|
||||
@light.x = @event.screen_x
|
||||
@light.y = @event.screen_y
|
||||
@light.zoom_x = 1.0
|
||||
end
|
||||
@light.zoom_y = @light.zoom_x
|
||||
@light.tone = $game_screen.tone
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class LightEffect_DayNight < LightEffect
|
||||
def update
|
||||
return if !@light || !@event
|
||||
super
|
||||
shade = PBDayNight.getShade
|
||||
if shade>=144 # If light enough, call it fully day
|
||||
shade = 255
|
||||
elsif shade<=64 # If dark enough, call it fully night
|
||||
shade = 0
|
||||
else
|
||||
shade = 255-(255*(144-shade)/(144-64))
|
||||
end
|
||||
@light.opacity = 255-shade
|
||||
if @light.opacity>0
|
||||
@light.ox = 32
|
||||
@light.oy = 48
|
||||
if (Object.const_defined?(:ScreenPosHelper) rescue false)
|
||||
@light.x = ScreenPosHelper.pbScreenX(@event)
|
||||
@light.y = ScreenPosHelper.pbScreenY(@event)
|
||||
@light.zoom_x = ScreenPosHelper.pbScreenZoomX(@event)
|
||||
@light.zoom_y = ScreenPosHelper.pbScreenZoomY(@event)
|
||||
else
|
||||
@light.x = @event.screen_x
|
||||
@light.y = @event.screen_y
|
||||
@light.zoom_x = 1.0
|
||||
@light.zoom_y = 1.0
|
||||
end
|
||||
@light.tone.set($game_screen.tone.red,
|
||||
$game_screen.tone.green,
|
||||
$game_screen.tone.blue,
|
||||
$game_screen.tone.gray)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
Events.onSpritesetCreate += proc { |_sender,e|
|
||||
spriteset = e[0] # Spriteset being created
|
||||
viewport = e[1] # Viewport used for tilemap and characters
|
||||
map = spriteset.map # Map associated with the spriteset (not necessarily the current map)
|
||||
for i in map.events.keys
|
||||
if map.events[i].name[/^outdoorlight\((\w+)\)$/i]
|
||||
filename = $~[1].to_s
|
||||
spriteset.addUserSprite(LightEffect_DayNight.new(map.events[i],viewport,map,filename))
|
||||
elsif map.events[i].name[/^outdoorlight$/i]
|
||||
spriteset.addUserSprite(LightEffect_DayNight.new(map.events[i],viewport,map))
|
||||
elsif map.events[i].name[/^light\((\w+)\)$/i]
|
||||
filename = $~[1].to_s
|
||||
spriteset.addUserSprite(LightEffect_Basic.new(map.events[i],viewport,map,filename))
|
||||
elsif map.events[i].name[/^light$/i]
|
||||
spriteset.addUserSprite(LightEffect_Basic.new(map.events[i],viewport,map))
|
||||
end
|
||||
end
|
||||
spriteset.addUserSprite(Particle_Engine.new(viewport,map))
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
#===============================================================================
|
||||
# Entering/exiting cave animations
|
||||
#===============================================================================
|
||||
def pbCaveEntranceEx(exiting)
|
||||
# Create bitmap
|
||||
sprite = BitmapSprite.new(Graphics.width,Graphics.height)
|
||||
sprite.z = 100000
|
||||
# Define values used for the animation
|
||||
totalFrames = (Graphics.frame_rate*0.4).floor
|
||||
increment = (255.0/totalFrames).ceil
|
||||
totalBands = 15
|
||||
bandheight = ((Graphics.height/2.0)-10)/totalBands
|
||||
bandwidth = ((Graphics.width/2.0)-12)/totalBands
|
||||
# Create initial array of band colors (black if exiting, white if entering)
|
||||
grays = Array.new(totalBands) { |i| (exiting) ? 0 : 255 }
|
||||
# Animate bands changing color
|
||||
totalFrames.times do |j|
|
||||
x = 0
|
||||
y = 0
|
||||
# Calculate color of each band
|
||||
for k in 0...totalBands
|
||||
next if k>=totalBands*j/totalFrames
|
||||
inc = increment
|
||||
inc *= -1 if exiting
|
||||
grays[k] -= inc
|
||||
grays[k] = 0 if grays[k]<0
|
||||
end
|
||||
# Draw gray rectangles
|
||||
rectwidth = Graphics.width
|
||||
rectheight = Graphics.height
|
||||
for i in 0...totalBands
|
||||
currentGray = grays[i]
|
||||
sprite.bitmap.fill_rect(Rect.new(x,y,rectwidth,rectheight),
|
||||
Color.new(currentGray,currentGray,currentGray))
|
||||
x += bandwidth
|
||||
y += bandheight
|
||||
rectwidth -= bandwidth*2
|
||||
rectheight -= bandheight*2
|
||||
end
|
||||
Graphics.update
|
||||
Input.update
|
||||
end
|
||||
# Set the tone at end of band animation
|
||||
if exiting
|
||||
pbToneChangeAll(Tone.new(255,255,255),0)
|
||||
else
|
||||
pbToneChangeAll(Tone.new(-255,-255,-255),0)
|
||||
end
|
||||
# Animate fade to white (if exiting) or black (if entering)
|
||||
for j in 0...totalFrames
|
||||
if exiting
|
||||
sprite.color = Color.new(255,255,255,j*increment)
|
||||
else
|
||||
sprite.color = Color.new(0,0,0,j*increment)
|
||||
end
|
||||
Graphics.update
|
||||
Input.update
|
||||
end
|
||||
# Set the tone at end of fading animation
|
||||
pbToneChangeAll(Tone.new(0,0,0),8)
|
||||
# Pause briefly
|
||||
(Graphics.frame_rate/10).times do
|
||||
Graphics.update
|
||||
Input.update
|
||||
end
|
||||
sprite.dispose
|
||||
end
|
||||
|
||||
def pbCaveEntrance
|
||||
pbSetEscapePoint
|
||||
pbCaveEntranceEx(false)
|
||||
end
|
||||
|
||||
def pbCaveExit
|
||||
pbEraseEscapePoint
|
||||
pbCaveEntranceEx(true)
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Blacking out animation
|
||||
#===============================================================================
|
||||
def pbStartOver(gameover=false)
|
||||
$game_variables[VAR_CURRENT_GYM_TYPE]=-1
|
||||
$game_switches[SWITCH_LOCK_PLAYER_MOVEMENT]=false
|
||||
$game_switches[SWITCH_TEAMED_WITH_ERIKA_SEWERS]=false
|
||||
|
||||
clear_all_images()
|
||||
$game_player.set_opacity(255)
|
||||
$game_system.menu_disabled=false
|
||||
|
||||
if pbInBugContest?
|
||||
pbBugContestStartOver
|
||||
return
|
||||
end
|
||||
$Trainer.heal_party
|
||||
if isOnPinkanIsland()
|
||||
if $game_switches[SWITCH_PINKAN_SIDE_POLICE]
|
||||
pbMessage(_INTL("\\w[]\\wm\\c[8]\\l[3]Hey, are you okay over there? Let me take you back to the dock."))
|
||||
else
|
||||
pbMessage(_INTL("\\w[]\\wm\\c[8]\\l[3]Hey, are you okay over there? Let me take you back to the beach."))
|
||||
end
|
||||
pinkanIslandWarpToStart()
|
||||
return
|
||||
end
|
||||
if $PokemonGlobal.pokecenterMapId && $PokemonGlobal.pokecenterMapId>=0
|
||||
if gameover
|
||||
pbMessage(_INTL("\\w[]\\wm\\c[8]\\l[3]After the unfortunate defeat, you scurry back to a Pokémon Center."))
|
||||
else
|
||||
pbMessage(_INTL("\\w[]\\wm\\c[8]\\l[3]You scurry back to a Pokémon Center, protecting your exhausted Pokémon from any further harm..."))
|
||||
end
|
||||
pbCancelVehicles
|
||||
pbRemoveDependencies
|
||||
$game_switches[Settings::STARTING_OVER_SWITCH] = true
|
||||
$game_temp.player_new_map_id = $PokemonGlobal.pokecenterMapId
|
||||
$game_temp.player_new_x = $PokemonGlobal.pokecenterX
|
||||
$game_temp.player_new_y = $PokemonGlobal.pokecenterY
|
||||
$game_temp.player_new_direction = $PokemonGlobal.pokecenterDirection
|
||||
$scene.transfer_player if $scene.is_a?(Scene_Map)
|
||||
$game_map.refresh
|
||||
else
|
||||
homedata = GameData::Metadata.get.home
|
||||
if homedata && !pbRgssExists?(sprintf("Data/Map%03d.rxdata",homedata[0]))
|
||||
if $DEBUG
|
||||
pbMessage(_ISPRINTF("Can't find the map 'Map{1:03d}' in the Data folder. The game will resume at the player's position.",homedata[0]))
|
||||
end
|
||||
$Trainer.heal_party
|
||||
return
|
||||
end
|
||||
if gameover
|
||||
pbMessage(_INTL("\\w[]\\wm\\c[8]\\l[3]After the unfortunate defeat, you scurry back home."))
|
||||
else
|
||||
pbMessage(_INTL("\\w[]\\wm\\c[8]\\l[3]You scurry back home, protecting your exhausted Pokémon from any further harm..."))
|
||||
end
|
||||
if homedata
|
||||
pbCancelVehicles
|
||||
pbRemoveDependencies
|
||||
$game_switches[Settings::STARTING_OVER_SWITCH] = true
|
||||
$game_temp.player_new_map_id = homedata[0]
|
||||
$game_temp.player_new_x = homedata[1]
|
||||
$game_temp.player_new_y = homedata[2]
|
||||
$game_temp.player_new_direction = homedata[3]
|
||||
$scene.transfer_player if $scene.is_a?(Scene_Map)
|
||||
$game_map.refresh
|
||||
else
|
||||
$Trainer.heal_party
|
||||
end
|
||||
end
|
||||
pbEraseEscapePoint
|
||||
end
|
||||
@@ -1,961 +0,0 @@
|
||||
#===============================================================================
|
||||
# Constant checks
|
||||
#===============================================================================
|
||||
# Pokérus check
|
||||
Events.onMapUpdate += proc { |_sender, _e|
|
||||
next if !$Trainer
|
||||
last = $PokemonGlobal.pokerusTime
|
||||
now = pbGetTimeNow
|
||||
if !last || last.year != now.year || last.month != now.month || last.day != now.day
|
||||
for i in $Trainer.pokemon_party
|
||||
i.lowerPokerusCount
|
||||
end
|
||||
$PokemonGlobal.pokerusTime = now
|
||||
end
|
||||
}
|
||||
|
||||
# Returns whether the Poké Center should explain Pokérus to the player, if a
|
||||
# healed Pokémon has it.
|
||||
def pbPokerus?
|
||||
return false if $game_switches[Settings::SEEN_POKERUS_SWITCH]
|
||||
for i in $Trainer.party
|
||||
return true if i.pokerusStage == 1
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
class PokemonTemp
|
||||
attr_accessor :batterywarning
|
||||
attr_accessor :cueBGM
|
||||
attr_accessor :cueFrames
|
||||
end
|
||||
|
||||
def pbBatteryLow?
|
||||
pstate = System.power_state
|
||||
# If it's not discharging, it doesn't matter if it's low
|
||||
return false if !pstate[:discharging]
|
||||
# Check for less than 10m, priority over the percentage
|
||||
# Some laptops (Chromebooks, Macbooks) have very long lifetimes
|
||||
return true if pstate[:seconds] && pstate[:seconds] <= 600
|
||||
# Check for <=15%
|
||||
return true if pstate[:percent] && pstate[:percent] <= 15
|
||||
return false
|
||||
end
|
||||
|
||||
def pbOnBattery?
|
||||
pstate = System.power_state
|
||||
return pstate[:discharging]
|
||||
end
|
||||
|
||||
Events.onMapUpdate += proc { |_sender, _e|
|
||||
if !$PokemonTemp.batterywarning && pbBatteryLow?
|
||||
if !$game_temp.in_menu && !$game_temp.in_battle &&
|
||||
!$game_player.move_route_forcing && !$game_temp.message_window_showing &&
|
||||
!pbMapInterpreterRunning?
|
||||
if pbGetTimeNow.sec == 0
|
||||
pbMessage(_INTL("The game has detected that the battery is low. You should save soon to avoid losing your progress."))
|
||||
$PokemonTemp.batterywarning = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if $PokemonTemp.cueFrames
|
||||
$PokemonTemp.cueFrames -= 1
|
||||
if $PokemonTemp.cueFrames <= 0
|
||||
$PokemonTemp.cueFrames = nil
|
||||
if $game_system.getPlayingBGM == nil
|
||||
pbBGMPlay($PokemonTemp.cueBGM)
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
#===============================================================================
|
||||
# Checks per step
|
||||
#===============================================================================
|
||||
# Party Pokémon gain happiness from walking
|
||||
Events.onStepTaken += proc {
|
||||
$PokemonGlobal.happinessSteps = 0 if !$PokemonGlobal.happinessSteps
|
||||
$PokemonGlobal.happinessSteps += 1
|
||||
if $PokemonGlobal.happinessSteps >= 128
|
||||
for pkmn in $Trainer.able_party
|
||||
pkmn.changeHappiness("walking") if rand(2) == 0
|
||||
end
|
||||
$PokemonGlobal.happinessSteps = 0
|
||||
end
|
||||
}
|
||||
|
||||
# Poison party Pokémon
|
||||
Events.onStepTakenTransferPossible += proc { |_sender, e|
|
||||
handled = e[0]
|
||||
next if handled[0]
|
||||
next if $game_switches[SWITCH_GAME_DIFFICULTY_EASY]
|
||||
if $PokemonGlobal.stepcount % 4 == 0 && Settings::POISON_IN_FIELD
|
||||
flashed = false
|
||||
for i in $Trainer.able_party
|
||||
if i.status == :POISON && !i.hasAbility?(:IMMUNITY)
|
||||
if !flashed
|
||||
pbFlash(Color.new(163, 73, 164, 128), 8)
|
||||
flashed = true
|
||||
end
|
||||
i.hp -= 1 if i.hp > 1 || Settings::POISON_FAINT_IN_FIELD
|
||||
if i.hp == 1 && !Settings::POISON_FAINT_IN_FIELD
|
||||
i.status = :NONE
|
||||
pbMessage(_INTL("{1} survived the poisoning.\\nThe poison faded away!\1", i.name))
|
||||
next
|
||||
elsif i.hp == 0
|
||||
i.changeHappiness("faint")
|
||||
i.status = :NONE
|
||||
pbMessage(_INTL("{1} fainted...", i.name))
|
||||
end
|
||||
if $Trainer.able_pokemon_count == 0
|
||||
handled[0] = true
|
||||
pbCheckAllFainted
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
def pbCheckAllFainted
|
||||
if $Trainer.able_pokemon_count == 0
|
||||
pbMessage(_INTL("You have no more Pokémon that can fight!\1"))
|
||||
pbMessage(_INTL("You blacked out!"))
|
||||
pbBGMFade(1.0)
|
||||
pbBGSFade(1.0)
|
||||
pbFadeOutIn { pbStartOver }
|
||||
end
|
||||
end
|
||||
|
||||
# Gather soot from soot grass
|
||||
Events.onStepTakenFieldMovement += proc { |_sender, e|
|
||||
event = e[0] # Get the event affected by field movement
|
||||
thistile = $MapFactory.getRealTilePos(event.map.map_id, event.x, event.y)
|
||||
map = $MapFactory.getMap(thistile[0])
|
||||
for i in [2, 1, 0]
|
||||
tile_id = map.data[thistile[1], thistile[2], i]
|
||||
next if tile_id == nil
|
||||
next if GameData::TerrainTag.try_get(map.terrain_tags[tile_id]).id != :SootGrass
|
||||
if event == $game_player && GameData::Item.exists?(:SOOTSACK)
|
||||
$Trainer.soot += 1 if $PokemonBag.pbHasItem?(:SOOTSACK)
|
||||
end
|
||||
# map.data[thistile[1], thistile[2], i] = 0
|
||||
# $scene.createSingleSpriteset(map.map_id)
|
||||
break
|
||||
end
|
||||
}
|
||||
|
||||
# Show grass rustle animation, and auto-move the player over waterfalls and ice
|
||||
Events.onStepTakenFieldMovement += proc { |_sender, e|
|
||||
event = e[0] # Get the event affected by field movement
|
||||
if $scene.is_a?(Scene_Map)
|
||||
event.each_occupied_tile do |x, y|
|
||||
if $MapFactory.getTerrainTag(event.map.map_id, x, y, true).shows_grass_rustle
|
||||
$scene.spriteset.addUserAnimation(Settings::GRASS_ANIMATION_ID, x, y, true, 1)
|
||||
end
|
||||
end
|
||||
if event == $game_player
|
||||
currentTag = $game_player.pbTerrainTag
|
||||
if isTerrainWaterfall(currentTag)
|
||||
pbDescendWaterfall
|
||||
elsif currentTag.ice && !$PokemonGlobal.sliding
|
||||
pbSlideOnIce
|
||||
elsif currentTag.waterCurrent && !$PokemonGlobal.sliding
|
||||
pbSlideOnWater
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
def isTerrainWaterfall(currentTag)
|
||||
return currentTag.waterfall_crest || currentTag.waterfall
|
||||
end
|
||||
|
||||
def isRepelActive()
|
||||
return false if $game_switches[SWITCH_USED_AN_INCENSE]
|
||||
return ($PokemonGlobal.repel > 0) || $PokemonTemp.pokeradar
|
||||
end
|
||||
|
||||
def pbOnStepTaken(eventTriggered)
|
||||
if $game_player.move_route_forcing || pbMapInterpreterRunning?
|
||||
Events.onStepTakenFieldMovement.trigger(nil, $game_player)
|
||||
return
|
||||
end
|
||||
$PokemonGlobal.stepcount = 0 if !$PokemonGlobal.stepcount
|
||||
$PokemonGlobal.stepcount += 1
|
||||
$PokemonGlobal.stepcount &= 0x7FFFFFFF
|
||||
repel_active = isRepelActive()
|
||||
|
||||
Events.onStepTaken.trigger(nil)
|
||||
# Events.onStepTakenFieldMovement.trigger(nil,$game_player)
|
||||
handled = [nil]
|
||||
Events.onStepTakenTransferPossible.trigger(nil, handled)
|
||||
return if handled[0]
|
||||
pbBattleOnStepTaken(repel_active) if !eventTriggered && !$game_temp.in_menu
|
||||
$PokemonTemp.encounterTriggered = false # This info isn't needed here
|
||||
end
|
||||
|
||||
# Start wild encounters while turning on the spot
|
||||
Events.onChangeDirection += proc {
|
||||
repel_active = isRepelActive()
|
||||
pbBattleOnStepTaken(repel_active) if !$game_temp.in_menu
|
||||
}
|
||||
|
||||
def isFusionForced?
|
||||
return false if $game_switches[SWITCH_RANDOM_WILD_TO_FUSION]
|
||||
return $game_switches[SWITCH_FORCE_FUSE_NEXT_POKEMON] || $game_switches[SWITCH_FORCE_ALL_WILD_FUSIONS]
|
||||
end
|
||||
|
||||
def isFusedEncounter
|
||||
#return false if !$game_switches[SWITCH_FUSED_WILD_POKEMON]
|
||||
return false if $game_switches[SWITCH_RANDOM_WILD_TO_FUSION]
|
||||
return true if isFusionForced?()
|
||||
chance = pbGet(VAR_WILD_FUSION_RATE) == 0 ? 5 : pbGet(VAR_WILD_FUSION_RATE)
|
||||
return (rand(chance) == 0)
|
||||
end
|
||||
|
||||
def getEncounter(encounter_type)
|
||||
encounter = $PokemonEncounters.choose_wild_pokemon(encounter_type)
|
||||
if $game_switches[SWITCH_RANDOM_WILD] #wild poke random activated
|
||||
if $game_switches[SWITCH_WILD_RANDOM_GLOBAL] && encounter != nil
|
||||
encounter[0] = getRandomizedTo(encounter[0])
|
||||
end
|
||||
end
|
||||
return encounter
|
||||
end
|
||||
|
||||
def pbBattleOnStepTaken(repel_active)
|
||||
return if $Trainer.able_pokemon_count == 0
|
||||
return if !$PokemonEncounters.encounter_possible_here?
|
||||
encounter_type = $PokemonEncounters.encounter_type
|
||||
return if !encounter_type
|
||||
return if !$PokemonEncounters.encounter_triggered?(encounter_type, repel_active)
|
||||
$PokemonTemp.encounterType = encounter_type
|
||||
|
||||
encounter = getEncounter(encounter_type)
|
||||
if isFusedEncounter()
|
||||
encounter_fusedWith = getEncounter(encounter_type)
|
||||
if encounter[0] != encounter_fusedWith[0]
|
||||
encounter[0] = getFusionSpeciesSymbol(encounter[0], encounter_fusedWith[0])
|
||||
end
|
||||
end
|
||||
|
||||
if encounter[0].is_a?(Integer)
|
||||
encounter[0] = getSpecies(encounter[0])
|
||||
end
|
||||
|
||||
$game_switches[SWITCH_FORCE_FUSE_NEXT_POKEMON] = false
|
||||
|
||||
encounter = EncounterModifier.trigger(encounter)
|
||||
if $PokemonEncounters.allow_encounter?(encounter, repel_active)
|
||||
if $PokemonEncounters.have_double_wild_battle?
|
||||
encounter2 = $PokemonEncounters.choose_wild_pokemon(encounter_type)
|
||||
encounter2 = EncounterModifier.trigger(encounter2)
|
||||
pbDoubleWildBattle(encounter[0], encounter[1], encounter2[0], encounter2[1])
|
||||
else
|
||||
pbWildBattle(encounter[0], encounter[1])
|
||||
end
|
||||
$PokemonTemp.encounterType = nil
|
||||
$PokemonTemp.encounterTriggered = true
|
||||
end
|
||||
$PokemonTemp.forceSingleBattle = false
|
||||
EncounterModifier.triggerEncounterEnd
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Checks when moving between maps
|
||||
#===============================================================================
|
||||
# Clears the weather of the old map, if the old map has defined weather and the
|
||||
# new map either has the same name as the old map or doesn't have defined
|
||||
# weather.
|
||||
Events.onMapChanging += proc { |_sender, e|
|
||||
new_map_ID = e[0]
|
||||
next if new_map_ID == 0
|
||||
old_map_metadata = GameData::MapMetadata.try_get($game_map.map_id)
|
||||
next if !old_map_metadata || !old_map_metadata.weather
|
||||
map_infos = pbLoadMapInfos
|
||||
if $game_map.name == map_infos[new_map_ID].name
|
||||
new_map_metadata = GameData::MapMetadata.try_get(new_map_ID)
|
||||
next if new_map_metadata && new_map_metadata.weather
|
||||
end
|
||||
$game_screen.weather(:None, 0, 0)
|
||||
}
|
||||
|
||||
# Set up various data related to the new map
|
||||
Events.onMapChange += proc { |_sender, e|
|
||||
old_map_ID = e[0] # previous map ID, is 0 if no map ID
|
||||
new_map_metadata = GameData::MapMetadata.try_get($game_map.map_id)
|
||||
if new_map_metadata && new_map_metadata.teleport_destination
|
||||
$PokemonGlobal.healingSpot = new_map_metadata.teleport_destination
|
||||
end
|
||||
if $PokemonMap
|
||||
blackFluteUsed = $PokemonMap.blackFluteUsed
|
||||
whiteFluteUsed = $PokemonMap.whiteFluteUsed
|
||||
$PokemonMap.clear
|
||||
$PokemonMap.blackFluteUsed = blackFluteUsed
|
||||
$PokemonMap.whiteFluteUsed = whiteFluteUsed
|
||||
end
|
||||
$PokemonEncounters.setup($game_map.map_id) if $PokemonEncounters
|
||||
$PokemonGlobal.visitedMaps[$game_map.map_id] = true
|
||||
next if old_map_ID == 0 || old_map_ID == $game_map.map_id
|
||||
|
||||
if !new_map_metadata || !new_map_metadata.weather
|
||||
$game_screen.weather(:None, 0, 0)
|
||||
next
|
||||
end
|
||||
map_infos = pbLoadMapInfos
|
||||
if $game_map.name == map_infos[old_map_ID].name
|
||||
old_map_metadata = GameData::MapMetadata.try_get(old_map_ID)
|
||||
next if old_map_metadata && old_map_metadata.weather
|
||||
end
|
||||
new_weather = new_map_metadata.weather
|
||||
|
||||
if !new_map_metadata.outdoor_map
|
||||
$game_screen.weather(:None, 0, 0)
|
||||
next
|
||||
end
|
||||
|
||||
echoln new_weather
|
||||
|
||||
$game_screen.weather(new_weather[0], 3, 0) if rand(100) < new_weather[1]
|
||||
}
|
||||
|
||||
# Events.onMapChange += proc { |_sender, e|
|
||||
# next if !Settings::SEVII_ROAMING.include?($game_map.map_id)
|
||||
# new_map_ID = e[0]
|
||||
# new_map_metadata = GameData::MapMetadata.try_get(new_map_ID)
|
||||
# next if new_map_metadata && new_map_metadata.weather
|
||||
# feebas_map = $PokemonGlobal.roamPosition[4]
|
||||
# if $game_map.map_id == feebas_map
|
||||
# $game_screen.weather(:Rain, 4, 0)
|
||||
# else
|
||||
# $game_screen.weather(:None, 0, 0)
|
||||
# end
|
||||
# }
|
||||
|
||||
# [:ENTEI, 50, 350, 1, "Legendary Birds",ROAMING_AREAS,:Sunny],
|
||||
# Events.onMapChange += proc { |_sender, e|
|
||||
# next if $game_screen.weather_type != :None
|
||||
# currently_roaming = $PokemonGlobal.roamPosition.keys
|
||||
# currently_roaming.each do |roamer_id|
|
||||
# roamerOnCurrentMap = $PokemonGlobal.roamPosition[roamer_id] == $game_map.map_id
|
||||
# echoln _INTL("{1} is on map {2}",roamer_id,$game_map.map_id)
|
||||
# echoln $PokemonGlobal.roamPokemon
|
||||
# if roamerOnCurrentMap
|
||||
# next if $PokemonGlobal.roamPokemonCaught[roamer_id]
|
||||
# weather = Settings::ROAMING_SPECIES[roamer_id][6]
|
||||
# $game_screen.weather(weather, 4, 0)
|
||||
# next
|
||||
# end
|
||||
#
|
||||
# end
|
||||
# }
|
||||
|
||||
Events.onMapSceneChange += proc { |_sender, e|
|
||||
scene = e[0]
|
||||
mapChanged = e[1]
|
||||
next if !scene || !scene.spriteset
|
||||
# Update map trail
|
||||
if $game_map
|
||||
$PokemonGlobal.mapTrail = [] if !$PokemonGlobal.mapTrail
|
||||
if $PokemonGlobal.mapTrail[0] != $game_map.map_id
|
||||
$PokemonGlobal.mapTrail.pop if $PokemonGlobal.mapTrail.length >= 4
|
||||
end
|
||||
$PokemonGlobal.mapTrail = [$game_map.map_id] + $PokemonGlobal.mapTrail
|
||||
end
|
||||
# Display darkness circle on dark maps
|
||||
map_metadata = GameData::MapMetadata.try_get($game_map.map_id)
|
||||
if map_metadata && map_metadata.dark_map || (darknessEffectOnCurrentMap())
|
||||
$PokemonTemp.darknessSprite = DarknessSprite.new
|
||||
scene.spriteset.addUserSprite($PokemonTemp.darknessSprite)
|
||||
if $PokemonGlobal.flashUsed
|
||||
$PokemonTemp.darknessSprite.radius = $PokemonTemp.darknessSprite.radiusMax
|
||||
end
|
||||
else
|
||||
$PokemonGlobal.flashUsed = false
|
||||
$PokemonTemp.darknessSprite.dispose if $PokemonTemp.darknessSprite
|
||||
$PokemonTemp.darknessSprite = nil
|
||||
end
|
||||
# Show location signpost
|
||||
if mapChanged && map_metadata && map_metadata.announce_location
|
||||
nosignpost = false
|
||||
if $PokemonGlobal.mapTrail[1]
|
||||
for i in 0...Settings::NO_SIGNPOSTS.length / 2
|
||||
nosignpost = true if Settings::NO_SIGNPOSTS[2 * i] == $PokemonGlobal.mapTrail[1] &&
|
||||
Settings::NO_SIGNPOSTS[2 * i + 1] == $game_map.map_id
|
||||
nosignpost = true if Settings::NO_SIGNPOSTS[2 * i + 1] == $PokemonGlobal.mapTrail[1] &&
|
||||
Settings::NO_SIGNPOSTS[2 * i] == $game_map.map_id
|
||||
break if nosignpost
|
||||
end
|
||||
mapinfos = pbLoadMapInfos
|
||||
oldmapname = mapinfos[$PokemonGlobal.mapTrail[1]].name
|
||||
nosignpost = true if $game_map.name == oldmapname
|
||||
end
|
||||
scene.spriteset.addUserSprite(LocationWindow.new($game_map.name)) if !nosignpost
|
||||
end
|
||||
# Force cycling/walking
|
||||
if map_metadata && map_metadata.always_bicycle
|
||||
pbMountBike
|
||||
elsif !pbCanUseBike?($game_map.map_id)
|
||||
pbDismountBike
|
||||
end
|
||||
}
|
||||
|
||||
#===============================================================================
|
||||
# Event locations, terrain tags
|
||||
#===============================================================================
|
||||
# NOTE: Assumes the event is 1x1 tile in size. Only returns one tile.
|
||||
def pbFacingTile(direction = nil, event = nil)
|
||||
return $MapFactory.getFacingTile(direction, event) if $MapFactory
|
||||
return pbFacingTileRegular(direction, event)
|
||||
end
|
||||
|
||||
# NOTE: Assumes the event is 1x1 tile in size. Only returns one tile.
|
||||
def pbFacingTileRegular(direction = nil, event = nil)
|
||||
event = $game_player if !event
|
||||
return [0, 0, 0] if !event
|
||||
x = event.x
|
||||
y = event.y
|
||||
direction = event.direction if !direction
|
||||
x_offset = [0, -1, 0, 1, -1, 0, 1, -1, 0, 1][direction]
|
||||
y_offset = [0, 1, 1, 1, 0, 0, 0, -1, -1, -1][direction]
|
||||
return [$game_map.map_id, x + x_offset, y + y_offset]
|
||||
end
|
||||
|
||||
def pbEventNextToPlayer?(event,player)
|
||||
return false if !event || !player
|
||||
return false if $PokemonGlobal.sliding
|
||||
if event.x == player.x
|
||||
return event.y == player.y+1 || event.y == player.y-1
|
||||
elsif event.y == player.y
|
||||
return event.x == player.x-1 || event.x == player.x+1
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
# Returns whether event is in line with the player, is
|
||||
# within distance tiles of the player.
|
||||
def pbEventFacesPlayer?(event, player, distance)
|
||||
return pbEventNextToPlayer?(event,player) if distance == 0
|
||||
return false if !event || !player || distance < 0
|
||||
x_min = x_max = y_min = y_max = -1
|
||||
case event.direction
|
||||
when 2 # Down
|
||||
x_min = event.x
|
||||
x_max = event.x + event.width - 1
|
||||
y_min = event.y + 1
|
||||
y_max = event.y + distance
|
||||
when 4 # Left
|
||||
x_min = event.x - distance
|
||||
x_max = event.x - 1
|
||||
y_min = event.y - event.height + 1
|
||||
y_max = event.y
|
||||
when 6 # Right
|
||||
x_min = event.x + event.width
|
||||
x_max = event.x + event.width - 1 + distance
|
||||
y_min = event.y - event.height + 1
|
||||
y_max = event.y
|
||||
when 8 # Up
|
||||
x_min = event.x
|
||||
x_max = event.x + event.width - 1
|
||||
y_min = event.y - event.height + 1 - distance
|
||||
y_max = event.y - event.height
|
||||
else
|
||||
return false
|
||||
end
|
||||
return player.x >= x_min && player.x <= x_max &&
|
||||
player.y >= y_min && player.y <= y_max
|
||||
end
|
||||
|
||||
# Returns whether event is able to walk up to the player.
|
||||
def pbEventCanReachPlayer?(event, player, distance)
|
||||
return false if !pbEventFacesPlayer?(event, player, distance)
|
||||
delta_x = (event.direction == 6) ? 1 : (event.direction == 4) ? -1 : 0
|
||||
delta_y = (event.direction == 2) ? 1 : (event.direction == 8) ? -1 : 0
|
||||
case event.direction
|
||||
when 2 # Down
|
||||
real_distance = player.y - event.y - 1
|
||||
when 4 # Left
|
||||
real_distance = event.x - player.x - 1
|
||||
when 6 # Right
|
||||
real_distance = player.x - event.x - event.width
|
||||
when 8 # Up
|
||||
real_distance = event.y - event.height - player.y
|
||||
end
|
||||
if real_distance > 0
|
||||
real_distance.times do |i|
|
||||
return false if !event.can_move_from_coordinate?(event.x + i * delta_x, event.y + i * delta_y, event.direction)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# Returns whether the two events are standing next to each other and facing each
|
||||
# other.
|
||||
def pbFacingEachOther(event1, event2)
|
||||
return pbEventFacesPlayer?(event1, event2, 1) && pbEventFacesPlayer?(event2, event1, 1)
|
||||
end
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Audio playing
|
||||
#===============================================================================
|
||||
def pbCueBGM(bgm, seconds, volume = nil, pitch = nil)
|
||||
return if !bgm
|
||||
bgm = pbResolveAudioFile(bgm, volume, pitch)
|
||||
playingBGM = $game_system.playing_bgm
|
||||
if !playingBGM || playingBGM.name != bgm.name || playingBGM.pitch != bgm.pitch
|
||||
pbBGMFade(seconds)
|
||||
if !$PokemonTemp.cueFrames
|
||||
$PokemonTemp.cueFrames = (seconds * Graphics.frame_rate) * 3 / 5
|
||||
end
|
||||
$PokemonTemp.cueBGM = bgm
|
||||
elsif playingBGM
|
||||
pbBGMPlay(bgm)
|
||||
end
|
||||
end
|
||||
|
||||
def pbAutoplayOnTransition
|
||||
surfbgm = GameData::Metadata.get.surf_BGM
|
||||
if $PokemonGlobal.surfing && surfbgm
|
||||
pbBGMPlay(surfbgm)
|
||||
else
|
||||
$game_map.autoplayAsCue
|
||||
end
|
||||
end
|
||||
|
||||
def pbAutoplayOnSave
|
||||
surfbgm = GameData::Metadata.get.surf_BGM
|
||||
if $PokemonGlobal.surfing && surfbgm
|
||||
pbBGMPlay(surfbgm)
|
||||
else
|
||||
$game_map.autoplay
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Event movement
|
||||
#===============================================================================
|
||||
module PBMoveRoute
|
||||
Down = 1
|
||||
Left = 2
|
||||
Right = 3
|
||||
Up = 4
|
||||
LowerLeft = 5
|
||||
LowerRight = 6
|
||||
UpperLeft = 7
|
||||
UpperRight = 8
|
||||
Random = 9
|
||||
TowardPlayer = 10
|
||||
AwayFromPlayer = 11
|
||||
Forward = 12
|
||||
Backward = 13
|
||||
Jump = 14 # xoffset, yoffset
|
||||
Wait = 15 # frames
|
||||
TurnDown = 16
|
||||
TurnLeft = 17
|
||||
TurnRight = 18
|
||||
TurnUp = 19
|
||||
TurnRight90 = 20
|
||||
TurnLeft90 = 21
|
||||
Turn180 = 22
|
||||
TurnRightOrLeft90 = 23
|
||||
TurnRandom = 24
|
||||
TurnTowardPlayer = 25
|
||||
TurnAwayFromPlayer = 26
|
||||
SwitchOn = 27 # 1 param
|
||||
SwitchOff = 28 # 1 param
|
||||
ChangeSpeed = 29 # 1 param
|
||||
ChangeFreq = 30 # 1 param
|
||||
WalkAnimeOn = 31
|
||||
WalkAnimeOff = 32
|
||||
StepAnimeOn = 33
|
||||
StepAnimeOff = 34
|
||||
DirectionFixOn = 35
|
||||
DirectionFixOff = 36
|
||||
ThroughOn = 37
|
||||
ThroughOff = 38
|
||||
AlwaysOnTopOn = 39
|
||||
AlwaysOnTopOff = 40
|
||||
Graphic = 41 # Name, hue, direction, pattern
|
||||
Opacity = 42 # 1 param
|
||||
Blending = 43 # 1 param
|
||||
PlaySE = 44 # 1 param
|
||||
Script = 45 # 1 param
|
||||
ScriptAsync = 101 # 1 param
|
||||
end
|
||||
|
||||
def pbMoveRoute(event, commands, waitComplete = false)
|
||||
route = RPG::MoveRoute.new
|
||||
route.repeat = false
|
||||
route.skippable = true
|
||||
route.list.clear
|
||||
route.list.push(RPG::MoveCommand.new(PBMoveRoute::ThroughOn))
|
||||
i = 0
|
||||
while i < commands.length
|
||||
case commands[i]
|
||||
when PBMoveRoute::Wait, PBMoveRoute::SwitchOn, PBMoveRoute::SwitchOff,
|
||||
PBMoveRoute::ChangeSpeed, PBMoveRoute::ChangeFreq, PBMoveRoute::Opacity,
|
||||
PBMoveRoute::Blending, PBMoveRoute::PlaySE, PBMoveRoute::Script
|
||||
route.list.push(RPG::MoveCommand.new(commands[i], [commands[i + 1]]))
|
||||
i += 1
|
||||
when PBMoveRoute::ScriptAsync
|
||||
route.list.push(RPG::MoveCommand.new(PBMoveRoute::Script, [commands[i + 1]]))
|
||||
route.list.push(RPG::MoveCommand.new(PBMoveRoute::Wait, [0]))
|
||||
i += 1
|
||||
when PBMoveRoute::Jump
|
||||
route.list.push(RPG::MoveCommand.new(commands[i], [commands[i + 1], commands[i + 2]]))
|
||||
i += 2
|
||||
when PBMoveRoute::Graphic
|
||||
route.list.push(RPG::MoveCommand.new(commands[i],
|
||||
[commands[i + 1], commands[i + 2], commands[i + 3], commands[i + 4]]))
|
||||
i += 4
|
||||
else
|
||||
route.list.push(RPG::MoveCommand.new(commands[i]))
|
||||
end
|
||||
i += 1
|
||||
end
|
||||
route.list.push(RPG::MoveCommand.new(PBMoveRoute::ThroughOff))
|
||||
route.list.push(RPG::MoveCommand.new(0))
|
||||
if event
|
||||
event.force_move_route(route)
|
||||
end
|
||||
return route
|
||||
end
|
||||
|
||||
def
|
||||
pbWait(numFrames)
|
||||
numFrames.times do
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Player/event movement in the field
|
||||
#===============================================================================
|
||||
def pbLedge(_xOffset, _yOffset)
|
||||
if $game_player.pbFacingTerrainTag.ledge
|
||||
if pbJumpToward(2, true)
|
||||
$scene.spriteset.addUserAnimation(Settings::DUST_ANIMATION_ID, $game_player.x, $game_player.y, true, 1)
|
||||
$game_player.increase_steps
|
||||
$game_player.check_event_trigger_here([1, 2])
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def pbSlideOnIce
|
||||
return if !$game_player.pbTerrainTag.ice
|
||||
$PokemonGlobal.sliding = true
|
||||
direction = $game_player.direction
|
||||
oldwalkanime = $game_player.walk_anime
|
||||
$game_player.straighten
|
||||
$game_player.walk_anime = false
|
||||
loop do
|
||||
break if !$game_player.can_move_in_direction?(direction)
|
||||
break if !$game_player.pbTerrainTag.ice
|
||||
$game_player.move_forward
|
||||
while $game_player.moving?
|
||||
pbUpdateSceneMap
|
||||
Graphics.update
|
||||
Input.update
|
||||
end
|
||||
end
|
||||
$game_player.center($game_player.x, $game_player.y)
|
||||
$game_player.straighten
|
||||
$game_player.walk_anime = oldwalkanime
|
||||
$PokemonGlobal.sliding = false
|
||||
end
|
||||
|
||||
def pbSlideOnWater
|
||||
return if !$game_player.pbTerrainTag.waterCurrent
|
||||
$PokemonGlobal.sliding = true
|
||||
direction = $game_player.direction
|
||||
oldwalkanime = $game_player.walk_anime
|
||||
$game_player.straighten
|
||||
$game_player.walk_anime = false
|
||||
loop do
|
||||
break if !$game_player.can_move_in_direction?(direction)
|
||||
break if !$game_player.pbTerrainTag.waterCurrent
|
||||
if $game_map.passable?($game_player.x, $game_player.y, 8)
|
||||
$game_player.move_up
|
||||
elsif $game_map.passable?($game_player.x, $game_player.y, 4)
|
||||
$game_player.move_left
|
||||
elsif $game_map.passable?($game_player.x, $game_player.y, 6)
|
||||
$game_player.move_right
|
||||
elsif $game_map.passable?($game_player.x, $game_player.y, 2)
|
||||
$game_player.move_down
|
||||
end
|
||||
while $game_player.moving?
|
||||
pbUpdateSceneMap
|
||||
Graphics.update
|
||||
Input.update
|
||||
end
|
||||
end
|
||||
$game_player.center($game_player.x, $game_player.y)
|
||||
$game_player.straighten
|
||||
$game_player.walk_anime = oldwalkanime
|
||||
$PokemonGlobal.sliding = false
|
||||
end
|
||||
|
||||
def pbTurnTowardEvent(event, otherEvent)
|
||||
sx = 0
|
||||
sy = 0
|
||||
if $MapFactory
|
||||
relativePos = $MapFactory.getThisAndOtherEventRelativePos(otherEvent, event)
|
||||
sx = relativePos[0]
|
||||
sy = relativePos[1]
|
||||
else
|
||||
sx = event.x - otherEvent.x
|
||||
sy = event.y - otherEvent.y
|
||||
end
|
||||
sx += (event.width - otherEvent.width) / 2.0
|
||||
sy -= (event.height - otherEvent.height) / 2.0
|
||||
return if sx == 0 && sy == 0
|
||||
if sx.abs > sy.abs
|
||||
(sx > 0) ? event.turn_left : event.turn_right
|
||||
else
|
||||
(sy > 0) ? event.turn_up : event.turn_down
|
||||
end
|
||||
end
|
||||
|
||||
def pbMoveTowardPlayer(event)
|
||||
maxsize = [$game_map.width, $game_map.height].max
|
||||
return if !pbEventCanReachPlayer?(event, $game_player, maxsize)
|
||||
loop do
|
||||
x = event.x
|
||||
y = event.y
|
||||
event.move_toward_player
|
||||
break if event.x == x && event.y == y
|
||||
while event.moving?
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
end
|
||||
end
|
||||
$PokemonMap.addMovedEvent(event.id) if $PokemonMap
|
||||
end
|
||||
|
||||
def pbJumpToward(dist = 1, playSound = false, cancelSurf = false)
|
||||
x = $game_player.x
|
||||
y = $game_player.y
|
||||
case $game_player.direction
|
||||
when 2 then
|
||||
$game_player.jump(0, dist) # down
|
||||
when 4 then
|
||||
$game_player.jump(-dist, 0) # left
|
||||
when 6 then
|
||||
$game_player.jump(dist, 0) # right
|
||||
when 8 then
|
||||
$game_player.jump(0, -dist) # up
|
||||
end
|
||||
if $game_player.x != x || $game_player.y != y
|
||||
pbSEPlay("Player jump") if playSound
|
||||
$PokemonEncounters.reset_step_count if cancelSurf
|
||||
$PokemonTemp.endSurf = true if cancelSurf
|
||||
while $game_player.jumping?
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Bridges, cave escape points, and setting the heal point
|
||||
#===============================================================================
|
||||
def pbBridgeOn(height = 2)
|
||||
$PokemonGlobal.bridge = height
|
||||
end
|
||||
|
||||
def pbBridgeOff
|
||||
$PokemonGlobal.bridge = 0
|
||||
end
|
||||
|
||||
def pbSetEscapePoint
|
||||
$PokemonGlobal.escapePoint = [] if !$PokemonGlobal.escapePoint
|
||||
xco = $game_player.x
|
||||
yco = $game_player.y
|
||||
case $game_player.direction
|
||||
when 2 # Down
|
||||
yco -= 1
|
||||
dir = 8
|
||||
when 4 # Left
|
||||
xco += 1
|
||||
dir = 6
|
||||
when 6 # Right
|
||||
xco -= 1
|
||||
dir = 4
|
||||
when 8 # Up
|
||||
yco += 1
|
||||
dir = 2
|
||||
end
|
||||
$PokemonGlobal.escapePoint = [$game_map.map_id, xco, yco, dir]
|
||||
end
|
||||
|
||||
def pbEraseEscapePoint
|
||||
$PokemonGlobal.escapePoint = []
|
||||
end
|
||||
|
||||
def pbSetPokemonCenter
|
||||
$PokemonGlobal.pokecenterMapId = $game_map.map_id
|
||||
$PokemonGlobal.pokecenterX = $game_player.x
|
||||
$PokemonGlobal.pokecenterY = $game_player.y
|
||||
$PokemonGlobal.pokecenterDirection = $game_player.direction
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Partner trainer
|
||||
#===============================================================================
|
||||
def pbRegisterPartner(tr_type, tr_name, tr_id = 0)
|
||||
tr_type = GameData::TrainerType.get(tr_type).id
|
||||
pbCancelVehicles
|
||||
trainer = pbLoadTrainer(tr_type, tr_name, tr_id)
|
||||
Events.onTrainerPartyLoad.trigger(nil, trainer)
|
||||
for i in trainer.party
|
||||
i.owner = Pokemon::Owner.new_from_trainer(trainer)
|
||||
i.calc_stats
|
||||
end
|
||||
$PokemonGlobal.partner = [tr_type, tr_name, trainer.id, trainer.party]
|
||||
end
|
||||
|
||||
def pbDeregisterPartner
|
||||
$PokemonGlobal.partner = nil
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Picking up an item found on the ground
|
||||
#===============================================================================
|
||||
def pbItemBall(item, quantity = 1, item_name = "", canRandom = true)
|
||||
canRandom = false if !$game_switches[SWITCH_RANDOM_ITEMS_GENERAL]
|
||||
if canRandom && ($game_switches[SWITCH_RANDOM_FOUND_ITEMS] || $game_switches[SWITCH_RANDOM_FOUND_TMS])
|
||||
item = pbGetRandomItem(item) if canRandom #fait rien si pas activé
|
||||
else
|
||||
item = GameData::Item.get(item)
|
||||
end
|
||||
return false if !item || quantity < 1
|
||||
itemname = (quantity > 1) ? item.name_plural : item.name
|
||||
pocket = item.pocket
|
||||
move = item.move
|
||||
if $PokemonBag.pbStoreItem(item, quantity) # If item can be picked up
|
||||
meName = (item.is_key_item?) ? "Key item get" : "Item get"
|
||||
text_color = item.is_key_item? ? "\\c[3]" : "\\c[1]"
|
||||
|
||||
if item == :LEFTOVERS
|
||||
pbMessage(_INTL("\\me[{1}]You found some \\c[1]{2}\\c[0]!\\wtnp[30]", meName, itemname))
|
||||
elsif item.is_machine? # TM or HM
|
||||
pbMessage(_INTL("\\me[{1}]You found \\c[1]{2} {3}\\c[0]!\\wtnp[30]", meName, itemname, GameData::Move.get(move).name))
|
||||
elsif quantity > 1
|
||||
pbMessage(_INTL("\\me[{1}]You found {2} #{text_color}{3}\\c[0]!\\wtnp[30]", meName, quantity, itemname))
|
||||
elsif itemname.starts_with_vowel?
|
||||
pbMessage(_INTL("\\me[{1}]You found an #{text_color}{2}\\c[0]!\\wtnp[30]", meName, itemname))
|
||||
else
|
||||
pbMessage(_INTL("\\me[{1}]You found a #{text_color}{2}\\c[0]!\\wtnp[30]", meName, itemname))
|
||||
end
|
||||
pbMessage(_INTL("You put the {1} away\\nin the <icon=bagPocket{2}>\\c[1]{3} Pocket\\c[0].",
|
||||
itemname, pocket, PokemonBag.pocketNames()[pocket]))
|
||||
|
||||
promptRegisterItem(item)
|
||||
updatePinkanBerryDisplay()
|
||||
return true
|
||||
end
|
||||
# Can't add the item
|
||||
if item == :LEFTOVERS
|
||||
pbMessage(_INTL("You found some \\c[1]{1}\\c[0]!\\wtnp[30]", itemname))
|
||||
elsif item.is_machine? # TM or HM
|
||||
pbMessage(_INTL("You found \\c[1]{1} {2}\\c[0]!\\wtnp[30]", itemname, GameData::Move.get(move).name))
|
||||
elsif quantity > 1
|
||||
pbMessage(_INTL("You found {1} \\c[1]{2}\\c[0]!\\wtnp[30]", quantity, itemname))
|
||||
elsif itemname.starts_with_vowel?
|
||||
pbMessage(_INTL("You found an \\c[1]{1}\\c[0]!\\wtnp[30]", itemname))
|
||||
else
|
||||
pbMessage(_INTL("You found a \\c[1]{1}\\c[0]!\\wtnp[30]", itemname))
|
||||
end
|
||||
pbMessage(_INTL("But your Bag is full..."))
|
||||
return false
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Being given an item
|
||||
#===============================================================================
|
||||
|
||||
def pbReceiveItem(item, quantity = 1, item_name = "", music = nil, canRandom = true)
|
||||
#item_name -> pour donner un autre nom à l'item. Pas encore réimplémenté et surtout là pour éviter que ça plante quand des events essaient de le faire
|
||||
canRandom = false if !$game_switches[SWITCH_RANDOM_ITEMS_GENERAL]
|
||||
original_item = GameData::Item.get(item)
|
||||
if canRandom && ((!original_item.is_TM? && $game_switches[SWITCH_RANDOM_GIVEN_ITEMS]) || (original_item.is_TM? && $game_switches[SWITCH_RANDOM_GIVEN_TMS]))
|
||||
item = pbGetRandomItem(item) if canRandom #fait rien si pas activé
|
||||
else
|
||||
item = GameData::Item.get(item)
|
||||
end
|
||||
# item = GameData::Item.get(item)
|
||||
# if $game_switches[SWITCH_RANDOM_ITEMS] && $game_switches[SWITCH_RANDOM_GIVEN_ITEMS]
|
||||
# item = pbGetRandomItem(item.id)
|
||||
# end
|
||||
#
|
||||
# if $game_switches[SWITCH_RANDOM_ITEMS] && $game_switches[SWITCH_RANDOM_GIVEN_TMS]
|
||||
# item = getRandomGivenTM(item)
|
||||
# end
|
||||
|
||||
return false if !item || quantity < 1
|
||||
itemname = (quantity > 1) ? item.name_plural : item.name
|
||||
pocket = item.pocket
|
||||
move = item.move
|
||||
meName = (item.is_key_item?) ? "Key item get" : "Item get"
|
||||
text_color = item.is_key_item? ? "\\c[3]" : "\\c[1]"
|
||||
if item == :LEFTOVERS
|
||||
pbMessage(_INTL("\\me[{1}]You obtained some \\c[1]{2}\\c[0]!\\wtnp[30]", meName, itemname))
|
||||
elsif item.is_machine? # TM or HM
|
||||
# if $game_switches[SWITCH_RANDOMIZE_GYMS_SEPARATELY] && $game_switches[SWITCH_RANDOMIZED_GYM_TYPES] && $game_variables[VAR_CURRENT_GYM_TYPE] > -1
|
||||
# item = GameData::Item.get(randomizeGymTM(item))
|
||||
# end
|
||||
pbMessage(_INTL("\\me[{1}]You obtained \\c[1]{2} {3}\\c[0]!\\wtnp[30]", meName, itemname, GameData::Move.get(move).name))
|
||||
elsif quantity > 1
|
||||
pbMessage(_INTL("\\me[{1}]You obtained {2} #{text_color}{3}\\c[0]!\\wtnp[30]", meName, quantity, itemname))
|
||||
elsif itemname.starts_with_vowel?
|
||||
pbMessage(_INTL("\\me[{1}]You obtained an #{text_color}{2}\\c[0]!\\wtnp[30]", meName, itemname))
|
||||
else
|
||||
pbMessage(_INTL("\\me[{1}]You obtained a #{text_color}{2}\\c[0]!\\wtnp[30]", meName, itemname))
|
||||
end
|
||||
promptRegisterItem(item)
|
||||
if $PokemonBag.pbStoreItem(item, quantity) # If item can be added
|
||||
pbMessage(_INTL("You put the {1} away\\nin the <icon=bagPocket{2}>\\c[1]{3} Pocket\\c[0].",
|
||||
itemname, pocket, PokemonBag.pocketNames()[pocket]))
|
||||
updatePinkanBerryDisplay()
|
||||
return true
|
||||
end
|
||||
return false # Can't add the item
|
||||
end
|
||||
|
||||
def promptRegisterItem(item)
|
||||
if item.is_key_item? && pbCanRegisterItem?(item)
|
||||
if pbConfirmMessage(_INTL("Would you like to register the \\c[3]{1}\\c[0] in the quick actions menu?",item.name))
|
||||
$PokemonBag.pbRegisterItem(item)
|
||||
pbMessage(_INTL("\\se[{1}]The \\c[3]{2}\\c[0] was registered!", "GUI trainer card open", item.name))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def randomizeGymTM(old_item)
|
||||
gym_index = pbGet(VAR_CURRENT_GYM_TYPE)
|
||||
type_id = pbGet(VAR_GYM_TYPES_ARRAY)[gym_index]
|
||||
idx = 0
|
||||
if $Trainer.badge_count >= 3
|
||||
idx = 1
|
||||
end
|
||||
if $Trainer.badge_count >= 6
|
||||
idx = 2
|
||||
end
|
||||
if $Trainer.badge_count >= 8
|
||||
idx = 3
|
||||
end
|
||||
typed_tms_array = Settings::RANDOMIZED_GYM_TYPE_TM[type_id]
|
||||
return old_item if !typed_tms_array
|
||||
return old_item if idx > typed_tms_array.size
|
||||
return typed_tms_array[idx]
|
||||
end
|
||||
@@ -1,860 +0,0 @@
|
||||
#===============================================================================
|
||||
# Battle preparation
|
||||
#===============================================================================
|
||||
class PokemonGlobalMetadata
|
||||
attr_accessor :nextBattleBGM
|
||||
attr_accessor :nextBattleME
|
||||
attr_accessor :nextBattleCaptureME
|
||||
attr_accessor :nextBattleBack
|
||||
end
|
||||
|
||||
|
||||
|
||||
class PokemonTemp
|
||||
attr_accessor :encounterTriggered
|
||||
attr_accessor :encounterType
|
||||
attr_accessor :evolutionLevels
|
||||
|
||||
def battleRules
|
||||
@battleRules = {} if !@battleRules
|
||||
return @battleRules
|
||||
end
|
||||
|
||||
def clearBattleRules
|
||||
self.battleRules.clear
|
||||
end
|
||||
|
||||
def recordBattleRule(rule,var=nil)
|
||||
rules = self.battleRules
|
||||
case rule.to_s.downcase
|
||||
when "single", "1v1", "1v2", "2v1", "1v3", "3v1",
|
||||
"double", "2v2", "2v3", "3v2", "triple", "3v3"
|
||||
rules["size"] = rule.to_s.downcase
|
||||
when "birdboss" then rules["birdboss"] = true
|
||||
when "canlose" then rules["canLose"] = true
|
||||
when "cannotlose" then rules["canLose"] = false
|
||||
when "canrun" then rules["canRun"] = true
|
||||
when "cannotrun" then rules["canRun"] = false
|
||||
when "roamerflees" then rules["roamerFlees"] = true
|
||||
when "noexp" then rules["expGain"] = false
|
||||
when "nomoney" then rules["moneyGain"] = false
|
||||
when "switchstyle" then rules["switchStyle"] = true
|
||||
when "setstyle" then rules["switchStyle"] = false
|
||||
when "anims" then rules["battleAnims"] = true
|
||||
when "noanims" then rules["battleAnims"] = false
|
||||
when "terrain"
|
||||
terrain_data = GameData::BattleTerrain.try_get(var)
|
||||
rules["defaultTerrain"] = (terrain_data) ? terrain_data.id : nil
|
||||
when "weather"
|
||||
weather_data = GameData::BattleWeather.try_get(var)
|
||||
rules["defaultWeather"] = (weather_data) ? weather_data.id : nil
|
||||
when "environment", "environ"
|
||||
environment_data = GameData::Environment.try_get(var)
|
||||
rules["environment"] = (environment_data) ? environment_data.id : nil
|
||||
when "backdrop", "battleback" then rules["backdrop"] = var
|
||||
when "base" then rules["base"] = var
|
||||
when "outcome", "outcomevar" then rules["outcomeVar"] = var
|
||||
when "nopartner" then rules["noPartner"] = true
|
||||
else
|
||||
raise _INTL("Battle rule \"{1}\" does not exist.", rule)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def setBattleRule(*args)
|
||||
r = nil
|
||||
for arg in args
|
||||
if r
|
||||
$PokemonTemp.recordBattleRule(r,arg)
|
||||
r = nil
|
||||
else
|
||||
case arg.downcase
|
||||
when "terrain", "weather", "environment", "environ", "backdrop",
|
||||
"battleback", "base", "outcome", "outcomevar"
|
||||
r = arg
|
||||
next
|
||||
end
|
||||
$PokemonTemp.recordBattleRule(arg)
|
||||
end
|
||||
end
|
||||
raise _INTL("Argument {1} expected a variable after it but didn't have one.",r) if r
|
||||
end
|
||||
|
||||
def pbNewBattleScene
|
||||
return PokeBattle_Scene.new
|
||||
end
|
||||
|
||||
def getBattleBackgroundFromMetadata(metadata)
|
||||
#if battle bg specified, return that
|
||||
battle_bg = metadata.battle_background
|
||||
return battle_bg if battle_bg
|
||||
|
||||
#if no battle bg specified, dedude from environment
|
||||
battle_env = metadata.battle_environment
|
||||
case battle_env
|
||||
when :Cave
|
||||
return "Cave1"
|
||||
when :Grass
|
||||
return "Field"
|
||||
when :Rock
|
||||
return "Mountain"
|
||||
when :Underwater
|
||||
return "Underwater"
|
||||
when :StillWater
|
||||
return "Water"
|
||||
when :MovingWater
|
||||
return "Water"
|
||||
when :Forest
|
||||
return "Forest"
|
||||
end
|
||||
|
||||
#if is city
|
||||
if metadata.teleport_destination && metadata.announce_location && metadata.outdoor_map
|
||||
return "City"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Sets up various battle parameters and applies special rules.
|
||||
def pbPrepareBattle(battle)
|
||||
battleRules = $PokemonTemp.battleRules
|
||||
# The size of the battle, i.e. how many Pokémon on each side (default: "single")
|
||||
battle.setBattleMode(battleRules["size"]) if !battleRules["size"].nil? || $game_switches[SWITCH_NEW_GAME_PLUS]
|
||||
battle.setBattleMode("1v3") if !battleRules["birdboss"].nil?
|
||||
|
||||
# Whether the game won't black out even if the player loses (default: false)
|
||||
battle.canLose = battleRules["canLose"] if !battleRules["canLose"].nil?
|
||||
# Whether the player can choose to run from the battle (default: true)
|
||||
battle.canRun = battleRules["canRun"] if !battleRules["canRun"].nil?
|
||||
# Whether wild Pokémon always try to run from battle (default: nil)
|
||||
battle.rules["alwaysflee"] = battleRules["roamerFlees"]
|
||||
# Whether Pokémon gain Exp/EVs from defeating/catching a Pokémon (default: true)
|
||||
battle.expGain = battleRules["expGain"] if !battleRules["expGain"].nil?
|
||||
# Whether the player gains/loses money at the end of the battle (default: true)
|
||||
battle.moneyGain = battleRules["moneyGain"] if !battleRules["moneyGain"].nil?
|
||||
# Whether the player is able to switch when an opponent's Pokémon faints
|
||||
battle.switchStyle = ($PokemonSystem.battlestyle==0)
|
||||
battle.switchStyle = battleRules["switchStyle"] if !battleRules["switchStyle"].nil?
|
||||
# Whether battle animations are shown
|
||||
battle.showAnims = ($PokemonSystem.battlescene==0)
|
||||
battle.showAnims = battleRules["battleAnims"] if !battleRules["battleAnims"].nil?
|
||||
# Terrain
|
||||
battle.defaultTerrain = battleRules["defaultTerrain"] if !battleRules["defaultTerrain"].nil?
|
||||
# Weather
|
||||
if battleRules["defaultWeather"].nil?
|
||||
case GameData::Weather.get($game_screen.weather_type).category
|
||||
when :Rain
|
||||
battle.defaultWeather = :Rain
|
||||
when :Hail
|
||||
battle.defaultWeather = :Hail
|
||||
when :Sandstorm
|
||||
battle.defaultWeather = :Sandstorm
|
||||
when :Sun
|
||||
battle.defaultWeather = :Sun
|
||||
when :StrongWinds
|
||||
battle.defaultWeather = :StrongWinds
|
||||
end
|
||||
else
|
||||
battle.defaultWeather = battleRules["defaultWeather"]
|
||||
end
|
||||
# Environment
|
||||
if battleRules["environment"].nil?
|
||||
battle.environment = pbGetEnvironment
|
||||
else
|
||||
battle.environment = battleRules["environment"]
|
||||
end
|
||||
# Backdrop graphic filename
|
||||
if !battleRules["backdrop"].nil?
|
||||
backdrop = battleRules["backdrop"]
|
||||
elsif $PokemonGlobal.nextBattleBack
|
||||
backdrop = $PokemonGlobal.nextBattleBack
|
||||
elsif $PokemonGlobal.surfing
|
||||
backdrop = "water" # This applies wherever you are, including in caves
|
||||
elsif GameData::MapMetadata.exists?($game_map.map_id)
|
||||
back = getBattleBackgroundFromMetadata(GameData::MapMetadata.get($game_map.map_id))
|
||||
backdrop = back if back && back != ""
|
||||
end
|
||||
|
||||
if !backdrop
|
||||
isOutdoor = GameData::MapMetadata.get($game_map.map_id).outdoor_map rescue false
|
||||
backdrop = "indoorA" if !isOutdoor
|
||||
backdrop = "Field" if isOutdoor
|
||||
end
|
||||
|
||||
battle.backdrop = backdrop
|
||||
# Choose a name for bases depending on environment
|
||||
if battleRules["base"].nil?
|
||||
environment_data = GameData::Environment.try_get(battle.environment)
|
||||
base = environment_data.battle_base if environment_data
|
||||
else
|
||||
base = battleRules["base"]
|
||||
end
|
||||
battle.backdropBase = base if base
|
||||
# Time of day
|
||||
if GameData::MapMetadata.exists?($game_map.map_id) &&
|
||||
GameData::MapMetadata.get($game_map.map_id).battle_environment == :Cave
|
||||
battle.time = 2 # This makes Dusk Balls work properly in caves
|
||||
elsif Settings::TIME_SHADING
|
||||
timeNow = pbGetTimeNow
|
||||
if PBDayNight.isNight?(timeNow); battle.time = 2
|
||||
elsif PBDayNight.isEvening?(timeNow); battle.time = 1
|
||||
else; battle.time = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Used to determine the environment in battle, and also the form of Burmy/
|
||||
# Wormadam.
|
||||
def pbGetEnvironment
|
||||
ret = :None
|
||||
map_metadata = GameData::MapMetadata.try_get($game_map.map_id)
|
||||
ret = map_metadata.battle_environment if map_metadata && map_metadata.battle_environment
|
||||
if $PokemonTemp.encounterType &&
|
||||
GameData::EncounterType.get($PokemonTemp.encounterType).type == :fishing
|
||||
terrainTag = $game_player.pbFacingTerrainTag
|
||||
else
|
||||
terrainTag = $game_player.terrain_tag
|
||||
end
|
||||
tile_environment = terrainTag.battle_environment
|
||||
if ret == :Forest && [:Grass, :TallGrass].include?(tile_environment)
|
||||
ret = :ForestGrass
|
||||
else
|
||||
ret = tile_environment if tile_environment
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
Events.onStartBattle += proc { |_sender|
|
||||
# Record current levels of Pokémon in party, to see if they gain a level
|
||||
# during battle and may need to evolve afterwards
|
||||
$PokemonTemp.evolutionLevels = []
|
||||
for i in 0...$Trainer.party.length
|
||||
$PokemonTemp.evolutionLevels[i] = $Trainer.party[i].level
|
||||
end
|
||||
}
|
||||
|
||||
def pbCanDoubleBattle?
|
||||
return $PokemonGlobal.partner || $Trainer.able_pokemon_count >= 2
|
||||
end
|
||||
|
||||
def pbCanTripleBattle?
|
||||
return true if $Trainer.able_pokemon_count >= 3
|
||||
return $PokemonGlobal.partner && $Trainer.able_pokemon_count >= 2
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Start a wild battle
|
||||
#===============================================================================
|
||||
def pbWildBattleCore(*args)
|
||||
outcomeVar = $PokemonTemp.battleRules["outcomeVar"] || 1
|
||||
canLose = $PokemonTemp.battleRules["canLose"] || false
|
||||
# Skip battle if the player has no able Pokémon, or if holding Ctrl in Debug mode
|
||||
if $Trainer.able_pokemon_count == 0 || ($DEBUG && Input.press?(Input::CTRL))
|
||||
pbMessage(_INTL("SKIPPING BATTLE...")) if $Trainer.pokemon_count > 0
|
||||
pbSet(outcomeVar,1) # Treat it as a win
|
||||
$PokemonTemp.clearBattleRules
|
||||
$PokemonGlobal.nextBattleBGM = nil
|
||||
$PokemonGlobal.nextBattleME = nil
|
||||
$PokemonGlobal.nextBattleCaptureME = nil
|
||||
$PokemonGlobal.nextBattleBack = nil
|
||||
$PokemonTemp.forced_alt_sprites=nil
|
||||
pbMEStop
|
||||
return 1 # Treat it as a win
|
||||
end
|
||||
# Record information about party Pokémon to be used at the end of battle (e.g.
|
||||
# comparing levels for an evolution check)
|
||||
Events.onStartBattle.trigger(nil)
|
||||
# Generate wild Pokémon based on the species and level
|
||||
foeParty = []
|
||||
sp = nil
|
||||
for arg in args
|
||||
if arg.is_a?(Pokemon)
|
||||
foeParty.push(arg)
|
||||
elsif arg.is_a?(Array)
|
||||
species = GameData::Species.get(arg[0]).id
|
||||
pkmn = pbGenerateWildPokemon(species,arg[1])
|
||||
foeParty.push(pkmn)
|
||||
elsif sp
|
||||
species = GameData::Species.get(sp).id
|
||||
pkmn = pbGenerateWildPokemon(species,arg)
|
||||
foeParty.push(pkmn)
|
||||
sp = nil
|
||||
else
|
||||
sp = arg
|
||||
end
|
||||
end
|
||||
raise _INTL("Expected a level after being given {1}, but one wasn't found.",sp) if sp
|
||||
# Calculate who the trainers and their party are
|
||||
playerTrainers = [$Trainer]
|
||||
playerParty = $Trainer.party
|
||||
playerPartyStarts = [0]
|
||||
room_for_partner = (foeParty.length > 1)
|
||||
if !room_for_partner && $PokemonTemp.battleRules["size"] &&
|
||||
!["single", "1v1", "1v2", "1v3"].include?($PokemonTemp.battleRules["size"])
|
||||
room_for_partner = true
|
||||
end
|
||||
if $PokemonGlobal.partner && !$PokemonTemp.battleRules["noPartner"] && room_for_partner
|
||||
ally = NPCTrainer.new($PokemonGlobal.partner[1],$PokemonGlobal.partner[0])
|
||||
ally.id = $PokemonGlobal.partner[2]
|
||||
ally.party = $PokemonGlobal.partner[3]
|
||||
playerTrainers.push(ally)
|
||||
playerParty = []
|
||||
$Trainer.party.each { |pkmn| playerParty.push(pkmn) }
|
||||
playerPartyStarts.push(playerParty.length)
|
||||
ally.party.each { |pkmn| playerParty.push(pkmn) }
|
||||
setBattleRule("double") if !$PokemonTemp.battleRules["size"]
|
||||
end
|
||||
# Create the battle scene (the visual side of it)
|
||||
scene = pbNewBattleScene
|
||||
# Create the battle class (the mechanics side of it)
|
||||
battle = PokeBattle_Battle.new(scene,playerParty,foeParty,playerTrainers,nil)
|
||||
battle.party1starts = playerPartyStarts
|
||||
# Set various other properties in the battle class
|
||||
pbPrepareBattle(battle)
|
||||
$PokemonTemp.clearBattleRules
|
||||
# Perform the battle itself
|
||||
decision = 0
|
||||
pbBattleAnimation(pbGetWildBattleBGM(foeParty),(foeParty.length==1) ? 0 : 2,foeParty) {
|
||||
pbSceneStandby {
|
||||
decision = battle.pbStartBattle
|
||||
}
|
||||
pbAfterBattle(decision,canLose)
|
||||
}
|
||||
Input.update
|
||||
# Save the result of the battle in a Game Variable (1 by default)
|
||||
# 0 - Undecided or aborted
|
||||
# 1 - Player won
|
||||
# 2 - Player lost
|
||||
# 3 - Player or wild Pokémon ran from battle, or player forfeited the match
|
||||
# 4 - Wild Pokémon was caught
|
||||
# 5 - Draw
|
||||
pbSet(outcomeVar,decision)
|
||||
return decision
|
||||
end
|
||||
|
||||
def pbWildDoubleBattleSpecific(pokemon1,pokemon2, outcomeVar=1, canRun=true, canLose=false)
|
||||
# Set some battle rules
|
||||
setBattleRule("outcomeVar",outcomeVar) if outcomeVar!=1
|
||||
setBattleRule("cannotRun") if !canRun
|
||||
setBattleRule("canLose") if canLose
|
||||
setBattleRule("double")
|
||||
# Perform the battle
|
||||
decision = pbWildBattleCore(pokemon1, pokemon2)
|
||||
return (decision!=2 && decision!=5)
|
||||
end
|
||||
|
||||
def pbWildBattleSpecific(pokemon, outcomeVar=1, canRun=true, canLose=false)
|
||||
# Set some battle rules
|
||||
setBattleRule("outcomeVar",outcomeVar) if outcomeVar!=1
|
||||
setBattleRule("cannotRun") if !canRun
|
||||
setBattleRule("canLose") if canLose
|
||||
# Perform the battle
|
||||
decision = pbWildBattleCore(pokemon)
|
||||
# Used by the Poké Radar to update/break the chain
|
||||
#Events.onWildBattleEnd.trigger(nil,species,level,decision)
|
||||
# Return false if the player lost or drew the battle, and true if any other result
|
||||
return (decision!=2 && decision!=5)
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Standard methods that start a wild battle of various sizes
|
||||
#===============================================================================
|
||||
# Used when walking in tall grass, hence the additional code.
|
||||
def pbWildBattle(species, level, outcomeVar=1, canRun=true, canLose=false)
|
||||
if !species
|
||||
displayRandomizerErrorMessage()
|
||||
return
|
||||
end
|
||||
species = GameData::Species.get(species).id
|
||||
dexnum = getDexNumberForSpecies(species)
|
||||
if $game_switches[SWITCH_RANDOM_STATIC_ENCOUNTERS] && dexnum <= NB_POKEMON
|
||||
newSpecies = $PokemonGlobal.psuedoBSTHash[dexnum]
|
||||
if !newSpecies
|
||||
displayRandomizerErrorMessage()
|
||||
else
|
||||
species = getSpecies(newSpecies)
|
||||
end
|
||||
end
|
||||
|
||||
# Potentially call a different pbWildBattle-type method instead (for roaming
|
||||
# Pokémon, Safari battles, Bug Contest battles)
|
||||
handled = [nil]
|
||||
Events.onWildBattleOverride.trigger(nil,species,level,handled)
|
||||
return handled[0] if handled[0]!=nil
|
||||
# Set some battle rules
|
||||
setBattleRule("outcomeVar",outcomeVar) if outcomeVar!=1
|
||||
setBattleRule("cannotRun") if !canRun
|
||||
setBattleRule("canLose") if canLose
|
||||
# Perform the battle
|
||||
decision = pbWildBattleCore(species, level)
|
||||
# Used by the Poké Radar to update/break the chain
|
||||
Events.onWildBattleEnd.trigger(nil,species,level,decision)
|
||||
# Return false if the player lost or drew the battle, and true if any other result
|
||||
return (decision!=2 && decision!=5)
|
||||
end
|
||||
|
||||
def pbDoubleWildBattle(species1, level1, species2, level2,
|
||||
outcomeVar=1, canRun=true, canLose=false)
|
||||
# Set some battle rules
|
||||
setBattleRule("outcomeVar",outcomeVar) if outcomeVar!=1
|
||||
setBattleRule("cannotRun") if !canRun
|
||||
setBattleRule("canLose") if canLose
|
||||
setBattleRule("double")
|
||||
# Perform the battle
|
||||
decision = pbWildBattleCore(species1, level1, species2, level2)
|
||||
# Return false if the player lost or drew the battle, and true if any other result
|
||||
return (decision!=2 && decision!=5)
|
||||
end
|
||||
|
||||
def pbTripleWildBattle(species1, level1, species2, level2, species3, level3,
|
||||
outcomeVar=1, canRun=true, canLose=false)
|
||||
# Set some battle rules
|
||||
setBattleRule("outcomeVar",outcomeVar) if outcomeVar!=1
|
||||
setBattleRule("cannotRun") if !canRun
|
||||
setBattleRule("canLose") if canLose
|
||||
setBattleRule("triple")
|
||||
# Perform the battle
|
||||
decision = pbWildBattleCore(species1, level1, species2, level2, species3, level3)
|
||||
# Return false if the player lost or drew the battle, and true if any other result
|
||||
return (decision!=2 && decision!=5)
|
||||
end
|
||||
|
||||
def pb1v3WildBattle(species1, level1, species2, level2, species3, level3,
|
||||
outcomeVar=1, canRun=true, canLose=false)
|
||||
# Set some battle rules
|
||||
setBattleRule("outcomeVar",outcomeVar) if outcomeVar!=1
|
||||
setBattleRule("cannotRun") if !canRun
|
||||
setBattleRule("canLose") if canLose
|
||||
setBattleRule("1v3")
|
||||
# Perform the battle
|
||||
decision = pbWildBattleCore(species1, level1, species2, level2, species3, level3)
|
||||
# Return false if the player lost or drew the battle, and true if any other result
|
||||
return (decision!=2 && decision!=5)
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Start a trainer battle
|
||||
#===============================================================================
|
||||
def pbTrainerBattleCore(*args)
|
||||
outcomeVar = $PokemonTemp.battleRules["outcomeVar"] || 1
|
||||
canLose = $PokemonTemp.battleRules["canLose"] || false
|
||||
# Skip battle if the player has no able Pokémon, or if holding Ctrl in Debug mode
|
||||
if $Trainer.able_pokemon_count == 0 || ($DEBUG && Input.press?(Input::CTRL))
|
||||
pbMessage(_INTL("SKIPPING BATTLE...")) if $DEBUG
|
||||
pbMessage(_INTL("AFTER WINNING...")) if $DEBUG && $Trainer.able_pokemon_count > 0
|
||||
pbSet(outcomeVar,($Trainer.able_pokemon_count == 0) ? 0 : 1) # Treat it as undecided/a win
|
||||
$PokemonTemp.clearBattleRules
|
||||
$PokemonGlobal.nextBattleBGM = nil
|
||||
$PokemonGlobal.nextBattleME = nil
|
||||
$PokemonGlobal.nextBattleCaptureME = nil
|
||||
$PokemonGlobal.nextBattleBack = nil
|
||||
$PokemonTemp.forced_alt_sprites=nil
|
||||
pbMEStop
|
||||
return ($Trainer.able_pokemon_count == 0) ? 0 : 1 # Treat it as undecided/a win
|
||||
end
|
||||
# Record information about party Pokémon to be used at the end of battle (e.g.
|
||||
# comparing levels for an evolution check)
|
||||
Events.onStartBattle.trigger(nil)
|
||||
# Generate trainers and their parties based on the arguments given
|
||||
foeTrainers = []
|
||||
foeItems = []
|
||||
foeEndSpeeches = []
|
||||
foeParty = []
|
||||
foePartyStarts = []
|
||||
for arg in args
|
||||
if arg.is_a?(NPCTrainer)
|
||||
foeTrainers.push(arg)
|
||||
foePartyStarts.push(foeParty.length)
|
||||
arg.party.each { |pkmn| foeParty.push(pkmn) }
|
||||
foeEndSpeeches.push(arg.lose_text)
|
||||
foeItems.push(arg.items)
|
||||
elsif arg.is_a?(Array) # [trainer type, trainer name, ID, speech (optional)]
|
||||
trainer = pbLoadTrainer(arg[0],arg[1],arg[2])
|
||||
if !trainer && $game_switches[SWITCH_MODERN_MODE] #retry without modern mode
|
||||
$game_switches[SWITCH_MODERN_MODE]=false
|
||||
trainer = pbLoadTrainer(arg[0],arg[1],arg[2])
|
||||
$game_switches[SWITCH_MODERN_MODE]=true
|
||||
end
|
||||
|
||||
pbMissingTrainer(arg[0],arg[1],arg[2]) if !trainer
|
||||
return 0 if !trainer
|
||||
|
||||
#infinite fusion edit
|
||||
name_override = arg[4]
|
||||
type_override = arg[5]
|
||||
if type_override != nil
|
||||
trainer.trainer_type = type_override
|
||||
end
|
||||
if name_override != nil
|
||||
trainer.name = name_override
|
||||
end
|
||||
#####
|
||||
Events.onTrainerPartyLoad.trigger(nil,trainer)
|
||||
foeTrainers.push(trainer)
|
||||
foePartyStarts.push(foeParty.length)
|
||||
trainer.party.each { |pkmn| foeParty.push(pkmn) }
|
||||
foeEndSpeeches.push(arg[3] || trainer.lose_text)
|
||||
foeItems.push(trainer.items)
|
||||
else
|
||||
raise _INTL("Expected NPCTrainer or array of trainer data, got {1}.", arg)
|
||||
end
|
||||
end
|
||||
# Calculate who the player trainer(s) and their party are
|
||||
playerTrainers = [$Trainer]
|
||||
playerParty = $Trainer.party
|
||||
playerPartyStarts = [0]
|
||||
room_for_partner = (foeParty.length > 1)
|
||||
if !room_for_partner && $PokemonTemp.battleRules["size"] &&
|
||||
!["single", "1v1", "1v2", "1v3"].include?($PokemonTemp.battleRules["size"])
|
||||
room_for_partner = true
|
||||
end
|
||||
if $PokemonGlobal.partner && !$PokemonTemp.battleRules["noPartner"] && room_for_partner
|
||||
ally = NPCTrainer.new($PokemonGlobal.partner[1], $PokemonGlobal.partner[0])
|
||||
ally.id = $PokemonGlobal.partner[2]
|
||||
ally.party = $PokemonGlobal.partner[3]
|
||||
playerTrainers.push(ally)
|
||||
playerParty = []
|
||||
$Trainer.party.each { |pkmn| playerParty.push(pkmn) }
|
||||
playerPartyStarts.push(playerParty.length)
|
||||
ally.party.each { |pkmn| playerParty.push(pkmn) }
|
||||
setBattleRule("double") if !$PokemonTemp.battleRules["size"]
|
||||
end
|
||||
# Create the battle scene (the visual side of it)
|
||||
scene = pbNewBattleScene
|
||||
# Create the battle class (the mechanics side of it)
|
||||
battle = PokeBattle_Battle.new(scene,playerParty,foeParty,playerTrainers,foeTrainers)
|
||||
battle.party1starts = playerPartyStarts
|
||||
battle.party2starts = foePartyStarts
|
||||
battle.items = foeItems
|
||||
battle.endSpeeches = foeEndSpeeches
|
||||
# Set various other properties in the battle class
|
||||
pbPrepareBattle(battle)
|
||||
$PokemonTemp.clearBattleRules
|
||||
# End the trainer intro music
|
||||
Audio.me_stop
|
||||
# Perform the battle itself
|
||||
decision = 0
|
||||
pbBattleAnimation(pbGetTrainerBattleBGM(foeTrainers),(battle.singleBattle?) ? 1 : 3,foeTrainers) {
|
||||
pbSceneStandby {
|
||||
decision = battle.pbStartBattle
|
||||
}
|
||||
pbAfterBattle(decision,canLose)
|
||||
}
|
||||
Input.update
|
||||
# Save the result of the battle in a Game Variable (1 by default)
|
||||
# 0 - Undecided or aborted
|
||||
# 1 - Player won
|
||||
# 2 - Player lost
|
||||
# 3 - Player or wild Pokémon ran from battle, or player forfeited the match
|
||||
# 5 - Draw
|
||||
pbSet(outcomeVar,decision)
|
||||
return decision
|
||||
end
|
||||
|
||||
def convert_pokemon_to_pokemon_hash(pokemon)
|
||||
pokemon_hash = Hash.new
|
||||
pokemon_hash[:species] = pokemon.species
|
||||
pokemon_hash[:level] = pokemon.level
|
||||
return pokemon_hash
|
||||
end
|
||||
|
||||
|
||||
|
||||
#party: array of pokemon team
|
||||
# [[:SPECIES,level], ... ]
|
||||
#
|
||||
def customTrainerBattle(trainerName, trainerType, party_array, default_level=50, endSpeech="", sprite_override=nil,custom_appearance=nil)
|
||||
|
||||
|
||||
# trainerID= "customTrainer"
|
||||
#
|
||||
# trainer_info_hash = {}
|
||||
# trainer_info_hash[:id] = trainerID
|
||||
# trainer_info_hash[:id_number] = 0
|
||||
# trainer_info_hash[:name] = trainerName
|
||||
# trainer_info_hash[:version] = 0
|
||||
# trainer_info_hash[:items] = []
|
||||
# trainer_info_hash[:lose_text] = endSpeech
|
||||
# trainer_info_hash[:pokemon] = party
|
||||
|
||||
#trainer = GameData::Trainer.new(trainer_info_hash)
|
||||
trainer = NPCTrainer.new(trainerName,trainerType,sprite_override,custom_appearance)
|
||||
trainer.lose_text=endSpeech
|
||||
party = []
|
||||
party_array.each { |pokemon|
|
||||
if pokemon.is_a?(Pokemon)
|
||||
party << pokemon
|
||||
elsif pokemon.is_a?(Symbol)
|
||||
party << Pokemon.new(pokemon,default_level,trainer)
|
||||
end
|
||||
}
|
||||
trainer.party=party
|
||||
Events.onTrainerPartyLoad.trigger(nil,trainer)
|
||||
|
||||
|
||||
|
||||
decision = pbTrainerBattleCore(trainer)
|
||||
# Return true if the player won the battle, and false if any other result
|
||||
return (decision==1)
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Standard methods that start a trainer battle of various sizes
|
||||
#===============================================================================
|
||||
# Used by most trainer events, which can be positioned in such a way that
|
||||
# multiple trainer events spot the player at once. The extra code in this method
|
||||
# deals with that case and can cause a double trainer battle instead.
|
||||
def pbTrainerBattle(trainerID, trainerName, endSpeech=nil,
|
||||
doubleBattle=false, trainerPartyID=0, canLose=false, outcomeVar=1,
|
||||
name_override=nil,trainer_type_overide=nil)
|
||||
|
||||
|
||||
#level override applies to every pokemon
|
||||
|
||||
# If there is another NPC trainer who spotted the player at the same time, and
|
||||
# it is possible to have a double battle (the player has 2+ able Pokémon or
|
||||
# has a partner trainer), then record this first NPC trainer into
|
||||
# $PokemonTemp.waitingTrainer and end this method. That second NPC event will
|
||||
# then trigger and cause the battle to happen against this first trainer and
|
||||
# themselves.
|
||||
if !$PokemonTemp.waitingTrainer && pbMapInterpreterRunning? &&
|
||||
($Trainer.able_pokemon_count > 1 ||
|
||||
($Trainer.able_pokemon_count > 0 && $PokemonGlobal.partner))
|
||||
thisEvent = pbMapInterpreter.get_character(0)
|
||||
# Find all other triggered trainer events
|
||||
triggeredEvents = $game_player.pbTriggeredTrainerEvents([2],false)
|
||||
otherEvent = []
|
||||
for i in triggeredEvents
|
||||
next if i.id==thisEvent.id
|
||||
next if $game_self_switches[[$game_map.map_id,i.id,"A"]]
|
||||
otherEvent.push(i)
|
||||
end
|
||||
# Load the trainer's data, and call an event w0hich might modify it
|
||||
trainer = pbLoadTrainer(trainerID,trainerName,trainerPartyID)
|
||||
if !trainer && $game_switches[SWITCH_MODERN_MODE] #retry without modern mode
|
||||
$game_switches[SWITCH_MODERN_MODE]=false
|
||||
trainer = pbLoadTrainer(trainerID,trainerName,trainerPartyID)
|
||||
$game_switches[SWITCH_MODERN_MODE]=true
|
||||
end
|
||||
pbMissingTrainer(trainerID,trainerName,trainerPartyID) if !trainer
|
||||
return false if !trainer
|
||||
Events.onTrainerPartyLoad.trigger(nil,trainer)
|
||||
# If there is exactly 1 other triggered trainer event, and this trainer has
|
||||
# 6 or fewer Pokémon, record this trainer for a double battle caused by the
|
||||
# other triggered trainer event
|
||||
if otherEvent.length == 1 && trainer.party.length <= Settings::MAX_PARTY_SIZE
|
||||
trainer.lose_text = endSpeech if endSpeech && !endSpeech.empty?
|
||||
$PokemonTemp.waitingTrainer = [trainer, thisEvent.id]
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Set some battle rules
|
||||
setBattleRule("outcomeVar",outcomeVar) if outcomeVar!=1
|
||||
setBattleRule("canLose") if canLose
|
||||
setBattleRule("double") if doubleBattle || $PokemonTemp.waitingTrainer
|
||||
# Perform the battle
|
||||
if $PokemonTemp.waitingTrainer
|
||||
decision = pbTrainerBattleCore($PokemonTemp.waitingTrainer[0],
|
||||
[trainerID,trainerName,trainerPartyID,endSpeech]
|
||||
)
|
||||
else
|
||||
decision = pbTrainerBattleCore([trainerID,trainerName,trainerPartyID,endSpeech,name_override,trainer_type_overide])
|
||||
end
|
||||
# Finish off the recorded waiting trainer, because they have now been battled
|
||||
if decision==1 && $PokemonTemp.waitingTrainer # Win
|
||||
pbMapInterpreter.pbSetSelfSwitch($PokemonTemp.waitingTrainer[1], "A", true)
|
||||
end
|
||||
$PokemonTemp.waitingTrainer = nil
|
||||
# Return true if the player won the battle, and false if any other result
|
||||
return (decision==1)
|
||||
end
|
||||
|
||||
def pbDoubleTrainerBattle(trainerID1, trainerName1, trainerPartyID1, endSpeech1,
|
||||
trainerID2, trainerName2, trainerPartyID2=0, endSpeech2=nil,
|
||||
canLose=false, outcomeVar=1)
|
||||
# Set some battle rules
|
||||
setBattleRule("outcomeVar",outcomeVar) if outcomeVar!=1
|
||||
setBattleRule("canLose") if canLose
|
||||
setBattleRule("double")
|
||||
# Perform the battle
|
||||
decision = pbTrainerBattleCore(
|
||||
[trainerID1,trainerName1,trainerPartyID1,endSpeech1],
|
||||
[trainerID2,trainerName2,trainerPartyID2,endSpeech2]
|
||||
)
|
||||
# Return true if the player won the battle, and false if any other result
|
||||
return (decision==1)
|
||||
end
|
||||
|
||||
def pbTripleTrainerBattle(trainerID1, trainerName1, trainerPartyID1, endSpeech1,
|
||||
trainerID2, trainerName2, trainerPartyID2, endSpeech2,
|
||||
trainerID3, trainerName3, trainerPartyID3=0, endSpeech3=nil,
|
||||
canLose=false, outcomeVar=1)
|
||||
# Set some battle rules
|
||||
setBattleRule("outcomeVar",outcomeVar) if outcomeVar!=1
|
||||
setBattleRule("canLose") if canLose
|
||||
setBattleRule("triple")
|
||||
# Perform the battle
|
||||
decision = pbTrainerBattleCore(
|
||||
[trainerID1,trainerName1,trainerPartyID1,endSpeech1],
|
||||
[trainerID2,trainerName2,trainerPartyID2,endSpeech2],
|
||||
[trainerID3,trainerName3,trainerPartyID3,endSpeech3]
|
||||
)
|
||||
# Return true if the player won the battle, and false if any other result
|
||||
return (decision==1)
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# After battles
|
||||
#===============================================================================
|
||||
def pbAfterBattle(decision,canLose)
|
||||
$Trainer.party.each do |pkmn|
|
||||
pkmn.statusCount = 0 if pkmn.status == :POISON # Bad poison becomes regular
|
||||
pkmn.makeUnmega
|
||||
pkmn.makeUnprimal
|
||||
end
|
||||
if $PokemonGlobal.partner
|
||||
$Trainer.heal_party
|
||||
$PokemonGlobal.partner[3].each do |pkmn|
|
||||
pkmn.heal
|
||||
pkmn.makeUnmega
|
||||
pkmn.makeUnprimal
|
||||
end
|
||||
end
|
||||
if decision==2 || decision==5 # if loss or draw
|
||||
if canLose
|
||||
$Trainer.party.each { |pkmn| pkmn.heal }
|
||||
(Graphics.frame_rate/4).times { Graphics.update }
|
||||
end
|
||||
end
|
||||
Events.onEndBattle.trigger(nil,decision,canLose)
|
||||
$game_player.straighten
|
||||
end
|
||||
|
||||
Events.onEndBattle += proc { |_sender,e|
|
||||
decision = e[0]
|
||||
canLose = e[1]
|
||||
if Settings::CHECK_EVOLUTION_AFTER_ALL_BATTLES || (decision!=2 && decision!=5) # not a loss or a draw
|
||||
if $PokemonTemp.evolutionLevels
|
||||
pbEvolutionCheck($PokemonTemp.evolutionLevels)
|
||||
$PokemonTemp.evolutionLevels = nil
|
||||
end
|
||||
end
|
||||
case decision
|
||||
when 1, 4 # Win, capture
|
||||
$Trainer.pokemon_party.each do |pkmn|
|
||||
pbPickup(pkmn)
|
||||
pbHoneyGather(pkmn)
|
||||
end
|
||||
pickUpTypeItemSetBonus()
|
||||
qmarkMaskCheck()
|
||||
when 2, 5 # Lose, draw
|
||||
if !canLose
|
||||
$game_system.bgm_unpause
|
||||
$game_system.bgs_unpause
|
||||
pbStartOver
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
def pbEvolutionCheck(currentLevels,scene=nil)
|
||||
for i in 0...currentLevels.length
|
||||
pkmn = $Trainer.party[i]
|
||||
next if !pkmn || (pkmn.hp==0 && !Settings::CHECK_EVOLUTION_FOR_FAINTED_POKEMON)
|
||||
next if currentLevels[i] && pkmn.level==currentLevels[i]
|
||||
newSpecies = pkmn.check_evolution_on_level_up()
|
||||
next if !newSpecies
|
||||
evo = PokemonEvolutionScene.new
|
||||
evo.pbStartScreen(pkmn,newSpecies)
|
||||
evo.pbEvolution
|
||||
evo.pbEndScreen
|
||||
end
|
||||
end
|
||||
|
||||
def pbDynamicItemList(*args)
|
||||
ret = []
|
||||
for i in 0...args.length
|
||||
ret.push(args[i]) if GameData::Item.exists?(args[i])
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
# Try to gain an item after a battle if a Pokemon has the ability Pickup.
|
||||
def pbPickup(pkmn)
|
||||
return if pkmn.egg? || !pkmn.hasAbility?(:PICKUP)
|
||||
return if pkmn.hasItem?
|
||||
return unless rand(100)<10 # 10% chance
|
||||
# Common items to find (9 items from this list are added to the pool)
|
||||
pickupList = pbDynamicItemList(
|
||||
:POTION,
|
||||
:ANTIDOTE,
|
||||
:SUPERPOTION,
|
||||
:GREATBALL,
|
||||
:REPEL,
|
||||
:ESCAPEROPE,
|
||||
:FULLHEAL,
|
||||
:HYPERPOTION,
|
||||
:ULTRABALL,
|
||||
:REVIVE,
|
||||
:RARECANDY,
|
||||
:SUNSTONE,
|
||||
:MOONSTONE,
|
||||
:HEARTSCALE,
|
||||
:FULLRESTORE,
|
||||
:MAXREVIVE,
|
||||
:PPUP,
|
||||
:MAXELIXIR
|
||||
)
|
||||
# Rare items to find (2 items from this list are added to the pool)
|
||||
pickupListRare = pbDynamicItemList(
|
||||
:HYPERPOTION,
|
||||
:NUGGET,
|
||||
:KINGSROCK,
|
||||
:FULLRESTORE,
|
||||
:ETHER,
|
||||
:IRONBALL,
|
||||
:DESTINYKNOT,
|
||||
:ELIXIR,
|
||||
:DESTINYKNOT,
|
||||
:LEFTOVERS,
|
||||
:DESTINYKNOT
|
||||
)
|
||||
return if pickupList.length<18
|
||||
return if pickupListRare.length<11
|
||||
# Generate a pool of items depending on the Pokémon's level
|
||||
items = []
|
||||
pkmnLevel = [100,pkmn.level].min
|
||||
itemStartIndex = (pkmnLevel-1)/10
|
||||
itemStartIndex = 0 if itemStartIndex<0
|
||||
for i in 0...9
|
||||
items.push(pickupList[itemStartIndex+i])
|
||||
end
|
||||
for i in 0...2
|
||||
items.push(pickupListRare[itemStartIndex+i])
|
||||
end
|
||||
# Probabilities of choosing each item in turn from the pool
|
||||
chances = [30,10,10,10,10,10,10,4,4,1,1] # Needs to be 11 numbers
|
||||
chanceSum = 0
|
||||
chances.each { |c| chanceSum += c }
|
||||
# Randomly choose an item from the pool to give to the Pokémon
|
||||
rnd = rand(chanceSum)
|
||||
cumul = 0
|
||||
chances.each_with_index do |c,i|
|
||||
cumul += c
|
||||
next if rnd>=cumul
|
||||
pkmn.item = items[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# Try to gain a Honey item after a battle if a Pokemon has the ability Honey Gather.
|
||||
def pbHoneyGather(pkmn)
|
||||
return if !GameData::Item.exists?(:HONEY)
|
||||
return if pkmn.egg? || !pkmn.hasAbility?(:HONEYGATHER) || pkmn.hasItem?
|
||||
chance = 5 + ((pkmn.level - 1) / 10) * 5
|
||||
return unless rand(100) < chance
|
||||
pkmn.item = :HONEY
|
||||
end
|
||||
@@ -1,352 +0,0 @@
|
||||
#===============================================================================
|
||||
# Battle intro animation
|
||||
#===============================================================================
|
||||
def pbSceneStandby
|
||||
$scene.disposeSpritesets if $scene.is_a?(Scene_Map)
|
||||
if RPG::Cache.need_clearing
|
||||
RPG::Cache.clear
|
||||
end
|
||||
Graphics.frame_reset
|
||||
yield
|
||||
$scene.createSpritesets if $scene.is_a?(Scene_Map)
|
||||
end
|
||||
|
||||
def pbBattleAnimation(bgm=nil,battletype=0,foe=nil)
|
||||
$game_temp.in_battle = true
|
||||
viewport = Viewport.new(0,0,Graphics.width,Graphics.height)
|
||||
viewport.z = 99999
|
||||
# Set up audio
|
||||
playingBGS = nil
|
||||
playingBGM = nil
|
||||
if $game_system && $game_system.is_a?(Game_System)
|
||||
playingBGS = $game_system.getPlayingBGS
|
||||
playingBGM = $game_system.getPlayingBGM
|
||||
$game_system.bgm_pause
|
||||
$game_system.bgs_pause
|
||||
end
|
||||
pbMEFade(0.25)
|
||||
#pbWait(Graphics.frame_rate/4)
|
||||
pbMEStop
|
||||
# Play battle music
|
||||
bgm = pbGetWildBattleBGM([]) if !bgm
|
||||
pbBGMPlay(bgm)
|
||||
# Take screenshot of game, for use in some animations
|
||||
$game_temp.background_bitmap.dispose if $game_temp.background_bitmap
|
||||
$game_temp.background_bitmap = Graphics.snap_to_bitmap
|
||||
# Check for custom battle intro animations
|
||||
handled = pbBattleAnimationOverride(viewport,battletype,foe)
|
||||
# Default battle intro animation
|
||||
if !handled
|
||||
# Determine which animation is played
|
||||
location = 0 # 0=outside, 1=inside, 2=cave, 3=water
|
||||
if $PokemonGlobal.surfing || $PokemonGlobal.diving
|
||||
location = 3
|
||||
elsif $PokemonTemp.encounterType &&
|
||||
GameData::EncounterType.get($PokemonTemp.encounterType).type == :fishing
|
||||
location = 3
|
||||
elsif $PokemonEncounters.has_cave_encounters?
|
||||
location = 2
|
||||
elsif !GameData::MapMetadata.exists?($game_map.map_id) ||
|
||||
!GameData::MapMetadata.get($game_map.map_id).outdoor_map
|
||||
location = 1
|
||||
end
|
||||
anim = ""
|
||||
if PBDayNight.isDay?
|
||||
case battletype
|
||||
when 0, 2 # Wild, double wild
|
||||
anim = ["SnakeSquares","DiagonalBubbleTL","DiagonalBubbleBR","RisingSplash"][location]
|
||||
when 1 # Trainer
|
||||
anim = ["TwoBallPass","ThreeBallDown","BallDown","WavyThreeBallUp"][location]
|
||||
when 3 # Double trainer
|
||||
anim = "FourBallBurst"
|
||||
end
|
||||
else
|
||||
case battletype
|
||||
when 0, 2 # Wild, double wild
|
||||
anim = ["SnakeSquares","DiagonalBubbleBR","DiagonalBubbleBR","RisingSplash"][location]
|
||||
when 1 # Trainer
|
||||
anim = ["SpinBallSplit","BallDown","BallDown","WavySpinBall"][location]
|
||||
when 3 # Double trainer
|
||||
anim = "FourBallBurst"
|
||||
end
|
||||
end
|
||||
# Initial screen flashing
|
||||
if location==2 || PBDayNight.isNight?
|
||||
viewport.color = Color.new(0,0,0) # Fade to black a few times
|
||||
else
|
||||
viewport.color = Color.new(255,255,255) # Fade to white a few times
|
||||
end
|
||||
halfFlashTime = Graphics.frame_rate*2/10 # 0.2 seconds, 8 frames
|
||||
alphaDiff = (255.0/halfFlashTime).ceil
|
||||
2.times do
|
||||
viewport.color.alpha = 0
|
||||
for i in 0...halfFlashTime*2
|
||||
if i<halfFlashTime; viewport.color.alpha += alphaDiff
|
||||
else; viewport.color.alpha -= alphaDiff
|
||||
end
|
||||
Graphics.update
|
||||
pbUpdateSceneMap
|
||||
end
|
||||
end
|
||||
# Play main animation
|
||||
Graphics.freeze
|
||||
Graphics.transition(Graphics.frame_rate*1.25,sprintf("Graphics/Transitions/%s",anim))
|
||||
viewport.color = Color.new(0,0,0,255) # Ensure screen is black
|
||||
# Slight pause after animation before starting up the battle scene
|
||||
(Graphics.frame_rate/10).times do
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
end
|
||||
end
|
||||
pbPushFade
|
||||
# Yield to the battle scene
|
||||
yield if block_given?
|
||||
# After the battle
|
||||
pbPopFade
|
||||
if $game_system && $game_system.is_a?(Game_System)
|
||||
$game_system.bgm_resume(playingBGM)
|
||||
$game_system.bgs_resume(playingBGS)
|
||||
end
|
||||
$PokemonGlobal.nextBattleBGM = nil
|
||||
$PokemonGlobal.nextBattleME = nil
|
||||
$PokemonGlobal.nextBattleCaptureME = nil
|
||||
$PokemonGlobal.nextBattleBack = nil
|
||||
$PokemonTemp.forced_alt_sprites=nil
|
||||
$PokemonEncounters.reset_step_count
|
||||
# Fade back to the overworld
|
||||
viewport.color = Color.new(0,0,0,255)
|
||||
numFrames = Graphics.frame_rate*4/10 # 0.4 seconds, 16 frames
|
||||
alphaDiff = (255.0/numFrames).ceil
|
||||
numFrames.times do
|
||||
viewport.color.alpha -= alphaDiff
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
end
|
||||
viewport.dispose
|
||||
$game_temp.in_battle = false
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Vs. battle intro animation
|
||||
#===============================================================================
|
||||
def pbBattleAnimationOverride(viewport,battletype=0,foe=nil)
|
||||
##### VS. animation, by Luka S.J. #####
|
||||
##### Tweaked by Maruno #####
|
||||
if (battletype==1 || battletype==3) && foe.length==1 # Against single trainer
|
||||
tr_type = foe[0].trainer_type
|
||||
tr_number= GameData::TrainerType.get(tr_type).id_number
|
||||
|
||||
|
||||
if tr_type
|
||||
tbargraphic = sprintf("vsBar_%s", tr_type.to_s) rescue nil
|
||||
#tgraphic = sprintf("vsTrainer_%s", tr_type.to_s) rescue nil
|
||||
tgraphic = sprintf("trainer%03d", tr_number) rescue nil
|
||||
|
||||
echoln tgraphic
|
||||
if pbResolveBitmap("Graphics/Transitions/" + tbargraphic) && pbResolveBitmap("Graphics/Characters/" + tgraphic)
|
||||
player_tr_type = $Trainer.trainer_type
|
||||
outfit = $Trainer.outfit
|
||||
# Set up
|
||||
viewplayer = Viewport.new(0,Graphics.height/3,Graphics.width/2,128)
|
||||
viewplayer.z = viewport.z
|
||||
viewopp = Viewport.new(Graphics.width/2,Graphics.height/3,Graphics.width/2,128)
|
||||
viewopp.z = viewport.z
|
||||
viewvs = Viewport.new(0,0,Graphics.width,Graphics.height)
|
||||
viewvs.z = viewport.z
|
||||
fade = Sprite.new(viewport)
|
||||
fade.bitmap = RPG::Cache.transition("vsFlash")
|
||||
fade.tone = Tone.new(-255,-255,-255)
|
||||
fade.opacity = 100
|
||||
overlay = Sprite.new(viewport)
|
||||
overlay.bitmap = Bitmap.new(Graphics.width,Graphics.height)
|
||||
pbSetSystemFont(overlay.bitmap)
|
||||
#pbargraphic = sprintf("vsBar_%s_%d", player_tr_type.to_s, outfit) rescue nil
|
||||
pbargraphic = sprintf("vsBar_%s", player_tr_type.to_s) rescue nil
|
||||
if !pbResolveBitmap("Graphics/Transitions/" + pbargraphic)
|
||||
pbargraphic = sprintf("vsBar_%s", player_tr_type.to_s) rescue nil
|
||||
end
|
||||
# xoffset = ((Graphics.width/2)/10)*10
|
||||
xoffset = ((Graphics.width/2)/10)*10
|
||||
#xoffset = 0#((Graphics.width/2)/10)*10
|
||||
|
||||
bar1 = Sprite.new(viewplayer)
|
||||
bar1.bitmap = RPG::Cache.transition(pbargraphic)
|
||||
bar1.x = -xoffset
|
||||
bar2 = Sprite.new(viewopp)
|
||||
bar2.bitmap = RPG::Cache.transition(tbargraphic)
|
||||
bar2.x = xoffset
|
||||
vs = Sprite.new(viewvs)
|
||||
vs.bitmap = RPG::Cache.transition("vs")
|
||||
vs.ox = vs.bitmap.width/2
|
||||
vs.oy = vs.bitmap.height/2
|
||||
vs.x = Graphics.width/2
|
||||
vs.y = Graphics.height/1.5
|
||||
vs.visible = false
|
||||
flash = Sprite.new(viewvs)
|
||||
flash.bitmap = RPG::Cache.transition("vsFlash")
|
||||
flash.opacity = 0
|
||||
# Animate bars sliding in from either side
|
||||
slideInTime = (Graphics.frame_rate*0.25).floor
|
||||
|
||||
for i in 0...slideInTime
|
||||
bar1.x = xoffset*(i+1-slideInTime)/slideInTime
|
||||
bar2.x = xoffset*(slideInTime-i-1)/slideInTime
|
||||
pbWait(1)
|
||||
end
|
||||
bar1.dispose
|
||||
bar2.dispose
|
||||
# Make whole screen flash white
|
||||
pbSEPlay("Vs flash")
|
||||
pbSEPlay("Vs sword")
|
||||
flash.opacity = 255
|
||||
# Replace bar sprites with AnimatedPlanes, set up trainer sprites
|
||||
bar1 = AnimatedPlane.new(viewplayer)
|
||||
bar1.bitmap = RPG::Cache.transition(pbargraphic)
|
||||
bar2 = AnimatedPlane.new(viewopp)
|
||||
bar2.bitmap = RPG::Cache.transition(tbargraphic)
|
||||
#pgraphic = sprintf("vsTrainer_%s_%d", player_tr_type.to_s, outfit) rescue nil
|
||||
#pgraphic = sprintf("vsTrainer_%s", player_tr_type.to_s) rescue nil
|
||||
|
||||
# pgraphic = generate_front_trainer_sprite_bitmap()#sprintf("trainer%03d", tr_number) rescue nil
|
||||
#
|
||||
# #if !pbResolveBitmap("Graphics/Transitions/" + pgraphic)
|
||||
# if !pbResolveBitmap("Graphics/Characters/" + pgraphic)
|
||||
# pgraphic = sprintf("vsTrainer_%s", player_tr_type.to_s) rescue nil
|
||||
# end
|
||||
player = Sprite.new(viewplayer)
|
||||
#player.bitmap = RPG::Cache.transition(tgraphic)
|
||||
#
|
||||
playerSpriteWrapper = generate_front_trainer_sprite_bitmap()
|
||||
player.bitmap = playerSpriteWrapper.bitmap # RPG::Cache.load_bitmap("Graphics/Characters/", pgraphic) #RPG::Cache.transition(pgraphic)
|
||||
player.x = -250
|
||||
player.y = -30
|
||||
player.zoom_x = 2
|
||||
player.zoom_y = 2
|
||||
|
||||
player.mirror =true
|
||||
player_center_offset=-20
|
||||
|
||||
trainer = Sprite.new(viewopp)
|
||||
#trainer.bitmap = RPG::Cache.transition(tgraphic)
|
||||
trainer.bitmap =RPG::Cache.load_bitmap("Graphics/Characters/", tgraphic) #RPG::Cache.transition(pgraphic)
|
||||
trainer.x = xoffset+150
|
||||
trainer.tone = Tone.new(-255,-255,-255)
|
||||
trainer.zoom_x = 2
|
||||
trainer.zoom_y = 2
|
||||
trainer.y = -10
|
||||
trainer_center_offset=0
|
||||
|
||||
# Dim the flash and make the trainer sprites appear, while animating bars
|
||||
animTime = (Graphics.frame_rate*1.2).floor
|
||||
for i in 0...animTime
|
||||
flash.opacity -= 52*20/Graphics.frame_rate if flash.opacity>0
|
||||
bar1.ox -= 32*20/Graphics.frame_rate
|
||||
bar2.ox += 32*20/Graphics.frame_rate
|
||||
if i>=animTime/2 && i<slideInTime+animTime/2
|
||||
player.x = (xoffset*(i+1-slideInTime-animTime/2)/slideInTime)+player_center_offset
|
||||
trainer.x = xoffset*(slideInTime-i-1+animTime/2)/slideInTime+trainer_center_offset
|
||||
end
|
||||
pbWait(1)
|
||||
end
|
||||
|
||||
|
||||
echoln "VS flash"
|
||||
#player.x = -150
|
||||
#player.y=-75
|
||||
|
||||
#trainer.x = -20
|
||||
# trainer.y = -75
|
||||
|
||||
# Make whole screen flash white again
|
||||
flash.opacity = 255
|
||||
pbSEPlay("Vs sword")
|
||||
# Make the Vs logo and trainer names appear, and reset trainer's tone
|
||||
vs.visible = true
|
||||
trainer.tone = Tone.new(0,0,0)
|
||||
trainername = foe[0].name
|
||||
textpos = [
|
||||
[$Trainer.name,Graphics.width/4,(Graphics.height/1.5)+4,2,
|
||||
Color.new(248,248,248),Color.new(12*6,12*6,12*6)],
|
||||
[trainername,(Graphics.width/4)+(Graphics.width/2),(Graphics.height/1.5)+4,2,
|
||||
Color.new(248,248,248),Color.new(12*6,12*6,12*6)]
|
||||
]
|
||||
pbDrawTextPositions(overlay.bitmap,textpos)
|
||||
# Fade out flash, shudder Vs logo and expand it, and then fade to black
|
||||
animTime = (Graphics.frame_rate*2.75).floor
|
||||
shudderTime = (Graphics.frame_rate*1.75).floor
|
||||
zoomTime = (Graphics.frame_rate*2.5).floor
|
||||
shudderDelta = [4*20/Graphics.frame_rate,1].max
|
||||
for i in 0...animTime
|
||||
if i<shudderTime # Fade out the white flash
|
||||
flash.opacity -= 52*20/Graphics.frame_rate if flash.opacity>0
|
||||
elsif i==shudderTime # Make the flash black
|
||||
flash.tone = Tone.new(-255,-255,-255)
|
||||
elsif i>=zoomTime # Fade to black
|
||||
flash.opacity += 52*20/Graphics.frame_rate if flash.opacity<255
|
||||
end
|
||||
bar1.ox -= 32*20/Graphics.frame_rate
|
||||
bar2.ox += 32*20/Graphics.frame_rate
|
||||
if i<shudderTime
|
||||
j = i%(2*Graphics.frame_rate/20)
|
||||
if j>=0.5*Graphics.frame_rate/20 && j<1.5*Graphics.frame_rate/20
|
||||
vs.x += shudderDelta
|
||||
vs.y -= shudderDelta
|
||||
else
|
||||
vs.x -= shudderDelta
|
||||
vs.y += shudderDelta
|
||||
end
|
||||
elsif i<zoomTime
|
||||
vs.zoom_x += 0.4*20/Graphics.frame_rate
|
||||
vs.zoom_y += 0.4*20/Graphics.frame_rate
|
||||
end
|
||||
pbWait(1)
|
||||
end
|
||||
# End of animation
|
||||
player.dispose
|
||||
trainer.dispose
|
||||
flash.dispose
|
||||
vs.dispose
|
||||
bar1.dispose
|
||||
bar2.dispose
|
||||
overlay.dispose
|
||||
fade.dispose
|
||||
viewvs.dispose
|
||||
viewopp.dispose
|
||||
viewplayer.dispose
|
||||
viewport.color = Color.new(0,0,0,255)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Override battle intro animation
|
||||
#===============================================================================
|
||||
# If you want to add a custom battle intro animation, copy the following alias
|
||||
# line and method into a new script section. Change the name of the alias part
|
||||
# ("__over1__") in your copied code in both places. Then add in your custom
|
||||
# transition code in the place shown.
|
||||
# Note that $game_temp.background_bitmap contains an image of the current game
|
||||
# screen.
|
||||
# When the custom animation has finished, the screen should have faded to black
|
||||
# somehow.
|
||||
|
||||
alias __over1__pbBattleAnimationOverride pbBattleAnimationOverride
|
||||
|
||||
def pbBattleAnimationOverride(viewport,battletype=0,foe=nil)
|
||||
# The following example runs a common event that ought to do a custom
|
||||
# animation if some condition is true:
|
||||
#
|
||||
# if $game_map.map_id==20 # If on map 20
|
||||
# pbCommonEvent(20)
|
||||
# return true # Note that the battle animation is done
|
||||
# end
|
||||
#
|
||||
# The following line needs to call the aliased method if the custom transition
|
||||
# animation was NOT shown.
|
||||
return __over1__pbBattleAnimationOverride(viewport,battletype,foe)
|
||||
end
|
||||
@@ -1,465 +0,0 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class PokemonEncounters
|
||||
attr_reader :step_count
|
||||
|
||||
def initialize
|
||||
@step_chances = {}
|
||||
@encounter_tables = {}
|
||||
@chance_accumulator = 0
|
||||
end
|
||||
|
||||
def setup(map_ID)
|
||||
@step_count = 0
|
||||
@step_chances = {}
|
||||
@encounter_tables = {}
|
||||
encounter_data = getEncounterMode().get(map_ID, $PokemonGlobal.encounter_version)
|
||||
encounter_data = GameData::Encounter.get(map_ID, $PokemonGlobal.encounter_version) if !encounter_data
|
||||
if encounter_data
|
||||
encounter_data.step_chances.each { |type, value| @step_chances[type] = value }
|
||||
@encounter_tables = Marshal.load(Marshal.dump(encounter_data.types))
|
||||
end
|
||||
end
|
||||
|
||||
def getEncounterMode()
|
||||
|
||||
mode = GameData::Encounter
|
||||
if $game_switches && $game_switches[SWITCH_MODERN_MODE]
|
||||
mode = GameData::EncounterModern
|
||||
end
|
||||
if $game_switches && $game_switches[SWITCH_RANDOM_WILD] && $game_switches[SWITCH_RANDOM_WILD_AREA]
|
||||
mode= GameData::EncounterRandom
|
||||
end
|
||||
echoln mode
|
||||
return mode
|
||||
end
|
||||
|
||||
def reset_step_count
|
||||
@step_count = 0
|
||||
@chance_accumulator = 0
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# Returns whether encounters for the given encounter type have been defined
|
||||
# for the current map.
|
||||
def has_encounter_type?(enc_type)
|
||||
return false if !enc_type
|
||||
return @encounter_tables[enc_type] && @encounter_tables[enc_type].length > 0
|
||||
end
|
||||
|
||||
# Returns whether encounters for the given encounter type have been defined
|
||||
# for the given map. Only called by Bug Catching Contest to see if it can use
|
||||
# the map's BugContest encounter type to generate caught Pokémon for the other
|
||||
# contestants.
|
||||
def map_has_encounter_type?(map_ID, enc_type)
|
||||
return false if !enc_type
|
||||
encounter_data = getEncounterMode().get(map_ID, $PokemonGlobal.encounter_version)
|
||||
return false if !encounter_data
|
||||
return encounter_data.types[enc_type] && encounter_data.types[enc_type].length > 0
|
||||
end
|
||||
|
||||
# Returns whether land-like encounters have been defined for the current map.
|
||||
# Applies only to encounters triggered by moving around.
|
||||
def has_land_encounters?
|
||||
GameData::EncounterType.each do |enc_type|
|
||||
next if ![:land, :contest].include?(enc_type.type)
|
||||
return true if has_encounter_type?(enc_type.id)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# Returns whether land-like encounters have been defined for the current map
|
||||
# (ignoring the Bug Catching Contest one).
|
||||
# Applies only to encounters triggered by moving around.
|
||||
def has_normal_land_encounters?
|
||||
GameData::EncounterType.each do |enc_type|
|
||||
return true if enc_type.type == :land && has_encounter_type?(enc_type.id)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# Returns whether cave-like encounters have been defined for the current map.
|
||||
# Applies only to encounters triggered by moving around.
|
||||
def has_cave_encounters?
|
||||
GameData::EncounterType.each do |enc_type|
|
||||
return true if enc_type.type == :cave && has_encounter_type?(enc_type.id)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# Returns whether water-like encounters have been defined for the current map.
|
||||
# Applies only to encounters triggered by moving around (i.e. not fishing).
|
||||
def has_water_encounters?
|
||||
GameData::EncounterType.each do |enc_type|
|
||||
return true if enc_type.type == :water && has_encounter_type?(enc_type.id)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# Returns whether the player's current location allows wild encounters to
|
||||
# trigger upon taking a step.
|
||||
def encounter_possible_here?
|
||||
return true if $PokemonGlobal.surfing
|
||||
terrain_tag = $game_map.terrain_tag($game_player.x, $game_player.y)
|
||||
return false if terrain_tag.ice
|
||||
return true if has_cave_encounters? # i.e. this map is a cave
|
||||
return true if has_land_encounters? && terrain_tag.land_wild_encounters
|
||||
return false
|
||||
end
|
||||
|
||||
# Returns whether a wild encounter should happen, based on its encounter
|
||||
# chance. Called when taking a step and by Rock Smash.
|
||||
def encounter_triggered?(enc_type, repel_active = false, triggered_by_step = true)
|
||||
if !enc_type || !GameData::EncounterType.exists?(enc_type)
|
||||
raise ArgumentError.new(_INTL("Encounter type {1} does not exist", enc_type))
|
||||
end
|
||||
return false if $game_system.encounter_disabled
|
||||
return false if !$Trainer
|
||||
return false if $DEBUG && Input.press?(Input::CTRL)
|
||||
# Check if enc_type has a defined step chance/encounter table
|
||||
return false if !@step_chances[enc_type] || @step_chances[enc_type] == 0
|
||||
return false if !has_encounter_type?(enc_type)
|
||||
#Always check encounter if pokeradar is active
|
||||
return true if $PokemonTemp.pokeradar != nil
|
||||
|
||||
# Get base encounter chance and minimum steps grace period
|
||||
encounter_chance = @step_chances[enc_type].to_f
|
||||
min_steps_needed = (8 - encounter_chance / 10).clamp(0, 8).to_f
|
||||
# Apply modifiers to the encounter chance and the minimum steps amount
|
||||
if triggered_by_step
|
||||
encounter_chance += @chance_accumulator / 200
|
||||
encounter_chance *= 0.8 if $PokemonGlobal.bicycle
|
||||
end
|
||||
if !Settings::FLUTES_CHANGE_WILD_ENCOUNTER_LEVELS
|
||||
encounter_chance /= 2 if $PokemonMap.blackFluteUsed
|
||||
min_steps_needed *= 2 if $PokemonMap.blackFluteUsed
|
||||
encounter_chance *= 1.5 if $PokemonMap.whiteFluteUsed
|
||||
min_steps_needed /= 2 if $PokemonMap.whiteFluteUsed
|
||||
end
|
||||
first_pkmn = $Trainer.first_pokemon
|
||||
if first_pkmn
|
||||
case first_pkmn.item_id
|
||||
when :CLEANSETAG
|
||||
encounter_chance *= 2.0 / 3
|
||||
min_steps_needed *= 4 / 3.0
|
||||
when :PUREINCENSE
|
||||
encounter_chance *= 2.0 / 3
|
||||
min_steps_needed *= 4 / 3.0
|
||||
else # Ignore ability effects if an item effect applies
|
||||
case first_pkmn.ability_id
|
||||
when :STENCH, :WHITESMOKE, :QUICKFEET
|
||||
encounter_chance /= 2
|
||||
min_steps_needed *= 2
|
||||
when :SNOWCLOAK
|
||||
if GameData::Weather.get($game_screen.weather_type).category == :Hail
|
||||
encounter_chance /= 2
|
||||
min_steps_needed *= 2
|
||||
end
|
||||
when :SANDVEIL
|
||||
if GameData::Weather.get($game_screen.weather_type).category == :Sandstorm
|
||||
encounter_chance /= 2
|
||||
min_steps_needed *= 2
|
||||
end
|
||||
when :SWARM
|
||||
encounter_chance *= 1.5
|
||||
min_steps_needed /= 2
|
||||
when :ILLUMINATE, :ARENATRAP, :NOGUARD
|
||||
encounter_chance *= 2
|
||||
min_steps_needed /= 2
|
||||
end
|
||||
end
|
||||
end
|
||||
# Wild encounters are much less likely to happen for the first few steps
|
||||
# after a previous wild encounter
|
||||
if triggered_by_step && @step_count < min_steps_needed
|
||||
@step_count += 1
|
||||
return false if rand(100) >= encounter_chance * 5 / (@step_chances[enc_type] + @chance_accumulator / 200)
|
||||
end
|
||||
# Decide whether the wild encounter should actually happen
|
||||
return true if rand(100) < encounter_chance
|
||||
# If encounter didn't happen, make the next step more likely to produce one
|
||||
if triggered_by_step
|
||||
@chance_accumulator += @step_chances[enc_type]
|
||||
@chance_accumulator = 0 if repel_active
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# Returns whether an encounter with the given Pokémon should be allowed after
|
||||
# taking into account Repels and ability effects.
|
||||
def allow_encounter?(enc_data, repel_active = false)
|
||||
return false if !enc_data
|
||||
# Repel
|
||||
if repel_active && !pbPokeRadarOnShakingGrass
|
||||
first_pkmn = (Settings::REPEL_COUNTS_FAINTED_POKEMON) ? $Trainer.first_pokemon : $Trainer.first_able_pokemon
|
||||
if first_pkmn && enc_data[1] < first_pkmn.level
|
||||
@chance_accumulator = 0
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Some abilities make wild encounters less likely if the wild Pokémon is
|
||||
# sufficiently weaker than the Pokémon with the ability
|
||||
first_pkmn = $Trainer.first_pokemon
|
||||
if first_pkmn
|
||||
case first_pkmn.ability_id
|
||||
when :INTIMIDATE, :KEENEYE
|
||||
return false if enc_data[1] <= first_pkmn.level - 5 && rand(100) < 50
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# Returns whether a wild encounter should be turned into a double wild
|
||||
# encounter.
|
||||
def have_double_wild_battle?
|
||||
return false if $PokemonTemp.forceSingleBattle
|
||||
return false if pbInSafari?
|
||||
return true if $PokemonGlobal.partner
|
||||
return false if $Trainer.able_pokemon_count <= 1
|
||||
return true if $game_player.pbTerrainTag.double_wild_encounters && rand(100) < 30
|
||||
return false
|
||||
end
|
||||
|
||||
# Checks the defined encounters for the current map and returns the encounter
|
||||
# type that the given time should produce. Only returns an encounter type if
|
||||
# it has been defined for the current map.
|
||||
def find_valid_encounter_type_for_time(base_type, time)
|
||||
ret = nil
|
||||
if PBDayNight.isDay?(time)
|
||||
try_type = nil
|
||||
if PBDayNight.isMorning?(time)
|
||||
try_type = (base_type.to_s + "Morning").to_sym
|
||||
elsif PBDayNight.isAfternoon?(time)
|
||||
try_type = (base_type.to_s + "Afternoon").to_sym
|
||||
elsif PBDayNight.isEvening?(time)
|
||||
try_type = (base_type.to_s + "Evening").to_sym
|
||||
end
|
||||
ret = try_type if try_type && has_encounter_type?(try_type)
|
||||
if !ret
|
||||
try_type = (base_type.to_s + "Day").to_sym
|
||||
ret = try_type if has_encounter_type?(try_type)
|
||||
end
|
||||
else
|
||||
try_type = (base_type.to_s + "Night").to_sym
|
||||
ret = try_type if has_encounter_type?(try_type)
|
||||
end
|
||||
return ret if ret
|
||||
return (has_encounter_type?(base_type)) ? base_type : nil
|
||||
end
|
||||
|
||||
# Returns the encounter method that the current encounter should be generated
|
||||
# from, depending on the player's current location.
|
||||
def encounter_type
|
||||
time = pbGetTimeNow
|
||||
ret = nil
|
||||
terrain_tag = $game_map.terrain_tag($game_player.x, $game_player.y)
|
||||
if $PokemonGlobal.surfing
|
||||
ret = find_valid_encounter_type_for_time(:Water, time)
|
||||
else # Land/Cave (can have both in the same map)
|
||||
if has_land_encounters? && $game_map.terrain_tag($game_player.x, $game_player.y).land_wild_encounters
|
||||
ret = :BugContest if pbInBugContest? && has_encounter_type?(:BugContest)
|
||||
baseType = :Land #default grass
|
||||
baseType = :Land1 if terrain_tag == :Grass_alt1
|
||||
baseType = :Land2 if terrain_tag == :Grass_alt2
|
||||
baseType = :Land3 if terrain_tag == :Grass_alt3
|
||||
ret = find_valid_encounter_type_for_time(baseType, time) if !ret
|
||||
end
|
||||
if !ret && has_cave_encounters?
|
||||
ret = find_valid_encounter_type_for_time(:Cave, time)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# For the current map, randomly chooses a species and level from the encounter
|
||||
# list for the given encounter type. Returns nil if there are none defined.
|
||||
# A higher chance_rolls makes this method prefer rarer encounter slots.
|
||||
def choose_wild_pokemon(enc_type, chance_rolls = 1)
|
||||
if !enc_type || !GameData::EncounterType.exists?(enc_type)
|
||||
raise ArgumentError.new(_INTL("Encounter type {1} does not exist", enc_type))
|
||||
end
|
||||
enc_list = @encounter_tables[enc_type]
|
||||
return nil if !enc_list || enc_list.length == 0
|
||||
# Static/Magnet Pull prefer wild encounters of certain types, if possible.
|
||||
# If they activate, they remove all Pokémon from the encounter table that do
|
||||
# not have the type they favor. If none have that type, nothing is changed.
|
||||
first_pkmn = $Trainer.first_pokemon
|
||||
if first_pkmn
|
||||
favored_type = nil
|
||||
case first_pkmn.ability_id
|
||||
when :STATIC
|
||||
favored_type = :ELECTRIC if GameData::Type.exists?(:ELECTRIC) && rand(100) < 50
|
||||
when :MAGNETPULL
|
||||
favored_type = :STEEL if GameData::Type.exists?(:STEEL) && rand(100) < 50
|
||||
end
|
||||
if favored_type
|
||||
new_enc_list = []
|
||||
enc_list.each do |enc|
|
||||
species_data = GameData::Species.get(enc[1])
|
||||
t1 = species_data.type1
|
||||
t2 = species_data.type2
|
||||
new_enc_list.push(enc) if t1 == favored_type || t2 == favored_type
|
||||
end
|
||||
enc_list = new_enc_list if new_enc_list.length > 0
|
||||
end
|
||||
end
|
||||
enc_list.sort! { |a, b| b[0] <=> a[0] } # Highest probability first
|
||||
# Calculate the total probability value
|
||||
chance_total = 0
|
||||
enc_list.each { |a| chance_total += a[0] }
|
||||
# Choose a random entry in the encounter table based on entry probabilities
|
||||
rnd = 0
|
||||
chance_rolls.times do
|
||||
r = rand(chance_total)
|
||||
rnd = r if r > rnd # Prefer rarer entries if rolling repeatedly
|
||||
end
|
||||
encounter = nil
|
||||
enc_list.each do |enc|
|
||||
rnd -= enc[0]
|
||||
next if rnd >= 0
|
||||
encounter = enc
|
||||
break
|
||||
end
|
||||
# Get the chosen species and level
|
||||
level = rand(encounter[2]..encounter[3])
|
||||
# Some abilities alter the level of the wild Pokémon
|
||||
if first_pkmn
|
||||
case first_pkmn.ability_id
|
||||
when :HUSTLE, :PRESSURE, :VITALSPIRIT
|
||||
level = encounter[3] if rand(100) < 50 # Highest possible level
|
||||
end
|
||||
end
|
||||
# Black Flute and White Flute alter the level of the wild Pokémon
|
||||
if Settings::FLUTES_CHANGE_WILD_ENCOUNTER_LEVELS
|
||||
if $PokemonMap.blackFluteUsed
|
||||
level = [level + rand(1..4), GameData::GrowthRate.max_level].min
|
||||
elsif $PokemonMap.whiteFluteUsed
|
||||
level = [level - rand(1..4), 1].max
|
||||
end
|
||||
end
|
||||
# Return [species, level]
|
||||
return [encounter[1], level]
|
||||
end
|
||||
|
||||
# For the given map, randomly chooses a species and level from the encounter
|
||||
# list for the given encounter type. Returns nil if there are none defined.
|
||||
# Used by the Bug Catching Contest to choose what the other participants
|
||||
# caught.
|
||||
def choose_wild_pokemon_for_map(map_ID, enc_type)
|
||||
if !enc_type || !GameData::EncounterType.exists?(enc_type)
|
||||
raise ArgumentError.new(_INTL("Encounter type {1} does not exist", enc_type))
|
||||
end
|
||||
# Get the encounter table
|
||||
encounter_data = getEncounterMode().get(map_ID, $PokemonGlobal.encounter_version)
|
||||
return nil if !encounter_data
|
||||
enc_list = encounter_data.types[enc_type]
|
||||
return nil if !enc_list || enc_list.length == 0
|
||||
# Calculate the total probability value
|
||||
chance_total = 0
|
||||
enc_list.each { |a| chance_total += a[0] }
|
||||
# Choose a random entry in the encounter table based on entry probabilities
|
||||
rnd = 0
|
||||
chance_rolls.times do
|
||||
r = rand(chance_total)
|
||||
rnd = r if r > rnd # Prefer rarer entries if rolling repeatedly
|
||||
end
|
||||
encounter = nil
|
||||
enc_list.each do |enc|
|
||||
rnd -= enc[0]
|
||||
next if rnd >= 0
|
||||
encounter = enc
|
||||
break
|
||||
end
|
||||
# Return [species, level]
|
||||
level = rand(encounter[2]..encounter[3])
|
||||
return [encounter[1], level]
|
||||
end
|
||||
|
||||
|
||||
|
||||
def listPossibleEncounters(enctype)
|
||||
if !enctype
|
||||
raise ArgumentError.new(_INTL("Encounter type out of range"))
|
||||
end
|
||||
return @encounter_tables[enctype]
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
# Creates and returns a Pokémon based on the given species and level.
|
||||
# Applies wild Pokémon modifiers (wild held item, shiny chance modifiers,
|
||||
# Pokérus, gender/nature forcing because of player's lead Pokémon).
|
||||
def pbGenerateWildPokemon(species,level,isRoamer=false)
|
||||
genwildpoke = Pokemon.new(species,level)
|
||||
# Give the wild Pokémon a held item
|
||||
items = genwildpoke.wildHoldItems
|
||||
first_pkmn = $Trainer.first_pokemon
|
||||
chances = [50,5,1]
|
||||
chances = [60,20,5] if first_pkmn && first_pkmn.hasAbility?(:COMPOUNDEYES)
|
||||
itemrnd = rand(100)
|
||||
if (items[0]==items[1] && items[1]==items[2]) || itemrnd<chances[0]
|
||||
genwildpoke.item = items[0]
|
||||
elsif itemrnd<(chances[0]+chances[1])
|
||||
genwildpoke.item = items[1]
|
||||
elsif itemrnd<(chances[0]+chances[1]+chances[2])
|
||||
genwildpoke.item = items[2]
|
||||
end
|
||||
# Shiny Charm makes shiny Pokémon more likely to generate
|
||||
if GameData::Item.exists?(:SHINYCHARM) && $PokemonBag.pbHasItem?(:SHINYCHARM)
|
||||
2.times do # 3 times as likely
|
||||
break if genwildpoke.shiny?
|
||||
genwildpoke.personalID = rand(2**16) | rand(2**16) << 16
|
||||
end
|
||||
end
|
||||
# Give Pokérus
|
||||
genwildpoke.givePokerus if rand(65536) < Settings::POKERUS_CHANCE
|
||||
# Change wild Pokémon's gender/nature depending on the lead party Pokémon's
|
||||
# ability
|
||||
if first_pkmn
|
||||
if first_pkmn.hasAbility?(:CUTECHARM) && !genwildpoke.singleGendered?
|
||||
if first_pkmn.male?
|
||||
(rand(3)<2) ? genwildpoke.makeFemale : genwildpoke.makeMale
|
||||
elsif first_pkmn.female?
|
||||
(rand(3)<2) ? genwildpoke.makeMale : genwildpoke.makeFemale
|
||||
end
|
||||
elsif first_pkmn.hasAbility?(:SYNCHRONIZE)
|
||||
genwildpoke.nature = first_pkmn.nature if !isRoamer && rand(100)<50
|
||||
end
|
||||
end
|
||||
# Trigger events that may alter the generated Pokémon further
|
||||
Events.onWildPokemonCreate.trigger(nil,genwildpoke)
|
||||
return genwildpoke
|
||||
end
|
||||
|
||||
# Used by fishing rods and Headbutt/Rock Smash/Sweet Scent to generate a wild
|
||||
# Pokémon (or two) for a triggered wild encounter.
|
||||
def pbEncounter(enc_type)
|
||||
$PokemonTemp.encounterType = enc_type
|
||||
encounter1 = $PokemonEncounters.choose_wild_pokemon(enc_type)
|
||||
encounter1 = EncounterModifier.trigger(encounter1)
|
||||
return false if !encounter1
|
||||
if $PokemonEncounters.have_double_wild_battle?
|
||||
encounter2 = $PokemonEncounters.choose_wild_pokemon(enc_type)
|
||||
encounter2 = EncounterModifier.trigger(encounter2)
|
||||
return false if !encounter2
|
||||
pbDoubleWildBattle(encounter1[0], encounter1[1], encounter2[0], encounter2[1])
|
||||
else
|
||||
pbWildBattle(encounter1[0], encounter1[1])
|
||||
end
|
||||
$PokemonTemp.encounterType = nil
|
||||
$PokemonTemp.forceSingleBattle = false
|
||||
EncounterModifier.triggerEncounterEnd
|
||||
return true
|
||||
end
|
||||
@@ -1,50 +0,0 @@
|
||||
################################################################################
|
||||
# This section was created solely for you to put various bits of code that
|
||||
# modify various wild Pokémon and trainers immediately prior to battling them.
|
||||
# Be sure that any code you use here ONLY applies to the Pokémon/trainers you
|
||||
# want it to apply to!
|
||||
################################################################################
|
||||
|
||||
# Make all wild Pokémon shiny while a certain Switch is ON (see Settings).
|
||||
Events.onWildPokemonCreate += proc { |_sender, e|
|
||||
pokemon = e[0]
|
||||
if $game_switches[Settings::SHINY_WILD_POKEMON_SWITCH]
|
||||
pokemon.shiny = true
|
||||
pokemon.debug_shiny=true
|
||||
end
|
||||
}
|
||||
|
||||
# # Used in the random dungeon map. Makes the levels of all wild Pokémon in that
|
||||
# # map depend on the levels of Pokémon in the player's party.
|
||||
# # This is a simple method, and can/should be modified to account for evolutions
|
||||
# # and other such details. Of course, you don't HAVE to use this code.
|
||||
# Events.onWildPokemonCreate += proc { |_sender, e|
|
||||
# pokemon = e[0]
|
||||
# if $game_map.map_id == 0
|
||||
# new_level = pbBalancedLevel($Trainer.party) - 4 + rand(5) # For variety
|
||||
# new_level = new_level.clamp(1, GameData::GrowthRate.max_level)
|
||||
# pokemon.level = new_level
|
||||
# pokemon.calc_stats
|
||||
# pokemon.reset_moves
|
||||
# end
|
||||
# }
|
||||
|
||||
# This is the basis of a trainer modifier. It works both for trainers loaded
|
||||
# when you battle them, and for partner trainers when they are registered.
|
||||
# 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
|
||||
# before each battle.
|
||||
#Events.onTrainerPartyLoad += proc { |_sender, trainer|
|
||||
# if trainer # An NPCTrainer object containing party/items/lose text, etc.
|
||||
# YOUR CODE HERE
|
||||
# end
|
||||
#}
|
||||
|
||||
|
||||
#NECROZMA BATTLE
|
||||
Events.onWildPokemonCreate += proc { |_sender, e|
|
||||
pokemon = e[0]
|
||||
if $game_switches[SWITCH_KANTO_DARKNESS_STAGE_4] && pokemon.species == :NECROZMA
|
||||
pokemon.item = :NECROZIUM
|
||||
end
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
class PokemonGlobalMetadata
|
||||
attr_accessor :roamPosition
|
||||
attr_accessor :roamedAlready # Whether a roamer has been encountered on current map
|
||||
attr_accessor :roamEncounter
|
||||
attr_accessor :roamPokemon
|
||||
attr_writer :roamPokemonCaught
|
||||
|
||||
def roamPokemonCaught
|
||||
return @roamPokemonCaught || []
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Making roaming Pokémon roam around.
|
||||
#===============================================================================
|
||||
# Resets all roaming Pokemon that were defeated without having been caught.
|
||||
def pbResetAllRoamers
|
||||
return if !$PokemonGlobal.roamPokemon
|
||||
for i in 0...$PokemonGlobal.roamPokemon.length
|
||||
next if $PokemonGlobal.roamPokemon[i]!=true || !$PokemonGlobal.roamPokemonCaught[i]
|
||||
$PokemonGlobal.roamPokemon[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the roaming areas for a particular Pokémon.
|
||||
def pbRoamingAreas(idxRoamer)
|
||||
# [species ID, level, Game Switch, encounter type, battle BGM, area maps hash]
|
||||
roamData = Settings::ROAMING_SPECIES[idxRoamer]
|
||||
return roamData[5] if roamData && roamData[5]
|
||||
return Settings::ROAMING_AREAS
|
||||
end
|
||||
|
||||
def getRoamingMap(roamingPokemon)
|
||||
possible_roamers = {}
|
||||
for roamer in Settings::ROAMING_SPECIES
|
||||
name = roamer[0]
|
||||
id =
|
||||
possible_roamers[name] = id
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# Puts a roamer in a completely random map available to it.
|
||||
def pbRandomRoam(index)
|
||||
return if !$PokemonGlobal.roamPosition
|
||||
keys = pbRoamingAreas(index).keys
|
||||
$PokemonGlobal.roamPosition[index] = keys[rand(keys.length)]
|
||||
end
|
||||
|
||||
# Makes all roaming Pokémon roam to another map.
|
||||
def pbRoamPokemon
|
||||
$PokemonGlobal.roamPokemon = [] if !$PokemonGlobal.roamPokemon
|
||||
# Start all roamers off in random maps
|
||||
if !$PokemonGlobal.roamPosition
|
||||
$PokemonGlobal.roamPosition = {}
|
||||
for i in 0...Settings::ROAMING_SPECIES.length
|
||||
next if !GameData::Species.exists?(i[0])
|
||||
keys = pbRoamingAreas(i).keys
|
||||
$PokemonGlobal.roamPosition[i] = keys[rand(keys.length)]
|
||||
end
|
||||
end
|
||||
# Roam each Pokémon in turn
|
||||
for i in 0...Settings::ROAMING_SPECIES.length
|
||||
pbRoamPokemonOne(i)
|
||||
end
|
||||
|
||||
applyRoamWeather()
|
||||
end
|
||||
|
||||
|
||||
def applyRoamWeather()
|
||||
return if $game_screen.weather_type != :None
|
||||
currently_roaming = getAllCurrentlyRoamingPokemon()
|
||||
currently_roaming.each do |roamer_id|
|
||||
roamer_switch = Settings::ROAMING_SPECIES[roamer_id][2]
|
||||
roamer_active = $game_switches[roamer_switch]
|
||||
roamerOnCurrentMap = $PokemonGlobal.roamPosition[roamer_id] == $game_map.map_id && roamer_active
|
||||
if roamerOnCurrentMap
|
||||
return if $PokemonGlobal.roamPokemonCaught[roamer_id]
|
||||
weather = Settings::ROAMING_SPECIES[roamer_id][6]
|
||||
$game_screen.weather(weather, 4, 0)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Makes a single roaming Pokémon roam to another map. Doesn't roam if it isn't
|
||||
# currently possible to encounter it (i.e. its Game Switch is off).
|
||||
def pbRoamPokemonOne(idxRoamer)
|
||||
# [species ID, level, Game Switch, encounter type, battle BGM, area maps hash]
|
||||
roamData = Settings::ROAMING_SPECIES[idxRoamer]
|
||||
return if roamData[2]>0 && !$game_switches[roamData[2]] # Game Switch is off
|
||||
return if !GameData::Species.exists?(roamData[0])
|
||||
# Get hash of area patrolled by the roaming Pokémon
|
||||
mapIDs = pbRoamingAreas(idxRoamer).keys
|
||||
return if !mapIDs || mapIDs.length==0 # No roaming area defined somehow
|
||||
# Get the roaming Pokémon's current map
|
||||
currentMap = $PokemonGlobal.roamPosition[idxRoamer]
|
||||
if !currentMap
|
||||
currentMap = mapIDs[rand(mapIDs.length)]
|
||||
$PokemonGlobal.roamPosition[idxRoamer] = currentMap
|
||||
end
|
||||
# Make an array of all possible maps the roaming Pokémon could roam to
|
||||
newMapChoices = []
|
||||
nextMaps = pbRoamingAreas(idxRoamer)[currentMap]
|
||||
return if !nextMaps
|
||||
for map in nextMaps
|
||||
# Only add map as a choice if the player hasn't been there recently
|
||||
newMapChoices.push(map)
|
||||
end
|
||||
# Rarely, add a random possible map into the mix
|
||||
if rand(32)==0
|
||||
newMapChoices.push(mapIDs[rand(mapIDs.length)])
|
||||
end
|
||||
#50% chance of moving to a new map
|
||||
if rand(2)==0
|
||||
# Choose a random new map to roam to
|
||||
if newMapChoices.length>0
|
||||
$PokemonGlobal.roamPosition[idxRoamer] = newMapChoices[rand(newMapChoices.length)]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# When the player moves to a new map (with a different name), make all roaming
|
||||
# Pokémon roam.
|
||||
Events.onMapChange += proc { |_sender,e|
|
||||
oldMapID = e[0]
|
||||
# Get and compare map names
|
||||
mapInfos = pbLoadMapInfos
|
||||
next if mapInfos && oldMapID>0 && mapInfos[oldMapID] &&
|
||||
mapInfos[oldMapID].name && $game_map.name==mapInfos[oldMapID].name
|
||||
# Make roaming Pokémon roam
|
||||
pbRoamPokemon
|
||||
$PokemonGlobal.roamedAlready = false
|
||||
}
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Encountering a roaming Pokémon in a wild battle.
|
||||
#===============================================================================
|
||||
class PokemonTemp
|
||||
attr_accessor :roamerIndex # Index of roaming Pokémon to encounter next
|
||||
end
|
||||
|
||||
|
||||
|
||||
# Returns whether the given category of encounter contains the actual encounter
|
||||
# method that will occur in the player's current position.
|
||||
def pbRoamingMethodAllowed(roamer_method)
|
||||
enc_type = $PokemonTemp.encounterType #$PokemonEncounters.encounter_type
|
||||
type = GameData::EncounterType.get(enc_type).type
|
||||
case roamer_method
|
||||
when 0 # Any step-triggered method (except Bug Contest)
|
||||
return [:land, :cave, :water].include?(type)
|
||||
when 1 # Walking (except Bug Contest)
|
||||
return [:land, :cave].include?(type)
|
||||
when 2 # Surfing
|
||||
return type == :water
|
||||
when 3 # Fishing
|
||||
return type == :fishing
|
||||
when 4 # Water-based
|
||||
return [:water, :fishing].include?(type)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
EncounterModifier.register(proc { |encounter|
|
||||
$PokemonTemp.roamerIndex = nil
|
||||
next nil if !encounter
|
||||
# Give the regular encounter if encountering a roaming Pokémon isn't possible
|
||||
next encounter if $PokemonGlobal.roamedAlready
|
||||
next encounter if $PokemonGlobal.partner
|
||||
next encounter if $PokemonTemp.pokeradar
|
||||
#next encounter if rand(100) < 75 # 25% chance of encountering a roaming Pokémon
|
||||
# Look at each roaming Pokémon in turn and decide whether it's possible to
|
||||
# encounter it
|
||||
currentRegion = pbGetCurrentRegion
|
||||
currentMapName = pbGetMessage(MessageTypes::MapNames, $game_map.map_id)
|
||||
possible_roamers = []
|
||||
Settings::ROAMING_SPECIES.each_with_index do |data, i|
|
||||
# data = [species, level, Game Switch, roamer method, battle BGM, area maps hash]
|
||||
next if !GameData::Species.exists?(data[0])
|
||||
next if data[2] > 0 && !$game_switches[data[2]] # Isn't roaming
|
||||
next if $PokemonGlobal.roamPokemon[i] == true # Roaming Pokémon has been caught
|
||||
# Get the roamer's current map
|
||||
roamerMap = $PokemonGlobal.roamPosition[i]
|
||||
if !roamerMap
|
||||
mapIDs = pbRoamingAreas(i).keys # Hash of area patrolled by the roaming Pokémon
|
||||
next if !mapIDs || mapIDs.length == 0 # No roaming area defined somehow
|
||||
roamerMap = mapIDs[rand(mapIDs.length)]
|
||||
$PokemonGlobal.roamPosition[i] = roamerMap
|
||||
end
|
||||
# If roamer isn't on the current map, check if it's on a map with the same
|
||||
# name and in the same region
|
||||
if roamerMap != $game_map.map_id
|
||||
map_metadata = GameData::MapMetadata.try_get(roamerMap)
|
||||
next if !map_metadata || !map_metadata.town_map_position ||
|
||||
map_metadata.town_map_position[0] != currentRegion
|
||||
next if pbGetMessage(MessageTypes::MapNames, roamerMap) != currentMapName
|
||||
end
|
||||
# Check whether the roamer's roamer method is currently possible
|
||||
next if !pbRoamingMethodAllowed(data[3])
|
||||
# Add this roaming Pokémon to the list of possible roaming Pokémon to encounter
|
||||
possible_roamers.push([i, data[0], data[1], data[4]]) # [i, species, level, BGM]
|
||||
end
|
||||
# No encounterable roaming Pokémon were found, just have the regular encounter
|
||||
next encounter if possible_roamers.length == 0
|
||||
# Pick a roaming Pokémon to encounter out of those available
|
||||
roamer = possible_roamers[rand(possible_roamers.length)]
|
||||
$PokemonGlobal.roamEncounter = roamer
|
||||
$PokemonTemp.roamerIndex = roamer[0]
|
||||
$PokemonGlobal.nextBattleBGM = roamer[3] if roamer[3] && !roamer[3].empty?
|
||||
$PokemonTemp.forceSingleBattle = true
|
||||
next [roamer[1], roamer[2]] # Species, level
|
||||
})
|
||||
|
||||
Events.onWildBattleOverride += proc { |_sender,e|
|
||||
species = e[0]
|
||||
level = e[1]
|
||||
handled = e[2]
|
||||
next if handled[0]!=nil
|
||||
next if !$PokemonGlobal.roamEncounter || $PokemonTemp.roamerIndex.nil?
|
||||
handled[0] = pbRoamingPokemonBattle(species, level)
|
||||
}
|
||||
|
||||
def pbRoamingPokemonBattle(species, level)
|
||||
# Get the roaming Pokémon to encounter; generate it based on the species and
|
||||
# level if it doesn't already exist
|
||||
idxRoamer = $PokemonTemp.roamerIndex
|
||||
if !$PokemonGlobal.roamPokemon[idxRoamer] ||
|
||||
!$PokemonGlobal.roamPokemon[idxRoamer].is_a?(Pokemon)
|
||||
$PokemonGlobal.roamPokemon[idxRoamer] = pbGenerateWildPokemon(species,level,true)
|
||||
end
|
||||
# Set some battle rules
|
||||
setBattleRule("single")
|
||||
setBattleRule("roamerFlees")
|
||||
# Perform the battle
|
||||
decision = pbWildBattleCore($PokemonGlobal.roamPokemon[idxRoamer])
|
||||
# Update Roaming Pokémon data based on result of battle
|
||||
if decision==1 || decision==4 # Defeated or caught
|
||||
$PokemonGlobal.roamPokemon[idxRoamer] = true
|
||||
$PokemonGlobal.roamPokemonCaught[idxRoamer] = (decision==4)
|
||||
end
|
||||
$PokemonGlobal.roamEncounter = nil
|
||||
$PokemonGlobal.roamedAlready = true
|
||||
# Used by the Poké Radar to update/break the chain
|
||||
Events.onWildBattleEnd.trigger(nil,species,level,decision)
|
||||
# Return false if the player lost or drew the battle, and true if any other result
|
||||
return (decision!=2 && decision!=5)
|
||||
end
|
||||
|
||||
EncounterModifier.registerEncounterEnd(proc {
|
||||
$PokemonTemp.roamerIndex = nil
|
||||
})
|
||||
@@ -1,291 +0,0 @@
|
||||
#===============================================================================
|
||||
# Global metadata not specific to a map. This class holds field state data that
|
||||
# span multiple maps.
|
||||
#===============================================================================
|
||||
class PokemonGlobalMetadata
|
||||
# Movement
|
||||
attr_accessor :bicycle
|
||||
attr_accessor :surfing
|
||||
attr_accessor :diving
|
||||
attr_accessor :sliding
|
||||
attr_accessor :fishing
|
||||
# Player data
|
||||
attr_accessor :startTime
|
||||
attr_accessor :stepcount
|
||||
attr_accessor :pcItemStorage
|
||||
attr_accessor :mailbox
|
||||
attr_accessor :phoneNumbers
|
||||
attr_accessor :phoneTime
|
||||
attr_accessor :partner
|
||||
attr_accessor :creditsPlayed
|
||||
# Pokédex
|
||||
attr_accessor :pokedexUnlocked # Deprecated, replaced with Player::Pokedex#unlocked_dexes
|
||||
attr_accessor :pokedexDex # Dex currently looking at (-1 is National Dex)
|
||||
attr_accessor :pokedexIndex # Last species viewed per Dex
|
||||
attr_accessor :pokedexMode # Search mode
|
||||
# Day Care
|
||||
attr_accessor :daycare
|
||||
attr_accessor :daycareEgg
|
||||
attr_accessor :daycareEggSteps
|
||||
# Special battle modes
|
||||
attr_accessor :safariState
|
||||
attr_accessor :bugContestState
|
||||
attr_accessor :challenge
|
||||
attr_accessor :lastbattle # Saved recording of a battle
|
||||
# Events
|
||||
attr_accessor :eventvars
|
||||
# Affecting the map
|
||||
attr_accessor :bridge
|
||||
attr_accessor :repel
|
||||
attr_accessor :tempRepel
|
||||
attr_accessor :flashUsed
|
||||
attr_accessor :encounter_version
|
||||
# Map transfers
|
||||
attr_accessor :healingSpot
|
||||
attr_accessor :escapePoint
|
||||
attr_accessor :pokecenterMapId
|
||||
attr_accessor :pokecenterX
|
||||
attr_accessor :pokecenterY
|
||||
attr_accessor :pokecenterDirection
|
||||
# Movement history
|
||||
attr_accessor :visitedMaps
|
||||
attr_accessor :mapTrail
|
||||
# Counters
|
||||
attr_accessor :happinessSteps
|
||||
attr_accessor :pokerusTime
|
||||
# Save file
|
||||
attr_accessor :safesave
|
||||
#Trainers rematch
|
||||
attr_accessor :rematchedTrainers
|
||||
attr_accessor :questRewardsObtained
|
||||
|
||||
def initialize
|
||||
# Movement
|
||||
@bicycle = false
|
||||
@surfing = false
|
||||
@diving = false
|
||||
@sliding = false
|
||||
@fishing = false
|
||||
# Player data
|
||||
@startTime = Time.now
|
||||
@stepcount = 0
|
||||
@pcItemStorage = nil
|
||||
@mailbox = nil
|
||||
@phoneNumbers = []
|
||||
@phoneTime = 0
|
||||
@partner = nil
|
||||
@creditsPlayed = false
|
||||
# Pokédex
|
||||
numRegions = pbLoadRegionalDexes.length
|
||||
@pokedexDex = (numRegions==0) ? -1 : 0
|
||||
@pokedexIndex = []
|
||||
@pokedexMode = 0
|
||||
for i in 0...numRegions+1 # National Dex isn't a region, but is included
|
||||
@pokedexIndex[i] = 0
|
||||
end
|
||||
# Day Care
|
||||
@daycare = [[nil,0],[nil,0]]
|
||||
@daycareEgg = false
|
||||
@daycareEggSteps = 0
|
||||
# Special battle modes
|
||||
@safariState = nil
|
||||
@bugContestState = nil
|
||||
@challenge = nil
|
||||
@lastbattle = nil
|
||||
# Events
|
||||
@eventvars = {}
|
||||
# Affecting the map
|
||||
@bridge = 0
|
||||
@repel = 0
|
||||
@tempRepel = false
|
||||
@flashused = false
|
||||
@encounter_version = 0
|
||||
# Map transfers
|
||||
@healingSpot = nil
|
||||
@escapePoint = []
|
||||
@pokecenterMapId = -1
|
||||
@pokecenterX = -1
|
||||
@pokecenterY = -1
|
||||
@pokecenterDirection = -1
|
||||
# Movement history
|
||||
@visitedMaps = []
|
||||
@mapTrail = []
|
||||
# Counters
|
||||
@happinessSteps = 0
|
||||
@pokerusTime = nil
|
||||
# Save file
|
||||
@safesave = false
|
||||
@questRewardsObtained = []
|
||||
end
|
||||
|
||||
# @deprecated Use {Player#character_ID} instead. This alias is slated to be removed in v20.
|
||||
def playerID
|
||||
Deprecation.warn_method('PokemonGlobalMetadata#playerID', 'v20', '$Trainer.character_ID')
|
||||
return @playerID || $Trainer.character_ID
|
||||
end
|
||||
|
||||
# @deprecated Use {Player#character_ID=} instead. This alias is slated to be removed in v20.
|
||||
def playerID=(value)
|
||||
Deprecation.warn_method('PokemonGlobalMetadata#playerID=', 'v20', '$Trainer.character_ID=')
|
||||
if value.nil?
|
||||
@playerID = value # For setting to nil by a save data conversion
|
||||
else
|
||||
$Trainer.character_ID = value
|
||||
end
|
||||
end
|
||||
|
||||
# @deprecated Use {Player#coins} instead. This alias is slated to be removed in v20.
|
||||
def coins
|
||||
Deprecation.warn_method('PokemonGlobalMetadata#coins', 'v20', '$Trainer.coins')
|
||||
return @coins || $Trainer.coins
|
||||
end
|
||||
|
||||
# @deprecated Use {Player#coins=} instead. This alias is slated to be removed in v20.
|
||||
def coins=(value)
|
||||
Deprecation.warn_method('PokemonGlobalMetadata#coins=', 'v20', '$Trainer.coins=')
|
||||
if value.nil?
|
||||
@coins = value # For setting to nil by a save data conversion
|
||||
else
|
||||
$Trainer.coins = value
|
||||
end
|
||||
end
|
||||
|
||||
# @deprecated Use {Player#soot} instead. This alias is slated to be removed in v20.
|
||||
def sootsack
|
||||
Deprecation.warn_method('PokemonGlobalMetadata#sootsack', 'v20', '$Trainer.soot')
|
||||
return @sootsack || $Trainer.soot
|
||||
end
|
||||
|
||||
# @deprecated Use {Player#soot=} instead. This alias is slated to be removed in v20.
|
||||
def sootsack=(value)
|
||||
Deprecation.warn_method('PokemonGlobalMetadata#sootsack=', 'v20', '$Trainer.soot=')
|
||||
if value.nil?
|
||||
@sootsack = value # For setting to nil by a save data conversion
|
||||
else
|
||||
$Trainer.soot = value
|
||||
end
|
||||
end
|
||||
|
||||
# @deprecated Use {Player#has_running_shoes} instead. This alias is slated to be removed in v20.
|
||||
def runningShoes
|
||||
Deprecation.warn_method('PokemonGlobalMetadata#runningShoes', 'v20', '$Trainer.has_running_shoes')
|
||||
return (!@runningShoes.nil?) ? @runningShoes : $Trainer.has_running_shoes
|
||||
end
|
||||
|
||||
# @deprecated Use {Player#has_running_shoes=} instead. This alias is slated to be removed in v20.
|
||||
def runningShoes=(value)
|
||||
Deprecation.warn_method('PokemonGlobalMetadata#runningShoes=', 'v20', '$Trainer.has_running_shoes=')
|
||||
if value.nil?
|
||||
@runningShoes = value # For setting to nil by a save data conversion
|
||||
else
|
||||
$Trainer.has_running_shoes = value
|
||||
end
|
||||
end
|
||||
|
||||
# @deprecated Use {Player#seen_storage_creator} instead. This alias is slated to be removed in v20.
|
||||
def seenStorageCreator
|
||||
Deprecation.warn_method('PokemonGlobalMetadata#seenStorageCreator', 'v20', '$Trainer.seen_storage_creator')
|
||||
return (!@seenStorageCreator.nil?) ? @seenStorageCreator : $Trainer.seen_storage_creator
|
||||
end
|
||||
|
||||
# @deprecated Use {Player#seen_storage_creator=} instead. This alias is slated to be removed in v20.
|
||||
def seenStorageCreator=(value)
|
||||
Deprecation.warn_method('PokemonGlobalMetadata#seenStorageCreator=', 'v20', '$Trainer.seen_storage_creator=')
|
||||
if value.nil?
|
||||
@seenStorageCreator = value # For setting to nil by a save data conversion
|
||||
else
|
||||
$Trainer.seen_storage_creator = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# This class keeps track of erased and moved events so their position
|
||||
# can remain after a game is saved and loaded. This class also includes
|
||||
# variables that should remain valid only for the current map.
|
||||
#===============================================================================
|
||||
class PokemonMapMetadata
|
||||
attr_reader :erasedEvents
|
||||
attr_reader :movedEvents
|
||||
attr_accessor :strengthUsed
|
||||
attr_accessor :blackFluteUsed
|
||||
attr_accessor :whiteFluteUsed
|
||||
|
||||
def initialize
|
||||
clear
|
||||
end
|
||||
|
||||
def clear
|
||||
@erasedEvents = {}
|
||||
@movedEvents = {}
|
||||
@strengthUsed = false
|
||||
@blackFluteUsed = false
|
||||
@whiteFluteUsed = false
|
||||
end
|
||||
|
||||
def addErasedEvent(eventID)
|
||||
key = [$game_map.map_id,eventID]
|
||||
@erasedEvents[key] = true
|
||||
end
|
||||
|
||||
def addMovedEvent(eventID)
|
||||
key = [$game_map.map_id,eventID]
|
||||
event = $game_map.events[eventID] if eventID.is_a?(Integer)
|
||||
@movedEvents[key] = [event.x,event.y,event.direction,event.through] if event
|
||||
end
|
||||
|
||||
def updateMap
|
||||
for i in @erasedEvents
|
||||
if i[0][0]==$game_map.map_id && i[1]
|
||||
event = $game_map.events[i[0][1]]
|
||||
event.erase if event
|
||||
end
|
||||
end
|
||||
for i in @movedEvents
|
||||
if i[0][0]==$game_map.map_id && i[1]
|
||||
next if !$game_map.events[i[0][1]]
|
||||
$game_map.events[i[0][1]].moveto(i[1][0],i[1][1])
|
||||
case i[1][2]
|
||||
when 2 then $game_map.events[i[0][1]].turn_down
|
||||
when 4 then $game_map.events[i[0][1]].turn_left
|
||||
when 6 then $game_map.events[i[0][1]].turn_right
|
||||
when 8 then $game_map.events[i[0][1]].turn_up
|
||||
end
|
||||
end
|
||||
if i[1][3]!=nil
|
||||
$game_map.events[i[0][1]].through = i[1][3]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Temporary data which is not saved and which is erased when a game restarts.
|
||||
#===============================================================================
|
||||
class PokemonTemp
|
||||
attr_accessor :menuLastChoice
|
||||
attr_accessor :keyItemCalling
|
||||
attr_accessor :hiddenMoveEventCalling
|
||||
attr_accessor :begunNewGame
|
||||
attr_accessor :miniupdate
|
||||
attr_accessor :waitingTrainer
|
||||
attr_accessor :darknessSprite
|
||||
attr_accessor :lastbattle
|
||||
attr_accessor :flydata
|
||||
attr_accessor :surfJump
|
||||
attr_accessor :endSurf
|
||||
attr_accessor :forceSingleBattle
|
||||
|
||||
def initialize
|
||||
@menuLastChoice = 0
|
||||
@keyItemCalling = false
|
||||
@hiddenMoveEventCalling = false
|
||||
@begunNewGame = false
|
||||
@miniupdate = false
|
||||
@forceSingleBattle = false
|
||||
end
|
||||
end
|
||||
@@ -1,340 +0,0 @@
|
||||
#===============================================================================
|
||||
# Day and night system
|
||||
#===============================================================================
|
||||
def pbGetTimeNow
|
||||
return Time.now
|
||||
end
|
||||
|
||||
module PBDayNight
|
||||
HourlyTones = [
|
||||
Tone.new(-70, -90, 15, 55), # Night # Midnight
|
||||
Tone.new(-70, -90, 15, 55), # Night
|
||||
Tone.new(-70, -90, 15, 55), # Night
|
||||
Tone.new(-70, -90, 15, 55), # Night
|
||||
Tone.new(-60, -70, -5, 50), # Night
|
||||
Tone.new(-40, -50, -35, 50), # Day/morning
|
||||
Tone.new(-40, -50, -35, 50), # Day/morning # 6AM
|
||||
Tone.new(-40, -50, -35, 50), # Day/morning
|
||||
Tone.new(-40, -50, -35, 50), # Day/morning
|
||||
Tone.new(-20, -25, -15, 20), # Day/morning
|
||||
Tone.new(0, 0, 0, 0), # Day
|
||||
Tone.new(0, 0, 0, 0), # Day
|
||||
Tone.new(0, 0, 0, 0), # Day # Noon
|
||||
Tone.new(0, 0, 0, 0), # Day
|
||||
Tone.new(0, 0, 0, 0), # Day/afternoon
|
||||
Tone.new(0, 0, 0, 0), # Day/afternoon
|
||||
Tone.new(0, 0, 0, 0), # Day/afternoon
|
||||
Tone.new(0, 0, 0, 0), # Day/afternoon
|
||||
Tone.new(-5, -30, -20, 0), # Day/evening # 6PM
|
||||
Tone.new(-15, -60, -10, 20), # Day/evening
|
||||
Tone.new(-15, -60, -10, 20), # Day/evening
|
||||
Tone.new(-40, -75, 5, 40), # Night
|
||||
Tone.new(-70, -90, 15, 55), # Night
|
||||
Tone.new(-70, -90, 15, 55) # Night
|
||||
]
|
||||
@cachedTone = nil
|
||||
@dayNightToneLastUpdate = nil
|
||||
@oneOverSixty = 1 / 60.0
|
||||
|
||||
# Returns true if it's day.
|
||||
def self.isDay?(time = nil)
|
||||
return false if darknessEffectOnCurrentMap()
|
||||
time = pbGetTimeNow if !time
|
||||
return (time.hour >= 5 && time.hour < 20)
|
||||
end
|
||||
|
||||
# Returns true if it's night.
|
||||
def self.isNight?(time = nil)
|
||||
return true if darknessEffectOnCurrentMap()
|
||||
time = pbGetTimeNow if !time
|
||||
return (time.hour >= 20 || time.hour < 5)
|
||||
end
|
||||
|
||||
# Returns true if it's morning.
|
||||
def self.isMorning?(time = nil)
|
||||
return false if darknessEffectOnCurrentMap()
|
||||
time = pbGetTimeNow if !time
|
||||
return (time.hour >= 5 && time.hour < 10)
|
||||
end
|
||||
|
||||
# Returns true if it's the afternoon.
|
||||
def self.isAfternoon?(time = nil)
|
||||
return false if darknessEffectOnCurrentMap()
|
||||
time = pbGetTimeNow if !time
|
||||
return (time.hour >= 14 && time.hour < 17)
|
||||
end
|
||||
|
||||
# Returns true if it's the evening.
|
||||
def self.isEvening?(time = nil)
|
||||
return false if darknessEffectOnCurrentMap()
|
||||
time = pbGetTimeNow if !time
|
||||
return (time.hour >= 17 && time.hour < 20)
|
||||
end
|
||||
|
||||
# Gets a number representing the amount of daylight (0=full night, 255=full day).
|
||||
def self.getShade
|
||||
time = pbGetDayNightMinutes
|
||||
time = (24 * 60) - time if time > (12 * 60)
|
||||
return 255 * time / (12 * 60)
|
||||
end
|
||||
|
||||
# Gets a Tone object representing a suggested shading
|
||||
# tone for the current time of day.
|
||||
def self.getTone
|
||||
@cachedTone = Tone.new(0, 0, 0) if !@cachedTone
|
||||
return @cachedTone if !Settings::TIME_SHADING
|
||||
if !@dayNightToneLastUpdate ||
|
||||
Graphics.frame_count - @dayNightToneLastUpdate >= Graphics.frame_rate * 30
|
||||
getToneInternal
|
||||
@dayNightToneLastUpdate = Graphics.frame_count
|
||||
end
|
||||
return @cachedTone
|
||||
end
|
||||
|
||||
def self.pbGetDayNightMinutes
|
||||
return 0 if darknessEffectOnCurrentMap() #midnight
|
||||
now = pbGetTimeNow # Get the current in-game time
|
||||
return (now.hour * 60) + now.min
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.getToneInternal
|
||||
# Calculates the tone for the current frame, used for day/night effects
|
||||
realMinutes = pbGetDayNightMinutes
|
||||
hour = realMinutes / 60
|
||||
minute = realMinutes % 60
|
||||
tone = PBDayNight::HourlyTones[hour]
|
||||
|
||||
nexthourtone = PBDayNight::HourlyTones[(hour + 1) % 24]
|
||||
|
||||
darkness_tone = Tone.new(-80, -100, 05, 55)
|
||||
if $game_switches[SWITCH_KANTO_DARKNESS] || darknessEffectOnCurrentMap()
|
||||
tone = darkness_tone
|
||||
nexthourtone = darkness_tone
|
||||
end
|
||||
|
||||
# Calculate current tint according to current and next hour's tint and
|
||||
# depending on current minute
|
||||
@cachedTone.red = ((nexthourtone.red - tone.red) * minute * @oneOverSixty) + tone.red
|
||||
@cachedTone.green = ((nexthourtone.green - tone.green) * minute * @oneOverSixty) + tone.green
|
||||
@cachedTone.blue = ((nexthourtone.blue - tone.blue) * minute * @oneOverSixty) + tone.blue
|
||||
@cachedTone.gray = ((nexthourtone.gray - tone.gray) * minute * @oneOverSixty) + tone.gray
|
||||
end
|
||||
end
|
||||
|
||||
def pbDayNightTint(object)
|
||||
return if !$scene.is_a?(Scene_Map)
|
||||
if Settings::TIME_SHADING && GameData::MapMetadata.exists?($game_map.map_id) &&
|
||||
GameData::MapMetadata.get($game_map.map_id).outdoor_map
|
||||
tone = PBDayNight.getTone
|
||||
object.tone.set(tone.red, tone.green, tone.blue, tone.gray)
|
||||
else
|
||||
object.tone.set(0, 0, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Moon phases and Zodiac
|
||||
#===============================================================================
|
||||
# Calculates the phase of the moon.
|
||||
# 0 - New Moon
|
||||
# 1 - Waxing Crescent
|
||||
# 2 - First Quarter
|
||||
# 3 - Waxing Gibbous
|
||||
# 4 - Full Moon
|
||||
# 5 - Waning Gibbous
|
||||
# 6 - Last Quarter
|
||||
# 7 - Waning Crescent
|
||||
def moonphase(time = nil)
|
||||
# in UTC
|
||||
time = pbGetTimeNow if !time
|
||||
transitions = [
|
||||
1.8456618033125,
|
||||
5.5369854099375,
|
||||
9.2283090165625,
|
||||
12.9196326231875,
|
||||
16.6109562298125,
|
||||
20.3022798364375,
|
||||
23.9936034430625,
|
||||
27.6849270496875]
|
||||
yy = time.year - ((12 - time.mon) / 10.0).floor
|
||||
j = (365.25 * (4712 + yy)).floor + (((time.mon + 9) % 12) * 30.6 + 0.5).floor + time.day + 59
|
||||
j -= (((yy / 100.0) + 49).floor * 0.75).floor - 38 if j > 2299160
|
||||
j += (((time.hour * 60) + time.min * 60) + time.sec) / 86400.0
|
||||
v = (j - 2451550.1) / 29.530588853
|
||||
v = ((v - v.floor) + (v < 0 ? 1 : 0))
|
||||
ag = v * 29.53
|
||||
for i in 0...transitions.length
|
||||
return i if ag <= transitions[i]
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
# Calculates the zodiac sign based on the given month and day:
|
||||
# 0 is Aries, 11 is Pisces. Month is 1 if January, and so on.
|
||||
def zodiac(month, day)
|
||||
time = [
|
||||
3, 21, 4, 19, # Aries
|
||||
4, 20, 5, 20, # Taurus
|
||||
5, 21, 6, 20, # Gemini
|
||||
6, 21, 7, 20, # Cancer
|
||||
7, 23, 8, 22, # Leo
|
||||
8, 23, 9, 22, # Virgo
|
||||
9, 23, 10, 22, # Libra
|
||||
10, 23, 11, 21, # Scorpio
|
||||
11, 22, 12, 21, # Sagittarius
|
||||
12, 22, 1, 19, # Capricorn
|
||||
1, 20, 2, 18, # Aquarius
|
||||
2, 19, 3, 20 # Pisces
|
||||
]
|
||||
for i in 0...12
|
||||
return i if month == time[i * 4] && day >= time[i * 4 + 1]
|
||||
return i if month == time[i * 4 + 2] && day <= time[i * 4 + 3]
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
# Returns the opposite of the given zodiac sign.
|
||||
# 0 is Aries, 11 is Pisces.
|
||||
def zodiacOpposite(sign)
|
||||
return (sign + 6) % 12
|
||||
end
|
||||
|
||||
# 0 is Aries, 11 is Pisces.
|
||||
def zodiacPartners(sign)
|
||||
return [(sign + 4) % 12, (sign + 8) % 12]
|
||||
end
|
||||
|
||||
# 0 is Aries, 11 is Pisces.
|
||||
def zodiacComplements(sign)
|
||||
return [(sign + 1) % 12, (sign + 11) % 12]
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Days of the week
|
||||
#===============================================================================
|
||||
def pbIsWeekday(wdayVariable, *arg)
|
||||
timenow = pbGetTimeNow
|
||||
wday = timenow.wday
|
||||
ret = false
|
||||
for wd in arg
|
||||
ret = true if wd == wday
|
||||
end
|
||||
if wdayVariable > 0
|
||||
$game_variables[wdayVariable] = [
|
||||
_INTL("Sunday"),
|
||||
_INTL("Monday"),
|
||||
_INTL("Tuesday"),
|
||||
_INTL("Wednesday"),
|
||||
_INTL("Thursday"),
|
||||
_INTL("Friday"),
|
||||
_INTL("Saturday")][wday]
|
||||
$game_map.need_refresh = true if $game_map
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Months
|
||||
#===============================================================================
|
||||
def pbIsMonth(monVariable, *arg)
|
||||
timenow = pbGetTimeNow
|
||||
thismon = timenow.mon
|
||||
ret = false
|
||||
for wd in arg
|
||||
ret = true if wd == thismon
|
||||
end
|
||||
if monVariable > 0
|
||||
$game_variables[monVariable] = pbGetMonthName(thismon)
|
||||
$game_map.need_refresh = true if $game_map
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbGetMonthName(month)
|
||||
return [_INTL("January"),
|
||||
_INTL("February"),
|
||||
_INTL("March"),
|
||||
_INTL("April"),
|
||||
_INTL("May"),
|
||||
_INTL("June"),
|
||||
_INTL("July"),
|
||||
_INTL("August"),
|
||||
_INTL("September"),
|
||||
_INTL("October"),
|
||||
_INTL("November"),
|
||||
_INTL("December")][month - 1]
|
||||
end
|
||||
|
||||
def pbGetAbbrevMonthName(month)
|
||||
return ["",
|
||||
_INTL("Jan."),
|
||||
_INTL("Feb."),
|
||||
_INTL("Mar."),
|
||||
_INTL("Apr."),
|
||||
_INTL("May"),
|
||||
_INTL("Jun."),
|
||||
_INTL("Jul."),
|
||||
_INTL("Aug."),
|
||||
_INTL("Sep."),
|
||||
_INTL("Oct."),
|
||||
_INTL("Nov."),
|
||||
_INTL("Dec.")][month]
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Seasons
|
||||
#===============================================================================
|
||||
def pbGetSeason
|
||||
return (pbGetTimeNow.mon - 1) % 4
|
||||
end
|
||||
|
||||
def pbIsSeason(seasonVariable, *arg)
|
||||
thisseason = pbGetSeason
|
||||
ret = false
|
||||
for wd in arg
|
||||
ret = true if wd == thisseason
|
||||
end
|
||||
if seasonVariable > 0
|
||||
$game_variables[seasonVariable] = [
|
||||
_INTL("Spring"),
|
||||
_INTL("Summer"),
|
||||
_INTL("Autumn"),
|
||||
_INTL("Winter")][thisseason]
|
||||
$game_map.need_refresh = true if $game_map
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbIsSpring
|
||||
return pbIsSeason(0, 0);
|
||||
end
|
||||
|
||||
# Jan, May, Sep
|
||||
def pbIsSummer
|
||||
return pbIsSeason(0, 1);
|
||||
end
|
||||
|
||||
# Feb, Jun, Oct
|
||||
def pbIsAutumn
|
||||
return pbIsSeason(0, 2);
|
||||
end
|
||||
|
||||
# Mar, Jul, Nov
|
||||
def pbIsFall
|
||||
return pbIsAutumn;
|
||||
end
|
||||
|
||||
def pbIsWinter
|
||||
return pbIsSeason(0, 3);
|
||||
end
|
||||
|
||||
# Apr, Aug, Dec
|
||||
|
||||
def pbGetSeasonName(season)
|
||||
return [_INTL("Spring"),
|
||||
_INTL("Summer"),
|
||||
_INTL("Autumn"),
|
||||
_INTL("Winter")][season]
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,174 +0,0 @@
|
||||
#===============================================================================
|
||||
# Fishing
|
||||
#===============================================================================
|
||||
def pbFishingBegin
|
||||
$PokemonGlobal.fishing = true
|
||||
if !pbCommonEvent(Settings::FISHING_BEGIN_COMMON_EVENT)
|
||||
patternb = 2*$game_player.direction - 1
|
||||
meta = GameData::Metadata.get_player($Trainer.character_ID)
|
||||
num = ($PokemonGlobal.surfing) ? 7 : 6
|
||||
if meta && meta[num] && meta[num]!=""
|
||||
charset = pbGetPlayerCharset(meta,num)
|
||||
4.times do |pattern|
|
||||
$game_player.setDefaultCharName(charset,patternb-pattern,true)
|
||||
(Graphics.frame_rate/20).times do
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbFishingEnd
|
||||
if !pbCommonEvent(Settings::FISHING_END_COMMON_EVENT)
|
||||
patternb = 2*($game_player.direction - 2)
|
||||
meta = GameData::Metadata.get_player($Trainer.character_ID)
|
||||
num = ($PokemonGlobal.surfing) ? 7 : 6
|
||||
if meta && meta[num] && meta[num]!=""
|
||||
charset = pbGetPlayerCharset(meta,num)
|
||||
4.times do |pattern|
|
||||
$game_player.setDefaultCharName(charset,patternb+pattern,true)
|
||||
(Graphics.frame_rate/20).times do
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
$PokemonGlobal.fishing = false
|
||||
end
|
||||
|
||||
def pbFishing(hasEncounter,rodType=1)
|
||||
autohook= Settings::FISHING_AUTO_HOOK || $game_switches[SWITCH_FISHING_AUTOHOOK]
|
||||
speedup = ($Trainer.first_pokemon && [:STICKYHOLD, :SUCTIONCUPS].include?($Trainer.first_pokemon.ability_id))
|
||||
biteChance = 20+(25*rodType) # 45, 70, 95
|
||||
biteChance *= 1.5 if speedup # 67.5, 100, 100
|
||||
hookChance = 100
|
||||
oldpattern = $game_player.fullPattern
|
||||
pbFishingBegin
|
||||
msgWindow = pbCreateMessageWindow
|
||||
ret = false
|
||||
loop do
|
||||
time = 5+rand(6)
|
||||
time = [time,5+rand(6)].min if speedup
|
||||
message = ""
|
||||
time.times { message += ". " }
|
||||
if pbWaitMessage(msgWindow,time)
|
||||
pbFishingEnd
|
||||
$game_player.setDefaultCharName(nil,oldpattern)
|
||||
pbMessageDisplay(msgWindow,_INTL("Not even a nibble..."))
|
||||
break
|
||||
end
|
||||
if hasEncounter && rand(100)<biteChance
|
||||
$scene.spriteset.addUserAnimation(Settings::EXCLAMATION_ANIMATION_ID,$game_player.x,$game_player.y,true,3)
|
||||
frames = Graphics.frame_rate - rand(Graphics.frame_rate/2) # 0.5-1 second
|
||||
if !pbWaitForInput(msgWindow,message+_INTL("\r\nOh! A bite!"),frames)
|
||||
pbFishingEnd
|
||||
$game_player.setDefaultCharName(nil,oldpattern)
|
||||
pbMessageDisplay(msgWindow,_INTL("The Pokémon got away..."))
|
||||
break
|
||||
end
|
||||
|
||||
itemChance = rand((rodType)*5)
|
||||
if itemChance<=1
|
||||
#ITEM
|
||||
items = [:PEARL,
|
||||
:OLDBOOT,
|
||||
:OLDBOOT,
|
||||
:OLDBOOT,
|
||||
:OLDBOOT,
|
||||
:WATERGEM,
|
||||
:PEARL,
|
||||
:WATERGEM
|
||||
]
|
||||
hats = [
|
||||
HAT_SLOWKING_SHELL,
|
||||
]
|
||||
hatChance = rand(5)
|
||||
if true#hatChance == 0
|
||||
hat = hats.sample
|
||||
if !hasHat?(hat)
|
||||
obtainHat(hat)
|
||||
else
|
||||
Kernel.pbItemBall(items[rand(items.size)],1,nil,false)
|
||||
end
|
||||
else
|
||||
Kernel.pbItemBall(items[rand(items.size)],1,nil,false)
|
||||
end
|
||||
Kernel.pbDisposeMessageWindow(msgWindow)
|
||||
pbFishingEnd
|
||||
$game_player.setDefaultCharName(nil,oldpattern)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
if autohook || rand(100) < hookChance
|
||||
pbFishingEnd
|
||||
pbMessageDisplay(msgWindow,_INTL("Landed a Pokémon!")) if !autohook
|
||||
$game_player.setDefaultCharName(nil,oldpattern)
|
||||
ret = true
|
||||
break
|
||||
end
|
||||
# biteChance += 15
|
||||
# hookChance += 15
|
||||
else
|
||||
pbFishingEnd
|
||||
$game_player.setDefaultCharName(nil,oldpattern)
|
||||
pbMessageDisplay(msgWindow,_INTL("Not even a nibble..."))
|
||||
break
|
||||
end
|
||||
end
|
||||
pbDisposeMessageWindow(msgWindow)
|
||||
return ret
|
||||
end
|
||||
|
||||
# Show waiting dots before a Pokémon bites
|
||||
def pbWaitMessage(msgWindow,time)
|
||||
message = ""
|
||||
periodTime = Graphics.frame_rate*4/10 # 0.4 seconds, 16 frames per dot
|
||||
(time+1).times do |i|
|
||||
message += ". " if i>0
|
||||
pbMessageDisplay(msgWindow,message,false)
|
||||
periodTime.times do
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
if Input.trigger?(Input::USE) || Input.trigger?(Input::BACK)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# A Pokémon is biting, reflex test to reel it in
|
||||
def pbWaitForInput(msgWindow,message,frames)
|
||||
autohook= Settings::FISHING_AUTO_HOOK || $game_switches[SWITCH_FISHING_AUTOHOOK]
|
||||
pbMessageDisplay(msgWindow,message,false)
|
||||
numFrame = 0
|
||||
twitchFrame = 0
|
||||
twitchFrameTime = Graphics.frame_rate/10 # 0.1 seconds, 4 frames
|
||||
loop do
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
# Twitch cycle: 1,0,1,0,0,0,0,0
|
||||
twitchFrame = (twitchFrame+1)%(twitchFrameTime*8)
|
||||
case twitchFrame%twitchFrameTime
|
||||
when 0, 2
|
||||
$game_player.pattern = 1
|
||||
else
|
||||
$game_player.pattern = 0
|
||||
end
|
||||
if Input.trigger?(Input::USE) || Input.trigger?(Input::BACK)
|
||||
$game_player.pattern = 0
|
||||
return true
|
||||
end
|
||||
break if !autohook && numFrame > frames
|
||||
numFrame += 1
|
||||
end
|
||||
return false
|
||||
end
|
||||
@@ -1,542 +0,0 @@
|
||||
Events.onSpritesetCreate += proc { |_sender,e|
|
||||
spriteset = e[0]
|
||||
viewport = e[1]
|
||||
map = spriteset.map
|
||||
for i in map.events.keys
|
||||
if map.events[i].name[/berryplant/i]
|
||||
spriteset.addUserSprite(BerryPlantMoistureSprite.new(map.events[i],map,viewport))
|
||||
spriteset.addUserSprite(BerryPlantSprite.new(map.events[i],map,viewport))
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
|
||||
class BerryPlantMoistureSprite
|
||||
def initialize(event,map,viewport=nil)
|
||||
@event=event
|
||||
@map=map
|
||||
@light = IconSprite.new(0,0,viewport)
|
||||
@light.ox=16
|
||||
@light.oy=24
|
||||
@oldmoisture=-1 # -1=none, 0=dry, 1=damp, 2=wet
|
||||
updateGraphic
|
||||
@disposed=false
|
||||
end
|
||||
|
||||
def disposed?
|
||||
return @disposed
|
||||
end
|
||||
|
||||
def dispose
|
||||
@light.dispose
|
||||
@map=nil
|
||||
@event=nil
|
||||
@disposed=true
|
||||
end
|
||||
|
||||
def updateGraphic
|
||||
case @oldmoisture
|
||||
when -1 then @light.setBitmap("")
|
||||
when 0 then @light.setBitmap("Graphics/Characters/berrytreeDry")
|
||||
when 1 then @light.setBitmap("Graphics/Characters/berrytreeDamp")
|
||||
when 2 then @light.setBitmap("Graphics/Characters/berrytreeWet")
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
return if !@light || !@event
|
||||
newmoisture=-1
|
||||
if @event.variable && @event.variable.length>6 && @event.variable[1]
|
||||
# Berry was planted, show moisture patch
|
||||
newmoisture=(@event.variable[4]>50) ? 2 : (@event.variable[4]>0) ? 1 : 0
|
||||
end
|
||||
if @oldmoisture!=newmoisture
|
||||
@oldmoisture=newmoisture
|
||||
updateGraphic
|
||||
end
|
||||
@light.update
|
||||
if (Object.const_defined?(:ScreenPosHelper) rescue false)
|
||||
@light.x = ScreenPosHelper.pbScreenX(@event)
|
||||
@light.y = ScreenPosHelper.pbScreenY(@event)
|
||||
@light.zoom_x = ScreenPosHelper.pbScreenZoomX(@event)
|
||||
else
|
||||
@light.x = @event.screen_x
|
||||
@light.y = @event.screen_y
|
||||
@light.zoom_x = 1.0
|
||||
end
|
||||
@light.zoom_y = @light.zoom_x
|
||||
pbDayNightTint(@light)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class BerryPlantSprite
|
||||
def initialize(event,map,_viewport)
|
||||
@event=event
|
||||
@map=map
|
||||
@oldstage=0
|
||||
@disposed=false
|
||||
berryData=event.variable
|
||||
return if !berryData
|
||||
@oldstage=berryData[0]
|
||||
@event.character_name=""
|
||||
berryData=updatePlantDetails(berryData)
|
||||
setGraphic(berryData,true) # Set the event's graphic
|
||||
@event.setVariable(berryData) # Set new berry data
|
||||
end
|
||||
|
||||
def dispose
|
||||
@event=nil
|
||||
@map=nil
|
||||
@disposed=true
|
||||
end
|
||||
|
||||
def disposed?
|
||||
@disposed
|
||||
end
|
||||
|
||||
def update # Constantly updates, used only to immediately
|
||||
berryData=@event.variable # change sprite when planting/picking berries
|
||||
if berryData
|
||||
berryData=updatePlantDetails(berryData) if berryData.length>6
|
||||
setGraphic(berryData)
|
||||
@event.setVariable(berryData)
|
||||
end
|
||||
end
|
||||
|
||||
def updatePlantDetails(berryData)
|
||||
return berryData if berryData[0]==0
|
||||
berryvalues = GameData::BerryPlant.get(berryData[1])
|
||||
timeperstage = berryvalues.hours_per_stage * 3600
|
||||
timenow=pbGetTimeNow
|
||||
if berryData.length>6
|
||||
# Gen 4 growth mechanisms
|
||||
# Check time elapsed since last check
|
||||
timeDiff=(timenow.to_i-berryData[3]) # in seconds
|
||||
return berryData if timeDiff<=0
|
||||
berryData[3]=timenow.to_i # last updated now
|
||||
# Mulch modifiers
|
||||
dryingrate = berryvalues.drying_per_hour
|
||||
maxreplants = GameData::BerryPlant::NUMBER_OF_REPLANTS
|
||||
ripestages = 4
|
||||
case berryData[7]
|
||||
when :GROWTHMULCH
|
||||
timeperstage = (timeperstage * 0.75).to_i
|
||||
dryingrate = (dryingrate * 1.5).ceil
|
||||
when :DAMPMULCH
|
||||
timeperstage = (timeperstage * 1.25).to_i
|
||||
dryingrate = (dryingrate * 0.5).floor
|
||||
when :GOOEYMULCH
|
||||
maxreplants = (maxreplants * 1.5).ceil
|
||||
when :STABLEMULCH
|
||||
ripestages = 6
|
||||
end
|
||||
# Cycle through all replants since last check
|
||||
loop do
|
||||
secondsalive=berryData[2]
|
||||
growinglife=(berryData[5]>0) ? 3 : 4 # number of growing stages
|
||||
numlifestages=growinglife+ripestages # number of growing + ripe stages
|
||||
# Should replant itself?
|
||||
if secondsalive+timeDiff>=timeperstage*numlifestages
|
||||
# Should replant
|
||||
if berryData[5]>=maxreplants # Too many replants
|
||||
return [0,0,0,0,0,0,0,0]
|
||||
end
|
||||
# Replant
|
||||
berryData[0]=2 # replants start in sprouting stage
|
||||
berryData[2]=0 # seconds alive
|
||||
berryData[5]+=1 # add to replant count
|
||||
berryData[6]=0 # yield penalty
|
||||
timeDiff-=(timeperstage*numlifestages-secondsalive)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
# Update current stage and dampness
|
||||
if berryData[0]>0
|
||||
# Advance growth stage
|
||||
oldlifetime=berryData[2]
|
||||
newlifetime=oldlifetime+timeDiff
|
||||
if berryData[0]<5
|
||||
berryData[0]=1+(newlifetime/timeperstage).floor
|
||||
berryData[0]+=1 if berryData[5]>0 # replants start at stage 2
|
||||
berryData[0]=5 if berryData[0]>5
|
||||
end
|
||||
# Update the "seconds alive" counter
|
||||
berryData[2]=newlifetime
|
||||
# Reduce dampness, apply yield penalty if dry
|
||||
growinglife=(berryData[5]>0) ? 3 : 4 # number of growing stages
|
||||
oldhourtick=(oldlifetime/3600).floor
|
||||
newhourtick=(([newlifetime,timeperstage*growinglife].min)/3600).floor
|
||||
(newhourtick-oldhourtick).times do
|
||||
if berryData[4]>0
|
||||
berryData[4]=[berryData[4]-dryingrate,0].max
|
||||
else
|
||||
berryData[6]+=1
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
# Gen 3 growth mechanics
|
||||
loop do
|
||||
if berryData[0]>0 && berryData[0]<5
|
||||
levels=0
|
||||
# Advance time
|
||||
timeDiff=(timenow.to_i-berryData[3]) # in seconds
|
||||
if timeDiff>=timeperstage
|
||||
levels+=1
|
||||
if timeDiff>=timeperstage*2
|
||||
levels+=1
|
||||
if timeDiff>=timeperstage*3
|
||||
levels+=1
|
||||
if timeDiff>=timeperstage*4
|
||||
levels+=1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
levels=5-berryData[0] if levels>5-berryData[0]
|
||||
break if levels==0
|
||||
berryData[2]=false # not watered this stage
|
||||
berryData[3]+=levels*timeperstage # add to time existed
|
||||
berryData[0]+=levels # increase growth stage
|
||||
berryData[0]=5 if berryData[0]>5
|
||||
end
|
||||
if berryData[0]>=5
|
||||
# Advance time
|
||||
timeDiff=(timenow.to_i-berryData[3]) # in seconds
|
||||
if timeDiff>=timeperstage*4 # ripe for 4 times as long as a stage
|
||||
# Replant
|
||||
berryData[0]=2 # replants start at stage 2
|
||||
berryData[2]=false # not watered this stage
|
||||
berryData[3]+=timeperstage*4 # add to time existed
|
||||
berryData[4]=0 # reset total waterings count
|
||||
berryData[5]+=1 # add to replanted count
|
||||
if berryData[5] > GameData::BerryPlant::NUMBER_OF_REPLANTS # Too many replants
|
||||
berryData = [0,0,false,0,0,0]
|
||||
break
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
# If raining, automatically water the plant
|
||||
if berryData[0] > 0 && berryData[0] < 5 && $game_screen &&
|
||||
GameData::Weather.get($game_screen.weather_type).category == :Rain
|
||||
if berryData[2] == false
|
||||
berryData[2] = true
|
||||
berryData[4] += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return berryData
|
||||
end
|
||||
|
||||
def setGraphic(berryData,fullcheck=false)
|
||||
return if !berryData || (@oldstage==berryData[0] && !fullcheck)
|
||||
case berryData[0]
|
||||
when 0
|
||||
@event.character_name=""
|
||||
when 1
|
||||
@event.character_name="berrytreeplanted" # Common to all berries
|
||||
@event.turn_down
|
||||
else
|
||||
filename=sprintf("berrytree%s",GameData::Item.get(berryData[1]).id.to_s)
|
||||
if pbResolveBitmap("Graphics/Characters/"+filename)
|
||||
@event.character_name=filename
|
||||
case berryData[0]
|
||||
when 2 then @event.turn_down # X sprouted
|
||||
when 3 then @event.turn_left # X taller
|
||||
when 4 then @event.turn_right # X flowering
|
||||
when 5 then @event.turn_up # X berries
|
||||
end
|
||||
else
|
||||
@event.character_name="Object ball"
|
||||
end
|
||||
if @oldstage!=berryData[0] && berryData.length>6 # Gen 4 growth mechanisms
|
||||
$scene.spriteset.addUserAnimation(Settings::PLANT_SPARKLE_ANIMATION_ID,@event.x,@event.y,false,1) if $scene.spriteset
|
||||
end
|
||||
end
|
||||
@oldstage=berryData[0]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbBerryPlant
|
||||
interp=pbMapInterpreter
|
||||
thisEvent=interp.get_character(0)
|
||||
berryData=interp.getVariable
|
||||
if !berryData
|
||||
if Settings::NEW_BERRY_PLANTS
|
||||
berryData=[0,nil,0,0,0,0,0,0]
|
||||
else
|
||||
berryData=[0,nil,false,0,0,0]
|
||||
end
|
||||
end
|
||||
# Stop the event turning towards the player
|
||||
case berryData[0]
|
||||
when 1 then thisEvent.turn_down # X planted
|
||||
when 2 then thisEvent.turn_down # X sprouted
|
||||
when 3 then thisEvent.turn_left # X taller
|
||||
when 4 then thisEvent.turn_right # X flowering
|
||||
when 5 then thisEvent.turn_up # X berries
|
||||
end
|
||||
watering = [:SPRAYDUCK, :SQUIRTBOTTLE, :WAILMERPAIL, :SPRINKLOTAD]
|
||||
berry=berryData[1]
|
||||
case berryData[0]
|
||||
when 0 # empty
|
||||
if Settings::NEW_BERRY_PLANTS
|
||||
# Gen 4 planting mechanics
|
||||
if !berryData[7] || berryData[7]==0 # No mulch used yet
|
||||
cmd=pbMessage(_INTL("It's soft, earthy soil."),[
|
||||
_INTL("Fertilize"),
|
||||
_INTL("Plant Berry"),
|
||||
_INTL("Exit")],-1)
|
||||
if cmd==0 # Fertilize
|
||||
ret=0
|
||||
pbFadeOutIn {
|
||||
scene = PokemonBag_Scene.new
|
||||
screen = PokemonBagScreen.new(scene,$PokemonBag)
|
||||
ret = screen.pbChooseItemScreen(Proc.new { |item| GameData::Item.get(item).is_mulch? })
|
||||
}
|
||||
if ret
|
||||
if GameData::Item.get(ret).is_mulch?
|
||||
berryData[7]=ret
|
||||
pbMessage(_INTL("The {1} was scattered on the soil.\1",GameData::Item.get(ret).name))
|
||||
if pbConfirmMessage(_INTL("Want to plant a Berry?"))
|
||||
pbFadeOutIn {
|
||||
scene = PokemonBag_Scene.new
|
||||
screen = PokemonBagScreen.new(scene,$PokemonBag)
|
||||
berry = screen.pbChooseItemScreen(Proc.new { |item| GameData::Item.get(item).is_berry? })
|
||||
}
|
||||
if berry
|
||||
timenow=pbGetTimeNow
|
||||
berryData[0]=1 # growth stage (1-5)
|
||||
berryData[1]=berry # item ID of planted berry
|
||||
berryData[2]=0 # seconds alive
|
||||
berryData[3]=timenow.to_i # time of last checkup (now)
|
||||
berryData[4]=100 # dampness value
|
||||
berryData[5]=0 # number of replants
|
||||
berryData[6]=0 # yield penalty
|
||||
$PokemonBag.pbDeleteItem(berry,1)
|
||||
pbMessage(_INTL("The {1} was planted in the soft, earthy soil.",
|
||||
GameData::Item.get(berry).name))
|
||||
end
|
||||
end
|
||||
interp.setVariable(berryData)
|
||||
else
|
||||
pbMessage(_INTL("That won't fertilize the soil!"))
|
||||
end
|
||||
return
|
||||
end
|
||||
elsif cmd==1 # Plant Berry
|
||||
pbFadeOutIn {
|
||||
scene = PokemonBag_Scene.new
|
||||
screen = PokemonBagScreen.new(scene,$PokemonBag)
|
||||
berry = screen.pbChooseItemScreen(Proc.new { |item| GameData::Item.get(item).is_berry? })
|
||||
}
|
||||
if berry
|
||||
timenow=pbGetTimeNow
|
||||
berryData[0]=1 # growth stage (1-5)
|
||||
berryData[1]=berry # item ID of planted berry
|
||||
berryData[2]=0 # seconds alive
|
||||
berryData[3]=timenow.to_i # time of last checkup (now)
|
||||
berryData[4]=100 # dampness value
|
||||
berryData[5]=0 # number of replants
|
||||
berryData[6]=0 # yield penalty
|
||||
$PokemonBag.pbDeleteItem(berry,1)
|
||||
pbMessage(_INTL("The {1} was planted in the soft, earthy soil.",
|
||||
GameData::Item.get(berry).name))
|
||||
interp.setVariable(berryData)
|
||||
end
|
||||
return
|
||||
end
|
||||
else
|
||||
pbMessage(_INTL("{1} has been laid down.\1",GameData::Item.get(berryData[7]).name))
|
||||
if pbConfirmMessage(_INTL("Want to plant a Berry?"))
|
||||
pbFadeOutIn {
|
||||
scene = PokemonBag_Scene.new
|
||||
screen = PokemonBagScreen.new(scene,$PokemonBag)
|
||||
berry = screen.pbChooseItemScreen(Proc.new { |item| GameData::Item.get(item).is_berry? })
|
||||
}
|
||||
if berry
|
||||
timenow=pbGetTimeNow
|
||||
berryData[0]=1 # growth stage (1-5)
|
||||
berryData[1]=berry # item ID of planted berry
|
||||
berryData[2]=0 # seconds alive
|
||||
berryData[3]=timenow.to_i # time of last checkup (now)
|
||||
berryData[4]=100 # dampness value
|
||||
berryData[5]=0 # number of replants
|
||||
berryData[6]=0 # yield penalty
|
||||
$PokemonBag.pbDeleteItem(berry,1)
|
||||
pbMessage(_INTL("The {1} was planted in the soft, earthy soil.",
|
||||
GameData::Item.get(berry).name))
|
||||
interp.setVariable(berryData)
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
else
|
||||
# Gen 3 planting mechanics
|
||||
if pbConfirmMessage(_INTL("It's soft, loamy soil.\nPlant a berry?"))
|
||||
pbFadeOutIn {
|
||||
scene = PokemonBag_Scene.new
|
||||
screen = PokemonBagScreen.new(scene,$PokemonBag)
|
||||
berry = screen.pbChooseItemScreen(Proc.new { |item| GameData::Item.get(item).is_berry? })
|
||||
}
|
||||
if berry
|
||||
timenow=pbGetTimeNow
|
||||
berryData[0]=1 # growth stage (1-5)
|
||||
berryData[1]=berry # item ID of planted berry
|
||||
berryData[2]=false # watered in this stage?
|
||||
berryData[3]=timenow.to_i # time planted
|
||||
berryData[4]=0 # total waterings
|
||||
berryData[5]=0 # number of replants
|
||||
berryData[6]=nil; berryData[7]=nil; berryData.compact! # for compatibility
|
||||
$PokemonBag.pbDeleteItem(berry,1)
|
||||
pbMessage(_INTL("{1} planted a {2} in the soft loamy soil.",
|
||||
$Trainer.name,GameData::Item.get(berry).name))
|
||||
interp.setVariable(berryData)
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
when 1 # X planted
|
||||
pbMessage(_INTL("A {1} was planted here.",GameData::Item.get(berry).name))
|
||||
when 2 # X sprouted
|
||||
pbMessage(_INTL("The {1} has sprouted.",GameData::Item.get(berry).name))
|
||||
when 3 # X taller
|
||||
pbMessage(_INTL("The {1} plant is growing bigger.",GameData::Item.get(berry).name))
|
||||
when 4 # X flowering
|
||||
if Settings::NEW_BERRY_PLANTS
|
||||
pbMessage(_INTL("This {1} plant is in bloom!",GameData::Item.get(berry).name))
|
||||
else
|
||||
case berryData[4]
|
||||
when 4
|
||||
pbMessage(_INTL("This {1} plant is in fabulous bloom!",GameData::Item.get(berry).name))
|
||||
when 3
|
||||
pbMessage(_INTL("This {1} plant is blooming very beautifully!",GameData::Item.get(berry).name))
|
||||
when 2
|
||||
pbMessage(_INTL("This {1} plant is blooming prettily!",GameData::Item.get(berry).name))
|
||||
when 1
|
||||
pbMessage(_INTL("This {1} plant is blooming cutely!",GameData::Item.get(berry).name))
|
||||
else
|
||||
pbMessage(_INTL("This {1} plant is in bloom!",GameData::Item.get(berry).name))
|
||||
end
|
||||
end
|
||||
when 5 # X berries
|
||||
berryvalues = GameData::BerryPlant.get(berryData[1])
|
||||
# Get berry yield (berrycount)
|
||||
berrycount=1
|
||||
if berryData.length > 6
|
||||
# Gen 4 berry yield calculation
|
||||
berrycount = [berryvalues.maximum_yield - berryData[6], berryvalues.minimum_yield].max
|
||||
else
|
||||
# Gen 3 berry yield calculation
|
||||
if berryData[4] > 0
|
||||
berrycount = (berryvalues.maximum_yield - berryvalues.minimum_yield) * (berryData[4] - 1)
|
||||
berrycount += rand(1 + berryvalues.maximum_yield - berryvalues.minimum_yield)
|
||||
berrycount = (berrycount / 4) + berryvalues.minimum_yield
|
||||
else
|
||||
berrycount = berryvalues.minimum_yield
|
||||
end
|
||||
end
|
||||
item = GameData::Item.get(berry)
|
||||
itemname = (berrycount>1) ? item.name_plural : item.name
|
||||
pocket = item.pocket
|
||||
if berrycount>1
|
||||
message=_INTL("There are {1} \\c[1]{2}\\c[0]!\nWant to pick them?",berrycount,itemname)
|
||||
else
|
||||
message=_INTL("There is 1 \\c[1]{1}\\c[0]!\nWant to pick it?",itemname)
|
||||
end
|
||||
if pbConfirmMessage(message)
|
||||
if !$PokemonBag.pbCanStore?(berry,berrycount)
|
||||
pbMessage(_INTL("Too bad...\nThe Bag is full..."))
|
||||
return
|
||||
end
|
||||
$PokemonBag.pbStoreItem(berry,berrycount)
|
||||
if berrycount>1
|
||||
pbMessage(_INTL("You picked the {1} \\c[1]{2}\\c[0].\\wtnp[30]",berrycount,itemname))
|
||||
else
|
||||
pbMessage(_INTL("You picked the \\c[1]{1}\\c[0].\\wtnp[30]",itemname))
|
||||
end
|
||||
pbMessage(_INTL("{1} put the \\c[1]{2}\\c[0] in the <icon=bagPocket{3}>\\c[1]{4}\\c[0] Pocket.\1",
|
||||
$Trainer.name,itemname,pocket,PokemonBag.pocketNames()[pocket]))
|
||||
if Settings::NEW_BERRY_PLANTS
|
||||
pbMessage(_INTL("The soil returned to its soft and earthy state."))
|
||||
berryData=[0,nil,0,0,0,0,0,0]
|
||||
else
|
||||
pbMessage(_INTL("The soil returned to its soft and loamy state."))
|
||||
berryData=[0,nil,false,0,0,0]
|
||||
end
|
||||
interp.setVariable(berryData)
|
||||
end
|
||||
end
|
||||
case berryData[0]
|
||||
when 1, 2, 3, 4
|
||||
for i in watering
|
||||
next if !GameData::Item.exists?(i) || !$PokemonBag.pbHasItem?(i)
|
||||
if pbConfirmMessage(_INTL("Want to sprinkle some water with the {1}?",GameData::Item.get(i).name))
|
||||
if berryData.length>6
|
||||
# Gen 4 berry watering mechanics
|
||||
berryData[4]=100
|
||||
else
|
||||
# Gen 3 berry watering mechanics
|
||||
if berryData[2]==false
|
||||
berryData[4]+=1
|
||||
berryData[2]=true
|
||||
end
|
||||
end
|
||||
interp.setVariable(berryData)
|
||||
pbMessage(_INTL("{1} watered the plant.\\wtnp[40]",$Trainer.name))
|
||||
if Settings::NEW_BERRY_PLANTS
|
||||
pbMessage(_INTL("There! All happy!"))
|
||||
else
|
||||
pbMessage(_INTL("The plant seemed to be delighted."))
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbPickBerry(berry, qty = 1)
|
||||
interp=pbMapInterpreter
|
||||
thisEvent=interp.get_character(0)
|
||||
berryData=interp.getVariable
|
||||
berry=GameData::Item.get(berry)
|
||||
itemname=(qty>1) ? berry.name_plural : berry.name
|
||||
if qty>1
|
||||
message=_INTL("There are {1} \\c[1]{2}\\c[0]!\nWant to pick them?",qty,itemname)
|
||||
else
|
||||
message=_INTL("There is 1 \\c[1]{1}\\c[0]!\nWant to pick it?",itemname)
|
||||
end
|
||||
if pbConfirmMessage(message)
|
||||
if !$PokemonBag.pbCanStore?(berry,qty)
|
||||
pbMessage(_INTL("Too bad...\nThe Bag is full..."))
|
||||
return
|
||||
end
|
||||
$PokemonBag.pbStoreItem(berry,qty)
|
||||
if qty>1
|
||||
pbMessage(_INTL("You picked the {1} \\c[1]{2}\\c[0].\\wtnp[30]",qty,itemname))
|
||||
else
|
||||
pbMessage(_INTL("You picked the \\c[1]{1}\\c[0].\\wtnp[30]",itemname))
|
||||
end
|
||||
pocket = berry.pocket
|
||||
pbMessage(_INTL("{1} put the \\c[1]{2}\\c[0] in the <icon=bagPocket{3}>\\c[1]{4}\\c[0] Pocket.\1",
|
||||
$Trainer.name,itemname,pocket,PokemonBag.pocketNames()[pocket]))
|
||||
if Settings::NEW_BERRY_PLANTS
|
||||
pbMessage(_INTL("The soil returned to its soft and earthy state."))
|
||||
berryData=[0,nil,0,0,0,0,0,0]
|
||||
else
|
||||
pbMessage(_INTL("The soil returned to its soft and loamy state."))
|
||||
berryData=[0,nil,false,0,0,0]
|
||||
end
|
||||
interp.setVariable(berryData)
|
||||
pbSetSelfSwitch(thisEvent.id,"A",true)
|
||||
end
|
||||
end
|
||||
@@ -1,403 +0,0 @@
|
||||
#===============================================================================
|
||||
# Query information about Pokémon in the Day Care.
|
||||
#===============================================================================
|
||||
# Returns the number of Pokémon in the Day Care.
|
||||
def pbDayCareDeposited
|
||||
ret = 0
|
||||
for i in 0...2
|
||||
ret += 1 if $PokemonGlobal.daycare[i][0]
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
# Get name/cost info of a particular Pokémon in the Day Care.
|
||||
def pbDayCareGetDeposited(index,nameVariable,costVariable)
|
||||
pkmn = $PokemonGlobal.daycare[index][0]
|
||||
return false if !pkmn
|
||||
cost = pbDayCareGetCost(index)
|
||||
$game_variables[nameVariable] = pkmn.name if nameVariable>=0
|
||||
$game_variables[costVariable] = cost if costVariable>=0
|
||||
end
|
||||
|
||||
# Get name/levels gained info of a particular Pokémon in the Day Care.
|
||||
def pbDayCareGetLevelGain(index,nameVariable,levelVariable)
|
||||
pkmn = $PokemonGlobal.daycare[index][0]
|
||||
return false if !pkmn
|
||||
$game_variables[nameVariable] = pkmn.name
|
||||
$game_variables[levelVariable] = pkmn.level-$PokemonGlobal.daycare[index][1]
|
||||
return true
|
||||
end
|
||||
|
||||
def pbDayCareGetCost(index)
|
||||
pkmn = $PokemonGlobal.daycare[index][0]
|
||||
return 0 if !pkmn
|
||||
cost = pkmn.level-$PokemonGlobal.daycare[index][1]+1
|
||||
cost *= 100
|
||||
return cost
|
||||
end
|
||||
|
||||
# Returns whether an egg is waiting to be collected.
|
||||
def pbEggGenerated?
|
||||
return false if pbDayCareDeposited!=2
|
||||
return $PokemonGlobal.daycareEgg==1
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Manipulate Pokémon in the Day Care.
|
||||
#===============================================================================
|
||||
def pbDayCareDeposit(index)
|
||||
for i in 0...2
|
||||
next if $PokemonGlobal.daycare[i][0]
|
||||
$PokemonGlobal.daycare[i][0] = $Trainer.party[index]
|
||||
$PokemonGlobal.daycare[i][1] = $Trainer.party[index].level
|
||||
$PokemonGlobal.daycare[i][0].heal
|
||||
$Trainer.party[index] = nil
|
||||
$Trainer.party.compact!
|
||||
$PokemonGlobal.daycareEgg = 0
|
||||
$PokemonGlobal.daycareEggSteps = 0
|
||||
return
|
||||
end
|
||||
raise _INTL("No room to deposit a Pokémon")
|
||||
end
|
||||
|
||||
def pbDayCareWithdraw(index)
|
||||
if !$PokemonGlobal.daycare[index][0]
|
||||
raise _INTL("There's no Pokémon here...")
|
||||
elsif $Trainer.party_full?
|
||||
raise _INTL("Can't store the Pokémon...")
|
||||
else
|
||||
$Trainer.party[$Trainer.party.length] = $PokemonGlobal.daycare[index][0]
|
||||
$PokemonGlobal.daycare[index][0] = nil
|
||||
$PokemonGlobal.daycare[index][1] = 0
|
||||
$PokemonGlobal.daycareEgg = 0
|
||||
end
|
||||
end
|
||||
|
||||
def pbDayCareChoose(text,variable)
|
||||
count = pbDayCareDeposited
|
||||
if count==0
|
||||
raise _INTL("There's no Pokémon here...")
|
||||
elsif count==1
|
||||
$game_variables[variable] = ($PokemonGlobal.daycare[0][0]) ? 0 : 1
|
||||
else
|
||||
choices = []
|
||||
for i in 0...2
|
||||
pokemon = $PokemonGlobal.daycare[i][0]
|
||||
if pokemon.male?
|
||||
choices.push(_ISPRINTF("{1:s} (♂, Lv.{2:d})",pokemon.name,pokemon.level))
|
||||
elsif pokemon.female?
|
||||
choices.push(_ISPRINTF("{1:s} (♀, Lv.{2:d})",pokemon.name,pokemon.level))
|
||||
else
|
||||
choices.push(_ISPRINTF("{1:s} (Lv.{2:d})",pokemon.name,pokemon.level))
|
||||
end
|
||||
end
|
||||
choices.push(_INTL("CANCEL"))
|
||||
command = pbMessage(text,choices,choices.length)
|
||||
$game_variables[variable] = (command==2) ? -1 : command
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Check compatibility of Pokémon in the Day Care.
|
||||
#===============================================================================
|
||||
def pbIsDitto?(pkmn)
|
||||
return pkmn.species_data.egg_groups.include?(:Ditto)
|
||||
end
|
||||
|
||||
def pbDayCareCompatibleGender(pkmn1, pkmn2)
|
||||
return true if pkmn1.female? && pkmn2.male?
|
||||
return true if pkmn1.male? && pkmn2.female?
|
||||
ditto1 = pbIsDitto?(pkmn1)
|
||||
ditto2 = pbIsDitto?(pkmn2)
|
||||
return true if ditto1 && !ditto2
|
||||
return true if ditto2 && !ditto1
|
||||
return false
|
||||
end
|
||||
|
||||
def pbDayCareGetCompat
|
||||
return 0 if pbDayCareDeposited != 2
|
||||
pkmn1 = $PokemonGlobal.daycare[0][0]
|
||||
pkmn2 = $PokemonGlobal.daycare[1][0]
|
||||
# Shadow Pokémon cannot breed
|
||||
return 0 if pkmn1.shadowPokemon? || pkmn2.shadowPokemon?
|
||||
# Pokémon in the Undiscovered egg group cannot breed
|
||||
egg_groups1 = pkmn1.species_data.egg_groups
|
||||
egg_groups2 = pkmn2.species_data.egg_groups
|
||||
return 0 if egg_groups1.include?(:Undiscovered) ||
|
||||
egg_groups2.include?(:Undiscovered)
|
||||
# Pokémon that don't share an egg group (and neither is in the Ditto group)
|
||||
# cannot breed
|
||||
return 0 if !egg_groups1.include?(:Ditto) &&
|
||||
!egg_groups2.include?(:Ditto) &&
|
||||
(egg_groups1 & egg_groups2).length == 0
|
||||
# Pokémon with incompatible genders cannot breed
|
||||
return 0 if !pbDayCareCompatibleGender(pkmn1, pkmn2)
|
||||
# Pokémon can breed; calculate a compatibility factor
|
||||
ret = 1
|
||||
ret += 1 if pkmn1.species == pkmn2.species
|
||||
ret += 1 if pkmn1.owner.id != pkmn2.owner.id
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbDayCareGetCompatibility(variable)
|
||||
$game_variables[variable] = pbDayCareGetCompat
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Generate an Egg based on Pokémon in the Day Care.
|
||||
#===============================================================================
|
||||
def pbDayCareGenerateEgg
|
||||
return if pbDayCareDeposited != 2
|
||||
raise _INTL("Can't store the egg.") if $Trainer.party_full?
|
||||
pkmn0 = $PokemonGlobal.daycare[0][0]
|
||||
pkmn1 = $PokemonGlobal.daycare[1][0]
|
||||
mother = nil
|
||||
father = nil
|
||||
babyspecies = nil
|
||||
ditto0 = pbIsDitto?(pkmn0)
|
||||
ditto1 = pbIsDitto?(pkmn1)
|
||||
if pkmn0.female? || ditto0
|
||||
mother = pkmn0
|
||||
father = pkmn1
|
||||
babyspecies = (ditto0) ? father.species : mother.species
|
||||
else
|
||||
mother = pkmn1
|
||||
father = pkmn0
|
||||
babyspecies = (ditto1) ? father.species : mother.species
|
||||
end
|
||||
# Determine the egg's species
|
||||
babyspecies = GameData::Species.get(babyspecies).get_baby_species(true, mother.item_id, father.item_id)
|
||||
case babyspecies
|
||||
when :MANAPHY
|
||||
babyspecies = :PHIONE if GameData::Species.exists?(:PHIONE)
|
||||
when :NIDORANfE, :NIDORANmA
|
||||
if GameData::Species.exists?(:NIDORANfE) && GameData::Species.exists?(:NIDORANmA)
|
||||
babyspecies = [:NIDORANfE, :NIDORANmA][rand(2)]
|
||||
end
|
||||
when :VOLBEAT, :ILLUMISE
|
||||
if GameData::Species.exists?(:VOLBEAT) && GameData::Species.exists?(:ILLUMISE)
|
||||
babyspecies = [:VOLBEAT, :ILLUMISE][rand(2)]
|
||||
end
|
||||
end
|
||||
# Generate egg
|
||||
egg = Pokemon.new(babyspecies, Settings::EGG_LEVEL)
|
||||
# Randomise personal ID
|
||||
pid = rand(65536)
|
||||
pid |= (rand(65536)<<16)
|
||||
egg.personalID = pid
|
||||
# Inheriting form
|
||||
if [:BURMY, :SHELLOS, :BASCULIN, :FLABEBE, :PUMPKABOO, :ORICORIO, :ROCKRUFF, :MINIOR].include?(babyspecies)
|
||||
newForm = mother.form
|
||||
newForm = 0 if mother.isSpecies?(:MOTHIM)
|
||||
egg.form = newForm
|
||||
end
|
||||
# Inheriting Alolan form
|
||||
if [:RATTATA, :SANDSHREW, :VULPIX, :DIGLETT, :MEOWTH, :GEODUDE, :GRIMER].include?(babyspecies)
|
||||
if mother.form==1
|
||||
egg.form = 1 if mother.hasItem?(:EVERSTONE)
|
||||
elsif father.species_data.get_baby_species(true, mother.item_id, father.item_id) == babyspecies
|
||||
egg.form = 1 if father.form==1 && father.hasItem?(:EVERSTONE)
|
||||
end
|
||||
end
|
||||
# Inheriting Moves
|
||||
moves = []
|
||||
othermoves = []
|
||||
movefather = father
|
||||
movemother = mother
|
||||
if pbIsDitto?(movefather) && !mother.female?
|
||||
movefather = mother
|
||||
movemother = father
|
||||
end
|
||||
# Initial Moves
|
||||
initialmoves = egg.getMoveList
|
||||
for k in initialmoves
|
||||
if k[0] <= Settings::EGG_LEVEL
|
||||
moves.push(k[1])
|
||||
elsif mother.hasMove?(k[1]) && father.hasMove?(k[1])
|
||||
othermoves.push(k[1])
|
||||
end
|
||||
end
|
||||
# Inheriting Natural Moves
|
||||
for move in othermoves
|
||||
moves.push(move)
|
||||
end
|
||||
# Inheriting Machine Moves
|
||||
if Settings::BREEDING_CAN_INHERIT_MACHINE_MOVES
|
||||
GameData::Item.each do |i|
|
||||
atk = i.move
|
||||
next if !atk
|
||||
next if !egg.compatible_with_move?(atk)
|
||||
next if !movefather.hasMove?(atk)
|
||||
moves.push(atk)
|
||||
end
|
||||
end
|
||||
# Inheriting Egg Moves
|
||||
babyEggMoves = egg.species_data.egg_moves
|
||||
if movefather.male?
|
||||
babyEggMoves.each { |m| moves.push(m) if movefather.hasMove?(m) }
|
||||
end
|
||||
if Settings::BREEDING_CAN_INHERIT_EGG_MOVES_FROM_MOTHER
|
||||
babyEggMoves.each { |m| moves.push(m) if movemother.hasMove?(m) }
|
||||
end
|
||||
# Volt Tackle
|
||||
lightball = false
|
||||
if (father.isSpecies?(:PIKACHU) || father.isSpecies?(:RAICHU)) &&
|
||||
father.hasItem?(:LIGHTBALL)
|
||||
lightball = true
|
||||
end
|
||||
if (mother.isSpecies?(:PIKACHU) || mother.isSpecies?(:RAICHU)) &&
|
||||
mother.hasItem?(:LIGHTBALL)
|
||||
lightball = true
|
||||
end
|
||||
if lightball && babyspecies == :PICHU && GameData::Move.exists?(:VOLTTACKLE)
|
||||
moves.push(:VOLTTACKLE)
|
||||
end
|
||||
moves = moves.reverse
|
||||
moves |= [] # remove duplicates
|
||||
moves = moves.reverse
|
||||
# Assembling move list
|
||||
first_move_index = moves.length - Pokemon::MAX_MOVES
|
||||
first_move_index = 0 if first_move_index < 0
|
||||
finalmoves = []
|
||||
for i in first_move_index...moves.length
|
||||
finalmoves.push(Pokemon::Move.new(moves[i]))
|
||||
end
|
||||
# Inheriting Individual Values
|
||||
ivs = {}
|
||||
GameData::Stat.each_main { |s| ivs[s.id] = rand(Pokemon::IV_STAT_LIMIT + 1) }
|
||||
ivinherit = []
|
||||
for i in 0...2
|
||||
parent = [mother,father][i]
|
||||
ivinherit[i] = :HP if parent.hasItem?(:POWERWEIGHT)
|
||||
ivinherit[i] = :ATTACK if parent.hasItem?(:POWERBRACER)
|
||||
ivinherit[i] = :DEFENSE if parent.hasItem?(:POWERBELT)
|
||||
ivinherit[i] = :SPECIAL_ATTACK if parent.hasItem?(:POWERLENS)
|
||||
ivinherit[i] = :SPECIAL_DEFENSE if parent.hasItem?(:POWERBAND)
|
||||
ivinherit[i] = :SPEED if parent.hasItem?(:POWERANKLET)
|
||||
end
|
||||
num = 0
|
||||
r = rand(2)
|
||||
2.times do
|
||||
if ivinherit[r]!=nil
|
||||
parent = [mother,father][r]
|
||||
ivs[ivinherit[r]] = parent.iv[ivinherit[r]]
|
||||
num += 1
|
||||
break
|
||||
end
|
||||
r = (r+1)%2
|
||||
end
|
||||
limit = (mother.hasItem?(:DESTINYKNOT) || father.hasItem?(:DESTINYKNOT)) ? 5 : 3
|
||||
loop do
|
||||
freestats = []
|
||||
GameData::Stat.each_main { |s| freestats.push(s.id) if !ivinherit.include?(s.id) }
|
||||
break if freestats.length==0
|
||||
r = freestats[rand(freestats.length)]
|
||||
parent = [mother,father][rand(2)]
|
||||
ivs[r] = parent.iv[r]
|
||||
ivinherit.push(r)
|
||||
num += 1
|
||||
break if num>=limit
|
||||
end
|
||||
# Inheriting nature
|
||||
new_natures = []
|
||||
new_natures.push(mother.nature) if mother.hasItem?(:EVERSTONE)
|
||||
new_natures.push(father.nature) if father.hasItem?(:EVERSTONE)
|
||||
if new_natures.length > 0
|
||||
new_nature = (new_natures.length == 1) ? new_natures[0] : new_natures[rand(new_natures.length)]
|
||||
egg.nature = new_nature
|
||||
end
|
||||
# Masuda method and Shiny Charm
|
||||
shinyretries = 0
|
||||
shinyretries += 5 if father.owner.language != mother.owner.language
|
||||
shinyretries += 2 if GameData::Item.exists?(:SHINYCHARM) && $PokemonBag.pbHasItem?(:SHINYCHARM)
|
||||
if shinyretries>0
|
||||
shinyretries.times do
|
||||
break if egg.shiny?
|
||||
egg.personalID = rand(2**16) | rand(2**16) << 16
|
||||
end
|
||||
end
|
||||
# Inheriting ability from the mother
|
||||
if !ditto0 || !ditto1
|
||||
parent = (ditto0) ? father : mother # The non-Ditto
|
||||
if parent.hasHiddenAbility?
|
||||
egg.ability_index = parent.ability_index if rand(100) < 60
|
||||
elsif !ditto0 && !ditto1
|
||||
if rand(100) < 80
|
||||
egg.ability_index = mother.ability_index
|
||||
else
|
||||
egg.ability_index = (mother.ability_index + 1) % 2
|
||||
end
|
||||
end
|
||||
end
|
||||
# Inheriting Poké Ball from the mother (or father if it's same species as mother)
|
||||
if !ditto0 || !ditto1
|
||||
possible_balls = []
|
||||
if mother.species == father.species
|
||||
possible_balls.push(mother.poke_ball)
|
||||
possible_balls.push(father.poke_ball)
|
||||
else
|
||||
possible_balls.push(pkmn0.poke_ball) if pkmn0.female? || ditto1
|
||||
possible_balls.push(pkmn1.poke_ball) if pkmn1.female? || ditto0
|
||||
end
|
||||
possible_balls.delete(:MASTERBALL) # Can't inherit this Ball
|
||||
possible_balls.delete(:CHERISHBALL) # Can't inherit this Ball
|
||||
if possible_balls.length > 0
|
||||
egg.poke_ball = possible_balls[0]
|
||||
egg.poke_ball = possible_balls[rand(possible_balls.length)] if possible_balls.length > 1
|
||||
end
|
||||
end
|
||||
# Set all stats
|
||||
egg.happiness = 120
|
||||
egg.iv = ivs
|
||||
egg.moves = finalmoves
|
||||
egg.calc_stats
|
||||
egg.obtain_text = _INTL("Day-Care Couple")
|
||||
egg.name = _INTL("Egg")
|
||||
egg.steps_to_hatch = egg.species_data.hatch_steps
|
||||
egg.givePokerus if rand(65536) < Settings::POKERUS_CHANCE
|
||||
# Add egg to party
|
||||
$Trainer.party[$Trainer.party.length] = egg
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Code that happens every step the player takes.
|
||||
#===============================================================================
|
||||
Events.onStepTaken += proc { |_sender,_e|
|
||||
# Make an egg available at the Day Care
|
||||
deposited = pbDayCareDeposited
|
||||
if deposited==2 && $PokemonGlobal.daycareEgg==0
|
||||
$PokemonGlobal.daycareEggSteps = 0 if !$PokemonGlobal.daycareEggSteps
|
||||
$PokemonGlobal.daycareEggSteps += 1
|
||||
if $PokemonGlobal.daycareEggSteps==256
|
||||
$PokemonGlobal.daycareEggSteps = 0
|
||||
compatval = [0,20,50,70][pbDayCareGetCompat]
|
||||
if GameData::Item.exists?(:OVALCHARM) && $PokemonBag.pbHasItem?(:OVALCHARM)
|
||||
compatval = [0,40,80,88][pbDayCareGetCompat]
|
||||
end
|
||||
$PokemonGlobal.daycareEgg = 1 if rand(100)<compatval # Egg is generated
|
||||
end
|
||||
end
|
||||
# Day Care Pokémon gain Exp/moves
|
||||
for i in 0...2
|
||||
pkmn = $PokemonGlobal.daycare[i][0]
|
||||
next if !pkmn
|
||||
maxexp = pkmn.growth_rate.maximum_exp
|
||||
next if pkmn.exp>=maxexp
|
||||
oldlevel = pkmn.level
|
||||
pkmn.exp += 1 # Gain Exp
|
||||
next if pkmn.level==oldlevel
|
||||
pkmn.calc_stats
|
||||
movelist = pkmn.getMoveList
|
||||
for i in movelist
|
||||
pkmn.learn_move(i[1]) if i[0]==pkmn.level # Learned a new move
|
||||
end
|
||||
end
|
||||
}
|
||||
@@ -1,669 +0,0 @@
|
||||
#===============================================================================
|
||||
# Code that generates a random dungeon layout, and implements it in a given map.
|
||||
#===============================================================================
|
||||
module RandomDungeonGenerator
|
||||
#=============================================================================
|
||||
# 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
|
||||
|
||||
#=============================================================================
|
||||
# Contains constants that define what types of tiles a random dungeon map can
|
||||
# consist of, and helper methods that translate those tiles into data usable
|
||||
# by a map/printable to the console (for debug purposes).
|
||||
#=============================================================================
|
||||
module DungeonTile
|
||||
VOID = 0
|
||||
ROOM = 1
|
||||
WALL = 2
|
||||
CORRIDOR = 3
|
||||
# Which autotile each type of tile uses (1-7)
|
||||
TILE_IDS = {
|
||||
VOID => 1,
|
||||
ROOM => 2,
|
||||
WALL => 3,
|
||||
CORRIDOR => 2
|
||||
}
|
||||
# Used for debugging when printing out an ASCII image of the dungeon
|
||||
TEXT_SYMBOLS = {
|
||||
VOID => "#",
|
||||
ROOM => " ",
|
||||
WALL => "-",
|
||||
CORRIDOR => "."
|
||||
}
|
||||
|
||||
module_function
|
||||
|
||||
def to_tile_id(value)
|
||||
return TILE_IDS[value] || TILE_IDS[VOID]
|
||||
end
|
||||
|
||||
def to_text(value)
|
||||
return TEXT_SYMBOLS[value] || TEXT_SYMBOLS[VOID]
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Helper functions that set tiles in the map to a particular type.
|
||||
#=============================================================================
|
||||
module DungeonMaze
|
||||
CELL_WIDTH = 13 # Should be at least 7
|
||||
CELL_HEIGHT = 13 # Should be at least 7
|
||||
ROOM_MIN_WIDTH = 5
|
||||
ROOM_MAX_WIDTH = CELL_WIDTH - 2 # Should be at most CELL_WIDTH - 2
|
||||
ROOM_MIN_HEIGHT = 4
|
||||
ROOM_MAX_HEIGHT = CELL_HEIGHT - 3 # Should be at most CELL_HEIGHT - 3
|
||||
CORRIDOR_WIDTH = 3
|
||||
None = 0
|
||||
TurnLeft = 1
|
||||
TurnRight = 2
|
||||
Turn180 = 3
|
||||
@@corridor_layouts = nil
|
||||
|
||||
module_function
|
||||
|
||||
# Generates sets of tiles depicting corridors coming out of a room, for all
|
||||
# combinations of the sides that they can come out of.
|
||||
def generate_corridor_patterns
|
||||
if !@@corridor_layouts
|
||||
tiles = []
|
||||
x_offset = (CELL_WIDTH - CORRIDOR_WIDTH) / 2
|
||||
y_offset = (CELL_HEIGHT - CORRIDOR_WIDTH) / 2
|
||||
for combo in 0...16
|
||||
tiles[combo] = []
|
||||
for i in 0...CELL_WIDTH * CELL_HEIGHT
|
||||
tiles[combo][i] = DungeonTile::VOID
|
||||
end
|
||||
if (combo & EdgeMasks::North) == 0
|
||||
paint_corridor(tiles[combo], x_offset, 0, CORRIDOR_WIDTH, y_offset + CORRIDOR_WIDTH)
|
||||
end
|
||||
if (combo & EdgeMasks::South) == 0
|
||||
paint_corridor(tiles[combo], x_offset, y_offset, CORRIDOR_WIDTH, CELL_HEIGHT - y_offset)
|
||||
end
|
||||
if (combo & EdgeMasks::East) == 0
|
||||
paint_corridor(tiles[combo], x_offset, y_offset, CELL_WIDTH - x_offset, CORRIDOR_WIDTH)
|
||||
end
|
||||
if (combo & EdgeMasks::West) == 0
|
||||
paint_corridor(tiles[combo], 0, y_offset, x_offset + CORRIDOR_WIDTH, CORRIDOR_WIDTH)
|
||||
end
|
||||
end
|
||||
@@corridor_layouts = tiles
|
||||
end
|
||||
return @@corridor_layouts
|
||||
end
|
||||
|
||||
# Makes all tiles in a particular area corridor tiles.
|
||||
def paint_corridor(tile, x, y, width, height)
|
||||
for j in 0...height
|
||||
for i in 0...width
|
||||
tile[(y + j) * CELL_WIDTH + (x + i)] = DungeonTile::CORRIDOR
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Used to draw tiles from the given tile_layout and rotation (for corridors).
|
||||
def paint_tile_layout(dungeon, dstX, dstY, tile_layout, rotation)
|
||||
case rotation
|
||||
when None
|
||||
for y in 0...CELL_HEIGHT
|
||||
for x in 0...CELL_WIDTH
|
||||
dungeon[x + dstX, y + dstY] = tile_layout[y * CELL_WIDTH + x]
|
||||
end
|
||||
end
|
||||
when TurnLeft
|
||||
for y in 0...CELL_HEIGHT
|
||||
for x in 0...CELL_WIDTH
|
||||
dungeon[y + dstX , CELL_WIDTH - 1 - x + dstY] = tile_layout[y * CELL_WIDTH + x]
|
||||
end
|
||||
end
|
||||
when TurnRight
|
||||
for y in 0...CELL_HEIGHT
|
||||
for x in 0...CELL_WIDTH
|
||||
dungeon[CELL_HEIGHT - 1 - y + dstX, x + dstY] = tile_layout[y * CELL_WIDTH + x]
|
||||
end
|
||||
end
|
||||
when Turn180
|
||||
for y in 0...CELL_HEIGHT
|
||||
for x in 0...CELL_WIDTH
|
||||
dungeon[CELL_WIDTH - 1 - x + dstX, CELL_HEIGHT - 1 - y + dstY] = tile_layout[y * CELL_WIDTH + x]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Draws a cell's contents, which is an underlying pattern based on tile
|
||||
#_layout and a rotation (the corridors), and possibly a room on top of that.
|
||||
def paint_cell_contents(dungeon, xDst, yDst, tile_layout, rotation)
|
||||
return false if !tile_layout
|
||||
# Draw the corridors
|
||||
paint_tile_layout(dungeon, xDst, yDst, tile_layout, rotation)
|
||||
return false if rand(100) < 30
|
||||
# Generate a randomly placed room
|
||||
width = rand(ROOM_MIN_WIDTH..ROOM_MAX_WIDTH)
|
||||
height = rand(ROOM_MIN_HEIGHT..ROOM_MAX_HEIGHT)
|
||||
return false if width <= 0 || height <= 0
|
||||
centerX = CELL_WIDTH / 2 + rand(5) - 2
|
||||
centerY = CELL_HEIGHT / 2 + rand(5) - 2
|
||||
x = centerX - (width / 2)
|
||||
y = centerY - (height / 2)
|
||||
rect = [x, y, width, height]
|
||||
rect[0] = rect[0].clamp(1, CELL_WIDTH - 1 - width)
|
||||
rect[1] = rect[1].clamp(2, CELL_HEIGHT - 1 - height) # 2 because walls are 2 tiles tall
|
||||
dungeon.paint_room(rect, xDst, yDst)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Bitwise values used to keep track of the generation of node connections.
|
||||
#=============================================================================
|
||||
module EdgeMasks
|
||||
North = 1
|
||||
West = 2
|
||||
East = 4
|
||||
South = 8
|
||||
Visited = 16
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# A node in a randomly generated dungeon. There is one node per cell, and
|
||||
# nodes are connected to each other.
|
||||
#=============================================================================
|
||||
class MazeNode
|
||||
def initialize
|
||||
@edges = 0
|
||||
end
|
||||
|
||||
def setEdge(e); @edges |= e; end
|
||||
def clearEdge(e); @edges &= ~e; end
|
||||
def clear; @edges = 0; end
|
||||
def set; @edges = 15; end
|
||||
def getEdge(e); return (@edges & e) != 0; end
|
||||
def isBlocked?; return @edges != 0; end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Vector class representing the location of a node.
|
||||
#=============================================================================
|
||||
class NodeListElement
|
||||
attr_accessor :x, :y
|
||||
|
||||
def initialize(x, y)
|
||||
@x = x
|
||||
@y = y
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Maze generator. Given the number of cells horizontally and vertically in a
|
||||
# map, connects all the cells together.
|
||||
# A node is the boundary between two adjacent cells, which may or may not be a
|
||||
# connection.
|
||||
#=============================================================================
|
||||
class Maze
|
||||
attr_accessor :cellWidth, :cellHeight, :nodeWidth, :nodeHeight
|
||||
DIRECTIONS = [EdgeMasks::North, EdgeMasks::South, EdgeMasks::East, EdgeMasks::West]
|
||||
|
||||
def initialize(cw, ch)
|
||||
raise ArgumentError.new if cw == 0 || ch == 0
|
||||
@cellWidth = cw
|
||||
@cellHeight = ch
|
||||
@nodeWidth = cw + 1
|
||||
@nodeHeight = ch + 1
|
||||
@cells = []
|
||||
clearAllCells
|
||||
@nodes = Array.new(@nodeWidth * @nodeHeight) { MazeNode.new }
|
||||
end
|
||||
|
||||
def randomDir
|
||||
return DIRECTIONS[rand(4)]
|
||||
end
|
||||
|
||||
def getVisited(x, y)
|
||||
return false if x < 0 || y < 0 || x >= cellWidth || x >= cellHeight
|
||||
return (@cells[y * cellWidth + x] & EdgeMasks::Visited) != 0
|
||||
end
|
||||
|
||||
def setVisited(x, y)
|
||||
return if x < 0 || y < 0 || x >= cellWidth || x >= cellHeight
|
||||
@cells[y * cellWidth + x] |= EdgeMasks::Visited
|
||||
end
|
||||
|
||||
def clearVisited(x, y)
|
||||
return if x < 0 || y < 0 || x >= cellWidth || x >= cellHeight
|
||||
@cells[y * cellWidth + x] &=~EdgeMasks::Visited
|
||||
end
|
||||
|
||||
def clearAllCells
|
||||
for c in 0...cellWidth * cellHeight
|
||||
@cells[c] = 0
|
||||
end
|
||||
end
|
||||
|
||||
def getEdgeNode(x, y, edge)
|
||||
return false if x < 0 || y < 0 || x >= nodeWidth || y >= nodeHeight
|
||||
return @nodes[y * nodeWidth + x].getEdge(edge)
|
||||
end
|
||||
|
||||
def setEdgeNode(x, y, edge)
|
||||
return if x < 0 || x >= nodeWidth || y < 0 || y >= nodeHeight
|
||||
@nodes[y * nodeWidth + x].setEdge(edge)
|
||||
e = 0
|
||||
nx = x
|
||||
ny = y
|
||||
case edge
|
||||
when EdgeMasks::North
|
||||
e = EdgeMasks::South
|
||||
ny = y - 1
|
||||
when EdgeMasks::South
|
||||
e = EdgeMasks::North
|
||||
ny = y + 1
|
||||
when EdgeMasks::East
|
||||
e = EdgeMasks::West
|
||||
nx = x + 1
|
||||
when EdgeMasks::West
|
||||
e = EdgeMasks::East
|
||||
nx = x - 1
|
||||
else
|
||||
return
|
||||
end
|
||||
return if nx < 0 || ny < 0 || nx >= nodeWidth || ny >= nodeHeight
|
||||
@nodes[ny * nodeWidth + nx].setEdge(e)
|
||||
end
|
||||
|
||||
def setAllEdges
|
||||
for c in 0...nodeWidth * nodeHeight
|
||||
@nodes[c].set
|
||||
end
|
||||
end
|
||||
|
||||
def clearEdgeNode(x, y, edge)
|
||||
return if x < 0 || x >= nodeWidth || y < 0 || y >= nodeHeight
|
||||
@nodes[y * nodeWidth + x].clearEdge(edge)
|
||||
e = 0
|
||||
nx = x
|
||||
ny = y
|
||||
case edge
|
||||
when EdgeMasks::North
|
||||
e = EdgeMasks::South
|
||||
ny -= 1
|
||||
when EdgeMasks::South
|
||||
e = EdgeMasks::North
|
||||
ny += 1
|
||||
when EdgeMasks::East
|
||||
e = EdgeMasks::West
|
||||
nx += 1
|
||||
when EdgeMasks::West
|
||||
e = EdgeMasks::East
|
||||
nx -= 1
|
||||
else
|
||||
raise ArgumentError.new
|
||||
end
|
||||
return if nx < 0 || ny < 0 || nx >= nodeWidth || ny >= nodeHeight
|
||||
@nodes[ny * nodeWidth + nx].clearEdge(e)
|
||||
end
|
||||
|
||||
def clearAllEdges
|
||||
for c in 0...nodeWidth * nodeHeight
|
||||
@nodes[c].clear
|
||||
end
|
||||
end
|
||||
|
||||
def isBlockedNode?(x, y)
|
||||
return false if x < 0 || y < 0 || x >= nodeWidth || y >= nodeHeight
|
||||
return @nodes[y * nodeWidth + x].isBlocked?
|
||||
end
|
||||
|
||||
def getEdgePattern(x, y)
|
||||
pattern = 0
|
||||
pattern |= EdgeMasks::North if getEdgeNode(x, y, EdgeMasks::North)
|
||||
pattern |= EdgeMasks::South if getEdgeNode(x, y, EdgeMasks::South)
|
||||
pattern |= EdgeMasks::East if getEdgeNode(x, y, EdgeMasks::East)
|
||||
pattern |= EdgeMasks::West if getEdgeNode(x, y, EdgeMasks::West)
|
||||
return pattern
|
||||
end
|
||||
|
||||
def buildMazeWall(x, y, dir, len)
|
||||
return if isBlockedNode?(x, y)
|
||||
wx = x
|
||||
wy = y
|
||||
len.times do
|
||||
ox = wx
|
||||
oy = wy
|
||||
case dir
|
||||
when EdgeMasks::North
|
||||
wy -= 1
|
||||
when EdgeMasks::West
|
||||
wx -= 1
|
||||
when EdgeMasks::East
|
||||
wx += 1
|
||||
when EdgeMasks::South
|
||||
wy += 1
|
||||
end
|
||||
if isBlockedNode?(wx, wy)
|
||||
setEdgeNode(ox, oy, dir)
|
||||
return
|
||||
end
|
||||
setEdgeNode(ox,oy,dir)
|
||||
end
|
||||
end
|
||||
|
||||
def buildNodeList
|
||||
list = []
|
||||
for x in 0...nodeWidth
|
||||
for y in 0...nodeHeight
|
||||
list.push(NodeListElement.new(x, y))
|
||||
end
|
||||
end
|
||||
list.shuffle!
|
||||
return list
|
||||
end
|
||||
|
||||
def generateWallGrowthMaze(minWall = 0, maxWall = nil)
|
||||
maxWall = cellWidth if !maxWall
|
||||
nlist = buildNodeList()
|
||||
return if nlist.length == 0
|
||||
for c in 0...nlist.length
|
||||
d = randomDir()
|
||||
len = rand(maxWall + 1)
|
||||
x = nlist[c].x
|
||||
y = nlist[c].y
|
||||
buildMazeWall(x, y, d, len)
|
||||
end
|
||||
end
|
||||
|
||||
def recurseDepthFirst(x, y, depth)
|
||||
setVisited(x, y)
|
||||
dirs = DIRECTIONS.shuffle
|
||||
for c in 0...4
|
||||
d = dirs[c]
|
||||
cx = x
|
||||
cy = y
|
||||
case d
|
||||
when EdgeMasks::North
|
||||
cy -= 1
|
||||
when EdgeMasks::South
|
||||
cy += 1
|
||||
when EdgeMasks::East
|
||||
cx += 1
|
||||
when EdgeMasks::West
|
||||
cx -= 1
|
||||
end
|
||||
if cx >= 0 && cy >= 0 && cx < cellWidth && cy < cellHeight
|
||||
if !getVisited(cx, cy)
|
||||
clearEdgeNode(x, y, d)
|
||||
recurseDepthFirst(cx, cy, depth + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def generateDepthFirstMaze
|
||||
# Pick a cell to start in
|
||||
sx = rand(cellWidth)
|
||||
sy = rand(cellHeight)
|
||||
# Set up all nodes
|
||||
setAllEdges
|
||||
# Generate a maze
|
||||
recurseDepthFirst(sx, sy, 0)
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Random dungeon generator class. Calls class Maze to generate the abstract
|
||||
# layout of the dungeon, and turns that into usable map data.
|
||||
#=============================================================================
|
||||
class Dungeon
|
||||
class DungeonTable
|
||||
def initialize(dungeon)
|
||||
@dungeon = dungeon
|
||||
end
|
||||
|
||||
def xsize; @dungeon.width; end
|
||||
def ysize; @dungeon.height; end
|
||||
|
||||
# Returns which tile in the tileset corresponds to the type of tile is at
|
||||
# the given coordinates
|
||||
def [](x, y)
|
||||
return DungeonTile.to_tile_id(@dungeon[x, y])
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :width, :height
|
||||
BUFFER_X = 8
|
||||
BUFFER_Y = 6
|
||||
|
||||
def initialize(width, height)
|
||||
@width = width
|
||||
@height = height
|
||||
@array = []
|
||||
end
|
||||
|
||||
def clear
|
||||
for i in 0...width * height
|
||||
@array[i] = DungeonTile::VOID
|
||||
end
|
||||
end
|
||||
|
||||
def write
|
||||
ret = ""
|
||||
i = 0
|
||||
for y in 0...@height
|
||||
for x in 0...@width
|
||||
ret += DungeonTile.to_text(value(x, y))
|
||||
i += 1
|
||||
end
|
||||
ret += "\r\n"
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def [](x, y)
|
||||
return @array[y * @width + x]
|
||||
end
|
||||
|
||||
def []=(x, y, value)
|
||||
@array[y * @width + x] = value
|
||||
end
|
||||
|
||||
def value(x, y)
|
||||
return DungeonTile::VOID if x < 0 || y < 0 || x >= @width || y >= @height
|
||||
return @array[y * @width + x]
|
||||
end
|
||||
|
||||
# Unused
|
||||
def get(x, y)
|
||||
return false if x < 0 || y < 0 || x >= @width || y >= @height
|
||||
return @array[y * @width + x] != DungeonTile::VOID
|
||||
end
|
||||
|
||||
# Unused
|
||||
def intersects?(r1, r2)
|
||||
return !(((r2[0] + r2[2] <= r1[0]) ||
|
||||
(r2[0] >= r1[0] + r1[2]) ||
|
||||
(r2[1] + r2[3] <= r1[1]) ||
|
||||
(r2[1] >= r1[1] + r1[3])) &&
|
||||
((r1[0] <= r2[0] + r2[2])||
|
||||
(r1[0] >= r2[0] + r2[2]) ||
|
||||
(r1[1] + r1[3] <= r2[1]) ||
|
||||
(r1[1] >= r2[1] + r2[3]))
|
||||
)
|
||||
end
|
||||
|
||||
# Returns whether the given coordinates are a room floor that isn't too close
|
||||
# to a corridor
|
||||
def isRoom?(x, y)
|
||||
if value(x, y) == DungeonTile::ROOM
|
||||
return false if value(x - 1, y - 1) == DungeonTile::CORRIDOR
|
||||
return false if value( x, y - 1) == DungeonTile::CORRIDOR
|
||||
return false if value(x + 1, y - 1) == DungeonTile::CORRIDOR
|
||||
return false if value(x - 1, y) == DungeonTile::CORRIDOR
|
||||
return false if value(x + 1, y) == DungeonTile::CORRIDOR
|
||||
return false if value(x - 1, y + 1) == DungeonTile::CORRIDOR
|
||||
return false if value( x, y + 1) == DungeonTile::CORRIDOR
|
||||
return false if value(x + 1, y + 1) == DungeonTile::CORRIDOR
|
||||
return true # No surrounding tiles are corridor floor
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def isWall?(x, y)
|
||||
if value(x, y) == DungeonTile::VOID
|
||||
v1 = value(x, y + 1)
|
||||
return true if v1 == DungeonTile::ROOM || v1 == DungeonTile::CORRIDOR
|
||||
if v1 == DungeonTile::VOID # The tile below is void
|
||||
v1 = value(x, y + 2)
|
||||
return true if v1 == DungeonTile::ROOM || v1 == DungeonTile::CORRIDOR
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def paint_room(rect,offsetX,offsetY)
|
||||
for y in (rect[1] + offsetY)...(rect[1] + offsetY + rect[3])
|
||||
for x in (rect[0] + offsetX)...(rect[0] + offsetX + rect[2])
|
||||
self[x, y] = DungeonTile::ROOM
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def generate
|
||||
self.clear
|
||||
maxWidth = @width - BUFFER_X * 2
|
||||
maxHeight = @height - BUFFER_Y * 2
|
||||
cellWidth = DungeonMaze::CELL_WIDTH
|
||||
cellHeight = DungeonMaze::CELL_HEIGHT
|
||||
return if maxWidth < 0 || maxHeight < 0
|
||||
if maxWidth < cellWidth || maxHeight < cellHeight # Map is too small
|
||||
for x in 0...maxWidth
|
||||
for y in 0...maxHeight
|
||||
self[x + BUFFER_X, y + BUFFER_Y] = DungeonTile::ROOM
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
# Generate connections between cells
|
||||
maze = Maze.new(maxWidth / cellWidth, maxHeight / cellHeight)
|
||||
maze.generateDepthFirstMaze()
|
||||
# Draw each cell's contents in turn (room and corridors)
|
||||
corridor_patterns = DungeonMaze.generate_corridor_patterns
|
||||
roomcount = 0
|
||||
for y in 0...maxHeight / cellHeight
|
||||
for x in 0...maxWidth / cellWidth
|
||||
pattern = maze.getEdgePattern(x, y)
|
||||
if DungeonMaze.paint_cell_contents(
|
||||
self, BUFFER_X + x * cellWidth, BUFFER_Y + y * cellHeight,
|
||||
corridor_patterns[pattern], DungeonMaze::None)
|
||||
roomcount += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
# If no rooms were generated, make the whole map a room
|
||||
if roomcount == 0
|
||||
for x in 0...maxWidth
|
||||
for y in 0...maxHeight
|
||||
self[x + BUFFER_X, y + BUFFER_Y] = DungeonTile::ROOM
|
||||
end
|
||||
end
|
||||
end
|
||||
# Generate walls
|
||||
for y in 0...@height
|
||||
for x in 0...@width
|
||||
self[x, y] = DungeonTile::WALL if isWall?(x, y) # Make appropriate tiles wall tiles
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Convert dungeon layout into proper map tiles
|
||||
def generateMapInPlace(map)
|
||||
tbl = DungeonTable.new(self)
|
||||
for i in 0...map.width
|
||||
for j in 0...map.height
|
||||
nb = TileDrawingHelper.tableNeighbors(tbl, i, j)
|
||||
tile = TileDrawingHelper::NEIGHBORS_TO_AUTOTILE_INDEX[nb]
|
||||
map.data[i, j, 0] = tile + 48 * (tbl[i, j])
|
||||
map.data[i, j, 1] = 0
|
||||
map.data[i, j, 2] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#
|
||||
#=============================================================================
|
||||
# Get a random room tile that isn't too close to a corridor (to avoid blocking
|
||||
# a room's entrance).
|
||||
def self.pbRandomRoomTile(dungeon, tiles)
|
||||
ar1 = AntiRandom.new(dungeon.width)
|
||||
ar2 = AntiRandom.new(dungeon.height)
|
||||
((tiles.length + 1) * 1000).times do
|
||||
x = ar1.get()
|
||||
y = ar2.get()
|
||||
if dungeon.isRoom?(x, y) &&
|
||||
!tiles.any? { |item| (item[0] - x).abs < 2 && (item[1] - y).abs < 2 }
|
||||
ret = [x, y]
|
||||
tiles.push(ret)
|
||||
return ret
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
# Test method that generates a dungeon map and prints it to the console.
|
||||
# @param x_cells [Integer] the number of cells wide the dungeon will be
|
||||
# @param y_cells [Intenger] the number of cells tall the dungeon will be
|
||||
def self.generate_test_dungeon(x_cells = 4, y_cells = 4)
|
||||
dungeon = Dungeon.new(Dungeon::BUFFER_X * 2 + DungeonMaze::CELL_WIDTH * x_cells,
|
||||
Dungeon::BUFFER_Y * 2 + DungeonMaze::CELL_HEIGHT * y_cells)
|
||||
dungeon.generate
|
||||
echoln dungeon.write
|
||||
end
|
||||
end
|
||||
|
||||
Events.onMapCreate += proc { |_sender, e|
|
||||
mapID = e[0]
|
||||
map = e[1]
|
||||
next if !GameData::MapMetadata.try_get(mapID)&.random_dungeon
|
||||
# this map is a randomly generated dungeon
|
||||
dungeon = RandomDungeonGenerator::Dungeon.new(map.width, map.height)
|
||||
dungeon.generate
|
||||
dungeon.generateMapInPlace(map)
|
||||
roomtiles = []
|
||||
# Reposition events
|
||||
for event in map.events.values
|
||||
tile = RandomDungeonGenerator.pbRandomRoomTile(dungeon, roomtiles)
|
||||
if tile
|
||||
event.x = tile[0]
|
||||
event.y = tile[1]
|
||||
end
|
||||
end
|
||||
# Override transfer X and Y
|
||||
tile = RandomDungeonGenerator.pbRandomRoomTile(dungeon, roomtiles)
|
||||
if tile
|
||||
$game_temp.player_new_x = tile[0]
|
||||
$game_temp.player_new_y = tile[1]
|
||||
end
|
||||
}
|
||||
Reference in New Issue
Block a user