Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Actor Cannot Select Specific Enemy

Update: Sorry, just realized this was in the wrong forum. Is there any way for me to delete or move this post? Thanks!

What I'm Trying to Accomplish:

I'm creating a system that simulates ranges. Bows fire from long-range, spears attack at mid-range, and other melee at short. This distinction opens up a lot of strategic possibilities, such as having melee attackers block opponents so they cannot reach vulnerable archers. In game terms, a swordsman cannot attack an archer if there are other melee characters between them.

I'm approaching this through states, so that characters with states 38, 40, and 41 cannot be attack by characters with states 36, 38, or 41. They can, however, be attacked by characters with states 37, 39, and 40. Characters with state 41 cannot attack anyone. I've already managed to alter the enemy AI so that it follows these rules. I'm having a harder time with player controlled characters.

I'm attempting to do so through the class Arrow_Enemy by altering which enemies can be selected. I'm using the following code based on Atoa's battle system:

Code:
#==============================================================================

# ■ Arrow_Enemy

#==============================================================================

class Arrow_Enemy < Arrow_Base

  #--------------------------------------------------------------------------

  def update

    super

    $game_troop.enemies.size.times do

      break if self.enemy.exist? or actor_cannot_select(enemy)

      @index += 1

      @index %= $game_troop.enemies.size

    end

    cursor_down if Input.repeat?(Input::RIGHT)

    cursor_down if Input.repeat?(Input::UP)

    cursor_up if Input.repeat?(Input::LEFT)

    cursor_up if Input.repeat?(Input::DOWN)

    if self.enemy != nil

      self.x = self.enemy.actual_x

      self.y = self.enemy.actual_y

    end

  end

  #--------------------------------------------------------------------------

  def actor_cannot_select(target)

    battler = $game_party.actors[@index]

    return true if battler.states.include?(41)

    return false if battler.states.include?(37) or battler.states.include?(39) or battler.states.include?(40)

    return true if target.states.include?(38) or target.states.include?(40)

  end

  #--------------------------------------------------------------------------

  def cursor_up

    $game_system.se_play($data_system.cursor_se)

    $game_troop.enemies.size.times do

      @index += $game_troop.enemies.size - 1

      @index %= $game_troop.enemies.size

      break if self.enemy.exist? or actor_cannot_select(enemy)

    end

  end

  #--------------------------------------------------------------------------

  def cursor_down

    $game_system.se_play($data_system.cursor_se)

    $game_troop.enemies.size.times do

      @index += 1

      @index %= $game_troop.enemies.size

      break if self.enemy.exist? or actor_cannot_select(enemy)

    end

  end  

end

 

Normally this script works fine.

What I've Added:

I've added four things. The first is the method 'actor_cannot_select,' and the other three are calls of my new method next to 'break if self.enemy.exist?'

The Error:

The game still starts normally. However, when I move the arrow beyond the last enemy in the index, I get the error:

Script 'ACBS | Battle Main Code' line 3697: NoMethodError occured.

undefined method 'states' for nil:NilClass

My Uneducated Guess:

I suspect this is because the class Arrow_Enemy does not have access to the states index and so is responding with nil. If so, how do I call the states index so that it can be used within this class?

Any help would be appreciated! I just started teaching myself Ruby last week and my understanding is far from complete.

-Tuatha
 
The problem is that it's stopping on enemies that don't exist.
The problem appears to be these lines:
break if self.enemy.exist? or actor_cannot_select(enemy)

Since it's using or, it's calling the actor_cannot_select method if self.enemy.exist? returns false... which, of course, means it's being called on an enemy that does not exist. Additionally, because it's using or, it will never skip any enemies. It will stop the cursor on them as long as they exist, negating the entire point of the script in the first place.
I'd change it to something like
break if self.enemy.exist? and !actor_cannot_select(self.enemy)

I dunno what you've got going on in actor_cannot_select, though. It's using game_actors, so... if the actor has the state, it'll always be unselectable, and it will loop through without doing anyways. I would move it to whatever calls the enemy select arrow and have it call decide_random_target_for_actor instead of the arrow if the actor has the state on them. For the target part, you should probably throw something in so it doesn't bug out if ALL the enemies have the states on them.


Also, unrelated to the problem:
You can just use @index -= 1 rather than @index += $game_troop.enemies.size - 1.
 
