Chaos Project

RPG Maker => RPG Maker Scripts => Script Troubleshooting => Topic started by: bigace on December 09, 2012, 03:43:25 pm

Title: [RESOLVED][RGSS] Can't see the issue...
Post by: bigace on December 09, 2012, 03:43:25 pm
Okay so I was trying to simplify my code:

Old Code:
	def draw_enemy_hp(enemy, x, y, hidden)
colour = STAT_BAR_COLOURS[:hp_bar]
draw_enemy_bar(x, y, 120, 10, enemy.maxhp, ENEMY_STATS[:maxhp], colour)
contents.font.color = system_color
contents.draw_text(x, y-22, 24, 32, "#{$data_system.words.hp}:")
contents.font.color = normal_color
rect = Rect.new(x + 24, y-22, 72, 32)
unless hidden
contents.draw_text(rect, enemy.maxhp.group)
else
contents.draw_text(rect, '???')
end
end
def draw_enemy_sp(enemy, x, y, hidden)
colour = STAT_BAR_COLOURS[:hp_bar]
draw_enemy_bar(x, y, 120, 10, enemy.maxsp, ENEMY_STATS[:maxsp], colour)
contents.font.color = system_color
contents.draw_text(x, y-22, 24, 32, "#{$data_system.words.sp}:")
contents.font.color = normal_color
rect = Rect.new(x + 24, y-22, 72, 32)
unless hidden
contents.draw_text(rect, enemy.maxhp.group)
else
contents.draw_text(rect, '???')
end
end


New Code:

