• Having trouble receiving email verification when signing up? Contact an administrator via our Discord server!
  • Consider joining our Discord server if you haven't already! Discord is a free voice and text chat platform that's more or less a combination of Skype and Teamspeak. Using Discord, you can chat with other Relic Castle members in real-time! Wowza! Click here for the details!
Phenomenon: BW Style Grass Rustle, Cave Dust + More

Phenomenon: BW Style Grass Rustle, Cave Dust + More 1.1

Pokémon Essentials Version
v17.2 ✅
Phenomenon

phenomenon_cave.gif
phenomenon_bird.gif

My favourite feature of Black and White was the phenomena - random events that let you snag good items or rare Pokémon, or even just fighting Audinos for a good EXP boost. So I've created it in Essentials!

This is my first 'big script', so any experienced coders, I'd love some feedback and tips to improve it.

Features
  • All 4 random events - Grass rustling, Water bubbles, Cave dust and Flying birds, complete with sound effects
  • Random item drops for caves and birds
  • Distance-based sound effect volume
  • Custom battle music option
  • No need for events - works with terrain tags (Grass, Water, Rock and a custom one for Bird locations)
  • Toggleable with a switch to protect cutscene
To Install
First, download the attached zip file. This contains 4 sound effects, an animation sheet, and an optional Animations.rxdata.

Place the sound effects in Audio/SE. Place the animation sheet in Graphics/Animations.

If it's a new project, you can simply replace your existing Animations.rxdata with the attached one.
If not, create a new project, place the animations sheet in the Graphics/Animations folder and replace the Animations.rxdata with the downloaded one. If you open both your project and this new project at the same time, you can copy and paste each of the animations across.

Make these changes to PField_Encounters:

Add these lines below BugContest = 14 NOTE: If you already have custom encounters, you'll need to make slight changes to the numbers here.

Ruby:
  PhenomenonGrass = 13
  PhenomenonWater = 14
  PhenomenonCave = 15
  PhenomenonBird = 16
Then these lines at the bottom of the Names list, under "BugContest". NOTE: Don't forget the comma between the item before and PhenomenonGrass
Ruby:
    "PhenomenonGrass",
    "PhenomenonWater",
    "PhenomenonCave",
    "PhenomenonBird"
Then these lines at the bottom of EncTypeChances (remember the comma!)
Ruby:
    [50, 20, 10, 5, 5, 5, 5],
    [50, 20, 10, 5, 5, 5, 5],
    [50, 30, 10, 5, 5],
    [50, 30, 10, 5, 5]
Then add ,100,100,100,100 at the end of the EnctypeDensities array and ,1,1,1,1 at the end of the EnctypeCompileDens array. Last time - make sure the commas are in order on all of these.

Then add this script above Main:

Ruby:
################################################################################
# Phenomenon: Pokemon BW Style Grass Rustle, Water Drop, Cave Dust & Flying Bird
# v1.1 by Boonzeet
################################################################################

################################################################################
# Configuration
################################################################################

# Chance for phenomenon to generate on step e.g. (1/300). Keep it a high number.
PHENOMENON_FREQ = 400
# How many update cycles to wait until the phenomenon is cleared:
PHENOMENON_TIMER = 1800

# Switch to enable phenomenon. Switching to OFF disables phenomenon and clears any existing ones
PHENOMENON_TOGGLE_SWITCH = 70

# Enable 4x probability of shiny Pokémon in phenomena
PHENOMENON_POKE_SHINY = false

# Probabilities of pokemon modifiers.
# -1 to disable, 1 for 100% chance, otherwise 1/x chance of occuring
PHENOMENON_POKE_IVS = -1 # Probability of two or three high IVs
PHENOMENON_POKE_EGGMOVES = -1 # Probability of having a random egg move
PHENOMENON_POKE_HIDDENABILITY = -1 # Probability of Hidden ability

# Animations and sound effects
# Rustling grass
GRASS_PHENOMENON_ANIMATION_ID = 56
GRASS_PHENOMENON_SE = "phenomenon_grass"
# Bubbles
WATER_PHENOMENON_ANIMATION_ID = 57
WATER_PHENOMENON_SE = "phenomenon_water"
# Cave Dust
CAVE_PHENOMENON_ANIMATION_ID = 58
CAVE_PHENOMENON_SE = "phenomenon_cave"
# Birds Flying
BIRD_PHENOMENON_ANIMATION_ID = 59
BIRD_PHENOMENON_SE = "phenomenon_bird"

