KSkillRunes XP
#1
KSkillRunes XP
Version Beta 9


by Kyonides Arkanthes

Introduction

The following script pretends to be an alternative to a Materia System. It uses the so called Runes to let you learn new skills. You then get the need to sum up rune points in order to activate those skills permanently or to level them up.

Instructions have been included in the script.



Script

Code:
# * KSkillRunes XP
#   Scripter : Kyonides Arkanthes
#   2021-04-03 - Beta 9

# This script is a Rune Based Skill Learning System vaguely similar to a
# Materia System.

# * Instructions * #

# Create Items representing the Rune Skill Gem Stones.
# Create a Temp directory and place the template TXT file here and set its
# values accordingly. Copy and Paste it into new TXT files as many times as
# needed.
# Set the ITEM_IDS_RANGE constant's value below.
# If a Hero has acquired a Rune Gem Stone, no existing skills will be
# overwritten. Every Rune Gem Stone has an activation cost (in gold pieces).
# Every Rune Skill needs Rune Points so spend them wisely.

# Game_Battler#skill_effect has been overwritten.

# * Script Calls * #

# * Open Rune Scene - Positions: 0 through 3
# $scene = KSkillRuneScene.new
# $scene = KSkillRuneScene.new(ActorIndex)
# * First Select an Actor - Positions: 0 through 3
# actor = $game_party.actors[Position]
# * Set or Increase or Decrease the Maximum Number of the Actor's Skill Runes
# actor.skill_runes_max = Number
# actor.skill_runes_max += Number
# actor.skill_runes_max -= Number
# * Manually Increase an Actor's RP (Rune Points)
# actor.rp += Number
# * Use Rune Points RP to Activate a given Skill the Rune can teach the Hero
# actor.learn_rune_skill(RuneItemID, TargetSkillID)

module KSRunes
  TEMP_DIR = "Temp"
  MISSED_TARGET = "Miss"
  TITLE = 'Skill Runes'
  STARTING_RUNE_MAX = 1
  ITEM_IDS_RANGE = 40..51
  BACKDROP = ''
  ACTOR_BLOCKED_RUNES = {}
# * End of Setup Section * #
  class Skill
    attr_accessor :id, :level, :learn_skill, :skill_points
    def can_learn?(pts) @skill_points == pts end
  end

  class Rune
    def initialize
      @id = 0
      @name = ""
      @level = 0
      @level_max = 1
      @blocked_rune = 0
      @price = 0
      @skills = {}
    end
    attr_accessor :id, :name, :level, :level_max, :blocked_rune, :price, :skills
  end
  extend self
  attr_reader :runes
  def scan_int(line) line.scan(/\d+/).map{|d| d.to_i } end
  def parse_skill(numbers)
    skill = Skill.new
    skill.id = numbers.shift
    skill.level = numbers.shift
    skill.learn_skill = numbers.shift
    skill.skill_points = numbers.shift
    skill
  end

  def parse_file(name)
    rune = Rune.new
    lines = File.readlines(name)
    rune.id = scan_int(lines.shift)[0]
    rune.name = lines.shift.sub(/magic type: /i, "")
    rune.level = scan_int(lines.shift)[0]
    rune.level_max = scan_int(lines.shift)[0]
    rune.blocked_rune = scan_int(lines.shift)[0] || 0
    rune.price = scan_int(lines.shift)[0]
    n = 0
    lines.each do |line|
      numbers = scan_int(line)
      skill = parse_skill(numbers)
      rune.skills[skill.id] = skill
    end
    @runes[rune.id] = rune
  end

  def retrieve_runes
    return @runes = load_data('Data/KSkillRunes.rxdata') unless $DEBUG
    @runes = {}
    Dir[TEMP_DIR + '/*.txt'].sort.each{|name| parse_file(name) }
    File.open('Data/KSkillRunes.rxdata', 'wb'){|f| Marshal.dump(@runes, f) }
  end
  retrieve_runes
end

