[RESOLVED] Learn Skills from using other Skills

Started by Viviatus, August 25, 2008, 04:50:14 am

Previous topic - Next topic

Fantasist

August 27, 2008, 03:47:08 pm #20 Last Edit: August 27, 2008, 07:18:58 pm by Fantasist
See if you can understand this config (part-2 mainly). If you can, I'll be releasing this shortly (if you permit me to, that is). Otherwise, I'll have to explain things better or change the config again.

SLCC v0.91: ShowHide

#============================================================================
# ** Skill Learning by Cast Count (SLCC)
#----------------------------------------------------------------------------------------
# by Fantasist
# Version 0.91
# 28-Aug-2008
#----------------------------------------------------------------------------------------
# Version History:
#
#   0.9 - Beta prototype
#   0.91 - updated documentation and SKILL_LEARN_SE can be on/off
#----------------------------------------------------------------------------------------
# Description:
#
#      This script allows actors to learn new skills after using one of their
#    existing skills a certain number of times, similar to the "Tales of" Games.
#    That's the basic concept, here are a few examples:
#
#  1 - If you cast "Heal" 20 times, you learn "Greater Heal".
#  2 - If you cast "Heal" 25 times, you learn "Greater Heal". Casting "Heal" 50
#       times (or 25 more times after that) would result in learning "Mass Heal".
#  3 - If you cast "Heal" 20 times, both "Greater Heal" AND "Mass Heal" will be
#       learned.
#  4 - If you cast "Heal" 10 times and "Raise" 5 times, you learn "Mass Heal".
#  5 - You can set different conditions for every actor.
#
# Therefore, what this script enables:
#
#   - Learning 1 or more skills by casting existing skills at any time.
#   - Setup evrything differently for each actor
#----------------------------------------------------------------------------------------
# Instructions/Configuration:
#
#     Place this script above "Main".
#
#     The configuration might look tricky, but if you follow the instructions,
#   it's easy. It's just like applying a formula to get a result. Note that each
#   config has to be done for each actor seperately. The main format will be
#   something like this:
#
#   when ACTOR_ID
#     CONFIG_FOR_ACTOR
#   when ACTOR_ID
#     CONFIG_FOR_ACTOR
#   end
#
#   The config mainly consists of two parts:
#      - Config of skill(s) learned by casting ONE skill (1, 2, 3 in description)
#      - Config of skill(s) learned by casting MULTIPLE skills (4 in description)
#
#   PART 1:
#
#     when SKILL_ID then [[x, ID1], [y, ID2, ID3, ID4....], .....]
#
#   The above line means that when SKILL_ID is cast...
#     x times, then skill with ID1 is learned 
#     y times, then skills with IDs ID1, ID2, ID3, ID4... are learned
#
#   PART 2:
#
#   when ACTOR_ID
#       [
#       [ [1, 1], [57, 1], [6, 1], [10] ] ,
#       [ [1, 2], [6, 1], [10, 1], [14, 15, 16...] ]
#       ]
#
#   The above lines mean that when ACTOR_ID:
#      - When skill with ID 1 is used once, 57 is used once, and 6 is used once,
#         then ACTOR_ID learns Skill ID 10. This is all ONE CONDITION.
#      - When skill with ID 1 is used twice, 6 is used once, and 10 is used once,
#         then skills 14, 15, 16... are learned.
#
#     Observe how for every condition the list of skills that will be
#     learned should be at the end, while in the beginning it's the skills that
#     need to be casted a certain number of times, being
#     ([skill_id, cast_number_of_times]).
#
#     Add as many conditions as you want in new lines between the top and
#   bottom "[" and "]", but remember to put the comma after every condition
#   except the last one.
#
#     Lastly, newly learned skills are displayed in popups after the battle is
#   complete. If you want an SE to play with the popups, change the constant
#   SKILL_LEARN_SE. The format is:
#
#       SKILL_LEARN_SE = RPG::AudioFile.new('SE Filename', volume, pitch)
#
#     If you want to disable the sound, set to "nil". It would look like this:
#
#             SKILL_LEARN_SE = nil
#     
#----------------------------------------------------------------------------------------
# Credits and Thanks:
#
#   Credits: Fantasist for making this.
#   Thanks: Viviatus for requesting this.
#               Starrodkirby86 for helping me explain the config.
#----------------------------------------------------------------------------------------
# Notes:
#
#   THIS IS NOT A PUBLIC VERSION!!!
#   If you have any problems or suggestions, you can find me by the name
#   'Fantasist' at:
#
#   www.quantumcore.forumotion.com
#   www.chaos-project.com
#
#   Enjoy! ^_^
#============================================================================