# Change this to custom music, leave blank or remove if not desired
PHENOMENON_BATTLE_MUSIC = "Battle roaming"

# Change this to any value you want for the tiles for birds to appear on.
# Not recommended: You can set it to -1 to allow events anywhere, but these can
# and likely will appear in inaccessible locations.
PHENOMENON_BIRD_TERRAINTAG = 18

# These can be changed to whatever items you want the player to find.
# Items are 40% probability, Stones at 10%
CAVE_ITEMS_COMMON = [:FIREGEM, :WATERGEM, :ICEGEM, :ELECTRICGEM, :GRASSGEM, :FIGHTINGGEM,
:POISONGEM, :GROUNDGEM, :FLYINGGEM, :PSYCHICGEM, :BUGGEM, :ROCKGEM, :GHOSTGEM, :DRAGONGEM,
:DARKGEM, :STEELGEM, :NORMALGEM, :REDSHARD, :BLUESHARD, :YELLOWSHARD, :GREENSHARD]

CAVE_ITEMS_RARE = [:THUNDERSTONE, :WATERSTONE, :LEAFSTONE, :MOONSTONE, :FIRESTONE,
:SUNSTONE, :SHINYSTONE, :DUSKSTONE, :DAWNSTONE, :EVERSTONE, :OVALSTONE]

# These can be changed to whatever items you want the player to find. Pretty wing will always be 10% chance.
BIRD_ITEMS = [:HEALTHWING, :RESISTWING, :CLEVERWING, :PRETTYWING, :MUSCLEWING, :GENIUSWING, :SWIFTWING]

################################################################################
# Main code
################################################################################

module PBTerrain
  BirdBridge = PHENOMENON_BIRD_TERRAINTAG
end

class PokemonTemp
  attr_accessor :phenomenon   # [x,y,type,timer]
end

# Looks for compatible phenomenon tiles on the map and creates a single phenomenon if possible
def phenomenonHighlight
  phenomenon_tiles = []   # x, y, type
  grass_enabled = $PokemonEncounters.pbMapHasEncounter?($game_map.map_id, EncounterTypes::PhenomenonGrass)
  water_enabled = $PokemonEncounters.pbMapHasEncounter?($game_map.map_id, EncounterTypes::PhenomenonWater)
  cave_enabled = $PokemonEncounters.pbMapHasEncounter?($game_map.map_id, EncounterTypes::PhenomenonCave)
  bird_enabled = $PokemonEncounters.pbMapHasEncounter?($game_map.map_id, EncounterTypes::PhenomenonBird)
  if (!grass_enabled && !water_enabled && !cave_enabled && !bird_enabled)
    return
  end

  # 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 grass_enabled && PBTerrain.isJustGrass?(terrain_tag)
        phenomenon_tiles.push([x, y, 0])
      end
      if water_enabled && PBTerrain.isJustWater?(terrain_tag) && !PBTerrain.isDeepWater?(terrain_tag)
        phenomenon_tiles.push([x, y, 1])
      end
      if cave_enabled && terrain_tag == PBTerrain::Rock && $MapFactory.isPassable?($game_map.map_id, x, y)
        phenomenon_tiles.push([x, y, 2])
      end
      if bird_enabled && (!defined?(PHENOMENON_BIRD_TERRAINTAG) || PHENOMENON_BIRD_TERRAINTAG == -1 ||
        terrain_tag == PBTerrain::BirdBridge) && $MapFactory.isPassable?($game_map.map_id, x, y)
        phenomenon_tiles.push([x, y, 3])
      end
    end
  end
  if phenomenon_tiles.length == 0
    phenomenonCancel
  else
    selected_tile = phenomenon_tiles[rand(phenomenon_tiles.length)]
    $PokemonTemp.phenomenon = [selected_tile[0], selected_tile[1], selected_tile[2], PHENOMENON_TIMER]
  end
end

# Cancels the phenomenon
def phenomenonCancel
  $PokemonTemp.phenomenon = nil
end

# Returns true if an existing phenomenon has been set up and exists
def phenomenonExists?
  return defined?($PokemonTemp) && defined?($PokemonTemp.phenomenon) && $PokemonTemp.phenomenon != nil
end

# Returns true if there's a phenomenon and the player is on top of it
def phenomenonPlayerOn?
  return phenomenonExists? && ($game_player.x == $PokemonTemp.phenomenon[0] && $game_player.y == $PokemonTemp.phenomenon[1])
