Local Achievements script VX + Ace
Heya. I was dissapointed with absence of a propper Achievement handler besides Steam API for VX, so I made my own that utilizes local files and events!Keeps track of locked and unlocked achievements on title screen via extra window command, an option to reset collection progress as well.
Progress saves between save files, and after a shutdown.
Ruby:
# Achievements Script for RPGMaker VX by @le_kastle (pls credit)
module Achievements
# Create achievements.txt in Data folder, and achivement images in Graphics/Pictures
FILE_PATH = "Data/achievements.txt"
ACHIEVEMENTS = {
:achievement1 => { :name => "1", :description => "desc1", :achieved => false, :image => "achievement1", :common_event_id => 6 },
:achievement2 => { :name => "2", :description => "desc2", :achieved => false, :image => "achievement2", :common_event_id => 7 },
:achievement3 => { :name => "3", :description => "desc3", :achieved => false, :image => "achievement3", :common_event_id => 8 }
} # Common events used for displaying achievement acquirement in game (if you want it)
# Loads achievements from a file
def self.load_achievements
return unless File.exist?(FILE_PATH)
File.readlines(FILE_PATH).each do |line|
key, value = line.strip.split(" = ")
key = key.downcase.to_sym
if ACHIEVEMENTS.has_key?(key)
ACHIEVEMENTS[:achieved] = (value == "true")
else
puts "Warning: Achievement key '#{key}' not found in ACHIEVEMENTS hash."
end
end
end
# Save the achievements to the file
def self.save_achievements
File.open(FILE_PATH, "w") do |file|
ACHIEVEMENTS.each do |key, data|
file.puts "#{key} = #{data[:achieved]}"
end
end
end
# Unlock an achievement
def self.unlock(achievement)
return if ACHIEVEMENTS[:achieved]
ACHIEVEMENTS[:achieved] = true
save_achievements
end
# Check if an achievement is unlocked
def self.unlocked?(achievement)
ACHIEVEMENTS[:achieved]
end
# Reset all achievements
def self.reset_achievements
ACHIEVEMENTS.each do |key, data|
data[:achieved] = false
end
save_achievements
end
end
# Interpreter integration for unlocking achievements
class Game_Interpreter
def unlock_achievement(achievement)
Achievements.unlock(achievement)
end
end
class Scene_Title < Scene_Base
alias achievements_update update unless method_defined?(:achievements_update)
def update
achievements_update
handle_achievements_input if @command_window && @command_window.active
end
private
# Handle Achievements command
def command_achievements
Sound.play_decision
$scene = Scene_Achievements.new
end
def handle_achievements_input
return unless Input.trigger?(Input::C)
case @command_window.index
when 3 # Achievements
command_achievements
when 4 # Reset
command_reset_achievements
end
end
# Handle Reset Achievements command
def command_reset_achievements
Sound.play_decision
if confirm_reset_achievements
Achievements.reset_achievements
Sound.play_recovery
else
Sound.play_buzzer
end
end
# Confirmation to reset
def confirm_reset_achievements
Graphics.update
Input.update
# Wait for input for confirmation
loop do
Graphics.update
Input.update
if Input.trigger?(Input::C)# Confirm
return true
elsif Input.trigger?(Input::B)# Cancel with ESC
return false
end
end
end
end
class Scene_Achievements < Scene_Base
def start
super
create_achievement_window
end
def create_achievement_window
@achievement_window = Window_Achievements.new(0, 0, Graphics.width, Graphics.height)
end
def update
super
@achievement_window.update
if Input.trigger?(Input::B)
Sound.play_cancel
return_to_title
end
end
# Properly dispose of the window and return to the title
def return_to_title
@achievement_window.dispose
$scene = Scene_Title.new
end
end
# Achievement window
class Window_Achievements < Window_Base
def initialize(x, y, width, height)
super(x, y, width, height)
@page = 0
refresh
end
def refresh
self.contents.clear
draw_page_indicator
achievements = Achievements::ACHIEVEMENTS.to_a[@page * 3, 3]# Adjust number of achievements per page
achievements.each_with_index do |(key, data), index|
draw_achievement(data, index)
end
end
def draw_page_indicator
total_pages = (Achievements::ACHIEVEMENTS.size / 3.0).ceil
text = "Page #{@page + 1}/#{total_pages}"
self.contents.draw_text(0, self.contents.height - 24, self.contents.width, 24, text, 1)
end
def draw_achievement(data, index)
# Calculate manual position for each achievement entry
x = 12
y = index * WLH * 4# Increase the spacing to reduce overlap
# Draw achievement name and description
self.contents.font.color = normal_color
self.contents.draw_text(x + 110, y, contents.width - 110, WLH, data[:name])
if data[:achieved]
self.contents.draw_text(x + 110, y + WLH, contents.width - 110, WLH, data[:description])
end
# Draw achievement icon (if available)
draw_icon(data[:image], x, y)
end
def draw_icon(image_name, x, y)
bitmap = Cache.picture(image_name)
rect = Rect.new(0, 0, 100, 100)
self.contents.blt(x, y, bitmap, rect)
end
def update
super
if Input.trigger?(Input::RIGHT)
next_page
elsif Input.trigger?(Input::LEFT)
prev_page
end
end
def next_page
@page = (@page + 1) % total_pages
refresh
end
def prev_page
@page = (@page - 1) % total_pages
refresh
end
def total_pages
(Achievements::ACHIEVEMENTS.size / 3.0).ceil# Adjust the page count
end
end
# Load achievements at game start
Achievements.load_achievements
How to utilize:
1. Put anywhere in your custom scripts area in the editor (Above main)
2. Use this in event tab:
Code:
if Achievements.unlocked?(:achievement1)
# Code to execute if the achievement is already unlocked (for example activate switch)
else
# Unlock if not unlocked already
unlock_achievement(:achievement1)
end
Watch screenshots to see how it works
本贴来自国际rpgmaker官方论坛作者:Kastle处,因国际论坛即将永久关站,为了存档多年珍贵资料,署名转载到本论坛存档,由于官方帖子为英文原帖,需要中文翻译请点击论坛顶部切换语言为中文就可以将帖子翻译成中文浏览,方便大家随时查看,原文地址:https://forums.rpgmakerweb.com/threads/local-achievements-script-vx-ace.175371/
页:
[1]