#==============================================================================
# FTS (module)
#==============================================================================

module FTS
 
  # RPG::AudioFile.new('SE Filename', volume, pitch)
  # for disabling, set to "nil" (SKILL_LEARN_SE = nil)
  SKILL_LEARN_SE = RPG::AudioFile.new('056-Right02', 100, 100)
 
  module_function
 
  def learn_new_skills?(actor_id, skill_id)
    case actor_id
    #================================
    # Config PART-1 Begin
    #================================
    when 1 # when actor_id
      a = case skill_id
      when 1 then [[1, 6], [2, 7], [5, 10], [12, 13, 14, 15, 16], [3, 34, 35]]
      else false
      end
    #----------------------------------------------------------------
    # Actor Seperator
    #----------------------------------------------------------------
    when 7 # when actor_id
      a = case skill_id
      when 1 then [[2, 8, 9]]
      else false
      end
    #================================
    # Config PART-1 End
    #================================
    end
    return a
  end
 
  def learn_from_many?(actor_id)
    a = case actor_id
    #================================
    # Config PART-2 Begin
    #================================
    when 1 # when actor_id
      [
      [[1, 1], [57, 1], [6, 1], [10, 11, 12, 13]],
      [[1, 2], [6, 1], [10, 1], [14, 15, 16, 17]]
      ]
    #----------------------------------------------------------------
    # Actor Seperator
    #----------------------------------------------------------------
    when 7 # when actor_id
      [
      [[1, 2], [8, 1], [9, 1], [14, 15, 16, 17]]
      ]
    #================================
    # Config PART-2 End
    #================================
    else
      false
    end
    return a
  end
 
end

#==============================================================================
# Game_Actor
#==============================================================================

class Game_Actor
 
  attr_accessor :skill_learns, :skill_uses
 
  alias fts_skill_learning_game_actor_setup setup
  def setup(actor_id)
    fts_skill_learning_game_actor_setup(actor_id)
    skill_list = load_data('Data/Skills.rxdata')
    @skill_uses = Array.new(skill_list.size + 1, 0)
    @skill_uses[0], @skill_learns, skill_list = id, [], nil
  end
 
end

#==============================================================================
# Scene_Battle
#==============================================================================

class Scene_Battle
 
  alias fts_skill_learning_scene_battle_skill_action_result make_skill_action_result
  def make_skill_action_result
    battler = @active_battler
    @skill = $data_skills[battler.current_action.skill_id]
    if battler.is_a?(Game_Actor) && battler.skill_can_use?(@skill.id)
      battler.skill_uses[@skill.id] += 1
      conditions_list = FTS::learn_new_skills?(battler.id, @skill.id)
      if conditions_list
        conditions_list.each {|times_list| times = times_list.shift
        if battler.skill_uses[@skill.id] == times
        times_list.each {|skill_id| battler.skill_learns.push(skill_id)}
        end}
      end
      conditions_list = FTS::learn_from_many?(battler.id)
      if conditions_list
        conditions_list.each {|conditions| result, val = conditions.pop, true
        conditions.each {|id_times| id, times = id_times[0], id_times[1]
        val = false unless battler.skill_uses[id] >= times}
        battler.skill_learns |= result if val}
      end
      battler.skill_learns -= battler.skills
    end
    fts_skill_learning_scene_battle_skill_action_result
  end
 
  alias fts_skill_learning_scene_battle_init5 start_phase5
  def start_phase5
    fts_skill_learning_scene_battle_init5
    @new_skills = []
    $game_party.actors.each_with_index {|actor, i| actor.skill_learns.each {|id|
    @new_skills.push([i, id])}
    actor.skill_learns = []}
    @learn_skill_count = @new_skills.size
  end
 
  alias fts_skill_learning_scene_battle_upd5 update_phase5
  def update_phase5
    if @learn_skill_count > 0
      if @learn_skill_count == @new_skills.size
        a = @new_skills.shift
        actor = $game_party.actors[a[0]]
        actor.learn_skill(a[1])
        actor.damage = "+ #{$data_skills[a[1]].name}!"
        $game_system.se_play(FTS::SKILL_LEARN_SE) if FTS::SKILL_LEARN_SE
        actor.damage_pop = true
      end
      @learn_skill_count -= 1
    end
    fts_skill_learning_scene_battle_upd5
  end
 
