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
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.
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
/EDITAnyway, 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.
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.
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.
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
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
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 (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):
#===============================================================================
# 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