Chaos Project

RPG Maker => RPG Maker Scripts => Script Requests => Topic started by: Nath on September 03, 2016, 03:38:00 am

Title: [RESOLVED] [XP] Fancy way of learning attacks based on studying enemies.
Post by: Nath on September 03, 2016, 03:38:00 am
So I have this idea that I wish I was able to code, myself, but... I am a total noob, it seems. I'm using a few things from Tons of Addons, and I thought about trying to modify Blizzard's Blue Magic Skill script, but I'm not sure that's the best way, and I am also not nearly skilled enough. I don't think any of my little custom scripts are involved enough to conflict with this idea.

OK, so, what I want to do is have a skill (just one skill, that only one character will have) which, when used on an enemy, will cause the user to learn a new skill based on which enemy was targeted, assuming they don't have it, already. Unlike Blue Magic, it's not a skill that the target enemy actually possesses.

I imagine there would need to be a configuration area that includes a list of learnable skill ID's, each paired with an array of enemy ID's, since there will likely be a bunch of enemies that can "teach" the same skill. Oh, and... probably the ID of the main skill, too.

I hope that's enough info to go on. Thanks to whoever goes to the trouble of helping me out!  :D
Title: Re: [XP] Fancy way of learning attacks based on studying enemies.
Post by: Blizzard on September 03, 2016, 07:05:10 am
Quote from: Nath on September 03, 2016, 03:38:00 am
I imagine there would need to be a configuration area that includes a list of learnable skill ID's, each paired with an array of enemy ID's, since there will likely be a bunch of enemies that can "teach" the same skill. Oh, and... probably the ID of the main skill, too.


This.
It's actually easy. Use the Blue Magic skill, but change the code where the enemy skill ID is selected to call that method which will give a specific ID based on the enemy.
Title: Re: [XP] Fancy way of learning attacks based on studying enemies.
Post by: Nath on September 03, 2016, 10:29:00 am
Alrighty, so... I just need to change this bit of it, then?

if target.is_a?(Game_Enemy)
  ids = []
  target.actions.each {|act| ids.push(act.skill_id) if act.kind == 1}
elsif target.is_a?(Game_Actor)
  ids = target.skills.clone
end


...and I have no use for the randomization, so I can just check for the enemy ID, then assign a skill ID to ids based on that. Hmm... I'm not really well-versed in Ruby stuffs, so... I need to study other scripts for examples, I suppose.

Ok. I was thinking about doing it with arrays, but I'm not sure how to go about it. The best I can think of is this:

def do_the_thing_with_the_skillz(enemy)
  case enemy
    when 1 then return 1
    when 2 then return 1
    when 3 then return 2
    when 4 then return 3
  end
  return nil
end


Is it possible to do something like...

  when [1, 2, 3].include? then return 1


...just for brevity's sake? I realize include doesn't work that way, but... something?

EDIT: Maybe something like this is better?

def do_the_thing_with_the_skillz(enemy)
  return 1 if [1,2,3].include?(enemy)
  return 2 if [4,5].include?(enemy)
  return 3 if [6,7,8,23].include?(enemy)
  return nil
end


/EDIT

Anyway, then I'd have to have the other part be something like...

if target.is_a?(Game_Enemy)
  ids = do_the_thing_with_the_skillz(target.id)
else   # It should never be targeting an actor, so this part shouldn't even come up.
  ids = nil
end


Right?

Did I do all that correctly? Will it work with the rest of the script the way it is?


EDIT: Oh! A final, more complex question!

Would it be possible to have something like "Skill already learned!" be displayed in the help window, while selecting targets with this skill? Well... I'm sure it's possible, but is it not unreasonably difficult? It'd just be a QOL improvement, so it's not terribly necessary.
Title: Re: [XP] Fancy way of learning attacks based on studying enemies.
Post by: Blizzard on September 03, 2016, 05:58:39 pm
Yeah, you pretty much did it right there.

How you organized the config is up to you. Each of the styles you suggested works.

No, it wouldn't be too difficult. You have to find the code where the enemy name is assigned to the help window (I think it goes something like "@window_help.text = BLABLABLA"), then get the skill ID with your database method that you implemented like you described in your previous post and finally check if @active_battler is a Game_Actor and if the skill was already learned.
Title: Re: [XP] Fancy way of learning attacks based on studying enemies.
Post by: Nath on September 03, 2016, 06:05:12 pm
Right, awesome! I'll have to look into that.

EDIT: I found the part in Window_Help, I think, but I'm not sure how to change what it says when a specific skill is used.
Title: Re: [RESOLVED] [XP] Fancy way of learning attacks based on studying enemies.
Post by: KK20 on September 04, 2016, 02:16:13 am
It's more complicated than it actually seems.
The actual drawing occurs inside Arrow_Enemy:

  #--------------------------------------------------------------------------
  # * Help Text Update
  #--------------------------------------------------------------------------
  def update_help
    # Display enemy name and state in the help window
    @help_window.set_enemy(self.enemy)
  end

