Yet more script rearranging

This commit is contained in:
Maruno17
2021-04-17 23:45:42 +01:00
parent 96c68e79a3
commit 2ca8a42949
236 changed files with 923 additions and 928 deletions

View File

@@ -0,0 +1,772 @@
#===============================================================================
# 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
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]
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
$game_screen.start_flash(Color.new(255,0,0,128), 4)
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 currentTag.waterfall_crest
pbDescendWaterfall
elsif currentTag.ice && !$PokemonGlobal.sliding
pbSlideOnIce
end
end
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 = ($PokemonGlobal.repel > 0)
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 = ($PokemonGlobal.repel > 0)
pbBattleOnStepTaken(repel_active) if !$game_temp.in_menu
}
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 = $PokemonEncounters.choose_wild_pokemon(encounter_type)
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
$PokemonMap.clear if $PokemonMap
$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
next if !new_map_metadata || !new_map_metadata.weather
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
$game_screen.weather(new_weather[0], 9, 0) if rand(100) < new_weather[1]
}
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
$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
# Returns whether event is in line with the player, is facing the player and is
# within distance tiles of the player.
def pbEventFacesPlayer?(event, player, distance)
return false if !event || !player || distance <= 0
x_min = x_max = y_min = y_max = -1
case 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 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 and 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 = GameData::Item.get(item)
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"
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} \\c[1]{3}\\c[0]!\\wtnp[30]",meName,quantity,itemname))
elsif itemname.starts_with_vowel?
pbMessage(_INTL("\\me[{1}]You found an \\c[1]{2}\\c[0]!\\wtnp[30]",meName,itemname))
else
pbMessage(_INTL("\\me[{1}]You found a \\c[1]{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]))
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 = GameData::Item.get(item)
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"
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
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} \\c[1]{3}\\c[0]!\\wtnp[30]",meName,quantity,itemname))
elsif itemname.starts_with_vowel?
pbMessage(_INTL("\\me[{1}]You obtained an \\c[1]{2}\\c[0]!\\wtnp[30]",meName,itemname))
else
pbMessage(_INTL("\\me[{1}]You obtained a \\c[1]{2}\\c[0]!\\wtnp[30]",meName,itemname))
end
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]))
return true
end
return false # Can't add the item
end

View File

@@ -0,0 +1,521 @@
# 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.2) ? 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 !sprite || !sprite.bitmap || !sprite.visible
weather_type = @type
if @fading && @fade_time >= [FADE_OLD_TONE_END - @time_shift, 0].max
weather_type = @target_type
end
sprite.x = @ox + @tile_x + (index % @tiles_wide) * sprite.bitmap.width
sprite.y = @oy + @tile_y + (index / @tiles_wide) * sprite.bitmap.height
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

View File

@@ -0,0 +1,221 @@
#===============================================================================
# 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
#===============================================================================
# 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 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_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))
}

View File

@@ -0,0 +1,134 @@
#===============================================================================
# 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)
if pbInBugContest?
pbBugContestStartOver
return
end
$Trainer.heal_party
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

View File

@@ -0,0 +1,686 @@
#===============================================================================
# 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 "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
# 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?
# 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
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 = GameData::MapMetadata.get($game_map.map_id).battle_background
backdrop = back if back && back != ""
end
backdrop = "indoor1" if !backdrop
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
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
#===============================================================================
# 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)
species = GameData::Species.get(species).id
# 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
#===============================================================================
# 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
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
raise _INTL("Expected an array of trainer data, got {1}.",arg) if !arg.is_a?(Array)
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)
else
# [trainer type, trainer name, ID, speech (optional)]
trainer = pbLoadTrainer(arg[0],arg[1],arg[2])
pbMissingTrainer(arg[0],arg[1],arg[2]) if !trainer
return 0 if !trainer
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)
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
#===============================================================================
# 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)
# 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 which might modify it
trainer = pbLoadTrainer(trainerID,trainerName,trainerPartyID)
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
waitingTrainer = $PokemonTemp.waitingTrainer
decision = pbTrainerBattleCore($PokemonTemp.waitingTrainer,
[trainerID,trainerName,trainerPartyID,endSpeech]
)
else
decision = pbTrainerBattleCore([trainerID,trainerName,trainerPartyID,endSpeech])
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
when 2, 5 # Lose, draw
if !canLose
$game_system.bgm_unpause
$game_system.bgs_unpause
pbStartOver
end
end
}
def pbEvolutionCheck(currentLevels)
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(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

View File

@@ -0,0 +1,310 @@
#===============================================================================
# Battle intro animation
#===============================================================================
def pbSceneStandby
$scene.disposeSpritesets if $scene && $scene.is_a?(Scene_Map)
RPG::Cache.clear
Graphics.frame_reset
yield
$scene.createSpritesets if $scene && $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
$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
if tr_type
tbargraphic = sprintf("vsBar_%s", tr_type.to_s) rescue nil
tgraphic = sprintf("vsTrainer_%s", tr_type.to_s) rescue nil
if pbResolveBitmap(tbargraphic) && pbResolveBitmap(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
if !pbResolveBitmap(pbargraphic)
pbargraphic = sprintf("vsBar_%s", player_tr_type.to_s) rescue nil
end
xoffset = ((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
if !pbResolveBitmap(pgraphic)
pgraphic = sprintf("vsTrainer_%s", player_tr_type.to_s) rescue nil
end
player = Sprite.new(viewplayer)
player.bitmap = RPG::Cache.transition(pgraphic)
player.x = -xoffset
trainer = Sprite.new(viewopp)
trainer.bitmap = RPG::Cache.transition(tgraphic)
trainer.x = xoffset
trainer.tone = Tone.new(-255,-255,-255)
# 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
trainer.x = xoffset*(slideInTime-i-1+animTime/2)/slideInTime
end
pbWait(1)
end
player.x = 0
trainer.x = 0
# 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

View File

@@ -0,0 +1,432 @@
#===============================================================================
#
#===============================================================================
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 = GameData::Encounter.get(map_ID, $PokemonGlobal.encounter_version)
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 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 = GameData::Encounter.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)
# 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
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)
ret = find_valid_encounter_type_for_time(:Land, 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[0])
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 = GameData::Encounter.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
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

View File

@@ -0,0 +1,40 @@
################################################################################
# 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
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 == 51
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
#}

View File

@@ -0,0 +1,225 @@
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
# 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
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
# Choose a random new map to roam to
if newMapChoices.length>0
$PokemonGlobal.roamPosition[idxRoamer] = newMapChoices[rand(newMapChoices.length)]
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 = $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
})

