Random Weather v7.0
By OS
For those who don't remember, I wrote a somewhat decent Random Weather generator earlier this year (up to Version 3.0) that had some cool features like Memorizing Weather, allowing Inner Maps to be free of weather affects without eventing, etc. I have been trying to make the perfect update to that script to compete with other Random Weather Gens built into Time Scripts that I have seen floating around. I thought I had finally created the perfect update, but it had a bug in it that I couldn't find, so Version 4.0 was trashed, and I wrote 5.0. 5.5 was created soon after to be compatible with my Game_Time class (unreleased), and found a bug I hadn't noticed before. So I rewrote the script entirely (6.0) and was planning to release that one, but it didn't run as smoothly as the earlier versions, so I made 6.1, which ran smoother, but felt obsolete still. Now I am making 7.0! I will release this version, but first I need features so it doesn't feel so empty. Of course there will be a Lite version with only the basic features, but otherwise I want to fill it up as much as possible.
Accepted Features go here:
- Compatible with all scripts, including Ccoa's Weather -- COMPLETE
- OS Game_Time allows more features, but is not mandatory! -- COMPLETE (7.0 only)
- Regionalized Weather -- COMPLETE
- Inner Map Support -- COMPLETE
- Weather Tags to easily find which weather is active and how powerful it is (good for Events!)
- Realistic Weather Changes (Rain goes to Storm, Snow to Blizzard, etc.) -- COMPLETED
- Weather Links -- use to connect weather types for Realistic Weather Changes -- COMPLETED
- Random Intervals between changes
- Lite Version with less features
- Easy to Use, minimal lag -- SO FAR, PERFECT
- Interior Maps have Weather on Panorama Layer (submitted by Prexus) -- COMPLETED
- Predictable Weather (for In-Game prediction of future meteorological events) (submitted by Venetia)
- Seasonal Weather (submitted by Venetia)
- World Class -- Holds Game_Time and Game_Weather in one Global Variable, and will have the capability of holding other scripts that affect the Map visually or are updated each frame while the player is on the map. -- COMPLETED (7.0 Only)
- Weather Machine Feature -- allow player to alter weather through various items (can be taken out of/added to the system easily)
- Weather Spells -- allow player to alter weather with skills (very easy to set up)
- Weather-Based events -- allow events to activate while several conditions are met, including Time (down to the minute), Weather, Weather's Power, and a [maybe]User Defined[/maybe] condition...
- Plug-In Capable -- allow future plug ins to the script that can be added/deleted easily -- COMPLETED
- Physical Effects Plug-In -- causes players to be affected by weather effects (i.e. rain causes the player to slow down, slip, or slide depending on surfaces which are set with Terrain Tags)
- Stat Effects Plug-In -- weather effects player and monster stats and states.
First place Game_Time above Main.
Then place above Game_Time Game_Weather
And finally place Game_World on top of those two.
And to make it all work place this module anywhere above Main. (all three of the otehr scripts must be above Main and below Scene_Debug!)
NOTE: The Months and Days I used for samples are from a book by Tamera Pierce called "The Will of the Empress".
Code:
class Game_Time
def initialize
#Current Time = Hour, Minute, Second
@hour, @minute, @second = OS::T_StartHour, OS::T_StartMinute, 0
#Current Time = Day, Month, Year
@day, @month, @year = OS::T_StartDay, OS::T_StartMonth, OS::T_StartYear
#Speeds
@sbase = OS::T_Speed
@sfast = OS::T_Speed * 10
@sslow = OS::T_Speed / 10
@speed = @sbase
#Switches and 0's
@frame = 0
@reverse = false
@pause = false
@pm = false
#Tint
@tone = create_new_time_tone
@tone += weather_tone_modifier(nil)
$game_screen.start_tone_change(Tone.new(@tone,@tone,@tone),1)
end
def time?
string = sprintf("%02d:%02d:%02d", hour?, @minute, @second)
string += " #{@month}-#{@day}-#{@year}"
return string
end
def hour?(base=12)
if base == 24
return @hour
elsif base == 12
return @hour > OS::T_MaxHours ? @hour - 12 : @hour
else
return 0
end
end
def create_new_time_tone
case @hour
when 1
return -90
when 2
return -80
when 3
return -70
when 4
return -60
when 5
return -50
when 6
return -40
when 7
return -30
when 8
return -12
when 9
return -10
when 10
return 0
when 11
return 10
when 12
return 20
when 13
return 10
when 14
return 0
when 15
return -10
when 16
return -20
when 17
return -30
when 18
return -40
when 19
return -50
when 20
return -60
when 21
return -70
when 22
return -80
when 23
return -90
when 24
return -100
end
end
def weather_tone_modifier(type)
return 0 if type == nil
return $game_world.weather.tone_mod(type)
end
def update
if @reverse
update_back
else
update_forward
end
return
end
def update_back
@frame += 1
if @frame == @speed
@frame = 0
@second -= 1
end
if @second == 0
@second = OS::T_MaxSeconds
@minute -= 1
end
if @minute == 0
@minute = OS::T_MaxMinutes
@hour -= 1
end
if @hour == 0
@hour = OS::T_MaxHours
end
type = $game_world.weather.type
power = $game_world.weather.power
$game_screen.weather(type, power, rand(19)+1)
@tone = create_new_time_tone
@tone += weather_tone_modifier(type)
$game_screen.start_tone_change(Tone.new(@tone,@tone,@tone),1)
return
end
def update_forward
@frame += 1
if @frame == @speed
@frame = 0
@second += 1
end
if @second == OS::T_MaxSeconds
@second = 0
@minute += 1
end
if @minute == OS::T_MaxMinutes
@minute = 1
@hour += 1
end
if @hour == OS::T_MaxHours
@hour = 1
@day = OS::T_Days[OS::T_Days.index(@day) + 1]
if @day == OS::T_Days[OS::T_Days.size - 1]
@day = OS::T_Days[0]
@month = OS::T_Months[OS::T_Months.index(@month)+1]
end
if @month == OS::T_Months[OS::T_Months.size - 1]
@month = OS::T_Months[0]
@year += 1
end
end
type = $game_world.weather.type
power = $game_world.weather.power
$game_screen.weather(type, power, rand(19)+1)
@tone = create_new_time_tone
@tone += weather_tone_modifier(type)
$game_screen.start_tone_change(Tone.new(@tone,@tone,@tone),1)
return
end
end
Then place above Game_Time Game_Weather
Code:
class Game_Weather
attr_accessor :type, :power
def initialize
@type = 0
@power = 0
@map_id = $game_map.map_id
@memorized = [0,0]
@count = 0
end
def update
@map_id = $game_map.map_id if @map_id != $game_map.map_id
alter_weather
call_plugins
return
end
def alter_weather
if OS::W_InnerMaps.include(@map_id)
@memorize = [@type,@power]
@type = 0
@power = 0
return
end
@count += 1
if @count > rand(19) + 1
@count = 0
if @type == 0
randomize
return
else
if rand(9) + 1 > 5
upgrade
return
elsif rand(9) + 1 > 5
downgrade
return
else
return
end
end
return
end
end
def call_plugins
return
end
def tone_mod(type)
if type == 1 || type == 2 || type == 3 # Rain, Snow, or Storm
return -10
else
return 0
end
end
def randomize
i = 0
while i != nil
if rand(9) + 1 > 5
@type = OS::Regions[@map_id][i]
@power = rand(19) + 1
i = nil
end
i += 1
if i > OS::W_Regions[@map_id].size - 1
i = 0
end
end
return
end
def upgrade
if @power > 35
if OS::W_Upgrades.keys.include(OS::W_Regions[@map_id][@type])
ntype = OS::W_Upgrades[@type]
if OS::W_Regions[@map_id].include?(ntype)
@type = ntype
@power = rand(9) + 1
return
end
end
end
if rand(9) + 1 > 5
@power += rand(9) + 1
else
@power += rand(rand(9) + 1) + 1
end
if @power > 50
case rand(2)
when 0
@power = 50
when 1
@power = 45
else
@power = 40
end
end
return
end
def downgrade
if @power < 15
if OS::W_Downgrades.keys.include(OS::W_Regions[@map_id][@type])
ntype = OS::W_Downgrades[@type]
if OS::W_Regions[@map_id].include?(ntype)
@type = ntype
@power = rand(49) + 1
while @power < 30
@power += rand(4) + 1
end
return
end
end
end
if rand(9) + 1 > 5
@power -= rand(9) + 1
else
@power -= rand(rand(9) + 1) + 1
end
if @power < 0
case rand(2)
when 0
@power = 0
when 1
@power = rand(9) + 1
else
@power = rand(19) - rand(9)
end
end
return
end
end
#===============================================================================
# Call Plugins
#
# Plug-Ins work by aliasing the Call Plugins Method. That is what makes Plug-Ins
# so easy to install. Each plug-in will come with an aliased call_plugins method.
# I will also have Plug-In packs that will alter the method only once for several
# plug-ins.
#===============================================================================
And finally place Game_World on top of those two.
Code:
class Game_World
attr_reader :time, :weather
def initialize
@time = Game_Time.new
@weather = Game_Weather.new
end
def update
@time.update
return
end
def dispose
return
end
def time?
return @time.time?
end
end
And to make it all work place this module anywhere above Main. (all three of the otehr scripts must be above Main and below Scene_Debug!)
Code:
module OS
W_InnerMaps = [2]
W_Regions = {
#Map_ID => [type,type,type,etc...]
1 => [1,2,3]
}
W_Upgrades = {
#StartType => EndType
1 => 2
}
W_Downgrades = {
#StartType => EndType
2 => 1
}
T_StartHour = 5
T_StartMinute = 58
T_Speed = Graphics.frame_rate/20
T_MaxSeconds = 60
T_MaxMinutes = 60
T_MaxHours = 24
T_StartYear = 1654
T_Months = [
"Wolf Moon",
"Storm Moon",
"Carp Moon",
"Seed Moon",
"Goose Moon",
"Rose Moon",
"Mead Moon",
"Wort Moon",
"Barley Moon",
"Blood Moon",
"Snow Moon",
"Hearth Moon",
]
T_Days = [
"Sunsday",
"Moonsday",
"Starsday",
"Earthsday",
"Airsday",
"Firesday",
"Watersday"
]
T_StartMonth = "Wolf Moon"
T_StartDay = "Sunsday"
end
To fully install, you must do the following:
In Scene_Title's command_new_game method, underneath the $game_* = Game_* lines add $game_world = Game_World.new
Then, in Scene_Map, in the main method, after @message_window.dispose, add $game_world.dispose. This isn't necessary just yet, but will be used with plug-ins later.
Finally, go to Scene_Map's update method, and below $game_system.update, use $game_world.update.
There you go! It should be all ready for use and new plug-ins!
NOTE REGARDING PLUG-INS:
Some of the originally planned features decided before the Plug-In Feature was thought of will be turned into Plug-Ins to allow for a more customizable engine.
If you have any ideas for features let me know. When I think there are enough for 7.0, I'll begin on adding the features to the actual script. I'll keep accepting features after the first release for 7.1 and so on.
Thanks to those who supported my earlier engines, and thanks to whomever supports this one!
~OS
PLUG-INS:
Code:
module RPG
class Weather
################################################################################
def initialize(viewport = nil, z = 1000)
@type = 0
@max = 0
@ox = 0
@oy = 0
@z = z
color1 = Color.new(255, 255, 255, 255)
color2 = Color.new(255, 255, 255, 128)
@rain_bitmap = Bitmap.new(7, 56)
for i in 0..6
@rain_bitmap.fill_rect(6-i, i*8, 1, 8, color1)
end
@storm_bitmap = Bitmap.new(34, 64)
for i in 0..31
@storm_bitmap.fill_rect(33-i, i*2, 1, 2, color2)
@storm_bitmap.fill_rect(32-i, i*2, 1, 2, color1)
@storm_bitmap.fill_rect(31-i, i*2, 1, 2, color2)
end
@snow_bitmap = Bitmap.new(6, 6)
@snow_bitmap.fill_rect(0, 1, 6, 4, color2)
@snow_bitmap.fill_rect(1, 0, 4, 6, color2)
@snow_bitmap.fill_rect(1, 2, 4, 2, color1)
@snow_bitmap.fill_rect(2, 1, 2, 4, color1)
@sprites = []
for i in 1..40
sprite = Sprite.new(viewport)
sprite.z = @z
sprite.visible = false
sprite.opacity = 0
@sprites.push(sprite)
end
end
################################################################################
def dispose
for sprite in @sprites
sprite.dispose
end
@rain_bitmap.dispose
@storm_bitmap.dispose
@snow_bitmap.dispose
end
################################################################################
def type=(type)
return if @type == type
@type = type
case @type
when 1
bitmap = @rain_bitmap
when 2
bitmap = @storm_bitmap
when 3
bitmap = @snow_bitmap
else
bitmap = nil
end
for i in 1..40
sprite = @sprites[i]
if sprite != nil
sprite.visible = (i <= @max)
sprite.bitmap = bitmap
end
end
end
################################################################################
def ox=(ox)
return if @ox == ox;
@ox = ox
for sprite in @sprites
sprite.ox = @ox
end
end
def oy=(oy)
return if @oy == oy;
@oy = oy
for sprite in @sprites
sprite.oy = @oy
end
end
################################################################################
def max=(max)
return if @max == max;
@max = [[max, 0].max, 40].min
for i in 1..40
sprite = @sprites[i]
if sprite != nil
sprite.visible = (i <= @max)
end
end
end
################################################################################
def update
return if @type == 0
for i in 1..@max
sprite = @sprites[i]
if sprite == nil
break
end
if @type == 1
sprite.x -= 2
sprite.y += 16
sprite.opacity -= 8
end
if @type == 2
sprite.x -= 8
sprite.y += 16
sprite.opacity -= 12
end
if @type == 3
sprite.x -= 2
sprite.y += 8
sprite.opacity -= 8
end
x = sprite.x - @ox
y = sprite.y - @oy
if sprite.opacity < 64 or x < -50 or x > 750 or y < -300 or y > 500
sprite.x = rand(800) - 50 + @ox
sprite.y = rand(800) - 200 + @oy
sprite.opacity = 255
end
end
if OS::W_Inners.include?($game_map.map_id)
for i in 0..@sprites.size - 1
@sprites[i].z = -999
end
else
for i in 0..@sprites.size - 1
@sprites[i].z = 1000
end
end
end
################################################################################
attr_reader :type
attr_reader :max
attr_reader :ox
attr_reader :oy
attr_reader :z
end
end
Code:
module OS
W_Inners = [id]
end
Just plug the script into your editor below my Weather Generator. Edit the W_Regions list as necessary.
I added a feature for scriptors who want to show the current region in a window. Use the OS::Weather.region? method to get a string containing the region's name.
Code:
module OS
W_Regions = {
#Region => [[Maps],[Weathers]]
"Plains" => [[1,2],[1,2,3]]
}
class Weather
# Initialize
def initialize
# Type
@type = 0
# Power
@power = 0
# Memorized Weather Effects
@memorized = []
# Weathers available in the current map
@weathers = []
# The current map id
@map_id = 0
# Randomly selected frame count using W_MacCount
@count = rand(W_MaxCount - 1) + 1
# Weather Affects Allowed
@allowed = true
# Regional Data
for i in 0..W_Regions.keys.size - 1
if W_Regions.values[i][0].includes?(@map_id)
reg = W_Regions.values[i]
@region = [W_Regions.keys[i],reg[1]]
break
end
end
end
# Update
def update
# If weather effects are allowed
if @allowed == true
# And if the map id is different than the current map
if @map_id != $game_map.map_id
# Fix the map id and current weathers
@map_id = $game_map.map_id
@weathers = @region[1]
end
# Count Down
@count -= 1
# If count reaches 0
if @count <= 0
# Reset Count randomly
@count = rand(W_MaxCount - 1) + 1
# Generate Weather
gen_weather
end
# Fixes power so it isn't above 50
fix_power
# Fix Tone (Not perfect yet)
fix_tone
# Set weather effects
$game_screen.weather(@type,@power,rand(19) + 1)
end
return
end
end
# Region?
def region?
return @region[0]
end
end
NOT COMPATIBLE WITH REGIONAL WEATHER AT THIS TIME!!!!!!!!
Code:
module OS
W_Seasons = {
#Region => [[Maps],[Weathers]]
"Summer" => [],
"Autumn" => [1,2],
"Winter" => [3],
"Spring" => [1,2]
}
class Weather
# Initialize
def initialize
# Type
@type = 0
# Power
@power = 0
# Memorized Weather Effects
@memorized = []
# Weathers available in the current map
@weathers = []
# The current map id
@map_id = 0
# Randomly selected frame count using W_MacCount
@count = rand(W_MaxCount - 1) + 1
# Weather Affects Allowed
@allowed = true
# Seasonal Data
sea = W_Seasons[current_season?]
@season = [current_season?,sea]
end
# Update
def update
# If weather effects are allowed
if @allowed == true
# And if the map id is different than the current map
if @map_id != $game_map.map_id
# Fix the map id and current weathers and Season
sea = W_Seasons[current_season?]
@season = [current_season?,sea]
@map_id = $game_map.map_id
@weathers = @season[1]
end
# Count Down
@count -= 1
# If count reaches 0
if @count <= 0
# Reset Count randomly
@count = rand(W_MaxCount - 1) + 1
# Generate Weather
gen_weather
end
# Fixes power so it isn't above 50
fix_power
# Fix Tone (Not perfect yet)
fix_tone
# Set weather effects
$game_screen.weather(@type,@power,rand(19) + 1)
end
return
end
end
# Current Season?
def current_season?
if $game_time != nil
return $game_time.season?
elsif $game_world != nil
return $game_world.time.season?
else
return W_Season.keys[rand(W_Season.size - 1)]
end
end
# Season?
def season?
return @season[0]
end
end