class Game_Battler
  def alive_not_dead?(skill)
    (skill.scope == 3 or skill.scope == 4) and @hp == 0
  end

  def dead_not_alive?(skill)
    (skill.scope == 5 or skill.scope == 6) and @hp >= 1
  end

  def calculate_skill_power
    power = @skill.power
    if @user.is_actor? and @user.rune_skill?(@skill.id)
      rune_skill = @user.rune_skills[@skill.id]
      power += @skill.variance * rune_skill.level
    end
    power = power + @user.atk * @skill.atk_f / 100
    if power > 0
      power -= self.pdef * @skill.pdef_f / 200
      power -= self.mdef * @skill.mdef_f / 200
      power = [power, 0].max
    end
    power
  end

  def checking_hit(hit, hit_result)
    return hit unless hit_result
    power = calculate_skill_power
    rate = 20
    rate += (@user.str * @skill.str_f / 100)
    rate += (@user.dex * @skill.dex_f / 100)
    rate += (@user.agi * @skill.agi_f / 100)
    rate += (@user.int * @skill.int_f / 100)
    @damage = power * rate / 20
    @damage *= elements_correct(@skill.element_set)
    @damage /= 100
    @damage /= 2 if @damage > 0 and self.guarding?
    if @skill.variance > 0 and @damage.abs > 0
      amp = [@damage.abs * @skill.variance / 100, 1].max
      @damage += rand(amp+1) + rand(amp+1) - amp
    end
    eva = 8 * self.agi / @user.dex + self.eva
    hit = @damage < 0 ? 100 : 100 - eva * @skill.eva_f / 100
    self.cant_evade? ? 100 : hit
  end

  def checking_effectivity(effective)
    if @skill.power != 0 and @skill.atk_f > 0
      remove_states_shock
      effective = true
    end
    last_hp = @hp
    self.hp -= @damage
    effective |= @hp != last_hp
    @state_changed = false
    effective |= states_plus(@skill.plus_state_set)
    effective |= states_minus(@skill.minus_state_set)
    @last_damage = @damage
    if @skill.power == 0
      @damage = @state_changed ? "" : KSRunes::MISSED_TARGET
      @last_damage = 0
    end
    effective
  end

  def skill_effect(user, skill)
    @critical = false
    user.last_skill = $game_temp.in_battle ? skill : nil
    return false if alive_not_dead?(skill) or dead_not_alive?(skill)
    @user = user
    @skill = skill
    effective = false
    effective |= @skill.common_event_id > 0
    hit = @skill.hit
    hit *= @user.hit / 100 if @skill.atk_f > 0
    hit_result = (rand(100) < hit)
    effective |= hit < 100
    hit = checking_hit(hit, hit_result)
    effective |= hit < 100
    hit_result = (rand(100) < hit)
    if hit_result
      effective = checking_effectivity(effective)
    else
      @damage = "Miss"
      @last_damage = 0
    end
    unless $game_temp.in_battle
      @damage = nil
      @last_damage = 0
    end
    @skill = @user = nil
    return effective
  end
  attr_accessor :last_skill, :last_damage
end

class Game_Actor
  alias :kyon_skillrunes_gm_actor_init :initialize
  def initialize(actor_id)
    kyon_skillrunes_gm_actor_init(actor_id)
    @skill_runes_max = KSRunes::STARTING_RUNE_MAX
    @rune_skills = {}
    @rp = 0
  end
  
  def item_effect(item)
    item_id = item.id
    return super(item) unless KSRunes::ITEM_IDS_RANGE.include?(item_id)
    return false unless learn_from_rune?(item_id)
    return false if rune_skill?(item_id)
    return false if skill_runes_max?
    rune = KSRunes.runes[item_id]
    return false if $game_party.gold < rune.price
    $game_party.gain_gold(-rune.price)
    skills = rune.skills
    learn_rune_skills(rune.blocked_rune, skills.values)
    skills.each{|k,v| @rune_skills[k] ||= v.dup }
  end

  def learn_rune_skill(rid, sid)
    rskills = @rune_skills[rid]
    return "No Rune" unless rskills
    skill = rskills[sid]
    return "Wrong Skill ID" unless skill
    return "Not Enough RP" if @rp == 0 or skill.skill_points > @rp
    skill.level += 1 if skill.level < KSRunes.runes[rid].level_max
    @rp -= skill.skill_points
  end

  def learn_from_rune?(rune_id)
    blocked_runes = KSRunes::ACTOR_BLOCKED_RUNES[@actor_id]
    return true unless blocked_runes
    !blocked_runes.include?(rune_id)
  end

  def learn_rune_skill?(level, skill_id, skill)
    return false if @level < level or skill_learn?(skill_id)
    skill.can_learn?(@rp)
  end

  def learn_rune_skills(rune_id, blocked_rune, skills)
    br = blocked_rune
    skills = skills.map{|s| s.id if learn_rune_skill?(s.level, br, s) }
    skills = skills.compact
    @skills = (@skills + skills).uniq.sort
  end
  def rune_skill?(skill_id) @rune_skills.has_key?(skill_id) end
  def skill_runes_max?() @rune_skills.size == @skill_runes_max end
  def is_actor?() true end
  def runes() @rune_skills.keys.sort end
  attr_accessor :skill_runes_max, :rp
  attr_reader :rune_skills