which doesn't really need any more information inside the battle scene other than the Troop. You're going to have to do some extra modifications here.

Try pasting this script in your project and see if that gets you anywhere.

class Scene_Battle
  alias blue_magic_help_window_text start_enemy_select
  def start_enemy_select
    blue_magic_help_window_text
    $game_troop.enemies.each_with_index{|enemy, index|
      # If using blue magic skill
      if @skill_window and BLUE_MAGIC_IDS.include?(@skill_window.skill.id)
        # Get list of learnable skills
        can_learn = do_the_thing_with_the_skillz(enemy.id)
        # Cannot learn anything from this monster
        if can_learn.nil?
          @enemy_arrow.extra_text[index] = " [Can't Learn!]"
          next
        end
        # Iterate through each skill, check if all skills are learned
        if not can_learn.to_a.any?{|skill_id| !@active_battler.skills.include?(skill_id) }
          @enemy_arrow.extra_text[index] = " [Already Learned!]"
          next
        end
      end
      # Empty out the extra text
      @enemy_arrow.extra_text[index] = ""
    }
  end
end

class Arrow_Enemy
  attr_accessor :extra_text
 
  def initialize(viewport)
    super(viewport)
    @extra_text = []
    $game_troop.enemies.size.times { @extra_text.push("")}
  end
 
  def update_help
    # Display enemy name and state in the help window
    @help_window.set_text(self.enemy.name + @extra_text[@index])
  end
end
Title: Re: [RESOLVED] [XP] Fancy way of learning attacks based on studying enemies.
Post by: Nath on September 04, 2016, 05:06:57 am
Works perfectly! Thanks!
It has the side effect of left-aligning the help text, but I don't dislike that.  ;)

I have just one final*, noobish question:
Is there a way to put a line break in the "damage" display?

target.damage = "#{skill.name} learned!"


Like in this bit? I tried \n, but it was ignored.

It's not a super big deal, though. I could also just change it to say a generic "Skill learned!" rather than the whole skill name.

*This is a lie. I have an unusual amount of questions, but I'll spare you the pain. :^P
Title: Re: [RESOLVED] [XP] Fancy way of learning attacks based on studying enemies.
Post by: KK20 on September 05, 2016, 04:56:25 pm
For the alignment, that's an optional parameter for set_text.

  #--------------------------------------------------------------------------
  # * Set Text
  #  text  : text string displayed in window
  #  align : alignment (0..flush left, 1..center, 2..flush right)
  #--------------------------------------------------------------------------
  def set_text(text, align = 0)

So the change you would make is

@help_window.set_text(self.enemy.name + @extra_text[@index], 1) # Centered


As for \n not working, it has something to do with the way Enterbrain created their Bitmap.draw_text method. We don't have access to the code, so we can't "fix" it. The alternative is to do the following:

This method is common in many scripts here. Use the search bar for "slice_text" and you can find the code. I use a modified version in my Organized Quest System (http://forum.chaos-project.com/index.php/topic,12242.0.html) that already handles all of this, although it is designed for Windows, not Bitmaps in general (though that shouldn't be much work to convert):
Spoiler: ShowHide


#===============================================================================
# Window_Base Class
#   : Modified method provided by Blizzard
#===============================================================================
class Window_Base < Window
 
  def draw_even_text(x, y, width, height, text, align = 0)
    # Replace all instances of \v[n] to the game variable's value
    text.gsub!(/\\[Vv]\[([0-9]+)\]/) { $game_variables[$1.to_i] }
    text.gsub!(/[\V\v]\[([0-9]+)\]/) { $game_variables[$1.to_i] }
    # Break up the text into lines
    lines = text.split("\n")
    result = []
    # For each line generated from \n
    lines.each{|text_line|
      # Divide text into each individual word
      words = text_line.split(' ')
      current_text = words.shift
      # If there were less than two words in that line, just push the text
      if words.empty?
        result.push(current_text == nil ? "" : current_text)
        next
      end
      # Evaluate each word and determine when text overflows to a new line
      words.each_index {|i|
        if self.contents.text_size("#{current_text} #{words[i]}").width > width
          result.push(current_text)
          current_text = words[i]
        else
          current_text = "#{current_text} #{words[i]}"
        end
        result.push(current_text) if i >= words.size - 1
      }
    }
    # Draw results to the window
    result.each_index {|i|
        self.contents.draw_text(x, y + i*height, width, height, result[i], align)}
  end
     
end