View File

@@ -0,0 +1,285 @@
#===============================================================================
# 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 :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
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
@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
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

View File

@@ -0,0 +1,312 @@
#===============================================================================
# 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)
time = pbGetTimeNow if !time
return (time.hour>=5 && time.hour<20)
end
# Returns true if it's night.
def self.isNight?(time=nil)
time = pbGetTimeNow if !time
return (time.hour>=20 || time.hour<5)
end
# Returns true if it's morning.
def self.isMorning?(time=nil)
time = pbGetTimeNow if !time
return (time.hour>=5 && time.hour<10)
end
# Returns true if it's the afternoon.
def self.isAfternoon?(time=nil)
time = pbGetTimeNow if !time
return (time.hour>=14 && time.hour<17)
end
# Returns true if it's the evening.
def self.isEvening?(time=nil)
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
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]
# 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

View File

@@ -0,0 +1,987 @@
#===============================================================================
# Hidden move handlers
#===============================================================================
module HiddenMoveHandlers
CanUseMove = MoveHandlerHash.new
ConfirmUseMove = MoveHandlerHash.new
UseMove = MoveHandlerHash.new
def self.addCanUseMove(item,proc); CanUseMove.add(item,proc); end
def self.addConfirmUseMove(item,proc); ConfirmUseMove.add(item,proc); end
def self.addUseMove(item,proc); UseMove.add(item,proc); end
def self.hasHandler(item)
return CanUseMove[item]!=nil && UseMove[item]!=nil
end
# Returns whether move can be used
def self.triggerCanUseMove(item,pokemon,showmsg)
return false if !CanUseMove[item]
return CanUseMove.trigger(item,pokemon,showmsg)
end
# Returns whether the player confirmed that they want to use the move
def self.triggerConfirmUseMove(item,pokemon)
return true if !ConfirmUseMove[item]
return ConfirmUseMove.trigger(item,pokemon)
end
# Returns whether move was used
def self.triggerUseMove(item,pokemon)
return false if !UseMove[item]
return UseMove.trigger(item,pokemon)
end
end
def pbCanUseHiddenMove?(pkmn,move,showmsg=true)
return HiddenMoveHandlers.triggerCanUseMove(move,pkmn,showmsg)
end
def pbConfirmUseHiddenMove(pokemon,move)
return HiddenMoveHandlers.triggerConfirmUseMove(move,pokemon)
end
def pbUseHiddenMove(pokemon,move)
return HiddenMoveHandlers.triggerUseMove(move,pokemon)
end
# Unused
def pbHiddenMoveEvent
Events.onAction.trigger(nil)
end
def pbCheckHiddenMoveBadge(badge=-1,showmsg=true)
return true if badge<0 # No badge requirement
return true if $DEBUG
if (Settings::FIELD_MOVES_COUNT_BADGES) ? $Trainer.badge_count >= badge : $Trainer.badges[badge]
return true
end
pbMessage(_INTL("Sorry, a new Badge is required.")) if showmsg
return false
end
#===============================================================================
# Hidden move animation
#===============================================================================
def pbHiddenMoveAnimation(pokemon)
return false if !pokemon
viewport=Viewport.new(0,0,0,0)
viewport.z=99999
bg=Sprite.new(viewport)
bg.bitmap=RPG::Cache.picture("hiddenMovebg")
sprite=PokemonSprite.new(viewport)
sprite.setOffset(PictureOrigin::Center)
sprite.setPokemonBitmap(pokemon)
sprite.z=1
sprite.visible=false
strobebitmap=AnimatedBitmap.new("Graphics/Pictures/hiddenMoveStrobes")
strobes=[]
15.times do |i|
strobe=BitmapSprite.new(26*2,8*2,viewport)
strobe.bitmap.blt(0,0,strobebitmap.bitmap,Rect.new(0,(i%2)*8*2,26*2,8*2))
strobe.z=((i%2)==0 ? 2 : 0)
strobe.visible=false
strobes.push(strobe)
end
strobebitmap.dispose
interp=RectInterpolator.new(
Rect.new(0,Graphics.height/2,Graphics.width,0),
Rect.new(0,(Graphics.height-bg.bitmap.height)/2,Graphics.width,bg.bitmap.height),
Graphics.frame_rate/4)
ptinterp=nil
phase=1
frames=0
strobeSpeed = 64*20/Graphics.frame_rate
loop do
Graphics.update
Input.update
sprite.update
case phase
when 1 # Expand viewport height from zero to full
interp.update
interp.set(viewport.rect)
bg.oy=(bg.bitmap.height-viewport.rect.height)/2
if interp.done?
phase=2
ptinterp=PointInterpolator.new(
Graphics.width+(sprite.bitmap.width/2),bg.bitmap.height/2,
Graphics.width/2,bg.bitmap.height/2,
Graphics.frame_rate*4/10)
end
when 2 # Slide Pokémon sprite in from right to centre
ptinterp.update
sprite.x=ptinterp.x
sprite.y=ptinterp.y
sprite.visible=true
if ptinterp.done?
phase=3
GameData::Species.play_cry_from_pokemon(pokemon)
frames=0
end
when 3 # Wait
frames+=1
if frames>Graphics.frame_rate*3/4
phase=4
ptinterp=PointInterpolator.new(
Graphics.width/2,bg.bitmap.height/2,
-(sprite.bitmap.width/2),bg.bitmap.height/2,
Graphics.frame_rate*4/10)
frames=0
end
when 4 # Slide Pokémon sprite off from centre to left
ptinterp.update
sprite.x=ptinterp.x
sprite.y=ptinterp.y
if ptinterp.done?
phase=5
sprite.visible=false
interp=RectInterpolator.new(
Rect.new(0,(Graphics.height-bg.bitmap.height)/2,Graphics.width,bg.bitmap.height),
Rect.new(0,Graphics.height/2,Graphics.width,0),
Graphics.frame_rate/4)
end
when 5 # Shrink viewport height from full to zero
interp.update
interp.set(viewport.rect)
bg.oy=(bg.bitmap.height-viewport.rect.height)/2
phase=6 if interp.done?
end
# Constantly stream the strobes across the screen
for strobe in strobes
strobe.ox=strobe.viewport.rect.x
strobe.oy=strobe.viewport.rect.y
if !strobe.visible # Initial placement of strobes
randomY = 16*(1+rand(bg.bitmap.height/16-2))
strobe.y = randomY+(Graphics.height-bg.bitmap.height)/2
strobe.x = rand(Graphics.width)
strobe.visible = true
elsif strobe.x<Graphics.width # Move strobe right
strobe.x += strobeSpeed
else # Strobe is off the screen, reposition it to the left of the screen
randomY = 16*(1+rand(bg.bitmap.height/16-2))
strobe.y = randomY+(Graphics.height-bg.bitmap.height)/2
strobe.x = -strobe.bitmap.width-rand(Graphics.width/4)
end
end
pbUpdateSceneMap
break if phase==6
end
sprite.dispose
for strobe in strobes
strobe.dispose
end
strobes.clear
bg.dispose
viewport.dispose
return true
end
#===============================================================================
# Cut
#===============================================================================
def pbCut
move = :CUT
movefinder = $Trainer.get_pokemon_with_move(move)
if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_CUT,false) || (!$DEBUG && !movefinder)
pbMessage(_INTL("This tree looks like it can be cut down."))
return false
end
pbMessage(_INTL("This tree looks like it can be cut down!\1"))
if pbConfirmMessage(_INTL("Would you like to cut it?"))
speciesname = (movefinder) ? movefinder.name : $Trainer.name
pbMessage(_INTL("{1} used {2}!",speciesname,GameData::Move.get(move).name))
pbHiddenMoveAnimation(movefinder)
return true
end
return false
end
HiddenMoveHandlers::CanUseMove.add(:CUT,proc { |move,pkmn,showmsg|
next false if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_CUT,showmsg)
facingEvent = $game_player.pbFacingEvent
if !facingEvent || !facingEvent.name[/cuttree/i]
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
next true
})
HiddenMoveHandlers::UseMove.add(:CUT,proc { |move,pokemon|
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
facingEvent = $game_player.pbFacingEvent
if facingEvent
pbSmashEvent(facingEvent)
end
next true
})
def pbSmashEvent(event)
return if !event
if event.name[/cuttree/i]
pbSEPlay("Cut",80)
elsif event.name[/smashrock/i]
pbSEPlay("Rock Smash",80)
end
pbMoveRoute(event,[
PBMoveRoute::Wait,2,
PBMoveRoute::TurnLeft,
PBMoveRoute::Wait,2,
PBMoveRoute::TurnRight,
PBMoveRoute::Wait,2,
PBMoveRoute::TurnUp,
PBMoveRoute::Wait,2
])
pbWait(Graphics.frame_rate*4/10)
event.erase
$PokemonMap.addErasedEvent(event.id) if $PokemonMap
end
#===============================================================================
# Dig
#===============================================================================
HiddenMoveHandlers::CanUseMove.add(:DIG,proc { |move,pkmn,showmsg|
escape = ($PokemonGlobal.escapePoint rescue nil)
if !escape || escape==[]
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
if $game_player.pbHasDependentEvents?
pbMessage(_INTL("It can't be used when you have someone with you.")) if showmsg
next false
end
next true
})
HiddenMoveHandlers::ConfirmUseMove.add(:DIG,proc { |move,pkmn|
escape = ($PokemonGlobal.escapePoint rescue nil)
next false if !escape || escape==[]
mapname = pbGetMapNameFromId(escape[0])
next pbConfirmMessage(_INTL("Want to escape from here and return to {1}?",mapname))
})
HiddenMoveHandlers::UseMove.add(:DIG,proc { |move,pokemon|
escape = ($PokemonGlobal.escapePoint rescue nil)
if escape
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
pbFadeOutIn {
$game_temp.player_new_map_id = escape[0]
$game_temp.player_new_x = escape[1]
$game_temp.player_new_y = escape[2]
$game_temp.player_new_direction = escape[3]
$scene.transfer_player
$game_map.autoplay
$game_map.refresh
}
pbEraseEscapePoint
next true
end
next false
})
#===============================================================================
# Dive
#===============================================================================
def pbDive
return false if $game_player.pbFacingEvent
map_metadata = GameData::MapMetadata.try_get($game_map.map_id)
return false if !map_metadata || !map_metadata.dive_map_id
move = :DIVE
movefinder = $Trainer.get_pokemon_with_move(move)
if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_DIVE,false) || (!$DEBUG && !movefinder)
pbMessage(_INTL("The sea is deep here. A Pokémon may be able to go underwater."))
return false
end
if pbConfirmMessage(_INTL("The sea is deep here. Would you like to use Dive?"))
speciesname = (movefinder) ? movefinder.name : $Trainer.name
pbMessage(_INTL("{1} used {2}!",speciesname,GameData::Move.get(move).name))
pbHiddenMoveAnimation(movefinder)
pbFadeOutIn {
$game_temp.player_new_map_id = map_metadata.dive_map_id
$game_temp.player_new_x = $game_player.x
$game_temp.player_new_y = $game_player.y
$game_temp.player_new_direction = $game_player.direction
$PokemonGlobal.surfing = false
$PokemonGlobal.diving = true
pbUpdateVehicle
$scene.transfer_player(false)
$game_map.autoplay
$game_map.refresh
}
return true
end
return false
end
def pbSurfacing
return if !$PokemonGlobal.diving
return false if $game_player.pbFacingEvent
surface_map_id = nil
GameData::MapMetadata.each do |map_data|
next if !map_data.dive_map_id || map_data.dive_map_id != $game_map.map_id
surface_map_id = map_data.id
break
end
return if !surface_map_id
move = :DIVE
movefinder = $Trainer.get_pokemon_with_move(move)
if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_DIVE,false) || (!$DEBUG && !movefinder)
pbMessage(_INTL("Light is filtering down from above. A Pokémon may be able to surface here."))
return false
end
if pbConfirmMessage(_INTL("Light is filtering down from above. Would you like to use Dive?"))
speciesname = (movefinder) ? movefinder.name : $Trainer.name
pbMessage(_INTL("{1} used {2}!",speciesname,GameData::Move.get(move).name))
pbHiddenMoveAnimation(movefinder)
pbFadeOutIn {
$game_temp.player_new_map_id = surface_map_id
$game_temp.player_new_x = $game_player.x
$game_temp.player_new_y = $game_player.y
$game_temp.player_new_direction = $game_player.direction
$PokemonGlobal.surfing = true
$PokemonGlobal.diving = false
pbUpdateVehicle
$scene.transfer_player(false)
surfbgm = GameData::Metadata.get.surf_BGM
(surfbgm) ? pbBGMPlay(surfbgm) : $game_map.autoplayAsCue
$game_map.refresh
}
return true
end
return false
end
def pbTransferUnderwater(mapid,x,y,direction=$game_player.direction)
pbFadeOutIn {
$game_temp.player_new_map_id = mapid
$game_temp.player_new_x = x
$game_temp.player_new_y = y
$game_temp.player_new_direction = direction
$scene.transfer_player(false)
$game_map.autoplay
$game_map.refresh
}
end
Events.onAction += proc { |_sender, _e|
if $PokemonGlobal.diving
surface_map_id = nil
GameData::MapMetadata.each do |map_data|
next if !map_data.dive_map_id || map_data.dive_map_id != $game_map.map_id
surface_map_id = map_data.id
break
end
if surface_map_id &&
$MapFactory.getTerrainTag(surface_map_id, $game_player.x, $game_player.y).can_dive
pbSurfacing
end
else
pbDive if $game_player.terrain_tag.can_dive
end
}
HiddenMoveHandlers::CanUseMove.add(:DIVE,proc { |move,pkmn,showmsg|
next false if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_DIVE,showmsg)
if $PokemonGlobal.diving
surface_map_id = nil
GameData::MapMetadata.each do |map_data|
next if !map_data.dive_map_id || map_data.dive_map_id != $game_map.map_id
surface_map_id = map_data.id
break
end
if !surface_map_id ||
!$MapFactory.getTerrainTag(surface_map_id, $game_player.x, $game_player.y).can_dive
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
else
if !GameData::MapMetadata.exists?($game_map.map_id) ||
!GameData::MapMetadata.get($game_map.map_id).dive_map_id
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
if !$game_player.terrain_tag.can_dive
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
end
next true
})
HiddenMoveHandlers::UseMove.add(:DIVE,proc { |move,pokemon|
wasdiving = $PokemonGlobal.diving
if $PokemonGlobal.diving
dive_map_id = nil
GameData::MapMetadata.each do |map_data|
next if !map_data.dive_map_id || map_data.dive_map_id != $game_map.map_id
dive_map_id = map_data.id
break
end
else
map_metadata = GameData::MapMetadata.try_get($game_map.map_id)
dive_map_id = map_metadata.dive_map_id if map_metadata
end
next false if !dive_map_id
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
pbFadeOutIn {
$game_temp.player_new_map_id = dive_map_id
$game_temp.player_new_x = $game_player.x
$game_temp.player_new_y = $game_player.y
$game_temp.player_new_direction = $game_player.direction
$PokemonGlobal.surfing = wasdiving
$PokemonGlobal.diving = !wasdiving
pbUpdateVehicle
$scene.transfer_player(false)
$game_map.autoplay
$game_map.refresh
}
next true
})
#===============================================================================
# Flash
#===============================================================================
HiddenMoveHandlers::CanUseMove.add(:FLASH,proc { |move,pkmn,showmsg|
next false if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_FLASH,showmsg)
if !GameData::MapMetadata.exists?($game_map.map_id) ||
!GameData::MapMetadata.get($game_map.map_id).dark_map
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
if $PokemonGlobal.flashUsed
pbMessage(_INTL("Flash is already being used.")) if showmsg
next false
end
next true
})
HiddenMoveHandlers::UseMove.add(:FLASH,proc { |move,pokemon|
darkness = $PokemonTemp.darknessSprite
next false if !darkness || darkness.disposed?
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
$PokemonGlobal.flashUsed = true
radiusDiff = 8*20/Graphics.frame_rate
while darkness.radius<darkness.radiusMax
Graphics.update
Input.update
pbUpdateSceneMap
darkness.radius += radiusDiff
darkness.radius = darkness.radiusMax if darkness.radius>darkness.radiusMax
end
next true
})
#===============================================================================
# Fly
#===============================================================================
HiddenMoveHandlers::CanUseMove.add(:FLY,proc { |move,pkmn,showmsg|
next false if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_FLY,showmsg)
if $game_player.pbHasDependentEvents?
pbMessage(_INTL("It can't be used when you have someone with you.")) if showmsg
next false
end
if !GameData::MapMetadata.exists?($game_map.map_id) ||
!GameData::MapMetadata.get($game_map.map_id).outdoor_map
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
next true
})
HiddenMoveHandlers::UseMove.add(:FLY,proc { |move,pokemon|
if !$PokemonTemp.flydata
pbMessage(_INTL("Can't use that here."))
next false
end
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
pbFadeOutIn {
$game_temp.player_new_map_id = $PokemonTemp.flydata[0]
$game_temp.player_new_x = $PokemonTemp.flydata[1]
$game_temp.player_new_y = $PokemonTemp.flydata[2]
$game_temp.player_new_direction = 2
$PokemonTemp.flydata = nil
$scene.transfer_player
$game_map.autoplay
$game_map.refresh
}
pbEraseEscapePoint
next true
})
#===============================================================================
# Headbutt
#===============================================================================
def pbHeadbuttEffect(event=nil)
event = $game_player.pbFacingEvent(true) if !event
a = (event.x+(event.x/24).floor+1)*(event.y+(event.y/24).floor+1)
a = (a*2/5)%10 # Even 2x as likely as odd, 0 is 1.5x as likely as odd
b = $Trainer.public_ID % 10 # Practically equal odds of each value
chance = 1 # ~50%
if a==b; chance = 8 # 10%
elsif a>b && (a-b).abs<5; chance = 5 # ~30.3%
elsif a<b && (a-b).abs>5; chance = 5 # ~9.7%
end
if rand(10)>=chance
pbMessage(_INTL("Nope. Nothing..."))
else
enctype = (chance==1) ? :HeadbuttLow : :HeadbuttHigh
if !pbEncounter(enctype)
pbMessage(_INTL("Nope. Nothing..."))
end
end
end
def pbHeadbutt(event=nil)
move = :HEADBUTT
movefinder = $Trainer.get_pokemon_with_move(move)
if !$DEBUG && !movefinder
pbMessage(_INTL("A Pokémon could be in this tree. Maybe a Pokémon could shake it."))
return false
end
if pbConfirmMessage(_INTL("A Pokémon could be in this tree. Would you like to use Headbutt?"))
speciesname = (movefinder) ? movefinder.name : $Trainer.name
pbMessage(_INTL("{1} used {2}!",speciesname,GameData::Move.get(move).name))
pbHiddenMoveAnimation(movefinder)
pbHeadbuttEffect(event)
return true
end
return false
end
HiddenMoveHandlers::CanUseMove.add(:HEADBUTT,proc { |move,pkmn,showmsg|
facingEvent = $game_player.pbFacingEvent
if !facingEvent || !facingEvent.name[/headbutttree/i]
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
next true
})
HiddenMoveHandlers::UseMove.add(:HEADBUTT,proc { |move,pokemon|
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
facingEvent = $game_player.pbFacingEvent
pbHeadbuttEffect(facingEvent)
})
#===============================================================================
# Rock Smash
#===============================================================================
def pbRockSmashRandomEncounter
if $PokemonEncounters.encounter_triggered?(:RockSmash, false, false)
pbEncounter(:RockSmash)
end
end
def pbRockSmash
move = :ROCKSMASH
movefinder = $Trainer.get_pokemon_with_move(move)
if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_ROCKSMASH,false) || (!$DEBUG && !movefinder)
pbMessage(_INTL("It's a rugged rock, but a Pokémon may be able to smash it."))
return false
end
if pbConfirmMessage(_INTL("This rock appears to be breakable. Would you like to use Rock Smash?"))
speciesname = (movefinder) ? movefinder.name : $Trainer.name
pbMessage(_INTL("{1} used {2}!",speciesname,GameData::Move.get(move).name))
pbHiddenMoveAnimation(movefinder)
return true
end
return false
end
HiddenMoveHandlers::CanUseMove.add(:ROCKSMASH,proc { |move,pkmn,showmsg|
next false if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_ROCKSMASH,showmsg)
facingEvent = $game_player.pbFacingEvent
if !facingEvent || !facingEvent.name[/smashrock/i]
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
next true
})
HiddenMoveHandlers::UseMove.add(:ROCKSMASH,proc { |move,pokemon|
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
facingEvent = $game_player.pbFacingEvent
if facingEvent
pbSmashEvent(facingEvent)
pbRockSmashRandomEncounter
end
next true
})
#===============================================================================
# Strength
#===============================================================================
def pbStrength
if $PokemonMap.strengthUsed
pbMessage(_INTL("Strength made it possible to move boulders around."))
return false
end
move = :STRENGTH
movefinder = $Trainer.get_pokemon_with_move(move)
if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_STRENGTH,false) || (!$DEBUG && !movefinder)
pbMessage(_INTL("It's a big boulder, but a Pokémon may be able to push it aside."))
return false
end
pbMessage(_INTL("It's a big boulder, but a Pokémon may be able to push it aside.\1"))
if pbConfirmMessage(_INTL("Would you like to use Strength?"))
speciesname = (movefinder) ? movefinder.name : $Trainer.name
pbMessage(_INTL("{1} used {2}!",speciesname,GameData::Move.get(move).name))
pbHiddenMoveAnimation(movefinder)
pbMessage(_INTL("{1}'s Strength made it possible to move boulders around!",speciesname))
$PokemonMap.strengthUsed = true
return true
end
return false
end
Events.onAction += proc { |_sender,_e|
facingEvent = $game_player.pbFacingEvent
pbStrength if facingEvent && facingEvent.name[/strengthboulder/i]
}
HiddenMoveHandlers::CanUseMove.add(:STRENGTH,proc { |move,pkmn,showmsg|
next false if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_STRENGTH,showmsg)
if $PokemonMap.strengthUsed
pbMessage(_INTL("Strength is already being used.")) if showmsg
next false
end
next true
})
HiddenMoveHandlers::UseMove.add(:STRENGTH,proc { |move,pokemon|
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!\1",pokemon.name,GameData::Move.get(move).name))
end
pbMessage(_INTL("{1}'s Strength made it possible to move boulders around!",pokemon.name))
$PokemonMap.strengthUsed = true
next true
})
#===============================================================================
# Surf
#===============================================================================
def pbSurf
return false if $game_player.pbFacingEvent
return false if $game_player.pbHasDependentEvents?
move = :SURF
movefinder = $Trainer.get_pokemon_with_move(move)
if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_SURF,false) || (!$DEBUG && !movefinder)
return false
end
if pbConfirmMessage(_INTL("The water is a deep blue...\nWould you like to surf on it?"))
speciesname = (movefinder) ? movefinder.name : $Trainer.name
pbMessage(_INTL("{1} used {2}!",speciesname,GameData::Move.get(move).name))
pbCancelVehicles
pbHiddenMoveAnimation(movefinder)
surfbgm = GameData::Metadata.get.surf_BGM
pbCueBGM(surfbgm,0.5) if surfbgm
pbStartSurfing
return true
end
return false
end
def pbStartSurfing
pbCancelVehicles
$PokemonEncounters.reset_step_count
$PokemonGlobal.surfing = true
pbUpdateVehicle
$PokemonTemp.surfJump = $MapFactory.getFacingCoords($game_player.x,$game_player.y,$game_player.direction)
pbJumpToward
$PokemonTemp.surfJump = nil
$game_player.check_event_trigger_here([1,2])
end
def pbEndSurf(_xOffset,_yOffset)
return false if !$PokemonGlobal.surfing
x = $game_player.x
y = $game_player.y
if $game_map.terrain_tag(x,y).can_surf && !$game_player.pbFacingTerrainTag.can_surf
$PokemonTemp.surfJump = [x,y]
if pbJumpToward(1,false,true)
$game_map.autoplayAsCue
$game_player.increase_steps
result = $game_player.check_event_trigger_here([1,2])
pbOnStepTaken(result)
end
$PokemonTemp.surfJump = nil
return true
end
return false
end
def pbTransferSurfing(mapid,xcoord,ycoord,direction=$game_player.direction)
pbFadeOutIn {
$game_temp.player_new_map_id = mapid
$game_temp.player_new_x = xcoord
$game_temp.player_new_y = ycoord
$game_temp.player_new_direction = direction
$scene.transfer_player(false)
$game_map.autoplay
$game_map.refresh
}
end
Events.onAction += proc { |_sender,_e|
next if $PokemonGlobal.surfing
next if GameData::MapMetadata.exists?($game_map.map_id) &&
GameData::MapMetadata.get($game_map.map_id).always_bicycle
next if !$game_player.pbFacingTerrainTag.can_surf_freely
next if !$game_map.passable?($game_player.x,$game_player.y,$game_player.direction,$game_player)
pbSurf
}
HiddenMoveHandlers::CanUseMove.add(:SURF,proc { |move,pkmn,showmsg|
next false if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_SURF,showmsg)
if $PokemonGlobal.surfing
pbMessage(_INTL("You're already surfing.")) if showmsg
next false
end
if $game_player.pbHasDependentEvents?
pbMessage(_INTL("It can't be used when you have someone with you.")) if showmsg
next false
end
if GameData::MapMetadata.exists?($game_map.map_id) &&
GameData::MapMetadata.get($game_map.map_id).always_bicycle
pbMessage(_INTL("Let's enjoy cycling!")) if showmsg
next false
end
if !$game_player.pbFacingTerrainTag.can_surf_freely ||
!$game_map.passable?($game_player.x,$game_player.y,$game_player.direction,$game_player)
pbMessage(_INTL("No surfing here!")) if showmsg
next false
end
next true
})
HiddenMoveHandlers::UseMove.add(:SURF,proc { |move,pokemon|
$game_temp.in_menu = false
pbCancelVehicles
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
surfbgm = GameData::Metadata.get.surf_BGM
pbCueBGM(surfbgm,0.5) if surfbgm
pbStartSurfing
next true
})
#===============================================================================
# Sweet Scent
#===============================================================================
def pbSweetScent
if $game_screen.weather_type != :None
pbMessage(_INTL("The sweet scent faded for some reason..."))
return
end
viewport = Viewport.new(0,0,Graphics.width,Graphics.height)
viewport.z = 99999
count = 0
viewport.color.red = 255
viewport.color.green = 0
viewport.color.blue = 0
viewport.color.alpha -= 10
alphaDiff = 12 * 20 / Graphics.frame_rate
loop do
if count==0 && viewport.color.alpha<128
viewport.color.alpha += alphaDiff
elsif count>Graphics.frame_rate/4
viewport.color.alpha -= alphaDiff
else
count += 1
end
Graphics.update
Input.update
pbUpdateSceneMap
break if viewport.color.alpha<=0
end
viewport.dispose
enctype = $PokemonEncounters.encounter_type
if enctype < 0 || !$PokemonEncounters.encounter_possible_here? ||
!pbEncounter(enctype)
pbMessage(_INTL("There appears to be nothing here..."))
end
end
HiddenMoveHandlers::CanUseMove.add(:SWEETSCENT,proc { |move,pkmn,showmsg|
next true
})
HiddenMoveHandlers::UseMove.add(:SWEETSCENT,proc { |move,pokemon|
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
pbSweetScent
next true
})
#===============================================================================
# Teleport
#===============================================================================
HiddenMoveHandlers::CanUseMove.add(:TELEPORT,proc { |move,pkmn,showmsg|
if !GameData::MapMetadata.exists?($game_map.map_id) ||
!GameData::MapMetadata.get($game_map.map_id).outdoor_map
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
healing = $PokemonGlobal.healingSpot
healing = GameData::Metadata.get.home if !healing # Home
if !healing
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
if $game_player.pbHasDependentEvents?
pbMessage(_INTL("It can't be used when you have someone with you.")) if showmsg
next false
end
next true
})
HiddenMoveHandlers::ConfirmUseMove.add(:TELEPORT,proc { |move,pkmn|
healing = $PokemonGlobal.healingSpot
healing = GameData::Metadata.get.home if !healing # Home
next false if !healing
mapname = pbGetMapNameFromId(healing[0])
next pbConfirmMessage(_INTL("Want to return to the healing spot used last in {1}?",mapname))
})
HiddenMoveHandlers::UseMove.add(:TELEPORT,proc { |move,pokemon|
healing = $PokemonGlobal.healingSpot
healing = GameData::Metadata.get.home if !healing # Home
next false if !healing
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
pbFadeOutIn {
$game_temp.player_new_map_id = healing[0]
$game_temp.player_new_x = healing[1]
$game_temp.player_new_y = healing[2]
$game_temp.player_new_direction = 2
$scene.transfer_player
$game_map.autoplay
$game_map.refresh
}
pbEraseEscapePoint
next true
})
#===============================================================================
# Waterfall
#===============================================================================
def pbAscendWaterfall
return if $game_player.direction != 8 # Can't ascend if not facing up
terrain = $game_player.pbFacingTerrainTag
return if !terrain.waterfall && !terrain.waterfall_crest
oldthrough = $game_player.through
oldmovespeed = $game_player.move_speed
$game_player.through = true
$game_player.move_speed = 2
loop do
$game_player.move_up
terrain = $game_player.pbTerrainTag
break if !terrain.waterfall && !terrain.waterfall_crest
end
$game_player.through = oldthrough
$game_player.move_speed = oldmovespeed
end
def pbDescendWaterfall
return if $game_player.direction != 2 # Can't descend if not facing down
terrain = $game_player.pbFacingTerrainTag
return if !terrain.waterfall && !terrain.waterfall_crest
oldthrough = $game_player.through
oldmovespeed = $game_player.move_speed
$game_player.through = true
$game_player.move_speed = 2
loop do
$game_player.move_down
terrain = $game_player.pbTerrainTag
break if !terrain.waterfall && !terrain.waterfall_crest
end
$game_player.through = oldthrough
$game_player.move_speed = oldmovespeed
end
def pbWaterfall
move = :WATERFALL
movefinder = $Trainer.get_pokemon_with_move(move)
if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_WATERFALL,false) || (!$DEBUG && !movefinder)
pbMessage(_INTL("A wall of water is crashing down with a mighty roar."))
return false
end
if pbConfirmMessage(_INTL("It's a large waterfall. Would you like to use Waterfall?"))
speciesname = (movefinder) ? movefinder.name : $Trainer.name
pbMessage(_INTL("{1} used {2}!",speciesname,GameData::Move.get(move).name))
pbHiddenMoveAnimation(movefinder)
pbAscendWaterfall
return true
end
return false
end
Events.onAction += proc { |_sender,_e|
terrain = $game_player.pbFacingTerrainTag
if terrain.waterfall
pbWaterfall
elsif terrain.waterfall_crest
pbMessage(_INTL("A wall of water is crashing down with a mighty roar."))
end
}
HiddenMoveHandlers::CanUseMove.add(:WATERFALL,proc { |move,pkmn,showmsg|
next false if !pbCheckHiddenMoveBadge(Settings::BADGE_FOR_WATERFALL,showmsg)
if !$game_player.pbFacingTerrainTag.waterfall
pbMessage(_INTL("Can't use that here.")) if showmsg
next false
end
next true
})
HiddenMoveHandlers::UseMove.add(:WATERFALL,proc { |move,pokemon|
if !pbHiddenMoveAnimation(pokemon)
pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name))
end
pbAscendWaterfall
next true
})

