[RESOLVED] [XP] Fancy way of learning attacks based on studying enemies.

Started by Nath, September 03, 2016, 03:38:00 am

Previous topic - Next topic

Nath

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

Blizzard

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.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Nath

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.

Blizzard

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.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Nath

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.

KK20

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

Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!

Nath

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

KK20

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:

  • Evaluate the string, look for \n, and split the string in parts

  • Ensure that the bitmap you're going to draw on is large enough to draw the text onto

  • Draw each part of the string, moving the drawing coordinate down for each subsequent part


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 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


Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!