The problem is that it's stopping on enemies that don't exist. The problem appears to be these lines:
break if self.enemy.exist? or actor_cannot_select(enemy)

Since it's using or, it's calling the actor_cannot_select method if self.enemy.exist? returns false... which, of course, means it's being called on an enemy that does not exist. Additionally, because it's using or, it will never skip any enemies. It will stop the cursor on them as long as they exist, negating the entire point of the script in the first place.
I'd change it to something like break if self.enemy.exist? and !actor_cannot_select(self.enemy)

This sounds like good advice, but there's an error in actor_cannot_select which triggers as soon as it's called, before the computer can even detect errors in the code context. To illustrate, if I remove all calls of the method and then insert a meaningless one such as "flubber = actor_cannot_select" at the top of "cursor_up" or "cursor_down" I get the same error message about states being nil. It seems that as soon as actor_cannot_select runs, it bugs out.

I tried moving the method to Scene_Battle (because I know it has access to states), but then when I try to call it using Scene_Battle.actor_cannot_select, I get an error telling me that the method is undefined. Error after error, huh? Do you why this might be happening and a way around it?

I would move it to whatever calls the enemy select arrow and have it call decide_random_target_for_actor instead of the arrow if the actor has the state on them.

That sounds like it would work, but in the process, would the player be able to select a target? Or would it be like the actor has the state "Beserk" and moves automatically?

For the target part, you should probably throw something in so it doesn't bug out if ALL the enemies have the states on them.

Excellent point.
 
This sounds like good advice, but there's an error in actor_cannot_select which triggers as soon as it's called, before the computer can even detect errors in the code context. To illustrate, if I remove all calls of the method and then insert a meaningless one such as "flubber = actor_cannot_select" at the top of "cursor_up" or "cursor_down" I get the same error message about states being nil. It seems that as soon as actor_cannot_select runs, it bugs out.
Well, I just noticed that you're using $game_party.actors[@index], but are looping @index through $game_troop.enemies, so there's one of the errors. The actor part needs to be moved out of arrow_enemy anyways.

I tried moving the method to Scene_Battle (because I know it has access to states), but then when I try to call it using Scene_Battle.actor_cannot_select, I get an error telling me that the method is undefined. Error after error, huh? Do you why this might be happening and a way around it?
You can't use Scene_Battle.xxxxxx, because Scene_Battle itself is not a variable. It's a class, which in this case is instanced to the $scene variable. You could use $scene.actor_cannot_select, but it wouldn't serve any purpose since it doesn't have access to anything the method needs that the arrow_enemy class itself doesn't have access to. states is a property of the game_battler class, which both scene_battle and arrow_enemy can access using $game_troop.enemies and $game_party.actors. The problem isn't that the class does not have access to the states, the problem is that you're trying to pull states out of something that doesn't exist or doesn't have states.

That sounds like it would work, but in the process, would the player be able to select a target? Or would it be like the actor has the state "Beserk" and moves automatically?
That would be up to you. It'll always return false if the actor has one of those states, so it would bug out in the same way as if every enemy had one of the states. Only the part that checks the actor's states needs to be moved, by the way.



Basically, your logic flow for the method is all messed up o-o
 
You can't use Scene_Battle.xxxxxx, because Scene_Battle itself is not a variable. It's a class, which in this case is instanced to the $scene variable. You could use $scene.actor_cannot_select, but it wouldn't serve any purpose since it doesn't have access to anything the method needs that the arrow_enemy class itself doesn't have access to. states is a property of the game_battler class, which both scene_battle and arrow_enemy can access using $game_troop.enemies and $game_party.actors. The problem isn't that the class does not have access to the states, the problem is that you're trying to pull states out of something that doesn't exist or doesn't have states.

Thanks. That makes a lot of sense.

Basically, your logic flow for the method is all messed up o-o

I agree that you're right, but the scary thing is that I have no idea why. Again, I'm new to coding and don't really know what I'm doing. What little bit I've learned has been through trial-and-error. Although you've been helpful, I hate to keep bothering you and others with such basic problems. Perhaps there's a website that's good for teaching Ruby? And even more important than that, a site that has a coding "dictionary" so that I can look up symbols and methods I'm unfamiliar with? Right now, as I read over these methods I understand snippets of them, but like reading in a foriegn language, a lot of the syntax and vocabulary is contextual guesswork--and often I get it wrong.

Thanks again for your help!
Tuatha
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top