end


SLCC Info Scene v0.2: ShowHide

#============================================================================
# ** SLCC Information Scene
#----------------------------------------------------------------------------------------
# by Fantasist
# Version 0.2
# 28-Aug-2008
#----------------------------------------------------------------------------------------
# Version History:
#
#   0.2 - Alpha stage version, just for checking out the learning trees
#----------------------------------------------------------------------------------------
# Description:
#
#     This is the scene for checking skill learning information by using the
#   script SLCC (Skill Learning by Cast Count).
#----------------------------------------------------------------------------------------
# Compatibility:
#
#     This is useless and will give an error if you're not using SLCC.
#   Place this below SLCC. This is a seperate scene, so it should be
#   compatible with almost anything.
#----------------------------------------------------------------------------------------
# Instructions/Configuration:
#
#   There's nothing to configure for this version. You can call the scene by
#   using the following piece of code in a "Call Script" event command:
#
#           $scene = Scene_SkillLearnInfo.new
#
#     During the scene, press L and R to cycle between all the actors in the
#   party.
#----------------------------------------------------------------------------------------
# Issues:
#
#     1 - This will give an error if it is called when the party is empty.
#     2 - For this version, there are no sounds.
#     3 - You can't check multiple skill requirements with this scene, it
#          focuses on only ONE skill at a time and displays all the skills that
#          you can learn by using it different times.
#----------------------------------------------------------------------------------------
# Credits and Thanks:
#
#   Credit: Fantasist for making this.
#----------------------------------------------------------------------------------------
# Notes:
#
#   THIS IS NOT A PUBLIC VERSION!!!
#   If you have any problems or suggestions, you can find me by the name
#   'Fantasist' at:
#
#   www.quantumcore.forumotion.com
#   www.chaos-project.com
#
#   Enjoy! ^_^
#============================================================================

#==============================================================================
# ** Window_SkillList
#==============================================================================

