#-------------------------------------------------------------------------------
# Phenomenon: Pokemon BW Style Grass Rustle, Water Drop, Cave Dust & Flying Bird
# v1.5 by Boonzeet
#-------------------------------------------------------------------------------
# Credit is required to use this script.
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Configuration
#-------------------------------------------------------------------------------
module PhenomenonConfig
Frequency = 10 # Chance for phenomenon to generate on step. Best between 350-600.
Timer = 1800 # How many frames to wait before phenomenon disappears
Switch = 56 # Switch # when set ON enables phenomena
Pokemon = {
:shiny => false, # 4x chance of shininess
:expBoost => false, # 1.3x Exp Boost
# Below are 1/n chance of Pokémon being generated with these settings
# Set to -1 to disable
:ivs => 10, # 2 perfect IVs
:eggMoves => -1, # A random egg move
:hiddenAbility => -1 # Generated with hidden ability
}
Types = {
# Animation ID, sound, animation height (1 above player 0 below), encounter type
:grass => [18, "phenomenon_grass", 1, EncounterTypes::PhenomenonGrass],
:water => [19, "phenomenon_water", 0, EncounterTypes::PhenomenonWater],
:cave => [20, "phenomenon_cave", 1, EncounterTypes::PhenomenonCave],
:bird => [21, "phenomenon_bird", 0, EncounterTypes::PhenomenonBird]
}
BattleMusic = "" # Custom music to play during Phenomenon
BirdTerrainTag = 18 # Terrain tag for Bird encounters. Important! This is
# to prevent encounters appearing in inaccessible spots
Items = {
# 80% chance of appearing in dust
:commonCave => [:FIREGEM, :WATERGEM, :ICEGEM, :ELECTRICGEM, :GRASSGEM, :FIGHTINGGEM,
:POISONGEM, :GROUNDGEM, :FLYINGGEM, :PSYCHICGEM, :BUGGEM, :ROCKGEM,
:GHOSTGEM, :DRAGONGEM, :DARKGEM, :STEELGEM, :NORMALGEM, :REDSHARD,
:BLUESHARD, :YELLOWSHARD, :GREENSHARD],
# 10% chance
:rareCave => [:THUNDERSTONE, :WATERSTONE, :LEAFSTONE, :MOONSTONE, :FIRESTONE,
:SUNSTONE, :SHINYSTONE, :DUSKSTONE, :DAWNSTONE, :EVERSTONE, :OVALSTONE],
:bird => [:HEALTHWING, :RESISTWING, :CLEVERWING, :PRETTYWING, :MUSCLEWING, :GENIUSWING, :SWIFTWING]
}
end
#-------------------------------------------------------------------------------
# Main code
#-------------------------------------------------------------------------------
module PBTerrain
BirdBridge = PhenomenonConfig::BirdTerrainTag
end
class PokemonTemp
attr_accessor :phenomenon # [x,y,type,timer]
end
class Array # Add quick random array fetch - by Marin
def random
return self[rand(self.size)]
end
end
class Phenomenon
attr_accessor :timer
attr_accessor :x
attr_accessor :y
attr_accessor :type
attr_accessor :active
def initialize(types)
@x = nil
@y = nil
@types = types
@timer = PhenomenonConfig::Frequency <= 6 ? 6 : rand(PhenomenonConfig::Frequency-6)+6
@active = false
end
def generate!
phenomenon_tiles = [] # x, y, type
# limit range to around the player to reduce CPU load
x_range = [[$game_player.x - 20, 0].max, [$game_player.x + 20, $game_map.width].min]
y_range = [[$game_player.y - 20, 0].max, [$game_player.y + 20, $game_map.height].min]
# list all grass tiles
for x in x_range[0]..x_range[1]
for y in y_range[0]..y_range[1]
terrain_tag = $game_map.terrain_tag(x, y)
if @types.include?(:grass) && PBTerrain.isJustGrass?(terrain_tag)
phenomenon_tiles.push([x, y, :grass])
end
if @types.include?(:water) && PBTerrain.isJustWater?(terrain_tag) && !PBTerrain.isDeepWater?(terrain_tag)
phenomenon_tiles.push([x, y, :water])
end
if @types.include?(:cave) && terrain_tag == PBTerrain::Rock && $MapFactory.isPassable?($game_map.map_id, x, y)
phenomenon_tiles.push([x, y, :cave])
end
if @types.include?(:bird) && (!defined?(PhenomenonConfig::BirdTerrainTag) || PhenomenonConfig::BirdTerrainTag == -1 ||
terrain_tag == PBTerrain::BirdBridge) && $MapFactory.isPassable?($game_map.map_id, x, y)
phenomenon_tiles.push([x, y, :bird])
end
end
end
if phenomenon_tiles.length == 0
phenomenonCancel
else
selected_tile = phenomenon_tiles.random
@x = selected_tile[0]
@y = selected_tile[1]
@type = selected_tile[2]
@timer = PhenomenonConfig::Timer
@active = true
end
end
def activate!
encounter = nil
item = nil
chance = rand(10)
# Different types have different effects, e.g. items in caves
case @type
when :grass
encounter = $PokemonEncounters.pbEncounteredPokemon(PhenomenonConfig::Types[:grass][3])
when :water
encounter = $PokemonEncounters.pbEncounteredPokemon(PhenomenonConfig::Types[:water][3])
when :cave
if chance >= 5
encounter = $PokemonEncounters.pbEncounteredPokemon(PhenomenonConfig::Types[:cave][3])
else
item = chance > 0 ? PhenomenonConfig::Items[:commonCave].random : PhenomenonConfig::Items[:rareCave].random
end
when :bird
if chance >= 8
encounter = $PokemonEncounters.pbEncounteredPokemon(PhenomenonConfig::Types[:bird][3])
else
item = chance > 0 ? PhenomenonConfig::Items[:bird].random : :PRETTYWING
end
end
if encounter != nil
if PhenomenonConfig::BattleMusic != "" && FileTest.audio_exist?("Audio/BGM/#{PHENOMENON_BATTLE_MUSIC}")
$PokemonGlobal.nextBattleBGM = PhenomenonConfig::BattleMusic
end
$PokemonTemp.forceSingleBattle = true
pbWildBattle(encounter[0], encounter[1])
elsif item != nil
phenomenonCancel
Kernel.pbReceiveItem(item)
end
end
def drawAnim(sound)
dist = (((@x - $game_player.x).abs + (@y - $game_player.y).abs) / 4).floor
if dist <= 6 && dist >= 0
animation = PhenomenonConfig::Types[@type]
$scene.spriteset.addUserAnimation(animation[0], @x, @y, true, animation[2])
level = [75, 65, 55, 40, 27, 22, 15][dist]
pbSEPlay(animation[1], level) if sound
end
end
end
# Cancels the phenomenon
def phenomenonCancel
$PokemonTemp.phenomenon = nil
end
def phenomenonInactive?
return defined?($PokemonTemp.phenomenon) && $PokemonTemp.phenomenon != nil && !$PokemonTemp.phenomenon.active
end
# Returns true if an existing phenomenon has been set up and exists
def phenomenonActive?
return defined?($PokemonTemp.phenomenon) && $PokemonTemp.phenomenon != nil && $PokemonTemp.phenomenon.active
end
# Returns true if there's a phenomenon and the player is on top of it
def phenomenonPlayerOn?
return phenomenonActive? && ($game_player.x == $PokemonTemp.phenomenon.x && $game_player.y == $PokemonTemp.phenomenon.y)
end
#-------------------------------------------------------------------------------
# Event handlers
#-------------------------------------------------------------------------------
class PokemonTemp
attr_accessor :phenomenonExp
attr_accessor :phenomenonTypes
attr_accessor :phenomenon
end
# Cancels phenomenon on battle start to stop animation during battle intro
Events.onStartBattle += proc { |sender, e|
$PokemonTemp.phenomenonExp = true if PhenomenonConfig::Pokemon[:expBoost] && phenomenonPlayerOn?
phenomenonCancel
}
Events.onEndBattle += proc { |sender, e|
$PokemonTemp.phenomenonExp = false
}
# Generate the phenomenon or process the player standing on it
Events.onStepTaken += proc { |sender, e|
if phenomenonPlayerOn?
$PokemonTemp.phenomenon.activate!
elsif phenomenonInactive?
if $PokemonTemp.phenomenon.timer <= 0
$PokemonTemp.phenomenon.generate!
else
$PokemonTemp.phenomenon.timer -= 1
end
elsif $PokemonTemp.phenomenon == nil && $PokemonTemp.phenomenonTypes.size && (PhenomenonConfig::Switch == -1 || $game_switches[PhenomenonConfig::Switch])
$PokemonTemp.phenomenon = Phenomenon.new($PokemonTemp.phenomenonTypes)
end
}
# Remove any phenomenon events on map change
Events.onMapChange += proc { |sender, e|
phenomenonCancel
}
# Process map available encounters on map change
Events.onMapChanging += proc { |sender, e|
types = []
PhenomenonConfig::Types.each do |(key, value)|
types.push(key) if $PokemonEncounters && $PokemonEncounters.pbMapHasEncounter?(e[0], value[3])
end
$PokemonTemp.phenomenonTypes = types
}
# Modify the wild encounter based on the settings above
Events.onWildPokemonCreate+=proc {|sender,e|
pokemon = e[0]
if phenomenonPlayerOn?
if PhenomenonConfig::Pokemon[:shiny] # 4x the normal shiny chance
pokemon.makeShiny if rand(65536) <= SHINYPOKEMONCHANCE*4
end
if PhenomenonConfig::Pokemon[:ivs] > -1 && rand(PhenomenonConfig::Pokemon[:ivs]) == 0
for i in 0...2 # gives a high chance of 2 perfect ivs and a low chance of 1
pokemon.iv[rand(6)] = 31
end
end
if PhenomenonConfig::Pokemon[:eggMoves] > -1 && rand(PhenomenonConfig::Pokemon[:eggMoves]) == 0
moves = []
pbRgssOpen("Data/eggEmerald.dat","rb"){|f|
f.pos=(pokemon.fSpecies-1)*8
offset=f.fgetdw
length=f.fgetdw
if length>0
f.pos=offset
i=0; loop do break unless i<length
moves.push(f.fgetw)
i+=1
end
end
}
pokemon.pbLearnMove(moves.random) if moves.length > 0
end
if PhenomenonConfig::Pokemon[:hiddenAbility] > -1 && rand(PhenomenonConfig::Pokemon[:hiddenAbility]) == 0
a = poke.getAbilityList
if a != nil && a.length >= 2 && a[2] != nil && a[2][1] == 2
pokemon.setAbility(a[2][1])
end
end
end
}
#-------------------------------------------------------------------------------
# Class modifiers
#-------------------------------------------------------------------------------
class PokemonEncounters
alias isCave_phenomenon isCave?
def isCave? # show cave background on battle for dust clouds
return self.hasEncounter?(PhenomenonConfig::Types[:cave][3]) || isCave_phenomenon
end
end
class Spriteset_Map
alias update_phenomenon update
def update
if phenomenonActive? && !$game_temp.in_menu
phn = $PokemonTemp.phenomenon
phn.timer -= 1
if (PhenomenonConfig::Switch != -1 &&
!$game_switches[PhenomenonConfig::Switch]) || phn.timer <= 0
phenomenonCancel
elsif phn.timer % 40 == 0 # play animation every 40 cycles
sound = phn.type == :grass ? (phn.timer % 80 == 0) : true
phn.drawAnim(sound)
end
end
update_phenomenon
end
end