end

class Game_Enemy
  def is_actor?() false end
end

class KSRuneSpriteset
  include KSRunes
  def initialize(pos)
    @index = pos
    @rune_index = 0
    @actors = $game_party.actors
    actor = @actors[@index]
    @backdrop = Sprite.new
    @backdrop.bitmap = RPG::Cache.title(BACKDROP)
    @heading = Sprite.new
    @heading.x = 160
    @heading.y = 8
    @heading.bitmap = b = Bitmap.new(320, 32)
    b.draw_text(0, 4, 320, 24, TITLE, 1)
    @name_sprite = Sprite.new
    @name_sprite.x = 8
    @name_sprite.y = 36
    @name_sprite.bitmap = b = Bitmap.new(240, 32)
    b.draw_text(0, 4, 240, 24, actor.name, 1)
    @icon_names = actor.runes.map{|n| $data_items[n].icon_name }
    @icons = []
    @icon_labels = []
    @icon_names.size.times{|n| draw_rune_icons(n) }
    @sprites = [@backdrop, @heading, @name_sprite]
  end

  def draw_rune_icons(pos)
    @icons << s = Sprite.new
    s.x = 8
    s.y = 64 + pos * 28
    s.bitmap = RPG::Cache.icon(@icon_names[pos])
    @icon_labels << l = Sprite.new
    l.x = s.x + 28
    l.y = s.y
    l.bitmap = b = Bitmap.new(200, 24)
    b.draw_text(0, 0, 200, 24, @icon_names[pos])
  end

  def dispose
    @icon_labels.each{|s| s.dispose }
    @sprites.each{|s| s.dispose }
    @icons.each{|s| s.dispose }
    @sprites.clear
    @icons.clear
    @icon_names.clear
    @actors = nil
  end
  attr_reader :rune_index
end

class KSkillRuneScene
  def initialize(pos=0) @index = pos end
  def main
    @run = true
    @spriteset = KSRuneSpriteset.new(@index)
    Graphics.transition
    while @run
      Graphics.update
      Input.update
      update
    end
    Graphics.freeze
    @spriteset.dispose
  end

  def update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = Scene_Map.new
      return @run = nil
    elsif Input.trigger?(Input::C)
      $game_system.se_play($data_system.decision_se)
      
      
    end
  end
end

Rune Template

Code:
ID 43
Magic Type: Frost
Character Level: 5
Skill Level Max: 3
Blocked Runes: None
Gold: 180
Skill 12 Level 5  Skill 1  Points 10
Skill 13 Level 8  Skill 12 Points 20
Skill 14 Level 11 Skill 13 Points 30




Questions & Answers

Q: Can I open a menu and set the runes on a given hero?
A: You are able to open the item menu and select the rune and assign it to a given hero... and that's it! Laughing 

Q: Can I activate rune gem stones for free?
A: Actually nope, you can't. You need to pay the price in gold pieces. Tongue sticking out The cost will be subtracted from your purse automatically. Thief


Terms & Conditions

Free to use in any non commercial game.
Contact me if you need it for a commercial game.
Send me a copy of your full game if you use 2 or more of my scripts. [Image: laughing.gif]
Do Not Repost This Script! [Image: veryangry.gif]
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }




Users browsing this thread: 3 Guest(s)