class Window_SkillList < Window_Selectable
 
  def initialize(actor)
    super(0, 64, 240, 416)
    @actor, @column_max = actor, 1
    refresh
    self.index = 0
  end
 
  def skill
    return @data[self.index]
  end
 
  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    for i in 0...@actor.skills.size
      skill = $data_skills[@actor.skills[i]]
      @data.push(skill) if skill != nil
    end
    @item_max = @data.size
    if @item_max > 0
      self.contents = Bitmap.new(width - 32, row_max * 32)
      for i in 0...@item_max
        draw_item(i)
      end
    end
  end
 
  def draw_item(index)
    skill, x, y = @data[index], 4, index * 32
    self.contents.font.color = normal_color
    rect = Rect.new(x, y, self.width / @column_max - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(skill.icon_name)
    opacity = self.contents.font.color == normal_color ? 255 : 128
    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
    self.contents.draw_text(x + 28, y, 204, 32, skill.name, 0)
  end
 
  def update_help
    @help_window.set_text(self.skill == nil ? '' : self.skill.description)
  end
 
end

#==============================================================================
# ** Window_SkillInfo
#==============================================================================

class Window_SkillInfo < Window_Base
 
  def initialize(actor)
    @actor = actor
    super(240, 64, 400, 416)
    refresh
  end
 
  def refresh(skill=nil)
    return unless skill
    self.oy = 0
    a, size = FTS::learn_new_skills?(@actor.id, skill.id), 0
    a.each {|c| size += c.size} if a
    self.contents.dispose if self.contents
    self.contents = Bitmap.new(width - 32, 96 + size * 32)
    self.contents.font.size = 28
    contents.draw_text(0, 0, contents.width, 64, @actor.name, 1)
    self.contents.font.size = 22
    draw_actor_graphic(@actor, 320, 64)
    txt = "Times used: #{@actor.skill_uses[skill.id]}"
    contents.draw_text(4, 64, contents.width - 8, 32, txt)
    return unless a
    y = 96
    a.each_with_index {|c, i| times = c.shift
    contents.draw_text(4, y, contents.width - 8, 32, "When used #{times} time(s), learns:")
    y += 32
    c.size.times {|i| skill_id = c[i]
    rect = Rect.new(4, y + 4, 24, 24)
    contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon($data_skills[skill_id].icon_name)
    contents.blt(rect.x, rect.y, bitmap, Rect.new(0, 0, 24, 24))
    contents.draw_text(32, y, contents.width - 36, 32, "#{$data_skills[skill_id].name}")
    y += 32}}
    if contents.height > self.height - 32
      self.contents.font.size = 16
      contents.draw_text(4, 0, contents.width - 8, 24, 'Hold SHIFT and press UP/DOWN', 1)
    end
  end
 
  def update
    super
    if self.active && contents.height > self.height - 32
      if Input.press?(Input::DOWN) && (contents.height - oy > self.height - 32)
        self.oy += 2
      elsif Input.press?(Input::UP) && (oy > 0)
        self.oy -= 2
      end
    end
  end
 
end

#==============================================================================
# Scene_SkillLearnInfo
#==============================================================================

class Scene_SkillLearnInfo
 
  def initialize(actor_index=0)
    @actor_index = actor_index
    $data_skills = load_data('Data/Skills.rxdata') unless $data_skills
  end
 
  def main
    @actor = $game_party.actors[@actor_index]
    @help_win = Window_Help.new
    @list_win = Window_SkillList.new(@actor)
    @list_win.help_window = @help_win
    @info_win = Window_SkillInfo.new(@actor)
    @info_win.refresh(@list_win.skill)
    Graphics.transition
    loop do
      Graphics.update
      Input.update
      update
      break if $scene != self
    end
    Graphics.freeze
    @help_win.dispose
    @list_win.dispose
    @info_win.dispose
  end
 
  def update
    if @list_win.active
      update_list
    elsif @info_win.active
      update_info
    end
    @info_win.active = Input.press?(Input::A)
    @list_win.active = !@info_win.active
  end
 
  def update_list
    @help_win.update
    @list_win.update
    if Input.trigger?(Input::B)
      $scene = Scene_Map.new
    elsif Input.trigger?(Input::L)
      new_index = (@actor_index - 1) % $game_party.actors.size
      $scene = Scene_SkillLearnInfo.new(new_index)
    elsif Input.trigger?(Input::R)
      new_index = (@actor_index + 1) % $game_party.actors.size
      $scene = Scene_SkillLearnInfo.new(new_index)
    elsif Input.repeat?(Input::UP) || Input.repeat?(Input::DOWN)
      @info_win.refresh(@list_win.skill)
    end
  end
 
  def update_info
    @info_win.update
  end
 
end


If you want anything changed, let me know (for example to be able to enable/disable the popups, etc). I haven't tested it with LevelUp Notifier yet. I'll do that later anyway, but if you're using it, I'll make this compatible. Just let me know ^_^
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews




Berans

Personally I don't mind writing a bit of inefficient code, provided it doesn't result in any visible lag. I avoid it as much as I can, but I find user friendlyness much more important than efficiency of code. It's pretty stupid if the user can't understand how to use a script because of a stubborn tendancy to optimise everything past belief :P
That's why I like using hashes, I know they're inefficient, I just feel that many users understand how to do setups with them more easily than with other systems.

Regardless, this is looking quite good ^_^
I'm gonna write my own script anyway :p

Fantasist

QuoteI just feel that many users understand how to do setups with them more easily than with other systems.

Could be argued :P But yeah, it's the scripter's preference and I learnt stuff from Blizz, so there :)

QuotePersonally I don't mind writing a bit of inefficient code, provided it doesn't result in any visible lag. I avoid it as much as I can, but I find user friendlyness much more important than efficiency of code.

You're right. In fact, if aliasing methods does what I think it does, it's a major memory drain, but I need to look it up.

*waits for Vivi to approve*
Do you like ambient/electronic music? Then you should promote a talented artist! Help out here. (I'm serious. Just listen to his work at least!)


The best of freeware reviews: Gizmo's Freeware Reviews




Viviatus

August 28, 2008, 05:00:02 am #23 Last Edit: August 28, 2008, 05:30:25 am by Viviatus
Well ... at first I was like WTF? But after I took some time to take a closer looks it's quite easy to understand. You were right with the config, though. But it won't be a big problem for me, since I'm not a newbie to complicated scripts ;)

If I'm right then for the part2 config the last brackets always include the skill being learnd? It doesn't matter how many conditions there are? Cause you always gave 3 conditions in the examples, though there could only be 2 or even more? I gonna try it out properly once I'm back from work! Thank you so much so far!

I'm so happy someone finally scripted this for me!

EDIT:

Works perfectly! Awesome job! Thanks!
And of course you may release it!