Jump to content
Sign in to follow this  

Counterattack with certain skill if attacked with physical/magical attack.

Recommended Posts

Hello, me, a complete noob in scripting, want to get some help.

I want to create an enemy that's able to counterattack if they are in a certain state or 'stance'. The game does have the 'counterattack' state that has the general idea, but I want to make it slightly more complex.

First, I want to try to make a state of counterattack that will only counter magic attacks. Normal attacks will still do damage, but it will evade magic attack sort of case. Second, the game's normal counterattack state only counters with a normal attack. Is there a way to make the enemy counter with, say, a spell instead? Of course, they will only attack the player that attacks them last.

Can anyone help me?

Share this post

Link to post
Share on other sites

I don't know of any pre-made scripts to do this, but there might be one. I custom-rolled something for my own game that achieves this, but it's pretty complicated and messy. (And extremely buggy if you want the counterattack to be a hit-all attack - had to workaround by activating a switch then using events to actually perform the attack.)


I recall doing this by looking for the code that triggers the normal counter attack, then diverting it to a certain custom function (a specific one for each enemy it's relevant to) that returns which attack and who to target - the latter part matters too, because some enemies counter by casting healing spells on themself, or aren't guaranteed to attack the character who attacked them, etc.

Share this post

Link to post
Share on other sites

Hmm, I think I get the gist of it.

On 2/17/2019 at 3:38 AM, Ninjamida said:

diverting it to a certain custom function (a specific one for each enemy it's relevant to)

But I'm not sure what does this mean, can you please make it more clear?
Thanks for responding, by the way :)

Share this post

Link to post
Share on other sites

Sorry about the slow response - I don't check this site often these days.


I'll explain in brief how my game's counterattack code works. You will need to either learn a bit of scripting, or get help from someone who does, in order to follow along. This is all fairly basic stuff, but not basic enough that it'll make sense to someone who isn't familiar with scripting - if anyone else would like to further simplify this to that level, go ahead.


Firstly, enemies need to have some kind of property to indicate their counterattack routine. In my case, I used a numeric value called "counter AI". You can either use notetags, or values coded in the script, to assign these to the enemies - there's plenty of information out there on how to do either of these, so I won't go into detail on that. If your counterattack system is very simple - ie: the only thing you want to change is which attack they use - then you could even directly store the attack ID in this property.


Next, you'll need to find the code responsible for calling a counterattack. By default, it's hardcoded to return the first attack in the database, which will generally in turn correspond to the Attack command. Instead, it needs to call a separate function that handles counterattack decisions - or if you're using the "store attack ID directly in the property", it simply needs to return the attack that corresponds to that property. It's tidier to override the function altogether, but if you prefer, you can modify it in-place.


If we're going the function route, then the main function should then divert to separate functions based on the value of the enemy's counter AI property. For example, in my game:


  def counterskill(target, attacker, item)
    counteraiscript = target.caiscript
    case counteraiscript
    when 1
      # No action but memorises attacker.
      return counter_ai_001(attacker)
    when 2
      # Memories attacker if they are lowest HP, also uses Radar.
      return counter_ai_002(attacker)
    when 3
      # Counters with random element, changes to alignment to it.
      return counter_ai_003(attacker)
    when 4
      # Yu Pagoda style full-HP revival but instant. Cuts off once
      # max HP excees AIVAR#1.
      return counter_ai_004(target)
    when 5
      # Physical with Blind, Magical with Silence. If neither, or
      # target already under status, picks a random status to try
      # out of Darkness, Silence, Sleep, Poison, Slow. If under
      # all, will not counter.
      return counter_ai_005(attacker, item)
    when 6
      # Counts up damage in @aivars[1]
      return counter_ai_006(attacker)
    when 7
      # Just messes with a few switches.
      return counter_ai_007(item)
    # etc
      return [1, attacker.index]

The "else" is a fallback to the default. Note that my functions return an array with two values - an attack and a target. Simpler systems may not need to do this.


It's probably possible to do this in a tidier way, in particular, instead of hardcoding for each possible value of "counter ai", do some kind of call that appends the number to some prefix in order to determine which function to call - I was pretty new to Ruby when I threw this together, so it doesn't make use of that kind of option.


In turn, the "counter_ai_xxx" functions determine, using normal scripting, what attack to use as a counter, and who to use it on (because in my game, I don't always want the counter to be used against the attacker - in some cases, I might want to target a random or specific-but-not-the-attacker ally, or I might want the enemy to counter by casting a healing spell on themself, etc). It's also possible for the functions to return nil, which indicates that no counterattack should be used. Such a scenario might be that you have an enemy that attacks whichever actor last attacked them - so the counter AI would remember who attacked, but would do nothing instead of launching any kind of counterattack. (Obviously, this requires a similar setup for on-turn attack selection, because the built-in attack selection features don't allow for selecting specific targets.)


Here's an example of one of the counterattack function's code:

  def counter_ai_005(attacker, item)
    if hp == 0
      $game_switches[57] = true
      return nil
    return nil if result.hp_damage < 1
    possstat = [2, 3, 4, 5, 20]
    possstat.delete_if {|x| attacker.state?(x)}
    return nil if possstat.empty?
    if item.physical? && possstat.include?(3)
      return [184, attacker.index]
    if item.magical? && possstat.include?(4)
      return [185, attacker.index]
    nposs = possstat.size
    try = possstat[rand(nposs)]
    return [183, attacker.index] if try == 2
    return [184, attacker.index] if try == 3
    return [185, attacker.index] if try == 4
    return [186, attacker.index] if try == 5
    return [190, attacker.index] if try == 20
    return nil


Edited by Ninjamida

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.