You all know Blizz's old time system, the ATES. Well, I saw it in his dev pack, and saw that he had never finished implementing all the planned features. So, I decided to finish it for him. This system adds a time and weather system to games that can be turned on and off at will. Every aspect of the script is configurable, from the time system, to the weather system, and even the clock hud.
The time system allows you to create multiple times of day, each with their own unique and configurable tint. At any point within the day, the script will interpolate between the two closest times of day to create the current tint. In turn, these times of day will fall at different times throughout the year. You can set the values for the longest and shortest days of the year, and the script will determine the current times by interpolating between these.
The weather system gives you lots of options, allowing you to customize the bgs, fog, weather effect, and even effects like thunder with screen flashes and sound effects. Each weather effect can be assigned a severity, which influences the likelihood that they will occur. More on this when I talk about seasons. You can also configure a range of durations for each weather effect. When a weather effect starts, a random value in the range will be chosen for its duration.
Both the tint and the weather effects are influenced by the player's current location (outside, inside, or inside a dark place). When outside, all tint and weather effects will be applied at full force. When inside, the engine weather effects (rain, snow, etc) and fog effects will not be applied, and sounds and tints will be dampened. When inside a dark place, everything is the same as for inside, except the screen tint will be set to a fixed configurable value.
The year is divided into seasons set up in the configuration. Each season has a defined temperature range, probability of weather, bad weather, and very bad weather, and set of weather possibilities.
You can also configure various terrains that can influence various aspects of the system. Each terrain has a defined range of temperature modifiers, and a set of weather effect exclusions.
You can create holidays, which have essentially no effect besides changing certain lines of text in the clock. Each holiday can either be defined by date or by a position within the month (i.e. first monday, second to last thursday, etc).
Finally, the clock is fully configurable, and gives you a wide range of information to pull from and various methods to display it. For instance, you can display either the weekday name (replaced by the holiday if applicable) or the weekday abbreviation. More on these in the instructions in the script.
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# Advanced Time and Environment System (ATES) by Blizzard and ThallionDarkshine
# Version: 1.1
# Type: Autonomous Timeflow and Environment Controller
# Date v0.3: 11.3.2008
# Date v0.31: 8.4.2009
# Date v0.32: 13.4.2009
# Date v0.33: 4.5.2009
# Date v0.34: 5.5.2009
# Date v1.0: 12.2.2013
# Date v1.01: 28.4.2013
# Date v1.02: 20.3.2015
# Date v1.1: 18.12.2017
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#
# This work is protected by the following license:
# #----------------------------------------------------------------------------
# #
# # Creative Commons - Attribution-NonCommercial-ShareAlike 3.0 Unported
# # ( http://creativecommons.org/licenses/by-nc-sa/3.0/ )
# #
# # You are free:
# #
# # to Share - to copy, distribute and transmit the work
# # to Remix - to adapt the work
# #
# # Under the following conditions:
# #
# # Attribution. You must attribute the work in the manner specified by the
# # author or licensor (but not in any way that suggests that they endorse you
# # or your use of the work).
# #
# # Noncommercial. You may not use this work for commercial purposes.
# #
# # Share alike. If you alter, transform, or build upon this work, you may
# # distribute the resulting work only under the same or similar license to
# # this one.
# #
# # - For any reuse or distribution, you must make clear to others the license
# # terms of this work. The best way to do this is with a link to this web
# # page.
# #
# # - Any of the above conditions can be waived if you get permission from the
# # copyright holder.
# #
# # - Nothing in this license impairs or restricts the author's moral rights.
# #
# #----------------------------------------------------------------------------
#
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#
# Compatibility:
#
# 99% compatible with SDK v1.x. 90% compatible with SDK 2.x. WILL corrupt old
# savegames. Can cause incompatibilty issues with DNS-es.
#
#
# Features:
#
# - complete control over and easy manipulating of time and weather
# - customizable day and night tinting
# - HUD clock optional
# - easier to control and more powerful than DDNS
#
#
# IMPORTANT NOTES:
#
# - This system has a working preconfiguration, be aware that a custom setup
# will need you to understand what each option does, so please read the
# configuration instructions.
# - Why does this system use switches to determine whether it's day or night?
# Simple: You can use conditions in enemy attacks to determine whether an
# attack should be used only at night or only at day.
#
#
# Instructions:
#
# - Explanation:
#
# This Time System will make your game have daytime and nighttime periods.
# The screen will be tinted accordingly. You can set up the length of the
# day. Other features are explained below. Please be sure to configure this
# system appropriately.
#
#
# - Basic manipulation of ATES:
#
# This system is based upon your eventing. It will work basically if you
# want, but with a little bit of using the "Call Script" event command you
# are able to control this system fully. You can call following commands:
#
# On/Off Controls
# ------------------------------------------------------------------------------
# ATES.on
# Turns ATES on.
#
# ATES.off
# Turns ATES off.
#
# ATES.tint_on
# Turns ATES's screen tinting on.
#
# ATES.tint_off
# Turns ATES's screen tinting off.
#
# ATES.clock_on
# Turns ATES's clock display on.
#
# ATES.clock_off
# Turns ATES's clock display off.
#
# ATES.weather_on
# Turns ATES's weather system on.
#
# ATES.weather_off
# Turns ATES's weather system off.
# ------------------------------------------------------------------------------
#
# Time Controls
# ------------------------------------------------------------------------------
# ATES.advance(M, H)
# This will make the time advanced by M minutes and H hours. Any negative
# value used will cancel the execution of this command.
#
# ATES.make_it_day
# This is a feature from DDNS which allows you to quickly jump to the
# daytime.
#
# ATES.make_it_night
# This is a feature from DDNS which allows you to quickly jump to the
# nighttime.
#
# ATES.set_time(TIME_INDEX or TIME_NAME)
# Sets the current time to the time at the index of TIME_INDEX or with the
# name of TIME_NAME. Its better to use TIME_NAME because some bugs may occur
# from using TIME_INDEX.
# ------------------------------------------------------------------------------
#
# Weather Controls
# ------------------------------------------------------------------------------
# ATES.lock_weather
# This allows you to lock the current weather in place without disabling the
# weather system entirely.
#
# ATES.unlock_weather
# This command unlocks the current weather.
#
# ATES.set_weather(INDEX)
# Sets the current weather to the weather at index INDEX.
# ------------------------------------------------------------------------------
#
# Location (inside/outside) Controls
# ------------------------------------------------------------------------------
# ATES.go_inside
# A feature from the DDNS which allows you to change the lighting mode to
# inside.
#
# ATES.go_inside_dark
# A feature from the DDNS which allows you to change the lighting mode to
# inside dark.
#
# ATES.go_outside
# A feature from the DDNS which allows you to change the lighting mode to
# outside.
# ------------------------------------------------------------------------------
#
# Terrain Controls
# ------------------------------------------------------------------------------
# ATES.terrain=(TERRAIN_NAME)
# Sets the terrain to the terrain named TERRAIN_NAME.
# ------------------------------------------------------------------------------
#
# Conditionals
# ------------------------------------------------------------------------------
# ATES.active?
# Returns true if ATES is turned on, otherwise false.
#
# ATES.tinting?
# Returns true if ATES tinting is turned on, otherwise false.
#
# ATES.weather_active?
# Returns true if the weather system is turned on, otherwise false.
#
# ATES.day?
# Returns true if it's day, otherwise false. Alternatively you can check the
# assigned switch instead.
#
# ATES.night?
# Returns true if it's night, otherwise false. Alternatively you can check
# the assigned switch instead.
# ------------------------------------------------------------------------------
#
# Getters
# ------------------------------------------------------------------------------
# ATES.time_name
# Returns the name of the current time of day.
# ------------------------------------------------------------------------------
#
# - Enhancement hints:
#
# If you wish to implement the DDNS further into your game and e.g. allow
# different behavious of monsters during day and night, you only need to
# check the the state of the appropriate switch. e.g. If NSWITCH is turned
# on inflict "Sleep" on one enemy. The same is true for temperature (check
# TVARIABLE) and weather (check WVARIABLE).
#
#
# Additional info:
#
# - The daytime and nighttime tintings were tested appropriately and optimal
# tinting is being used.
#
# - Keep in mind that all aspects of the ATES are initially turned off, so
# you'll have to use the commands ATES.on, ATES.tint_on, ATES.clock_on, and
# ATES.weather_on to enable the components.
#
# - Further instructions can be found in the script database topic:
# http://forum.chaos-project.com/index.php/topic,12869.0.html
#
# If you find any bugs, please report them here:
# http://forum.chaos-project.com
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
module ATES
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# switch ID of the "day" switch
DSWITCH = 51
# switch ID of the "night" switch
NSWITCH = 52
# variable ID of the temperature variable
TVARIABLE = 51
# variable ID of the weather variable
WVARIABLE = 52
# length of a day in seconds in-game, can't be less than 36, is being
# quantized into intervals of 36 seconds
LENGTH = 1440
# the amount to multiply weather sound by when inside
INSIDE_SOUND = 0.7
# the amount to multiply tone red, green, blue and gray by when inside
INSIDE_TONE = 0.0
# the tone for dark interiors
DARK_INSIDE_TONE = Tone.new(-85, -85, -85, 85)
# weather setup, create new types of weather here
# note - if you don't want a certain effect such as weather, fog, or sound,
# just leave the array for that effect empty
# ['NAME', WEATHER_SEVERITY, LOW_STRENGTH..HIGH_STRENGTH,
# WEATHER_DURATION_MIN..WEATHER_DURATION_MAX, [WEATHER_TYPE],
# [SOUND_NAME, SOUND_VOLUME_MIN..SOUND_VOLUME_MAX, SOUND_PITCH],
# [FOG_NAME, FOG_OPACITY, FOG_HUE, FOG_ZOOM, FOG_SX, FOG_SY,
# [TONE_RED, TONE_GREEN, TONE_BLUE, TONE_GRAY]],
# [SOUND_EFFECT_NAME, SOUND_VOLUME_MIN..SOUND_VOLUME_MAX, SOUND_PITCH,
# EFFECT_PROBABILITY, FLASH_DURATION, [FLASH_COLOR_RED,
# FLASH_COLOR_GREEN, FLASH_COLOR_BLUE]]]
WEATHER = [['Drizzling', 0, 1..4, 150..480, [1], ['005-Rain01', 65..80, 100], [], []],
['Raining', 0, 5..8, 150..450, [1], ['006-Rain02', 75..90, 100], [], ['061-Thunderclap01', 60..85, 100, 0.0018, 4, [255, 255, 255]]],
['Storm', 1, 9..10, 180..450, [1], ['007-Rain03', 80..100, 100], [], ['061-Thunderclap01', 70..95, 110, 0.002, 6, [255, 255, 255]]],
['Cloudy', 0, 1..1, 240..720, [], [], ['002-Clouds01', 60, 0, 200, 4, 3, [0, 0, 0, 0]], []],
['Raining', 0, 1..4, 150..450, [2], ['006-Rain02', 70..85, 100], [], ['061-Thunderclap01', 65..90, 110, 0.002, 6, [255, 255, 255]]],
['Storm', 1, 5..8, 180..450, [2], ['007-Rain03', 75..90, 100], [], ['061-Thunderclap01', 70..95, 110, 0.0022, 7, [255, 255, 255]]],
['Storm', 2, 9..10, 180..450, [2], ['007-Rain03', 90..100, 100], [], ['061-Thunderclap01', 85..100, 110, 0.0026, 7, [255, 255, 255]]],
['Flurry', 1, 1..4, 150..480, [3], ['002-Wind02', 70..85, 100], [], []],
['Snowing', 1, 5..8, 150..450, [3], ['003-Wind03', 80..95, 100], [], []],
['Blizzard', 2, 9..10, 180..450, [3], ['004-Wind04', 85..100, 100], [], []]]
# the name of the default weather type (what gets shown in the clock when
# there is no weather)
DEFAULT_WEATHER_NAME = 'Sunny'
# season setup, create a new season by using this template
# ['NAME', START_DAY, START_MONTH, MIN_TEMP..MAX_TEMP, WEATHER_PROBABILITY,
# BAD_WEATHER_PROBABILITY, VERY_BAD_WEATHER_PROBABILITY, WEATHER_POSSIBILITIES]
SEASONS = [
['Spring', 22, 3, 0..25, 0.003, 0.3, 0.05, [0, 1, 2, 3, 4, 5]] ,
['Summer', 21, 6, 20..35, 0.003, 0.1, 0.2, [0, 1, 3, 4, 5, 6]] ,
['Autumn', 20, 9, 0..25, 0.003, 0.2, 0.1, [0, 2, 3, 4, 5, 7]] ,
['Winter', 21, 12, -20..5, 0.003, 0.5, 0.1, [0, 2, 3, 4, 7, 8, 9]]
]
# terrain setup, create a new terrain by using this template
# ['NAME', MIN_TEMP..MAX_TEMP, WEATHER_EXCLUSIONS]
TERRAINS = [
['Forest', -7..0, [3]],
['Desert', 11..16, [8, 9]],
['Mountain', -9..-4, []],
['Plains', -2..0, []],
['Beach', -5..-2, [8, 9]]
]
# longest day date, the date of the longest night is half a year later/earlier
LONGEST = [21, 6]
# the tone at which day starts
DAY_START = "Sunrise"
# the tone at which night starts
NIGHT_START = "Dusk"
# the different screen tones and temperature modifiers at certain points during the day on the longest and shortest days
# to make a new time of day, add this into TIMES:
# NAME => [RED, GREEN, BLUE, GRAY, TEMPERATURE_MODIFIER]
TIMES = {
"Dawn" => [-17, -17, 17, 0, -4],
"Sunrise" => [48, 30, 30, 0, -2],
"Noon" => [24, 10, 10, 0, 5],
"Sunset" => [57, -17, -17, 0, 1],
"Dusk" => [-17, -17, 17, 0, -3],
"Night" => [-140, -110, -110, 160, -8]
}
# once you have customized the tones, put the tones into LONG_TIMES and SHORT_TIMES with [name_of_time, hour, minute]
LONG_TIMES = [["Dawn", 4, 30],
["Sunrise", 5, 30],
["Noon", 13, 00],
["Sunset", 21, 00],
["Dusk", 22, 00],
["Night", 1, 30]]
SHORT_TIMES = [["Dawn", 6, 30],
["Sunrise", 7, 30],
["Noon", 13, 00],
["Sunset", 16, 30],
["Dusk", 17, 00],
["Night", 23, 30]]
# the first year in your calender, the player can't scroll further back
FYEAR = 1990
# the last year in your calender, the player can't scroll further forth
LYEAR = 2099
# the suffix for temperature
TEMP_SUFFIX = "°C"
# the different holidays and their dates
# the format for adding a new holiday is:
# [NAME, SETUP_TYPE, MONTH, (DAY or WEEKDAY, NUMBER)]
# whether to use DAY or WEEKDAY, NUMBER depends on SETUP_TYPE:
# (0 - DAY; 1 - WDAY, NUMBER)
# note - the current holiday will replace the weekday in the clock if it is a
# holiday
HOLIDAYS = [
["Christmas", 0, 11, 24],
["New Year's Day", 0, 0, 0],
["Thanksgiving", 1, 10, 4, 4],
["Groundhog Day", 0, 1, 1],
["Valentine's Day", 0, 1, 13],
["Earth Day", 0, 3, 21],
["Arbor Day", 1, 3, 5, -1],
["Mother's Day", 1, 2, 7, 2],
["Father's Day", 1, 5, 7, 3],
["Halloween", 0, 9, 30],
]
# HUD clock format
# default : ['%H:%M%s', '%A', '%d/%m/%Y', '%S']
# use [] for no clock
# it means: 1st row - "HOURS:MINUTES SUFFIX"
# 2nd row - "WEEKDAY"
# 3rd row - "DAY/MONTH/YEAR"
# 4th row - "SEASON"
# different combinations to input ATES information into the clock
# %H - Hour
# %M - Minute
# %s - Suffix (AM or PM) (only if not using 24 hour time)
# %A - Weekday
# %a - Weekday Abbreviation
# %d - Day of the Month
# %D - Day of the Year
# %m - Month
# %n - Month Name
# %l - Month Length
# %Y - Year
# %L - Year Length
# %S - Season
# %w - Weather
# %t - Terrain
# %T - Temperature
# %p - Time of Day
CFORMAT = ['%H:%M', '%d/%m/%Y', '%A', '%w', '%p']
# the width of the clock
CWIDTH = 180
# names of your days, automatically sets up a week's length
WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday']
WEEKDAY_ABBREVIATIONS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
# names of your months, automatically sets up a year's length
MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July',
'August', 'September', 'October', 'November', 'December']
# abbreviations for month names
MONTH_ABBREVIATIONS = ['Jan', 'Feb', 'March', 'Apr', 'May', 'June', 'July',
'Aug', 'Sept', 'Oct', 'Nov', 'Dec']
# days in each month
MONTHDAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
# the first day in the game [DAY, MONTH, YEAR, WEEKDAY]
# set this option to [] if you want the game to start "now"
START = [24, 11, 2007, 7]
# set this option to true to turn on 24 hour time
HOUR24 = true
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
mon = (LONGEST[1] + MONTHS.length / 2) % 12
mon = 12 if mon == 0
day = LONGEST[0] + (MONTHS.length % 2) == 1 ? MONTHDAYS[mon - 1] / 2 : 0
while day > MONTHDAYS[mon - 1]
day -= MONTHDAYS[mon - 1]
mon = (mon + 1) % 12
mon = 12 if mon == 0
end
SHORTEST = [day, mon]
# Perform some simple checks of the config
if ATES::MONTHS.size > ATES::MONTHDAYS.size
raise 'ATEScfgError: Not all months have a length in days specified!'
elsif ATES::LENGTH < 36
raise 'ATEScfgError: A day\'s length must be equal to or greater than 36 seconds!'
end
$ates = 1.0
#============================================================================
# ATES::Time
#============================================================================
class Time
attr_accessor :min
attr_accessor :hour
attr_accessor :day
attr_accessor :mon
attr_accessor :year
attr_accessor :wday
def initialize(m, h, d, mon, y, w)
@min, @hour, @day, @mon, @year, @wday = m, h, d, mon, y, w
end
end
#==============================================================================
# ATES::Weather
#==============================================================================
class Weather
attr_accessor :current_weather, :current_intensity, :locked, :weather_enabled, :weather_count
attr_reader :weather_duration
def initialize
@current_weather = -1
@current_intensity = 0
@locked = false
@weather_enabled = true
end
def update
if @current_weather != -1 && @weather_enabled && @current_weather[7].length > 0
weather = @current_weather
if rand <= weather[7][3]
high, low = weather[2].first, weather[2].last
vol = weather[7][1].first + (weather[7][1].last - weather[7][1].first) * (high - @current_intensity).to_f / (high - low)
vol *= ATES::INSIDE_SOUND if $game_system.ates.map_type > 0
sound = RPG::AudioFile.new(weather[7][0], vol, weather[7][2])
$game_system.se_play(sound)
col = Color.new(0, 0, 0)
$game_screen.start_flash(Color.new(*weather[7][5]), weather[7][4])
end
end
end
def stop_weather(speed = -1)
return if @current_weather == -1
speed = speed == -1 ? rand(10) + 60 : speed
if @current_weather[4].length > 0
$game_screen.weather(0, 1, speed)
end
if @current_weather[5].length > 0
$game_system.bgs_fade(speed.to_f / 40)
end
if @current_weather[6].length > 0
$game_map.fog_name = ''
end
@current_weather = -1
end
def pause_weather(speed = -1)
return if @current_weather == -1
$game_system.ates.show_weather = false
speed = speed == -1 ? rand(10) + 60 : speed
if @current_weather[4].length > 0
$game_screen.weather(0, 1, speed)
end
if @current_weather[5].length > 0
$game_system.bgs_fade(speed.to_f / 40)
end
if @current_weather[6].length > 0
$game_map.fog_name = ''
end
end
def resume_weather(speed = -1)
return if @current_weather == -1
$game_system.ates.show_weather = true
weather = @current_weather
intensity = @current_intensity
low, high = weather[2].first, weather[2].last
speed = speed == -1 ? rand(10) + 60 : speed
if weather[4].length > 0
$game_screen.weather(weather[4][0], intensity, speed)
end
if weather[5].length > 0
volume = weather[5][1].first + (weather[5][1].last - weather[5][1].first) * (high - intensity).to_f / (high - low)
bgm = RPG::AudioFile.new(weather[5][0], volume, weather[5][2])
$game_system.bgs_play(bgm)
end
if weather[6].length > 0
$game_map.fog_name = weather[6][0]
$game_map.fog_opacity = weather[6][1]
$game_map.fog_hue = weather[6][2]
$game_map.fog_zoom = weather[6][3]
$game_map.fog_sx = weather[6][4]
$game_map.fog_sy = weather[6][5]
$game_map.start_fog_tone_change(Tone.new(*weather[6][6]), 0)
end
end
def set_weather(weather, speed = -1)
stop_weather if @current_weather != -1
if weather.is_a?(Fixnum)
weather = WEATHER[weather]
end
@weather_count = 0
@weather_duration = rand(weather[3].max - weather[3].min) + weather[3].min
low, high = weather[2].first, weather[2].last
intensity = rand(high + 1 - low) + low
@current_weather = weather
@current_intensity = intensity
return unless @weather_enabled
speed = speed == -1 ? rand(10) + 60 : speed
if weather[5].length > 0
volume = weather[5][1].first + (weather[5][1].last - weather[5][1].first) * (high - intensity).to_f / (high - low)
volume *= ATES::INSIDE_SOUND if $game_system.ates.map_type > 0
bgm = RPG::AudioFile.new(weather[5][0], volume, weather[5][2])
$game_system.bgs_play(bgm)
end
return if $game_system.ates.map_type > 0
if weather[4].length > 0
if $modified_aws and weather[4].length > 1
$game_screen.weather(weather[4][0], intensity, speed, weather[3][1])
else
$game_screen.weather(weather[4][0], intensity, speed)
end
end
if weather[6].length > 0
$game_map.fog_name = weather[6][0]
$game_map.fog_opacity = weather[6][1]
$game_map.fog_hue = weather[6][2]
$game_map.fog_zoom = weather[6][3]
$game_map.fog_sx = weather[6][4]
$game_map.fog_sy = weather[6][5]
$game_map.start_fog_tone_change(Tone.new(*weather[6][6]), 0)
end
end
end
def self.on
$game_system.ates.active = true
return true
end
def self.off
$game_system.ates.active = false
return true
end
def self.tint_on(frames = 0)
$game_screen.start_tone_change($game_system.ates.get_environment[0], frames)
$game_system.ates.tinting = true
return true
end
def self.tint_off(reset = true)
$game_screen.start_tone_change(Tone.new(0, 0, 0, 0), 0) if reset
$game_system.ates.tinting = false
return true
end
def self.weather_off
$game_system.ates.weather.weather_enabled = false
$game_system.ates.weather.pause_weather(0) if $game_system.ates.weather.current_weather and $game_system.ates.weather.current_weather != -1
return true
end
def self.weather_on
$game_system.ates.weather.weather_enabled = true
$game_system.ates.weather.resume_weather(0) if $game_system.ates.weather.current_weather and $game_system.ates.weather.current_weather != -1
return true
end
def self.weather_active?
return $game_system.ates.weather.weather_enabled
end
def self.lock_weather
$game_system.ates.weather.locked = true
return true
end
def self.unlock_weather
$game_system.ates.weather.locked = false
return true
end
def self.clock_on
$game_system.show_clock = true
return true
end
def self.clock_off
$game_system.show_clock = false
return true
end
def self.active?
return $game_system.ates.active
end
def self.tinting?
return $game_system.ates.tinting
end
def self.day?
i = $game_system.ates.time_index
while true
if $game_system.ates.current_times[i][0] == DAY_START
return true
elsif $game_system.ates.current_times[i][0] == NIGHT_START
return false
end
i = (i + $game_system.ates.current_times.length - 1) % $game_system.ates.current_times.length
end
end
def self.night?
return !self.day?
end
def self.make_it_day
time = $game_system.ates.current_times.select { |time| time[0] == DAY_START }
h, m = time[0][1], time[0][2]
$game_system.ates.time.hour = h
$game_system.ates.time.min = m
return true
end
def self.make_it_night
time = $game_system.ates.current_times.select { |time| time[0] == NIGHT_START }
h, m = time[0][1], time[0][2]
$game_system.ates.time.hour = h
$game_system.ates.time.min = m
return true
end
def self.set_time(time = 0)
return unless $game_system
if time.is_a?(Fixnum)
time = $game_system.ates.current_times[time.to_i]
else
time = $game_system.ates.current_times.select { |current_time| current_time[0] == time }[0]
end
h, m = time[1], time[2]
$game_system.ates.time.hour = h
$game_system.ates.time.min = m
return true
end
def self.day_start
return DAY_START
end
def self.night_start
return NIGHT_START
end
def self.go_inside_dark
weather = $game_system.ates.weather.current_weather
$game_system.ates.map_type = 2
self.tint_on
$game_system.ates.weather.pause_weather(0)
return true if weather == -1
low, high = weather[2].first, weather[2].last
intensity = $game_system.ates.weather.current_intensity
if weather[5].length > 0
volume = ATES::INSIDE_SOUND * weather[5][1].first + (weather[5][1].last - weather[5][1].first) * (high - intensity).to_f / (high - low)
bgm = RPG::AudioFile.new(weather[5][0], volume, weather[5][2])
$game_system.bgs_play(bgm)
end
return true
end
def self.go_inside
weather = $game_system.ates.weather.current_weather
$game_system.ates.map_type = 1
self.tint_on
$game_system.ates.weather.pause_weather(0)
return true if weather == -1
low, high = weather[2].first, weather[2].last
intensity = $game_system.ates.weather.current_intensity
if weather[5].length > 0
volume = ATES::INSIDE_SOUND * weather[5][1].first + (weather[5][1].last - weather[5][1].first) * (high - intensity).to_f / (high - low)
bgm = RPG::AudioFile.new(weather[5][0], volume, weather[5][2])
$game_system.bgs_play(bgm)
end
return true
end
def self.go_outside
$game_system.ates.weather.resume_weather(0)
$game_system.ates.map_type = 0
self.tint_on
return true
end
def self.set_weather(id)
$game_system.ates.weather.set_weather(WEATHER[id])
return true
end
def self.terrain=(terrain)
terrain = TERRAINS[terrain.to_i][0] if terrain.is_a?(Fixnum)
$game_system.ates.terrain = terrain
return true
end
def self.advance(m, h, d, mon, y)
return true if [m, h, d, mon, y].any? {|i| i < 0}
h += ($game_system.ates.time.min + m) / 60
$game_system.ates.time.min = ($game_system.ates.time.min + m) % 60
d += ($game_system.ates.time.hour + h) / 24
$game_system.ates.time.hour = ($game_system.ates.time.hour + h) % 24
while d > 0
if $game_system.ates.time.day < MONTHDAYS[mon]
$game_system.ates.time.day += 1
else
$game_system.ates.time.day = 0
mon = (mon + 1) % MONTHS.size
end
$game_system.ates.time.wday += 1
$game_system.ates.time.wday %= WEEKDAYS.size
d -= 1
end
y += ($game_system.ates.time.mon + mon) / MONTHS.size
$game_system.ates.time.mon = ($game_system.ates.time.mon + mon) % MONTHS.size
$game_system.ates.time.year += y
return true
end
def self.time_name
return $game_system.ates.current_times[$game_system.ates.time_index][0]
end
end
#==============================================================================
# Game_System
#==============================================================================
class Game_System
attr_accessor :ates
attr_accessor :show_clock
alias init_ates_later initialize
def initialize
init_ates_later
@ates = Game_ATES.new
@show_clock = false
end
end
#==============================================================================
# Game_ATES
#==============================================================================
class Game_ATES
attr_accessor :active
attr_accessor :tinting
attr_accessor :time
attr_accessor :weather
attr_accessor :frame_count
attr_accessor :current_times
attr_accessor :tone
attr_accessor :map_type
attr_accessor :show_weather
attr_accessor :terrain
attr_accessor :temp
attr_reader :holiday
attr_reader :time_index
def initialize
if ATES::START.size == 4
@time = ATES::Time.new(0, 0, ATES::START[0], ATES::START[1],
ATES::START[2], ATES::START[3])
else
@time = Time.now
@time = ATES::Time.new(@time.min, @time.hour, @time.mday, @time.mon, @time.year, @time.wday)
end
@weather = ATES::Weather.new
@long_times = ATES::LONG_TIMES.sort { |t1, t2| t1[1] * 100 + t1[2] <=> t2[1] * 100 + t2[2] }
@short_times = ATES::SHORT_TIMES.sort { |t1, t2| t1[1] * 100 + t1[2] <=> t2[1] * 100 + t2[2] }
@year_length = ATES::MONTHDAYS.inject { |sum, x| sum + x }
@normal_weather = []
@bad_weather = []
@very_bad_weather = []
@terrain = ''
@current_times = setup_times
@temp_modifier = (rand(201) - 100) / 100.0
@tone, @temp = get_environment
@holiday = get_holiday(@time.mon, @time.day, @time.wday)
@s_time = get_time(@time.min, @time.hour)
$game_screen.start_tone_change(@tone, 0) if $game_screen
@active = true
@tinting = true
@show_weather = true
@map_type = 0
@frame_count = 0
end
# get the holiday corresponding to a date
def get_holiday(month, day, wday)
ATES::HOLIDAYS.each { |el|
case el[1] # branch by holiday definition
when 0 # defined by date
return el if el[2..3] == [month, day]
when 1 # defined by position in month
if el[4] > 0 # nth instance of a weekday
return el if el[2] == month and el[3] == wday and el[4] == (day.to_f / 7 + 1).floor
elsif el[4] < 0 # nth to last instance of a weekday
return el if el[2] == month and el[3] == wday and -el[4] == ((ATES::MONTHDAYS[month] - 1 - day).to_f / 7 + 1).floor
end
end
}[0]
end
# generate the correct tone based on the time of day and current location
def get_environment
red = 0
green = 0
blue = 0
grey = 0
@temp_modifier += (rand(3) - 1) / 100.0 if rand(10) == 0
changed = false
# loop through the times of day to determine where the current time falls
for i in 0...@current_times.length
time1 = get_time(@current_times[i][2], @current_times[i][1])
time2 = get_time(@current_times[(i + 1) % @current_times.length][2], @current_times[(i + 1) % @current_times.length][1])
current = get_time(@time.min, @time.hour)
if time2 < time1
time2 += 24 * 60
end
if current < time1
current += 24 * 60
end
# found the two times to interpolate between
if time1 <= current and time2 >= current
changed = true
tone1 = @current_times[i]
tone2 = @current_times[(i + 1) % @current_times.length]
tone1 = ATES::TIMES[tone1[0]]
tone2 = ATES::TIMES[tone2[0]]
max = time2 - time1
# interpolate the current screen tone
ratios = [(current - time1).to_f / max, (time2 - current).to_f / max]
red = tone1[0] * ratios[1] + tone2[0] * ratios[0]
green = tone1[1] * ratios[1] + tone2[1] * ratios[0]
blue = tone1[2] * ratios[1] + tone2[2] * ratios[0]
grey = tone1[3] * ratios[1] + tone2[3] * ratios[0]
# deal with temperature (NEEDS REWORK)
season_data = get_full_season[3]
temp_range = [season_data.first, season_data.last].sort
unless @base_temp
# set up initial temperature
temp = temp_range[0] + rand(temp_range[1] - temp_range[0] + 1)
if @terrain != ''
modifier = get_terrain_full[1]
modifier = [modifier.first, modifier.last].sort
modifier = modifier[0] + rand(modifier[1] - modifier[0] + 1)
temp += modifier
end
@base_temp = temp
else
temp = @base_temp
end
# handle temperature changes
temp_mod = round(tone1[4] * ratios[1] + tone2[4] * ratios[0], 2)
temp += temp_mod + @temp_modifier
# update the time of day if necessary
@time_index = ratios[0] < 0.5 ? i : (i + 1) % @current_times.length
break
end
end
print "not right" unless changed
# use the generated tone to determine the actual screen tone based on
# whether the player is inside, outside, or inside a dark place
if @map_type == 1
return Tone.new(red * ATES::INSIDE_TONE, green * ATES::INSIDE_TONE, blue * ATES::INSIDE_TONE, grey * ATES::INSIDE_TONE), temp
elsif @map_type == 2
return ATES::DARK_INSIDE_TONE, temp
else
return Tone.new(red, green, blue, grey), temp
end
end
def get_weather_possibilities(severity = 0)
weather = []
season = $game_system.ates.get_full_season
terrain = get_terrain_full
ATES::WEATHER.each_with_index { |el, ind|
weather.push(el) if el[1] == severity && season[7].include?(ind) && (terrain.nil? || !terrain[2].include?(ind))
}
return weather
end
def get_terrain_full
return ATES::TERRAINS.select { |terrain| terrain[0] == @terrain }[0]
end
# interpolate between LONG_TIMES and SHORT_TIMES to find the current time of
# day changes
def setup_times
current_date = [@time.day, @time.mon]
# check for trivial cases
if current_date == ATES::LONGEST or @long_times == @short_times
return @long_times
elsif current_date == ATES::SHORTEST
return @short_times
end
short_times = @long_times.clone
addons = @short_times.clone
current_date = get_date(*current_date)
long, short = get_date(*ATES::LONGEST), get_date(*ATES::SHORTEST)
# calculate distances to shortest and longest days
dists = []
if (current_date >= short and current_date <= long)
dists = [current_date - short, long - current_date]
elsif (current_date >= short and short >= long)
dists = [current_date - short, long + @year_length - current_date]
elsif (current_date <= long and long <= short)
dists = [current_date + @year_length - short, long - current_date]
elsif (current_date >= long and current_date <= short)
dists = [current_date - long, short - current_date]
elsif (current_date <= short and short <= long)
dists = [current_date + @year_length - long, short - current_date]
elsif (current_date >= long and long >= short)
dists = [current_date - long, short + @year_length - current_date]
end
# generate the time for each time of day by interpolating between short and long
sum = dists[0] + dists[1]
short_times.each { |tone|
addons.each { |addon|
if tone[0] == addon[0]
ts = [get_time(tone[2], tone[1]), get_time(addon[2], addon[1])]
min, max = ts.min, ts.max
ts = [min + 1440, max] if max - min > min + 1440 - max
ts = (ts[0] * dists[0] / sum.to_f + ts[1] * dists[1] / sum.to_f) % 1440
h = (ts / 60).floor
m = ts.floor - h * 60
tone[1], tone[2] = h, m
break
end
}
}
return short_times.sort { |x, y| get_time(x[2], x[1]) <=> get_time(y[2], y[1]) }
end
# utility function to round a number to specified number of decimal places
def round(num, places = 0)
return ((num * 10 ** places).round.to_f) / (10 ** places)
end
# converts a time to minutes
def get_time(minutes, hours)
return minutes + hours * 60
end
# determine the current season from the date
def get_season
get_full_season[0]
end
# determine the season data from the date
def get_full_season
season_list = ATES::SEASONS.sort { |x, y| get_date(x[1], x[2]) <=> get_date(y[1], y[2]) }
day = @time.day
month = @time.mon
current = get_date(day, month)
for i in 0...season_list.length
seasons = [season_list[i], season_list[(i + 1) % season_list.length]]
times = [get_date(seasons[0][1], seasons[0][2]), get_date(seasons[1][1], seasons[1][2])]
if times[0] <= current and current < times[1]
return seasons[0]
end
end
return season_list[0]
end
# get the current day since the start of the year
def get_date(day, month)
month = ATES::MONTHS.length if month == 0
return (ATES::MONTHDAYS[0...month - 1].inject { |sum, x| sum + x } or 0) + day
end
# weather update
def update_weather
return unless @weather.weather_enabled
if @weather.current_weather != -1
@weather.weather_count += 1
if @weather.weather_count >= @weather.weather_duration && !@weather.locked
@weather.stop_weather
end
end
season = get_full_season
if !@season or @season != season
@normal_weather = get_weather_possibilities
@bad_weather = get_weather_possibilities(1)
@very_bad_weather = get_weather_possibilities(2)
@season = season
end
unless @weather.locked
if rand <= season[4] and season[7].length > 0
if rand <= season[5] and @bad_weather.length > 0
weather = rand(@bad_weather.length)
weather = @bad_weather[weather]
@weather.set_weather(weather)
elsif rand <= season[6] and @very_bad_weather.length > 0
weather = rand(@very_bad_weather.length)
weather = @very_bad_weather[weather]
@weather.set_weather(weather)
elsif @normal_weather.length > 0
weather = rand(@normal_weather.length)
weather = @normal_weather[weather]
@weather.set_weather(weather)
end
end
end
end
# update function
def update
if @active
@frame_count += 1
if @frame_count % (ATES::LENGTH / 36) == 0
tmp = @time.day
ATES.advance(1, 0, 0, 0, 0)
if @time.day != tmp
@current_times = setup_times
@holiday = get_holiday(@time.mon, @time.day, @time.wday)
end
update_weather
# update the switches if necessary
if ATES.day?
$game_map.need_refresh = true if !$game_switches[ATES::DSWITCH]
$game_switches[ATES::DSWITCH] = true
$game_switches[ATES::NSWITCH] = false
else
$game_map.need_refresh = true if !$game_switches[ATES::NSWITCH]
$game_switches[ATES::DSWITCH] = false
$game_switches[ATES::NSWITCH] = true
end
# update the variables
@tone, @temp = get_environment
$game_variables[ATES::TVARIABLE] = @temp
weather = -1
if @weather.current_weather != -1
weather = ATES::WEATHER.index(@weather.current_weather)
end
$game_variables[ATES::WVARIABLE] = weather
if @tinting # handle screen tone
cur_time = get_time(@time.min, @time.hour)
$game_screen.start_tone_change(@tone, ((@s_time - cur_time).abs < [1440 / ATES::LENGTH, 1].max ? 0 : 20))
end
end
# in-game time speed should not affect the weather animations and effects
@weather.update
end
end
end
#==============================================================================
# Bitmap
#==============================================================================
class Bitmap
if $tons_version == nil || $tons_version < 1.6
alias draw_text_shaded_later draw_text
end
def draw_text_full(x2, y2, w2 = 0, h2 = 0, text2 = '', a2 = 0)
if x2.is_a?(Rect)
x, y, w, h, text, a = x2.x, x2.y, x2.width, x2.height, y2, w2
else
x, y, w, h, text, a = x2, y2, w2, h2, text2, a2
end
save_color = self.font.color.clone
self.font.color = Color.new(0, 0, 0)
[x-1, x+1].each {|xx| [y-1, y+1].each {|yy|
draw_text_shaded_later(xx, yy, w, h, text, a)}}
self.font.color = save_color
draw_text_shaded_later(x, y, w, h, text, a)
end
end
#==============================================================================
# Clock_Sprite
#==============================================================================
class Clock_Sprite < Sprite
def initialize
super
self.x, self.y, self.z = 640 - 8 - ATES::CWIDTH, 8, 5000
self.bitmap = Bitmap.new(ATES::CWIDTH, ATES::CFORMAT.length * 32)
if $fontface != nil
self.bitmap.font.name = $fontface
elsif $defaultfonttype != nil
self.bitmap.font.name = $defaultfonttype
end
self.bitmap.font.size = 26
@odd = 0
draw if $game_system.ates.active
end
def draw
self.bitmap.clear
hours = $game_system.ates.time.hour
minutes = sprintf('%02d', $game_system.ates.time.min)
weekday = ATES::WEEKDAYS[$game_system.ates.time.wday - 1]
wday_abbr = ATES::WEEKDAY_ABBREVIATIONS[$game_system.ates.time.wday - 1]
day = $game_system.ates.time.day + 1
month = $game_system.ates.time.mon + 1
yday = ATES::MONTHDAYS[0..month - 1].inject { |s, r| s + r } + day
month_name = ATES::MONTHS[month - 1]
month_abbr = ATES::MONTH_ABBREVIATIONS[month - 1]
month_days = ATES::MONTHDAYS[month - 1]
year = $game_system.ates.time.year
year_days = ATES::MONTHDAYS.inject { |s, r| s + r }
season = $game_system.ates.get_season
terrain = $game_system.ates.terrain
temp = $game_system.ates.temp.to_s + ATES::TEMP_SUFFIX
weather = $game_system.ates.weather.current_weather == -1 ? ATES::DEFAULT_WEATHER_NAME : $game_system.ates.weather.current_weather[0]
tod = $game_system.ates.current_times[$game_system.ates.time_index][0]
hday = $game_system.ates.holiday
if hday != nil
weekday = hday[0]
end
clock_text = ATES::CFORMAT.map { |ln| ln.clone }
unless ATES::HOUR24
suffix = "PM"
if hours < 12
suffix = "AM"
hours = 12 if hours == 0
elsif hours > 12
suffix = "PM"
hours -= 12
end
else
suffix = ""
hours = 24 if hours == 0
hours = sprintf('%02d', hours)
end
colon = @odd % 2 == 0 ? " " : ":"
clock_text.each { |ln|
ln.gsub!(/%M/, minutes)
ln.gsub!(/%H/, hours.to_s)
ln.gsub!(/%A/, weekday)
ln.gsub!(/%a/, wday_abbr)
ln.gsub!(/%s/, " " + suffix)
ln.gsub!(/:/, colon)
ln.gsub!(/%m/, month.to_s)
ln.gsub!(/%n/, month_name)
ln.gsub!(/%l/, month_days.to_s)
ln.gsub!(/%Y/, year.to_s)
ln.gsub!(/%L/, year_days.to_s)
ln.gsub!(/%d/, day.to_s)
ln.gsub!(/%D/, yday.to_s)
ln.gsub!(/%S/, season)
ln.gsub!(/%w/, weather)
ln.gsub!(/%t/, terrain)
ln.gsub!(/%T/, temp)
ln.gsub!(/%p/, tod)
}
for i in 0...clock_text.length
self.bitmap.draw_text_full(0, i * 32, self.bitmap.width, 32, clock_text[i], 1)
end
@odd = (@odd + 1) % 2
end
end
#==============================================================================
# Scene_Map
#==============================================================================
class Scene_Map
alias main_ates_later main
def main
@clock = Clock_Sprite.new if $game_system.show_clock
main_ates_later
@clock.dispose if @clock != nil
end
alias update_ates_later update
def update
$game_system.ates.update
update_ates_later
if $game_system.show_clock
@clock = Clock_Sprite.new if @clock == nil
@clock.draw if $game_system.ates.frame_count % 20 == 0
elsif @clock != nil
@clock.dispose
@clock = nil
end
end
end
#==============================================================================
# Scene_Battle
#==============================================================================
class Scene_Battle
alias update_ates_later update
def update
$game_system.ates.update
update_ates_later
end
end
#==============================================================================
# Game_Map
#==============================================================================
class Game_Map
alias setup_ates_later setup
def setup(map_id)
$game_system.ates.update
setup_ates_later(map_id)
if $game_system.ates.show_weather and $game_system.ates.weather.current_weather and $game_system.ates.weather.current_weather != -1
weather = $game_system.ates.weather.current_weather
if weather[5].length > 0
$game_map.fog_name = weather[5][0]
$game_map.fog_opacity = weather[5][1]
$game_map.fog_hue = weather[5][2]
$game_map.fog_zoom = weather[5][3]
$game_map.fog_sx = weather[5][4]
$game_map.fog_sy = weather[5][5]
$game_map.start_fog_tone_change(Tone.new(*weather[5][6]), 0)
end
end
@events.each { |ev|
ev = ev[1]
if ev.list and ev.list.length > 0 and ev.list[0].code == 108 and ev.list[0].parameters[0] =~ /Terrain='(.+)'/
$game_system.ates.terrain = $1
end
}
end
end
#==============================================================================
# Scene_Calendar
#==============================================================================
class Scene_Calendar
def main
# Make calendar window
@calendar_window = Window_Calendar.new
@calendar_window.active = true
@calendar_window.z = 1000
#@day_window = Window_Day.new
#@day_window.z = 1010
#@day_window.visible = false
#@dir = rand(4)
# Make spriteset
@spriteset = Spriteset_Map.new
# Execute transition
Graphics.transition
# Main loop
loop do
# Update game screen
Graphics.update
# Update input information
Input.update
# Frame update
update
# Abort loop if screen is changed
if $scene != self
break
end
end
# Prepare for transition
Graphics.freeze
# Dispose of window
@calendar_window.dispose
#@day_window.dispose
# Dispose of spriteset
@spriteset.dispose
end
def update
@calendar_window.update
#@day_window.update
#if @calendar_window.active
#if Input.trigger?(Input::C)
# @day_window.visible = true
# @day_window.active = true
# @calendar_window.active = false
# @day_window.x, @day_window.y = 80, 80
# @day_window.appear(@dir)
# @dir = rand(4)
#end
if Input.trigger?(Input::B)
$game_system.se_play($data_system.cancel_se)
$scene = Scene_Map.new
end
#elsif @day_window.active
#if Input.trigger?(Input::B)
# @day_window.disappear(@dir)
# @day_window.active = false
# @calendar_window.active = true
#end
#end
end
end
#==============================================================================
# Window_Calendar
#==============================================================================
class Window_Calendar < Window_Base
def initialize
super(48, 48, 544, 384)
self.contents = Bitmap.new(width - 32, height - 32)
@month, @day, @wday, @year = $game_system.ates.time.mon, $game_system.ates.time.day, $game_system.ates.time.wday, $game_system.ates.time.year
update
refresh
end
def update
prev_mon = @month
if Input.repeat?(Input::LEFT)
$game_system.se_play($data_system.cursor_se)
continue = true
@day -= 1
if @day == 0
@month -= 1
if @month == 0
unless @year == ATES::FYEAR
@year -= 1
@month = ATES::MONTHS.length
else
@day = 1
@month = 1
continue = false
end
end
@day = ATES::MONTHDAYS[@month - 1]
end
if continue
@wday = (@wday + ATES::WEEKDAYS.length - 1) % ATES::WEEKDAYS.length
@wday = ATES::WEEKDAYS.length if @wday == 0
end
end
if Input.repeat?(Input::RIGHT)
$game_system.se_play($data_system.cursor_se)
continue = true
@day += 1
if @day == ATES::MONTHDAYS[@month - 1] + 1
@month += 1
if @month == ATES::MONTHS.length + 1
unless @year == ATES::LYEAR
@year += 1
@month = 1
else
@month = ATES::MONTHS.length
@day = ATES::MONTHDAYS[@month - 1]
continue = false
end
end
@day = 1
end
if continue
@wday = (@wday + 1) % ATES::WEEKDAYS.length
@wday = ATES::WEEKDAYS.length if @wday == 0
end
end
if Input.repeat?(Input::UP)
$game_system.se_play($data_system.cursor_se)
continue = true
tmpday = @day
@day -= ATES::WEEKDAYS.length
if @day <= 0
@month -= 1
if @month == 0
unless @year == ATES::FYEAR
@year -= 1
@month = ATES::MONTHS.length
else
@day = tmpday
@month = 1
continue = false
end
end
if continue
tmp = (@wday + ATES::WEEKDAYS.length - @day) % ATES::WEEKDAYS.length
tmp = ATES::WEEKDAYS.length if tmp == 0
if @wday > tmp
tmp = tmp + ATES::WEEKDAYS.length - @wday
else
tmp = tmp - @wday
end
@day = ATES::MONTHDAYS[@month - 1]
@day -= tmp
end
end
end
if Input.repeat?(Input::DOWN)
$game_system.se_play($data_system.cursor_se)
continue = true
tmpday = @day
@day += ATES::WEEKDAYS.length
if @day >= ATES::MONTHDAYS[@month - 1] + 1
@month += 1
if @month == ATES::MONTHS.length + 1
unless @year == ATES::LYEAR
@year += 1
@month = 1
else
@day = tmpday
@month = ATES::MONTHS.length
continue = false
end
end
if continue
tmp = (@wday + ATES::MONTHDAYS[@month - 2] - @day) % ATES::WEEKDAYS.length
tmp = ATES::WEEKDAYS.length if tmp == 0
if @wday <= tmp
tmp -= ATES::WEEKDAYS.length
end
@day = @wday - tmp
end
end
end
super()
refresh if prev_mon != @month
row_count = (ATES::MONTHDAYS.max - 2) / ATES::WEEKDAYS.length + 2
row_height = height - 116
top_margin = ((row_height % row_count) / 2.0).ceil
row_height -= row_height % row_count
row_height /= row_count
colwidth = width - 32
margin = ((colwidth % ATES::WEEKDAY_ABBREVIATIONS.length) / 2.0).ceil
colwidth -= colwidth % ATES::WEEKDAY_ABBREVIATIONS.length
colwidth /= ATES::WEEKDAY_ABBREVIATIONS.length
start_wday = (@wday + ATES::WEEKDAYS.length - (@day - 1) % ATES::WEEKDAYS.length) % ATES::WEEKDAYS.length
start_wday = ATES::WEEKDAYS.length if start_wday == 0
row = (@day + start_wday - 2) / ATES::WEEKDAYS.length
self.cursor_rect.set(margin + (@wday - 1) * colwidth, 84 + top_margin + row * row_height, colwidth, 32)
end
def refresh
self.contents.clear
self.contents.font.size = 32
self.contents.font.color = system_color
self.contents.draw_text_full(Rect.new(0, 0, width - 32, 32), ATES::MONTHS[@month - 1] + " " + @year.to_s, 1)
self.contents.font.size = 24
colwidth = width - 32
margin = ((colwidth % ATES::WEEKDAY_ABBREVIATIONS.length) / 2.0).ceil
colwidth -= colwidth % ATES::WEEKDAY_ABBREVIATIONS.length
colwidth /= ATES::WEEKDAY_ABBREVIATIONS.length
for i in 0...ATES::WEEKDAY_ABBREVIATIONS.length
self.contents.draw_text_full(Rect.new(margin + i * colwidth, 40, colwidth, 32), ATES::WEEKDAY_ABBREVIATIONS[i], 1)
end
self.contents.fill_rect(Rect.new(0, 76, width - 32, 2), system_color)
row_count = (ATES::MONTHDAYS.max - 2) / ATES::WEEKDAYS.length + 2
row_height = height - 116
top_margin = ((row_height % row_count) / 2.0).ceil
row_height -= row_height % row_count
row_height /= row_count
cur_wday = (@wday + ATES::WEEKDAYS.length - (@day - 1) % ATES::WEEKDAYS.length) % ATES::WEEKDAYS.length
cur_wday = ATES::WEEKDAYS.length if cur_wday == 0
start_wday = cur_wday
cur_day = 1
cur_row = (cur_day - 1) / 7
while cur_day <= ATES::MONTHDAYS[@month - 1]
if (cur_day == $game_system.ates.time.day and @month == $game_system.ates.time.mon and @year == $game_system.ates.time.year)
self.contents.font.color = Color.new(240, 40, 40)
elsif $game_system.ates.get_holiday(@month - 1, cur_day - 1, cur_wday) != nil
self.contents.font.color = Color.new(150, 150, 0)
else
self.contents.font.color = normal_color
end
self.contents.draw_text_full(Rect.new(margin + (cur_wday - 1) * colwidth, 84 + top_margin + cur_row * row_height, colwidth, 32), cur_day.to_s, 1)
cur_day += 1
cur_wday = cur_wday + 1
if cur_wday > ATES::WEEKDAYS.length
cur_wday -= ATES::WEEKDAYS.length
cur_row += 1
end
end
end
end
#==============================================================================
# Window_Day
#==============================================================================
class Window_Day < Window_Base
def initialize
#(dir == 2 ? 320 : 48), (dir == 3 ? 240 : 48), (dir % 2 == 0 ? 272 : 544), (dir % 2 == 1 ? 192 : 384)
super(80, 80, 480, 320)
self.contents = Bitmap.new(width - 32, height - 32)
end
def appear(dir, duration = 40)
@d_pos = [self.x, self.y]
case dir
when 0
self.x = -480
when 1
self.y = -320
when 2
self.x = 640
when 3
self.y = 480
end
@s_pos = [self.x, self.y]
@dir = dir
@duration = duration
@frames = 0
@moving = true
end
def disappear(dir, duration = 40)
@s_pos = [self.x, self.y]
case dir
when 0
self.x += 560
when 1
self.y -= 400
when 2
self.x += 560
when 3
self.y += 400
end
@d_pos = [self.x, self.y]
self.x, self.y = *@s_pos
@dir = dir
@duration = duration
@frames = 0
@moving = true
end
def update
if @moving
self.x = (@d_pos[0] * @frames + @s_pos[0] * (@duration - @frames)) / @duration
self.y = (@d_pos[1] * @frames + @s_pos[1] * (@duration - @frames)) / @duration
@moving = ([self.x, self.y] != @d_pos)
@frames += 1
end
super()
end
end
class Window_Text < Window_Base
def initialize
super(48, 48, 544, 384)
self.contents = Bitmap.new(width - 32, height - 32)
@dual_keys = ['`','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E',
'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U',
'V','W','X','Y','Z','-','=','[',']','\\',';','\'',',','.','/']
@single_keys = ['NumberPad 0','NumberPad 1','NumberPad 2','NumberPad 3',
'NumberPad 4','NumberPad 5','NumberPad 6','NumberPad 7',
'NumberPad 8','NumberPad 9','Space','Enter','Tab']
@chars1 = ['`','1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w',
'x','y','z','-','=','[',']','/',';','\'',',','.','\\']
@chars2 = ['~','!','@','#','$','%','^','&','*','(',')','A','B','C','D','E','F',
'G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W',
'X','Y','Z','_','+','{','}','?',':','"','<','>','|']
@chars = ['0','1','2','3','4','5','6','7','8','9',' ','\n','\t']
@text = ""
@cursor = true
end
def update
@dual_keys.each_with_index { |i, ind|
if Input.repeat?(Input::Key[i])
@text += (Input.press?(Input::Key['Shift']) ? @chars2[ind] : @chars1[ind])
end
}
@single_keys.each_with_index { |i, ind|
if Input.repeat?(Input::Key[i])
@text += @chars[ind]
end
}
if Input.repeat?(Input::Key['Backspace'])
@text = @text.split('')
tmp = @text.pop()
if (tmp == 'n' or tmp == 't') and @text[@text.length - 1] == '\\'
@text.pop()
end
@text = @text.join('')
end
@cursor = !@cursor if Graphics.frame_count % 20 == 0
refresh
end
def refresh
self.contents.clear
tmp = @text.gsub(/((?:\\n)+)\z/, '')
y_mod = $1 ? $1.length / 2 : 0
x_pos = y_mod > 0
lns = tmp.gsub(/\\t/,' ').split(/\\n/)
y = 0
x = 0
lns.each_with_index { |ln, ind|
rect = self.contents.text_size(ln)
rect.height = self.contents.text_size('a').height
rect.width += 1 unless ln.index(/[vVAwf\/\\]\z/).nil?
rect.y = y
self.contents.draw_text(rect, ln)
y += rect.height
x = rect.width
}
#p lns if lns.length > 1
height = self.contents.text_size('a').height
y -= height unless lns.last.nil?
y += y_mod * height
x = (x_pos ? 0 : x + 1)
self.contents.fill_rect(Rect.new(x, y, 2, height), Color.new(0, 0, 0)) if @cursor
#@cursor = !@cursor
end
end
unless $BlizzABS or ($tons_version and TONS_OF_ADDONS::CUSTOM_CONTROLS)
#==============================================================================
# module Input
#==============================================================================
module Input
#----------------------------------------------------------------------------
# Simple ASCII table
#----------------------------------------------------------------------------
Key = {'A' => 65, 'B' => 66, 'C' => 67, 'D' => 68, 'E' => 69, 'F' => 70,
'G' => 71, 'H' => 72, 'I' => 73, 'J' => 74, 'K' => 75, 'L' => 76,
'M' => 77, 'N' => 78, 'O' => 79, 'P' => 80, 'Q' => 81, 'R' => 82,
'S' => 83, 'T' => 84, 'U' => 85, 'V' => 86, 'W' => 87, 'X' => 88,
'Y' => 89, 'Z' => 90,
'0' => 48, '1' => 49, '2' => 50, '3' => 51, '4' => 52, '5' => 53,
'6' => 54, '7' => 55, '8' => 56, '9' => 57,
'NumberPad 0' => 45, 'NumberPad 1' => 35, 'NumberPad 2' => 40,
'NumberPad 3' => 34, 'NumberPad 4' => 37, 'NumberPad 5' => 12,
'NumberPad 6' => 39, 'NumberPad 7' => 36, 'NumberPad 8' => 38,
'NumberPad 9' => 33,
'F1' => 112, 'F2' => 113, 'F3' => 114, 'F4' => 115, 'F5' => 116,
'F6' => 117, 'F7' => 118, 'F8' => 119, 'F9' => 120, 'F10' => 121,
'F11' => 122, 'F12' => 123,
';' => 186, '=' => 187, ',' => 188, '-' => 189, '.' => 190, '/' => 220,
'\\' => 191, '\'' => 222, '[' => 219, ']' => 221, '`' => 192,
'Backspace' => 8, 'Tab' => 9, 'Enter' => 13, 'Shift' => 16,
'Left Shift' => 160, 'Right Shift' => 161, 'Left Ctrl' => 162,
'Right Ctrl' => 163, 'Left Alt' => 164, 'Right Alt' => 165,
'Ctrl' => 17, 'Alt' => 18, 'Esc' => 27, 'Space' => 32, 'Page Up' => 33,
'Page Down' => 34, 'End' => 35, 'Home' => 36, 'Insert' => 45,
'Delete' => 46, 'Arrow Left' => 37, 'Arrow Up' => 38,
'Arrow Right' => 39, 'Arrow Down' => 40,
'Mouse Left' => 1, 'Mouse Right' => 2, 'Mouse Middle' => 4,
'Mouse 4' => 5, 'Mouse 5' => 6}
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
UP = [Key['Arrow Up']]
LEFT = [Key['Arrow Left']]
DOWN = [Key['Arrow Down']]
RIGHT = [Key['Arrow Right']]
A = [Key['Shift']]
B = [Key['Esc'], Key['NumberPad 0'], Key['X']]
C = [Key['Space'], Key['Enter'], Key['C']]
X = [Key['A']]
Y = [Key['S']]
Z = [Key['D']]
L = [Key['Q'], Key['Page Down']]
R = [Key['W'], Key['Page Up']]
F5 = [Key['F5']]
F6 = [Key['F6']]
F7 = [Key['F7']]
F8 = [Key['F8']]
F9 = [Key['F9']]
SHIFT = [Key['Shift']]
CTRL = [Key['Ctrl']]
ALT = [Key['Alt']]
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# All keys
KEY_COUNT = 256
ALL_KEYS = (0...KEY_COUNT).to_a
# Win32 API calls
GetKeyboardState = Win32API.new('user32', 'GetKeyboardState', 'P', 'I')
GetKeyboardLayout = Win32API.new('user32', 'GetKeyboardLayout', 'L', 'L')
MapVirtualKeyEx = Win32API.new('user32', 'MapVirtualKeyEx', 'IIL', 'I')
ToUnicodeEx = Win32API.new('user32', 'ToUnicodeEx', 'LLPPILL', 'L')
# some other constants
DOWN_STATE_MASK = 0x80
DEAD_KEY_MASK = 0x80000000
# data
@state = "\0" * KEY_COUNT
@triggered = Array.new(KEY_COUNT, false)
@pressed = Array.new(KEY_COUNT, false)
@released = Array.new(KEY_COUNT, false)
@repeatedKey = -1
@repeatedCount = 0
#----------------------------------------------------------------------------
# update
# Updates input.
#----------------------------------------------------------------------------
def self.update
# get current language layout
@language_layout = GetKeyboardLayout.call(0)
# get new keyboard state
GetKeyboardState.call(@state)
# this special code is used because Ruby 1.9.x does not return a char
# when using String#[] but another String
key = 0
@state.each_byte {|byte|
# if pressed state
if (byte & DOWN_STATE_MASK) == DOWN_STATE_MASK
# not released anymore
@released[key] = false
# if not pressed yet
if !@pressed[key]
# pressed and triggered
@pressed[key] = true
@triggered[key] = true
@repeatedKey = key
@repeatedCount = 0
else
# not triggered anymore
@triggered[key] = false
end
# update of repeat counter
if key == @repeatedKey
@repeatedCount < 17 ? @repeatedCount += 1 : @repeatedCount = 15
end
# not released yet
elsif !@released[key]
# if still pressed
if @pressed[key]
# not triggered, pressed or repeated, but released
@triggered[key] = false
@pressed[key] = false
@released[key] = true
if key == @repeatedKey
@repeatedKey = -1
@repeatedCount = 0
end
end
else
# not released anymore
@released[key] = false
end
key += 1}
end
#----------------------------------------------------------------------------
# dir4
# 4 direction check.
#----------------------------------------------------------------------------
def self.dir4
return 2 if self.press?(DOWN)
return 4 if self.press?(LEFT)
return 6 if self.press?(RIGHT)
return 8 if self.press?(UP)
return 0
end
#----------------------------------------------------------------------------
# dir8
# 8 direction check.
#----------------------------------------------------------------------------
def self.dir8
down = self.press?(DOWN)
left = self.press?(LEFT)
return 1 if down && left
right = self.press?(RIGHT)
return 3 if down && right
up = self.press?(UP)
return 7 if up && left
return 9 if up && right
return 2 if down
return 4 if left
return 6 if right
return 8 if up
return 0
end
#----------------------------------------------------------------------------
# trigger?
# Test if key was triggered once.
#----------------------------------------------------------------------------
def self.trigger?(keys)
keys = [keys] unless keys.is_a?(Array)
return keys.any? {|key| @triggered[key]}
end
#----------------------------------------------------------------------------
# press?
# Test if key is being pressed.
#----------------------------------------------------------------------------
def self.press?(keys)
keys = [keys] unless keys.is_a?(Array)
return keys.any? {|key| @pressed[key]}
end
#----------------------------------------------------------------------------
# repeat?
# Test if key is being pressed for repeating.
#----------------------------------------------------------------------------
def self.repeat?(keys)
keys = [keys] unless keys.is_a?(Array)
return (@repeatedKey >= 0 && keys.include?(@repeatedKey) &&
(@repeatedCount == 1 || @repeatedCount == 16))
end
#----------------------------------------------------------------------------
# release?
# Test if key was released.
#----------------------------------------------------------------------------
def self.release?(keys)
keys = [keys] unless keys.is_a?(Array)
return keys.any? {|key| @released[key]}
end
#----------------------------------------------------------------------------
# get_character
# vk - virtual key
# Gets the character from keyboard input using the input locale identifier
# (formerly called keyboard layout handles).
#----------------------------------------------------------------------------
def self.get_character(vk)
# get corresponding character from virtual key
c = MapVirtualKeyEx.call(vk, 2, @language_layout)
# stop if character is non-printable and not a dead key
return '' if c < 32 && (c & DEAD_KEY_MASK != DEAD_KEY_MASK)
# get scan code
vsc = MapVirtualKeyEx.call(vk, 0, @language_layout)
# result string is never longer than 4 bytes (Unicode)
result = "\0" * 4
# get input string from Win32 API
length = ToUnicodeEx.call(vk, vsc, @state, result, 4, 0, @language_layout)
return (length == 0 ? '' : result)
end
#----------------------------------------------------------------------------
# get_input_string
# Gets the string that was entered using the keyboard over the input locale
# identifier (formerly called keyboard layout handles).
#----------------------------------------------------------------------------
def self.get_input_string
result = ''
# check every key
ALL_KEYS.each {|key|
# if repeated
if self.repeat?(key)
# get character from keyboard state
c = self.get_character(key)
# add character if there is a character
result += c if c != ''
end}
# empty if result is empty
return '' if result == ''
# convert string from Unicode to UTF-8
return self.unicode_to_utf8(result)
end
#----------------------------------------------------------------------------
# unicode_to_utf8
# string - string in Unicode format
# Converts a string from Unicode format to UTF-8 format as RGSS does not
# support Unicode.
#----------------------------------------------------------------------------
def self.unicode_to_utf8(string)
result = ''
# L* format means a bunch of 4-byte wide-chars
string.unpack('L*').each {|c|
# characters under 0x80 are 1 byte characters
if c < 0x0080
result += c.chr
# other characters under 0x800 are 2 byte characters
elsif c < 0x0800
result += (0xC0 | (c >> 6)).chr
result += (0x80 | (c & 0x3F)).chr
# other characters under 0x10000 are 3 byte characters
elsif c < 0x10000
result += (0xE0 | (c >> 12)).chr
result += (0x80 | ((c >> 6) & 0x3F)).chr
result += (0x80 | (c & 0x3F)).chr
# other characters under 0x200000 are 4 byte characters
elsif c < 0x200000
result += (0xF0 | (c >> 18)).chr
result += (0x80 | ((c >> 12) & 0x3F)).chr
result += (0x80 | ((c >> 6) & 0x3F)).chr
result += (0x80 | (c & 0x3F)).chr
# other characters under 0x4000000 are 5 byte characters
elsif c < 0x4000000
result += (0xF8 | (c >> 24)).chr
result += (0x80 | ((c >> 18) & 0x3F)).chr
result += (0x80 | ((c >> 12) & 0x3F)).chr
result += (0x80 | ((c >> 6) & 0x3F)).chr
result += (0x80 | (c & 0x3F)).chr
# other characters under 0x80000000 are 6 byte characters
elsif c < 0x80000000
result += (0xFC | (c >> 30)).chr
result += (0x80 | ((c >> 24) & 0x3F)).chr
result += (0x80 | ((c >> 18) & 0x3F)).chr
result += (0x80 | ((c >> 12) & 0x3F)).chr
result += (0x80 | ((c >> 6) & 0x3F)).chr
result += (0x80 | (c & 0x3F)).chr
end}
return result
end
end
end
All in the script.
No known issues, but may not work with other scripts that change the tint unless you turn tinting off.