DEF = [
['hp', :hp_bar, 'enemy.maxhp', :maxhp],
['sp', :sp_bar, 'enemy.maxsp', :maxsp],
]
(DEF.size).times do |i|
eval "def draw_enemy_#{DEF[i][0]}(enemy, x, y, hidden)
value = #{DEF[i][2]}
max = ENEMY_STATS[#{DEF[i][3]}]
draw_enemy_bar(x, y, 120, 10, value, max, STAT_BAR_COLOURS[#{DEF[i][1]}])
contents.font.color = system_color
contents.draw_text(x, y-22, 24, 32, $data_system.words.#{DEF[i][0]})
contents.font.color = normal_color
rect = Rect.new(x + 24, y-22, 72, 32)
unless hidden
contents.draw_text(rect, #{DEF[i][2]}.group)
else
contents.draw_text(rect, '???')
end
end"
end


And for some reason I kept getting an error, well to my eyes I don't really see how I'm getting this error. So if anyone else can help spot it that would be great. If you need anymore info I'll post it.
Title: Re: [RGSS] Can't see the issue...
Post by: Blizzard on December 09, 2012, 03:54:16 pm
*fixes* Use [code] tags for code.

You seem to have a comma at the end of line 3 which basically adds a nil value as 3rd element into your array.
Title: Re: [RGSS] Can't see the issue...
Post by: bigace on December 09, 2012, 04:48:35 pm
Nope I still get the same error

Quote
Script 'Window_Bestiary_Info' line 32: NameError occurred.

undefined local variable or method 'maxhp' for #<Window_Bestiary_Info:0x31c9d60>


Also I don't know why the error is pointing there the only thing on that line is:
draw_enemy_hp(@enemy, 4, bar_Y=286, @hidden)
Title: Re: [RGSS] Can't see the issue...
Post by: Blizzard on December 09, 2012, 05:08:03 pm
Maybe you should just use the classic way (or make a method that takes a few more parameters), because using eval in such a way is really bad design.

EDIT: You can try putting the symbols in strings as well:

['hp', ':hp_bar', 'enemy.maxhp', ':maxhp'],
Title: Re: [RGSS] Can't see the issue...
Post by: bigace on December 09, 2012, 06:54:45 pm
oh okay I'll test it when I get home.
Title: Re: [RGSS] Can't see the issue...
Post by: bigace on December 09, 2012, 07:32:41 pm
Nope doesn't work, I guess I'll just stick with the normal way :P . thanks for the help though.
Title: Re: [RGSS] Can't see the issue...
Post by: Ryex on December 10, 2012, 03:51:08 am
well, I applaud you for being clever and trying to define both methods at once but I would hardly consider this "simplification" of your code. but as you see here Eval has some very interesting scope considerations to take into account. some how "enemy" in your evaled code was an instance of a Window_Bestiary_Info I'm not sure how it happened.

Using eval in general is bad practice for multiple reasons but it does have a place. I'd advise you to read these two pages.

http://stackoverflow.com/questions/1902744/when-is-eval-in-ruby-justified
http://blog.grayproductions.net/articles/eval_isnt_quite_pure_evil

general rule of thumb:
if your using eval to reduce the number of lines of code you have, your doing it wrong.
if your using it to deal with a dynamic system where your program must adapt at run-time then it's good tool, but use wisely.


If you really want to get clever you could write a generic bar drawing method and use something like this

def draw_enemy_stat(enemy, x, y, hidden, stat)
...
value = enemy.instance_variable_get(stat)
draw_enemy_bar(x, y, 120, 10, value, ENEMY_STATS[stat], colour)
...
end


note that you can turn strings to symbols with to_sym so you can build a symbol form a string


stat = "hp"
enemy.instance_variable_get(("max" + stat).to_sym)
STAT_BAR_COLOURS[(stat + "_bar").to_sym]


note that the above assumes that maxhp and maxsp are instance variables (it's been too long since I used XP so I cant remember) if the value is handeled by getter and setter methods (ie. attr_accessor, attr_reader, and attr_writer) you will need to use send.

enemy.send(:maxhp)
Title: Re: [RGSS] Can't see the issue...
Post by: bigace on December 10, 2012, 05:06:52 pm
wait so where does the line go, because even after I put it in still got the same error message that maxhp wasn't an instance variables

Scratch that, I got the error to go away but now both the sp and hp guages say the same thing. Plus instead of saying HP: & SP: from the database. It now prints RPG:Sy... (Can't read the rest).


def draw_enemy_health(enemy, x, y, type, hidden)
colour = STAT_BAR_COLOURS[(type + "_bar").to_sym]
value = enemy.send(:maxhp)
max = ENEMY_STATS[("max" + type).to_sym]
draw_enemy_bar(x, y, 120, 10, value, max, colour)
contents.font.color = system_color
contents.draw_text(x, y-22, 24, 32, "#{$data_system.words.type}:")
contents.font.color = normal_color
rect = Rect.new(x + 24, y-22, 72, 32)
unless hidden
contents.draw_text(rect, value.group)
else
contents.draw_text(rect, '???')
end
end


----------------
So practically from reading those findings you posted: eval() is evil as it can ruin your hardware if used extensively (something like that), though it's alright to use it sometimes, but rarely should you use it.
Title: Re: [RGSS] Can't see the issue...
Post by: Ryex on December 11, 2012, 02:56:00 am
well because your using enemy.send(:maxhp) you need to build that symbol from a string using the type like you do the rest to get both HP and SP bars. don't just cut and past my code I gave it as examples not exactly how to do it.

and eval isn't evil (but that is the common over-generalization) it is meirly a powerfully tool that can be misused very easyily
Title: Re: [RGSS] Can't see the issue...
Post by: Blizzard on December 11, 2012, 03:04:12 am
I think that one article has a few pretty good comments on it. Using eval for code definition is bad design, but using it to run dynamically created code or allow some sort of Ruby prompt (like I allowed in RMX-OS if somebody is an admin) are great ways where eval is not only useful and is considered good design, it's sometimes also the only possible solution (or the cleanest anyway).
Title: Re: [RGSS] Can't see the issue...
Post by: Heretic86 on December 11, 2012, 09:19:45 pm
PHP has an eval equivilant.  When running a web server, one definitely does not want to allow unchecked user input to be allowed to run in eval because it effectively runs as shell on the system, which can be dangerous. 

But running eval in RMXP doesnt have the same security needs and boils down to how it needs to be used.  Eval threw me for a loop with Zeriab's caterpillar where he used eval to create a bunch of definitions dynamically, and applied the same change to each dynamic definition.  Space saver, and in that situation I dont think it was required. 

I also used eval in Timed User Inputs to allow scripts to run at specific times in different scenes.  It became necessary to allow access to eval to process scripts after you change scenes to a non eventable / scriptable scene (like Menu) and not modify the scene itself in any way.

Eval does have very legit uses.
Title: Re: [RGSS] Can't see the issue...
Post by: bigace on December 12, 2012, 01:28:19 am
Okay thank you for the help Ryex as I got this code to work:
	
def draw_enemy_health(enemy, x, y, type, hidden)
colour = STAT_BAR_COLOURS[(type + "_bar").to_sym]
value = enemy.send(("max" + type).to_sym)
max = ENEMY_STATS[("max" + type).to_sym]
draw_enemy_bar(x, y, 120, 10, value, max, colour)
contents.font.color = system_color
contents.draw_text(x, y-22, 24, 32, eval("$data_system.words.#{type}") + ":")
contents.font.color = normal_color
rect = Rect.new(x + 24, y-22, 72, 32)
unless hidden
contents.draw_text(rect, value.group)
else
contents.draw_text(rect, '???')
end
end


And thank you everyone for giving more info on eval()