+- Save-Point (https://www.save-point.org)
+-- Forum: Games Development (https://www.save-point.org/forum-4.html)
+--- Forum: Code Support (https://www.save-point.org/forum-20.html)
+--- Thread: Ruby, RGSS & General Code Discussion (/thread-4438.html)
Ruby, RGSS & General Code Discussion - Kain Nobel - 11-14-2012
Hello and good day!
I'm starting this thread as a sort of general discussion, but instead of flashing memes and making dick jokes we're going to discuss code (how fun!) Did you have a silly problem that, according to you, didn't make any damn sense? Did you figure it out afterwards and go "Duh"? Heck, do you have useful code snippets that you want to share, but don't feel like posting a Script / Support thread about it? That's what this thread is for!
Anywho, I'll share my silly code story of the day...
So I was testing Trickster's ATB when I kept coming across a silly error related to something that was in fact defined. Every time an actor levels up, I get this NoMethodError for level_up which is defined in Window_BattleStatus. "Strange," I said to the resident werewolf as he stared back at me, both of us puzzled. That's when I realized; I changed Window_BattleStatus from inheriting from Window_Base to inheriting from Window_Selectable, that way a cursor is over whomever is currently selecting actions.
"What does that have to do with anything," you ask?
Quite simply this...
Code:
# First, we make two parent classes, ParentA and ParentB.
class ParentA
end
class ParentB
end
# Now Child inherits from ParentA with the 'blah' method defined.
class Child < ParentA
def blah
p 'blah'
end
end
# Now we create the Child object and call the 'blah' method.
# This should result in no error and print 'blah'.
c = Child.new
c.blah
# Changing inheritance from ParentA to ParentB cancels the 'blah' method.
class Child < ParentB
end
# Now we create the Child object and call the 'blah' method.
# This results in an error, all defined methods have been cancelled.
c = Child.new
c.blah
Lesson Learned: Changing the inheritance of a predefined class in Ruby will cancel all of its unique methods, so you'll have to copy them over or re-write them.
I think the all RGSS code should be open source. There are some scripts that require DLL or executable to work. The custom DLL's should have included source. The scripter reading other scripts, learns how to making scripts. Why people uses DLL in RGSS scripts? The first thing is - to hide source.
Some coding standards prefered by me :
98 % of Rpg Maker users edits RGSS Default Interpreter Scripts. This is not good idea.
The better is make new * Mods script and paste in it modified segments.
For ex.
This is Window Playtime class.
Code:
class Window_PlayTime < Window_Base
def initialize
super(0, 0, 160, 96)
self.contents = Bitmap.new(width - 32, height - 32)
self.contents.font.name = $font.get($actual_font, 0)
self.contents.font.size = $font.get($actual_font, 1)
refresh
end
def refresh
self.contents.clear
self.contents.font.color = system_color
self.contents.draw_text(4, 0, 120, 32, "Play Time")
@total_sec = Graphics.frame_count / Graphics.frame_rate
hour = @total_sec / 60 / 60
min = @total_sec / 60 % 60
sec = @total_sec % 60
text = sprintf("d:d:d", hour, min, sec)
self.contents.font.color = normal_color
self.contents.draw_text(4, 32, 120, 32, text, 2)
end
def update
super
if Graphics.frame_count / Graphics.frame_rate != @total_sec
refresh
end
end
end
You want to edit a part of this class to change the text "Play Time" at the "Real Time" and you want to make visible your computer, real hour instead of PlayTime.
In * Mods :
Copy object you want to edit and edit features in the mods class.
Using this method makes code clean :)
Code:
class Window_PlayTime < Window_Base
def refresh
self.contents.clear
self.contents.font.color = system_color
self.contents.draw_text(4, 0, 120, 32, "Real Time")
text = "#{Time.now.hour} : #{Time.now.min} : #{Time.now.sec}"
self.contents.font.color = normal_color
self.contents.draw_text(4, 32, 120, 32, text, 2)
end
end
module RPG module Cache
Graphic_Log_Filename = "Used_Graphics.txt"
def self.load_bitmap(folder_name, filename, hue = 0)
path = folder_name + filename
if not @cache.include?(path) or @cache[path].disposed?
if filename != ""
@cache[path] = Bitmap.new(path)
File.open(Graphic_Log_Filename, 'a') {|f| f.write(path + "\n") }
else
@cache[path] = Bitmap.new(32, 32)
end
end
if hue == 0
@cache[path]
else
key = [path, hue]
if not @cache.include?(key) or @cache[key].disposed?
@cache[key] = @cache[path].clone
@cache[key].hue_change(hue)
end
@cache[key]
end
end
end
end
class Game_System
Sound_Log_Filename = "Used_Sounds.txt"
#--------------------------------------------------------------------------
# * Play Background Music
# bgm : background music to be played
#--------------------------------------------------------------------------
def bgm_play(bgm)
@playing_bgm = bgm
if bgm != nil and bgm.name != ""
Audio.bgm_play("Audio/BGM/" + bgm.name, bgm.volume, bgm.pitch)
File.open(Sound_Log_Filename, 'a') {|f| f.write(bgm.name + "\n") }
else
Audio.bgm_stop
end
Graphics.frame_reset
end
#--------------------------------------------------------------------------
# * Play Background Sound
# bgs : background sound to be played
#--------------------------------------------------------------------------
def bgs_play(bgs)
@playing_bgs = bgs
if bgs != nil and bgs.name != ""
Audio.bgs_play("Audio/BGS/" + bgs.name, bgs.volume, bgs.pitch)
File.open(Sound_Log_Filename, 'a') {|f| f.write(bgs.name + "\n") }
else
Audio.bgs_stop
end
Graphics.frame_reset
end
#--------------------------------------------------------------------------
# * Play Music Effect
# me : music effect to be played
#--------------------------------------------------------------------------
def me_play(me)
if me != nil and me.name != ""
Audio.me_play("Audio/ME/" + me.name, me.volume, me.pitch)
File.open(Sound_Log_Filename, 'a') {|f| f.write(me.name + "\n") }
else
Audio.me_stop
end
Graphics.frame_reset
end
#--------------------------------------------------------------------------
# * Play Sound Effect
# se : sound effect to be played
#--------------------------------------------------------------------------
def se_play(se)
if se != nil and se.name != ""
Audio.se_play("Audio/SE/" + se.name, se.volume, se.pitch)
File.open(Sound_Log_Filename, 'a') {|f| f.write(se.name + "\n") }
end
end
end
i have no idea how to use this script, and the person who sent it to me hasn't responded. it's supposed to log all the resources used in order to help keep the filesize down.
Simple paste script like other scripts.
The script will automatically log used resources ;)
That's all :)
Edit the script, you have syntax error in first line.
First line is :
Code:
module RPG module Cache
The first lines should be :
Code:
module RPG
module Cache
RE: Ruby, RGSS & General Code Discussion - Kain Nobel - 12-21-2012
I found an interesting little tidbit today! Actually I've found it before and forgot about it, but since I've been reminded...
Game_Battler#add_state
Notice
how in the definition of add_state, the definition calls itself?
This is from the default script, but I'm curious why it doesn't throw a
Stack Level Too Deep or something.
Code:
#--------------------------------------------------------------------------
# * Add State
# state_id : state ID
# force : forcefully added flag (used to deal with auto state)
#--------------------------------------------------------------------------
def add_state(state_id, force = false)
# For an ineffective state
if $data_states[state_id] == nil
# End Method
return
end
# If not forcefully added
unless force
# A state loop already in existance
for i in @states
# If a new state is included in the state change (-) of an existing
# state, and that state is not included in the state change (-) of
# a new state (example: an attempt to add poison during dead)
if $data_states[i].minus_state_set.include?(state_id) and
not $data_states[state_id].minus_state_set.include?(i)
# End Method
return
end
end
end
# If this state is not added
unless state?(state_id)
# Add state ID to @states array
@states.push(state_id)
# If option [regarded as HP 0]is effective
if $data_states[state_id].zero_hp
# Change HP to 0
@hp = 0
end
# All state loops
for i in 1...$data_states.size
# Dealing with a state change (+)
if $data_states[state_id].plus_state_set.include?(i)
add_state(i)
end
# Dealing with a state change (-)
if $data_states[state_id].minus_state_set.include?(i)
remove_state(i)
end
end
# line change to a large rating order (if value is the same, then a
# strong restriction order)
@states.sort! do |a, b|
state_a = $data_states[a]
state_b = $data_states[b]
if state_a.rating > state_b.rating
-1
elsif state_a.rating < state_b.rating
+1
elsif state_a.restriction > state_b.restriction
-1
elsif state_a.restriction < state_b.restriction
+1
else
a <=> b
end
end
end
# If added forcefully
if force
# Set the natural removal's lowest number of turns to -1
@states_turn[state_id] = -1
end
# If not added forcefully
unless @states_turn[state_id] == -1
# Set the natural removal's lowest number of turns
@states_turn[state_id] = $data_states[state_id].hold_turn
end
# If unable to move
unless movable?
# Clear action
@current_action.clear
end
# Check the maximum value of HP and SP
@hp = [@hp, self.maxhp].min
@sp = [@sp, self.maxsp].min
end
There is a way for a method to call itself within its own definition,
but that is via the use of alias or alias_method. A child
method can call the definition of a parent's method by using a super, a parent method can call other methods defined by it's
child class even if its not defined within its own class, but a method calling itself
just seems odd to me.
A freshly defined method shouldn't be able to call itself within it's own definition, should it?
The catch here would be the need to find a way to assign them a specific level either by using an array, a hash or something else.
Oh, oh, I found some other weird stuff found in the default scripts.
Code:
def all_dead?
# If number of party members is 0
if $game_party.actors.size == 0
return false
end
# If an actor is in the party with 0 or more HP
for actor in @actors
if actor.hp > 0
return false
end
end
# All members dead
return true
end
#--------------------------------------------------------------------------
# * Slip Damage Check (for map)
#--------------------------------------------------------------------------
def check_map_slip_damage
for actor in @actors
if actor.hp > 0 and actor.slip_damage?
actor.hp -= [actor.maxhp / 100, 1].max
if actor.hp == 0
$game_system.se_play($data_system.actor_collapse_se)
end
$game_screen.start_flash(Color.new(255,0,0,128), 4)
$game_temp.gameover = $game_party.all_dead?
end
end
end
Note that this comes from Game_Party class an even so it calls itself with an external flag, i.e. $game_party.actors.size and $game_party.all_dead?, I don't really know why they thought it would ever make any sense to achieve such a terrible and useless feat.
(12-21-2012, 11:25 AM)Kain Nobel Wrote: I found an interesting little tidbit today! Actually I've found it before and forgot about it, but since I've been reminded...
Game_Battler#add_state
Notice
how in the definition of add_state, the definition calls itself?
This is from the default script, but I'm curious why it doesn't throw a
Stack Level Too Deep or something.
Code:
#--------------------------------------------------------------------------
# * Add State
# state_id : state ID
# force : forcefully added flag (used to deal with auto state)
#--------------------------------------------------------------------------
def add_state(state_id, force = false)
# For an ineffective state
if $data_states[state_id] == nil
# End Method
return
end
# If not forcefully added
unless force
# A state loop already in existance
for i in @states
# If a new state is included in the state change (-) of an existing
# state, and that state is not included in the state change (-) of
# a new state (example: an attempt to add poison during dead)
if $data_states[i].minus_state_set.include?(state_id) and
not $data_states[state_id].minus_state_set.include?(i)
# End Method
return
end
end
end
# If this state is not added
unless state?(state_id)
# Add state ID to @states array
@states.push(state_id)
# If option [regarded as HP 0]is effective
if $data_states[state_id].zero_hp
# Change HP to 0
@hp = 0
end
# All state loops
for i in 1...$data_states.size
# Dealing with a state change (+)
if $data_states[state_id].plus_state_set.include?(i)
add_state(i)
end
# Dealing with a state change (-)
if $data_states[state_id].minus_state_set.include?(i)
remove_state(i)
end
end
# line change to a large rating order (if value is the same, then a
# strong restriction order)
@states.sort! do |a, b|
state_a = $data_states[a]
state_b = $data_states[b]
if state_a.rating > state_b.rating
-1
elsif state_a.rating < state_b.rating
+1
elsif state_a.restriction > state_b.restriction
-1
elsif state_a.restriction < state_b.restriction
+1
else
a <=> b
end
end
end
# If added forcefully
if force
# Set the natural removal's lowest number of turns to -1
@states_turn[state_id] = -1
end
# If not added forcefully
unless @states_turn[state_id] == -1
# Set the natural removal's lowest number of turns
@states_turn[state_id] = $data_states[state_id].hold_turn
end
# If unable to move
unless movable?
# Clear action
@current_action.clear
end
# Check the maximum value of HP and SP
@hp = [@hp, self.maxhp].min
@sp = [@sp, self.maxsp].min
end
There is a way for a method to call itself within its own definition,
but that is via the use of alias or alias_method. A child
method can call the definition of a parent's method by using a super, a parent method can call other methods defined by it's
child class even if its not defined within its own class, but a method calling itself
just seems odd to me.
A freshly defined method shouldn't be able to call itself within it's own definition, should it?
That is actually a misconception. In RGSS, you can indeed have a method call itself recursively, just as you can in regular old Ruby. You only get the "stack level too deep" error if you actually make a stack that is too deep. Unfortunately for RGSS I remember this stack being really small (200 something if I remember correctly) and so recursive calls are not very useful when scripting. In this case, it is VERY unlikely states will be nested in a way to exceed the stack so this is an okay thing to do.