Author Topic: [FF7] Enemy AI main script template  (Read 10483 times)

Bosola

  • Fire hazard!
  • No life
  • *
  • Posts: 1753
  • Karma: 15
    • View Profile
    • My YouTube Channel
Here's another template. It looks for targets without or with a particular status, then chooses to buff or debuff them. Let's say that our monster wants to haste everyone on its team that it can.

02 2080 [friends - 20A0 for opponents]
00 4008 [haste]
80 [creates a list of friends and their hasted / un-hasted statuses]
60 0 [haste not active]
40 [compare with value '0' - returns a 1 if there are un-hasted friends]
02 2060
02 4140
80 [pushes own MP]
61 [index of spell to use - likely haste]
86
42 [sees if the spell costs less MP than available]
50 [IF both are TRUE...]
70 yy [don't jump to yy (the ELSE action)]
12 2070
02 2080 [friends]
00 4008 [haste]
80
60 0 [haste not active]
40
82
90
60 20 [use if an enemy specific attack; use 01 if player-usable magic]
61 XX [index of attack]
92
72 LLLL  [last line of script]
[This next line is YY, would be 32 if nothing preceded the script]
Etc. for else...


This would disassemble to:

If ( ( (AllAllyMask.Status:Haste == 0)  And  (Self.MP >= MPCost(of attack)) ) )
{
   TargetMask <- RandomBit( (AllAllyMask.Status:Haste == 0) )
   Perform("Whatever"[XXXX], EnemyAttack)

}

Else...

================
For direct copy-pasting...
================

02 2080
00 4008
80
60 0
40
02 2060
02 4140
80
61 19
86
42
50
70 32
12 2070
02 2080
00 4008
80
60 0
40
82
90
60 01
61 19
92
72 LLLL
[This next line is YY, would be 32 if nothing preceded the script]
« Last Edit: 2010-01-30 02:07:22 by Bosola »

Bosola

  • Fire hazard!
  • No life
  • *
  • Posts: 1753
  • Karma: 15
    • View Profile
    • My YouTube Channel
So, in the above example, you would have a monster looking at its friends. If friends don't all have haste, then it randomly selects one and casts some haste-conferring move on it (could be the spell, or some other buffing move). You could make a small set of changes to have it look at the party, choose members who don't have poison and cast bio on them.

Of course, this would mean that should the party have ribbons, the enemy will spend the entire battle bio-ing fruitlessly. There are ways around this, such as including a counter, so that the monster doesn't do it too many times, and eventually gives up.

Bosola

  • Fire hazard!
  • No life
  • *
  • Posts: 1753
  • Karma: 15
    • View Profile
    • My YouTube Channel
[Sorry, chose 'quote' rather than 'modify'...]

Bosola

  • Fire hazard!
  • No life
  • *
  • Posts: 1753
  • Karma: 15
    • View Profile
    • My YouTube Channel
QUADRA-POST

I've been looking into how H0512 and H0512-opt 'work', hoping for code that can tell me how to make one creature support a specific peer, but not itself.

Here's how it does it:

1. In H0512's Pre-Battle script, there is a set of opcodes:

12 0020
02 2050
02 4120
80
60 41
40
90
73

This pushes the address of localvar20 to the stack. Then, it uses a mask to create a list of players who are both active, and have enemy ID (address 4120) $41 (65 - that's H0512-opt's ID), and stores it at 0020.

2. Now, one way it can interact with its peers is to directly change the statuses of them in a script. One example appears in the Death script, where H0512-opt is made un-targetable:

12 0020
10 4023
80
60 00
90

This uses the mask, taking the list of active players with ID 65, then specifying the target-able flag. Basically, you use 12 0020 as you would use 12 2060 if you wanted to change the stats of the script owner, or 12 20A0 if you wanted to change the stats of all opponents.

3. What if you want to, say, target a peer with a particular ID? Well, you can probably guess from above that you might substitute 02 0020 for a 'all opponent mask', 'all allies mask' etc. etc. You're right. H0512's code for targeting H0512-opt is:

12 2070
02 0020
90

You can also mask the list provided by 0020. H0512 masks the list, targetting Opt-units which are dead:

12 2070
02 0020
00 4000
80
60 01
40
90

Address 4000 is 'dead'. A list of Opt-units and their death-statuses is created, then the opcode 40 compares the value of each entry with the 'True' condition. You could add an 82 before the 'store' opcode (90) of that if you wanted to pick a random dead H0512-opt unit.

You could easily adapt this code to have a monster buff another monster in certain conditions. I think, though, that you'd have to change the way that LocalVar0020 is set, instead setting it at the start of the script and having it choose from *alive* units, or else I think you might get your monster trying to cast haste on something that's dead. Of course, you could just set a condition saying that the ability is only used when monster X is both unbuffed and alive, and only target those living, but I think changing the way LocalVar0020 is set would be easier.

Also, I was wondering if one of our veterans could tell me: what if I wanted to use multiple conditions in targeting? What if I wanted to choose targets who were both asleep and slowed?

Edit: Found it. I looked at how Helletic Hojo locates targets for Pile Banger:

12 2070 [pushes address of 'target mask']
02 20A0 [all opps]
00 4006 [confu]
80 [mask - all opponents and their confu statuses]
60 00
40 [compare - creates list of opponents without confu]
90 [store this to target mask]
12 2070
02 2070 [loads the list of enemies from the target mask]
00 4002 [sleep]
80
60 00
40
90 [so, takes the list from the target mask, then sees the sleep status of these targets, and returns to the target mask only party members in neither confu nor sleep]
12 2070
02 2070 [again]
82
90 [and a random target from that list]

Ta-da!
« Last Edit: 2010-01-31 02:27:52 by Bosola »

Bosola

  • Fire hazard!
  • No life
  • *
  • Posts: 1753
  • Karma: 15
    • View Profile
    • My YouTube Channel
Edit: This is a chunky and unnecessarily complicated script. I've no idea what I was trying to do when designing it, when I could just have a healer's main script look for allies with a certain ID whose HP was less than their MaxHP. I must have been trying to achieve something else, for some reason or other, but I'm not sure what.

I've been posting consecutively; I hope no-one thinks of this as spamming. However, there has been a fair bit of interest in these topics, so I'm going to post another template, one that I've disassembled but not yet tried out.

It's similar to the ideas above, where one creature heals its friends. In this case, though, we're looking to restore HP rather than remove debuffs.

So, the monster that's going to be healed needs the counter-script:

12 0020

02 2060
03 4160
80
02 2060
03 4180
80
41

90

[This stores a non-zero at LocalVar0020 if MaxHP != CurrentHP]

It also needs a death-script that clears the value of 0020, so that our 'healer' won't target dead allies

12 0020
60 0
90


The friend needs to be able to read this state, then act accordingly;

02 0020
70 [address of the creature's other move]
12 2070
02 2080
02 4120
80
60 [ID of peer]
40
90
60 20
60 [atk number]
92
12 0020
60 0
90
72 [send to end of script]

This 'main' template can be used as a part of a larger AI structure. It could be followed by a simple attack instruction (choose random enemy, hit with a stick) or it could be part of something far more complicated, like

Create random number
If odd,
 - see if an enemy needs help, use atk1 if so, or go to next section if not
If even,
 - use atk2
End script.

I'm going to test this out with MPs and guard hounds, seeing if I can get the MPs to heal their dogs half the time when injured.
« Last Edit: 2010-04-08 15:00:47 by Bosola »