11-15-2015, 05:14 AM
For the past while I've been struggling with the weirdest bug that emerged while making my "pure RGSS enemy AI" thingy.
If an enemy is in a confused/berserk state and the skill they use (normally only Attack) costs MP they don't have, even after they just paid the cost, the action is negated. Since it gets negated, there is no active skill (even though they already "passed go"), no targets, and the following error occurs:
Scene_Battle, line 584, NoMethodError
undefined method 'make_targets' for nil:NilClass
The line in question:
targets = @subject.current_action.make_targets.compact
This error happens because... somehow... the current_action has been erased the moment before it was used.
It took me a lot of messing around to be able to recreate this bug in a fresh project - it wasn't to do with my custom AI or anything, it was... to do with my "tiredness" script? It adds/removes a Tired state for "critical" MP. Like, literally all it is is this:
I have no idea as of yet why this code would do this? It's also possible refresh isn't the best place for this code (even though this is where the dead state is refreshed too).
EDIT: ...
Okay, when the tiredness state is added, the game ends up passing through add_state, add_new_state, on_restrict, and then clear_actions. While "tired" is unrestricted, because the enemy has another restrictive state (confusion qualifies), it then clears the action. It does this at the moment of paying MP, but before the action itself, thus the crashing bug.
... so the answer to that is to probably move the add/removal to tiredness to somewhere like end-of-turn instead of refresh. Maybe?
If an enemy is in a confused/berserk state and the skill they use (normally only Attack) costs MP they don't have, even after they just paid the cost, the action is negated. Since it gets negated, there is no active skill (even though they already "passed go"), no targets, and the following error occurs:
Scene_Battle, line 584, NoMethodError
undefined method 'make_targets' for nil:NilClass
The line in question:
targets = @subject.current_action.make_targets.compact
This error happens because... somehow... the current_action has been erased the moment before it was used.
It took me a lot of messing around to be able to recreate this bug in a fresh project - it wasn't to do with my custom AI or anything, it was... to do with my "tiredness" script? It adds/removes a Tired state for "critical" MP. Like, literally all it is is this:
PHP Code:
class Game_BattlerBase
alias :tayruu_tiredness_gamebattlerbase_refresh :refresh
def refresh
tayruu_tiredness_gamebattlerbase_refresh
mp_rate <= 0.25 ? add_state(2) : remove_state(2)
end
end
I have no idea as of yet why this code would do this? It's also possible refresh isn't the best place for this code (even though this is where the dead state is refreshed too).
EDIT: ...
PHP Code:
class Game_Battler < Game_BattlerBase
def add_new_state(state_id)
die if state_id == death_state_id
@states.push(state_id)
on_restrict if restriction > 0
sort_states
refresh
end
def on_restrict
clear_actions
states.each do |state|
remove_state(state.id) if state.remove_by_restriction
end
end
Okay, when the tiredness state is added, the game ends up passing through add_state, add_new_state, on_restrict, and then clear_actions. While "tired" is unrestricted, because the enemy has another restrictive state (confusion qualifies), it then clears the action. It does this at the moment of paying MP, but before the action itself, thus the crashing bug.
... so the answer to that is to probably move the add/removal to tiredness to somewhere like end-of-turn instead of refresh. Maybe?