end

# Gets the hidden ability for an input Pokémon
def phenomenonGetHiddenAbility(poke)
  abilities = poke.getAbilityList
  if abilities != nil && abilities.length >= 2 && abilities[2] != nil && abilities[2][1] == 2
    return abilities[2]
  else
    return nil
  end
end

# Draws the appropriate animation for the phenomenon at x,y
def phenomenonDrawAnimation(x, y, type, sound = true, dist = 6)
  case type
  when 0
    animation = GRASS_PHENOMENON_ANIMATION_ID
    se = GRASS_PHENOMENON_SE
    height = 1
  when 1
    animation = WATER_PHENOMENON_ANIMATION_ID
    se = WATER_PHENOMENON_SE
    height = 0
  when 2
    animation = CAVE_PHENOMENON_ANIMATION_ID
    se = CAVE_PHENOMENON_SE
    height = 1
  when 3
    animation = BIRD_PHENOMENON_ANIMATION_ID
    se = BIRD_PHENOMENON_SE
    height = 0
  end
  $scene.spriteset.addUserAnimation(animation, $PokemonTemp.phenomenon[0], $PokemonTemp.phenomenon[1], true, height)
  pbSEPlay(se, [75, 65, 55, 40, 27, 22, 15][dist]) if sound
end

################################################################################
# Event handlers
################################################################################

# Cancels phenomenon on battle start to stop animation during battle intro
Events.onStartBattle += proc { |sender, e|
  phenomenonCancel
}

# Generate the phenomenon or process the player standing on it
Events.onStepTaken += proc { |sender, e|
  if !phenomenonExists? && (PHENOMENON_TOGGLE_SWITCH == -1 || $game_switches[PHENOMENON_TOGGLE_SWITCH])
    r = rand(1 + PHENOMENON_FREQ)
    phenomenonHighlight if (r > PHENOMENON_FREQ - 1)
  elsif phenomenonPlayerOn? && PHENOMENON_TOGGLE_SWITCH != -1
    encounter = nil
    item = nil
    # Different types have different effects, e.g. items in caves
    case $PokemonTemp.phenomenon[2]
    when 0 # grass
      encounter = $PokemonEncounters.pbEncounteredPokemon(EncounterTypes::PhenomenonGrass)
    when 1 # water
      encounter = $PokemonEncounters.pbEncounteredPokemon(EncounterTypes::PhenomenonWater)
    when 2 # cave
      chance = rand(10)
      item = nil
      if chance >= 5
        encounter = $PokemonEncounters.pbEncounteredPokemon(EncounterTypes::PhenomenonCave)
      elsif chance > 0
        item = CAVE_ITEMS_COMMON[rand(CAVE_ITEMS_COMMON.length)]
      else
        item = CAVE_ITEMS_RARE[rand(CAVE_ITEMS_RARE.length)]
      end
    when 3 # bird
      chance = rand(10)
      item = nil
      if chance >= 8
        encounter = $PokemonEncounters.pbEncounteredPokemon(EncounterTypes::PhenomenonBird)
      elsif chance > 0
        item = BIRD_ITEMS[rand(BIRD_ITEMS.length)]
      else
        item = :PRETTYWING
      end
    end
    if encounter != nil
      if PHENOMENON_BATTLE_MUSIC != nil && PHENOMENON_BATTLE_MUSIC != "" && FileTest.audio_exist?("Audio/BGM/#{PHENOMENON_BATTLE_MUSIC}")
        $PokemonGlobal.nextBattleBGM = PHENOMENON_BATTLE_MUSIC
      end
      $PokemonTemp.forceSingleBattle = true
      pbWildBattle(encounter[0], encounter[1])
    elsif item != nil
      phenomenonCancel
      Kernel.pbReceiveItem(item)
    end
  end
}

# Remove any phenomenon events on map change
Events.onMapChange += proc { |sender, e|
  phenomenonCancel
}

