KyoWatch XP / VX Version: 1.0.1.1 By: Kyonides alias Kyonides-Arkanthos, Shadowball
Introduction
It allows the player to set a clock, configure a calendar (made of simple text sprites for now), so the player may think the game has its own clock for calculating when any event might happen and it may not be affected by the OS clock / calendar at all and even so the data will look realistic. Well, the clock on the menu screen will show its hands once the clock is set. It should show / update the current time correctly.
Features
Digital Clock
Analog Clock
Calendar with correct data about dates (including leap year calculation)
Can set the time from event via script call
Screenshots
For later, but you can download the demo and the script in a separate file if you like.
# KyoWatch VX
# v 1.0.1.0 - 12.27.2009
# v 1.0.0.1 - 12.22.2009
# by Kyonides-Arkanthos alias Kyonides, Shadowball
# Plug and Play script
# Basic Instructions
# If $game_kyowatch.no_reset is false, you may set the clock and setup the
# calendar options. Otherwise you will hear a Buzzer telling you the clock
# settings cannot be modified.
# You may create a script call like this one
#
# $game_kyowatch.no_reset = true
#
# to prevent the player to change the clock / calendar settings at any time.
# YearRangeMIN and YearRangeMAX are the minimal and maximal limits for the
# current year settings. Any other value is unavailable but you may modify
# these Constants at will before you play the game.
# KyoX and KyoY are the default values for the clock graphic X and Y
# coordinates. You may also change this values as needed.
# The rest of the script, except for the Constants for the graphic filenames,
# should stay as it is. I mean, you should leave the rest of the script alone
# especially if you are no scripter. This will prevent any malfunctioning
# from ever happening.
# For any bugs you may contact me at anytime by sending a PM or an email.
class Sprite_KyoPicture < Sprite # Class to show a picture that may rotate
def initialize(name, center=true, viewport=nil)
@viewport = Viewport.new(0,0,544,416) if viewport == nil
@viewport = viewport if viewport != nil
super(@viewport)
self.bitmap = Cache.picture(name)
@width = self.bitmap.width/2
self.x, self.y, self.z = 0, 0, 1000
self.ox, self.oy = @width, @width if center
self.ox, self.oy = 0, 0 if !center
end
def update(value)
if Input.trigger?(Input::UP) or Input.repeat?(Input::UP)
self.angle -= value
elsif Input.trigger?(Input::DOWN) or Input.repeat?(Input::DOWN)
self.angle += value
end
end
def rotate(value)
self.angle -= value
end
def refresh(name,x=0,y=0,center=true)
self.bitmap = Cache.picture(name)
@width = self.bitmap.width/2
self.x, self.y, self.z = x, y, 1000
self.ox, self.oy = @width, @width if center
self.ox, self.oy = 0, 0 if !center
end
end
class Sprite_PlayTime < Sprite # Just A PlayTime Script
def initialize(x=0,y=0)
@viewport = Viewport.new(0,0,544,416)
super(@viewport)
self.bitmap = Bitmap.new(140, 48)
self.bitmap.font.name = 'Digital-7'
self.bitmap.font.size = 32
self.bitmap.font.bold = true
self.x, self.y, self.z, self.visible = x, y, 1000, true
update
end
def update
super
@clock.update_clock
if @clock.time_now != @time_now
refresh
end
end
def refresh
self.bitmap.clear
@clock.update_clock
self.bitmap.font.color.set(255, 255, 255)
self.bitmap.draw_text(self.bitmap.rect, @day.to_s)
@time_now = @clock.time_now
end
end
class Sprite_KyoWatchSys < Sprite # Make the Clock hands rotate
attr_accessor :hour, :min, :ampm, :active
def initialize(x=0,y=0,f1=false,f2=false,f3=false)
@viewport = Viewport.new(0,0,544,416)
super(@viewport)
self.bitmap = Bitmap.new(116, 48)
self.bitmap.font.name = 'Digital-7'
self.bitmap.font.size = 32
self.bitmap.font.bold = true
self.x, self.y, self.z, self.visible = x, y, 1000, true
@active = false
@clock = $game_kyowatch.kyoclock
@hour, @min, @ampm = @clock[3]%12, @clock[4], @clock[5]
update(f1,f2,f3) if @active
end
def update(hour_flag, min_flag, ampm_flag)
if @active
@hour_flag, @min_flag, @ampm_flag = hour_flag, min_flag, ampm_flag
update_hour if !@hour_flag
update_minute if @hour_flag and !@min_flag
update_ampm if @hour_flag and @min_flag and !@ampm_flag
end
refresh
end
def update_hour
@hour = 12 if @hour == 0
@hour -= 12 if @hour >= 13
if Input.trigger?(Input::UP) or Input.repeat?(Input::UP)
@hour += 1 if @hour >= 0 and @hour <= 12
@hour = 1 if @hour == 13
elsif Input.trigger?(Input::DOWN) or Input.repeat?(Input::DOWN)
@hour -= 1 if @hour >= 0 and @hour <= 12
@hour = 12 if @hour == 0
end
end
def update_minute
if Input.trigger?(Input::UP) or Input.repeat?(Input::UP)
@min += 1 if @min >= 0 and @min <= 60
@min = 0 if @min == 60
elsif Input.trigger?(Input::DOWN) or Input.repeat?(Input::DOWN)
@min -= 1 if @min >= 0 and @min <= 60
@min = 59 if @min == -1
end
end
def update_ampm
if Input.trigger?(Input::DOWN) or Input.trigger?(Input::LEFT)
@ampm = 'AM'
elsif Input.trigger?(Input::UP) or Input.trigger?(Input::RIGHT)
@ampm = 'PM'
end
end
def refresh
self.bitmap.clear
text = sprintf("%02d:%02d", @hour, @min)
self.bitmap.font.color.set(255, 255, 255)
self.bitmap.draw_text(self.bitmap.rect, text+' '+@ampm, 1)
end
end
class Sprite_KyoCalendarSys < Sprite_KyoWatchSys # Setup the current date
include KyoVocab
attr_accessor :year, :month, :day, :day_name, :update_sprite, :on_screen
alias :kyon_skcs_init :initialize
def initialize(x=0,y=0,f1=false,f2=false,f3=false,f4=false)
kyon_skcs_init(x=0,y=0,f1=false,f2=false,f3=false)
@clock_req = $game_kyowatch
@year, @month, @day = @clock[0], @clock[1], @clock[2]
@day_name = @clock[6]
@update_sprite = nil
@on_screen = false
update(f1,f2,f3,f4) if @active
end
def update(year_flag, month_flag, day_flag, day_name_flag)
if @active
@year_flag, @month_flag = year_flag, month_flag
@day_flag, @day_name_flag = day_flag, day_name_flag
update_year if !@year_flag
update_month if @year_flag and !@month_flag
update_day if @year_flag and @month_flag and !@day_flag
update_day_name if @day_flag and !@day_name_flag and !@on_screen
end
refresh(@update_sprite)
end
def update_year
if Input.trigger?(Input::UP) or Input.repeat?(Input::UP)
@year += 1 if @year >= YearRangeMIN and @year <= YearRangeMAX
@year = YearRangeMIN if @year == YearRangeMAX+1
elsif Input.trigger?(Input::DOWN) or Input.repeat?(Input::DOWN)
@year -= 1 if @year >= YearRangeMIN and @year <= YearRangeMAX
@year = YearRangeMAX if @year == YearRangeMIN-1
end
end
def update_month
if Input.trigger?(Input::UP) or Input.repeat?(Input::UP)
@month += 1 if @month >= 1 and @month <= 12
@month = 1 if @month == 13 or @month == 0
elsif Input.trigger?(Input::DOWN) or Input.repeat?(Input::DOWN)
@month -= 1 if @month >= 1 and @month <= 12
@month = 12 if @month == 0
end
end
def update_day
if Input.trigger?(Input::UP) or Input.repeat?(Input::UP)
if !@clock_req.leap? @year
@day += 1 if @day >= 1 and @day <= REGYEAR[@month]
@day = 1 if @day == 0 or @day > REGYEAR[@month]
elsif @clock_req.leap? @year
@day += 1 if @day >= 1 and @day <= LEAPYEAR[@month]
@day = 1 if @day == 0 or @day > LEAPYEAR[@month]
end
elsif Input.trigger?(Input::DOWN) or Input.repeat?(Input::DOWN)
if !@clock_req.leap? @year
@day -= 1 if @day >= 1 and @day <= REGYEAR[@month]
@day = REGYEAR[@month] if @day == 0 or @day > REGYEAR[@month]
elsif @clock_req.leap? @year
@day -= 1 if @day >= 1 and @day <= LEAPYEAR[@month]
@day = LEAPYEAR[@month] if @day == 0 or @day > LEAPYEAR[@month]
end
end
end
def refresh(target_sprite=nil) # A Sprite as argument
@target_sprite = target_sprite
if @target_sprite != nil and @target_sprite.is_a? Sprite
# Current target is KyoYear
if !@year_flag and !@month_flag
@this_year = @target_sprite
@this_year.year = @year
@this_year.refresh
# Current target is KyoMonthName
elsif @year_flag and !@month_flag and !@day_flag
@this_month = @target_sprite
@this_month.mname = @month
@this_month.refresh
# Current target is KyoDay
elsif @year_flag and @month_flag and !@day_flag
@todaynum = @target_sprite
@todaynum.day = @day
@todaynum.refresh
elsif @month_flag and @day_flag and !@day_name_flag
@today = @target_sprite
@today.dname = @day_name
@today.refresh
end
end
end
end
def update
super
@clock.update_clock
if @clock.time_now != @time_now
refresh
end
end
def refresh
self.bitmap.clear
@clock.update_clock
c = @clock.time_now
@clock.weekday = KyoDayFullNames if @clock.full_mnames
@clock.weekday = KyoDayPartialNames if !@clock.full_mnames
text = @clock.weekday[@dname]
self.bitmap.font.color.set(255, 255, 255)
self.bitmap.draw_text(self.bitmap.rect, text)
@time_now = @clock.time_now
end
end
class Sprite_KyoMonthName < Sprite_KyoDayName
def refresh
self.bitmap.clear
@clock.update_clock
c = @clock.time_now
@clock.month_name = KyoMonthFullNames if @clock.full_mnames
@clock.month_name = KyoMonthPartialNames if !@clock.full_mnames
text = @clock.month_name[@mname]
self.bitmap.font.color.set(255, 255, 255)
self.bitmap.draw_text(self.bitmap.rect, text)
@time_now = @clock.time_now
end
end
class Scene_Menu < Scene_Base
include KyoVocab
def initialize(menu_index=0)
@menu_index = menu_index
@clock = $game_kyowatch # Call Watch script
@minutes = @clock.minutes * 6 if !@clock.no_clocktime
@hours = @clock.hours * 30 if !@clock.no_clocktime
end
def terminate
super
dispose_menu_background
[@command_window,@gold_window,@pokeball,@playtime].each {|s| s.dispose}
[@clockpic, @clockmin, @clockhour, @watch, @weekday].each do |s|
s.dispose if !@clock.no_clocktime
end
end
def update
super
update_menu_background
@command_window.update
if !@clock.no_clocktime
@clockmin.rotate(@clock.minutes*6-@minutes)
@clockhour.rotate(@clock.hours*30-@hours)
@minutes = @clock.minutes*6
@hours = @clock.hours*30
end
@pokeball.update(45)
@gold_window.update
@playtime.update
@watch.update if !@clock.no_clocktime
@weekday.update if !@clock.no_clocktime
update_command_selection if @command_window.active
end
def create_command_window
s1 = 'Bestiary'
s2 = 'Party'
s3 = Vocab::item
s4 = 'Map'
s5 = 'Watch'
s6 = 'Achievements'
s7 = Vocab::save
s8 = 'Options'
s9 = Vocab::game_end
@kyon_options = [s1,s2,s3,s4,s5,s6,s7,s8,s9]
@command_window = Window_Command.new(160, @kyon_options)
@command_window.x = 384
@command_window.index = @menu_index
if $game_system.save_disabled # If save is forbidden
@command_window.draw_item(6, false) # Disable save
end
end
def update_command_selection
if Input.trigger?(Input::B)
Sound.play_cancel
$scene = Scene_Map.new
elsif Input.trigger?(Input::C)
if $game_system.save_disabled and @command_window.index == 4
Sound.play_buzzer
return
end
Sound.play_decision
case @command_window.index
when 0 # Bestiary
#$scene = Scene_KyoBestiary.new
when 1 # Party Members
#$scene = Scene_KyoMembers.new
when 2 # Items / Bag
#$scene = Scene_KyoItems.new
when 3 # Map
#$scene = Scene_KyoMapViewer.new
when 4 # Watch
$scene = Scene_KyoWatch.new if !$game_kyowatch.no_reset
when 5 # Achievements
#$scene = Scene_KyoMadeIt.new
when 6 # Save
$scene = Scene_File.new(true, false, false)
when 7 # Options
#$scene = Scene_KyoWinSkin.new
when 8 # End Game
$scene = Scene_End.new
end
end
end
end
class Scene_KyoWatch < Scene_Base
include KyoVocab
def initialize
@clock = $game_kyowatch
end
def sun_moon_settings # Should the Sun or the Moon picture appear?
@am_pm = @watch.ampm # Load picture depending on current daytime
@hour = @watch.hour
if @am_pm == 'AM' or @am_pm == 'PM' # Check the Daytime Hash
@picture = KyoSun if KyoDay[@am_pm].include?(@hour)
@picture = KyoMoon if !KyoDay[@am_pm].include?(@hour)
elsif @am_pm == '??'
@picture = KyoSun
end
end
def terminate
super
dispose_menu_background
things = [@clockhour, @clockmin, @watch_back, @help_window, @sun_moon]
things.push @clockpic, @watch, @command_window, @calendar
things.push @this_year, @this_month, @todaynum, @today
things.each {|s| s.dispose}
end
def update
super
update_menu_background
@command_window.update
@help_window.update
if @command_window.active
update_command
elsif !@command_window.active
# Set the clock if index == 0
if @command_window.index == 0
@watch.update(@kyon_fixed_hour, @kyon_fixed_min, @kyon_fixed_ampm)
if !@kyon_fixed_hour and @kyon_set_flags and !@kyon_exit
update_hour
elsif @kyon_fixed_hour and !@kyon_fixed_min
update_min
elsif @kyon_fixed_hour and @kyon_fixed_min and !@kyon_fixed_ampm
update_ampm
elsif @kyon_fixed_min and @kyon_fixed_ampm and !@kyon_exit
update_exit_current_setup # Show confirmation message
end
# Setup the calendar if index == 1
elsif @command_window.index == 1
@calendar.update(@kyon_fixed_year, @kyon_fixed_month,
@kyon_fixed_day, @kyon_fixed_day_name)
if !@kyon_fixed_year and !@kyon_fixed_month
update_year
elsif @kyon_fixed_year and !@kyon_fixed_month
update_month
elsif @kyon_fixed_year and @kyon_fixed_month and !@kyon_fixed_day
update_day
elsif @kyon_fixed_year and @kyon_fixed_month and @kyon_fixed_day and
!@kyon_fixed_day_name
update_day_name
elsif @kyon_fixed_day and @kyon_fixed_day_name and @calendar.on_screen
update_exit_current_setup # Show confirmation message
end
end
end
end
def update_command
@help_window.set_text('KyoWatch VX version 1.0', 1)
if Input.trigger?(Input::B)
if @kyon_set_flags
Sound.play_buzzer
return
else
Sound.play_cancel
$scene = Scene_Map.new
end
elsif Input.trigger?(Input::C)
Sound.play_decision
@index = @command_window.index
case @index
when 0, 1
kyon_reset_flags
@kyon_exit = false # Need to set the clock
@command_window.active = false
@command_window.visible = false
@calendar.update_sprite = @this_year if @index == 1
@watch.active = true if @index == 0
@calendar.active = true if @index == 1
end
end
end
def update_hour
@help_window.set_text('Please set the current hour.', 1)
@clockhour.update(30) if !@kyon_fixed_hour
if Input.trigger?(Input::C)
@kyon_fixed_hour = true if !@kyon_fixed_hour
end
end
def update_min
@help_window.set_text('Please set the current minutes.', 1)
@clockmin.update(6) if @kyon_fixed_hour and !@kyon_fixed_min
if Input.trigger?(Input::C)
@kyon_fixed_min = true if !@kyon_fixed_min
end
end
def update_ampm
@help_window.set_text('Is it AM or PM?', 1)
if Input.trigger?(Input::C)
if !@kyon_fixed_ampm and @watch.ampm != '??'
@kyon_fixed_ampm = true
else
return
end
sun_moon_settings
@sun_moon.refresh(@picture,0,140)
# Clock does not handle 24 hours, check how many hours passed
# and calculate the time in 24 hour format if needed
if @watch.hour > 0 and @watch.hour < 12 and @watch.ampm == 'PM'
hour = @watch.hour + 12
elsif @watch.hour == 12 and @watch.ampm == 'AM'
hour = 0
else
hour = @watch.hour
end
h_min_ampm = [hour, @watch.min, @watch.ampm]
@clock.kyoclock[3,3] = h_min_ampm
@clock.frame_count = Graphics.frame_count
@clock.update_clock
@clock.no_clocktime = false
end
end
def update_year
@help_window.set_text('And the current year is...', 1)
if Input.trigger?(Input::C)
if !@kyon_fixed_year and @calendar.year >= YearRangeMIN
@kyon_fixed_year = true
@calendar.update_sprite = @this_month
end
end
end
def update_month
@help_window.set_text('What about the current month?', 1)
if Input.trigger?(Input::C)
if !@kyon_fixed_month
@kyon_fixed_month = true
@calendar.update_sprite = @todaynum
end
end
end
def update_day
@help_window.set_text('What day is it?', 1)
if Input.trigger?(Input::C)
if !@kyon_fixed_day
@kyon_fixed_day = true
@calendar.update_sprite = @today
@today.refresh
end
end
end
def update_day_name
@help_window.set_text('Now you should see the name of the day', 1)
if Input.trigger?(Input::C)
return if @kyon_fixed_day_name
@kyon_fixed_day_name = true
year_month_day = [@calendar.year, @calendar.month, @calendar.day]
@clock.kyoclock[6] = @calendar.day_name if @kyon_set_flags
@clock.kyoclock[0,3] = year_month_day if @kyon_set_flags
end
end
def update_exit_current_setup
text = 'Ready! Now press Enter to exit to the selection menu'
@help_window.set_text(text, 1)
if Input.trigger?(Input::C)
@kyon_set_flags = false if @kyon_set_flags
@watch.active = false if @watch.active
@calendar.active = false if @calendar.active
@command_window.visible = true
@command_window.active = true
end
end
def kyon_reset_flags
if @command_window.index == 0
@kyon_fixed_hour, @kyon_fixed_ampm, @kyon_fixed_min = false, false, false
elsif @command_window.index == 1
@kyon_fixed_year, @kyon_fixed_month = false, false
@kyon_fixed_day, @kyon_fixed_day_name = false, false
end
@kyon_set_flags = true # Need to set hour, minutes and AM / PM or setup date
end
end
class Scene_Title
alias kyon_title_cgo create_game_objects
alias kyon_title_cng command_new_game
def create_game_objects
kyon_title_cgo
$game_kyowatch = Game_KyoWatch.new # Call system script
end
def command_new_game
$game_kyowatch.frame_count = 0 # Reset frame count before
kyon_title_cng # setting up the clocktime for the first time
end
end
class Scene_File
def return_scene
if @from_title
$scene = Scene_Title.new
elsif @from_event
$scene = Scene_Map.new
else
$scene = Scene_Menu.new(6) # Save option current position
end
end
alias kyon_sf_wsd write_save_data
def write_save_data(file)
kyon_sf_wsd(file) # Do not forget to save the System script
Marshal.dump($game_kyowatch, file)
end
def read_save_data(file)
characters = Marshal.load(file)
Graphics.frame_count = Marshal.load(file)
@last_bgm = Marshal.load(file)
@last_bgs = Marshal.load(file)
$game_system = Marshal.load(file)
$game_message = Marshal.load(file)
$game_switches = Marshal.load(file)
$game_variables = Marshal.load(file)
$game_self_switches = Marshal.load(file)
$game_actors = Marshal.load(file)
$game_party = Marshal.load(file)
$game_troop = Marshal.load(file)
$game_map = Marshal.load(file)
$game_player = Marshal.load(file)
# Load Watch System script data
$game_kyowatch = Marshal.load(file) if !file.eof?
$game_kyowatch = Game_Kyowatch.new if file.eof?
if $game_system.version_id != $data_system.version_id
$game_map.setup($game_map.map_id)
$game_player.center($game_player.x, $game_player.y)
end
end
end
Instructions
The script includes a menu screen that already includes an option to enter the Clock and Calendar scene. You may need to add that option manually to any other menu like a Ring Menu script.
You may call the script like this
$scene = Scene_KyoWatch.new
To enable or disable access to the scene, use this line at any time
$game_kyowatch.no_reset = true (or false if needed)
Take a look at the Constants inside the KyoVocab module, there you can edit any graphic configuration related to the script, but there are a lot of things you may leave alone to make sure the script will work properly.
BTW, the Scene_File script was modified to include my script while saving or loading data from the save data file. Don't ever forget that! Of course, I modified the Scene_Title scene, too, to load the Game class I added named Game_KyoWatch.
Bugs
There was a little bug in a previous version that was solved in the current one (1.0.0.1). I just forgot to include an if statement twice in lines 540 and 541, I think, so the clock does not start spinning right away but just after the player set the clock at least once.
The Demo and the Script were updated.
FAQ
None yet.
Compatibility
Not sure if it's SDK compliant, maybe not, gotta check it out.
Credits and Thanks
Well, the clock graphic (except for the clock hands) are not mine but from a guy that made it for KDE (a Linux OS GUI).
Thanks, GlitchFinder for telling me about the EOF compatibility issue.
Author's Notes
Now it's also available for XP! (I also fix some little bug...)
I wished the Maker included the DateTime class... it would make it a bit easier to develop it.
Terms and Conditions
Not intended for Commercial Use.
I should be credited for the script if included in any project or game.