じ☆ve冰风 发表于 2026-7-24 11:00:11

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]
查看完整版本: Local Achievements script VX + Ace