# Modify the wild encounter based on the settings above
Events.onWildPokemonCreate+=proc {|sender,e|
  pokemon = e[0]
  if phenomenonExists?
    if $game_player.x==$PokemonTemp.phenomenon[0] && $game_player.y==$PokemonTemp.phenomenon[1]
      if PHENOMENON_POKE_SHINY # 4x the mormal shiny chance
        pokemon.makeShiny if rand(65536) <= SHINYPOKEMONCHANCE*4
      end
      if PHENOMENON_POKE_IVS > -1
        if rand(PHENOMENON_POKE_IVS) == 0
          old_ivs = pokemon.iv
          for i in 0...2 # gives a high chance of 2 perfect ivs and a low chance of 1
            old_ivs[rand(6)] = 31
          end
          pokemon.iv = old_ivs
        end
      end
      if PHENOMENON_POKE_EGGMOVES > -1
        if rand(PHENOMENON_POKE_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
            }
          if moves.length > 0
            pokemon.pbLearnMove(moves[rand(moves.length)])
          end
        end
      end
      if PHENOMENON_POKE_HIDDENABILITY > -1
        if rand(PHENOMENON_POKE_HIDDENABILITY) == 0
          a = phenomenonGetHiddenAbility(pokemon)
          pokemon.setAbility(a[1]) if a != nil
        end
      end
      return
    end
  end
}

################################################################################
# Class modifiers
################################################################################

class PokemonEncounters
  alias isCave_phenomenon isCave?
  def isCave? # show cave background on battle for dust clouds
    return true if self.hasEncounter?(EncounterTypes::PhenomenonCave)
    return isCave_phenomenon
  end
end

class Spriteset_Map
  alias update_phenomenon update
  def update
    if !$game_temp.in_menu && phenomenonExists?
      if (PHENOMENON_TOGGLE_SWITCH != -1 && !$game_switches[PHENOMENON_TOGGLE_SWITCH])
        phenomenonCancel
      else
        $PokemonTemp.phenomenon[3] -= 1
        if $PokemonTemp.phenomenon[3] <= 0
          phenomenonCancel
        elsif $PokemonTemp.phenomenon[3] % 40 == 0 # play animation every 38 cycles
          dist = ((($PokemonTemp.phenomenon[0] - $game_player.x).abs + ($PokemonTemp.phenomenon[1] - $game_player.y).abs) / 4).floor
          if dist <= 6 && dist >= 0
            play_sound = ($PokemonTemp.phenomenon[2] == 0 || $PokemonTemp.phenomenon[3] % (40 * 2) == 0) # grass rustles more than other effects
            phenomenonDrawAnimation($PokemonTemp.phenomenon[0], $PokemonTemp.phenomenon[1], $PokemonTemp.phenomenon[2], play_sound, dist)
          end
        end
      end
    end
    update_phenomenon
  end
end
To Use
Set up encounters in encounters.txt like so:
Ruby:
#-------------------------------
004 # Drowned Cave B1F
25,10,10
PhenomenonWater
POLIWHIRL,15
POLIWHIRL,16
GOLDEEN,15
GOLDEEN,15
GOLDEEN,17
GOLDEEN,5
SQUIRTLE,5
PhenomenonCave
DRILBUR,10,11
DRILBUR,12
DRILBUR,14
DRILBUR,11
DRILBUR,15
#-------------------------------
006 # Route 1
25,10,10
PhenomenonGrass
AUDINO,5
AUDINO,5
AUDINO,5
AUDINO,5
AUDINO,5
AUDINO,5
ELEKID,5
PhenomenonBird
DUCKLETT,5
DUCKLETT,5,7
PIDOVE,5
PIDOVE,5
PIDOVE,5
And you should be good to go! Let me know if you find any bugs or ways to improve it. Please credit if used!

Credits
Boonzeet | Scripts and Graphics
DaSpirit | BW Style Grass Graphic
Game Freak | Sound Effects (Pokémon Black/White) ripped by BadSamaritan
Maruno & Marin | Help with distance based sound volume
Credits
Credit if used:
Boonzeet | Scripts and Graphics
DaSpirit | BW Style Grass Graphic

Game Freak | Sound Effects (Pokémon Black/White) ripped by BadSamaritan
Maruno & Marin | Help with distance based sound volume
Author
boonzeet
Downloads
180
First release
Last update
Rating
5.00 star(s) 1 ratings

More resources from boonzeet

Latest updates

  1. v1.1: Optional chances for shininess, egg moves, some perfect IVs and hidden abilities!

    Updated to v1.1. This version allows the user to optionally enable a 4x higher probability of...

Latest reviews

Works great, but keep in mind:
- Script comment says the switch DISABLES the encounter phenomena when in reality it ENABLES it
- The animation IDs for the constants do not match the IDs in the example Animations.rxdata so if you use the included one just remember that.
boonzeet
boonzeet
Good catch on both of these, my bad! Updated to fix them. Thanks for the review :)
Top