View File

@@ -0,0 +1,138 @@
#===============================================================================
# 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)
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
if Settings::FISHING_AUTO_HOOK || rand(100) < hookChance
pbFishingEnd
pbMessageDisplay(msgWindow,_INTL("Landed a Pokémon!")) if !Settings::FISHING_AUTO_HOOK
$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)
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 !Settings::FISHING_AUTO_HOOK && numFrame > frames
numFrame += 1
end
return false
end

View File

@@ -0,0 +1,542 @@
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

View File

@@ -0,0 +1,403 @@
#===============================================================================
# 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_bably_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
}

View File

@@ -0,0 +1,613 @@
#===============================================================================
# This class is designed to favor different values more than a uniform
# random generator does
#===============================================================================
class AntiRandom
def initialize(size)
@old = []
@new = []
@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
#===============================================================================
#
#===============================================================================
module DungeonMaze
TILE_WIDTH = 13
TILE_HEIGHT = 13
MINWIDTH = 5
MINHEIGHT = 4
MAXWIDTH = 11
MAXHEIGHT = 10
None = 0
TurnLeft = 1
TurnRight = 2
Turn180 = 3
def self.paintRect(tile, x, y, width, height) # paints a room
for j in 0...height
for i in 0...width
tile[(y + j) * TILE_WIDTH + (x + i)] = 3
end
end
end
def self.paintTile(dungeon, dstX, dstY, tile, rotation) # paints a tile
case rotation
when None
for y in 0...TILE_HEIGHT
for x in 0...TILE_WIDTH
dungeon[x + dstX, y + dstY] = tile[y * TILE_WIDTH + x]
end
end
when TurnLeft
for y in 0...TILE_HEIGHT
for x in 0...TILE_WIDTH
dungeon[y + dstX , TILE_WIDTH - 1 - x + dstY] = tile[y * TILE_WIDTH + x]
end
end
when TurnRight
for y in 0...TILE_HEIGHT
for x in 0...TILE_WIDTH
dungeon[TILE_HEIGHT - 1 - y + dstX, x + dstY] = tile[y * TILE_WIDTH + x]
end
end
when Turn180
for y in 0...TILE_HEIGHT
for x in 0...TILE_WIDTH
dungeon[TILE_WIDTH - 1 - x + dstX, TILE_HEIGHT - 1 - y + dstY] = tile[y * TILE_WIDTH + x]
end
end
end
end
def self.paintCell(dungeon, xDst, yDst, tile, rotation)
return false if !tile
paintTile(dungeon, xDst, yDst, tile, rotation)
return false if rand(100) < 30
# Generate a randomly placed room
width = rand(MINWIDTH..MAXWIDTH)
height = rand(MINHEIGHT..MAXHEIGHT)
return false if width <= 0 || height <= 0
centerX = TILE_WIDTH / 2 + rand(5) - 2
centerY = TILE_HEIGHT / 2 + rand(5) - 2
x = centerX - (width / 2)
y = centerY - (height / 2)
rect = [x, y, width, height]
rect[0] = 1 if rect[0] < 1
rect[1] = 2 if rect[1] < 2
rect[0] = TILE_WIDTH - 1 - width if rect[0] + width > TILE_WIDTH - 1
rect[1] = TILE_HEIGHT - 1 - height if rect[0] + height > TILE_HEIGHT - 1
dungeon.paint(rect, xDst, yDst)
return true
end
def self.generateTiles
tiles = []
for i in 0...6
tiles[i] = []
for j in 0...TILE_WIDTH * TILE_HEIGHT
tiles[i][j] = 0
end
end
paintRect(tiles[0], 5, 0, 3, 10) # N
paintRect(tiles[1], 5, 0, 3, 8) # N E
paintRect(tiles[1], 5, 5, 8, 3)
paintRect(tiles[2], 5, 0, 3, 8) # N W E
paintRect(tiles[2], 0, 5, 13, 3)
paintRect(tiles[3], 5, 0, 3, 13) # N S
paintRect(tiles[4], 5, 0, 3, 13)
paintRect(tiles[4], 0, 5, 13, 3)
realtiles = [
[tiles[4], None], # N W E S
[tiles[2], Turn180], # W E S
[tiles[2], TurnRight], # N E S
[tiles[1], TurnRight], # E S
[tiles[2], TurnLeft], # N W S
[tiles[1], Turn180], # W S
[tiles[3], None], # N S
[tiles[0], Turn180], # S
[tiles[2], None], # N W E
[tiles[3], TurnLeft], # W E
[tiles[1], None], # N E
[tiles[0], TurnRight], # E
[tiles[1], TurnLeft], # N W
[tiles[0], TurnLeft], # W
[tiles[0], None], # N
[nil, None]
]
return realtiles
end
end
module EdgeMasks
North = 1
West = 2
East = 4
South = 8
Visited = 16
end
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
class NodeListElement
attr_accessor :x, :y
def initialize(x, y)
@x = x
@y = y
end
end
class Maze
attr_accessor :cellWidth, :cellHeight, :nodeWidth, :nodeHeight
@@dirs = [EdgeMasks::North, EdgeMasks::South, EdgeMasks::East, EdgeMasks::West]
def initialize(cw, ch)
@nodes = []
@cells = []
raise ArgumentError.new if cw == 0 || ch == 0
@cellWidth = cw
@cellHeight = ch
@nodeWidth = cw + 1
@nodeHeight = ch + 1
for i in 0...@nodeWidth * @nodeHeight
@nodes[i] = MazeNode.new
end
for i in 0...cw * ch
@cells[i] = 0
end
clearAllEdges()
clearAllCells()
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 setEdgeNode(x, y, edge)
return if x < 0 || x >= nodeWidth || y < 0 || y >= nodeHeight
@nodes[y * nodeWidth + x].setEdge(edge)
e = 0
nx = 0
ny = 0
case edge
when EdgeMasks::North
e = EdgeMasks::South
nx = x
ny = y - 1
when EdgeMasks::South
e = EdgeMasks::North
nx = x
ny = y + 1
when EdgeMasks::East
e = EdgeMasks::West
nx = x + 1
ny = y
when EdgeMasks::West
e = EdgeMasks::East
nx = x - 1
ny = y
else
return
end
return if nx < 0 || ny < 0 || nx >= nodeWidth || ny >= nodeHeight
@nodes[ny * nodeWidth + nx].setEdge(e)
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 = 0
ny = 0
case edge
when EdgeMasks::North
e = EdgeMasks::South
nx = x
ny = y - 1
when EdgeMasks::South
e = EdgeMasks::North
nx = x
ny = y + 1
when EdgeMasks::East
e = EdgeMasks::West
nx = x + 1
ny = y
when EdgeMasks::West
e = EdgeMasks::East
nx = x - 1
ny = y
else
raise ArgumentError.new
end
return if nx < 0 || ny < 0 || nx >= nodeWidth || ny >= nodeHeight
@nodes[ny * nodeWidth + nx].clearEdge(e)
end
def isBlockedNode?(x, y)
return false if x < 0 || y < 0 || x >= nodeWidth || y >= nodeHeight
return @nodes[y * nodeWidth + x].isBlocked?
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 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 setAllEdges
for c in 0...nodeWidth * nodeHeight
@nodes[c].set
end
end
def clearAllEdges
for c in 0...nodeWidth * nodeHeight
@nodes[c].clear
end
end
def clearAllCells
for c in 0...cellWidth * cellHeight
@cells[c] = 0
end
end
def setVisited(x, y)
return if x < 0 || y < 0 || x >= cellWidth || x >= cellHeight
@cells[y * cellWidth + x] |= EdgeMasks::Visited
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 clearVisited(x, y)
return if x < 0 || y < 0 || x >= cellWidth || x >= cellHeight
@cells[y * cellWidth + x] &=~EdgeMasks::Visited
end
def randomDir
return @@dirs[rand(4)]
end
def buildMazeWall(x, y, dir, len)
return if isBlockedNode?(x, y)
wx = x
wy = y
len.times do
ox = wx
oy = wy
wy -= 1 if dir == EdgeMasks::North
wx -= 1 if dir == EdgeMasks::West
wx += 1 if dir == EdgeMasks::East
wy += 1 if dir == EdgeMasks::South
if isBlockedNode?(wx, wy)
setEdgeNode(ox, oy, dir)
return
end
setEdgeNode(ox,oy,dir)
end
end
def generateWallGrowthMaze(minWall = nil, maxWall = nil)
minWall = 0 if !minWall
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 = @@dirs.shuffle!
for c in 0...4
d = dirs[c]
cx = 0
cy = 0
case d
when EdgeMasks::North
cx = x
cy = y - 1
when EdgeMasks::South
cx = x
cy = y + 1
when EdgeMasks::East
cx = x + 1
cy = y
when EdgeMasks::West
cx = x - 1
cy = y
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
sx = rand(cellWidth)
sy = rand(cellHeight)
setAllEdges()
recurseDepthFirst(sx, sy, 0)
end
end
class Dungeon
attr_accessor :width, :height
XBUFFER = 8
YBUFFER = 6
class DungeonTable
def initialize(dungeon)
@dungeon = dungeon
end
def xsize; @dungeon.width; end
def ysize; @dungeon.height; end
def [](x, y)
[1, 2, 3, 2][@dungeon[x, y]] # Void, room floor, wall, corridor floor
end
end
def initialize(width, height)
@width = width
@height = height
@array = []
end
def clear
for i in 0...width * height
@array[i] = 0
end
end
def write
ret = ""
i = 0
for y in 0...@height
for x in 0...@width
ret += [" ", ".", "~", ","][value(x, y)] # Void, room floor, wall, corridor floor
i += 1
end
ret += "\r\n"
end
return ret
end
def [](x, y)
@array[y * @width + x]
end
def []=(x, y, value)
@array[y * @width + x] = value
end
def value(x, y)
return 0 if x < 0 || y < 0 || x >= @width || y >= @height
@array[y * @width + x]
end
def get(x, y)
return false if x < 0 || y < 0 || x >= @width || y >= @height
@array[y * @width + x] != 0
end
def isWall?(x, y)
if value(x, y) == 0 # This tile is void
v1 = value(x, y + 1)
return true if v1 == 1 || v1 == 3 # The tile below is room floor/corridor floor
if v1 == 0 # The tile below is void
v1 = value(x, y + 2)
return true if v1 == 1 || v1 == 3 # The tile below that is room floor/corridor floor
end
end
return false
end
def isRoom?(x, y)
if value(x, y) == 1 # This tile is a room floor
return false if value(x - 1, y - 1) == 3
return false if value( x, y - 1) == 3
return false if value(x + 1, y - 1) == 3
return false if value(x - 1, y) == 3
return false if value(x + 1, y) == 3
return false if value(x - 1, y + 1) == 3
return false if value( x, y + 1) == 3
return false if value(x + 1, y + 1) == 3
return true # No surrounding tiles are corridor floor
end
return false
end
def generate
self.clear
maxWidth = @width - XBUFFER * 2
maxHeight = @height - YBUFFER * 2
cellWidth = DungeonMaze::TILE_WIDTH
cellHeight = DungeonMaze::TILE_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 + XBUFFER, y + YBUFFER] = 1 # Make all tiles room floor
end
end
return
end
maze = Maze.new(maxWidth / cellWidth, maxHeight / cellHeight)
maze.generateDepthFirstMaze()
tiles = DungeonMaze.generateTiles()
roomcount = 0
for y in 0...maxHeight / cellHeight
for x in 0...maxWidth / cellWidth
tile = maze.getEdgePattern(x, y)
if DungeonMaze.paintCell(self, XBUFFER + x * cellWidth, YBUFFER + y * cellHeight,
tiles[tile][0], tiles[tile][1])
roomcount += 1
end
end
end
if roomcount == 0
# Handle situation where no rooms were generated
for x in 0...maxWidth
for y in 0...maxHeight
self[x + XBUFFER, y + YBUFFER] = 1 # Make all tiles room floor
end
end
end
# Generate walls
for y in 0...@height
for x in 0...@width
self[x, y] = 2 if isWall?(x, y) # Make appropriate tiles wall tiles
end
end
end
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::NeighborsToTiles[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
def paint(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] = 1 # room tile
end
end
end
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
end
# Get a random room tile that isn't too close to a corridor (to avoid blocking
# a room's entrance)
def 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
Events.onMapCreate += proc { |_sender, e|
mapID = e[0]
map = e[1]
next if !GameData::MapMetadata.exists?(mapID) ||
!GameData::MapMetadata.get(mapID).random_dungeon
# this map is a randomly generated dungeon
dungeon = Dungeon.new(map.width, map.height)
dungeon.generate
dungeon.generateMapInPlace(map)
roomtiles = []
# Reposition events
for event in map.events.values
tile = pbRandomRoomTile(dungeon, roomtiles)
if tile
event.x = tile[0]
event.y = tile[1]
end
end
# Override transfer X and Y
tile = pbRandomRoomTile(dungeon, roomtiles)
if tile
$game_temp.player_new_x = tile[0]
$game_temp.player_new_y = tile[1]
end
}